@unchainedshop/core 5.0.0-alpha.1 → 5.0.0-alpha.10

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 (131) hide show
  1. package/README.md +92 -546
  2. package/lib/bulk-exporter/createBulkExporter.js +1 -1
  3. package/lib/bulk-exporter/handlers/exportProductsHandler.js +2 -2
  4. package/lib/bulk-importer/handlers/assortment/create.js +1 -3
  5. package/lib/bulk-importer/handlers/assortment/update.js +1 -1
  6. package/lib/bulk-importer/handlers/product/create.d.ts +150 -35
  7. package/lib/bulk-importer/handlers/product/create.js +35 -16
  8. package/lib/bulk-importer/handlers/product/update.d.ts +78 -36
  9. package/lib/bulk-importer/handlers/product/update.js +8 -48
  10. package/lib/core-index.d.ts +1 -2
  11. package/lib/core-index.js +2 -18
  12. package/lib/directors/BaseDiscountAdapter.d.ts +3 -0
  13. package/lib/directors/BaseDiscountDirector.d.ts +2 -2
  14. package/lib/directors/BaseDiscountDirector.js +7 -9
  15. package/lib/directors/BasePricingDirector.d.ts +2 -2
  16. package/lib/directors/BasePricingDirector.js +3 -6
  17. package/lib/directors/BaseWorker.js +3 -2
  18. package/lib/directors/DeliveryDirector.d.ts +1 -1
  19. package/lib/directors/DeliveryDirector.js +2 -12
  20. package/lib/directors/DeliveryPricingDirector.js +1 -10
  21. package/lib/directors/EnrollmentAdapter.js +0 -1
  22. package/lib/directors/EnrollmentDirector.d.ts +1 -1
  23. package/lib/directors/EnrollmentDirector.js +3 -15
  24. package/lib/directors/FileDirector.d.ts +4 -4
  25. package/lib/directors/FileDirector.js +2 -13
  26. package/lib/directors/FilterDirector.d.ts +1 -1
  27. package/lib/directors/FilterDirector.js +25 -32
  28. package/lib/directors/OrderDiscountDirector.d.ts +1 -15
  29. package/lib/directors/OrderDiscountDirector.js +1 -13
  30. package/lib/directors/OrderPricingDirector.js +1 -10
  31. package/lib/directors/OrderPricingSheet.d.ts +1 -0
  32. package/lib/directors/OrderPricingSheet.js +17 -17
  33. package/lib/directors/PaymentDirector.d.ts +1 -1
  34. package/lib/directors/PaymentDirector.js +2 -12
  35. package/lib/directors/PaymentPricingDirector.js +1 -10
  36. package/lib/directors/ProductDiscountDirector.d.ts +1 -15
  37. package/lib/directors/ProductDiscountDirector.js +1 -13
  38. package/lib/directors/ProductPricingDirector.js +1 -10
  39. package/lib/directors/QuotationDirector.d.ts +1 -1
  40. package/lib/directors/QuotationDirector.js +2 -14
  41. package/lib/directors/WarehousingDirector.js +16 -34
  42. package/lib/directors/WorkerDirector.d.ts +7 -1
  43. package/lib/directors/WorkerDirector.js +29 -29
  44. package/lib/directors/registryDirector.d.ts +2 -0
  45. package/lib/directors/registryDirector.js +6 -0
  46. package/lib/errors.d.ts +1 -0
  47. package/lib/errors.js +5 -0
  48. package/lib/factory/index.d.ts +12 -1
  49. package/lib/factory/index.js +12 -1
  50. package/lib/factory/registerAssortmentSearchFilter.d.ts +2 -1
  51. package/lib/factory/registerAssortmentSearchFilter.js +6 -3
  52. package/lib/factory/registerDeliveryPricing.d.ts +7 -0
  53. package/lib/factory/registerDeliveryPricing.js +30 -0
  54. package/lib/factory/registerDeliveryProvider.d.ts +12 -0
  55. package/lib/factory/registerDeliveryProvider.js +46 -0
  56. package/lib/factory/registerEnrollment.d.ts +18 -0
  57. package/lib/factory/registerEnrollment.js +43 -0
  58. package/lib/factory/registerFileAdapter.d.ts +17 -0
  59. package/lib/factory/registerFileAdapter.js +24 -0
  60. package/lib/factory/registerOrderDiscount.d.ts +13 -0
  61. package/lib/factory/registerOrderDiscount.js +39 -0
  62. package/lib/factory/registerOrderPricing.d.ts +7 -0
  63. package/lib/factory/registerOrderPricing.js +30 -0
  64. package/lib/factory/registerPaymentPricing.d.ts +7 -0
  65. package/lib/factory/registerPaymentPricing.js +30 -0
  66. package/lib/factory/registerPaymentProvider.d.ts +15 -0
  67. package/lib/factory/registerPaymentProvider.js +53 -0
  68. package/lib/factory/registerProductDiscount.d.ts +20 -0
  69. package/lib/factory/registerProductDiscount.js +47 -0
  70. package/lib/factory/registerProductDiscoverabilityFilter.d.ts +2 -1
  71. package/lib/factory/registerProductDiscoverabilityFilter.js +6 -3
  72. package/lib/factory/registerProductPricing.d.ts +7 -0
  73. package/lib/factory/registerProductPricing.js +30 -0
  74. package/lib/factory/registerProductSearchFilter.d.ts +2 -1
  75. package/lib/factory/registerProductSearchFilter.js +4 -3
  76. package/lib/factory/registerQuotation.d.ts +12 -0
  77. package/lib/factory/registerQuotation.js +52 -0
  78. package/lib/factory/registerVirtualWarehousing.js +1 -1
  79. package/lib/factory/registerWorker.js +1 -1
  80. package/lib/plugins/PluginRegistry.d.ts +1 -0
  81. package/lib/plugins/PluginRegistry.js +11 -2
  82. package/lib/services/addMultipleCartProducts.js +3 -2
  83. package/lib/services/bulkAssignProductsToAssortment.d.ts +8 -0
  84. package/lib/services/bulkAssignProductsToAssortment.js +11 -0
  85. package/lib/services/bulkDeleteUsers.d.ts +7 -0
  86. package/lib/services/bulkDeleteUsers.js +11 -0
  87. package/lib/services/bulkRemoveFilters.d.ts +7 -0
  88. package/lib/services/bulkRemoveFilters.js +10 -0
  89. package/lib/services/bulkRemoveProducts.d.ts +7 -0
  90. package/lib/services/bulkRemoveProducts.js +23 -0
  91. package/lib/services/bulkSetFilterActive.d.ts +8 -0
  92. package/lib/services/bulkSetFilterActive.js +12 -0
  93. package/lib/services/checkoutOrder.js +4 -0
  94. package/lib/services/createFilter.d.ts +3 -0
  95. package/lib/services/createFilter.js +6 -0
  96. package/lib/services/createFilterOption.d.ts +5 -0
  97. package/lib/services/createFilterOption.js +8 -0
  98. package/lib/services/createSignedURL.js +2 -1
  99. package/lib/services/deleteCart.d.ts +2 -0
  100. package/lib/services/deleteCart.js +7 -0
  101. package/lib/services/deleteDeadCarts.d.ts +2 -0
  102. package/lib/services/deleteDeadCarts.js +17 -0
  103. package/lib/services/deleteUser.js +2 -5
  104. package/lib/services/index.d.ts +24 -1
  105. package/lib/services/index.js +24 -1
  106. package/lib/services/initCartProviders.js +1 -0
  107. package/lib/services/isTokenInvalidateable.d.ts +3 -1
  108. package/lib/services/isTokenInvalidateable.js +2 -2
  109. package/lib/services/loadFilterOptions.js +3 -3
  110. package/lib/services/processEnrollment.js +2 -1
  111. package/lib/services/processOrder.js +3 -2
  112. package/lib/services/processQuotation.js +11 -13
  113. package/lib/services/proposeQuotation.js +3 -0
  114. package/lib/services/removeFilterOption.d.ts +6 -0
  115. package/lib/services/removeFilterOption.js +8 -0
  116. package/lib/services/removeProduct.js +2 -1
  117. package/lib/services/reserveOrderDiscountsForCheckout.d.ts +5 -0
  118. package/lib/services/reserveOrderDiscountsForCheckout.js +34 -0
  119. package/lib/services/simulateProductDispatching.d.ts +3 -1
  120. package/lib/services/simulateProductDispatching.js +3 -3
  121. package/lib/services/simulateProductInventory.d.ts +3 -1
  122. package/lib/services/simulateProductInventory.js +3 -3
  123. package/lib/services/supportedDeliveryProviders.js +9 -0
  124. package/lib/services/supportedPaymentProviders.js +9 -0
  125. package/lib/services/supportedWarehousingProviders.js +9 -0
  126. package/lib/services/updateCalculation.js +2 -1
  127. package/lib/services/updateFilter.d.ts +3 -0
  128. package/lib/services/updateFilter.js +8 -0
  129. package/lib/services/uploadFileFromStream.js +2 -1
  130. package/lib/services/validateOrder.js +7 -8
  131. package/package.json +29 -23
@@ -2,6 +2,7 @@ import { OrderStatus } from '@unchainedshop/core-orders';
2
2
  import { nextUserCartService } from "./nextUserCart.js";
3
3
  import { validateOrderService } from "./validateOrder.js";
4
4
  import { processOrderService } from "./processOrder.js";
5
+ import { reserveOrderDiscountsForCheckout } from "./reserveOrderDiscountsForCheckout.js";
5
6
  export async function checkoutOrderService(orderId, transactionContext) {
6
7
  const order = await this.orders.findOrder({ orderId });
7
8
  if (!order)
@@ -10,7 +11,9 @@ export async function checkoutOrderService(orderId, transactionContext) {
10
11
  return order;
11
12
  await validateOrderService.bind(this)(order);
12
13
  const lock = await this.orders.acquireLock(order._id, 'checkout');
14
+ let discounts;
13
15
  try {
16
+ discounts = await reserveOrderDiscountsForCheckout.call(this, order);
14
17
  const processedOrder = await processOrderService.bind(this)(order, transactionContext);
15
18
  if (processedOrder.billingAddress) {
16
19
  await this.users.updateLastBillingAddress(processedOrder.userId, processedOrder.billingAddress);
@@ -27,6 +30,7 @@ export async function checkoutOrderService(orderId, transactionContext) {
27
30
  return processedOrder;
28
31
  }
29
32
  finally {
33
+ await discounts?.release();
30
34
  await lock.release();
31
35
  }
32
36
  }
@@ -0,0 +1,3 @@
1
+ import type { Filter } from '@unchainedshop/core-filters';
2
+ import type { Modules } from '../modules.ts';
3
+ export declare function createFilterService(this: Modules, filter: Parameters<Modules['filters']['create']>[0]): Promise<Filter>;
@@ -0,0 +1,6 @@
1
+ import { FilterDirector } from "../core-index.js";
2
+ export async function createFilterService(filter) {
3
+ const newFilter = await this.filters.create(filter);
4
+ await FilterDirector.invalidateProductIdCache(newFilter, { modules: this });
5
+ return newFilter;
6
+ }
@@ -0,0 +1,5 @@
1
+ import type { Filter } from '@unchainedshop/core-filters';
2
+ import type { Modules } from '../modules.ts';
3
+ export declare function createFilterOptionService(this: Modules, filterId: string, { value }: {
4
+ value: string;
5
+ }): Promise<Filter | null>;
@@ -0,0 +1,8 @@
1
+ import { FilterDirector } from "../core-index.js";
2
+ export async function createFilterOptionService(filterId, { value }) {
3
+ const filter = await this.filters.createFilterOption(filterId, { value });
4
+ if (filter) {
5
+ await FilterDirector.invalidateProductIdCache(filter, { modules: this });
6
+ }
7
+ return filter;
8
+ }
@@ -1,12 +1,13 @@
1
1
  import { getFileFromFileData } from '@unchainedshop/core-files';
2
2
  import { getFileAdapter } from "../utils/getFileAdapter.js";
3
+ import { createServiceError } from "../errors.js";
3
4
  export async function createSignedURLService({ directoryName, fileName, meta }) {
4
5
  const fileUploadAdapter = getFileAdapter();
5
6
  const preparedFileData = await fileUploadAdapter.createSignedURL(directoryName, fileName, {
6
7
  modules: this,
7
8
  });
8
9
  if (!preparedFileData)
9
- throw new Error('Could not prepare signed URL');
10
+ throw createServiceError('SignedURLPreparationError', 'Could not prepare signed URL');
10
11
  const fileData = getFileFromFileData(preparedFileData, meta);
11
12
  const fileId = await this.files.create(fileData);
12
13
  const file = await this.files.findFile({ fileId });
@@ -0,0 +1,2 @@
1
+ import type { Modules } from '../modules.ts';
2
+ export declare function deleteCartService(this: Modules, orderId: string): Promise<number>;
@@ -0,0 +1,7 @@
1
+ export async function deleteCartService(orderId) {
2
+ await this.orders.positions.deleteOrderPositions(orderId);
3
+ await this.orders.payments.deleteOrderPayments(orderId);
4
+ await this.orders.deliveries.deleteOrderDeliveries(orderId);
5
+ await this.orders.discounts.deleteOrderDiscounts(orderId);
6
+ return this.orders.delete(orderId);
7
+ }
@@ -0,0 +1,2 @@
1
+ import type { Modules } from '../modules.ts';
2
+ export declare function deleteDeadCartsService(this: Modules): Promise<number>;
@@ -0,0 +1,17 @@
1
+ import { deleteCartService } from "./deleteCart.js";
2
+ export async function deleteDeadCartsService() {
3
+ const cartUserIds = (await this.orders.findCartUserIds()).filter(Boolean);
4
+ if (!cartUserIds.length)
5
+ return 0;
6
+ const existingUserIds = new Set(await this.users.findExistingUserIds({ userIds: cartUserIds }));
7
+ const deadUserIds = cartUserIds.filter((userId) => !existingUserIds.has(userId));
8
+ if (!deadUserIds.length)
9
+ return 0;
10
+ const deadCarts = await this.orders.findCarts({ userIds: deadUserIds }, { projection: { _id: 1 } });
11
+ let deletedCount = 0;
12
+ await Array.fromAsync(deadCarts, async (cart) => {
13
+ await deleteCartService.bind(this)(cart._id);
14
+ deletedCount += 1;
15
+ });
16
+ return deletedCount;
17
+ }
@@ -1,3 +1,4 @@
1
+ import { deleteCartService } from "./deleteCart.js";
1
2
  export async function deleteUserService({ userId }) {
2
3
  const user = await this.users.markDeleted(userId);
3
4
  if (!user)
@@ -11,11 +12,7 @@ export async function deleteUserService({ userId }) {
11
12
  }
12
13
  const carts = (await this.orders.findOrders({ userId, includeCarts: true })).filter((c) => c.status === null);
13
14
  await Array.fromAsync(carts, async (userCart) => {
14
- await this.orders.positions.deleteOrderPositions(userCart?._id);
15
- await this.orders.payments.deleteOrderPayments(userCart?._id);
16
- await this.orders.deliveries.deleteOrderDeliveries(userCart?._id);
17
- await this.orders.discounts.deleteOrderDiscounts(userCart?._id);
18
- await this.orders.delete(userCart?._id);
15
+ await deleteCartService.bind(this)(userCart._id);
19
16
  });
20
17
  const ordersCount = await this.orders.count({ userId, includeCarts: true });
21
18
  const quotationsCount = await this.quotations.count({ userId });
@@ -15,6 +15,7 @@ import { initCartProvidersService } from './initCartProviders.ts';
15
15
  import { updateCalculationService } from './updateCalculation.ts';
16
16
  import { supportedDeliveryProvidersService } from './supportedDeliveryProviders.ts';
17
17
  import { deleteUserService } from './deleteUser.ts';
18
+ import { deleteCartService } from './deleteCart.ts';
18
19
  import { supportedPaymentProvidersService } from './supportedPaymentProviders.ts';
19
20
  import { supportedWarehousingProvidersService } from './supportedWarehousingProviders.ts';
20
21
  import { createEnrollmentFromCheckoutService } from './createEnrollmentFromCheckout.ts';
@@ -23,6 +24,7 @@ import { searchProductsService } from './searchProducts.ts';
23
24
  import { calculateDiscountTotalService } from './calculateDiscountTotal.ts';
24
25
  import { registerPaymentCredentialsService } from './registerPaymentCredentials.ts';
25
26
  import { processOrderService } from './processOrder.ts';
27
+ import { processEnrollmentService } from './processEnrollment.ts';
26
28
  import { checkoutOrderService } from './checkoutOrder.ts';
27
29
  import { confirmOrderService } from './confirmOrder.ts';
28
30
  import { rejectOrderService } from './rejectOrder.ts';
@@ -40,6 +42,10 @@ import { verifyQuotationService } from './verifyQuotation.ts';
40
42
  import { loadFiltersService } from './loadFilters.ts';
41
43
  import { loadFilterOptionsService } from './loadFilterOptions.ts';
42
44
  import { removeFilterService } from './removeFilter.ts';
45
+ import { createFilterService } from './createFilter.ts';
46
+ import { updateFilterService } from './updateFilter.ts';
47
+ import { createFilterOptionService } from './createFilterOption.ts';
48
+ import { removeFilterOptionService } from './removeFilterOption.ts';
43
49
  import { removeCartDiscountService } from './removeCartDiscount.ts';
44
50
  import { addMultipleCartProductsService } from './addMultipleCartProducts.ts';
45
51
  import { ercMetadataService } from './ercMetadata.ts';
@@ -57,6 +63,11 @@ import { simulateConfigurablePriceRangeService } from './simulateConfigurablePri
57
63
  import { createFileDownloadURLService } from './createFileDownloadURL.ts';
58
64
  import { resolveTokenStatusService } from './resolveTokenStatus.ts';
59
65
  import { isTokenInvalidateableService } from './isTokenInvalidateable.ts';
66
+ import { bulkRemoveProductsService } from './bulkRemoveProducts.ts';
67
+ import { bulkRemoveFiltersService } from './bulkRemoveFilters.ts';
68
+ import { bulkDeleteUsersService } from './bulkDeleteUsers.ts';
69
+ import { bulkSetFilterActiveService } from './bulkSetFilterActive.ts';
70
+ import { bulkAssignProductsToAssortmentService } from './bulkAssignProductsToAssortment.ts';
60
71
  export type ServiceInterface = (this: Modules, ...args: any[]) => Promise<any> | any;
61
72
  export type Bound<T extends ServiceInterface> = OmitThisParameter<T>;
62
73
  export type CustomServices = Record<string, ServiceInterface | Record<string, ServiceInterface>>;
@@ -77,6 +88,7 @@ export default function initServices(modules: Modules, customServices?: CustomSe
77
88
  registerPaymentCredentials: Bound<typeof registerPaymentCredentialsService>;
78
89
  calculateDiscountTotal: Bound<typeof calculateDiscountTotalService>;
79
90
  migrateOrderCarts: Bound<typeof migrateOrderCartsService>;
91
+ deleteCart: Bound<typeof deleteCartService>;
80
92
  nextUserCart: Bound<typeof nextUserCartService>;
81
93
  findOrInitCart: Bound<typeof findOrInitCartService>;
82
94
  initCartProviders: Bound<typeof initCartProvidersService>;
@@ -99,18 +111,23 @@ export default function initServices(modules: Modules, customServices?: CustomSe
99
111
  simulateProductDispatching: Bound<typeof simulateProductDispatchingService>;
100
112
  simulateProductInventory: Bound<typeof simulateProductInventoryService>;
101
113
  removeProduct: Bound<typeof removeProductService>;
114
+ bulkRemoveProducts: Bound<typeof bulkRemoveProductsService>;
102
115
  findProductSiblings: Bound<typeof findProductSiblingsService>;
103
116
  simulateConfigurablePriceRange: Bound<typeof simulateConfigurablePriceRangeService>;
104
117
  };
118
+ assortments: {
119
+ bulkAssignProductsToAssortment: Bound<typeof bulkAssignProductsToAssortmentService>;
120
+ };
105
121
  users: {
106
122
  migrateUserData: Bound<typeof migrateUserDataService>;
107
123
  updateUserAvatarAfterUpload: Bound<typeof updateUserAvatarAfterUploadService>;
108
124
  deleteUser: Bound<typeof deleteUserService>;
125
+ bulkDeleteUsers: Bound<typeof bulkDeleteUsersService>;
109
126
  };
110
127
  enrollments: {
111
128
  createEnrollmentFromCheckout: Bound<typeof createEnrollmentFromCheckoutService>;
112
129
  generateOrderFromEnrollment: Bound<typeof generateOrderFromEnrollmentService>;
113
- processEnrollment: Bound<typeof processOrderService>;
130
+ processEnrollment: Bound<typeof processEnrollmentService>;
114
131
  initializeEnrollment: Bound<typeof initializeEnrollmentService>;
115
132
  activateEnrollment: Bound<typeof activateEnrollmentService>;
116
133
  terminateEnrollment: Bound<typeof terminateEnrollmentService>;
@@ -129,6 +146,12 @@ export default function initServices(modules: Modules, customServices?: CustomSe
129
146
  loadFilters: Bound<typeof loadFiltersService>;
130
147
  loadFilterOptions: Bound<typeof loadFilterOptionsService>;
131
148
  removeFilter: Bound<typeof removeFilterService>;
149
+ createFilter: Bound<typeof createFilterService>;
150
+ updateFilter: Bound<typeof updateFilterService>;
151
+ createFilterOption: Bound<typeof createFilterOptionService>;
152
+ removeFilterOption: Bound<typeof removeFilterOptionService>;
153
+ bulkRemoveFilters: Bound<typeof bulkRemoveFiltersService>;
154
+ bulkSetFilterActive: Bound<typeof bulkSetFilterActiveService>;
132
155
  };
133
156
  warehousing: {
134
157
  ercMetadata: Bound<typeof ercMetadataService>;
@@ -14,6 +14,7 @@ import { initCartProvidersService } from "./initCartProviders.js";
14
14
  import { updateCalculationService } from "./updateCalculation.js";
15
15
  import { supportedDeliveryProvidersService } from "./supportedDeliveryProviders.js";
16
16
  import { deleteUserService } from "./deleteUser.js";
17
+ import { deleteCartService } from "./deleteCart.js";
17
18
  import { supportedPaymentProvidersService } from "./supportedPaymentProviders.js";
18
19
  import { supportedWarehousingProvidersService } from "./supportedWarehousingProviders.js";
19
20
  import { createEnrollmentFromCheckoutService } from "./createEnrollmentFromCheckout.js";
@@ -22,6 +23,7 @@ import { searchProductsService } from "./searchProducts.js";
22
23
  import { calculateDiscountTotalService } from "./calculateDiscountTotal.js";
23
24
  import { registerPaymentCredentialsService } from "./registerPaymentCredentials.js";
24
25
  import { processOrderService } from "./processOrder.js";
26
+ import { processEnrollmentService } from "./processEnrollment.js";
25
27
  import { checkoutOrderService } from "./checkoutOrder.js";
26
28
  import { confirmOrderService } from "./confirmOrder.js";
27
29
  import { rejectOrderService } from "./rejectOrder.js";
@@ -39,6 +41,10 @@ import { verifyQuotationService } from "./verifyQuotation.js";
39
41
  import { loadFiltersService } from "./loadFilters.js";
40
42
  import { loadFilterOptionsService } from "./loadFilterOptions.js";
41
43
  import { removeFilterService } from "./removeFilter.js";
44
+ import { createFilterService } from "./createFilter.js";
45
+ import { updateFilterService } from "./updateFilter.js";
46
+ import { createFilterOptionService } from "./createFilterOption.js";
47
+ import { removeFilterOptionService } from "./removeFilterOption.js";
42
48
  import { removeCartDiscountService } from "./removeCartDiscount.js";
43
49
  import { addMultipleCartProductsService } from "./addMultipleCartProducts.js";
44
50
  import { ercMetadataService } from "./ercMetadata.js";
@@ -56,6 +62,11 @@ import { simulateConfigurablePriceRangeService } from "./simulateConfigurablePri
56
62
  import { createFileDownloadURLService } from "./createFileDownloadURL.js";
57
63
  import { resolveTokenStatusService } from "./resolveTokenStatus.js";
58
64
  import { isTokenInvalidateableService } from "./isTokenInvalidateable.js";
65
+ import { bulkRemoveProductsService } from "./bulkRemoveProducts.js";
66
+ import { bulkRemoveFiltersService } from "./bulkRemoveFilters.js";
67
+ import { bulkDeleteUsersService } from "./bulkDeleteUsers.js";
68
+ import { bulkSetFilterActiveService } from "./bulkSetFilterActive.js";
69
+ import { bulkAssignProductsToAssortmentService } from "./bulkAssignProductsToAssortment.js";
59
70
  function bindMethodsToModules(modules) {
60
71
  return {
61
72
  get(target, prop, receiver) {
@@ -88,6 +99,7 @@ export default function initServices(modules, customServices = {}) {
88
99
  registerPaymentCredentials: registerPaymentCredentialsService,
89
100
  calculateDiscountTotal: calculateDiscountTotalService,
90
101
  migrateOrderCarts: migrateOrderCartsService,
102
+ deleteCart: deleteCartService,
91
103
  nextUserCart: nextUserCartService,
92
104
  findOrInitCart: findOrInitCartService,
93
105
  initCartProviders: initCartProvidersService,
@@ -110,18 +122,23 @@ export default function initServices(modules, customServices = {}) {
110
122
  simulateProductDispatching: simulateProductDispatchingService,
111
123
  simulateProductInventory: simulateProductInventoryService,
112
124
  removeProduct: removeProductService,
125
+ bulkRemoveProducts: bulkRemoveProductsService,
113
126
  findProductSiblings: findProductSiblingsService,
114
127
  simulateConfigurablePriceRange: simulateConfigurablePriceRangeService,
115
128
  },
129
+ assortments: {
130
+ bulkAssignProductsToAssortment: bulkAssignProductsToAssortmentService,
131
+ },
116
132
  users: {
117
133
  migrateUserData: migrateUserDataService,
118
134
  updateUserAvatarAfterUpload: updateUserAvatarAfterUploadService,
119
135
  deleteUser: deleteUserService,
136
+ bulkDeleteUsers: bulkDeleteUsersService,
120
137
  },
121
138
  enrollments: {
122
139
  createEnrollmentFromCheckout: createEnrollmentFromCheckoutService,
123
140
  generateOrderFromEnrollment: generateOrderFromEnrollmentService,
124
- processEnrollment: processOrderService,
141
+ processEnrollment: processEnrollmentService,
125
142
  initializeEnrollment: initializeEnrollmentService,
126
143
  activateEnrollment: activateEnrollmentService,
127
144
  terminateEnrollment: terminateEnrollmentService,
@@ -140,6 +157,12 @@ export default function initServices(modules, customServices = {}) {
140
157
  loadFilters: loadFiltersService,
141
158
  loadFilterOptions: loadFilterOptionsService,
142
159
  removeFilter: removeFilterService,
160
+ createFilter: createFilterService,
161
+ updateFilter: updateFilterService,
162
+ createFilterOption: createFilterOptionService,
163
+ removeFilterOption: removeFilterOptionService,
164
+ bulkRemoveFilters: bulkRemoveFiltersService,
165
+ bulkSetFilterActive: bulkSetFilterActiveService,
143
166
  },
144
167
  warehousing: {
145
168
  ercMetadata: ercMetadataService,
@@ -39,6 +39,7 @@ export async function initCartProvidersService(order) {
39
39
  const paymentCredentials = await this.payment.paymentCredentials.findPaymentCredentials({ userId: updatedOrder.userId, isPreferred: true }, {
40
40
  sort: {
41
41
  created: -1,
42
+ _id: -1,
42
43
  },
43
44
  });
44
45
  const defaultOrderPaymentProvider = await paymentSettings.determineDefaultProvider({
@@ -1,5 +1,7 @@
1
1
  import type { TokenSurrogate } from '@unchainedshop/core-warehousing';
2
+ import type { Product } from '@unchainedshop/core-products';
2
3
  import type { Modules } from '../modules.ts';
3
- export declare function isTokenInvalidateableService(this: Modules, { token, }: {
4
+ export declare function isTokenInvalidateableService(this: Modules, { token, product: providedProduct, }: {
4
5
  token: TokenSurrogate;
6
+ product?: Product;
5
7
  }): Promise<boolean>;
@@ -1,7 +1,7 @@
1
1
  import { WarehousingProviderType } from '@unchainedshop/core-warehousing';
2
2
  import { WarehousingDirector } from "../directors/WarehousingDirector.js";
3
- export async function isTokenInvalidateableService({ token, }) {
4
- const product = await this.products.findProduct({ productId: token.productId });
3
+ export async function isTokenInvalidateableService({ token, product: providedProduct, }) {
4
+ const product = providedProduct || (await this.products.findProduct({ productId: token.productId }));
5
5
  if (!product)
6
6
  return false;
7
7
  const virtualProviders = (await this.warehousing.allProviders()).filter(({ type }) => type === WarehousingProviderType.VIRTUAL);
@@ -1,10 +1,10 @@
1
- import { FilterType } from '@unchainedshop/core-filters';
1
+ import { filterOptionValues } from '@unchainedshop/core-filters';
2
2
  import { FilterDirector, parseQueryArray } from "../directors/FilterDirector.js";
3
3
  export async function loadFilterOptionsService(filter, params) {
4
4
  const { forceLiveCollection, productIdSet, searchQuery } = params;
5
5
  const filterQueryParsed = parseQueryArray(searchQuery?.filterQuery);
6
6
  const values = filterQueryParsed[filter.key];
7
- const allOptions = (filter.type === FilterType.SWITCH && ['true', 'false']) || filter.options || [];
7
+ const allOptions = filterOptionValues(filter);
8
8
  const mappedOptions = await Promise.all(allOptions.map(async (value) => {
9
9
  const filterOptionProductIds = await FilterDirector.filterProductIds(filter, {
10
10
  values: [value],
@@ -12,7 +12,7 @@ export async function loadFilterOptionsService(filter, params) {
12
12
  }, { modules: this });
13
13
  const filteredProductIdSet = productIdSet.intersection(filterOptionProductIds);
14
14
  const normalizedValues = values && this.filters.parse(filter, values, [value]);
15
- const isSelected = normalizedValues && normalizedValues.indexOf(value) !== -1;
15
+ const isSelected = Boolean(normalizedValues && normalizedValues.indexOf(value) !== -1);
16
16
  if (!filteredProductIdSet.size && !isSelected) {
17
17
  return null;
18
18
  }
@@ -1,12 +1,13 @@
1
1
  import { EnrollmentStatus } from '@unchainedshop/core-enrollments';
2
2
  import { EnrollmentDirector } from "../core-index.js";
3
+ import { createServiceError } from "../errors.js";
3
4
  const findNextStatus = async (enrollment, modules) => {
4
5
  let status = enrollment.status;
5
6
  const product = await modules.products.findProduct({
6
7
  productId: enrollment.productId,
7
8
  });
8
9
  if (!product)
9
- throw new Error('Product not found for enrollment');
10
+ throw createServiceError('ProductNotFoundError', 'Product not found for enrollment');
10
11
  const director = await EnrollmentDirector.actions({ enrollment, product }, { modules });
11
12
  if (status === EnrollmentStatus.INITIAL || status === EnrollmentStatus.PAUSED) {
12
13
  if (await director.isValidForActivation()) {
@@ -5,6 +5,7 @@ import { WarehousingProviderType } from '@unchainedshop/core-warehousing';
5
5
  import { WarehousingDirector, DeliveryDirector, PaymentDirector } from "../directors/index.js";
6
6
  import { fulfillQuotationService } from "./fulfillQuotation.js";
7
7
  import { createLogger } from '@unchainedshop/logger';
8
+ import { createServiceError } from "../errors.js";
8
9
  const logger = createLogger('unchained:core:processOrder');
9
10
  const isAutoConfirmationEnabled = async ({ orderPayment, orderDelivery, }, modules) => {
10
11
  if (orderPayment.status !== OrderPaymentStatus.PAID) {
@@ -12,7 +13,7 @@ const isAutoConfirmationEnabled = async ({ orderPayment, orderDelivery, }, modul
12
13
  paymentProviderId: orderPayment.paymentProviderId,
13
14
  });
14
15
  if (!paymentProvider)
15
- throw new Error(`Payment provider not found: ${orderPayment.paymentProviderId}`);
16
+ throw createServiceError('PaymentProviderNotFoundError', `Payment provider not found: ${orderPayment.paymentProviderId}`);
16
17
  const actions = await PaymentDirector.actions(paymentProvider, {}, { modules });
17
18
  if (!actions.isPayLaterAllowed())
18
19
  return false;
@@ -22,7 +23,7 @@ const isAutoConfirmationEnabled = async ({ orderPayment, orderDelivery, }, modul
22
23
  deliveryProviderId: orderDelivery.deliveryProviderId,
23
24
  });
24
25
  if (!deliveryProvider)
25
- throw new Error(`Delivery provider not found: ${orderDelivery.deliveryProviderId}`);
26
+ throw createServiceError('DeliveryProviderNotFoundError', `Delivery provider not found: ${orderDelivery.deliveryProviderId}`);
26
27
  const director = await DeliveryDirector.actions(deliveryProvider, {}, { modules });
27
28
  if (!director.isAutoReleaseAllowed())
28
29
  return false;
@@ -1,9 +1,8 @@
1
1
  import { QuotationStatus } from '@unchainedshop/core-quotations';
2
2
  import { QuotationDirector } from "../core-index.js";
3
3
  import { addMessageService } from "./addMessage.js";
4
- const findNextStatus = async (quotation, modules) => {
4
+ const findNextStatus = async (director, quotation) => {
5
5
  let status = quotation.status;
6
- const director = await QuotationDirector.actions({ quotation }, { modules });
7
6
  if (status === QuotationStatus.REQUESTED) {
8
7
  if (!(await director.isManualRequestVerificationRequired())) {
9
8
  status = QuotationStatus.PROCESSING;
@@ -19,27 +18,26 @@ const findNextStatus = async (quotation, modules) => {
19
18
  export async function processQuotationService(initialQuotation, params) {
20
19
  const quotationId = initialQuotation._id;
21
20
  let quotation = initialQuotation;
22
- let nextStatus = await findNextStatus(quotation, this);
23
21
  const director = await QuotationDirector.actions({ quotation }, { modules: this });
22
+ const runHook = async (hook) => {
23
+ await hook(params.quotationContext);
24
+ quotation = (await this.quotations.findQuotation({ quotationId }));
25
+ return findNextStatus(director, quotation);
26
+ };
27
+ let nextStatus = await findNextStatus(director, quotation);
24
28
  if (quotation.status === QuotationStatus.REQUESTED && nextStatus !== QuotationStatus.REQUESTED) {
25
- await director.submitRequest(params.quotationContext);
29
+ nextStatus = await runHook(director.submitRequest);
26
30
  }
27
- quotation = (await this.quotations.findQuotation({ quotationId }));
28
- nextStatus = await findNextStatus(quotation, this);
29
31
  if (nextStatus !== QuotationStatus.PROCESSING) {
30
- await director.verifyRequest(params.quotationContext);
32
+ nextStatus = await runHook(director.verifyRequest);
31
33
  }
32
- quotation = (await this.quotations.findQuotation({ quotationId }));
33
- nextStatus = await findNextStatus(quotation, this);
34
34
  if (nextStatus === QuotationStatus.REJECTED) {
35
- await director.rejectRequest(params.quotationContext);
35
+ nextStatus = await runHook(director.rejectRequest);
36
36
  }
37
- quotation = (await this.quotations.findQuotation({ quotationId }));
38
- nextStatus = await findNextStatus(quotation, this);
39
37
  if (nextStatus === QuotationStatus.PROPOSED) {
40
38
  const proposal = await director.quote();
41
39
  quotation = (await this.quotations.updateProposal(quotation._id, proposal));
42
- nextStatus = await findNextStatus(quotation, this);
40
+ nextStatus = await findNextStatus(director, quotation);
43
41
  }
44
42
  const updatedQuotation = (await this.quotations.updateStatus(quotation._id, {
45
43
  status: nextStatus,
@@ -3,6 +3,9 @@ import { processQuotationService } from "./processQuotation.js";
3
3
  export async function proposeQuotationService(quotation, { quotationContext }) {
4
4
  if (quotation.status !== QuotationStatus.PROCESSING)
5
5
  return quotation;
6
+ if (quotationContext) {
7
+ await this.quotations.updateContext(quotation._id, { context: quotationContext });
8
+ }
6
9
  const updatedQuotation = (await this.quotations.updateStatus(quotation._id, {
7
10
  status: QuotationStatus.PROPOSED,
8
11
  info: 'proposed manually',
@@ -0,0 +1,6 @@
1
+ import type { Filter } from '@unchainedshop/core-filters';
2
+ import type { Modules } from '../modules.ts';
3
+ export declare function removeFilterOptionService(this: Modules, { filterId, filterOptionValue }: {
4
+ filterId: string;
5
+ filterOptionValue: string;
6
+ }): Promise<Filter | null>;
@@ -0,0 +1,8 @@
1
+ import { FilterDirector } from "../core-index.js";
2
+ export async function removeFilterOptionService({ filterId, filterOptionValue }) {
3
+ const filter = await this.filters.removeFilterOption({ filterId, filterOptionValue });
4
+ if (filter) {
5
+ await FilterDirector.invalidateProductIdCache(filter, { modules: this });
6
+ }
7
+ return filter;
8
+ }
@@ -1,5 +1,6 @@
1
1
  import { ProductStatus } from '@unchainedshop/core-products';
2
2
  import { updateCalculationService } from "./updateCalculation.js";
3
+ import { createServiceError } from "../errors.js";
3
4
  export async function removeProductService({ productId }) {
4
5
  const product = await this.products.findProduct({ productId });
5
6
  switch (product?.status) {
@@ -21,7 +22,7 @@ export async function removeProductService({ productId }) {
21
22
  case ProductStatus.DELETED:
22
23
  return false;
23
24
  default:
24
- throw new Error(`Invalid status: ${product?.status}`);
25
+ throw createServiceError('ProductWrongStatusError', `Invalid status: ${product?.status}`);
25
26
  }
26
27
  return true;
27
28
  }
@@ -0,0 +1,5 @@
1
+ import type { Order } from '@unchainedshop/core-orders';
2
+ import type { Modules } from '../modules.ts';
3
+ export declare function reserveOrderDiscountsForCheckout(this: Modules, order: Order): Promise<{
4
+ release: () => Promise<void>;
5
+ }>;
@@ -0,0 +1,34 @@
1
+ import { createLogger } from '@unchainedshop/logger';
2
+ import { OrderDiscountDirector } from "../directors/OrderDiscountDirector.js";
3
+ const logger = createLogger('unchained:core:checkoutOrder');
4
+ export async function reserveOrderDiscountsForCheckout(order) {
5
+ const reservations = [];
6
+ const release = async () => {
7
+ const results = await Promise.allSettled(reservations.map((reservation) => reservation.release()));
8
+ for (const result of results) {
9
+ if (result.status === 'rejected') {
10
+ logger.error(`Could not release a discount reservation of order ${order._id}`, {
11
+ error: result.reason,
12
+ });
13
+ }
14
+ }
15
+ };
16
+ try {
17
+ const discounts = await this.orders.discounts.findOrderDiscounts({ orderId: order._id });
18
+ for (const orderDiscount of discounts) {
19
+ const Adapter = OrderDiscountDirector.getAdapter(orderDiscount.discountKey);
20
+ if (!Adapter)
21
+ continue;
22
+ const adapter = await Adapter.actions({
23
+ context: { order, orderDiscount, code: orderDiscount.code, modules: this },
24
+ });
25
+ if (adapter.reserveForCheckout)
26
+ reservations.push(await adapter.reserveForCheckout());
27
+ }
28
+ return { release };
29
+ }
30
+ catch (error) {
31
+ await release();
32
+ throw error;
33
+ }
34
+ }
@@ -3,10 +3,12 @@ import type { Product } from '@unchainedshop/core-products';
3
3
  import { type EstimatedDispatch } from '../directors/WarehousingDirector.ts';
4
4
  import type { WarehousingContext } from '../directors/WarehousingAdapter.ts';
5
5
  import type { WarehousingProvider } from '@unchainedshop/core-warehousing';
6
- export declare function simulateProductDispatchingService(this: Modules, { product, quantity, referenceDate, }: {
6
+ import type { DeliveryProviderType } from '@unchainedshop/core-delivery';
7
+ export declare function simulateProductDispatchingService(this: Modules, { product, quantity, referenceDate, deliveryProviderType, }: {
7
8
  product: Product;
8
9
  quantity: number;
9
10
  referenceDate?: Date;
11
+ deliveryProviderType?: DeliveryProviderType | null;
10
12
  }): Promise<(WarehousingContext & EstimatedDispatch & {
11
13
  warehousingProvider: WarehousingProvider;
12
14
  })[]>;
@@ -1,7 +1,7 @@
1
1
  import { supportedWarehousingProvidersService } from "./supportedWarehousingProviders.js";
2
2
  import { WarehousingDirector } from "../directors/WarehousingDirector.js";
3
- export async function simulateProductDispatchingService({ product, quantity, referenceDate, }) {
4
- const deliveryProviders = await this.delivery.allProviders();
3
+ export async function simulateProductDispatchingService({ product, quantity, referenceDate, deliveryProviderType, }) {
4
+ const deliveryProviders = (await this.delivery.allProviders()).filter(({ type }) => !deliveryProviderType || type === deliveryProviderType);
5
5
  return deliveryProviders.reduce(async (oldResult, deliveryProvider) => {
6
6
  const result = await oldResult;
7
7
  const warehousingProviders = await supportedWarehousingProvidersService.bind(this)({
@@ -25,6 +25,6 @@ export async function simulateProductDispatchingService({ product, quantity, ref
25
25
  ...dispatch,
26
26
  };
27
27
  }));
28
- return result.concat(result, mappedWarehousingProviders);
28
+ return result.concat(mappedWarehousingProviders);
29
29
  }, Promise.resolve([]));
30
30
  }
@@ -2,9 +2,11 @@ import type { Modules } from '../modules.ts';
2
2
  import type { Product } from '@unchainedshop/core-products';
3
3
  import type { WarehousingContext } from '../directors/WarehousingAdapter.ts';
4
4
  import type { WarehousingProvider } from '@unchainedshop/core-warehousing';
5
- export declare function simulateProductInventoryService(this: Modules, { product, referenceDate, }: {
5
+ import type { DeliveryProviderType } from '@unchainedshop/core-delivery';
6
+ export declare function simulateProductInventoryService(this: Modules, { product, referenceDate, deliveryProviderType, }: {
6
7
  product: Product;
7
8
  referenceDate?: Date;
9
+ deliveryProviderType?: DeliveryProviderType | null;
8
10
  }): Promise<(WarehousingContext & {
9
11
  quantity?: number;
10
12
  } & {
@@ -1,7 +1,7 @@
1
1
  import { supportedWarehousingProvidersService } from "./supportedWarehousingProviders.js";
2
2
  import { WarehousingDirector } from "../directors/WarehousingDirector.js";
3
- export async function simulateProductInventoryService({ product, referenceDate, }) {
4
- const deliveryProviders = await this.delivery.allProviders();
3
+ export async function simulateProductInventoryService({ product, referenceDate, deliveryProviderType, }) {
4
+ const deliveryProviders = (await this.delivery.allProviders()).filter(({ type }) => !deliveryProviderType || type === deliveryProviderType);
5
5
  return deliveryProviders.reduce(async (oldResult, deliveryProvider) => {
6
6
  const result = await oldResult;
7
7
  const warehousingProviders = await supportedWarehousingProvidersService.bind(this)({
@@ -24,6 +24,6 @@ export async function simulateProductInventoryService({ product, referenceDate,
24
24
  ...stock,
25
25
  };
26
26
  }));
27
- return result.concat(result, mappedWarehousingProviders);
27
+ return result.concat(mappedWarehousingProviders);
28
28
  }, Promise.resolve([]));
29
29
  }
@@ -1,8 +1,17 @@
1
1
  import { deliverySettings } from '@unchainedshop/core-delivery';
2
+ import { createLogger } from '@unchainedshop/logger';
2
3
  import { DeliveryDirector } from "../directors/index.js";
4
+ const logger = createLogger('unchained:core');
3
5
  export async function supportedDeliveryProvidersService(params) {
4
6
  const allProviders = await this.delivery.allProviders();
5
7
  const providers = (await Promise.all(allProviders.map(async (provider) => {
8
+ if (!DeliveryDirector.getAdapter(provider.adapterKey)) {
9
+ logger.warn('Delivery provider skipped, its adapter is not registered', {
10
+ deliveryProviderId: provider._id,
11
+ adapterKey: provider.adapterKey,
12
+ });
13
+ return [];
14
+ }
6
15
  const adapter = await DeliveryDirector.actions(provider, params, { modules: this });
7
16
  return adapter.isActive() ? [provider] : [];
8
17
  }))).flat();
@@ -1,8 +1,17 @@
1
1
  import { paymentSettings } from '@unchainedshop/core-payment';
2
+ import { createLogger } from '@unchainedshop/logger';
2
3
  import { PaymentDirector } from "../directors/PaymentDirector.js";
4
+ const logger = createLogger('unchained:core');
3
5
  export async function supportedPaymentProvidersService(params) {
4
6
  const allProviders = await this.payment.paymentProviders.allProviders();
5
7
  const providers = (await Promise.all(allProviders.map(async (provider) => {
8
+ if (!PaymentDirector.getAdapter(provider.adapterKey)) {
9
+ logger.warn('Payment provider skipped, its adapter is not registered', {
10
+ paymentProviderId: provider._id,
11
+ adapterKey: provider.adapterKey,
12
+ });
13
+ return [];
14
+ }
6
15
  const adapter = await PaymentDirector.actions(provider, params, { modules: this });
7
16
  return adapter.isActive() ? [provider] : [];
8
17
  }))).flat();