@unchainedshop/core 4.0.0-rc.14 → 4.0.0-rc.16

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.
Files changed (193) hide show
  1. package/lib/bulk-importer/createBulkImporter.d.ts +61 -0
  2. package/lib/bulk-importer/createBulkImporter.d.ts.map +1 -0
  3. package/lib/bulk-importer/createBulkImporter.js +135 -0
  4. package/lib/bulk-importer/createBulkImporter.js.map +1 -0
  5. package/lib/bulk-importer/handlers/assortment/create.d.ts +15 -0
  6. package/lib/bulk-importer/handlers/assortment/create.d.ts.map +1 -0
  7. package/lib/bulk-importer/handlers/assortment/create.js +62 -0
  8. package/lib/bulk-importer/handlers/assortment/create.js.map +1 -0
  9. package/lib/bulk-importer/handlers/assortment/index.d.ts +4 -0
  10. package/lib/bulk-importer/handlers/assortment/index.d.ts.map +1 -0
  11. package/lib/bulk-importer/handlers/assortment/index.js +4 -0
  12. package/lib/bulk-importer/handlers/assortment/index.js.map +1 -0
  13. package/lib/bulk-importer/handlers/assortment/remove.d.ts +12 -0
  14. package/lib/bulk-importer/handlers/assortment/remove.d.ts.map +1 -0
  15. package/lib/bulk-importer/handlers/assortment/remove.js +13 -0
  16. package/lib/bulk-importer/handlers/assortment/remove.js.map +1 -0
  17. package/lib/bulk-importer/handlers/assortment/update.d.ts +16 -0
  18. package/lib/bulk-importer/handlers/assortment/update.d.ts.map +1 -0
  19. package/lib/bulk-importer/handlers/assortment/update.js +62 -0
  20. package/lib/bulk-importer/handlers/assortment/update.js.map +1 -0
  21. package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.d.ts +9 -0
  22. package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.d.ts.map +1 -0
  23. package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.js +37 -0
  24. package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.js.map +1 -0
  25. package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.d.ts +9 -0
  26. package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.d.ts.map +1 -0
  27. package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.js +32 -0
  28. package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.js.map +1 -0
  29. package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.d.ts +9 -0
  30. package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.d.ts.map +1 -0
  31. package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.js +37 -0
  32. package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.js.map +1 -0
  33. package/lib/bulk-importer/handlers/assortment/upsertMedia.d.ts +11 -0
  34. package/lib/bulk-importer/handlers/assortment/upsertMedia.d.ts.map +1 -0
  35. package/lib/bulk-importer/handlers/assortment/upsertMedia.js +39 -0
  36. package/lib/bulk-importer/handlers/assortment/upsertMedia.js.map +1 -0
  37. package/lib/bulk-importer/handlers/filter/create.d.ts +13 -0
  38. package/lib/bulk-importer/handlers/filter/create.d.ts.map +1 -0
  39. package/lib/bulk-importer/handlers/filter/create.js +58 -0
  40. package/lib/bulk-importer/handlers/filter/create.js.map +1 -0
  41. package/lib/bulk-importer/handlers/filter/index.d.ts +4 -0
  42. package/lib/bulk-importer/handlers/filter/index.d.ts.map +1 -0
  43. package/lib/bulk-importer/handlers/filter/index.js +4 -0
  44. package/lib/bulk-importer/handlers/filter/index.js.map +1 -0
  45. package/lib/bulk-importer/handlers/filter/remove.d.ts +12 -0
  46. package/lib/bulk-importer/handlers/filter/remove.d.ts.map +1 -0
  47. package/lib/bulk-importer/handlers/filter/remove.js +14 -0
  48. package/lib/bulk-importer/handlers/filter/remove.js.map +1 -0
  49. package/lib/bulk-importer/handlers/filter/update.d.ts +13 -0
  50. package/lib/bulk-importer/handlers/filter/update.d.ts.map +1 -0
  51. package/lib/bulk-importer/handlers/filter/update.js +48 -0
  52. package/lib/bulk-importer/handlers/filter/update.js.map +1 -0
  53. package/lib/bulk-importer/handlers/product/create.d.ts +15 -0
  54. package/lib/bulk-importer/handlers/product/create.d.ts.map +1 -0
  55. package/lib/bulk-importer/handlers/product/create.js +53 -0
  56. package/lib/bulk-importer/handlers/product/create.js.map +1 -0
  57. package/lib/bulk-importer/handlers/product/index.d.ts +4 -0
  58. package/lib/bulk-importer/handlers/product/index.d.ts.map +1 -0
  59. package/lib/bulk-importer/handlers/product/index.js +4 -0
  60. package/lib/bulk-importer/handlers/product/index.js.map +1 -0
  61. package/lib/bulk-importer/handlers/product/remove.d.ts +14 -0
  62. package/lib/bulk-importer/handlers/product/remove.d.ts.map +1 -0
  63. package/lib/bulk-importer/handlers/product/remove.js +13 -0
  64. package/lib/bulk-importer/handlers/product/remove.js.map +1 -0
  65. package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.d.ts +3 -0
  66. package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.d.ts.map +1 -0
  67. package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.js +16 -0
  68. package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.js.map +1 -0
  69. package/lib/bulk-importer/handlers/product/update.d.ts +15 -0
  70. package/lib/bulk-importer/handlers/product/update.d.ts.map +1 -0
  71. package/lib/bulk-importer/handlers/product/update.js +48 -0
  72. package/lib/bulk-importer/handlers/product/update.js.map +1 -0
  73. package/lib/bulk-importer/handlers/product/upsertMedia.d.ts +10 -0
  74. package/lib/bulk-importer/handlers/product/upsertMedia.d.ts.map +1 -0
  75. package/lib/bulk-importer/handlers/product/upsertMedia.js +45 -0
  76. package/lib/bulk-importer/handlers/product/upsertMedia.js.map +1 -0
  77. package/lib/bulk-importer/handlers/product/upsertVariations.d.ts +8 -0
  78. package/lib/bulk-importer/handlers/product/upsertVariations.d.ts.map +1 -0
  79. package/lib/bulk-importer/handlers/product/upsertVariations.js +48 -0
  80. package/lib/bulk-importer/handlers/product/upsertVariations.js.map +1 -0
  81. package/lib/bulk-importer/handlers/utils/convertTagsToLowerCase.d.ts +3 -0
  82. package/lib/bulk-importer/handlers/utils/convertTagsToLowerCase.d.ts.map +1 -0
  83. package/lib/bulk-importer/handlers/utils/convertTagsToLowerCase.js +6 -0
  84. package/lib/bulk-importer/handlers/utils/convertTagsToLowerCase.js.map +1 -0
  85. package/lib/bulk-importer/upsertAsset.d.ts +12 -0
  86. package/lib/bulk-importer/upsertAsset.d.ts.map +1 -0
  87. package/lib/bulk-importer/upsertAsset.js +33 -0
  88. package/lib/bulk-importer/upsertAsset.js.map +1 -0
  89. package/lib/core-index.d.ts +7 -5
  90. package/lib/core-index.d.ts.map +1 -1
  91. package/lib/core-index.js +5 -1
  92. package/lib/core-index.js.map +1 -1
  93. package/lib/directors/FilterAdapter.d.ts +1 -1
  94. package/lib/directors/FilterAdapter.d.ts.map +1 -1
  95. package/lib/directors/FilterDirector.d.ts.map +1 -1
  96. package/lib/directors/FilterDirector.js +6 -7
  97. package/lib/directors/FilterDirector.js.map +1 -1
  98. package/lib/directors/PaymentDirector.js +2 -2
  99. package/lib/directors/PaymentDirector.js.map +1 -1
  100. package/lib/directors/WorkerAdapter.d.ts +3 -2
  101. package/lib/directors/WorkerAdapter.d.ts.map +1 -1
  102. package/lib/directors/WorkerAdapter.js.map +1 -1
  103. package/lib/factory/index.d.ts +3 -0
  104. package/lib/factory/index.d.ts.map +1 -0
  105. package/lib/factory/index.js +3 -0
  106. package/lib/factory/index.js.map +1 -0
  107. package/lib/factory/registerProductDiscoverabilityFilter copy.d.ts +5 -0
  108. package/lib/factory/registerProductDiscoverabilityFilter copy.d.ts.map +1 -0
  109. package/lib/factory/registerProductDiscoverabilityFilter copy.js +28 -0
  110. package/lib/factory/registerProductDiscoverabilityFilter copy.js.map +1 -0
  111. package/lib/factory/registerProductDiscoverabilityFilter.d.ts +5 -0
  112. package/lib/factory/registerProductDiscoverabilityFilter.d.ts.map +1 -0
  113. package/lib/factory/registerProductDiscoverabilityFilter.js +27 -0
  114. package/lib/factory/registerProductDiscoverabilityFilter.js.map +1 -0
  115. package/lib/modules.d.ts.map +1 -1
  116. package/lib/modules.js +1 -0
  117. package/lib/modules.js.map +1 -1
  118. package/lib/services/activateEnrollment.d.ts.map +1 -1
  119. package/lib/services/activateEnrollment.js +5 -9
  120. package/lib/services/activateEnrollment.js.map +1 -1
  121. package/lib/services/addMessage.d.ts +4 -0
  122. package/lib/services/addMessage.d.ts.map +1 -0
  123. package/lib/services/addMessage.js +15 -0
  124. package/lib/services/addMessage.js.map +1 -0
  125. package/lib/services/index.d.ts +4 -0
  126. package/lib/services/index.d.ts.map +1 -1
  127. package/lib/services/index.js +4 -0
  128. package/lib/services/index.js.map +1 -1
  129. package/lib/services/initCartProviders.d.ts.map +1 -1
  130. package/lib/services/initCartProviders.js +6 -2
  131. package/lib/services/initCartProviders.js.map +1 -1
  132. package/lib/services/initializeEnrollment.d.ts.map +1 -1
  133. package/lib/services/initializeEnrollment.js +5 -9
  134. package/lib/services/initializeEnrollment.js.map +1 -1
  135. package/lib/services/processQuotation.d.ts.map +1 -1
  136. package/lib/services/processQuotation.js +4 -8
  137. package/lib/services/processQuotation.js.map +1 -1
  138. package/lib/services/removeFiles.js +2 -2
  139. package/lib/services/removeFiles.js.map +1 -1
  140. package/lib/services/searchAssortments.d.ts.map +1 -1
  141. package/lib/services/searchAssortments.js +2 -1
  142. package/lib/services/searchAssortments.js.map +1 -1
  143. package/lib/services/searchProducts.d.ts.map +1 -1
  144. package/lib/services/searchProducts.js +2 -1
  145. package/lib/services/searchProducts.js.map +1 -1
  146. package/lib/services/terminateEnrollment.d.ts.map +1 -1
  147. package/lib/services/terminateEnrollment.js +5 -9
  148. package/lib/services/terminateEnrollment.js.map +1 -1
  149. package/lib/services/updateCalculation.d.ts.map +1 -1
  150. package/lib/services/updateCalculation.js +5 -3
  151. package/lib/services/updateCalculation.js.map +1 -1
  152. package/package.json +21 -20
  153. package/src/bulk-importer/createBulkImporter.ts +193 -0
  154. package/src/bulk-importer/handlers/assortment/create.ts +87 -0
  155. package/src/bulk-importer/handlers/assortment/index.ts +3 -0
  156. package/src/bulk-importer/handlers/assortment/remove.ts +15 -0
  157. package/src/bulk-importer/handlers/assortment/update.ts +89 -0
  158. package/src/bulk-importer/handlers/assortment/upsertAssortmentChildren.ts +52 -0
  159. package/src/bulk-importer/handlers/assortment/upsertAssortmentFilters.ts +42 -0
  160. package/src/bulk-importer/handlers/assortment/upsertAssortmentProducts.ts +50 -0
  161. package/src/bulk-importer/handlers/assortment/upsertMedia.ts +58 -0
  162. package/src/bulk-importer/handlers/filter/create.ts +76 -0
  163. package/src/bulk-importer/handlers/filter/index.ts +3 -0
  164. package/src/bulk-importer/handlers/filter/remove.ts +20 -0
  165. package/src/bulk-importer/handlers/filter/update.ts +67 -0
  166. package/src/bulk-importer/handlers/product/create.ts +70 -0
  167. package/src/bulk-importer/handlers/product/index.ts +3 -0
  168. package/src/bulk-importer/handlers/product/remove.ts +21 -0
  169. package/src/bulk-importer/handlers/product/transformSpecificationToProductStructure.ts +22 -0
  170. package/src/bulk-importer/handlers/product/update.ts +66 -0
  171. package/src/bulk-importer/handlers/product/upsertMedia.ts +64 -0
  172. package/src/bulk-importer/handlers/product/upsertVariations.ts +71 -0
  173. package/src/bulk-importer/handlers/utils/convertTagsToLowerCase.ts +4 -0
  174. package/src/bulk-importer/upsertAsset.ts +42 -0
  175. package/src/core-index.ts +11 -6
  176. package/src/directors/FilterAdapter.ts +1 -1
  177. package/src/directors/FilterDirector.ts +6 -7
  178. package/src/directors/PaymentDirector.ts +2 -2
  179. package/src/directors/WorkerAdapter.ts +8 -3
  180. package/src/factory/index.ts +3 -0
  181. package/src/factory/registerProductDiscoverabilityFilter.ts +36 -0
  182. package/src/modules.ts +1 -0
  183. package/src/services/activateEnrollment.ts +5 -9
  184. package/src/services/addMessage.ts +20 -0
  185. package/src/services/index.ts +4 -0
  186. package/src/services/initCartProviders.ts +6 -8
  187. package/src/services/initializeEnrollment.ts +5 -9
  188. package/src/services/processQuotation.ts +4 -8
  189. package/src/services/removeFiles.ts +2 -2
  190. package/src/services/searchAssortments.ts +2 -1
  191. package/src/services/searchProducts.ts +3 -1
  192. package/src/services/terminateEnrollment.ts +5 -9
  193. package/src/services/updateCalculation.ts +5 -3
@@ -0,0 +1,67 @@
1
+ import { Modules } from '../../../modules.js';
2
+ import createFilter from './create.js';
3
+
4
+ export default async function updateFilter(
5
+ payload: any,
6
+ { logger, updateShouldUpsertIfIDNotExists }: { logger: any; updateShouldUpsertIfIDNotExists: boolean },
7
+ unchainedAPI: { modules: Modules },
8
+ ) {
9
+ const { modules } = unchainedAPI;
10
+ const { specification, _id } = payload;
11
+
12
+ if (!(await modules.filters.filterExists({ filterId: _id }))) {
13
+ if (updateShouldUpsertIfIDNotExists) {
14
+ return createFilter(payload, { logger, createShouldUpsertIfIDExists: false }, unchainedAPI);
15
+ }
16
+ throw new Error(`Can't update non-existing filter ${_id}`);
17
+ }
18
+
19
+ const { content, options, ...filterData } = specification;
20
+
21
+ if (specification) {
22
+ logger.debug('update filter object', specification);
23
+ await modules.filters.update(_id, {
24
+ ...filterData,
25
+ options: options?.map((option) => option.value) || [],
26
+ });
27
+ }
28
+
29
+ if (content) {
30
+ logger.debug('replace localized content for filter', content);
31
+ await modules.filters.texts.updateTexts(
32
+ { filterId: _id },
33
+ Object.entries(content).map(([locale, localizedData]: [string, any]) => {
34
+ return {
35
+ locale,
36
+ ...localizedData,
37
+ };
38
+ }),
39
+ );
40
+ }
41
+
42
+ if (options) {
43
+ logger.debug('replace localized content for filter options', content);
44
+ await Promise.all(
45
+ options.map(async ({ content: optionContent, value: optionValue }) => {
46
+ if (optionContent) {
47
+ await modules.filters.texts.updateTexts(
48
+ { filterId: _id, filterOptionValue: optionValue },
49
+ Object.entries(optionContent).map(([locale, localizedData]: [string, any]) => {
50
+ return {
51
+ locale,
52
+ ...localizedData,
53
+ };
54
+ }),
55
+ );
56
+ }
57
+ }),
58
+ );
59
+ }
60
+
61
+ return {
62
+ entity: 'FILTER',
63
+ operation: 'update',
64
+ _id,
65
+ success: true,
66
+ };
67
+ }
@@ -0,0 +1,70 @@
1
+ import { Modules } from '../../../modules.js';
2
+ import { Services } from '../../../services/index.js';
3
+ import upsertVariations from './upsertVariations.js';
4
+ import upsertMedia from './upsertMedia.js';
5
+ import transformSpecificationToProductStructure from './transformSpecificationToProductStructure.js';
6
+
7
+ export default async function createProduct(
8
+ payload: any,
9
+ { logger, createShouldUpsertIfIDExists },
10
+ unchainedAPI: { modules: Modules; services: Services },
11
+ ) {
12
+ const { modules } = unchainedAPI;
13
+ const { specification, media, variations, _id } = payload;
14
+
15
+ if (!specification) throw new Error(`Specification is required when creating new product ${_id}`);
16
+
17
+ if (!specification.content) throw new Error(`Content is required when creating new product ${_id}`);
18
+
19
+ const productData = transformSpecificationToProductStructure(specification);
20
+ logger.debug('create product object', productData);
21
+ try {
22
+ await modules.products.create({
23
+ ...productData,
24
+ _id,
25
+ });
26
+ } catch (e) {
27
+ if (!createShouldUpsertIfIDExists) throw e;
28
+
29
+ logger.debug('entity already exists, falling back to update', specification);
30
+ await modules.products.update(_id, {
31
+ ...productData,
32
+ });
33
+ }
34
+
35
+ if (!(await modules.products.productExists({ productId: _id }))) {
36
+ throw new Error(`Can't create product ${_id}, fields missing?`);
37
+ }
38
+
39
+ if (specification.content) {
40
+ logger.debug('create localized content for product', specification.content);
41
+ await modules.products.texts.updateTexts(
42
+ _id,
43
+ Object.entries(specification.content).map(([locale, localizedData]: [string, any]) => {
44
+ return {
45
+ locale,
46
+ ...localizedData,
47
+ };
48
+ }),
49
+ );
50
+ }
51
+
52
+ logger.debug('create product variations', variations);
53
+ await upsertVariations(
54
+ {
55
+ variations: variations || [],
56
+ productId: _id,
57
+ },
58
+ unchainedAPI,
59
+ );
60
+
61
+ logger.debug('create product media', media);
62
+ await upsertMedia({ media: media || [], productId: _id }, unchainedAPI);
63
+
64
+ return {
65
+ entity: 'PRODUCT',
66
+ operation: 'create',
67
+ _id,
68
+ success: true,
69
+ };
70
+ }
@@ -0,0 +1,3 @@
1
+ export { default as create } from './create.js';
2
+ export { default as update } from './update.js';
3
+ export { default as remove } from './remove.js';
@@ -0,0 +1,21 @@
1
+ import { Modules } from '../../../modules.js';
2
+ import { Services } from '../../../services/index.js';
3
+
4
+ export default async function removeProduct(
5
+ payload: any,
6
+ { logger },
7
+ unchainedAPI: { modules: Modules; services: Services },
8
+ ) {
9
+ const { services } = unchainedAPI;
10
+ const { _id } = payload;
11
+ logger.debug(`remove product ${_id}`);
12
+
13
+ await services.products.removeProduct({ productId: _id });
14
+
15
+ return {
16
+ entity: 'PRODUCT',
17
+ operation: 'remove',
18
+ _id,
19
+ success: true,
20
+ };
21
+ }
@@ -0,0 +1,22 @@
1
+ import convertTagsToLowerCase from '../utils/convertTagsToLowerCase.js';
2
+
3
+ export default (specification) => {
4
+ const {
5
+ variationResolvers: assignments,
6
+ content, // eslint-disable-line
7
+ warehousing: warehousingEmbeddedSupply,
8
+ ...productData
9
+ } = specification;
10
+
11
+ const { dimensions: supply, ...warehousing } = warehousingEmbeddedSupply || {};
12
+ const tags = convertTagsToLowerCase(productData?.tags);
13
+ const proxy = assignments ? { assignments } : undefined;
14
+
15
+ return {
16
+ ...productData,
17
+ tags,
18
+ warehousing,
19
+ supply,
20
+ proxy,
21
+ };
22
+ };
@@ -0,0 +1,66 @@
1
+ import { Modules } from '../../../modules.js';
2
+ import { Services } from '../../../services/index.js';
3
+ import upsertVariations from './upsertVariations.js';
4
+ import upsertMedia from './upsertMedia.js';
5
+ import transformSpecificationToProductStructure from './transformSpecificationToProductStructure.js';
6
+ import createProduct from './create.js';
7
+
8
+ export default async function updateProduct(
9
+ payload: any,
10
+ { logger, updateShouldUpsertIfIDNotExists },
11
+ unchainedAPI: { modules: Modules; services: Services },
12
+ ) {
13
+ const { modules } = unchainedAPI;
14
+ const { specification, media, variations, _id } = payload;
15
+
16
+ if (!(await modules.products.productExists({ productId: _id }))) {
17
+ if (updateShouldUpsertIfIDNotExists) {
18
+ return createProduct(payload, { logger, createShouldUpsertIfIDExists: false }, unchainedAPI);
19
+ }
20
+ throw new Error(`Can't update non-existing product ${_id}`);
21
+ }
22
+
23
+ if (specification) {
24
+ const productData = transformSpecificationToProductStructure(specification);
25
+ logger.debug('update product object', productData);
26
+ await modules.products.update(_id, {
27
+ ...productData,
28
+ });
29
+
30
+ if (specification.content) {
31
+ logger.debug('replace localized content for product', specification.content);
32
+ await modules.products.texts.updateTexts(
33
+ _id,
34
+ Object.entries(specification.content).map(([locale, localizedData]: [string, any]) => {
35
+ return {
36
+ locale,
37
+ ...localizedData,
38
+ };
39
+ }),
40
+ );
41
+ }
42
+ }
43
+
44
+ if (variations) {
45
+ logger.debug('replace variations', variations);
46
+ await upsertVariations(
47
+ {
48
+ variations: variations || [],
49
+ productId: _id,
50
+ },
51
+ unchainedAPI,
52
+ );
53
+ }
54
+
55
+ if (media) {
56
+ logger.debug('replace product media', media);
57
+ await upsertMedia({ media, productId: _id }, unchainedAPI);
58
+ }
59
+
60
+ return {
61
+ entity: 'PRODUCT',
62
+ operation: 'update',
63
+ _id,
64
+ success: true,
65
+ };
66
+ }
@@ -0,0 +1,64 @@
1
+ import { ProductMedia } from '@unchainedshop/core-products';
2
+ import { Modules } from '../../../modules.js';
3
+ import { Services } from '../../../services/index.js';
4
+ import convertTagsToLowerCase from '../utils/convertTagsToLowerCase.js';
5
+ import upsertAsset from '../../upsertAsset.js';
6
+
7
+ const upsertProductMedia = async (productMedia: ProductMedia, { modules }: { modules: Modules }) => {
8
+ try {
9
+ const productMediaObj = await modules.products.media.create(productMedia);
10
+ return productMediaObj;
11
+ } catch {
12
+ const { _id, ...productMediaData } = productMedia;
13
+ const productMediaId = _id;
14
+ return modules.products.media.update(productMediaId, productMediaData);
15
+ }
16
+ };
17
+
18
+ export default async function upsertMedia(
19
+ { media, productId },
20
+ unchainedAPI: { modules: Modules; services: Services },
21
+ ) {
22
+ const { modules } = unchainedAPI;
23
+
24
+ const productMediaObjects = await Promise.all(
25
+ media.map(async ({ asset, content, ...mediaData }) => {
26
+ const tags = convertTagsToLowerCase(mediaData?.tags);
27
+ const file = await upsertAsset(
28
+ 'product-media',
29
+ { meta: { ...(asset.meta || {}), productId }, ...asset },
30
+ unchainedAPI,
31
+ );
32
+ if (!file) throw new Error(`Unable to create binary ${asset._id}`);
33
+ const fileId = file._id;
34
+ const productMedia = await upsertProductMedia(
35
+ {
36
+ ...mediaData,
37
+ tags,
38
+ productId,
39
+ mediaId: file._id,
40
+ } as ProductMedia,
41
+ unchainedAPI,
42
+ );
43
+ if (!productMedia) throw new Error(`Unable to create product media object for file ${fileId}`);
44
+
45
+ if (content) {
46
+ await modules.products.media.texts.updateMediaTexts(
47
+ productMedia._id,
48
+ Object.entries(content).map(([locale, localizedData]: [string, any]) => {
49
+ return {
50
+ locale,
51
+ ...localizedData,
52
+ };
53
+ }),
54
+ );
55
+ }
56
+ return productMedia;
57
+ }),
58
+ );
59
+
60
+ await modules.products.media.deleteMediaFiles({
61
+ productId,
62
+ excludedProductMediaIds: productMediaObjects.map((obj) => obj._id),
63
+ });
64
+ }
@@ -0,0 +1,71 @@
1
+ import { ProductVariation } from '@unchainedshop/core-products';
2
+ import { Modules } from '../../../modules.js';
3
+
4
+ const upsert = async (productVariation: ProductVariation, unchainedAPI: { modules: Modules }) => {
5
+ const { modules } = unchainedAPI;
6
+ try {
7
+ const newVariation = await modules.products.variations.create(productVariation);
8
+ return newVariation;
9
+ } catch {
10
+ return modules.products.variations.update(productVariation._id, productVariation);
11
+ }
12
+ };
13
+
14
+ export default async function upsertVariations(
15
+ { variations, productId },
16
+ unchainedAPI: { modules: Modules },
17
+ ) {
18
+ const { modules } = unchainedAPI;
19
+
20
+ const upsertedProductVariationIds = await Promise.all(
21
+ variations.map(async ({ content, options, ...variationsRest }) => {
22
+ const variation = await upsert(
23
+ {
24
+ ...variationsRest,
25
+ options: options.map((option) => option.value),
26
+ productId,
27
+ },
28
+ unchainedAPI,
29
+ );
30
+
31
+ await Promise.all(
32
+ options.map(async ({ content: optionContent, value: optionValue }) => {
33
+ if (optionContent) {
34
+ await modules.products.variations.texts.updateVariationTexts(
35
+ variation._id,
36
+ Object.entries(optionContent).map(([locale, localizedData]: [string, any]) => {
37
+ return {
38
+ locale,
39
+ ...localizedData,
40
+ };
41
+ }),
42
+ optionValue,
43
+ );
44
+ }
45
+ }),
46
+ );
47
+ if (content) {
48
+ await modules.products.variations.texts.updateVariationTexts(
49
+ variation._id,
50
+ Object.entries(content).map(([locale, localizedData]: [string, any]) => {
51
+ return {
52
+ locale,
53
+ ...localizedData,
54
+ };
55
+ }),
56
+ );
57
+ }
58
+ return variation._id;
59
+ }),
60
+ );
61
+ const allVariations = await modules.products.variations.findProductVariations({
62
+ productId,
63
+ });
64
+ await Promise.all(
65
+ allVariations.map(async (variation) => {
66
+ if (!upsertedProductVariationIds.includes(variation._id)) {
67
+ await modules.products.variations.delete(variation._id);
68
+ }
69
+ }),
70
+ );
71
+ }
@@ -0,0 +1,4 @@
1
+ export default (tags) => {
2
+ if (Array.isArray(tags)) return tags.map((tag) => tag.toLowerCase());
3
+ return null;
4
+ };
@@ -0,0 +1,42 @@
1
+ import type { File } from '@unchainedshop/core-files';
2
+ import { Modules } from '../modules.js';
3
+ import { Services } from '../services/index.js';
4
+
5
+ const upsertAsset = async (
6
+ directoryName: string,
7
+ asset: File & { fileName: string; headers?: Record<string, unknown> },
8
+ unchainedAPI: { modules: Modules; services: Services },
9
+ ) => {
10
+ const { modules, services } = unchainedAPI;
11
+ const { _id: fileId, fileName, url, meta, headers, ...assetData } = asset;
12
+
13
+ try {
14
+ const existingFile = fileId && (await modules.files.findFile({ fileId }));
15
+ if (existingFile) {
16
+ if (JSON.stringify(meta) === JSON.stringify(existingFile.meta)) {
17
+ return existingFile;
18
+ }
19
+ await modules.files.update(fileId, { meta, ...assetData });
20
+ const updatedFile = await modules.files.findFile({ fileId });
21
+ return updatedFile;
22
+ }
23
+
24
+ const assetObject = await services.files.uploadFileFromURL({
25
+ directoryName,
26
+ fileInput: {
27
+ fileLink: url,
28
+ fileName,
29
+ fileId,
30
+ headers,
31
+ },
32
+ meta,
33
+ });
34
+
35
+ if (!assetObject) throw new Error('Media not created');
36
+ return assetObject;
37
+ } catch {
38
+ return null;
39
+ }
40
+ };
41
+
42
+ export default upsertAsset;
package/src/core-index.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { mongodb, MigrationRepository, ModuleInput } from '@unchainedshop/mongodb';
2
2
  import initServices, { CustomServices, Services } from './services/index.js';
