diff --git a/CHANGELOG.md b/CHANGELOG.md index 03e918fea..02a15aca9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 - Change plural form of "informations" to "information" strings across the app #722 by @mmarkusik - Fix misaligned rich text draft controls - #725 by @orzechdev +- Allow taxes to be configured per product - #728 by @dominik-zeglen ## 2.10.1 diff --git a/locale/defaultMessages.json b/locale/defaultMessages.json index c8e658d8e..117394cfc 100644 --- a/locale/defaultMessages.json +++ b/locale/defaultMessages.json @@ -4318,9 +4318,6 @@ "context": "product 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": { "context": "product shipping", "string": "Shipping" @@ -4355,6 +4352,18 @@ "src_dot_products_dot_components_dot_ProductStocks_dot_849869830": { "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": { "context": "product publication date label", "string": "will become published on {date}" diff --git a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx index bca5ac905..a7913a898 100644 --- a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx +++ b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx @@ -3,6 +3,7 @@ import { makeStyles } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { FetchMoreProps } from "@saleor/types"; +import classNames from "classnames"; import Downshift from "downshift"; import { filter } from "fuzzaldrin"; import React from "react"; @@ -27,6 +28,7 @@ const useStyles = makeStyles( export interface SingleAutocompleteSelectFieldProps extends Partial { add?: SingleAutocompleteActionType; + className?: string; error?: boolean; name: string; displayValue: string; @@ -51,6 +53,7 @@ const SingleAutocompleteSelectFieldComponent: React.FC +
= props => { const { add, @@ -147,6 +149,7 @@ const SingleAutocompleteSelectFieldContent: React.FC(); const scrollPosition = useElementScroll(anchor); const [calledForMore, setCalledForMore] = React.useState(false); + const [slice, setSlice] = React.useState(sliceSize); const scrolledToBottom = isScrolledToBottom(anchor, scrollPosition, offset); @@ -154,9 +157,18 @@ const SingleAutocompleteSelectFieldContent: React.FC slice + sliceSize); } }, [scrolledToBottom]); + React.useEffect(() => { + setSlice(sliceSize); + anchor.current.scrollTo({ + top: 0 + }); + }, [choices?.length]); + React.useEffect(() => { if (calledForMore && !loading) { setCalledForMore(false); @@ -219,7 +231,7 @@ const SingleAutocompleteSelectFieldContent: React.FC 0 && (!!add || displayCustomValue) && (
)} - {choices.map((suggestion, index) => { + {choices.slice(0, slice).map((suggestion, index) => { const choiceIndex = getChoiceIndex( index, emptyOption, diff --git a/src/fragments/products.ts b/src/fragments/products.ts index 50f94cff4..71ecbccfd 100644 --- a/src/fragments/products.ts +++ b/src/fragments/products.ts @@ -1,6 +1,7 @@ import gql from "graphql-tag"; import { metadataFragment } from "./metadata"; +import { taxTypeFragment } from "./taxes"; import { weightFragment } from "./weight"; export const stockFragment = gql` @@ -107,6 +108,7 @@ export const productFragmentDetails = gql` ${stockFragment} ${weightFragment} ${metadataFragment} + ${taxTypeFragment} fragment Product on Product { ...ProductVariantAttributesFragment ...MetadataFragment @@ -177,10 +179,16 @@ export const productFragmentDetails = gql` id name hasVariants + taxType { + ...TaxTypeFragment + } } weight { ...WeightFragment } + taxType { + ...TaxTypeFragment + } availableForPurchase visibleInListings } diff --git a/src/fragments/taxes.ts b/src/fragments/taxes.ts index 026bc00f4..16f8ed96e 100644 --- a/src/fragments/taxes.ts +++ b/src/fragments/taxes.ts @@ -26,3 +26,9 @@ export const shopTaxesFragment = gql` displayGrossPrices } `; +export const taxTypeFragment = gql` + fragment TaxTypeFragment on TaxType { + description + taxCode + } +`; diff --git a/src/fragments/types/Product.ts b/src/fragments/types/Product.ts index add3d5cfe..203e734a9 100644 --- a/src/fragments/types/Product.ts +++ b/src/fragments/types/Product.ts @@ -52,12 +52,19 @@ export interface Product_productType_variantAttributes { values: (Product_productType_variantAttributes_values | null)[] | null; } +export interface Product_productType_taxType { + __typename: "TaxType"; + description: string | null; + taxCode: string | null; +} + export interface Product_productType { __typename: "ProductType"; id: string; variantAttributes: (Product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; + taxType: Product_productType_taxType | null; } export interface Product_pricing_priceRangeUndiscounted_start_gross { @@ -191,6 +198,12 @@ export interface Product_weight { value: number; } +export interface Product_taxType { + __typename: "TaxType"; + description: string | null; + taxCode: string | null; +} + export interface Product { __typename: "Product"; id: string; @@ -217,6 +230,7 @@ export interface Product { images: (Product_images | null)[] | null; variants: (Product_variants | null)[] | null; weight: Product_weight | null; + taxType: Product_taxType | null; availableForPurchase: any | null; visibleInListings: boolean; } diff --git a/src/fragments/types/TaxTypeFragment.ts b/src/fragments/types/TaxTypeFragment.ts new file mode 100644 index 000000000..48d203ab0 --- /dev/null +++ b/src/fragments/types/TaxTypeFragment.ts @@ -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; +} diff --git a/src/products/components/ProductCreatePage/ProductCreatePage.tsx b/src/products/components/ProductCreatePage/ProductCreatePage.tsx index 1cc157800..031abec20 100644 --- a/src/products/components/ProductCreatePage/ProductCreatePage.tsx +++ b/src/products/components/ProductCreatePage/ProductCreatePage.tsx @@ -11,6 +11,7 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; +import { TaxTypeFragment } from "@saleor/fragments/types/TaxTypeFragment"; import useDateLocalize from "@saleor/hooks/useDateLocalize"; import useFormset from "@saleor/hooks/useFormset"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; @@ -46,14 +47,15 @@ import ProductOrganization from "../ProductOrganization"; import ProductPricing from "../ProductPricing"; import ProductShipping from "../ProductShipping/ProductShipping"; import ProductStocks, { ProductStockInput } from "../ProductStocks"; +import ProductTaxes from "../ProductTaxes"; interface FormData extends MetadataFormData { availableForPurchase: string; basePrice: number; - publicationDate: string; category: string; - collections: string[]; + changeTaxCode: boolean; chargeTaxes: boolean; + collections: string[]; description: RawDraftContentState; isAvailable: boolean; isAvailableForPurchase: boolean; @@ -61,10 +63,12 @@ interface FormData extends MetadataFormData { name: string; slug: string; productType: string; + publicationDate: string; seoDescription: string; seoTitle: string; sku: string; stockQuantity: number; + taxCode: string; trackInventory: boolean; visibleInListings: boolean; weight: string; @@ -93,6 +97,7 @@ interface ProductCreatePageProps { saveButtonBarState: ConfirmButtonTransitionState; weightUnit: string; warehouses: SearchWarehouses_search_edges_node[]; + taxTypes: TaxTypeFragment[]; fetchCategories: (data: string) => void; fetchCollections: (data: string) => void; fetchProductTypes: (data: string) => void; @@ -115,6 +120,7 @@ export const ProductCreatePage: React.FC = ({ productTypes: productTypeChoiceList, saveButtonBarState, warehouses, + taxTypes, onBack, fetchProductTypes, weightUnit, @@ -149,6 +155,7 @@ export const ProductCreatePage: React.FC = ({ availableForPurchase: "", basePrice: 0, category: "", + changeTaxCode: false, chargeTaxes: false, collections: [], description: {} as any, @@ -165,6 +172,7 @@ export const ProductCreatePage: React.FC = ({ sku: null, slug: "", stockQuantity: null, + taxCode: null, trackInventory: false, visibleInListings: false, weight: "" @@ -182,10 +190,16 @@ export const ProductCreatePage: React.FC = ({ >([]); const [productType, setProductType] = React.useState(null); + const [selectedTaxType, setSelectedTaxType] = useStateFromProps(null); const categories = getChoices(categoryChoiceList); const collections = getChoices(collectionChoiceList); const productTypes = getChoices(productTypeChoiceList); + const taxTypeChoices = + taxTypes?.map(taxType => ({ + label: taxType.description, + value: taxType.taxCode + })) || []; const handleSubmit = (data: FormData) => onSubmit({ @@ -230,6 +244,11 @@ export const ProductCreatePage: React.FC = ({ setProductType, productTypeChoiceList ); + const handleTaxTypeSelect = createSingleAutocompleteSelectHandler( + change, + setSelectedTaxType, + taxTypeChoices + ); const changeMetadata = makeMetadataChangeHandler(change); @@ -372,6 +391,15 @@ export const ProductCreatePage: React.FC = ({ }} onChange={change} /> + +
= props => { defaultMessage: "Pricing", description: "product pricing" })} - > - - + />
= ({ const warehousesToAssign = warehouses.filter( warehouse => !stocks.some(stock => stock.id === warehouse.id) ); + const formErrors = getFormErrors(["sku"], errors); return ( @@ -135,9 +136,9 @@ const ProductStocks: React.FC = ({
({ + content: { + paddingTop: theme.spacing(2) + }, + hr: { + margin: theme.spacing(2, 0) + }, + select: { + margin: theme.spacing(2, 0) + } + }), + { + name: "ProductTaxes" + } +); + +const ProductTaxes: React.FC = ({ + data, + disabled, + selectedTaxTypeDisplayName, + taxTypes, + onChange, + onTaxTypeChange +}) => { + const intl = useIntl(); + const classes = useStyles({}); + + return ( + + + + +
+ + {data.changeTaxCode && ( + ({ + label: taxType.description, + value: taxType.taxCode + })) || [] + } + InputProps={{ + autoComplete: "off" + }} + /> + )} +
+
+ ); +}; + +ProductTaxes.displayName = "ProductTaxes"; +export default ProductTaxes; diff --git a/src/products/components/ProductTaxes/index.ts b/src/products/components/ProductTaxes/index.ts new file mode 100644 index 000000000..e789213a0 --- /dev/null +++ b/src/products/components/ProductTaxes/index.ts @@ -0,0 +1,2 @@ +export * from "./ProductTaxes"; +export { default } from "./ProductTaxes"; diff --git a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx index 4db87dc4d..79252b195 100644 --- a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx +++ b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx @@ -10,6 +10,7 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; +import { TaxTypeFragment } from "@saleor/fragments/types/TaxTypeFragment"; import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment"; import useDateLocalize from "@saleor/hooks/useDateLocalize"; import useFormset from "@saleor/hooks/useFormset"; @@ -52,6 +53,7 @@ import ProductOrganization from "../ProductOrganization"; import ProductPricing from "../ProductPricing"; import ProductShipping from "../ProductShipping/ProductShipping"; import ProductStocks, { ProductStockInput } from "../ProductStocks"; +import ProductTaxes from "../ProductTaxes"; import ProductVariants from "../ProductVariants"; export interface ProductUpdatePageProps extends ListActions { @@ -69,6 +71,7 @@ export interface ProductUpdatePageProps extends ListActions { header: string; saveButtonBarState: ConfirmButtonTransitionState; warehouses: WarehouseFragment[]; + taxTypes: TaxTypeFragment[]; fetchCategories: (query: string) => void; fetchCollections: (query: string) => void; onVariantsAdd: () => void; @@ -111,6 +114,7 @@ export const ProductUpdatePage: React.FC = ({ saveButtonBarState, variants, warehouses, + taxTypes, onBack, onDelete, onImageDelete, @@ -161,6 +165,10 @@ export const ProductUpdatePage: React.FC = ({ getChoices(maybe(() => product.collections, [])) ); + const [selectedTaxType, setSelectedTaxType] = useStateFromProps( + product?.taxType.description + ); + const { isMetadataModified, isPrivateMetadataModified, @@ -177,6 +185,11 @@ export const ProductUpdatePage: React.FC = ({ const currency = product?.variants?.length && product.variants[0].price.currency; const hasVariants = maybe(() => product.productType.hasVariants, false); + const taxTypeChoices = + taxTypes?.map(taxType => ({ + label: taxType.description, + value: taxType.taxCode + })) || []; const handleSubmit = (data: ProductUpdatePageFormData) => { const metadata = isMetadataModified ? data.metadata : undefined; @@ -246,6 +259,11 @@ export const ProductUpdatePage: React.FC = ({ triggerChange ); const changeMetadata = makeMetadataChangeHandler(change); + const handleTaxTypeSelect = createSingleAutocompleteSelectHandler( + change, + setSelectedTaxType, + taxTypeChoices + ); return ( <> @@ -422,6 +440,15 @@ export const ProductUpdatePage: React.FC = ({ }} onChange={change} /> + +
( const productDetailsQuery = gql` ${productFragmentDetails} + ${taxTypeFragment} query ProductDetails($id: ID!) { product(id: $id) { ...Product } + taxTypes { + ...TaxTypeFragment + } } `; export const useProductDetails = makeQuery< diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index 84b5a6201..f31768995 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -2,7 +2,7 @@ /* eslint-disable */ // 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 @@ -58,12 +58,19 @@ export interface ProductCreate_productCreate_product_productType_variantAttribut 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 { __typename: "ProductType"; id: string; variantAttributes: (ProductCreate_productCreate_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; + taxType: ProductCreate_productCreate_product_productType_taxType | null; } export interface ProductCreate_productCreate_product_pricing_priceRangeUndiscounted_start_gross { @@ -197,6 +204,12 @@ export interface ProductCreate_productCreate_product_weight { value: number; } +export interface ProductCreate_productCreate_product_taxType { + __typename: "TaxType"; + description: string | null; + taxCode: string | null; +} + export interface ProductCreate_productCreate_product { __typename: "Product"; id: string; @@ -223,6 +236,7 @@ export interface ProductCreate_productCreate_product { images: (ProductCreate_productCreate_product_images | null)[] | null; variants: (ProductCreate_productCreate_product_variants | null)[] | null; weight: ProductCreate_productCreate_product_weight | null; + taxType: ProductCreate_productCreate_product_taxType | null; availableForPurchase: any | null; visibleInListings: boolean; } @@ -238,21 +252,5 @@ export interface ProductCreate { } export interface ProductCreateVariables { - attributes?: (AttributeValueInput | null)[] | null; - 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; + input: ProductCreateInput; } diff --git a/src/products/types/ProductDetails.ts b/src/products/types/ProductDetails.ts index 29f3ef2f1..21a614bc0 100644 --- a/src/products/types/ProductDetails.ts +++ b/src/products/types/ProductDetails.ts @@ -52,12 +52,19 @@ export interface ProductDetails_product_productType_variantAttributes { 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 { __typename: "ProductType"; id: string; variantAttributes: (ProductDetails_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; + taxType: ProductDetails_product_productType_taxType | null; } export interface ProductDetails_product_pricing_priceRangeUndiscounted_start_gross { @@ -191,6 +198,12 @@ export interface ProductDetails_product_weight { value: number; } +export interface ProductDetails_product_taxType { + __typename: "TaxType"; + description: string | null; + taxCode: string | null; +} + export interface ProductDetails_product { __typename: "Product"; id: string; @@ -217,12 +230,20 @@ export interface ProductDetails_product { images: (ProductDetails_product_images | null)[] | null; variants: (ProductDetails_product_variants | null)[] | null; weight: ProductDetails_product_weight | null; + taxType: ProductDetails_product_taxType | null; availableForPurchase: any | null; visibleInListings: boolean; } +export interface ProductDetails_taxTypes { + __typename: "TaxType"; + description: string | null; + taxCode: string | null; +} + export interface ProductDetails { product: ProductDetails_product | null; + taxTypes: (ProductDetails_taxTypes | null)[] | null; } export interface ProductDetailsVariables { diff --git a/src/products/types/ProductImageCreate.ts b/src/products/types/ProductImageCreate.ts index 0943f1040..c1782b45b 100644 --- a/src/products/types/ProductImageCreate.ts +++ b/src/products/types/ProductImageCreate.ts @@ -58,12 +58,19 @@ export interface ProductImageCreate_productImageCreate_product_productType_varia 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 { __typename: "ProductType"; id: string; variantAttributes: (ProductImageCreate_productImageCreate_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; + taxType: ProductImageCreate_productImageCreate_product_productType_taxType | null; } export interface ProductImageCreate_productImageCreate_product_pricing_priceRangeUndiscounted_start_gross { @@ -197,6 +204,12 @@ export interface ProductImageCreate_productImageCreate_product_weight { value: number; } +export interface ProductImageCreate_productImageCreate_product_taxType { + __typename: "TaxType"; + description: string | null; + taxCode: string | null; +} + export interface ProductImageCreate_productImageCreate_product { __typename: "Product"; id: string; @@ -223,6 +236,7 @@ export interface ProductImageCreate_productImageCreate_product { images: (ProductImageCreate_productImageCreate_product_images | null)[] | null; variants: (ProductImageCreate_productImageCreate_product_variants | null)[] | null; weight: ProductImageCreate_productImageCreate_product_weight | null; + taxType: ProductImageCreate_productImageCreate_product_taxType | null; availableForPurchase: any | null; visibleInListings: boolean; } diff --git a/src/products/types/ProductImageUpdate.ts b/src/products/types/ProductImageUpdate.ts index 3b38da546..2df7a1953 100644 --- a/src/products/types/ProductImageUpdate.ts +++ b/src/products/types/ProductImageUpdate.ts @@ -58,12 +58,19 @@ export interface ProductImageUpdate_productImageUpdate_product_productType_varia 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 { __typename: "ProductType"; id: string; variantAttributes: (ProductImageUpdate_productImageUpdate_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; + taxType: ProductImageUpdate_productImageUpdate_product_productType_taxType | null; } export interface ProductImageUpdate_productImageUpdate_product_pricing_priceRangeUndiscounted_start_gross { @@ -197,6 +204,12 @@ export interface ProductImageUpdate_productImageUpdate_product_weight { value: number; } +export interface ProductImageUpdate_productImageUpdate_product_taxType { + __typename: "TaxType"; + description: string | null; + taxCode: string | null; +} + export interface ProductImageUpdate_productImageUpdate_product { __typename: "Product"; id: string; @@ -223,6 +236,7 @@ export interface ProductImageUpdate_productImageUpdate_product { images: (ProductImageUpdate_productImageUpdate_product_images | null)[] | null; variants: (ProductImageUpdate_productImageUpdate_product_variants | null)[] | null; weight: ProductImageUpdate_productImageUpdate_product_weight | null; + taxType: ProductImageUpdate_productImageUpdate_product_taxType | null; availableForPurchase: any | null; visibleInListings: boolean; } diff --git a/src/products/types/ProductUpdate.ts b/src/products/types/ProductUpdate.ts index effa1bf01..8da5ceab4 100644 --- a/src/products/types/ProductUpdate.ts +++ b/src/products/types/ProductUpdate.ts @@ -2,7 +2,7 @@ /* eslint-disable */ // 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 @@ -58,12 +58,19 @@ export interface ProductUpdate_productUpdate_product_productType_variantAttribut 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 { __typename: "ProductType"; id: string; variantAttributes: (ProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; + taxType: ProductUpdate_productUpdate_product_productType_taxType | null; } export interface ProductUpdate_productUpdate_product_pricing_priceRangeUndiscounted_start_gross { @@ -197,6 +204,12 @@ export interface ProductUpdate_productUpdate_product_weight { value: number; } +export interface ProductUpdate_productUpdate_product_taxType { + __typename: "TaxType"; + description: string | null; + taxCode: string | null; +} + export interface ProductUpdate_productUpdate_product { __typename: "Product"; id: string; @@ -223,6 +236,7 @@ export interface ProductUpdate_productUpdate_product { images: (ProductUpdate_productUpdate_product_images | null)[] | null; variants: (ProductUpdate_productUpdate_product_variants | null)[] | null; weight: ProductUpdate_productUpdate_product_weight | null; + taxType: ProductUpdate_productUpdate_product_taxType | null; availableForPurchase: any | null; visibleInListings: boolean; } @@ -239,16 +253,5 @@ export interface ProductUpdate { export interface ProductUpdateVariables { id: string; - attributes?: (AttributeValueInput | null)[] | null; - 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; + input: ProductInput; } diff --git a/src/products/types/ProductVariantReorder.ts b/src/products/types/ProductVariantReorder.ts index 499588cb1..1870dd9c6 100644 --- a/src/products/types/ProductVariantReorder.ts +++ b/src/products/types/ProductVariantReorder.ts @@ -58,12 +58,19 @@ export interface ProductVariantReorder_productVariantReorder_product_productType 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 { __typename: "ProductType"; id: string; variantAttributes: (ProductVariantReorder_productVariantReorder_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; + taxType: ProductVariantReorder_productVariantReorder_product_productType_taxType | null; } export interface ProductVariantReorder_productVariantReorder_product_pricing_priceRangeUndiscounted_start_gross { @@ -197,6 +204,12 @@ export interface ProductVariantReorder_productVariantReorder_product_weight { value: number; } +export interface ProductVariantReorder_productVariantReorder_product_taxType { + __typename: "TaxType"; + description: string | null; + taxCode: string | null; +} + export interface ProductVariantReorder_productVariantReorder_product { __typename: "Product"; id: string; @@ -223,6 +236,7 @@ export interface ProductVariantReorder_productVariantReorder_product { images: (ProductVariantReorder_productVariantReorder_product_images | null)[] | null; variants: (ProductVariantReorder_productVariantReorder_product_variants | null)[] | null; weight: ProductVariantReorder_productVariantReorder_product_weight | null; + taxType: ProductVariantReorder_productVariantReorder_product_taxType | null; availableForPurchase: any | null; visibleInListings: boolean; } diff --git a/src/products/types/ProductVariantSetDefault.ts b/src/products/types/ProductVariantSetDefault.ts index 2fb7dcb8a..2448d3574 100644 --- a/src/products/types/ProductVariantSetDefault.ts +++ b/src/products/types/ProductVariantSetDefault.ts @@ -58,12 +58,19 @@ export interface ProductVariantSetDefault_productVariantSetDefault_product_produ 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 { __typename: "ProductType"; id: string; variantAttributes: (ProductVariantSetDefault_productVariantSetDefault_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; + taxType: ProductVariantSetDefault_productVariantSetDefault_product_productType_taxType | null; } export interface ProductVariantSetDefault_productVariantSetDefault_product_pricing_priceRangeUndiscounted_start_gross { @@ -197,6 +204,12 @@ export interface ProductVariantSetDefault_productVariantSetDefault_product_weigh value: number; } +export interface ProductVariantSetDefault_productVariantSetDefault_product_taxType { + __typename: "TaxType"; + description: string | null; + taxCode: string | null; +} + export interface ProductVariantSetDefault_productVariantSetDefault_product { __typename: "Product"; id: string; @@ -206,6 +219,7 @@ export interface ProductVariantSetDefault_productVariantSetDefault_product { metadata: (ProductVariantSetDefault_productVariantSetDefault_product_metadata | null)[]; privateMetadata: (ProductVariantSetDefault_productVariantSetDefault_product_privateMetadata | null)[]; name: string; + slug: string; descriptionJson: any; seoTitle: string | null; seoDescription: string | null; @@ -222,6 +236,7 @@ export interface ProductVariantSetDefault_productVariantSetDefault_product { images: (ProductVariantSetDefault_productVariantSetDefault_product_images | null)[] | null; variants: (ProductVariantSetDefault_productVariantSetDefault_product_variants | null)[] | null; weight: ProductVariantSetDefault_productVariantSetDefault_product_weight | null; + taxType: ProductVariantSetDefault_productVariantSetDefault_product_taxType | null; availableForPurchase: any | null; visibleInListings: boolean; } diff --git a/src/products/types/SimpleProductUpdate.ts b/src/products/types/SimpleProductUpdate.ts index 0d1a662d7..cbc11614e 100644 --- a/src/products/types/SimpleProductUpdate.ts +++ b/src/products/types/SimpleProductUpdate.ts @@ -2,7 +2,7 @@ /* eslint-disable */ // 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 @@ -58,12 +58,19 @@ export interface SimpleProductUpdate_productUpdate_product_productType_variantAt 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 { __typename: "ProductType"; id: string; variantAttributes: (SimpleProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; + taxType: SimpleProductUpdate_productUpdate_product_productType_taxType | null; } export interface SimpleProductUpdate_productUpdate_product_pricing_priceRangeUndiscounted_start_gross { @@ -197,6 +204,12 @@ export interface SimpleProductUpdate_productUpdate_product_weight { value: number; } +export interface SimpleProductUpdate_productUpdate_product_taxType { + __typename: "TaxType"; + description: string | null; + taxCode: string | null; +} + export interface SimpleProductUpdate_productUpdate_product { __typename: "Product"; id: string; @@ -223,6 +236,7 @@ export interface SimpleProductUpdate_productUpdate_product { images: (SimpleProductUpdate_productUpdate_product_images | null)[] | null; variants: (SimpleProductUpdate_productUpdate_product_variants | null)[] | null; weight: SimpleProductUpdate_productUpdate_product_weight | null; + taxType: SimpleProductUpdate_productUpdate_product_taxType | null; availableForPurchase: any | null; visibleInListings: boolean; } @@ -821,22 +835,10 @@ export interface SimpleProductUpdate { export interface SimpleProductUpdateVariables { id: string; - attributes?: (AttributeValueInput | null)[] | null; - publicationDate?: any | null; - category?: string | null; - chargeTaxes: boolean; - collections?: (string | null)[] | null; - descriptionJson?: any | null; - isPublished: boolean; - name?: string | null; - basePrice?: any | null; + input: ProductInput; productVariantId: string; productVariantInput: ProductVariantInput; - seo?: SeoInput | null; - slug?: string | null; addStocks: StockInput[]; deleteStocks: string[]; updateStocks: StockInput[]; - weight?: any | null; - visibleInListings?: boolean | null; } diff --git a/src/products/utils/data.ts b/src/products/utils/data.ts index ec378a288..2907367b3 100644 --- a/src/products/utils/data.ts +++ b/src/products/utils/data.ts @@ -174,11 +174,12 @@ export interface ProductUpdatePageFormData extends MetadataFormData { availableForPurchase: string; basePrice: number; category: string | null; - collections: string[]; + changeTaxCode: boolean; chargeTaxes: boolean; + collections: string[]; description: RawDraftContentState; - isAvailableForPurchase: boolean; isAvailable: boolean; + isAvailableForPurchase: boolean; isPublished: boolean; name: string; slug: string; @@ -186,9 +187,10 @@ export interface ProductUpdatePageFormData extends MetadataFormData { seoDescription: string; seoTitle: string; sku: string; + taxCode: string; trackInventory: boolean; - weight: string; visibleInListings: boolean; + weight: string; } export function getProductUpdatePageFormData( @@ -199,6 +201,7 @@ export function getProductUpdatePageFormData( availableForPurchase: product?.availableForPurchase, basePrice: maybe(() => product.variants[0].price.amount, 0), category: maybe(() => product.category.id, ""), + changeTaxCode: !!product?.taxType.taxCode, chargeTaxes: maybe(() => product.chargeTaxes, false), collections: maybe( () => product.collections.map(collection => collection.id), @@ -224,6 +227,7 @@ export function getProductUpdatePageFormData( "" ), slug: product?.slug || "", + taxCode: product?.taxType.taxCode, trackInventory: !!product?.variants[0]?.trackInventory, visibleInListings: !!product?.visibleInListings, weight: product?.weight?.value.toString() || "" diff --git a/src/products/views/ProductCreate.tsx b/src/products/views/ProductCreate.tsx index 30627ab5f..138e24e38 100644 --- a/src/products/views/ProductCreate.tsx +++ b/src/products/views/ProductCreate.tsx @@ -7,6 +7,7 @@ import { getProductAvailabilityVariables } from "@saleor/products/utils/handlers import useCategorySearch from "@saleor/searches/useCategorySearch"; import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import useProductTypeSearch from "@saleor/searches/useProductTypeSearch"; +import { useTaxTypeList } from "@saleor/taxes/queries"; import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; import { useMetadataUpdate, @@ -60,6 +61,7 @@ export const ProductCreateView: React.FC = () => { }); const [updateMetadata] = useMetadataUpdate({}); const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); + const taxTypes = useTaxTypeList({}); const handleBack = () => navigate(productListUrl()); @@ -91,33 +93,36 @@ export const ProductCreateView: React.FC = () => { const handleCreate = async (formData: ProductCreatePageSubmitData) => { const result = await productCreate({ variables: { - attributes: formData.attributes.map(attribute => ({ - id: attribute.id, - values: attribute.value - })), - basePrice: decimal(formData.basePrice), - category: formData.category, - chargeTaxes: formData.chargeTaxes, - collections: formData.collections, - descriptionJson: JSON.stringify(formData.description), - isPublished: formData.isPublished, - name: formData.name, - productType: formData.productType, - publicationDate: - formData.publicationDate !== "" ? formData.publicationDate : null, - seo: { - description: formData.seoDescription, - title: formData.seoTitle - }, - sku: formData.sku, - slug: formData.slug, - stocks: formData.stocks.map(stock => ({ - quantity: parseInt(stock.value, 0), - warehouse: stock.id - })), - trackInventory: formData.trackInventory, - visibleInListings: formData.visibleInListings, - weight: weight(formData.weight) + input: { + attributes: formData.attributes.map(attribute => ({ + id: attribute.id, + values: attribute.value + })), + basePrice: decimal(formData.basePrice), + category: formData.category, + chargeTaxes: formData.chargeTaxes, + collections: formData.collections, + descriptionJson: JSON.stringify(formData.description), + isPublished: formData.isPublished, + name: formData.name, + productType: formData.productType, + publicationDate: + formData.publicationDate !== "" ? formData.publicationDate : null, + seo: { + description: formData.seoDescription, + title: formData.seoTitle + }, + sku: formData.sku, + slug: formData.slug, + stocks: formData.stocks.map(stock => ({ + quantity: parseInt(stock.value, 0), + warehouse: stock.id + })), + taxCode: formData.changeTaxCode ? formData.taxCode : undefined, + trackInventory: formData.trackInventory, + visibleInListings: formData.visibleInListings, + weight: weight(formData.weight) + } } }); @@ -194,6 +199,7 @@ export const ProductCreateView: React.FC = () => { warehouses={ warehouses.data?.warehouses.edges.map(edge => edge.node) || [] } + taxTypes={taxTypes.data?.taxTypes || []} weightUnit={shop?.defaultWeightUnit} /> diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index 83c12371c..4b03c68d6 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -298,6 +298,7 @@ export const ProductUpdate: React.FC = ({ id, params }) => { warehouses={ warehouses.data?.warehouses.edges.map(edge => edge.node) || [] } + taxTypes={data?.taxTypes} variants={maybe(() => product.variants)} onBack={handleBack} onDelete={() => openModal("remove")} diff --git a/src/products/views/ProductUpdate/handlers.ts b/src/products/views/ProductUpdate/handlers.ts index 2c0756e0c..c68e32bf5 100644 --- a/src/products/views/ProductUpdate/handlers.ts +++ b/src/products/views/ProductUpdate/handlers.ts @@ -41,26 +41,29 @@ export function createUpdateHandler( ) { return async (data: ProductUpdatePageSubmitData) => { const productVariables: ProductUpdateVariables = { - attributes: data.attributes.map(attribute => ({ - id: attribute.id, - values: attribute.value[0] === "" ? [] : attribute.value - })), - basePrice: decimal(data.basePrice), - category: data.category, - chargeTaxes: data.chargeTaxes, - collections: data.collections, - descriptionJson: JSON.stringify(data.description), id: product.id, - isPublished: data.isPublished, - name: data.name, - publicationDate: - data.publicationDate !== "" ? data.publicationDate : null, - seo: { - description: data.seoDescription, - title: data.seoTitle - }, - slug: data.slug, - visibleInListings: data.visibleInListings + input: { + attributes: data.attributes.map(attribute => ({ + id: attribute.id, + values: attribute.value[0] === "" ? [] : attribute.value + })), + basePrice: decimal(data.basePrice), + category: data.category, + chargeTaxes: data.chargeTaxes, + collections: data.collections, + descriptionJson: JSON.stringify(data.description), + isPublished: data.isPublished, + name: data.name, + publicationDate: + data.publicationDate !== "" ? data.publicationDate : null, + seo: { + description: data.seoDescription, + title: data.seoTitle + }, + slug: data.slug, + taxCode: data.changeTaxCode ? data.taxCode : null, + visibleInListings: data.visibleInListings + } }; let errors: Array< @@ -75,13 +78,16 @@ export function createUpdateHandler( ...productVariables, addStocks: data.addStocks.map(mapFormsetStockToStockInput), deleteStocks: data.removeStocks, + input: { + ...productVariables.input, + weight: weight(data.weight) + }, productVariantId: product.variants[0].id, productVariantInput: { sku: data.sku, trackInventory: data.trackInventory }, - updateStocks: data.updateStocks.map(mapFormsetStockToStockInput), - weight: weight(data.weight) + updateStocks: data.updateStocks.map(mapFormsetStockToStockInput) }); errors = [ ...result.data.productUpdate.errors, diff --git a/src/searches/types/SearchProductTypes.ts b/src/searches/types/SearchProductTypes.ts index a35124ca1..2d79b4665 100644 --- a/src/searches/types/SearchProductTypes.ts +++ b/src/searches/types/SearchProductTypes.ts @@ -25,12 +25,19 @@ export interface SearchProductTypes_search_edges_node_productAttributes { 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 { __typename: "ProductType"; id: string; name: string; hasVariants: boolean; productAttributes: (SearchProductTypes_search_edges_node_productAttributes | null)[] | null; + taxType: SearchProductTypes_search_edges_node_taxType | null; } export interface SearchProductTypes_search_edges { diff --git a/src/searches/useProductTypeSearch.ts b/src/searches/useProductTypeSearch.ts index e5cad1f89..6414b8d7d 100644 --- a/src/searches/useProductTypeSearch.ts +++ b/src/searches/useProductTypeSearch.ts @@ -1,4 +1,5 @@ import { pageInfoFragment } from "@saleor/fragments/pageInfo"; +import { taxTypeFragment } from "@saleor/fragments/taxes"; import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; import gql from "graphql-tag"; @@ -9,6 +10,7 @@ import { export const searchProductTypes = gql` ${pageInfoFragment} + ${taxTypeFragment} query SearchProductTypes($after: String, $first: Int!, $query: String!) { search: productTypes( after: $after @@ -32,6 +34,9 @@ export const searchProductTypes = gql` slug } } + taxType { + ...TaxTypeFragment + } } } pageInfo { diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index d793ce8d5..f3142c690 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -137813,6 +137813,124 @@ Ctrl + K" />
+
+
+
+ + Taxes + +
+
+
+
+
+ +
+ +
+
@@ -138970,6 +139088,120 @@ Ctrl + K" /> +
+
+
+ + Taxes + +
+
+
+
+
+ +
+ +
+
@@ -140142,6 +140374,120 @@ Ctrl + K" /> +
+
+
+ + Taxes + +
+
+
+
+
+ +
+ +
+
@@ -143219,6 +143565,11 @@ exports[`Storyshots Views / Products / Create product variant with errors 1`] = +

+ A product with this SKU already exists +

+
+
+
+ + Taxes + +
+
+
+
+
+ +
+ +
+
+ + +
+
+
+
@@ -147997,6 +148534,192 @@ Ctrl + K" /> +
+
+
+ + Taxes + +
+
+
+
+
+ +
+ +
+
+ + +
+
+
+
@@ -149040,54 +149763,7 @@ Ctrl + K"
- -
+ />
@@ -150368,6 +151044,192 @@ Ctrl + K" /> +
+
+
+ + Taxes + +
+
+
+
+
+ +
+ +
+
+ + +
+
+
+
@@ -151411,54 +152273,7 @@ Ctrl + K"
- -
+ />
@@ -152873,6 +153688,192 @@ Ctrl + K" /> +
+
+
+ + Taxes + +
+
+
+
+
+ +
+ +
+
+ + +
+
+
+
@@ -155236,6 +156237,192 @@ Ctrl + K" /> +
+
+
+ + Taxes + +
+
+
+
+
+ +
+ +
+
+ + +
+
+
+
@@ -156542,6 +157729,124 @@ Ctrl + K" /> +
+
+
+ + Taxes + +
+
+
+
+
+ +
+ +
+
@@ -158861,6 +160166,192 @@ Ctrl + K" /> +
+
+
+ + Taxes + +
+
+
+
+
+ +
+ +
+
+ + +
+
+
+
@@ -159904,54 +161395,7 @@ Ctrl + K"
- -
+ />
@@ -161366,6 +162810,192 @@ Ctrl + K" /> +
+
+
+ + Taxes + +
+
+
+
+
+ +
+ +
+
+ + +
+
+
+
@@ -168794,7 +170424,7 @@ exports[`Storyshots Views / Products / Product variant details attribute errors

- Generic form error + A product with this SKU already exists

diff --git a/src/storybook/stories/products/ProductCreatePage.tsx b/src/storybook/stories/products/ProductCreatePage.tsx index 789bcc42f..babd8504a 100644 --- a/src/storybook/stories/products/ProductCreatePage.tsx +++ b/src/storybook/stories/products/ProductCreatePage.tsx @@ -10,6 +10,7 @@ import ProductCreatePage, { import { product as productFixture } from "../../../products/fixtures"; import { productTypes } from "../../../productTypes/fixtures"; import Decorator from "../../Decorator"; +import { taxTypes } from "../taxes/fixtures"; const product = productFixture(""); @@ -34,6 +35,7 @@ storiesOf("Views / Products / Create product", module) onSubmit={() => undefined} saveButtonBarState="default" warehouses={warehouseList} + taxTypes={taxTypes} weightUnit="kg" /> )) @@ -56,6 +58,7 @@ storiesOf("Views / Products / Create product", module) onSubmit={() => undefined} saveButtonBarState="default" warehouses={undefined} + taxTypes={taxTypes} weightUnit="kg" /> )) @@ -84,6 +87,7 @@ storiesOf("Views / Products / Create product", module) onSubmit={() => undefined} saveButtonBarState="default" warehouses={warehouseList} + taxTypes={taxTypes} weightUnit="kg" /> )); diff --git a/src/storybook/stories/products/ProductUpdatePage.tsx b/src/storybook/stories/products/ProductUpdatePage.tsx index 4e8ce5ba6..c44841a1b 100644 --- a/src/storybook/stories/products/ProductUpdatePage.tsx +++ b/src/storybook/stories/products/ProductUpdatePage.tsx @@ -12,6 +12,7 @@ import { storiesOf } from "@storybook/react"; import React from "react"; import Decorator from "../../Decorator"; +import { taxTypes } from "../taxes/fixtures"; const product = productFixture(placeholderImage); @@ -41,6 +42,7 @@ const props: ProductUpdatePageProps = { placeholderImage, product, saveButtonBarState: "default", + taxTypes, variants: product.variants, warehouses: warehouseList }; diff --git a/src/storybook/stories/taxes/fixtures.ts b/src/storybook/stories/taxes/fixtures.ts index cb344a011..ca5ac8882 100644 --- a/src/storybook/stories/taxes/fixtures.ts +++ b/src/storybook/stories/taxes/fixtures.ts @@ -1,3 +1,5 @@ +import { TaxTypeFragment } from "@saleor/fragments/types/TaxTypeFragment"; + import { CountryList_shop_countries } from "../../../taxes/types/CountryList"; import { TaxRateType } from "../../../types/globalTypes"; @@ -2714,3 +2716,84 @@ export const countries: CountryList = [ vat: null } ].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" } +]; diff --git a/src/taxes/queries.ts b/src/taxes/queries.ts index 342756eb4..7f55c8858 100644 --- a/src/taxes/queries.ts +++ b/src/taxes/queries.ts @@ -1,11 +1,14 @@ import { countryWithTaxesFragment, - shopTaxesFragment + shopTaxesFragment, + taxTypeFragment } from "@saleor/fragments/taxes"; +import makeQuery from "@saleor/hooks/makeQuery"; import gql from "graphql-tag"; import { TypedQuery } from "../queries"; import { CountryList } from "./types/CountryList"; +import { TaxTypeList } from "./types/TaxTypeList"; const countryList = gql` ${countryWithTaxesFragment} @@ -20,3 +23,13 @@ const countryList = gql` } `; export const TypedCountryListQuery = TypedQuery(countryList); + +const taxTypeList = gql` + ${taxTypeFragment} + query TaxTypeList { + taxTypes { + ...TaxTypeFragment + } + } +`; +export const useTaxTypeList = makeQuery(taxTypeList); diff --git a/src/taxes/types/TaxTypeList.ts b/src/taxes/types/TaxTypeList.ts new file mode 100644 index 000000000..1f241905d --- /dev/null +++ b/src/taxes/types/TaxTypeList.ts @@ -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; +} diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index 5d626b4df..f79be52c5 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -1341,6 +1341,28 @@ export interface PriceRangeInput { 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 { isPublished?: boolean | null; collections?: (string | null)[] | null; @@ -1356,6 +1378,26 @@ export interface ProductFilterInput { 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 { direction: OrderDirection; attributeId?: string | null; diff --git a/src/utils/errors/product.ts b/src/utils/errors/product.ts index 45a1e36dc..2c1295765 100644 --- a/src/utils/errors/product.ts +++ b/src/utils/errors/product.ts @@ -7,6 +7,9 @@ import { defineMessages, IntlShape } from "react-intl"; import commonErrorMessages from "./common"; const messages = defineMessages({ + alreadyExists: { + defaultMessage: "A product with this SKU already exists" + }, attributeAlreadyAssigned: { defaultMessage: "This attribute has already been assigned to this product type" @@ -48,6 +51,8 @@ function getProductErrorMessage( switch (err.code) { case ProductErrorCode.ATTRIBUTE_ALREADY_ASSIGNED: return intl.formatMessage(messages.attributeAlreadyAssigned); + case ProductErrorCode.ALREADY_EXISTS: + return intl.formatMessage(messages.alreadyExists); case ProductErrorCode.ATTRIBUTE_CANNOT_BE_ASSIGNED: return intl.formatMessage(messages.attributeCannotBeAssigned); case ProductErrorCode.ATTRIBUTE_VARIANTS_DISABLED: