@unchainedshop/core 3.1.13 → 4.0.0-rc.3

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 (205) hide show
  1. package/lib/directors/BaseDiscountAdapter.js +0 -1
  2. package/lib/directors/BaseDiscountAdapter.js.map +1 -1
  3. package/lib/directors/BaseDiscountDirector.d.ts +1 -1
  4. package/lib/directors/BaseDiscountDirector.d.ts.map +1 -1
  5. package/lib/directors/BasePricingAdapter.d.ts +4 -4
  6. package/lib/directors/BasePricingAdapter.d.ts.map +1 -1
  7. package/lib/directors/BasePricingDirector.d.ts +2 -2
  8. package/lib/directors/BasePricingDirector.d.ts.map +1 -1
  9. package/lib/directors/BasePricingDirector.js.map +1 -1
  10. package/lib/directors/BasePricingSheet.d.ts +10 -10
  11. package/lib/directors/BasePricingSheet.d.ts.map +1 -1
  12. package/lib/directors/BasePricingSheet.js +2 -2
  13. package/lib/directors/BasePricingSheet.js.map +1 -1
  14. package/lib/directors/DeliveryAdapter.d.ts +2 -2
  15. package/lib/directors/DeliveryAdapter.d.ts.map +1 -1
  16. package/lib/directors/DeliveryDirector.d.ts.map +1 -1
  17. package/lib/directors/DeliveryDirector.js +1 -3
  18. package/lib/directors/DeliveryDirector.js.map +1 -1
  19. package/lib/directors/DeliveryPricingAdapter.d.ts +3 -3
  20. package/lib/directors/DeliveryPricingAdapter.d.ts.map +1 -1
  21. package/lib/directors/DeliveryPricingAdapter.js +2 -2
  22. package/lib/directors/DeliveryPricingAdapter.js.map +1 -1
  23. package/lib/directors/DeliveryPricingDirector.d.ts +3 -3
  24. package/lib/directors/DeliveryPricingDirector.d.ts.map +1 -1
  25. package/lib/directors/DeliveryPricingDirector.js +6 -6
  26. package/lib/directors/DeliveryPricingDirector.js.map +1 -1
  27. package/lib/directors/DeliveryPricingSheet.js +2 -2
  28. package/lib/directors/DeliveryPricingSheet.js.map +1 -1
  29. package/lib/directors/EnrollmentAdapter.d.ts +3 -3
  30. package/lib/directors/EnrollmentAdapter.d.ts.map +1 -1
  31. package/lib/directors/EnrollmentAdapter.js.map +1 -1
  32. package/lib/directors/FilterAdapter.d.ts +9 -12
  33. package/lib/directors/FilterAdapter.d.ts.map +1 -1
  34. package/lib/directors/FilterAdapter.js +0 -4
  35. package/lib/directors/FilterAdapter.js.map +1 -1
  36. package/lib/directors/FilterDirector.d.ts +9 -9
  37. package/lib/directors/FilterDirector.d.ts.map +1 -1
  38. package/lib/directors/FilterDirector.js.map +1 -1
  39. package/lib/directors/MessagingDirector.d.ts +11 -15
  40. package/lib/directors/MessagingDirector.d.ts.map +1 -1
  41. package/lib/directors/OrderPricingAdapter.d.ts +3 -3
  42. package/lib/directors/OrderPricingAdapter.d.ts.map +1 -1
  43. package/lib/directors/OrderPricingAdapter.js +2 -2
  44. package/lib/directors/OrderPricingAdapter.js.map +1 -1
  45. package/lib/directors/OrderPricingDirector.d.ts +2 -2
  46. package/lib/directors/OrderPricingDirector.d.ts.map +1 -1
  47. package/lib/directors/OrderPricingDirector.js +4 -4
  48. package/lib/directors/OrderPricingDirector.js.map +1 -1
  49. package/lib/directors/OrderPricingSheet.js +2 -2
  50. package/lib/directors/OrderPricingSheet.js.map +1 -1
  51. package/lib/directors/PaymentAdapter.d.ts +2 -2
  52. package/lib/directors/PaymentAdapter.d.ts.map +1 -1
  53. package/lib/directors/PaymentPricingAdapter.d.ts +2 -2
  54. package/lib/directors/PaymentPricingAdapter.d.ts.map +1 -1
  55. package/lib/directors/PaymentPricingAdapter.js +2 -2
  56. package/lib/directors/PaymentPricingAdapter.js.map +1 -1
  57. package/lib/directors/PaymentPricingDirector.d.ts +3 -3
  58. package/lib/directors/PaymentPricingDirector.d.ts.map +1 -1
  59. package/lib/directors/PaymentPricingDirector.js +6 -6
  60. package/lib/directors/PaymentPricingDirector.js.map +1 -1
  61. package/lib/directors/PaymentPricingSheet.js +1 -1
  62. package/lib/directors/PaymentPricingSheet.js.map +1 -1
  63. package/lib/directors/ProductDiscountConfiguration.d.ts +1 -1
  64. package/lib/directors/ProductDiscountConfiguration.d.ts.map +1 -1
  65. package/lib/directors/ProductPricingAdapter.d.ts +3 -3
  66. package/lib/directors/ProductPricingAdapter.d.ts.map +1 -1
  67. package/lib/directors/ProductPricingAdapter.js +2 -2
  68. package/lib/directors/ProductPricingAdapter.js.map +1 -1
  69. package/lib/directors/ProductPricingDirector.d.ts +5 -5
  70. package/lib/directors/ProductPricingDirector.d.ts.map +1 -1
  71. package/lib/directors/ProductPricingDirector.js +6 -6
  72. package/lib/directors/ProductPricingDirector.js.map +1 -1
  73. package/lib/directors/ProductPricingSheet.js +2 -2
  74. package/lib/directors/ProductPricingSheet.js.map +1 -1
  75. package/lib/directors/QuotationAdapter.d.ts +2 -2
  76. package/lib/directors/QuotationAdapter.d.ts.map +1 -1
  77. package/lib/directors/WarehousingAdapter.d.ts +3 -3
  78. package/lib/directors/WarehousingAdapter.d.ts.map +1 -1
  79. package/lib/directors/WarehousingDirector.d.ts +3 -3
  80. package/lib/directors/WarehousingDirector.d.ts.map +1 -1
  81. package/lib/directors/WorkerDirector.d.ts +2 -2
  82. package/lib/directors/WorkerDirector.d.ts.map +1 -1
  83. package/lib/directors/index.d.ts +4 -0
  84. package/lib/directors/index.d.ts.map +1 -1
  85. package/lib/directors/index.js +4 -0
  86. package/lib/directors/index.js.map +1 -1
  87. package/lib/services/calculateDiscountTotal.d.ts +1 -1
  88. package/lib/services/calculateDiscountTotal.js +5 -5
  89. package/lib/services/calculateDiscountTotal.js.map +1 -1
  90. package/lib/services/createEnrollmentFromCheckout.d.ts +3 -3
  91. package/lib/services/createEnrollmentFromCheckout.d.ts.map +1 -1
  92. package/lib/services/createEnrollmentFromCheckout.js +1 -1
  93. package/lib/services/createEnrollmentFromCheckout.js.map +1 -1
  94. package/lib/services/discountedEntities.d.ts +1 -1
  95. package/lib/services/discountedEntities.d.ts.map +1 -1
  96. package/lib/services/discountedEntities.js +4 -4
  97. package/lib/services/discountedEntities.js.map +1 -1
  98. package/lib/services/ercMetadata.d.ts +5 -3
  99. package/lib/services/ercMetadata.d.ts.map +1 -1
  100. package/lib/services/ercMetadata.js +2 -11
  101. package/lib/services/ercMetadata.js.map +1 -1
  102. package/lib/services/index.d.ts +1 -3
  103. package/lib/services/index.d.ts.map +1 -1
  104. package/lib/services/index.js.map +1 -1
  105. package/lib/services/loadFilters.d.ts +1 -1
  106. package/lib/services/loadFilters.d.ts.map +1 -1
  107. package/lib/services/loadFilters.js.map +1 -1
  108. package/lib/services/migrateBookmarks.d.ts +1 -1
  109. package/lib/services/migrateBookmarks.d.ts.map +1 -1
  110. package/lib/services/migrateOrderCart.d.ts +2 -2
  111. package/lib/services/migrateOrderCart.d.ts.map +1 -1
  112. package/lib/services/migrateOrderCart.js +3 -3
  113. package/lib/services/migrateOrderCart.js.map +1 -1
  114. package/lib/services/migrateUserData.js +2 -2
  115. package/lib/services/migrateUserData.js.map +1 -1
  116. package/lib/services/nextUserCart.js +2 -2
  117. package/lib/services/nextUserCart.js.map +1 -1
  118. package/lib/services/processOrder.d.ts.map +1 -1
  119. package/lib/services/processOrder.js +1 -3
  120. package/lib/services/processOrder.js.map +1 -1
  121. package/lib/services/removeFiles.d.ts +1 -1
  122. package/lib/services/removeFiles.d.ts.map +1 -1
  123. package/lib/services/removeFiles.js +1 -1
  124. package/lib/services/removeFiles.js.map +1 -1
  125. package/lib/services/searchProducts.d.ts.map +1 -1
  126. package/lib/services/searchProducts.js +1 -2
  127. package/lib/services/searchProducts.js.map +1 -1
  128. package/lib/services/simulateProductDispatching.d.ts +1 -3
  129. package/lib/services/simulateProductDispatching.d.ts.map +1 -1
  130. package/lib/services/simulateProductDispatching.js +2 -1
  131. package/lib/services/simulateProductDispatching.js.map +1 -1
  132. package/lib/services/simulateProductInventory.d.ts +1 -3
  133. package/lib/services/simulateProductInventory.d.ts.map +1 -1
  134. package/lib/services/simulateProductInventory.js +2 -1
  135. package/lib/services/simulateProductInventory.js.map +1 -1
  136. package/lib/services/simulateProductPricing.d.ts +3 -3
  137. package/lib/services/simulateProductPricing.d.ts.map +1 -1
  138. package/lib/services/supportedDeliveryProviders.js +1 -1
  139. package/lib/services/supportedDeliveryProviders.js.map +1 -1
  140. package/lib/services/supportedPaymentProviders.js +1 -1
  141. package/lib/services/supportedPaymentProviders.js.map +1 -1
  142. package/lib/services/supportedWarehousingProviders.js +1 -1
  143. package/lib/services/supportedWarehousingProviders.js.map +1 -1
  144. package/lib/services/updateCalculation.d.ts.map +1 -1
  145. package/lib/services/updateCalculation.js +4 -5
  146. package/lib/services/updateCalculation.js.map +1 -1
  147. package/lib/services/updateScheduling.js +1 -1
  148. package/lib/services/updateScheduling.js.map +1 -1
  149. package/package.json +21 -20
  150. package/src/directors/BaseDiscountAdapter.ts +1 -1
  151. package/src/directors/BaseDiscountDirector.ts +1 -1
  152. package/src/directors/BasePricingAdapter.ts +4 -4
  153. package/src/directors/BasePricingDirector.ts +4 -10
  154. package/src/directors/BasePricingSheet.ts +12 -12
  155. package/src/directors/BaseWorker.ts +117 -0
  156. package/src/directors/DeliveryAdapter.ts +2 -2
  157. package/src/directors/DeliveryDirector.ts +1 -3
  158. package/src/directors/DeliveryPricingAdapter.ts +5 -5
  159. package/src/directors/DeliveryPricingDirector.ts +9 -9
  160. package/src/directors/DeliveryPricingSheet.ts +2 -2
  161. package/src/directors/EnrollmentAdapter.ts +3 -6
  162. package/src/directors/EventListenerWorker.ts +101 -0
  163. package/src/directors/FailedRescheduler.ts +73 -0
  164. package/src/directors/FilterAdapter.ts +11 -11
  165. package/src/directors/FilterDirector.ts +16 -16
  166. package/src/directors/IntervalWorker.ts +75 -0
  167. package/src/directors/MessagingDirector.ts +10 -10
  168. package/src/directors/OrderPricingAdapter.ts +5 -5
  169. package/src/directors/OrderPricingDirector.ts +6 -6
  170. package/src/directors/OrderPricingSheet.ts +2 -2
  171. package/src/directors/PaymentAdapter.ts +2 -2
  172. package/src/directors/PaymentPricingAdapter.ts +4 -4
  173. package/src/directors/PaymentPricingDirector.ts +9 -9
  174. package/src/directors/PaymentPricingSheet.ts +1 -1
  175. package/src/directors/ProductDiscountConfiguration.ts +1 -1
  176. package/src/directors/ProductPricingAdapter.ts +5 -5
  177. package/src/directors/ProductPricingDirector.ts +11 -11
  178. package/src/directors/ProductPricingSheet.test.ts +22 -13
  179. package/src/directors/ProductPricingSheet.ts +2 -2
  180. package/src/directors/QuotationAdapter.ts +2 -2
  181. package/src/directors/WarehousingAdapter.ts +3 -3
  182. package/src/directors/WarehousingDirector.ts +3 -3
  183. package/src/directors/WorkerDirector.ts +2 -2
  184. package/src/directors/index.ts +4 -0
  185. package/src/services/calculateDiscountTotal.ts +5 -5
  186. package/src/services/createEnrollmentFromCheckout.ts +4 -4
  187. package/src/services/discountedEntities.ts +5 -5
  188. package/src/services/ercMetadata.ts +6 -14
  189. package/src/services/index.ts +1 -3
  190. package/src/services/loadFilters.ts +1 -1
  191. package/src/services/migrateBookmarks.ts +1 -1
  192. package/src/services/migrateOrderCart.ts +4 -4
  193. package/src/services/migrateUserData.ts +2 -2
  194. package/src/services/nextUserCart.ts +2 -2
  195. package/src/services/processOrder.ts +4 -3
  196. package/src/services/removeFiles.ts +2 -2
  197. package/src/services/searchProducts.ts +1 -3
  198. package/src/services/simulateProductDispatching.ts +3 -4
  199. package/src/services/simulateProductInventory.ts +3 -4
  200. package/src/services/simulateProductPricing.ts +3 -3
  201. package/src/services/supportedDeliveryProviders.ts +1 -1
  202. package/src/services/supportedPaymentProviders.ts +1 -1
  203. package/src/services/supportedWarehousingProviders.ts +1 -1
  204. package/src/services/updateCalculation.ts +4 -5
  205. package/src/services/updateScheduling.ts +2 -2