3
3
  import initModules, { Modules, ModuleOptions } from './modules.js';
4
+ import createBulkImporterFactory, {
5
+ BulkImporter,
6
+ BulkImportHandler,
7
+ } from './bulk-importer/createBulkImporter.js';
4
8
 
5
9
  import {
6
10
  WorkerDirector,
@@ -18,17 +22,17 @@ import {
18
22
  WarehousingDirector,
19
23
  } from './directors/index.js';
20
24
 
25
+ export * from './bulk-importer/createBulkImporter.js';
21
26
  export * from './services/index.js';
22
27
  export * from './directors/index.js';
23
-
24
- export interface BulkImporter {
25
- createBulkImporter: (options: any) => any;
26
- }
28
+ export * from './factory/index.js';
27
29
 
28
30
  export interface UnchainedCoreOptions {
29
31
  db: mongodb.Db;
30
32
  migrationRepository: MigrationRepository<UnchainedCore>;
31
- bulkImporter: any;
33
+ bulkImporter?: {
34
+ handlers?: Record<string, BulkImportHandler<UnchainedCore>>;
35
+ };
32
36
  modules?: Record<
33
37
  string,
34
38
  {
@@ -49,13 +53,14 @@ export interface UnchainedCore {
49
53
  export const initCore = async ({
50
54
  db,
51
55
  migrationRepository,
52
- bulkImporter,
56
+ bulkImporter: bulkImporterOptions = {},
53
57
  modules: customModules = {},
54
58
  services: customServices = {},
55
59
  options = {},
56
60
  }: UnchainedCoreOptions): Promise<UnchainedCore> => {
57
61
  // Configure custom modules
58
62
 
63
+ const bulkImporter = createBulkImporterFactory(db, bulkImporterOptions);
59
64
  const modules = await initModules({ db, migrationRepository, options }, customModules);
60
65
  const services = initServices(modules, customServices);
61
66
 
@@ -41,7 +41,7 @@ export interface FilterAdapterActions {
41
41
  sortStage: mongodb.FindOptions['sort'];
42
42
  locale: Intl.Locale;
43
43
  },
44
- ) => Promise<string[]>;
44
+ ) => Promise<string[] | null>;
45
45
 
46
46
  transformFilterSelector: (
47
47
  query: mongodb.Filter<Filter>,
@@ -80,7 +80,7 @@ export const FilterDirector: IFilterDirector = {
80
80
  initialValue: V,
81
81
  ) => {
82
82
  if (adapters.length === 0) {
83
- return null;
83
+ return initialValue;
84
84
  }
85
85
  return adapters.reduce(async (lastSearchPromise, adapter, index) => {
86
86
  return reducer(lastSearchPromise, adapter, index);
@@ -89,11 +89,10 @@ export const FilterDirector: IFilterDirector = {
89
89
 
90
90
  return {
91
91
  aggregateProductIds: (params) => {
92
- const reducedProductIds = adapters.reduce(
92
+ return adapters.reduce(
93
93
  (productIds, adapter) => adapter.aggregateProductIds({ productIds }),
94
94
  params.productIds,
95
95
  );
96
- return reducedProductIds;
97
96
  },
98
97
 
99
98
  searchAssortments: async (params, options) => {
@@ -113,19 +112,19 @@ export const FilterDirector: IFilterDirector = {
113
112
  transformProductSelector: async (defaultSelector, options) => {
114
113
  return reduceAdapters<mongodb.Filter<Product>>(async (lastSelector, adapter) => {
115
114
  return adapter.transformProductSelector(await lastSelector, options);
116
- }, defaultSelector || null);
115
+ }, defaultSelector);
117
116
  },
118
117
 
119
118
  transformSortStage: async (defaultStage, options) => {
120
119
  return reduceAdapters<mongodb.FindOptions<Product>['sort']>(async (lastSortStage, adapter) => {
121
120
  return adapter.transformSortStage(await lastSortStage, options);
122
- }, defaultStage || null);
121
+ }, defaultStage);
123
122
  },
124
123
 
125
124
  transformFilterSelector: async (defaultSelector) => {
126
125
  return reduceAdapters<mongodb.Filter<Filter>>(async (lastSelector, adapter) => {
127
126
  return adapter.transformFilterSelector(await lastSelector);
128
- }, defaultSelector || null);
127
+ }, defaultSelector);
129
128
  },
130
129
  };
131
130
  },
@@ -161,7 +160,7 @@ export const FilterDirector: IFilterDirector = {
161
160
  filter.type === FilterType.SWITCH
162
161
  ? {
163
162
  true: await this.findProductIds(filter, { value: true }, unchainedAPI),
164
- false: await this.findProductIds(filter, { value: false }, unchainedAPI),
163
+ false: await this.findProductIds(filter, { value: { $in: [null, false] } }, unchainedAPI),
165
164
  }
166
165
  : await (filter.options || []).reduce(async (accumulatorPromise, option) => {
167
166
  const accumulator = await accumulatorPromise;
@@ -101,7 +101,7 @@ export const PaymentDirector: IPaymentDirector = {
101
101
  try {
102
102
  return adapter.isActive(paymentContext.transactionContext);
103
103
  } catch (error) {
104
- logger.error(error.message);
104
+ logger.error(error);
105
105
  return false;
106
106
  }
107
107
  },
@@ -110,7 +110,7 @@ export const PaymentDirector: IPaymentDirector = {
110
110
  try {
111
111
  return adapter.isPayLaterAllowed(paymentContext.transactionContext);
112
112
  } catch (error) {
113
- logger.error(error.message);
113
+ logger.error(error);
114
114
  return false;
115
115
  }
116
116
  },
@@ -1,8 +1,8 @@
1
1
  import { BaseAdapter, IBaseAdapter } from '@unchainedshop/utils';
2
2
  import { WorkResult } from '@unchainedshop/core-worker';
3
- import { Modules } from '../modules.js';
3
+ import { ModuleOptions, Modules } from '../modules.js';
4
4
  import { Services } from '../services/index.js';
5
- import { BulkImporter } from '../core-index.js';
5
+ import { BulkImporter } from '../bulk-importer/createBulkImporter.js';
6
6
 
7
7
  export type IWorkerAdapter<Input, Output> = IBaseAdapter & {
8
8
  type: string;
@@ -11,7 +11,12 @@ export type IWorkerAdapter<Input, Output> = IBaseAdapter & {
11
11
 
12
12
  doWork: (
13
13
  input: Input,
14
- unchainedAPI: { modules: Modules; services: Services; bulkImporter: BulkImporter },
14
+ unchainedAPI: {
15
+ modules: Modules;
16
+ services: Services;
17
+ bulkImporter: BulkImporter;
18
+ options: ModuleOptions;
19
+ },
15
20
  workId: string,
16
21
  ) => Promise<WorkResult<Output>>;
17
22
  };
@@ -0,0 +1,3 @@
1
+ import registerProductDiscoverabilityFilter from './registerProductDiscoverabilityFilter.js';
2
+
3
+ export { registerProductDiscoverabilityFilter };
@@ -0,0 +1,36 @@
1
+ import { FilterAdapter, FilterDirector } from '../core-index.js';
2
+
3
+ export default function registerProductDiscoverabilityFilter({
4
+ orderIndex = 0,
5
+ hiddenTagValue = 'hidden',
6
+ }: {
7
+ orderIndex?: number;
8
+ hiddenTagValue?: string;
9
+ }) {
10
+ FilterDirector.registerAdapter({
11
+ ...FilterAdapter,
12
+
13
+ key: `shop.unchained.filters.product-discoverability-${crypto.randomUUID()}`,
14
+ label: 'Product Discoverability Filter',
15
+ version: '1.0.0',
16
+ orderIndex,
17
+
18
+ actions: (params) => {
19
+ return {
20
+ ...FilterAdapter.actions(params),
21
+
22
+ transformProductSelector: async (lastSelector, options) => {
23
+ const { key } = options || {};
24
+
25
+ if (!key) {
26
+ const newSelector = { ...lastSelector };
27
+ if (!newSelector.$and) newSelector.$and = [];
28
+ newSelector.$and.push({ tags: { $ne: hiddenTagValue } });
29
+ return newSelector;
30
+ }
31
+ return lastSelector;
32
+ },
33
+ };
34
+ },
35
+ });
36
+ }
package/src/modules.ts CHANGED
@@ -154,6 +154,7 @@ const initModules = async (
154
154
  const products = await configureProductsModule({
155
155
  db,
156
156
  migrationRepository,
157
+ options: options.products,
157
158
  });
158
159
  const quotations = await configureQuotationsModule({
159
160
  db,
@@ -1,6 +1,7 @@
1
1
  import { Enrollment, EnrollmentStatus } from '@unchainedshop/core-enrollments';
2
2
  import { Modules } from '../modules.js';
3
3
  import { processEnrollmentService } from './processEnrollment.js';
4
+ import { addMessageService } from './addMessage.js';
4
5
 
5
6
  export async function activateEnrollmentService(this: Modules, enrollment: Enrollment) {
6
7
  if (enrollment.status === EnrollmentStatus.TERMINATED) return enrollment;
@@ -15,15 +16,10 @@ export async function activateEnrollmentService(this: Modules, enrollment: Enrol
15
16
  const user = await this.users.findUserById(enrollment.userId);
16
17
  const locale = this.users.userLocale(user);
17
18
 
18
- await this.worker.addWork({
19
- type: 'MESSAGE',
20
- retries: 0,
21
- input: {
22
- reason: 'status_change',
23
- locale: locale.baseName,
24
- template: 'ENROLLMENT_STATUS',
25
- enrollmentId: updatedEnrollment._id,
26
- },
19
+ await addMessageService.bind(this)('ENROLLMENT_STATUS', {
20
+ reason: 'status_change',
21
+ locale: locale.baseName,
22
+ enrollmentId: updatedEnrollment._id,
27
23
  });
28
24
 
29
25
  return updatedEnrollment;