@unchainedshop/api 4.0.0-rc.5 → 4.0.0-rc.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/lib/errors.d.ts +2 -0
- package/lib/errors.d.ts.map +1 -1
- package/lib/errors.js +2 -0
- package/lib/errors.js.map +1 -1
- package/lib/loaders/index.d.ts +5 -0
- package/lib/loaders/index.d.ts.map +1 -1
- package/lib/loaders/index.js +2 -0
- package/lib/loaders/index.js.map +1 -1
- package/lib/loaders/productProxiesLoader.d.ts +10 -0
- package/lib/loaders/productProxiesLoader.d.ts.map +1 -0
- package/lib/loaders/productProxiesLoader.js +30 -0
- package/lib/loaders/productProxiesLoader.js.map +1 -0
- package/lib/mcp/tools/assortment/addAssortmentMediaUploadHandler.d.ts.map +1 -1
- package/lib/mcp/tools/assortment/addAssortmentMediaUploadHandler.js +2 -1
- package/lib/mcp/tools/assortment/addAssortmentMediaUploadHandler.js.map +1 -1
- package/lib/mcp/tools/assortment/assortmentMediaHandler.d.ts +32 -0
- package/lib/mcp/tools/assortment/assortmentMediaHandler.d.ts.map +1 -0
- package/lib/mcp/tools/assortment/assortmentMediaHandler.js +48 -0
- package/lib/mcp/tools/assortment/assortmentMediaHandler.js.map +1 -0
- package/lib/mcp/tools/assortment/index.d.ts.map +1 -1
- package/lib/mcp/tools/assortment/index.js +3 -1
- package/lib/mcp/tools/assortment/index.js.map +1 -1
- package/lib/mcp/tools/assortment/removeAssortmentMediaHandler.d.ts.map +1 -1
- package/lib/mcp/tools/assortment/removeAssortmentMediaHandler.js +3 -1
- package/lib/mcp/tools/assortment/removeAssortmentMediaHandler.js.map +1 -1
- package/lib/mcp/tools/assortment/reorderAssortmentMediaHandler.js +2 -2
- package/lib/mcp/tools/assortment/reorderAssortmentMediaHandler.js.map +1 -1
- package/lib/mcp/tools/assortment/translatedAssortmentMediaTextsHandler.d.ts.map +1 -1
- package/lib/mcp/tools/assortment/translatedAssortmentMediaTextsHandler.js +7 -1
- package/lib/mcp/tools/assortment/translatedAssortmentMediaTextsHandler.js.map +1 -1
- package/lib/mcp/tools/assortment/updateAssortmentMediaTextsHandler.d.ts.map +1 -1
- package/lib/mcp/tools/assortment/updateAssortmentMediaTextsHandler.js +4 -1
- package/lib/mcp/tools/assortment/updateAssortmentMediaTextsHandler.js.map +1 -1
- package/lib/mcp/tools/product/addProductAssignmentHandler.d.ts.map +1 -1
- package/lib/mcp/tools/product/addProductAssignmentHandler.js +1 -1
- package/lib/mcp/tools/product/addProductAssignmentHandler.js.map +1 -1
- package/lib/mcp/tools/product/addProductBundleItemHandler.d.ts +48 -0
- package/lib/mcp/tools/product/addProductBundleItemHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/addProductBundleItemHandler.js +52 -0
- package/lib/mcp/tools/product/addProductBundleItemHandler.js.map +1 -0
- package/lib/mcp/tools/product/addProductMediaUploadHandler.d.ts.map +1 -1
- package/lib/mcp/tools/product/addProductMediaUploadHandler.js +3 -2
- package/lib/mcp/tools/product/addProductMediaUploadHandler.js.map +1 -1
- package/lib/mcp/tools/product/catalogPriceHandler.d.ts +28 -0
- package/lib/mcp/tools/product/catalogPriceHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/catalogPriceHandler.js +57 -0
- package/lib/mcp/tools/product/catalogPriceHandler.js.map +1 -0
- package/lib/mcp/tools/product/index.d.ts.map +1 -1
- package/lib/mcp/tools/product/index.js +27 -3
- package/lib/mcp/tools/product/index.js.map +1 -1
- package/lib/mcp/tools/product/productAssignmentsHandler.d.ts +24 -0
- package/lib/mcp/tools/product/productAssignmentsHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/productAssignmentsHandler.js +79 -0
- package/lib/mcp/tools/product/productAssignmentsHandler.js.map +1 -0
- package/lib/mcp/tools/product/productBundleItemsHandler.d.ts +20 -0
- package/lib/mcp/tools/product/productBundleItemsHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/productBundleItemsHandler.js +45 -0
- package/lib/mcp/tools/product/productBundleItemsHandler.js.map +1 -0
- package/lib/mcp/tools/product/productMediaHandler.d.ts +32 -0
- package/lib/mcp/tools/product/productMediaHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/productMediaHandler.js +46 -0
- package/lib/mcp/tools/product/productMediaHandler.js.map +1 -0
- package/lib/mcp/tools/product/productSiblingsHandler.d.ts +36 -0
- package/lib/mcp/tools/product/productSiblingsHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/productSiblingsHandler.js +66 -0
- package/lib/mcp/tools/product/productSiblingsHandler.js.map +1 -0
- package/lib/mcp/tools/product/productVariationsHandler.d.ts +20 -0
- package/lib/mcp/tools/product/productVariationsHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/productVariationsHandler.js +47 -0
- package/lib/mcp/tools/product/productVariationsHandler.js.map +1 -0
- package/lib/mcp/tools/product/removeProductBundleItemHandler.d.ts +24 -0
- package/lib/mcp/tools/product/removeProductBundleItemHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/removeProductBundleItemHandler.js +46 -0
- package/lib/mcp/tools/product/removeProductBundleItemHandler.js.map +1 -0
- package/lib/mcp/tools/product/removeProductMediaHandler.js +1 -1
- package/lib/mcp/tools/product/removeProductMediaHandler.js.map +1 -1
- package/lib/mcp/tools/product/reorderProductMediaHandler.js +2 -2
- package/lib/mcp/tools/product/reorderProductMediaHandler.js.map +1 -1
- package/lib/mcp/tools/product/simulatedPriceHandler.d.ts +70 -0
- package/lib/mcp/tools/product/simulatedPriceHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/simulatedPriceHandler.js +74 -0
- package/lib/mcp/tools/product/simulatedPriceHandler.js.map +1 -0
- package/lib/mcp/tools/product/simulatedPriceRangeHandler.d.ts +74 -0
- package/lib/mcp/tools/product/simulatedPriceRangeHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/simulatedPriceRangeHandler.js +103 -0
- package/lib/mcp/tools/product/simulatedPriceRangeHandler.js.map +1 -0
- package/lib/mcp/tools/product/translatedProductMediaTextsHandler.d.ts.map +1 -1
- package/lib/mcp/tools/product/translatedProductMediaTextsHandler.js +7 -1
- package/lib/mcp/tools/product/translatedProductMediaTextsHandler.js.map +1 -1
- package/lib/mcp/tools/product/translatedProductVariationTextsHandler.d.ts.map +1 -1
- package/lib/mcp/tools/product/translatedProductVariationTextsHandler.js +7 -1
- package/lib/mcp/tools/product/translatedProductVariationTextsHandler.js.map +1 -1
- package/lib/mcp/tools/product/updateProductMediaTextsHandler.js +1 -1
- package/lib/mcp/tools/product/updateProductMediaTextsHandler.js.map +1 -1
- package/lib/mcp/tools/product/updateProductPlanHandler.d.ts +47 -26
- package/lib/mcp/tools/product/updateProductPlanHandler.d.ts.map +1 -1
- package/lib/mcp/tools/product/updateProductPlanHandler.js +23 -7
- package/lib/mcp/tools/product/updateProductPlanHandler.js.map +1 -1
- package/lib/mcp/tools/product/updateProductVariationTextsHandler.d.ts +73 -0
- package/lib/mcp/tools/product/updateProductVariationTextsHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/updateProductVariationTextsHandler.js +52 -0
- package/lib/mcp/tools/product/updateProductVariationTextsHandler.js.map +1 -0
- package/lib/mcp/tools/product/variationProductsHandler.d.ts +52 -0
- package/lib/mcp/tools/product/variationProductsHandler.d.ts.map +1 -0
- package/lib/mcp/tools/product/variationProductsHandler.js +54 -0
- package/lib/mcp/tools/product/variationProductsHandler.js.map +1 -0
- package/lib/mcp/tools/shopInfoHandler.d.ts.map +1 -1
- package/lib/mcp/tools/shopInfoHandler.js +4 -2
- package/lib/mcp/tools/shopInfoHandler.js.map +1 -1
- package/lib/mcp/utils/getNormalizedProductDetails.d.ts +1 -1
- package/lib/mcp/utils/getNormalizedProductDetails.d.ts.map +1 -1
- package/lib/mcp/utils/getNormalizedProductDetails.js +25 -0
- package/lib/mcp/utils/getNormalizedProductDetails.js.map +1 -1
- package/lib/resolvers/mutations/filters/createFilter.d.ts.map +1 -1
- package/lib/resolvers/mutations/filters/createFilter.js +14 -5
- package/lib/resolvers/mutations/filters/createFilter.js.map +1 -1
- package/lib/resolvers/mutations/products/createProductBundleItem.d.ts.map +1 -1
- package/lib/resolvers/mutations/products/createProductBundleItem.js +7 -2
- package/lib/resolvers/mutations/products/createProductBundleItem.js.map +1 -1
- package/lib/resolvers/type/index.d.ts +9 -0
- package/lib/resolvers/type/index.d.ts.map +1 -1
- package/lib/resolvers/type/index.js +2 -0
- package/lib/resolvers/type/index.js.map +1 -1
- package/lib/resolvers/type/product/product-bundle-types.d.ts +1 -0
- package/lib/resolvers/type/product/product-bundle-types.d.ts.map +1 -1
- package/lib/resolvers/type/product/product-configurable-or-bundle-product-types.d.ts +5 -0
- package/lib/resolvers/type/product/product-configurable-or-bundle-product-types.d.ts.map +1 -0
- package/lib/resolvers/type/product/product-configurable-or-bundle-product-types.js +9 -0
- package/lib/resolvers/type/product/product-configurable-or-bundle-product-types.js.map +1 -0
- package/lib/resolvers/type/product/product-configurable-types.d.ts +1 -0
- package/lib/resolvers/type/product/product-configurable-types.d.ts.map +1 -1
- package/lib/resolvers/type/product/product-plan-types.d.ts +1 -0
- package/lib/resolvers/type/product/product-plan-types.d.ts.map +1 -1
- package/lib/resolvers/type/product/product-simple-types.d.ts +1 -0
- package/lib/resolvers/type/product/product-simple-types.d.ts.map +1 -1
- package/lib/resolvers/type/product/product-tokenized-types.d.ts +1 -0
- package/lib/resolvers/type/product/product-tokenized-types.d.ts.map +1 -1
- package/lib/resolvers/type/product/product-types.d.ts +1 -0
- package/lib/resolvers/type/product/product-types.d.ts.map +1 -1
- package/lib/resolvers/type/product/product-types.js +3 -0
- package/lib/resolvers/type/product/product-types.js.map +1 -1
- package/lib/schema/types/product/bundle-product.d.ts.map +1 -1
- package/lib/schema/types/product/bundle-product.js +2 -1
- package/lib/schema/types/product/bundle-product.js.map +1 -1
- package/lib/schema/types/product/configurable-product.d.ts.map +1 -1
- package/lib/schema/types/product/configurable-product.js +1 -0
- package/lib/schema/types/product/configurable-product.js.map +1 -1
- package/lib/schema/types/product/plan-product.d.ts.map +1 -1
- package/lib/schema/types/product/plan-product.js +1 -0
- package/lib/schema/types/product/plan-product.js.map +1 -1
- package/lib/schema/types/product/product.d.ts.map +1 -1
- package/lib/schema/types/product/product.js +3 -0
- package/lib/schema/types/product/product.js.map +1 -1
- package/lib/schema/types/product/simple-product.d.ts.map +1 -1
- package/lib/schema/types/product/simple-product.js +1 -0
- package/lib/schema/types/product/simple-product.js.map +1 -1
- package/lib/schema/types/product/tokenized-product.d.ts.map +1 -1
- package/lib/schema/types/product/tokenized-product.js +1 -0
- package/lib/schema/types/product/tokenized-product.js.map +1 -1
- package/package.json +6 -6
- package/src/errors.ts +10 -0
- package/src/loaders/index.ts +2 -0
- package/src/loaders/productProxiesLoader.ts +37 -0
- package/src/mcp/tools/assortment/addAssortmentMediaUploadHandler.ts +2 -1
- package/src/mcp/tools/assortment/assortmentMediaHandler.ts +57 -0
- package/src/mcp/tools/assortment/index.ts +9 -1
- package/src/mcp/tools/assortment/removeAssortmentMediaHandler.ts +3 -1
- package/src/mcp/tools/assortment/reorderAssortmentMediaHandler.ts +2 -2
- package/src/mcp/tools/assortment/translatedAssortmentMediaTextsHandler.ts +8 -1
- package/src/mcp/tools/assortment/updateAssortmentMediaTextsHandler.ts +4 -1
- package/src/mcp/tools/product/addProductAssignmentHandler.ts +3 -1
- package/src/mcp/tools/product/addProductBundleItemHandler.ts +64 -0
- package/src/mcp/tools/product/addProductMediaUploadHandler.ts +3 -2
- package/src/mcp/tools/product/catalogPriceHandler.ts +61 -0
- package/src/mcp/tools/product/index.ts +104 -3
- package/src/mcp/tools/product/productAssignmentsHandler.ts +86 -0
- package/src/mcp/tools/product/productBundleItemsHandler.ts +50 -0
- package/src/mcp/tools/product/productMediaHandler.ts +53 -0
- package/src/mcp/tools/product/productSiblingsHandler.ts +82 -0
- package/src/mcp/tools/product/productVariationsHandler.ts +53 -0
- package/src/mcp/tools/product/removeProductBundleItemHandler.ts +55 -0
- package/src/mcp/tools/product/removeProductMediaHandler.ts +1 -1
- package/src/mcp/tools/product/reorderProductMediaHandler.ts +2 -2
- package/src/mcp/tools/product/simulatedPriceHandler.ts +82 -0
- package/src/mcp/tools/product/simulatedPriceRangeHandler.ts +126 -0
- package/src/mcp/tools/product/translatedProductMediaTextsHandler.ts +6 -2
- package/src/mcp/tools/product/translatedProductVariationTextsHandler.ts +6 -1
- package/src/mcp/tools/product/updateProductMediaTextsHandler.ts +1 -1
- package/src/mcp/tools/product/updateProductPlanHandler.ts +37 -7
- package/src/mcp/tools/product/updateProductVariationTextsHandler.ts +65 -0
- package/src/mcp/tools/product/variationProductsHandler.ts +61 -0
- package/src/mcp/tools/shopInfoHandler.ts +4 -2
- package/src/mcp/utils/getNormalizedProductDetails.ts +28 -0
- package/src/resolvers/mutations/filters/createFilter.ts +11 -6
- package/src/resolvers/mutations/products/createProductBundleItem.ts +13 -3
- package/src/resolvers/type/index.ts +2 -0
- package/src/resolvers/type/product/product-configurable-or-bundle-product-types.ts +10 -0
- package/src/resolvers/type/product/product-types.ts +4 -0
- package/src/schema/types/product/bundle-product.ts +2 -1
- package/src/schema/types/product/configurable-product.ts +1 -0
- package/src/schema/types/product/plan-product.ts +1 -0
- package/src/schema/types/product/product.ts +3 -0
- package/src/schema/types/product/simple-product.ts +1 -0
- package/src/schema/types/product/tokenized-product.ts +1 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { Context } from '../../../context.js';
|
|
3
|
+
import { log } from '@unchainedshop/logger';
|
|
4
|
+
import { ProductVariationNotFoundError } from '../../../errors.js';
|
|
5
|
+
|
|
6
|
+
export const ProductVariationTextInputSchema = z.object({
|
|
7
|
+
locale: z.string().min(1).describe('Locale code (e.g., "en", "de")'),
|
|
8
|
+
title: z.string().optional().describe('Title of the variation in the given locale'),
|
|
9
|
+
subtitle: z.string().optional().describe('Subtitle of the variation in the given locale'),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const UpdateProductVariationTextsSchema = {
|
|
13
|
+
productVariationId: z.string().min(1).describe('ID of the product variation to update'),
|
|
14
|
+
productVariationOptionValue: z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe('Optional production option value to filter variations'),
|
|
18
|
+
texts: z
|
|
19
|
+
.array(ProductVariationTextInputSchema)
|
|
20
|
+
.min(1)
|
|
21
|
+
.describe('Localized texts to apply to the variation'),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const UpdateProductVariationTextsZodSchema = z.object(UpdateProductVariationTextsSchema);
|
|
25
|
+
|
|
26
|
+
export type UpdateProductVariationTextsParams = z.infer<typeof UpdateProductVariationTextsZodSchema>;
|
|
27
|
+
|
|
28
|
+
export async function updateProductVariationTextsHandler(
|
|
29
|
+
context: Context,
|
|
30
|
+
params: UpdateProductVariationTextsParams,
|
|
31
|
+
) {
|
|
32
|
+
const { productVariationId, productVariationOptionValue, texts } = params;
|
|
33
|
+
const { modules, userId } = context;
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
log('handler updateProductVariationTextsHandler', { userId, params });
|
|
37
|
+
const productVariation = await modules.products.variations.findProductVariation({
|
|
38
|
+
productVariationId,
|
|
39
|
+
});
|
|
40
|
+
if (!productVariation) throw new ProductVariationNotFoundError({ productVariationId });
|
|
41
|
+
|
|
42
|
+
const updatedTexts = await modules.products.variations.texts.updateVariationTexts(
|
|
43
|
+
productVariationId,
|
|
44
|
+
texts as any,
|
|
45
|
+
productVariationOptionValue,
|
|
46
|
+
);
|
|
47
|
+
return {
|
|
48
|
+
content: [
|
|
49
|
+
{
|
|
50
|
+
type: 'text' as const,
|
|
51
|
+
text: JSON.stringify({ texts: updatedTexts, productId: productVariation.productId }),
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
} catch (error) {
|
|
56
|
+
return {
|
|
57
|
+
content: [
|
|
58
|
+
{
|
|
59
|
+
type: 'text' as const,
|
|
60
|
+
text: `Error updating product warehousing: ${(error as Error).message}`,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { Context } from '../../../context.js';
|
|
3
|
+
import { ProductNotFoundError, ProductWrongTypeError } from '../../../errors.js';
|
|
4
|
+
import { log } from '@unchainedshop/logger';
|
|
5
|
+
import { getNormalizedProductDetails } from '../../utils/getNormalizedProductDetails.js';
|
|
6
|
+
|
|
7
|
+
const VariationProductsVectorSchema = z.object({
|
|
8
|
+
key: z.string().min(1),
|
|
9
|
+
value: z.string().min(1),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const VariationProductsSchema = {
|
|
13
|
+
productId: z.string().min(1),
|
|
14
|
+
vectors: z.array(VariationProductsVectorSchema).min(1),
|
|
15
|
+
includeInactive: z.boolean().optional().default(true).describe('Whether to include inactive products'),
|
|
16
|
+
};
|
|
17
|
+
export const VariationProductsZodSchema = z.object(VariationProductsSchema);
|
|
18
|
+
export type VariationProductsParams = z.infer<typeof VariationProductsZodSchema>;
|
|
19
|
+
|
|
20
|
+
export const variationProductsHandler = async (context: Context, params: VariationProductsParams) => {
|
|
21
|
+
const { modules, userId } = context;
|
|
22
|
+
const { productId, vectors, includeInactive } = params;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
log('handler variationProductsHandler', { userId, params });
|
|
26
|
+
const product = await modules.products.findProduct({ productId });
|
|
27
|
+
if (!product) throw new ProductNotFoundError({ productId });
|
|
28
|
+
|
|
29
|
+
if (product.type !== 'CONFIGURABLE_PRODUCT') {
|
|
30
|
+
throw new ProductWrongTypeError({
|
|
31
|
+
productId,
|
|
32
|
+
received: product.type,
|
|
33
|
+
required: 'CONFIGURABLE_PRODUCT',
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const products = await modules.products.proxyProducts(product, vectors as any, {
|
|
38
|
+
includeInactive,
|
|
39
|
+
});
|
|
40
|
+
const normalizedProducts = await Promise.all(
|
|
41
|
+
products.map(async ({ _id }) => getNormalizedProductDetails(_id, context)),
|
|
42
|
+
);
|
|
43
|
+
return {
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
type: 'text' as const,
|
|
47
|
+
text: JSON.stringify({ products: normalizedProducts }),
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: 'text' as const,
|
|
56
|
+
text: `Error fetching variation products: ${(error as Error).message}`,
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
};
|
|
@@ -5,12 +5,14 @@ export async function shopInfoHandler(context: Context) {
|
|
|
5
5
|
const { version, userId, loaders, locale, countryCode } = context;
|
|
6
6
|
|
|
7
7
|
try {
|
|
8
|
-
log('
|
|
8
|
+
log('handler shopInfoHandler', { userId });
|
|
9
9
|
|
|
10
10
|
const language = await loaders.languageLoader.load({ isoCode: locale.language });
|
|
11
11
|
|
|
12
12
|
const country = await loaders.countryLoader.load({ isoCode: countryCode });
|
|
13
|
-
const defaultLanguageIsoCode = language
|
|
13
|
+
const defaultLanguageIsoCode = language?.isoCode
|
|
14
|
+
? `${language.isoCode}${country?.isoCode ? '-' + country.isoCode : ''}`
|
|
15
|
+
: null;
|
|
14
16
|
|
|
15
17
|
return {
|
|
16
18
|
content: [
|
|
@@ -13,11 +13,38 @@ export async function getNormalizedProductDetails(productId: string, context: Co
|
|
|
13
13
|
locale,
|
|
14
14
|
});
|
|
15
15
|
let variations = [];
|
|
16
|
+
let bundleItems = [];
|
|
16
17
|
if (product.type === ProductTypes.ConfigurableProduct)
|
|
17
18
|
variations = await context.modules.products.variations.findProductVariations({
|
|
18
19
|
productId: product._id,
|
|
19
20
|
});
|
|
20
21
|
|
|
22
|
+
if (product.type === ProductTypes.BundleProduct) {
|
|
23
|
+
bundleItems = await Promise.all(
|
|
24
|
+
(product.bundleItems || []).map(async (item) => {
|
|
25
|
+
const bundleItemProduct = await loaders.productLoader.load({
|
|
26
|
+
productId: item.productId,
|
|
27
|
+
});
|
|
28
|
+
const productMedias = await modules.products.media.findProductMedias({
|
|
29
|
+
productId: item.productId,
|
|
30
|
+
});
|
|
31
|
+
const media = await normalizeMediaUrl(productMedias, context);
|
|
32
|
+
const texts = await loaders.productTextLoader.load({
|
|
33
|
+
productId: item.productId,
|
|
34
|
+
locale,
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
product: {
|
|
38
|
+
...bundleItemProduct,
|
|
39
|
+
media,
|
|
40
|
+
texts,
|
|
41
|
+
},
|
|
42
|
+
...item,
|
|
43
|
+
};
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
21
48
|
// Get pricing information
|
|
22
49
|
let pricing = null;
|
|
23
50
|
try {
|
|
@@ -37,6 +64,7 @@ export async function getNormalizedProductDetails(productId: string, context: Co
|
|
|
37
64
|
texts,
|
|
38
65
|
media,
|
|
39
66
|
variations,
|
|
67
|
+
bundleItems,
|
|
40
68
|
pricing,
|
|
41
69
|
};
|
|
42
70
|
}
|
|
@@ -2,6 +2,7 @@ import { log } from '@unchainedshop/logger';
|
|
|
2
2
|
import { Filter } from '@unchainedshop/core-filters';
|
|
3
3
|
import { Context } from '../../../context.js';
|
|
4
4
|
import { FilterDirector, FilterInputText } from '@unchainedshop/core';
|
|
5
|
+
import { DuplicateFilterKeyError } from '../../../errors.js';
|
|
5
6
|
|
|
6
7
|
export default async function createFilter(
|
|
7
8
|
root: never,
|
|
@@ -10,13 +11,17 @@ export default async function createFilter(
|
|
|
10
11
|
) {
|
|
11
12
|
const { modules, userId } = context;
|
|
12
13
|
log('mutation createFilter', { userId });
|
|
14
|
+
try {
|
|
15
|
+
const newFilter = await modules.filters.create(filter);
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
await FilterDirector.invalidateProductIdCache(newFilter, context);
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
if (texts) {
|
|
20
|
+
await modules.filters.texts.updateTexts({ filterId: newFilter._id }, texts);
|
|
21
|
+
}
|
|
22
|
+
return newFilter;
|
|
23
|
+
} catch (e) {
|
|
24
|
+
if (e?.message?.includes('duplicate')) throw new DuplicateFilterKeyError({ filter });
|
|
25
|
+
else throw e;
|
|
20
26
|
}
|
|
21
|
-
return newFilter;
|
|
22
27
|
}
|
|
@@ -2,7 +2,12 @@ import { log } from '@unchainedshop/logger';
|
|
|
2
2
|
import { ProductTypes } from '@unchainedshop/core-products';
|
|
3
3
|
import { Context } from '../../../context.js';
|
|
4
4
|
import { ProductBundleItem } from '@unchainedshop/core-products';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
ProductNotFoundError,
|
|
7
|
+
InvalidIdError,
|
|
8
|
+
ProductWrongTypeError,
|
|
9
|
+
CyclicProductBundlingNotSupportedError,
|
|
10
|
+
} from '../../../errors.js';
|
|
6
11
|
|
|
7
12
|
export default async function createProductBundleItem(
|
|
8
13
|
root: never,
|
|
@@ -24,8 +29,13 @@ export default async function createProductBundleItem(
|
|
|
24
29
|
required: ProductTypes.BundleProduct,
|
|
25
30
|
});
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
const itemProduct = await modules.products.findProduct({ productId: item.productId });
|
|
33
|
+
if (!itemProduct) throw new ProductNotFoundError({ productId: item.productId });
|
|
34
|
+
|
|
35
|
+
if (itemProduct._id === product._id)
|
|
36
|
+
throw new CyclicProductBundlingNotSupportedError({
|
|
37
|
+
productId: itemProduct._id,
|
|
38
|
+
});
|
|
29
39
|
|
|
30
40
|
await modules.products.bundleItems.addBundleItem(productId, item);
|
|
31
41
|
|
|
@@ -52,6 +52,7 @@ import { ProductVariation } from './product/product-variation-types.js';
|
|
|
52
52
|
import { ProductVariationAssignment } from './product/product-variation-assignment-types.js';
|
|
53
53
|
import { ProductVariationAssignmentVector } from './product/product-variation-assignment-vector.js';
|
|
54
54
|
import { ProductVariationOption } from './product/product-variation-option-types.js';
|
|
55
|
+
import { ConfigurableOrBundleProduct } from './product/product-configurable-or-bundle-product-types.js';
|
|
55
56
|
import { Quotation } from './quotation-types.js';
|
|
56
57
|
import { Shop } from './shop-types.js';
|
|
57
58
|
import { SimpleProduct } from './product/product-simple-types.js';
|
|
@@ -123,6 +124,7 @@ const types = {
|
|
|
123
124
|
ProductVariationAssignmentVector,
|
|
124
125
|
ProductVariationOption,
|
|
125
126
|
ProductSearchResult,
|
|
127
|
+
ConfigurableOrBundleProduct,
|
|
126
128
|
Quotation,
|
|
127
129
|
Shop,
|
|
128
130
|
SimpleProduct,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Product as ProductType } from '@unchainedshop/core-products';
|
|
2
|
+
import { ProductTypes } from '@unchainedshop/core-products';
|
|
3
|
+
import { objectInvert } from '@unchainedshop/utils';
|
|
4
|
+
|
|
5
|
+
export const ConfigurableOrBundleProduct = {
|
|
6
|
+
__resolveType: (product: ProductType): string => {
|
|
7
|
+
const invertedProductTypes = objectInvert(ProductTypes);
|
|
8
|
+
return invertedProductTypes[product.type];
|
|
9
|
+
},
|
|
10
|
+
};
|
|
@@ -13,6 +13,10 @@ export const Product = {
|
|
|
13
13
|
return invertedProductTypes[product.type];
|
|
14
14
|
},
|
|
15
15
|
|
|
16
|
+
async proxies(product: ProductType, _: never, context: Context): Promise<ProductType[]> {
|
|
17
|
+
return context.loaders.productProxiesLoader.load({ productId: product._id });
|
|
18
|
+
},
|
|
19
|
+
|
|
16
20
|
async assortmentPaths(
|
|
17
21
|
product: ProductType,
|
|
18
22
|
params: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default [
|
|
2
2
|
/* GraphQL */ `
|
|
3
3
|
"""
|
|
4
|
-
A Bundle product consists of multiple
|
|
4
|
+
A Bundle product consists of multiple products
|
|
5
5
|
"""
|
|
6
6
|
type BundleProduct implements Product @cacheControl(maxAge: 180) {
|
|
7
7
|
_id: ID!
|
|
@@ -22,6 +22,7 @@ export default [
|
|
|
22
22
|
): [ProductReview!]!
|
|
23
23
|
reviewsCount(queryString: String): Int!
|
|
24
24
|
assortmentPaths: [ProductAssortmentPath!]!
|
|
25
|
+
proxies: [ConfigurableOrBundleProduct!]!
|
|
25
26
|
siblings(
|
|
26
27
|
assortmentId: ID
|
|
27
28
|
limit: Int = 10
|
|
@@ -73,6 +73,7 @@ export default [
|
|
|
73
73
|
media(limit: Int = 10, offset: Int = 0, tags: [LowerCaseString!]): [ProductMedia!]!
|
|
74
74
|
texts(forceLocale: Locale): ProductTexts
|
|
75
75
|
assortmentPaths: [ProductAssortmentPath!]!
|
|
76
|
+
proxies: [ConfigurableOrBundleProduct!]!
|
|
76
77
|
siblings(
|
|
77
78
|
assortmentId: ID
|
|
78
79
|
limit: Int = 10
|
|
@@ -51,6 +51,7 @@ export default [
|
|
|
51
51
|
configuration: [ProductConfigurationParameterInput!]
|
|
52
52
|
): Price @cacheControl(scope: PRIVATE)
|
|
53
53
|
assortmentPaths(forceLocale: Locale): [ProductAssortmentPath!]!
|
|
54
|
+
proxies: [ConfigurableOrBundleProduct!]!
|
|
54
55
|
siblings(
|
|
55
56
|
assortmentId: ID
|
|
56
57
|
limit: Int = 10
|
|
@@ -71,6 +71,7 @@ export default [
|
|
|
71
71
|
): [ProductReview!]!
|
|
72
72
|
reviewsCount(queryString: String): Int!
|
|
73
73
|
assortmentPaths: [ProductAssortmentPath!]!
|
|
74
|
+
proxies: [ConfigurableOrBundleProduct!]!
|
|
74
75
|
siblings(
|
|
75
76
|
assortmentId: ID
|
|
76
77
|
limit: Int = 10
|
|
@@ -132,5 +133,7 @@ export default [
|
|
|
132
133
|
amount: Int!
|
|
133
134
|
maxQuantity: Int
|
|
134
135
|
}
|
|
136
|
+
|
|
137
|
+
union ConfigurableOrBundleProduct = BundleProduct | ConfigurableProduct
|
|
135
138
|
`,
|
|
136
139
|
];
|
|
@@ -42,6 +42,7 @@ export default [
|
|
|
42
42
|
): Price @cacheControl(scope: PRIVATE, maxAge: 10)
|
|
43
43
|
simulatedStocks(referenceDate: Timestamp): [Stock!] @cacheControl(scope: PRIVATE, maxAge: 10)
|
|
44
44
|
assortmentPaths(forceLocale: Locale): [ProductAssortmentPath!]!
|
|
45
|
+
proxies: [ConfigurableOrBundleProduct!]!
|
|
45
46
|
siblings(
|
|
46
47
|
assortmentId: ID
|
|
47
48
|
limit: Int = 10
|