@@ -2,22 +2,22 @@ import { PricingCalculation } from '@unchainedshop/utils';
2
2
  export interface PricingDiscount {
3
3
  discountId: string;
4
4
  amount: number;
5
- currency: string;
5
+ currencyCode: string;
6
6
  }
7
7
 
8
8
  export interface IPricingSheet<Calculation extends PricingCalculation>
9
9
  extends IBasePricingSheet<Calculation> {
10
- discountPrices: (discountId?: string) => Array<PricingDiscount>;
10
+ discountPrices: (discountId?: string) => PricingDiscount[];
11
11
  addDiscount: (params: { amount: number; discountId: string; meta?: any }) => void;
12
12
  }
13
13
 
14
14
  export interface IBasePricingSheet<Calculation extends PricingCalculation> {
15
- calculation: Array<Calculation>;
16
- currency?: string;
15
+ calculation: Calculation[];
16
+ currencyCode?: string;
17
17
  quantity?: number;
18
18
 
19
- getRawPricingSheet: () => Array<Calculation>;
20
- filterBy: (filter?: Partial<Calculation>) => Array<Calculation>;
19
+ getRawPricingSheet: () => Calculation[];
20
+ filterBy: (filter?: Partial<Calculation>) => Calculation[];
21
21
  isValid: () => boolean;
22
22
 
23
23
  gross: () => number;
@@ -25,17 +25,17 @@ export interface IBasePricingSheet<Calculation extends PricingCalculation> {
25
25
  sum: (filter?: Partial<Calculation>) => number;
26
26
  total: (params?: { category?: string; discountId?: string; useNetPrice?: boolean }) => {
27
27
  amount: number;
28
- currency: string;
28
+ currencyCode: string;
29
29
  };
30
30
 
31
31
  taxSum: (filter?: Partial<Calculation>) => number;
32
32
 
33
- resetCalculation: (sheetToInvert: IBasePricingSheet<Calculation>) => Array<Calculation>;
33
+ resetCalculation: (sheetToInvert: IBasePricingSheet<Calculation>) => Calculation[];
34
34
  }
35
35
 
36
36
  export interface PricingSheetParams<Calculation extends PricingCalculation> {
37
- calculation?: Array<Calculation>;
38
- currency?: string;
37
+ calculation?: Calculation[];
38
+ currencyCode?: string;
39
39
  quantity?: number;
40
40
  }
41
41
 
@@ -44,7 +44,7 @@ export const BasePricingSheet = <Calculation extends PricingCalculation>(
44
44
  ): IBasePricingSheet<Calculation> => {
45
45
  const pricingSheet: IBasePricingSheet<Calculation> = {
46
46
  calculation: params.calculation || [],
47
- currency: params.currency,
47
+ currencyCode: params.currencyCode,
48
48
  quantity: params.quantity,
49
49
 
50
50
  getRawPricingSheet() {
@@ -84,7 +84,7 @@ export const BasePricingSheet = <Calculation extends PricingCalculation>(
84
84
 
85
85
  return {
86
86
  amount: Math.round(useNetPrice ? netAmount : netAmount + taxAmountForCategory),
87
- currency: this.currency,
87
+ currencyCode: this.currencyCode,
88
88
  };
89
89
  },
90
90
 
@@ -0,0 +1,117 @@
1
+ import later from '@breejs/later';
2
+ import { Work, WorkData } from '@unchainedshop/core-worker';
3
+ import { WorkerDirector } from './WorkerDirector.js';
4
+
5
+ export interface IWorker<P extends { workerId?: string }> {
6
+ key: string;
7
+ label: string;
8
+ version: string;
9
+ type: string;
10
+ external: boolean;
11
+
12
+ getFloorDate: (date?: Date) => Date;
13
+
14
+ actions: (
15
+ params: P,
16
+ unchainedAPI,
17
+ ) => {
18
+ autorescheduleTypes: (options: { referenceDate: Date }) => Promise<(Work | null)[]>;
19
+ process: (options: { maxWorkItemCount?: number; referenceDate?: Date }) => Promise<void>;
20
+ reset: () => Promise<void> | void;
21
+ start: () => Promise<void> | void;
22
+ stop: () => Promise<void> | void;
23
+ };
24
+ }
25
+
26
+ interface WorkerParams {
27
+ workerId?: string;
28
+ worker: IWorker<any>;
29
+ }
30
+
31
+ export const BaseWorker: IWorker<WorkerParams> = {
32
+ key: 'shop.unchained.worker.base',
33
+ label: 'Base worker. Do not use this directly.',
34
+ version: '1.0.0',
35
+ type: 'BASE',
36
+ external: false,
37
+
38
+ getFloorDate: (date = new Date()) => {
39
+ const floored = new Date(Math.floor(date.getTime() / 1000) * 1000);
40
+ return floored;
41
+ },
42
+
43
+ actions: ({ workerId }: WorkerParams, unchainedAPI) => {
44
+ const workerActions = {
45
+ async start() {
46
+ throw new Error(`Not implemented on ${this.constructor.key}`);
47
+ },
48
+
49
+ async stop() {
50
+ throw new Error(`Not implemented on ${this.constructor.key}`);
51
+ },
52
+
53
+ reset: async (referenceDate = new Date()) => {
54
+ await unchainedAPI.modules.worker.markOldWorkAsFailed({
55
+ types: WorkerDirector.getActivePluginTypes({ external: false }),
56
+ worker: workerId,
57
+ referenceDate,
58
+ });
59
+ },
60
+
61
+ autorescheduleTypes: async ({ referenceDate }) => {
62
+ return Promise.all(
63
+ WorkerDirector.getAutoSchedules().map(async ([scheduleId, workConfig]) => {
64
+ if (!workConfig.schedule) {
65
+ await unchainedAPI.modules.worker.ensureNoWork({
66
+ type: workConfig.type,
67
+ priority: workConfig.priority || 0,
68
+ scheduleId,
69
+ });
70
+ return null;
71
+ }
72
+
73
+ const fixedSchedule = { ...workConfig.schedule };
74
+ fixedSchedule.schedules[0].s = [0]; // ignore seconds, always run on second 0
75
+ const nextDate = later.schedule(fixedSchedule).next(1, referenceDate) as Date;
76
+ nextDate.setMilliseconds(0);
77
+ const workData: WorkData = {
78
+ type: workConfig.type,
79
+ scheduleId,
80
+ scheduled: nextDate,
81
+ timeout: workConfig.timeout,
82
+ priority: workConfig.priority || 0,
83
+ retries: workConfig.retries || 0,
84
+ };
85
+ if (workConfig.input) {
86
+ workData.input = await workConfig.input(workData);
87
+ // A work input fn can skip auto scheduling a new record
88
+ // when it explicitly returns a falsish input instead of a dictionary
89
+ if (!workData.input) return null;
90
+ }
91
+ return unchainedAPI.modules.worker.ensureOneWork(workData);
92
+ }),
93
+ );
94
+ },
95
+
96
+ process: async ({ maxWorkItemCount = 10, referenceDate }) => {
97
+ await workerActions.autorescheduleTypes({
98
+ referenceDate,
99
+ });
100
+
101
+ let processedCount = 0;
102
+ while (true) {
103
+ if (maxWorkItemCount && maxWorkItemCount <= processedCount) break;
104
+
105
+ const doneWork = await WorkerDirector.processNextWork(unchainedAPI, workerId);
106
+ if (!doneWork) break;
107
+
108
+ processedCount++;
109
+ }
110
+ },
111
+ };
112
+
113
+ workerActions.reset();
114
+
115
+ return workerActions;
116
+ },
117
+ };
@@ -25,12 +25,12 @@ export interface DeliveryAdapterActions {
25
25
  isActive: () => boolean;
26
26
  isAutoReleaseAllowed: () => boolean;
27
27
  pickUpLocationById: (locationId: string) => Promise<DeliveryLocation>;
28
- pickUpLocations: () => Promise<Array<DeliveryLocation>>;
28
+ pickUpLocations: () => Promise<DeliveryLocation[]>;
29
29
  send: () => Promise<boolean | Work>;
30
30
  }
31
31
 
32
32
  export interface DeliveryContext {
33
- country?: string;
33
+ countryCode?: string;
34
34
  deliveryProvider?: DeliveryProvider;
35
35
  order?: Order;
36
36
  orderDelivery?: OrderDelivery;
@@ -103,12 +103,10 @@ export const DeliveryDirector: IDeliveryDirector = {
103
103
  const deliveryProvider = await unchainedAPI.modules.delivery.findProvider({
104
104
  deliveryProviderId: orderDelivery.deliveryProviderId,
105
105
  });
106
- const deliveryProviderId = deliveryProvider._id;
107
106
  const address = orderDelivery.context?.address || order || order.billingAddress;
108
- const provider = await await unchainedAPI.modules.delivery.findProvider({ deliveryProviderId });
109
107
 
110
108
  const adapter = await DeliveryDirector.actions(
111
- provider,
109
+ deliveryProvider,
112
110
  {
113
111
  order,
114
112
  orderDelivery,
@@ -37,14 +37,14 @@ export type IDeliveryPricingSheet = IPricingSheet<DeliveryPricingCalculation> &
37
37
  };
38
38
 
39
39
  export interface DeliveryPricingAdapterContext extends BasePricingAdapterContext {
40
- country?: string;
41
- currency?: string;
40
+ countryCode?: string;
41
+ currencyCode?: string;
42
42
  provider: DeliveryProvider;
43
43
  providerContext?: any;
44
44
  order: Order;
45
45
  orderDelivery: OrderDelivery;
46
46
  user: User;
47
- discounts: Array<OrderDiscount>;
47
+ discounts: OrderDiscount[];
48
48
  }
49
49
 
50
50
  export type IDeliveryPricingAdapter<DiscountConfiguration = unknown> = IPricingAdapter<
@@ -68,9 +68,9 @@ export const DeliveryPricingAdapter: IDeliveryPricingAdapter = {
68
68
 
69
69
  actions: (params) => {
70
70
  const { context } = params;
71
- const { currency } = context;
71
+ const { currencyCode } = context;
72
72
  const baseActions = basePricingAdapter.actions(params);
73
- const resultSheet = DeliveryPricingSheet({ currency });
73
+ const resultSheet = DeliveryPricingSheet({ currencyCode });
74
74
 
75
75
  return {
76
76
  ...baseActions,
@@ -14,14 +14,14 @@ import type { OrderDelivery } from '@unchainedshop/core-orders';
14
14
 
15
15
  export type DeliveryPricingContext =
16
16
  | {
17
- currency: string;
18
- country?: string;
17
+ currencyCode: string;
18
+ countryCode?: string;
19
19
  provider: DeliveryProvider;
20
20
  providerContext?: any;
21
21
  order: Order;
22
22
  user: User;
23
23
  }
24
- | { currency: string; item: OrderDelivery };
24
+ | { currencyCode: string; item: OrderDelivery };
25
25
 
26
26
  export type IDeliveryPricingDirector<DiscountConfiguration = unknown> = IPricingDirector<
27
27
  DeliveryPricingContext,
@@ -45,7 +45,7 @@ export const DeliveryPricingDirector: IDeliveryPricingDirector<any> = {
45
45
  const { modules } = unchainedAPI;
46
46
 
47
47
  if ('item' in context) {
48
- const { item, currency } = context;
48
+ const { item, currencyCode } = context;
49
49
  const order = await modules.orders.findOrder({
50
50
  orderId: item.orderId,
51
51
  });
@@ -59,8 +59,8 @@ export const DeliveryPricingDirector: IDeliveryPricingDirector<any> = {
59
59
 
60
60
  return {
61
61
  ...unchainedAPI,
62
- country: order.countryCode,
63
- currency,
62
+ countryCode: order.countryCode,
63
+ currencyCode,
64
64
  order,
65
65
  provider,
66
66
  user,
@@ -72,8 +72,8 @@ export const DeliveryPricingDirector: IDeliveryPricingDirector<any> = {
72
72
 
73
73
  return {
74
74
  ...unchainedAPI,
75
- country: context.country,
76
- currency: context.currency,
75
+ countryCode: context.countryCode,
76
+ currencyCode: context.currencyCode,
77
77
  order: context.order,
78
78
  provider: context.provider,
79
79
  user: context.user,
@@ -86,7 +86,7 @@ export const DeliveryPricingDirector: IDeliveryPricingDirector<any> = {
86
86
  calculationSheet(pricingContext, calculation) {
87
87
  return DeliveryPricingSheet({
88
88
  calculation,
89
- currency: pricingContext.currency,
89
+ currencyCode: pricingContext.currencyCode,
90
90
  });
91
91
  },
92
92
  };
@@ -65,7 +65,7 @@ export const DeliveryPricingSheet = (
65
65
 
66
66
  return [...new Set(discountIds)]
67
67
  .map((discountId) => {
68
- const { currency, amount } = basePricingSheet.total({
68
+ const { currencyCode, amount } = basePricingSheet.total({
69
69
  category: DeliveryPricingRowCategory.Discount,
70
70
  discountId,
71
71
  });
@@ -75,7 +75,7 @@ export const DeliveryPricingSheet = (
75
75
  return {
76
76
  discountId,
77
77
  amount: Math.round(amount),
78
- currency,
78
+ currencyCode,
79
79
  };
80
80
  })
81
81
  .filter(Boolean);
@@ -8,15 +8,12 @@ import {
8
8
  import type { Product, ProductPlan } from '@unchainedshop/core-products';
9
9
  import type { OrderPosition } from '@unchainedshop/core-orders';
10
10
 
11
- export type EnrollmentContext = {
11
+ export interface EnrollmentContext {
12
12
  enrollment: Enrollment;
13
- };
13
+ }
14
14
 
15
15
  export interface EnrollmentAdapterActions {
16
- configurationForOrder: (params: {
17
- period: EnrollmentPeriod;
18
- products: Array<Product>;
19
- }) => Promise<any>;
16
+ configurationForOrder: (params: { period: EnrollmentPeriod; products: Product[] }) => Promise<any>;
20
17
  isOverdue: () => Promise<boolean>;
21
18
  isValidForActivation: () => Promise<boolean>;
22
19
  nextPeriod: () => Promise<EnrollmentPeriod>;
@@ -0,0 +1,101 @@
1
+ import { subscribe } from '@unchainedshop/events';
2
+ import { BaseWorker, IWorker } from './BaseWorker.js';
3
+ import { WorkerEventTypes } from '@unchainedshop/core-worker';
4
+ import { setTimeout } from 'node:timers/promises';
5
+ import { createLogger } from '@unchainedshop/logger';
6
+
7
+ const logger = createLogger('unchained:worker');
8
+
9
+ function debounce<T extends (...args: any[]) => Promise<any>>(
10
+ func: T,
11
+ wait: number,
12
+ ): T & { cancel: () => void } {
13
+ let abortController: AbortController | null = null;
14
+
15
+ const debounced = (async (...args: Parameters<T>) => {
16
+ // Cancel any pending execution
17
+ if (abortController) {
18
+ abortController.abort();
19
+ }
20
+
21
+ // Create new abort controller for this execution
22
+ abortController = new AbortController();
23
+
24
+ try {
25
+ // Wait for the debounce period
26
+ await setTimeout(wait, undefined, { signal: abortController.signal });
27
+
28
+ // If we reach here, the timeout completed without being aborted
29
+ const result = await func(...args);
30
+ abortController = null;
31
+ return result;
32
+ } catch (error) {
33
+ // If the operation was aborted, don't execute the function
34
+ if (error.name === 'AbortError') {
35
+ return;
36
+ }
37
+ // Re-throw any other errors
38
+ throw error;
39
+ }
40
+ }) as T & { cancel: () => void };
41
+
42
+ debounced.cancel = () => {
43
+ if (abortController) {
44
+ abortController.abort();
45
+ abortController = null;
46
+ }
47
+ };
48
+
49
+ return debounced;
50
+ }
51
+
52
+ export interface EventListenerWorkerParams {
53
+ workerId?: string;
54
+ }
55
+
56
+ export const EventListenerWorker: IWorker<EventListenerWorkerParams> = {
57
+ ...BaseWorker,
58
+
59
+ key: 'shop.unchained.worker.event-listener',
60
+ label: 'Allocates work on events. This worker does not make sense on multiple containers.',
61
+ version: '1.0.0',
62
+ type: 'EVENT_LISTENER',
63
+
64
+ actions: ({ workerId }, unchainedAPI) => {
65
+ const baseWorkerActions = BaseWorker.actions(
66
+ { workerId, worker: EventListenerWorker },
67
+ unchainedAPI,
68
+ );
69
+
70
+ // Debounce in the event of many work queue events conflicting with each other
71
+ const processWorkQueue = debounce<() => Promise<void>>(async () => {
72
+ try {
73
+ await baseWorkerActions.process({
74
+ maxWorkItemCount: 1, // only one work item at a time, else we could end up in a loop
75
+ referenceDate: EventListenerWorker.getFloorDate(),
76
+ });
77
+ } catch (error) {
78
+ // Log error but don't crash the worker
79
+ logger.error(error);
80
+ }
81
+ }, 300);
82
+
83
+ return {
84
+ ...baseWorkerActions,
85
+
86
+ async start() {
87
+ subscribe(WorkerEventTypes.ADDED, processWorkQueue);
88
+ subscribe(WorkerEventTypes.FINISHED, processWorkQueue);
89
+
90
+ await setTimeout(300);
91
+ await baseWorkerActions.autorescheduleTypes({
92
+ referenceDate: EventListenerWorker.getFloorDate(),
93
+ });
94
+ },
95
+
96
+ stop() {
97
+ processWorkQueue.cancel();
98
+ },
99
+ };
100
+ },
101
+ };
@@ -0,0 +1,73 @@
1
+ import { defaultLogger } from '@unchainedshop/logger';
2
+ import { subscribe } from '@unchainedshop/events';
3
+ import { Work, WorkData, WorkerEventTypes } from '@unchainedshop/core-worker';
4
+
5
+ export interface FailedReschedulerParams {
6
+ transformRetry?: (workData: WorkData) => Promise<WorkData | null>;
7
+ }
8
+
9
+ export interface IScheduler<P> {
10
+ key: string;
11
+ label: string;
12
+ version: string;
13
+
14
+ actions: (
15
+ params: P,
16
+ unchainedAPI,
17
+ ) => {
18
+ start: () => void;
19
+ stop: () => void;
20
+ };
21
+ }
22
+
23
+ export const FailedRescheduler: IScheduler<FailedReschedulerParams> = {
24
+ key: 'shop.unchained.scheduler.failed',
25
+ label: 'Reschedule failed works',
26
+ version: '1.0.0',
27
+
28
+ actions: ({ transformRetry }, unchainedAPI) => {
29
+ const handleFinishedWork = async ({ payload: work }: { payload: Work }) => {
30
+ if (!work.success && work.retries > 0) {
31
+ const now = new Date();
32
+ const workDelayMs = work.scheduled.getTime() - work.created.getTime();
33
+
34
+ // In short: Double the delay of the old work or delay for 5 seconds
35
+ const scheduled =
36
+ workDelayMs > 1000
37
+ ? new Date(now.getTime() + workDelayMs * 2)
38
+ : new Date(now.setSeconds(now.getSeconds() + 5));
39
+
40
+ defaultLogger.error(
41
+ `${FailedRescheduler.key} -> Reschedule failed work ${work._id} ${
42
+ work.type
43
+ } for ${scheduled.toISOString()} (in ${Math.round(workDelayMs / 1000)}). Remaining retries: ${
44
+ work.retries
45
+ }`,
46
+ );
47
+
48
+ const newWorkData = {
49
+ type: work.type,
50
+ priority: work.priority,
51
+ originalWorkId: work.originalWorkId || work._id,
52
+ retries: work.retries - 1,
53
+ timeout: work.timeout,
54
+ input: work.input,
55
+ scheduled,
56
+ };
57
+ await unchainedAPI.modules.worker.addWork(
58
+ transformRetry ? await transformRetry(newWorkData) : newWorkData,
59
+ );
60
+ }
61
+ };
62
+
63
+ return {
64
+ start() {
65
+ subscribe<Work>(WorkerEventTypes.FINISHED, handleFinishedWork);
66
+ },
67
+
68
+ stop() {
69
+ /* */
70
+ },
71
+ };
72
+ },
73
+ };
@@ -5,23 +5,23 @@ import { Product } from '@unchainedshop/core-products';
5
5
  import { Filter, SearchQuery } from '@unchainedshop/core-filters';
6
6
  import { Modules } from '../modules.js';
7
7
 
8
- export type FilterInputText = { locale: string; title: string; subtitle?: string };
9
-
10
- export enum FilterError {
11
- NOT_IMPLEMENTED = 'NOT_IMPLEMENTED',
8
+ export interface FilterInputText {
9
+ locale: string;
10
+ title: string;
11
+ subtitle?: string;
12
12
  }
13
13
 
14
- export type FilterContext = {
14
+ export interface FilterContext {
15
15
  filter?: Filter;
16
16
  searchQuery: SearchQuery;
17
- };
17
+ }
18
18
 
19
19
  export interface FilterAdapterActions {
20
- aggregateProductIds: (params: { productIds: Array<string> }) => Array<string>;
20
+ aggregateProductIds: (params: { productIds: string[] }) => string[];
21
21
 
22
22
  searchAssortments: (
23
23
  params: {
24
- assortmentIds: Array<string>;
24
+ assortmentIds: string[];
25
25
  },
26
26
  options: {
27
27
  filterSelector: mongodb.Filter<Filter>;
@@ -29,11 +29,11 @@ export interface FilterAdapterActions {
29
29
  sortStage: mongodb.FindOptions['sort'];
30
30
  locale: Intl.Locale;
31
31
  },
32
- ) => Promise<Array<string>>;
32
+ ) => Promise<string[]>;
33
33
 
34
34
  searchProducts: (
35
35
  params: {
36
- productIds: Array<string>;
36
+ productIds?: string[];
37
37
  },
38
38
  options: {
39
39
  filterSelector: mongodb.Filter<Filter>;
@@ -41,7 +41,7 @@ export interface FilterAdapterActions {
41
41
  sortStage: mongodb.FindOptions['sort'];
42
42
  locale: Intl.Locale;
43
43
  },
44
- ) => Promise<Array<string>>;
44
+ ) => Promise<string[]>;
45
45
 
46
46
  transformFilterSelector: (
47
47
  query: mongodb.Filter<Filter>,
@@ -12,7 +12,7 @@ import {
12
12
  import { Product } from '@unchainedshop/core-products';
13
13
  import { Modules } from '../modules.js';
14
14
 
15
- export const parseQueryArray = (query: SearchFilterQuery): Record<string, Array<string>> =>
15
+ export const parseQueryArray = (query: SearchFilterQuery): Record<string, string[]> =>
16
16
  (query || []).reduce(
17
17
  (accumulator, { key, value }) => ({
18
18
  ...accumulator,
@@ -31,24 +31,24 @@ export type IFilterDirector = IBaseDirector<IFilterAdapter> & {
31
31
  filter: Filter,
32
32
  { value }: { value?: boolean | string },
33
33
  unchainedAPI: { modules: Modules },
34
- ) => Promise<Array<string>>;
34
+ ) => Promise<string[]>;
35
35
  buildProductIdMap: (
36
36
  filter: Filter,
37
37
  unchainedAPI: { modules: Modules },
38
- ) => Promise<[Array<string>, Record<string, Array<string>>]>;
38
+ ) => Promise<[string[], Record<string, string[]>]>;
39
39
  filterProductIds: (
40
40
  filter: Filter,
41
- { values, forceLiveCollection }: { values: Array<string>; forceLiveCollection?: boolean },
41
+ { values, forceLiveCollection }: { values: string[]; forceLiveCollection?: boolean },
42
42
  unchainedAPI: { modules: Modules },
43
- ) => Promise<Array<string>>;
43
+ ) => Promise<string[]>;
44
44
 
45
45
  filterFacets: (
46
46
  filter: Filter,
47
47
  params: {
48
48
  searchQuery: SearchQuery;
49
49
  forceLiveCollection?: boolean;
50
- allProductIds: Array<string>;
51
- otherFilters: Array<Filter>;
50
+ allProductIds: string[];
51
+ otherFilters: Filter[];
52
52
  },
53
53
  unchainedAPI: { modules: Modules },
54
54
  ) => Promise<{
@@ -58,10 +58,10 @@ export type IFilterDirector = IBaseDirector<IFilterAdapter> & {
58
58
  }>;
59
59
 
60
60
  productFacetedSearch: (
61
- productIds: Array<string>,
61
+ productIds: string[],
62
62
  searchConfiguration: SearchConfiguration,
63
63
  unchainedAPI: { modules: Modules },
64
- ) => Promise<Array<string>>;
64
+ ) => Promise<string[]>;
65
65
  };
66
66
 
67
67
  const baseDirector = BaseDirector<IFilterAdapter>('FilterDirector', {
@@ -97,14 +97,14 @@ export const FilterDirector: IFilterDirector = {
97
97
  },
98
98
 
99
99
  searchAssortments: async (params, options) => {
100
- return reduceAdapters<Array<string>>(async (lastSearchPromise, adapter) => {
100
+ return reduceAdapters<string[]>(async (lastSearchPromise, adapter) => {
101
101
  const assortmentIds = await lastSearchPromise;
102
102
  return adapter.searchAssortments({ assortmentIds }, options);
103
103
  }, params.assortmentIds);
104
104
  },
105
105
 
106
106
  searchProducts: async (params, options) => {
107
- return reduceAdapters<Array<string>>(async (lastSearchPromise, adapter) => {
107
+ return reduceAdapters<string[]>(async (lastSearchPromise, adapter) => {
108
108
  const productIds = await lastSearchPromise;
109
109
  return adapter.searchProducts({ productIds }, options);
110
110
  }, params.productIds);
@@ -155,7 +155,7 @@ export const FilterDirector: IFilterDirector = {
155
155
  async buildProductIdMap(
156
156
  filter: Filter,
157
157
  unchainedAPI: { modules: Modules },
158
- ): Promise<[Array<string>, Record<string, Array<string>>]> {
158
+ ): Promise<[string[], Record<string, string[]>]> {
159
159
  const allProductIds = await this.findProductIds(filter, {}, unchainedAPI);
160
160
  const productIdsMap =
161
161
  filter.type === FilterType.SWITCH
@@ -176,10 +176,10 @@ export const FilterDirector: IFilterDirector = {
176
176
 
177
177
  async filterProductIds(
178
178
  filter: Filter,
179
- { values, forceLiveCollection }: { values: Array<string>; forceLiveCollection?: boolean },
179
+ { values, forceLiveCollection }: { values: string[]; forceLiveCollection?: boolean },
180
180
  unchainedAPI: { modules: Modules },
181
181
  ) {
182
- const [allProductIds, keyToProductIdMap]: [Array<string>, Record<string, Array<string>>] =
182
+ const [allProductIds, keyToProductIdMap]: [string[], Record<string, string[]>] =
183
183
  (!forceLiveCollection && (await filtersSettings.getCachedProductIds(filter._id))) ||
184
184
  (await this.buildProductIdMap(filter, unchainedAPI));
185
185
 
@@ -199,10 +199,10 @@ export const FilterDirector: IFilterDirector = {
199
199
  },
200
200
 
201
201
  async productFacetedSearch(
202
- productIds: Array<string>,
202
+ productIds: string[],
203
203
  searchConfiguration: SearchConfiguration,
204
204
  unchainedAPI: { modules: Modules },
205
- ): Promise<Array<string>> {
205
+ ): Promise<string[]> {
206
206
  const { searchQuery, filterSelector, forceLiveCollection } = searchConfiguration;
207
207
  const { modules } = unchainedAPI;
208
208
  if (!searchQuery || !searchQuery.filterQuery) return productIds;