Merge branch 'master' into feat/add-slug-to-seo-form

This commit is contained in:
Magdalena Markusik 2020-09-25 17:41:58 +02:00
commit 8f43226e95
39 changed files with 2421 additions and 372 deletions

View file

@ -47,6 +47,7 @@ All notable, unreleased changes to this project will be documented in this file.
- Allow product variant to be set as default - #721 by @tomaszszymanski129 - Allow product variant to be set as default - #721 by @tomaszszymanski129
- Change plural form of "informations" to "information" strings across the app #722 by @mmarkusik - Change plural form of "informations" to "information" strings across the app #722 by @mmarkusik
- Fix misaligned rich text draft controls - #725 by @orzechdev - Fix misaligned rich text draft controls - #725 by @orzechdev
- Allow taxes to be configured per product - #728 by @dominik-zeglen
## 2.10.1 ## 2.10.1

View file

@ -4318,9 +4318,6 @@
"context": "product price", "context": "product price",
"string": "Price" "string": "Price"
}, },
"src_dot_products_dot_components_dot_ProductPricing_dot_3015886868": {
"string": "Charge taxes for this item"
},
"src_dot_products_dot_components_dot_ProductShipping_dot_1325966144": { "src_dot_products_dot_components_dot_ProductShipping_dot_1325966144": {
"context": "product shipping", "context": "product shipping",
"string": "Shipping" "string": "Shipping"
@ -4355,6 +4352,18 @@
"src_dot_products_dot_components_dot_ProductStocks_dot_849869830": { "src_dot_products_dot_components_dot_ProductStocks_dot_849869830": {
"string": "Active inventory tracking will automatically calculate changes of stock" "string": "Active inventory tracking will automatically calculate changes of stock"
}, },
"src_dot_products_dot_components_dot_ProductTaxes_dot_1943864488": {
"context": "checkbox",
"string": "Charge taxes on this product"
},
"src_dot_products_dot_components_dot_ProductTaxes_dot_2022558114": {
"context": "select tax ratte",
"string": "Tax Rate"
},
"src_dot_products_dot_components_dot_ProductTaxes_dot_2771905943": {
"context": "checkbox",
"string": "Override the product type's tax rate"
},
"src_dot_products_dot_components_dot_ProductUpdatePage_dot_2232321263": { "src_dot_products_dot_components_dot_ProductUpdatePage_dot_2232321263": {
"context": "product publication date label", "context": "product publication date label",
"string": "will become published on {date}" "string": "will become published on {date}"

View file

@ -3,6 +3,7 @@ import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import useStateFromProps from "@saleor/hooks/useStateFromProps"; import useStateFromProps from "@saleor/hooks/useStateFromProps";
import { FetchMoreProps } from "@saleor/types"; import { FetchMoreProps } from "@saleor/types";
import classNames from "classnames";
import Downshift from "downshift"; import Downshift from "downshift";
import { filter } from "fuzzaldrin"; import { filter } from "fuzzaldrin";
import React from "react"; import React from "react";
@ -27,6 +28,7 @@ const useStyles = makeStyles(
export interface SingleAutocompleteSelectFieldProps export interface SingleAutocompleteSelectFieldProps
extends Partial<FetchMoreProps> { extends Partial<FetchMoreProps> {
add?: SingleAutocompleteActionType; add?: SingleAutocompleteActionType;
className?: string;
error?: boolean; error?: boolean;
name: string; name: string;
displayValue: string; displayValue: string;
@ -51,6 +53,7 @@ const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectF
const { const {
add, add,
allowCustomValues, allowCustomValues,
className,
choices, choices,
disabled, disabled,
displayValue, displayValue,
@ -122,7 +125,10 @@ const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectF
); );
return ( return (
<div className={classes.container} {...rest}> <div
className={classNames(classes.container, className)}
{...rest}
>
<TextField <TextField
InputProps={{ InputProps={{
...InputProps, ...InputProps,

View file

@ -124,6 +124,8 @@ function getChoiceIndex(
return choiceIndex; return choiceIndex;
} }
const sliceSize = 20;
const SingleAutocompleteSelectFieldContent: React.FC<SingleAutocompleteSelectFieldContentProps> = props => { const SingleAutocompleteSelectFieldContent: React.FC<SingleAutocompleteSelectFieldContentProps> = props => {
const { const {
add, add,
@ -147,6 +149,7 @@ const SingleAutocompleteSelectFieldContent: React.FC<SingleAutocompleteSelectFie
const anchor = React.useRef<HTMLDivElement>(); const anchor = React.useRef<HTMLDivElement>();
const scrollPosition = useElementScroll(anchor); const scrollPosition = useElementScroll(anchor);
const [calledForMore, setCalledForMore] = React.useState(false); const [calledForMore, setCalledForMore] = React.useState(false);
const [slice, setSlice] = React.useState(sliceSize);
const scrolledToBottom = isScrolledToBottom(anchor, scrollPosition, offset); const scrolledToBottom = isScrolledToBottom(anchor, scrollPosition, offset);
@ -154,9 +157,18 @@ const SingleAutocompleteSelectFieldContent: React.FC<SingleAutocompleteSelectFie
if (!calledForMore && onFetchMore && scrolledToBottom) { if (!calledForMore && onFetchMore && scrolledToBottom) {
onFetchMore(); onFetchMore();
setCalledForMore(true); setCalledForMore(true);
} else if (scrolledToBottom) {
setSlice(slice => slice + sliceSize);
} }
}, [scrolledToBottom]); }, [scrolledToBottom]);
React.useEffect(() => {
setSlice(sliceSize);
anchor.current.scrollTo({
top: 0
});
}, [choices?.length]);
React.useEffect(() => { React.useEffect(() => {
if (calledForMore && !loading) { if (calledForMore && !loading) {
setCalledForMore(false); setCalledForMore(false);
@ -219,7 +231,7 @@ const SingleAutocompleteSelectFieldContent: React.FC<SingleAutocompleteSelectFie
{choices.length > 0 && (!!add || displayCustomValue) && ( {choices.length > 0 && (!!add || displayCustomValue) && (
<Hr className={classes.hr} /> <Hr className={classes.hr} />
)} )}
{choices.map((suggestion, index) => { {choices.slice(0, slice).map((suggestion, index) => {
const choiceIndex = getChoiceIndex( const choiceIndex = getChoiceIndex(
index, index,
emptyOption, emptyOption,

View file

@ -1,6 +1,7 @@
import gql from "graphql-tag"; import gql from "graphql-tag";
import { metadataFragment } from "./metadata"; import { metadataFragment } from "./metadata";
import { taxTypeFragment } from "./taxes";
import { weightFragment } from "./weight"; import { weightFragment } from "./weight";
export const stockFragment = gql` export const stockFragment = gql`
@ -107,6 +108,7 @@ export const productFragmentDetails = gql`
${stockFragment} ${stockFragment}
${weightFragment} ${weightFragment}
${metadataFragment} ${metadataFragment}
${taxTypeFragment}
fragment Product on Product { fragment Product on Product {
...ProductVariantAttributesFragment ...ProductVariantAttributesFragment
...MetadataFragment ...MetadataFragment
@ -177,10 +179,16 @@ export const productFragmentDetails = gql`
id id
name name
hasVariants hasVariants
taxType {
...TaxTypeFragment
}
} }
weight { weight {
...WeightFragment ...WeightFragment
} }
taxType {
...TaxTypeFragment
}
availableForPurchase availableForPurchase
visibleInListings visibleInListings
} }

View file

@ -26,3 +26,9 @@ export const shopTaxesFragment = gql`
displayGrossPrices displayGrossPrices
} }
`; `;
export const taxTypeFragment = gql`
fragment TaxTypeFragment on TaxType {
description
taxCode
}
`;

View file

@ -52,12 +52,19 @@ export interface Product_productType_variantAttributes {
values: (Product_productType_variantAttributes_values | null)[] | null; values: (Product_productType_variantAttributes_values | null)[] | null;
} }
export interface Product_productType_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface Product_productType { export interface Product_productType {
__typename: "ProductType"; __typename: "ProductType";
id: string; id: string;
variantAttributes: (Product_productType_variantAttributes | null)[] | null; variantAttributes: (Product_productType_variantAttributes | null)[] | null;
name: string; name: string;
hasVariants: boolean; hasVariants: boolean;
taxType: Product_productType_taxType | null;
} }
export interface Product_pricing_priceRangeUndiscounted_start_gross { export interface Product_pricing_priceRangeUndiscounted_start_gross {
@ -191,6 +198,12 @@ export interface Product_weight {
value: number; value: number;
} }
export interface Product_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface Product { export interface Product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -217,6 +230,7 @@ export interface Product {
images: (Product_images | null)[] | null; images: (Product_images | null)[] | null;
variants: (Product_variants | null)[] | null; variants: (Product_variants | null)[] | null;
weight: Product_weight | null; weight: Product_weight | null;
taxType: Product_taxType | null;
availableForPurchase: any | null; availableForPurchase: any | null;
visibleInListings: boolean; visibleInListings: boolean;
} }

View file

@ -0,0 +1,13 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL fragment: TaxTypeFragment
// ====================================================
export interface TaxTypeFragment {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}

View file

@ -11,6 +11,7 @@ import PageHeader from "@saleor/components/PageHeader";
import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SaveButtonBar from "@saleor/components/SaveButtonBar";
import SeoForm from "@saleor/components/SeoForm"; import SeoForm from "@saleor/components/SeoForm";
import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment";
import { TaxTypeFragment } from "@saleor/fragments/types/TaxTypeFragment";
import useDateLocalize from "@saleor/hooks/useDateLocalize"; import useDateLocalize from "@saleor/hooks/useDateLocalize";
import useFormset from "@saleor/hooks/useFormset"; import useFormset from "@saleor/hooks/useFormset";
import useStateFromProps from "@saleor/hooks/useStateFromProps"; import useStateFromProps from "@saleor/hooks/useStateFromProps";
@ -46,14 +47,15 @@ import ProductOrganization from "../ProductOrganization";
import ProductPricing from "../ProductPricing"; import ProductPricing from "../ProductPricing";
import ProductShipping from "../ProductShipping/ProductShipping"; import ProductShipping from "../ProductShipping/ProductShipping";
import ProductStocks, { ProductStockInput } from "../ProductStocks"; import ProductStocks, { ProductStockInput } from "../ProductStocks";
import ProductTaxes from "../ProductTaxes";
interface FormData extends MetadataFormData { interface FormData extends MetadataFormData {
availableForPurchase: string; availableForPurchase: string;
basePrice: number; basePrice: number;
publicationDate: string;
category: string; category: string;
collections: string[]; changeTaxCode: boolean;
chargeTaxes: boolean; chargeTaxes: boolean;
collections: string[];
description: RawDraftContentState; description: RawDraftContentState;
isAvailable: boolean; isAvailable: boolean;
isAvailableForPurchase: boolean; isAvailableForPurchase: boolean;
@ -61,10 +63,12 @@ interface FormData extends MetadataFormData {
name: string; name: string;
slug: string; slug: string;
productType: string; productType: string;
publicationDate: string;
seoDescription: string; seoDescription: string;
seoTitle: string; seoTitle: string;
sku: string; sku: string;
stockQuantity: number; stockQuantity: number;
taxCode: string;
trackInventory: boolean; trackInventory: boolean;
visibleInListings: boolean; visibleInListings: boolean;
weight: string; weight: string;
@ -93,6 +97,7 @@ interface ProductCreatePageProps {
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
weightUnit: string; weightUnit: string;
warehouses: SearchWarehouses_search_edges_node[]; warehouses: SearchWarehouses_search_edges_node[];
taxTypes: TaxTypeFragment[];
fetchCategories: (data: string) => void; fetchCategories: (data: string) => void;
fetchCollections: (data: string) => void; fetchCollections: (data: string) => void;
fetchProductTypes: (data: string) => void; fetchProductTypes: (data: string) => void;
@ -115,6 +120,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
productTypes: productTypeChoiceList, productTypes: productTypeChoiceList,
saveButtonBarState, saveButtonBarState,
warehouses, warehouses,
taxTypes,
onBack, onBack,
fetchProductTypes, fetchProductTypes,
weightUnit, weightUnit,
@ -149,6 +155,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
availableForPurchase: "", availableForPurchase: "",
basePrice: 0, basePrice: 0,
category: "", category: "",
changeTaxCode: false,
chargeTaxes: false, chargeTaxes: false,
collections: [], collections: [],
description: {} as any, description: {} as any,
@ -165,6 +172,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
sku: null, sku: null,
slug: "", slug: "",
stockQuantity: null, stockQuantity: null,
taxCode: null,
trackInventory: false, trackInventory: false,
visibleInListings: false, visibleInListings: false,
weight: "" weight: ""
@ -182,10 +190,16 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
>([]); >([]);
const [productType, setProductType] = React.useState<ProductType>(null); const [productType, setProductType] = React.useState<ProductType>(null);
const [selectedTaxType, setSelectedTaxType] = useStateFromProps(null);
const categories = getChoices(categoryChoiceList); const categories = getChoices(categoryChoiceList);
const collections = getChoices(collectionChoiceList); const collections = getChoices(collectionChoiceList);
const productTypes = getChoices(productTypeChoiceList); const productTypes = getChoices(productTypeChoiceList);
const taxTypeChoices =
taxTypes?.map(taxType => ({
label: taxType.description,
value: taxType.taxCode
})) || [];
const handleSubmit = (data: FormData) => const handleSubmit = (data: FormData) =>
onSubmit({ onSubmit({
@ -230,6 +244,11 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
setProductType, setProductType,
productTypeChoiceList productTypeChoiceList
); );
const handleTaxTypeSelect = createSingleAutocompleteSelectHandler(
change,
setSelectedTaxType,
taxTypeChoices
);
const changeMetadata = makeMetadataChangeHandler(change); const changeMetadata = makeMetadataChangeHandler(change);
@ -372,6 +391,15 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
}} }}
onChange={change} onChange={change}
/> />
<CardSpacer />
<ProductTaxes
data={data}
disabled={disabled}
onChange={change}
onTaxTypeChange={handleTaxTypeSelect}
selectedTaxTypeDisplayName={selectedTaxType}
taxTypes={taxTypes}
/>
</div> </div>
</Grid> </Grid>
<SaveButtonBar <SaveButtonBar

View file

@ -2,7 +2,6 @@ import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent"; import CardContent from "@material-ui/core/CardContent";
import { makeStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import CardTitle from "@saleor/components/CardTitle"; import CardTitle from "@saleor/components/CardTitle";
import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
import PriceField from "@saleor/components/PriceField"; import PriceField from "@saleor/components/PriceField";
import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment";
import { getFormErrors, getProductErrorMessage } from "@saleor/utils/errors"; import { getFormErrors, getProductErrorMessage } from "@saleor/utils/errors";
@ -23,7 +22,6 @@ const useStyles = makeStyles(
interface ProductPricingProps { interface ProductPricingProps {
currency?: string; currency?: string;
data: { data: {
chargeTaxes: boolean;
basePrice: number; basePrice: number;
}; };
disabled: boolean; disabled: boolean;
@ -46,17 +44,7 @@ const ProductPricing: React.FC<ProductPricingProps> = props => {
defaultMessage: "Pricing", defaultMessage: "Pricing",
description: "product pricing" description: "product pricing"
})} })}
>
<ControlledCheckbox
name="chargeTaxes"
label={intl.formatMessage({
defaultMessage: "Charge taxes for this item"
})}
checked={data.chargeTaxes}
onChange={onChange}
disabled={disabled}
/> />
</CardTitle>
<CardContent> <CardContent>
<div className={classes.root}> <div className={classes.root}>
<PriceField <PriceField

View file

@ -21,13 +21,13 @@ import CardTitle from "@saleor/components/CardTitle";
import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
import FormSpacer from "@saleor/components/FormSpacer"; import FormSpacer from "@saleor/components/FormSpacer";
import Hr from "@saleor/components/Hr"; import Hr from "@saleor/components/Hr";
import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment";
import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment"; import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment";
import { FormChange } from "@saleor/hooks/useForm"; import { FormChange } from "@saleor/hooks/useForm";
import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset"; import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset";
import { renderCollection } from "@saleor/misc"; import { renderCollection } from "@saleor/misc";
import { ICONBUTTON_SIZE } from "@saleor/theme"; import { ICONBUTTON_SIZE } from "@saleor/theme";
import { UserError } from "@saleor/types"; import { getFormErrors, getProductErrorMessage } from "@saleor/utils/errors";
import { getFieldError } from "@saleor/utils/errors";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -40,7 +40,7 @@ export interface ProductStockFormData {
export interface ProductStocksProps { export interface ProductStocksProps {
data: ProductStockFormData; data: ProductStockFormData;
disabled: boolean; disabled: boolean;
errors: UserError[]; errors: ProductErrorFragment[];
stocks: ProductStockInput[]; stocks: ProductStockInput[];
warehouses: WarehouseFragment[]; warehouses: WarehouseFragment[];
onChange: FormsetChange; onChange: FormsetChange;
@ -121,6 +121,7 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
const warehousesToAssign = warehouses.filter( const warehousesToAssign = warehouses.filter(
warehouse => !stocks.some(stock => stock.id === warehouse.id) warehouse => !stocks.some(stock => stock.id === warehouse.id)
); );
const formErrors = getFormErrors(["sku"], errors);
return ( return (
<Card> <Card>
@ -135,9 +136,9 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
<div className={classes.skuInputContainer}> <div className={classes.skuInputContainer}>
<TextField <TextField
disabled={disabled} disabled={disabled}
error={!!getFieldError(errors, "sku")} error={!!formErrors.sku}
fullWidth fullWidth
helperText={getFieldError(errors, "sku")?.message} helperText={getProductErrorMessage(formErrors.sku, intl)}
label={intl.formatMessage({ label={intl.formatMessage({
defaultMessage: "SKU (Stock Keeping Unit)" defaultMessage: "SKU (Stock Keeping Unit)"
})} })}

View file

@ -0,0 +1,112 @@
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import makeStyles from "@material-ui/core/styles/makeStyles";
import CardTitle from "@saleor/components/CardTitle";
import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
import Hr from "@saleor/components/Hr";
import SingleAutocompleteSelectField from "@saleor/components/SingleAutocompleteSelectField";
import { TaxTypeFragment } from "@saleor/fragments/types/TaxTypeFragment";
import { FormChange } from "@saleor/hooks/useForm";
import { sectionNames } from "@saleor/intl";
import React from "react";
import { useIntl } from "react-intl";
export interface ProductTaxesProps {
data: {
changeTaxCode: boolean;
chargeTaxes: boolean;
taxCode: string;
};
disabled: boolean;
selectedTaxTypeDisplayName: string;
taxTypes: TaxTypeFragment[];
onChange: FormChange;
onTaxTypeChange: FormChange;
}
const useStyles = makeStyles(
theme => ({
content: {
paddingTop: theme.spacing(2)
},
hr: {
margin: theme.spacing(2, 0)
},
select: {
margin: theme.spacing(2, 0)
}
}),
{
name: "ProductTaxes"
}
);
const ProductTaxes: React.FC<ProductTaxesProps> = ({
data,
disabled,
selectedTaxTypeDisplayName,
taxTypes,
onChange,
onTaxTypeChange
}) => {
const intl = useIntl();
const classes = useStyles({});
return (
<Card>
<CardTitle title={intl.formatMessage(sectionNames.taxes)} />
<CardContent className={classes.content}>
<ControlledCheckbox
checked={data.changeTaxCode}
disabled={disabled}
data-test="override-tax-type"
label={intl.formatMessage({
defaultMessage: "Override the product type's tax rate",
description: "checkbox"
})}
name="changeTaxCode"
onChange={onChange}
/>
<Hr className={classes.hr} />
<ControlledCheckbox
checked={data.chargeTaxes}
disabled={disabled}
data-test="charge-taxes"
label={intl.formatMessage({
defaultMessage: "Charge taxes on this product",
description: "checkbox"
})}
name="chargeTaxes"
onChange={onChange}
/>
{data.changeTaxCode && (
<SingleAutocompleteSelectField
className={classes.select}
disabled={disabled}
displayValue={selectedTaxTypeDisplayName}
data-test="select-tax-type"
label={intl.formatMessage({
defaultMessage: "Tax Rate",
description: "select tax ratte"
})}
name="taxCode"
onChange={onTaxTypeChange}
value={data.taxCode}
choices={
taxTypes?.map(taxType => ({
label: taxType.description,
value: taxType.taxCode
})) || []
}
InputProps={{
autoComplete: "off"
}}
/>
)}
</CardContent>
</Card>
);
};
ProductTaxes.displayName = "ProductTaxes";
export default ProductTaxes;

View file

@ -0,0 +1,2 @@
export * from "./ProductTaxes";
export { default } from "./ProductTaxes";

View file

@ -10,6 +10,7 @@ import PageHeader from "@saleor/components/PageHeader";
import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SaveButtonBar from "@saleor/components/SaveButtonBar";
import SeoForm from "@saleor/components/SeoForm"; import SeoForm from "@saleor/components/SeoForm";
import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment";
import { TaxTypeFragment } from "@saleor/fragments/types/TaxTypeFragment";
import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment"; import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment";
import useDateLocalize from "@saleor/hooks/useDateLocalize"; import useDateLocalize from "@saleor/hooks/useDateLocalize";
import useFormset from "@saleor/hooks/useFormset"; import useFormset from "@saleor/hooks/useFormset";
@ -52,6 +53,7 @@ import ProductOrganization from "../ProductOrganization";
import ProductPricing from "../ProductPricing"; import ProductPricing from "../ProductPricing";
import ProductShipping from "../ProductShipping/ProductShipping"; import ProductShipping from "../ProductShipping/ProductShipping";
import ProductStocks, { ProductStockInput } from "../ProductStocks"; import ProductStocks, { ProductStockInput } from "../ProductStocks";
import ProductTaxes from "../ProductTaxes";
import ProductVariants from "../ProductVariants"; import ProductVariants from "../ProductVariants";
export interface ProductUpdatePageProps extends ListActions { export interface ProductUpdatePageProps extends ListActions {
@ -69,6 +71,7 @@ export interface ProductUpdatePageProps extends ListActions {
header: string; header: string;
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
warehouses: WarehouseFragment[]; warehouses: WarehouseFragment[];
taxTypes: TaxTypeFragment[];
fetchCategories: (query: string) => void; fetchCategories: (query: string) => void;
fetchCollections: (query: string) => void; fetchCollections: (query: string) => void;
onVariantsAdd: () => void; onVariantsAdd: () => void;
@ -111,6 +114,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
saveButtonBarState, saveButtonBarState,
variants, variants,
warehouses, warehouses,
taxTypes,
onBack, onBack,
onDelete, onDelete,
onImageDelete, onImageDelete,
@ -161,6 +165,10 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
getChoices(maybe(() => product.collections, [])) getChoices(maybe(() => product.collections, []))
); );
const [selectedTaxType, setSelectedTaxType] = useStateFromProps(
product?.taxType.description
);
const { const {
isMetadataModified, isMetadataModified,
isPrivateMetadataModified, isPrivateMetadataModified,
@ -177,6 +185,11 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
const currency = const currency =
product?.variants?.length && product.variants[0].price.currency; product?.variants?.length && product.variants[0].price.currency;
const hasVariants = maybe(() => product.productType.hasVariants, false); const hasVariants = maybe(() => product.productType.hasVariants, false);
const taxTypeChoices =
taxTypes?.map(taxType => ({
label: taxType.description,
value: taxType.taxCode
})) || [];
const handleSubmit = (data: ProductUpdatePageFormData) => { const handleSubmit = (data: ProductUpdatePageFormData) => {
const metadata = isMetadataModified ? data.metadata : undefined; const metadata = isMetadataModified ? data.metadata : undefined;
@ -246,6 +259,11 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
triggerChange triggerChange
); );
const changeMetadata = makeMetadataChangeHandler(change); const changeMetadata = makeMetadataChangeHandler(change);
const handleTaxTypeSelect = createSingleAutocompleteSelectHandler(
change,
setSelectedTaxType,
taxTypeChoices
);
return ( return (
<> <>
@ -422,6 +440,15 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
}} }}
onChange={change} onChange={change}
/> />
<CardSpacer />
<ProductTaxes
data={data}
disabled={disabled}
selectedTaxTypeDisplayName={selectedTaxType}
taxTypes={taxTypes}
onChange={change}
onTaxTypeChange={handleTaxTypeSelect}
/>
</div> </div>
</Grid> </Grid>
<SaveButtonBar <SaveButtonBar

View file

@ -206,8 +206,11 @@ export const product: (
hasVariants: true, hasVariants: true,
id: "pt76406", id: "pt76406",
name: "Versatile", name: "Versatile",
seoDescription: "Omnis rerum ea. Fugit dignissimos modi est rerum", taxType: {
seoTitle: "Ergonomic Plastic Bacon", __typename: "TaxType",
description: "standard",
taxCode: "standard"
},
variantAttributes: [ variantAttributes: [
{ {
__typename: "Attribute", __typename: "Attribute",
@ -255,6 +258,11 @@ export const product: (
seoTitle: "Seo title", seoTitle: "Seo title",
sku: "59661-34207", sku: "59661-34207",
slug: "Borders", slug: "Borders",
taxType: {
__typename: "TaxType",
description: "standard",
taxCode: "standard"
},
thumbnail: { __typename: "Image" as "Image", url: placeholderImage }, thumbnail: { __typename: "Image" as "Image", url: placeholderImage },
url: "/example-url", url: "/example-url",
variants: [ variants: [

View file

@ -161,38 +161,8 @@ export const useProductVariantSetDefaultMutation = makeMutation<
export const productUpdateMutation = gql` export const productUpdateMutation = gql`
${productErrorFragment} ${productErrorFragment}
${productFragmentDetails} ${productFragmentDetails}
mutation ProductUpdate( mutation ProductUpdate($id: ID!, $input: ProductInput!) {
$id: ID! productUpdate(id: $id, input: $input) {
$attributes: [AttributeValueInput]
$publicationDate: Date
$category: ID
$chargeTaxes: Boolean!
$collections: [ID]
$descriptionJson: JSONString
$isPublished: Boolean!
$name: String
$basePrice: PositiveDecimal
$seo: SeoInput
$slug: String
$visibleInListings: Boolean
) {
productUpdate(
id: $id
input: {
attributes: $attributes
publicationDate: $publicationDate
category: $category
chargeTaxes: $chargeTaxes
collections: $collections
descriptionJson: $descriptionJson
isPublished: $isPublished
name: $name
basePrice: $basePrice
seo: $seo
slug: $slug
visibleInListings: $visibleInListings
}
) {
errors: productErrors { errors: productErrors {
...ProductErrorFragment ...ProductErrorFragment
} }
@ -215,43 +185,14 @@ export const simpleProductUpdateMutation = gql`
${fragmentVariant} ${fragmentVariant}
mutation SimpleProductUpdate( mutation SimpleProductUpdate(
$id: ID! $id: ID!
$attributes: [AttributeValueInput] $input: ProductInput!
$publicationDate: Date
$category: ID
$chargeTaxes: Boolean!
$collections: [ID]
$descriptionJson: JSONString
$isPublished: Boolean!
$name: String
$basePrice: PositiveDecimal
$productVariantId: ID! $productVariantId: ID!
$productVariantInput: ProductVariantInput! $productVariantInput: ProductVariantInput!
$seo: SeoInput
$slug: String
$addStocks: [StockInput!]! $addStocks: [StockInput!]!
$deleteStocks: [ID!]! $deleteStocks: [ID!]!
$updateStocks: [StockInput!]! $updateStocks: [StockInput!]!
$weight: WeightScalar
$visibleInListings: Boolean
) {
productUpdate(
id: $id
input: {
attributes: $attributes
publicationDate: $publicationDate
category: $category
chargeTaxes: $chargeTaxes
collections: $collections
descriptionJson: $descriptionJson
isPublished: $isPublished
name: $name
basePrice: $basePrice
seo: $seo
slug: $slug
weight: $weight
visibleInListings: $visibleInListings
}
) { ) {
productUpdate(id: $id, input: $input) {
errors: productErrors { errors: productErrors {
...ProductErrorFragment ...ProductErrorFragment
} }
@ -310,46 +251,8 @@ export const useSimpleProductUpdateMutation = makeMutation<
export const productCreateMutation = gql` export const productCreateMutation = gql`
${productErrorFragment} ${productErrorFragment}
${productFragmentDetails} ${productFragmentDetails}
mutation ProductCreate( mutation ProductCreate($input: ProductCreateInput!) {
$attributes: [AttributeValueInput] productCreate(input: $input) {
$publicationDate: Date
$category: ID!
$chargeTaxes: Boolean!
$collections: [ID]
$descriptionJson: JSONString
$isPublished: Boolean!
$name: String!
$basePrice: PositiveDecimal
$productType: ID!
$sku: String
$seo: SeoInput
$slug: String
$stocks: [StockInput!]!
$trackInventory: Boolean!
$weight: WeightScalar
$visibleInListings: Boolean
) {
productCreate(
input: {
attributes: $attributes
publicationDate: $publicationDate
category: $category
chargeTaxes: $chargeTaxes
collections: $collections
descriptionJson: $descriptionJson
isPublished: $isPublished
name: $name
basePrice: $basePrice
productType: $productType
sku: $sku
seo: $seo
slug: $slug
stocks: $stocks
trackInventory: $trackInventory
weight: $weight
visibleInListings: $visibleInListings
}
) {
errors: productErrors { errors: productErrors {
...ProductErrorFragment ...ProductErrorFragment
} }

View file

@ -6,6 +6,7 @@ import {
productFragmentDetails, productFragmentDetails,
productVariantAttributesFragment productVariantAttributesFragment
} from "@saleor/fragments/products"; } from "@saleor/fragments/products";
import { taxTypeFragment } from "@saleor/fragments/taxes";
import { warehouseFragment } from "@saleor/fragments/warehouses"; import { warehouseFragment } from "@saleor/fragments/warehouses";
import makeQuery from "@saleor/hooks/makeQuery"; import makeQuery from "@saleor/hooks/makeQuery";
import gql from "graphql-tag"; import gql from "graphql-tag";
@ -166,10 +167,14 @@ export const useCountAllProducts = makeQuery<CountAllProducts, null>(
const productDetailsQuery = gql` const productDetailsQuery = gql`
${productFragmentDetails} ${productFragmentDetails}
${taxTypeFragment}
query ProductDetails($id: ID!) { query ProductDetails($id: ID!) {
product(id: $id) { product(id: $id) {
...Product ...Product
} }
taxTypes {
...TaxTypeFragment
}
} }
`; `;
export const useProductDetails = makeQuery< export const useProductDetails = makeQuery<

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { AttributeValueInput, SeoInput, StockInput, ProductErrorCode, AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTypes"; import { ProductCreateInput, ProductErrorCode, AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: ProductCreate // GraphQL mutation operation: ProductCreate
@ -58,12 +58,19 @@ export interface ProductCreate_productCreate_product_productType_variantAttribut
values: (ProductCreate_productCreate_product_productType_variantAttributes_values | null)[] | null; values: (ProductCreate_productCreate_product_productType_variantAttributes_values | null)[] | null;
} }
export interface ProductCreate_productCreate_product_productType_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductCreate_productCreate_product_productType { export interface ProductCreate_productCreate_product_productType {
__typename: "ProductType"; __typename: "ProductType";
id: string; id: string;
variantAttributes: (ProductCreate_productCreate_product_productType_variantAttributes | null)[] | null; variantAttributes: (ProductCreate_productCreate_product_productType_variantAttributes | null)[] | null;
name: string; name: string;
hasVariants: boolean; hasVariants: boolean;
taxType: ProductCreate_productCreate_product_productType_taxType | null;
} }
export interface ProductCreate_productCreate_product_pricing_priceRangeUndiscounted_start_gross { export interface ProductCreate_productCreate_product_pricing_priceRangeUndiscounted_start_gross {
@ -197,6 +204,12 @@ export interface ProductCreate_productCreate_product_weight {
value: number; value: number;
} }
export interface ProductCreate_productCreate_product_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductCreate_productCreate_product { export interface ProductCreate_productCreate_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -223,6 +236,7 @@ export interface ProductCreate_productCreate_product {
images: (ProductCreate_productCreate_product_images | null)[] | null; images: (ProductCreate_productCreate_product_images | null)[] | null;
variants: (ProductCreate_productCreate_product_variants | null)[] | null; variants: (ProductCreate_productCreate_product_variants | null)[] | null;
weight: ProductCreate_productCreate_product_weight | null; weight: ProductCreate_productCreate_product_weight | null;
taxType: ProductCreate_productCreate_product_taxType | null;
availableForPurchase: any | null; availableForPurchase: any | null;
visibleInListings: boolean; visibleInListings: boolean;
} }
@ -238,21 +252,5 @@ export interface ProductCreate {
} }
export interface ProductCreateVariables { export interface ProductCreateVariables {
attributes?: (AttributeValueInput | null)[] | null; input: ProductCreateInput;
publicationDate?: any | null;
category: string;
chargeTaxes: boolean;
collections?: (string | null)[] | null;
descriptionJson?: any | null;
isPublished: boolean;
name: string;
basePrice?: any | null;
productType: string;
sku?: string | null;
seo?: SeoInput | null;
slug?: string | null;
stocks: StockInput[];
trackInventory: boolean;
weight?: any | null;
visibleInListings?: boolean | null;
} }

View file

@ -52,12 +52,19 @@ export interface ProductDetails_product_productType_variantAttributes {
values: (ProductDetails_product_productType_variantAttributes_values | null)[] | null; values: (ProductDetails_product_productType_variantAttributes_values | null)[] | null;
} }
export interface ProductDetails_product_productType_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductDetails_product_productType { export interface ProductDetails_product_productType {
__typename: "ProductType"; __typename: "ProductType";
id: string; id: string;
variantAttributes: (ProductDetails_product_productType_variantAttributes | null)[] | null; variantAttributes: (ProductDetails_product_productType_variantAttributes | null)[] | null;
name: string; name: string;
hasVariants: boolean; hasVariants: boolean;
taxType: ProductDetails_product_productType_taxType | null;
} }
export interface ProductDetails_product_pricing_priceRangeUndiscounted_start_gross { export interface ProductDetails_product_pricing_priceRangeUndiscounted_start_gross {
@ -191,6 +198,12 @@ export interface ProductDetails_product_weight {
value: number; value: number;
} }
export interface ProductDetails_product_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductDetails_product { export interface ProductDetails_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -217,12 +230,20 @@ export interface ProductDetails_product {
images: (ProductDetails_product_images | null)[] | null; images: (ProductDetails_product_images | null)[] | null;
variants: (ProductDetails_product_variants | null)[] | null; variants: (ProductDetails_product_variants | null)[] | null;
weight: ProductDetails_product_weight | null; weight: ProductDetails_product_weight | null;
taxType: ProductDetails_product_taxType | null;
availableForPurchase: any | null; availableForPurchase: any | null;
visibleInListings: boolean; visibleInListings: boolean;
} }
export interface ProductDetails_taxTypes {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductDetails { export interface ProductDetails {
product: ProductDetails_product | null; product: ProductDetails_product | null;
taxTypes: (ProductDetails_taxTypes | null)[] | null;
} }
export interface ProductDetailsVariables { export interface ProductDetailsVariables {

View file

@ -58,12 +58,19 @@ export interface ProductImageCreate_productImageCreate_product_productType_varia
values: (ProductImageCreate_productImageCreate_product_productType_variantAttributes_values | null)[] | null; values: (ProductImageCreate_productImageCreate_product_productType_variantAttributes_values | null)[] | null;
} }
export interface ProductImageCreate_productImageCreate_product_productType_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductImageCreate_productImageCreate_product_productType { export interface ProductImageCreate_productImageCreate_product_productType {
__typename: "ProductType"; __typename: "ProductType";
id: string; id: string;
variantAttributes: (ProductImageCreate_productImageCreate_product_productType_variantAttributes | null)[] | null; variantAttributes: (ProductImageCreate_productImageCreate_product_productType_variantAttributes | null)[] | null;
name: string; name: string;
hasVariants: boolean; hasVariants: boolean;
taxType: ProductImageCreate_productImageCreate_product_productType_taxType | null;
} }
export interface ProductImageCreate_productImageCreate_product_pricing_priceRangeUndiscounted_start_gross { export interface ProductImageCreate_productImageCreate_product_pricing_priceRangeUndiscounted_start_gross {
@ -197,6 +204,12 @@ export interface ProductImageCreate_productImageCreate_product_weight {
value: number; value: number;
} }
export interface ProductImageCreate_productImageCreate_product_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductImageCreate_productImageCreate_product { export interface ProductImageCreate_productImageCreate_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -223,6 +236,7 @@ export interface ProductImageCreate_productImageCreate_product {
images: (ProductImageCreate_productImageCreate_product_images | null)[] | null; images: (ProductImageCreate_productImageCreate_product_images | null)[] | null;
variants: (ProductImageCreate_productImageCreate_product_variants | null)[] | null; variants: (ProductImageCreate_productImageCreate_product_variants | null)[] | null;
weight: ProductImageCreate_productImageCreate_product_weight | null; weight: ProductImageCreate_productImageCreate_product_weight | null;
taxType: ProductImageCreate_productImageCreate_product_taxType | null;
availableForPurchase: any | null; availableForPurchase: any | null;
visibleInListings: boolean; visibleInListings: boolean;
} }

View file

@ -58,12 +58,19 @@ export interface ProductImageUpdate_productImageUpdate_product_productType_varia
values: (ProductImageUpdate_productImageUpdate_product_productType_variantAttributes_values | null)[] | null; values: (ProductImageUpdate_productImageUpdate_product_productType_variantAttributes_values | null)[] | null;
} }
export interface ProductImageUpdate_productImageUpdate_product_productType_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductImageUpdate_productImageUpdate_product_productType { export interface ProductImageUpdate_productImageUpdate_product_productType {
__typename: "ProductType"; __typename: "ProductType";
id: string; id: string;
variantAttributes: (ProductImageUpdate_productImageUpdate_product_productType_variantAttributes | null)[] | null; variantAttributes: (ProductImageUpdate_productImageUpdate_product_productType_variantAttributes | null)[] | null;
name: string; name: string;
hasVariants: boolean; hasVariants: boolean;
taxType: ProductImageUpdate_productImageUpdate_product_productType_taxType | null;
} }
export interface ProductImageUpdate_productImageUpdate_product_pricing_priceRangeUndiscounted_start_gross { export interface ProductImageUpdate_productImageUpdate_product_pricing_priceRangeUndiscounted_start_gross {
@ -197,6 +204,12 @@ export interface ProductImageUpdate_productImageUpdate_product_weight {
value: number; value: number;
} }
export interface ProductImageUpdate_productImageUpdate_product_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductImageUpdate_productImageUpdate_product { export interface ProductImageUpdate_productImageUpdate_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -223,6 +236,7 @@ export interface ProductImageUpdate_productImageUpdate_product {
images: (ProductImageUpdate_productImageUpdate_product_images | null)[] | null; images: (ProductImageUpdate_productImageUpdate_product_images | null)[] | null;
variants: (ProductImageUpdate_productImageUpdate_product_variants | null)[] | null; variants: (ProductImageUpdate_productImageUpdate_product_variants | null)[] | null;
weight: ProductImageUpdate_productImageUpdate_product_weight | null; weight: ProductImageUpdate_productImageUpdate_product_weight | null;
taxType: ProductImageUpdate_productImageUpdate_product_taxType | null;
availableForPurchase: any | null; availableForPurchase: any | null;
visibleInListings: boolean; visibleInListings: boolean;
} }

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { AttributeValueInput, SeoInput, ProductErrorCode, AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTypes"; import { ProductInput, ProductErrorCode, AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: ProductUpdate // GraphQL mutation operation: ProductUpdate
@ -58,12 +58,19 @@ export interface ProductUpdate_productUpdate_product_productType_variantAttribut
values: (ProductUpdate_productUpdate_product_productType_variantAttributes_values | null)[] | null; values: (ProductUpdate_productUpdate_product_productType_variantAttributes_values | null)[] | null;
} }
export interface ProductUpdate_productUpdate_product_productType_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductUpdate_productUpdate_product_productType { export interface ProductUpdate_productUpdate_product_productType {
__typename: "ProductType"; __typename: "ProductType";
id: string; id: string;
variantAttributes: (ProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; variantAttributes: (ProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null;
name: string; name: string;
hasVariants: boolean; hasVariants: boolean;
taxType: ProductUpdate_productUpdate_product_productType_taxType | null;
} }
export interface ProductUpdate_productUpdate_product_pricing_priceRangeUndiscounted_start_gross { export interface ProductUpdate_productUpdate_product_pricing_priceRangeUndiscounted_start_gross {
@ -197,6 +204,12 @@ export interface ProductUpdate_productUpdate_product_weight {
value: number; value: number;
} }
export interface ProductUpdate_productUpdate_product_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductUpdate_productUpdate_product { export interface ProductUpdate_productUpdate_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -223,6 +236,7 @@ export interface ProductUpdate_productUpdate_product {
images: (ProductUpdate_productUpdate_product_images | null)[] | null; images: (ProductUpdate_productUpdate_product_images | null)[] | null;
variants: (ProductUpdate_productUpdate_product_variants | null)[] | null; variants: (ProductUpdate_productUpdate_product_variants | null)[] | null;
weight: ProductUpdate_productUpdate_product_weight | null; weight: ProductUpdate_productUpdate_product_weight | null;
taxType: ProductUpdate_productUpdate_product_taxType | null;
availableForPurchase: any | null; availableForPurchase: any | null;
visibleInListings: boolean; visibleInListings: boolean;
} }
@ -239,16 +253,5 @@ export interface ProductUpdate {
export interface ProductUpdateVariables { export interface ProductUpdateVariables {
id: string; id: string;
attributes?: (AttributeValueInput | null)[] | null; input: ProductInput;
publicationDate?: any | null;
category?: string | null;
chargeTaxes: boolean;
collections?: (string | null)[] | null;
descriptionJson?: any | null;
isPublished: boolean;
name?: string | null;
basePrice?: any | null;
seo?: SeoInput | null;
slug?: string | null;
visibleInListings?: boolean | null;
} }

View file

@ -58,12 +58,19 @@ export interface ProductVariantReorder_productVariantReorder_product_productType
values: (ProductVariantReorder_productVariantReorder_product_productType_variantAttributes_values | null)[] | null; values: (ProductVariantReorder_productVariantReorder_product_productType_variantAttributes_values | null)[] | null;
} }
export interface ProductVariantReorder_productVariantReorder_product_productType_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductVariantReorder_productVariantReorder_product_productType { export interface ProductVariantReorder_productVariantReorder_product_productType {
__typename: "ProductType"; __typename: "ProductType";
id: string; id: string;
variantAttributes: (ProductVariantReorder_productVariantReorder_product_productType_variantAttributes | null)[] | null; variantAttributes: (ProductVariantReorder_productVariantReorder_product_productType_variantAttributes | null)[] | null;
name: string; name: string;
hasVariants: boolean; hasVariants: boolean;
taxType: ProductVariantReorder_productVariantReorder_product_productType_taxType | null;
} }
export interface ProductVariantReorder_productVariantReorder_product_pricing_priceRangeUndiscounted_start_gross { export interface ProductVariantReorder_productVariantReorder_product_pricing_priceRangeUndiscounted_start_gross {
@ -197,6 +204,12 @@ export interface ProductVariantReorder_productVariantReorder_product_weight {
value: number; value: number;
} }
export interface ProductVariantReorder_productVariantReorder_product_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductVariantReorder_productVariantReorder_product { export interface ProductVariantReorder_productVariantReorder_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -223,6 +236,7 @@ export interface ProductVariantReorder_productVariantReorder_product {
images: (ProductVariantReorder_productVariantReorder_product_images | null)[] | null; images: (ProductVariantReorder_productVariantReorder_product_images | null)[] | null;
variants: (ProductVariantReorder_productVariantReorder_product_variants | null)[] | null; variants: (ProductVariantReorder_productVariantReorder_product_variants | null)[] | null;
weight: ProductVariantReorder_productVariantReorder_product_weight | null; weight: ProductVariantReorder_productVariantReorder_product_weight | null;
taxType: ProductVariantReorder_productVariantReorder_product_taxType | null;
availableForPurchase: any | null; availableForPurchase: any | null;
visibleInListings: boolean; visibleInListings: boolean;
} }

View file

@ -58,12 +58,19 @@ export interface ProductVariantSetDefault_productVariantSetDefault_product_produ
values: (ProductVariantSetDefault_productVariantSetDefault_product_productType_variantAttributes_values | null)[] | null; values: (ProductVariantSetDefault_productVariantSetDefault_product_productType_variantAttributes_values | null)[] | null;
} }
export interface ProductVariantSetDefault_productVariantSetDefault_product_productType_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductVariantSetDefault_productVariantSetDefault_product_productType { export interface ProductVariantSetDefault_productVariantSetDefault_product_productType {
__typename: "ProductType"; __typename: "ProductType";
id: string; id: string;
variantAttributes: (ProductVariantSetDefault_productVariantSetDefault_product_productType_variantAttributes | null)[] | null; variantAttributes: (ProductVariantSetDefault_productVariantSetDefault_product_productType_variantAttributes | null)[] | null;
name: string; name: string;
hasVariants: boolean; hasVariants: boolean;
taxType: ProductVariantSetDefault_productVariantSetDefault_product_productType_taxType | null;
} }
export interface ProductVariantSetDefault_productVariantSetDefault_product_pricing_priceRangeUndiscounted_start_gross { export interface ProductVariantSetDefault_productVariantSetDefault_product_pricing_priceRangeUndiscounted_start_gross {
@ -197,6 +204,12 @@ export interface ProductVariantSetDefault_productVariantSetDefault_product_weigh
value: number; value: number;
} }
export interface ProductVariantSetDefault_productVariantSetDefault_product_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface ProductVariantSetDefault_productVariantSetDefault_product { export interface ProductVariantSetDefault_productVariantSetDefault_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -206,6 +219,7 @@ export interface ProductVariantSetDefault_productVariantSetDefault_product {
metadata: (ProductVariantSetDefault_productVariantSetDefault_product_metadata | null)[]; metadata: (ProductVariantSetDefault_productVariantSetDefault_product_metadata | null)[];
privateMetadata: (ProductVariantSetDefault_productVariantSetDefault_product_privateMetadata | null)[]; privateMetadata: (ProductVariantSetDefault_productVariantSetDefault_product_privateMetadata | null)[];
name: string; name: string;
slug: string;
descriptionJson: any; descriptionJson: any;
seoTitle: string | null; seoTitle: string | null;
seoDescription: string | null; seoDescription: string | null;
@ -222,6 +236,7 @@ export interface ProductVariantSetDefault_productVariantSetDefault_product {
images: (ProductVariantSetDefault_productVariantSetDefault_product_images | null)[] | null; images: (ProductVariantSetDefault_productVariantSetDefault_product_images | null)[] | null;
variants: (ProductVariantSetDefault_productVariantSetDefault_product_variants | null)[] | null; variants: (ProductVariantSetDefault_productVariantSetDefault_product_variants | null)[] | null;
weight: ProductVariantSetDefault_productVariantSetDefault_product_weight | null; weight: ProductVariantSetDefault_productVariantSetDefault_product_weight | null;
taxType: ProductVariantSetDefault_productVariantSetDefault_product_taxType | null;
availableForPurchase: any | null; availableForPurchase: any | null;
visibleInListings: boolean; visibleInListings: boolean;
} }

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { AttributeValueInput, ProductVariantInput, SeoInput, StockInput, ProductErrorCode, AttributeInputTypeEnum, WeightUnitsEnum, StockErrorCode } from "./../../types/globalTypes"; import { ProductInput, ProductVariantInput, StockInput, ProductErrorCode, AttributeInputTypeEnum, WeightUnitsEnum, StockErrorCode } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: SimpleProductUpdate // GraphQL mutation operation: SimpleProductUpdate
@ -58,12 +58,19 @@ export interface SimpleProductUpdate_productUpdate_product_productType_variantAt
values: (SimpleProductUpdate_productUpdate_product_productType_variantAttributes_values | null)[] | null; values: (SimpleProductUpdate_productUpdate_product_productType_variantAttributes_values | null)[] | null;
} }
export interface SimpleProductUpdate_productUpdate_product_productType_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface SimpleProductUpdate_productUpdate_product_productType { export interface SimpleProductUpdate_productUpdate_product_productType {
__typename: "ProductType"; __typename: "ProductType";
id: string; id: string;
variantAttributes: (SimpleProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; variantAttributes: (SimpleProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null;
name: string; name: string;
hasVariants: boolean; hasVariants: boolean;
taxType: SimpleProductUpdate_productUpdate_product_productType_taxType | null;
} }
export interface SimpleProductUpdate_productUpdate_product_pricing_priceRangeUndiscounted_start_gross { export interface SimpleProductUpdate_productUpdate_product_pricing_priceRangeUndiscounted_start_gross {
@ -197,6 +204,12 @@ export interface SimpleProductUpdate_productUpdate_product_weight {
value: number; value: number;
} }
export interface SimpleProductUpdate_productUpdate_product_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface SimpleProductUpdate_productUpdate_product { export interface SimpleProductUpdate_productUpdate_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -223,6 +236,7 @@ export interface SimpleProductUpdate_productUpdate_product {
images: (SimpleProductUpdate_productUpdate_product_images | null)[] | null; images: (SimpleProductUpdate_productUpdate_product_images | null)[] | null;
variants: (SimpleProductUpdate_productUpdate_product_variants | null)[] | null; variants: (SimpleProductUpdate_productUpdate_product_variants | null)[] | null;
weight: SimpleProductUpdate_productUpdate_product_weight | null; weight: SimpleProductUpdate_productUpdate_product_weight | null;
taxType: SimpleProductUpdate_productUpdate_product_taxType | null;
availableForPurchase: any | null; availableForPurchase: any | null;
visibleInListings: boolean; visibleInListings: boolean;
} }
@ -821,22 +835,10 @@ export interface SimpleProductUpdate {
export interface SimpleProductUpdateVariables { export interface SimpleProductUpdateVariables {
id: string; id: string;
attributes?: (AttributeValueInput | null)[] | null; input: ProductInput;
publicationDate?: any | null;
category?: string | null;
chargeTaxes: boolean;
collections?: (string | null)[] | null;
descriptionJson?: any | null;
isPublished: boolean;
name?: string | null;
basePrice?: any | null;
productVariantId: string; productVariantId: string;
productVariantInput: ProductVariantInput; productVariantInput: ProductVariantInput;
seo?: SeoInput | null;
slug?: string | null;
addStocks: StockInput[]; addStocks: StockInput[];
deleteStocks: string[]; deleteStocks: string[];
updateStocks: StockInput[]; updateStocks: StockInput[];
weight?: any | null;
visibleInListings?: boolean | null;
} }

View file

@ -174,11 +174,12 @@ export interface ProductUpdatePageFormData extends MetadataFormData {
availableForPurchase: string; availableForPurchase: string;
basePrice: number; basePrice: number;
category: string | null; category: string | null;
collections: string[]; changeTaxCode: boolean;
chargeTaxes: boolean; chargeTaxes: boolean;
collections: string[];
description: RawDraftContentState; description: RawDraftContentState;
isAvailableForPurchase: boolean;
isAvailable: boolean; isAvailable: boolean;
isAvailableForPurchase: boolean;
isPublished: boolean; isPublished: boolean;
name: string; name: string;
slug: string; slug: string;
@ -186,9 +187,10 @@ export interface ProductUpdatePageFormData extends MetadataFormData {
seoDescription: string; seoDescription: string;
seoTitle: string; seoTitle: string;
sku: string; sku: string;
taxCode: string;
trackInventory: boolean; trackInventory: boolean;
weight: string;
visibleInListings: boolean; visibleInListings: boolean;
weight: string;
} }
export function getProductUpdatePageFormData( export function getProductUpdatePageFormData(
@ -199,6 +201,7 @@ export function getProductUpdatePageFormData(
availableForPurchase: product?.availableForPurchase, availableForPurchase: product?.availableForPurchase,
basePrice: maybe(() => product.variants[0].price.amount, 0), basePrice: maybe(() => product.variants[0].price.amount, 0),
category: maybe(() => product.category.id, ""), category: maybe(() => product.category.id, ""),
changeTaxCode: !!product?.taxType.taxCode,
chargeTaxes: maybe(() => product.chargeTaxes, false), chargeTaxes: maybe(() => product.chargeTaxes, false),
collections: maybe( collections: maybe(
() => product.collections.map(collection => collection.id), () => product.collections.map(collection => collection.id),
@ -224,6 +227,7 @@ export function getProductUpdatePageFormData(
"" ""
), ),
slug: product?.slug || "", slug: product?.slug || "",
taxCode: product?.taxType.taxCode,
trackInventory: !!product?.variants[0]?.trackInventory, trackInventory: !!product?.variants[0]?.trackInventory,
visibleInListings: !!product?.visibleInListings, visibleInListings: !!product?.visibleInListings,
weight: product?.weight?.value.toString() || "" weight: product?.weight?.value.toString() || ""

View file

@ -7,6 +7,7 @@ import { getProductAvailabilityVariables } from "@saleor/products/utils/handlers
import useCategorySearch from "@saleor/searches/useCategorySearch"; import useCategorySearch from "@saleor/searches/useCategorySearch";
import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import useCollectionSearch from "@saleor/searches/useCollectionSearch";
import useProductTypeSearch from "@saleor/searches/useProductTypeSearch"; import useProductTypeSearch from "@saleor/searches/useProductTypeSearch";
import { useTaxTypeList } from "@saleor/taxes/queries";
import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler";
import { import {
useMetadataUpdate, useMetadataUpdate,
@ -60,6 +61,7 @@ export const ProductCreateView: React.FC = () => {
}); });
const [updateMetadata] = useMetadataUpdate({}); const [updateMetadata] = useMetadataUpdate({});
const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); const [updatePrivateMetadata] = usePrivateMetadataUpdate({});
const taxTypes = useTaxTypeList({});
const handleBack = () => navigate(productListUrl()); const handleBack = () => navigate(productListUrl());
@ -91,6 +93,7 @@ export const ProductCreateView: React.FC = () => {
const handleCreate = async (formData: ProductCreatePageSubmitData) => { const handleCreate = async (formData: ProductCreatePageSubmitData) => {
const result = await productCreate({ const result = await productCreate({
variables: { variables: {
input: {
attributes: formData.attributes.map(attribute => ({ attributes: formData.attributes.map(attribute => ({
id: attribute.id, id: attribute.id,
values: attribute.value values: attribute.value
@ -115,10 +118,12 @@ export const ProductCreateView: React.FC = () => {
quantity: parseInt(stock.value, 0), quantity: parseInt(stock.value, 0),
warehouse: stock.id warehouse: stock.id
})), })),
taxCode: formData.changeTaxCode ? formData.taxCode : undefined,
trackInventory: formData.trackInventory, trackInventory: formData.trackInventory,
visibleInListings: formData.visibleInListings, visibleInListings: formData.visibleInListings,
weight: weight(formData.weight) weight: weight(formData.weight)
} }
}
}); });
const productId = result.data.productCreate?.product?.id; const productId = result.data.productCreate?.product?.id;
@ -194,6 +199,7 @@ export const ProductCreateView: React.FC = () => {
warehouses={ warehouses={
warehouses.data?.warehouses.edges.map(edge => edge.node) || [] warehouses.data?.warehouses.edges.map(edge => edge.node) || []
} }
taxTypes={taxTypes.data?.taxTypes || []}
weightUnit={shop?.defaultWeightUnit} weightUnit={shop?.defaultWeightUnit}
/> />
</> </>

View file

@ -298,6 +298,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
warehouses={ warehouses={
warehouses.data?.warehouses.edges.map(edge => edge.node) || [] warehouses.data?.warehouses.edges.map(edge => edge.node) || []
} }
taxTypes={data?.taxTypes}
variants={maybe(() => product.variants)} variants={maybe(() => product.variants)}
onBack={handleBack} onBack={handleBack}
onDelete={() => openModal("remove")} onDelete={() => openModal("remove")}

View file

@ -41,6 +41,8 @@ export function createUpdateHandler(
) { ) {
return async (data: ProductUpdatePageSubmitData) => { return async (data: ProductUpdatePageSubmitData) => {
const productVariables: ProductUpdateVariables = { const productVariables: ProductUpdateVariables = {
id: product.id,
input: {
attributes: data.attributes.map(attribute => ({ attributes: data.attributes.map(attribute => ({
id: attribute.id, id: attribute.id,
values: attribute.value[0] === "" ? [] : attribute.value values: attribute.value[0] === "" ? [] : attribute.value
@ -50,7 +52,6 @@ export function createUpdateHandler(
chargeTaxes: data.chargeTaxes, chargeTaxes: data.chargeTaxes,
collections: data.collections, collections: data.collections,
descriptionJson: JSON.stringify(data.description), descriptionJson: JSON.stringify(data.description),
id: product.id,
isPublished: data.isPublished, isPublished: data.isPublished,
name: data.name, name: data.name,
publicationDate: publicationDate:
@ -60,7 +61,9 @@ export function createUpdateHandler(
title: data.seoTitle title: data.seoTitle
}, },
slug: data.slug, slug: data.slug,
taxCode: data.changeTaxCode ? data.taxCode : null,
visibleInListings: data.visibleInListings visibleInListings: data.visibleInListings
}
}; };
let errors: Array< let errors: Array<
@ -75,13 +78,16 @@ export function createUpdateHandler(
...productVariables, ...productVariables,
addStocks: data.addStocks.map(mapFormsetStockToStockInput), addStocks: data.addStocks.map(mapFormsetStockToStockInput),
deleteStocks: data.removeStocks, deleteStocks: data.removeStocks,
input: {
...productVariables.input,
weight: weight(data.weight)
},
productVariantId: product.variants[0].id, productVariantId: product.variants[0].id,
productVariantInput: { productVariantInput: {
sku: data.sku, sku: data.sku,
trackInventory: data.trackInventory trackInventory: data.trackInventory
}, },
updateStocks: data.updateStocks.map(mapFormsetStockToStockInput), updateStocks: data.updateStocks.map(mapFormsetStockToStockInput)
weight: weight(data.weight)
}); });
errors = [ errors = [
...result.data.productUpdate.errors, ...result.data.productUpdate.errors,

View file

@ -25,12 +25,19 @@ export interface SearchProductTypes_search_edges_node_productAttributes {
values: (SearchProductTypes_search_edges_node_productAttributes_values | null)[] | null; values: (SearchProductTypes_search_edges_node_productAttributes_values | null)[] | null;
} }
export interface SearchProductTypes_search_edges_node_taxType {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface SearchProductTypes_search_edges_node { export interface SearchProductTypes_search_edges_node {
__typename: "ProductType"; __typename: "ProductType";
id: string; id: string;
name: string; name: string;
hasVariants: boolean; hasVariants: boolean;
productAttributes: (SearchProductTypes_search_edges_node_productAttributes | null)[] | null; productAttributes: (SearchProductTypes_search_edges_node_productAttributes | null)[] | null;
taxType: SearchProductTypes_search_edges_node_taxType | null;
} }
export interface SearchProductTypes_search_edges { export interface SearchProductTypes_search_edges {

View file

@ -1,4 +1,5 @@
import { pageInfoFragment } from "@saleor/fragments/pageInfo"; import { pageInfoFragment } from "@saleor/fragments/pageInfo";
import { taxTypeFragment } from "@saleor/fragments/taxes";
import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch";
import gql from "graphql-tag"; import gql from "graphql-tag";
@ -9,6 +10,7 @@ import {
export const searchProductTypes = gql` export const searchProductTypes = gql`
${pageInfoFragment} ${pageInfoFragment}
${taxTypeFragment}
query SearchProductTypes($after: String, $first: Int!, $query: String!) { query SearchProductTypes($after: String, $first: Int!, $query: String!) {
search: productTypes( search: productTypes(
after: $after after: $after
@ -32,6 +34,9 @@ export const searchProductTypes = gql`
slug slug
} }
} }
taxType {
...TaxTypeFragment
}
} }
} }
pageInfo { pageInfo {

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,7 @@ import ProductCreatePage, {
import { product as productFixture } from "../../../products/fixtures"; import { product as productFixture } from "../../../products/fixtures";
import { productTypes } from "../../../productTypes/fixtures"; import { productTypes } from "../../../productTypes/fixtures";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
import { taxTypes } from "../taxes/fixtures";
const product = productFixture(""); const product = productFixture("");
@ -34,6 +35,7 @@ storiesOf("Views / Products / Create product", module)
onSubmit={() => undefined} onSubmit={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={warehouseList} warehouses={warehouseList}
taxTypes={taxTypes}
weightUnit="kg" weightUnit="kg"
/> />
)) ))
@ -56,6 +58,7 @@ storiesOf("Views / Products / Create product", module)
onSubmit={() => undefined} onSubmit={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={undefined} warehouses={undefined}
taxTypes={taxTypes}
weightUnit="kg" weightUnit="kg"
/> />
)) ))
@ -84,6 +87,7 @@ storiesOf("Views / Products / Create product", module)
onSubmit={() => undefined} onSubmit={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={warehouseList} warehouses={warehouseList}
taxTypes={taxTypes}
weightUnit="kg" weightUnit="kg"
/> />
)); ));

View file

@ -12,6 +12,7 @@ import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
import { taxTypes } from "../taxes/fixtures";
const product = productFixture(placeholderImage); const product = productFixture(placeholderImage);
@ -41,6 +42,7 @@ const props: ProductUpdatePageProps = {
placeholderImage, placeholderImage,
product, product,
saveButtonBarState: "default", saveButtonBarState: "default",
taxTypes,
variants: product.variants, variants: product.variants,
warehouses: warehouseList warehouses: warehouseList
}; };

View file

@ -1,3 +1,5 @@
import { TaxTypeFragment } from "@saleor/fragments/types/TaxTypeFragment";
import { CountryList_shop_countries } from "../../../taxes/types/CountryList"; import { CountryList_shop_countries } from "../../../taxes/types/CountryList";
import { TaxRateType } from "../../../types/globalTypes"; import { TaxRateType } from "../../../types/globalTypes";
@ -2714,3 +2716,84 @@ export const countries: CountryList = [
vat: null vat: null
} }
].filter(country => country.vat); ].filter(country => country.vat);
/* eslint-disable sort-keys */
export const taxTypes: TaxTypeFragment[] = [
{
description: "accommodation",
taxCode: "accommodation",
__typename: "TaxType"
},
{
description: "admission to cultural events",
taxCode: "admission to cultural events",
__typename: "TaxType"
},
{
description: "admission to entertainment events",
taxCode: "admission to entertainment events",
__typename: "TaxType"
},
{
description: "admission to sporting events",
taxCode: "admission to sporting events",
__typename: "TaxType"
},
{ description: "advertising", taxCode: "advertising", __typename: "TaxType" },
{
description: "agricultural supplies",
taxCode: "agricultural supplies",
__typename: "TaxType"
},
{
description: "baby foodstuffs",
taxCode: "baby foodstuffs",
__typename: "TaxType"
},
{ description: "bikes", taxCode: "bikes", __typename: "TaxType" },
{ description: "books", taxCode: "books", __typename: "TaxType" },
{
description: "childrens clothing",
taxCode: "childrens clothing",
__typename: "TaxType"
},
{
description: "domestic fuel",
taxCode: "domestic fuel",
__typename: "TaxType"
},
{
description: "domestic services",
taxCode: "domestic services",
__typename: "TaxType"
},
{ description: "e-books", taxCode: "e-books", __typename: "TaxType" },
{ description: "foodstuffs", taxCode: "foodstuffs", __typename: "TaxType" },
{ description: "hotels", taxCode: "hotels", __typename: "TaxType" },
{ description: "medical", taxCode: "medical", __typename: "TaxType" },
{ description: "newspapers", taxCode: "newspapers", __typename: "TaxType" },
{
description: "passenger transport",
taxCode: "passenger transport",
__typename: "TaxType"
},
{
description: "pharmaceuticals",
taxCode: "pharmaceuticals",
__typename: "TaxType"
},
{
description: "property renovations",
taxCode: "property renovations",
__typename: "TaxType"
},
{ description: "restaurants", taxCode: "restaurants", __typename: "TaxType" },
{
description: "social housing",
taxCode: "social housing",
__typename: "TaxType"
},
{ description: "standard", taxCode: "standard", __typename: "TaxType" },
{ description: "water", taxCode: "water", __typename: "TaxType" },
{ description: "wine", taxCode: "wine", __typename: "TaxType" }
];

View file

@ -1,11 +1,14 @@
import { import {
countryWithTaxesFragment, countryWithTaxesFragment,
shopTaxesFragment shopTaxesFragment,
taxTypeFragment
} from "@saleor/fragments/taxes"; } from "@saleor/fragments/taxes";
import makeQuery from "@saleor/hooks/makeQuery";
import gql from "graphql-tag"; import gql from "graphql-tag";
import { TypedQuery } from "../queries"; import { TypedQuery } from "../queries";
import { CountryList } from "./types/CountryList"; import { CountryList } from "./types/CountryList";
import { TaxTypeList } from "./types/TaxTypeList";
const countryList = gql` const countryList = gql`
${countryWithTaxesFragment} ${countryWithTaxesFragment}
@ -20,3 +23,13 @@ const countryList = gql`
} }
`; `;
export const TypedCountryListQuery = TypedQuery<CountryList, {}>(countryList); export const TypedCountryListQuery = TypedQuery<CountryList, {}>(countryList);
const taxTypeList = gql`
${taxTypeFragment}
query TaxTypeList {
taxTypes {
...TaxTypeFragment
}
}
`;
export const useTaxTypeList = makeQuery<TaxTypeList, {}>(taxTypeList);

View file

@ -0,0 +1,17 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: TaxTypeList
// ====================================================
export interface TaxTypeList_taxTypes {
__typename: "TaxType";
description: string | null;
taxCode: string | null;
}
export interface TaxTypeList {
taxTypes: (TaxTypeList_taxTypes | null)[] | null;
}

View file

@ -1341,6 +1341,28 @@ export interface PriceRangeInput {
lte?: number | null; lte?: number | null;
} }
export interface ProductCreateInput {
attributes?: (AttributeValueInput | null)[] | null;
publicationDate?: any | null;
category?: string | null;
chargeTaxes?: boolean | null;
collections?: (string | null)[] | null;
description?: string | null;
descriptionJson?: any | null;
isPublished?: boolean | null;
name?: string | null;
slug?: string | null;
taxCode?: string | null;
seo?: SeoInput | null;
weight?: any | null;
sku?: string | null;
trackInventory?: boolean | null;
basePrice?: any | null;
visibleInListings?: boolean | null;
productType: string;
stocks?: StockInput[] | null;
}
export interface ProductFilterInput { export interface ProductFilterInput {
isPublished?: boolean | null; isPublished?: boolean | null;
collections?: (string | null)[] | null; collections?: (string | null)[] | null;
@ -1356,6 +1378,26 @@ export interface ProductFilterInput {
productTypes?: (string | null)[] | null; productTypes?: (string | null)[] | null;
} }
export interface ProductInput {
attributes?: (AttributeValueInput | null)[] | null;
publicationDate?: any | null;
category?: string | null;
chargeTaxes?: boolean | null;
collections?: (string | null)[] | null;
description?: string | null;
descriptionJson?: any | null;
isPublished?: boolean | null;
name?: string | null;
slug?: string | null;
taxCode?: string | null;
seo?: SeoInput | null;
weight?: any | null;
sku?: string | null;
trackInventory?: boolean | null;
basePrice?: any | null;
visibleInListings?: boolean | null;
}
export interface ProductOrder { export interface ProductOrder {
direction: OrderDirection; direction: OrderDirection;
attributeId?: string | null; attributeId?: string | null;

View file

@ -7,6 +7,9 @@ import { defineMessages, IntlShape } from "react-intl";
import commonErrorMessages from "./common"; import commonErrorMessages from "./common";
const messages = defineMessages({ const messages = defineMessages({
alreadyExists: {
defaultMessage: "A product with this SKU already exists"
},
attributeAlreadyAssigned: { attributeAlreadyAssigned: {
defaultMessage: defaultMessage:
"This attribute has already been assigned to this product type" "This attribute has already been assigned to this product type"
@ -48,6 +51,8 @@ function getProductErrorMessage(
switch (err.code) { switch (err.code) {
case ProductErrorCode.ATTRIBUTE_ALREADY_ASSIGNED: case ProductErrorCode.ATTRIBUTE_ALREADY_ASSIGNED:
return intl.formatMessage(messages.attributeAlreadyAssigned); return intl.formatMessage(messages.attributeAlreadyAssigned);
case ProductErrorCode.ALREADY_EXISTS:
return intl.formatMessage(messages.alreadyExists);
case ProductErrorCode.ATTRIBUTE_CANNOT_BE_ASSIGNED: case ProductErrorCode.ATTRIBUTE_CANNOT_BE_ASSIGNED:
return intl.formatMessage(messages.attributeCannotBeAssigned); return intl.formatMessage(messages.attributeCannotBeAssigned);
case ProductErrorCode.ATTRIBUTE_VARIANTS_DISABLED: case ProductErrorCode.ATTRIBUTE_VARIANTS_DISABLED: