@unchainedshop/core-orders 4.0.0-rc.2 → 4.0.0-rc.21

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 (132) hide show
  1. package/lib/db/OrderDeliveriesCollection.d.ts +2 -2
  2. package/lib/db/OrderDeliveriesCollection.d.ts.map +1 -1
  3. package/lib/db/OrderDeliveriesSchema.d.ts +3 -0
  4. package/lib/db/OrderDeliveriesSchema.d.ts.map +1 -0
  5. package/lib/db/OrderDeliveriesSchema.js +20 -0
  6. package/lib/db/OrderDeliveriesSchema.js.map +1 -0
  7. package/lib/db/OrderDiscountTrigger.d.ts +5 -0
  8. package/lib/db/OrderDiscountTrigger.d.ts.map +1 -0
  9. package/lib/db/OrderDiscountTrigger.js +6 -0
  10. package/lib/db/OrderDiscountTrigger.js.map +1 -0
  11. package/lib/db/OrderDiscountsCollection.d.ts +2 -2
  12. package/lib/db/OrderDiscountsCollection.d.ts.map +1 -1
  13. package/lib/db/OrderDiscountsSchema.d.ts +3 -0
  14. package/lib/db/OrderDiscountsSchema.d.ts.map +1 -0
  15. package/lib/db/OrderDiscountsSchema.js +12 -0
  16. package/lib/db/OrderDiscountsSchema.js.map +1 -0
  17. package/lib/db/OrderPaymentsCollection.d.ts +3 -3
  18. package/lib/db/OrderPaymentsCollection.d.ts.map +1 -1
  19. package/lib/db/OrderPaymentsSchema.d.ts +3 -0
  20. package/lib/db/OrderPaymentsSchema.d.ts.map +1 -0
  21. package/lib/db/OrderPaymentsSchema.js +20 -0
  22. package/lib/db/OrderPaymentsSchema.js.map +1 -0
  23. package/lib/db/OrderPositionsCollection.d.ts +1 -2
  24. package/lib/db/OrderPositionsCollection.d.ts.map +1 -1
  25. package/lib/db/OrderPositionsCollection.js.map +1 -1
  26. package/lib/db/OrderPositionsSchema.d.ts +3 -0
  27. package/lib/db/OrderPositionsSchema.d.ts.map +1 -0
  28. package/lib/db/OrderPositionsSchema.js +37 -0
  29. package/lib/db/OrderPositionsSchema.js.map +1 -0
  30. package/lib/db/OrdersCollection.d.ts +5 -1
  31. package/lib/db/OrdersCollection.d.ts.map +1 -1
  32. package/lib/db/OrdersCollection.js +25 -21
  33. package/lib/db/OrdersCollection.js.map +1 -1
  34. package/lib/db/OrdersSchema.d.ts +3 -0
  35. package/lib/db/OrdersSchema.d.ts.map +1 -0
  36. package/lib/db/OrdersSchema.js +30 -0
  37. package/lib/db/OrdersSchema.js.map +1 -0
  38. package/lib/director/OrderDiscountAdapter.d.ts +4 -0
  39. package/lib/director/OrderDiscountAdapter.d.ts.map +1 -0
  40. package/lib/director/OrderDiscountAdapter.js +3 -0
  41. package/lib/director/OrderDiscountAdapter.js.map +1 -0
  42. package/lib/director/OrderDiscountConfiguration.d.ts +6 -0
  43. package/lib/director/OrderDiscountConfiguration.d.ts.map +1 -0
  44. package/lib/director/OrderDiscountConfiguration.js +2 -0
  45. package/lib/director/OrderDiscountConfiguration.js.map +1 -0
  46. package/lib/director/OrderDiscountDirector.d.ts +3 -0
  47. package/lib/director/OrderDiscountDirector.d.ts.map +1 -0
  48. package/lib/director/OrderDiscountDirector.js +3 -0
  49. package/lib/director/OrderDiscountDirector.js.map +1 -0
  50. package/lib/director/OrderPricingAdapter.d.ts +4 -0
  51. package/lib/director/OrderPricingAdapter.d.ts.map +1 -0
  52. package/lib/director/OrderPricingAdapter.js +25 -0
  53. package/lib/director/OrderPricingAdapter.js.map +1 -0
  54. package/lib/director/OrderPricingDirector.d.ts +3 -0
  55. package/lib/director/OrderPricingDirector.d.ts.map +1 -0
  56. package/lib/director/OrderPricingDirector.js +39 -0
  57. package/lib/director/OrderPricingDirector.js.map +1 -0
  58. package/lib/director/OrderPricingSheet.d.ts +4 -0
  59. package/lib/director/OrderPricingSheet.d.ts.map +1 -0
  60. package/lib/director/OrderPricingSheet.js +101 -0
  61. package/lib/director/OrderPricingSheet.js.map +1 -0
  62. package/lib/module/buildFindSelector.d.ts +1 -1
  63. package/lib/module/buildFindSelector.d.ts.map +1 -1
  64. package/lib/module/buildFindSelector.js +17 -1
  65. package/lib/module/buildFindSelector.js.map +1 -1
  66. package/lib/module/configureOrderDeliveriesModule.d.ts +9 -6
  67. package/lib/module/configureOrderDeliveriesModule.d.ts.map +1 -1
  68. package/lib/module/configureOrderDeliveriesModule.js +14 -10
  69. package/lib/module/configureOrderDeliveriesModule.js.map +1 -1
  70. package/lib/module/configureOrderDiscountsModule.d.ts +5 -5
  71. package/lib/module/configureOrderDiscountsModule.d.ts.map +1 -1
  72. package/lib/module/configureOrderDiscountsModule.js +3 -3
  73. package/lib/module/configureOrderDiscountsModule.js.map +1 -1
  74. package/lib/module/configureOrderPaymentsModule.d.ts +10 -7
  75. package/lib/module/configureOrderPaymentsModule.d.ts.map +1 -1
  76. package/lib/module/configureOrderPaymentsModule.js +18 -10
  77. package/lib/module/configureOrderPaymentsModule.js.map +1 -1
  78. package/lib/module/configureOrderPositionsModule.d.ts +16 -5
  79. package/lib/module/configureOrderPositionsModule.d.ts.map +1 -1
  80. package/lib/module/configureOrderPositionsModule.js +25 -5
  81. package/lib/module/configureOrderPositionsModule.js.map +1 -1
  82. package/lib/module/configureOrdersModule-mutations.d.ts +14 -13
  83. package/lib/module/configureOrdersModule-mutations.d.ts.map +1 -1
  84. package/lib/module/configureOrdersModule-mutations.js +19 -11
  85. package/lib/module/configureOrdersModule-mutations.js.map +1 -1
  86. package/lib/module/configureOrdersModule-processing.d.ts +14 -0
  87. package/lib/module/configureOrdersModule-processing.d.ts.map +1 -0
  88. package/lib/module/configureOrdersModule-processing.js +348 -0
  89. package/lib/module/configureOrdersModule-processing.js.map +1 -0
  90. package/lib/module/configureOrdersModule-queries.d.ts +21 -6
  91. package/lib/module/configureOrdersModule-queries.d.ts.map +1 -1
  92. package/lib/module/configureOrdersModule-queries.js +19 -84
  93. package/lib/module/configureOrdersModule-queries.js.map +1 -1
  94. package/lib/module/configureOrdersModule-transformations.d.ts +6 -0
  95. package/lib/module/configureOrdersModule-transformations.d.ts.map +1 -0
  96. package/lib/module/configureOrdersModule-transformations.js +112 -0
  97. package/lib/module/configureOrdersModule-transformations.js.map +1 -0
  98. package/lib/module/configureOrdersModule.d.ts +154 -21
  99. package/lib/module/configureOrdersModule.d.ts.map +1 -1
  100. package/lib/module/configureOrdersModule.js +9 -3
  101. package/lib/module/configureOrdersModule.js.map +1 -1
  102. package/lib/orders-settings.d.ts +8 -12
  103. package/lib/orders-settings.d.ts.map +1 -1
  104. package/lib/orders-settings.js +8 -8
  105. package/lib/orders-settings.js.map +1 -1
  106. package/lib/service/migrateOrderCartService.d.ts +3 -0
  107. package/lib/service/migrateOrderCartService.d.ts.map +1 -0
  108. package/lib/service/migrateOrderCartService.js +32 -0
  109. package/lib/service/migrateOrderCartService.js.map +1 -0
  110. package/lib/service/nextUserCartService.d.ts +3 -0
  111. package/lib/service/nextUserCartService.d.ts.map +1 -0
  112. package/lib/service/nextUserCartService.js +34 -0
  113. package/lib/service/nextUserCartService.js.map +1 -0
  114. package/lib/service/orderServices.d.ts +3 -0
  115. package/lib/service/orderServices.d.ts.map +1 -0
  116. package/lib/service/orderServices.js +7 -0
  117. package/lib/service/orderServices.js.map +1 -0
  118. package/package.json +6 -6
  119. package/src/db/OrderDeliveriesCollection.ts +2 -2
  120. package/src/db/OrderDiscountsCollection.ts +2 -2
  121. package/src/db/OrderPaymentsCollection.ts +3 -3
  122. package/src/db/OrderPositionsCollection.ts +1 -2
  123. package/src/db/OrdersCollection.ts +31 -22
  124. package/src/module/buildFindSelector.ts +19 -1
  125. package/src/module/configureOrderDeliveriesModule.ts +28 -16
  126. package/src/module/configureOrderDiscountsModule.ts +11 -11
  127. package/src/module/configureOrderPaymentsModule.ts +31 -20
  128. package/src/module/configureOrderPositionsModule.ts +47 -16
  129. package/src/module/configureOrdersModule-mutations.ts +46 -44
  130. package/src/module/configureOrdersModule-queries.ts +42 -91
  131. package/src/module/configureOrdersModule.ts +21 -33
  132. package/src/orders-settings.ts +20 -19
@@ -10,6 +10,17 @@ const ORDER_POSITION_EVENTS: string[] = [
10
10
  'ORDER_ADD_PRODUCT',
11
11
  ];
12
12
 
13
+ export interface OrderPositionAggregateParams {
14
+ match?: mongodb.Document;
15
+ matchAfterGroup?: mongodb.Document;
16
+ project?: mongodb.Document;
17
+ group?: mongodb.Document;
18
+ addFields?: mongodb.Document;
19
+ sort?: mongodb.Document;
20
+ limit?: number;
21
+ pipeline?: mongodb.Document[];
22
+ }
23
+
13
24
  export const buildFindOrderPositionByIdSelector = (orderPositionId: string, orderId?: string) =>
14
25
  generateDbFilterById(
15
26
  orderPositionId,
@@ -25,10 +36,7 @@ export const configureOrderPositionsModule = ({
25
36
 
26
37
  return {
27
38
  // Queries
28
- findOrderPosition: async (
29
- { itemId }: { itemId: string },
30
- options?: mongodb.FindOptions,
31
- ): Promise<OrderPosition> => {
39
+ findOrderPosition: async ({ itemId }: { itemId: string }, options?: mongodb.FindOptions) => {
32
40
  return OrderPositions.findOne(buildFindOrderPositionByIdSelector(itemId), options);
33
41
  },
34
42
 
@@ -37,13 +45,13 @@ export const configureOrderPositionsModule = ({
37
45
  return positions.toArray();
38
46
  },
39
47
 
40
- delete: async (orderPositionId: string): Promise<OrderPosition> => {
48
+ delete: async (orderPositionId: string) => {
41
49
  const selector = buildFindOrderPositionByIdSelector(orderPositionId);
42
50
  const orderPosition = await OrderPositions.findOneAndDelete(selector, {});
43
51
  await emit('ORDER_REMOVE_CART_ITEM', {
44
52
  orderPosition,
45
53
  });
46
- return { ...orderPosition, calculation: [] };
54
+ return orderPosition;
47
55
  },
48
56
 
49
57
  removePositions: async ({ orderId }: { orderId: string }): Promise<number> => {
@@ -60,7 +68,7 @@ export const configureOrderPositionsModule = ({
60
68
  orderPositionId: string;
61
69
  configuration?: { key: string; value: string }[];
62
70
  quantity?: number;
63
- }): Promise<OrderPosition> => {
71
+ }) => {
64
72
  const modifier: any = {
65
73
  $set: {
66
74
  updated: new Date(),
@@ -85,6 +93,7 @@ export const configureOrderPositionsModule = ({
85
93
  },
86
94
  );
87
95
 
96
+ if (!updatedOrderPosition) return null;
88
97
  await emit('ORDER_UPDATE_CART_ITEM', {
89
98
  orderPosition: updatedOrderPosition,
90
99
  });
@@ -128,7 +137,7 @@ export const configureOrderPositionsModule = ({
128
137
  return orderIdsToRecalculate;
129
138
  },
130
139
 
131
- updateScheduling: async (orderPositionId, scheduling): Promise<OrderPosition> => {
140
+ updateScheduling: async (orderPositionId, scheduling) => {
132
141
  return OrderPositions.findOneAndUpdate(
133
142
  generateDbFilterById(orderPositionId),
134
143
  {
@@ -143,7 +152,7 @@ export const configureOrderPositionsModule = ({
143
152
  updateCalculation: async <T extends PricingCalculation>(
144
153
  orderPositionId: string,
145
154
  calculation: T[],
146
- ): Promise<OrderPosition> => {
155
+ ) => {
147
156
  return OrderPositions.findOneAndUpdate(
148
157
  { _id: orderPositionId },
149
158
  {
@@ -171,11 +180,11 @@ export const configureOrderPositionsModule = ({
171
180
  orderId,
172
181
  productId,
173
182
  originalProductId,
174
- configuration: configuration || { $in: [null, undefined] },
183
+ configuration: configuration || { $exists: false },
175
184
  ...scope,
176
185
  };
177
186
 
178
- await OrderPositions.updateOne(
187
+ const upsertedOrderPosition = (await OrderPositions.findOneAndUpdate(
179
188
  selector,
180
189
  {
181
190
  $set: {
@@ -194,19 +203,41 @@ export const configureOrderPositionsModule = ({
194
203
  ...scope,
195
204
  },
196
205
  },
197
- { upsert: true },
198
- );
199
-
200
- const upsertedOrderPosition = await OrderPositions.findOne(selector);
206
+ { upsert: true, returnDocument: 'after' },
207
+ )) as OrderPosition;
201
208
 
202
209
  await emit('ORDER_ADD_PRODUCT', { orderPosition: upsertedOrderPosition });
203
-
204
210
  return upsertedOrderPosition;
205
211
  },
206
212
  deleteOrderPositions: async (orderId: string) => {
207
213
  const { deletedCount } = await OrderPositions.deleteMany({ orderId });
208
214
  return deletedCount;
209
215
  },
216
+
217
+ aggregatePositions: async ({
218
+ match,
219
+ project,
220
+ group,
221
+ addFields,
222
+ sort,
223
+ limit,
224
+ pipeline,
225
+ }: OrderPositionAggregateParams): Promise<mongodb.Document[]> => {
226
+ const stages: mongodb.Document[] = [];
227
+
228
+ if (pipeline?.length) {
229
+ return await OrderPositions.aggregate(pipeline).toArray();
230
+ }
231
+
232
+ if (match) stages.push({ $match: match });
233
+ if (project) stages.push({ $project: project });
234
+ if (group) stages.push({ $group: group });
235
+ if (addFields) stages.push({ $addFields: addFields });
236
+ if (sort) stages.push({ $sort: sort });
237
+ if (typeof limit === 'number') stages.push({ $limit: limit });
238
+
239
+ return OrderPositions.aggregate(stages).toArray();
240
+ },
210
241
  };
211
242
  };
212
243
 
@@ -9,28 +9,6 @@ import {
9
9
  import { Order, OrderStatus } from '../db/OrdersCollection.js';
10
10
  import { OrderPosition } from '../db/OrderPositionsCollection.js';
11
11
 
12
- export interface OrderMutations {
13
- create: (doc: {
14
- userId: string;
15
- billingAddress?: Address;
16
- contact?: Contact;
17
- countryCode: string;
18
- currencyCode: string;
19
- orderNumber?: string;
20
- originEnrollmentId?: string;
21
- }) => Promise<Order>;
22
-
23
- delete: (orderId: string) => Promise<number>;
24
-
25
- setCartOwner: (params: { orderId: string; userId: string }) => Promise<void>;
26
- moveCartPositions: (params: { fromOrderId: string; toOrderId: string }) => Promise<void>;
27
-
28
- updateBillingAddress: (orderId: string, billingAddress: Address) => Promise<Order>;
29
- updateContact: (orderId: string, contact: Contact) => Promise<Order>;
30
- updateContext: (orderId: string, context: any) => Promise<Order>;
31
- updateCalculationSheet: (orderId: string, calculation) => Promise<Order>;
32
- }
33
-
34
12
  const ORDER_EVENTS: string[] = [
35
13
  'ORDER_CREATE',
36
14
  'ORDER_REMOVE',
@@ -45,11 +23,28 @@ export const configureOrderModuleMutations = ({
45
23
  }: {
46
24
  Orders: mongodb.Collection<Order>;
47
25
  OrderPositions: mongodb.Collection<OrderPosition>;
48
- }): OrderMutations => {
26
+ }) => {
49
27
  registerEvents(ORDER_EVENTS);
50
28
 
51
29
  return {
52
- create: async ({ userId, orderNumber, currencyCode, countryCode, billingAddress, contact }) => {
30
+ create: async ({
31
+ userId,
32
+ orderNumber,
33
+ currencyCode,
34
+ countryCode,
35
+ billingAddress,
36
+ contact,
37
+ context,
38
+ }: {
39
+ userId: string;
40
+ billingAddress?: Address;
41
+ contact?: Contact;
42
+ countryCode: string;
43
+ currencyCode: string;
44
+ orderNumber?: string;
45
+ originEnrollmentId?: string;
46
+ context?: Record<string, any>;
47
+ }) => {
53
48
  const { insertedId: orderId } = await Orders.insertOne({
54
49
  _id: generateDbObjectId(),
55
50
  created: new Date(),
@@ -62,21 +57,23 @@ export const configureOrderModuleMutations = ({
62
57
  calculation: [],
63
58
  log: [],
64
59
  orderNumber,
60
+ context: context || {},
65
61
  });
66
62
 
67
- const order = await Orders.findOne(generateDbFilterById(orderId), {});
63
+ const order = (await Orders.findOne(generateDbFilterById(orderId), {})) as Order;
68
64
 
69
65
  await emit('ORDER_CREATE', { order });
70
66
  return order;
71
67
  },
72
68
 
73
- delete: async (orderId) => {
69
+ delete: async (orderId: string) => {
74
70
  const { deletedCount } = await Orders.deleteOne({ _id: orderId });
71
+ if (!deletedCount) return 0;
75
72
  await emit('ORDER_REMOVE', { orderId });
76
73
  return deletedCount;
77
74
  },
78
75
 
79
- setCartOwner: async ({ orderId, userId }) => {
76
+ setCartOwner: async ({ orderId, userId }: { orderId: string; userId: string }) => {
80
77
  await Orders.updateOne(generateDbFilterById(orderId), {
81
78
  $set: {
82
79
  userId,
@@ -84,7 +81,13 @@ export const configureOrderModuleMutations = ({
84
81
  });
85
82
  },
86
83
 
87
- moveCartPositions: async ({ fromOrderId, toOrderId }) => {
84
+ moveCartPositions: async ({
85
+ fromOrderId,
86
+ toOrderId,
87
+ }: {
88
+ fromOrderId: string;
89
+ toOrderId: string;
90
+ }) => {
88
91
  await OrderPositions.updateMany(
89
92
  { orderId: fromOrderId },
90
93
  {
@@ -95,7 +98,7 @@ export const configureOrderModuleMutations = ({
95
98
  );
96
99
  },
97
100
 
98
- updateBillingAddress: async (orderId, billingAddress) => {
101
+ updateBillingAddress: async (orderId: string, billingAddress: Address) => {
99
102
  const selector = generateDbFilterById(orderId);
100
103
  const order = await Orders.findOneAndUpdate(
101
104
  selector,
@@ -107,12 +110,12 @@ export const configureOrderModuleMutations = ({
107
110
  },
108
111
  { returnDocument: 'after' },
109
112
  );
110
-
111
- await emit('ORDER_UPDATE', { order, field: 'billing' });
113
+ if (!order) return null;
114
+ await emit('ORDER_UPDATE', { order, field: 'billingAddress' });
112
115
  return order;
113
116
  },
114
117
 
115
- updateContact: async (orderId, contact) => {
118
+ updateContact: async (orderId: string, contact: Contact) => {
116
119
  const selector = generateDbFilterById(orderId);
117
120
  const order = await Orders.findOneAndUpdate(
118
121
  selector,
@@ -124,12 +127,12 @@ export const configureOrderModuleMutations = ({
124
127
  },
125
128
  { returnDocument: 'after' },
126
129
  );
127
-
130
+ if (!order) return null;
128
131
  await emit('ORDER_UPDATE', { order, field: 'contact' });
129
132
  return order;
130
133
  },
131
134
 
132
- updateCalculationSheet: async (orderId, calculation) => {
135
+ updateCalculationSheet: async (orderId: string, calculation: any) => {
133
136
  const selector = generateDbFilterById(orderId);
134
137
  const order = await Orders.findOneAndUpdate(
135
138
  selector,
@@ -141,12 +144,12 @@ export const configureOrderModuleMutations = ({
141
144
  },
142
145
  { returnDocument: 'after' },
143
146
  );
144
-
147
+ if (!order) return null;
145
148
  await emit('ORDER_UPDATE', { order, field: 'calculation' });
146
149
  return order;
147
150
  },
148
151
 
149
- updateContext: async (orderId, context) => {
152
+ updateContext: async (orderId: string, context: any) => {
150
153
  const selector = generateDbFilterById<Order>(orderId);
151
154
  selector.status = { $in: [null, OrderStatus.PENDING] };
152
155
 
@@ -155,7 +158,7 @@ export const configureOrderModuleMutations = ({
155
158
  const contextSetters = Object.fromEntries(
156
159
  Object.entries(context).map(([key, value]) => [`context.${key}`, value]),
157
160
  );
158
- const result = await Orders.findOneAndUpdate(
161
+ const order = await Orders.findOneAndUpdate(
159
162
  selector,
160
163
  {
161
164
  $set: {
@@ -163,14 +166,13 @@ export const configureOrderModuleMutations = ({
163
166
  updated: new Date(),
164
167
  },
165
168
  },
166
- { includeResultMetadata: true, returnDocument: 'after' },
169
+ { returnDocument: 'after' },
167
170
  );
168
-
169
- if (result.ok) {
170
- await emit('ORDER_UPDATE', { order: result.value, field: 'context' });
171
- return result.value;
172
- }
173
- return null;
171
+ if (!order) return null;
172
+ await emit('ORDER_UPDATE', { order, field: 'context' });
173
+ return order;
174
174
  },
175
175
  };
176
176
  };
177
+
178
+ export type OrderMutations = ReturnType<typeof configureOrderModuleMutations>;
@@ -1,4 +1,4 @@
1
- import { SortDirection, SortOption, DateFilterInput } from '@unchainedshop/utils';
1
+ import { SortDirection, SortOption } from '@unchainedshop/utils';
2
2
  import { generateDbFilterById, buildSortOptions, mongodb } from '@unchainedshop/mongodb';
3
3
  import buildFindSelector from './buildFindSelector.js';
4
4
  import { Order, OrderQuery } from '../db/OrdersCollection.js';
@@ -10,21 +10,23 @@ export interface OrderReport {
10
10
  confirmCount: number;
11
11
  fulfillCount: number;
12
12
  }
13
-
14
- const normalizeOrderAggregateResult = (data = {}): OrderReport => {
15
- const statusToFieldMap = {
16
- newCount: 0,
17
- checkoutCount: 0,
18
- rejectCount: 0,
19
- confirmCount: 0,
20
- fulfillCount: 0,
13
+ export interface OrderStatisticsRecord {
14
+ date: string;
15
+ total: {
16
+ amount: number;
17
+ currency: string;
21
18
  };
22
-
23
- Object.entries(data).forEach(([key, value]) => {
24
- statusToFieldMap[key] = value;
25
- });
26
- return statusToFieldMap;
27
- };
19
+ }
20
+ export interface OrderAggregateParams {
21
+ match?: Record<string, any>;
22
+ matchAfterGroup?: Record<string, any>;
23
+ project?: Record<string, any>;
24
+ group?: Record<string, any>;
25
+ sort?: Record<string, number>;
26
+ limit?: number;
27
+ addFields?: Record<string, any>;
28
+ pipeline?: any[];
29
+ }
28
30
 
29
31
  export const configureOrdersModuleQueries = ({ Orders }: { Orders: mongodb.Collection<Order> }) => {
30
32
  return {
@@ -40,7 +42,7 @@ export const configureOrdersModuleQueries = ({ Orders }: { Orders: mongodb.Colle
40
42
  countryCode?: string;
41
43
  orderNumber?: string;
42
44
  userId: string;
43
- }): Promise<Order> => {
45
+ }) => {
44
46
  const selector: mongodb.Filter<Order> = {
45
47
  countryCode,
46
48
  status: { $eq: null },
@@ -72,7 +74,7 @@ export const configureOrdersModuleQueries = ({ Orders }: { Orders: mongodb.Colle
72
74
  orderNumber?: string;
73
75
  },
74
76
  options?: mongodb.FindOptions,
75
- ): Promise<Order> => {
77
+ ) => {
76
78
  const selector = orderId ? generateDbFilterById(orderId) : { orderNumber };
77
79
  return Orders.findOne(selector, options);
78
80
  },
@@ -122,86 +124,35 @@ export const configureOrdersModuleQueries = ({ Orders }: { Orders: mongodb.Colle
122
124
 
123
125
  return Orders.find(selector, findOptions).toArray();
124
126
  },
125
-
126
- getReport: async (params: { dateRange?: DateFilterInput }): Promise<OrderReport> => {
127
- const { dateRange } = params || {};
128
- const selector: any = { $exists: true };
129
- if (dateRange?.end || dateRange?.start) {
130
- if (dateRange?.start) {
131
- const fromDate = new Date(dateRange?.start);
132
- selector.$gte = fromDate;
133
- }
134
- if (dateRange?.end) {
135
- const toDate = new Date(dateRange?.end);
136
- selector.$lte = toDate;
137
- }
138
- }
139
-
140
- const pipeline = [
141
- {
142
- $facet: {
143
- checkoutCount: [
144
- {
145
- $match: {
146
- ordered: selector,
147
- },
148
- },
149
- { $count: 'count' },
150
- ],
151
- fulfillCount: [
152
- {
153
- $match: {
154
- fullfilled: selector,
155
- },
156
- },
157
- { $count: 'count' },
158
- ],
159
- rejectCount: [
160
- {
161
- $match: {
162
- rejected: selector,
163
- },
164
- },
165
- { $count: 'count' },
166
- ],
167
- newCount: [
168
- {
169
- $match: {
170
- created: selector,
171
- },
172
- },
173
- { $count: 'count' },
174
- ],
175
- confirmCount: [
176
- {
177
- $match: {
178
- confirmed: selector,
179
- },
180
- },
181
- { $count: 'count' },
182
- ],
183
- },
184
- },
185
- {
186
- $project: {
187
- checkoutCount: { $arrayElemAt: ['$checkoutCount.count', 0] },
188
- fulfillCount: { $arrayElemAt: ['$fulfillCount.count', 0] },
189
- rejectCount: { $arrayElemAt: ['$rejectCount.count', 0] },
190
- newCount: { $arrayElemAt: ['$newCount.count', 0] },
191
- confirmCount: { $arrayElemAt: ['$confirmCount.count', 0] },
192
- },
193
- },
194
- ];
195
- const [facetedResult] = await Orders.aggregate(pipeline).toArray();
196
- return normalizeOrderAggregateResult(facetedResult);
197
- },
198
-
199
127
  orderExists: async ({ orderId }: { orderId: string }): Promise<boolean> => {
200
128
  const orderCount = await Orders.countDocuments(generateDbFilterById(orderId), {
201
129
  limit: 1,
202
130
  });
203
131
  return !!orderCount;
204
132
  },
133
+ aggregateOrders: async ({
134
+ match,
135
+ project,
136
+ group,
137
+ sort,
138
+ limit,
139
+ addFields,
140
+ pipeline,
141
+ }: OrderAggregateParams): Promise<mongodb.Document[]> => {
142
+ const stages: mongodb.Document[] = [];
143
+ if (pipeline?.length) {
144
+ return await Orders.aggregate(pipeline).toArray();
145
+ }
146
+
147
+ if (match) stages.push({ $match: match });
148
+ if (project) stages.push({ $project: project });
149
+ if (group) stages.push({ $group: group });
150
+ if (addFields) stages.push({ $addFields: addFields });
151
+ if (sort) stages.push({ $sort: sort });
152
+ if (typeof limit === 'number') stages.push({ $limit: limit });
153
+
154
+ return Orders.aggregate(stages, { allowDiskUse: true }).toArray();
155
+ },
205
156
  };
206
157
  };
207
158
 
@@ -6,37 +6,16 @@ import { OrderPaymentsCollection } from '../db/OrderPaymentsCollection.js';
6
6
  import { OrderPositionsCollection } from '../db/OrderPositionsCollection.js';
7
7
  import { OrdersCollection, Order, OrderStatus } from '../db/OrdersCollection.js';
8
8
  import { ordersSettings, OrdersSettingsOptions } from '../orders-settings.js';
9
- import {
10
- configureOrderDeliveriesModule,
11
- OrderDeliveriesModule,
12
- } from './configureOrderDeliveriesModule.js';
13
- import { configureOrderDiscountsModule, OrderDiscountsModule } from './configureOrderDiscountsModule.js';
14
- import { configureOrderPaymentsModule, OrderPaymentsModule } from './configureOrderPaymentsModule.js';
15
- import { configureOrderPositionsModule, OrderPositionsModule } from './configureOrderPositionsModule.js';
16
- import { configureOrderModuleMutations, OrderMutations } from './configureOrdersModule-mutations.js';
17
- import { configureOrdersModuleQueries, OrderQueries } from './configureOrdersModule-queries.js';
9
+ import { configureOrderDeliveriesModule } from './configureOrderDeliveriesModule.js';
10
+ import { configureOrderDiscountsModule } from './configureOrderDiscountsModule.js';
11
+ import { configureOrderPaymentsModule } from './configureOrderPaymentsModule.js';
12
+ import { configureOrderPositionsModule } from './configureOrderPositionsModule.js';
13
+ import { configureOrderModuleMutations } from './configureOrdersModule-mutations.js';
14
+ import { configureOrdersModuleQueries } from './configureOrdersModule-queries.js';
18
15
  import { emit, registerEvents } from '@unchainedshop/events';
19
16
 
20
17
  import renameCurrencyCode from '../migrations/20250502111800-currency-code.js';
21
18
 
22
- export type OrdersModule = OrderQueries &
23
- OrderMutations & {
24
- // Sub entities
25
- deliveries: OrderDeliveriesModule;
26
- discounts: OrderDiscountsModule;
27
- positions: OrderPositionsModule;
28
- payments: OrderPaymentsModule;
29
-
30
- updateStatus: (orderId: string, params: { status: OrderStatus; info?: string }) => Promise<Order>;
31
- acquireLock: (
32
- orderId: string,
33
- identifier: string,
34
- timeout?: number,
35
- ) => Promise<{ release: () => void }>;
36
- setDeliveryProvider: (orderId: string, deliveryProviderId: string) => Promise<Order>;
37
- setPaymentProvider: (orderId: string, paymentProviderId: string) => Promise<Order>;
38
- };
39
-
40
19
  // @kontsedal/locco uses a deprecated way of importing files in ESM (node16 behavior)
41
20
  const require = createRequire(import.meta.url);
42
21
  const { Locker, MongoAdapter } = require('@kontsedal/locco');
@@ -52,7 +31,7 @@ export const configureOrdersModule = async ({
52
31
  db,
53
32
  migrationRepository,
54
33
  options: orderOptions = {},
55
- }: ModuleInput<OrdersSettingsOptions>): Promise<OrdersModule> => {
34
+ }: ModuleInput<OrdersSettingsOptions>) => {
56
35
  // Migration v3 -> v4
57
36
  renameCurrencyCode(migrationRepository);
58
37
 
@@ -117,10 +96,14 @@ export const configureOrdersModule = async ({
117
96
  positions: orderPositionsModule,
118
97
  payments: orderPaymentsModule,
119
98
 
120
- updateStatus: async (orderId, { status, info }) => {
99
+ updateStatus: async (
100
+ orderId: string,
101
+ { status, info }: { status: OrderStatus | null; info?: string },
102
+ ) => {
121
103
  const selector = generateDbFilterById(orderId);
122
104
  const order = await Orders.findOne(selector, {});
123
105
 
106
+ if (!order) return null;
124
107
  if (order.status === status) return order;
125
108
 
126
109
  const date = new Date();
@@ -197,7 +180,7 @@ export const configureOrdersModule = async ({
197
180
  return await locker.lock(`order:${identifier}:${orderId}`, timeout).acquire();
198
181
  },
199
182
 
200
- setDeliveryProvider: async (orderId, deliveryProviderId) => {
183
+ setDeliveryProvider: async (orderId: string, deliveryProviderId: string) => {
201
184
  const delivery = await OrderDeliveries.findOne({
202
185
  orderId,
203
186
  deliveryProviderId,
@@ -215,7 +198,7 @@ export const configureOrdersModule = async ({
215
198
  )._id;
216
199
 
217
200
  const order = await Orders.findOneAndUpdate(
218
- { _id: orderId },
201
+ { _id: orderId, deliveryId: { $ne: deliveryId } },
219
202
  {
220
203
  $set: {
221
204
  deliveryId,
@@ -225,6 +208,7 @@ export const configureOrdersModule = async ({
225
208
  { returnDocument: 'after' },
226
209
  );
227
210
 
211
+ if (!order) return null;
228
212
  await emit('ORDER_SET_DELIVERY_PROVIDER', {
229
213
  order,
230
214
  deliveryProviderId,
@@ -233,7 +217,7 @@ export const configureOrdersModule = async ({
233
217
  return order;
234
218
  },
235
219
 
236
- setPaymentProvider: async (orderId, paymentProviderId) => {
220
+ setPaymentProvider: async (orderId: string, paymentProviderId: string) => {
237
221
  const payment = await OrderPayments.findOne({
238
222
  orderId,
239
223
  paymentProviderId,
@@ -250,14 +234,16 @@ export const configureOrdersModule = async ({
250
234
  status: null,
251
235
  })
252
236
  )._id;
237
+
253
238
  const order = await Orders.findOneAndUpdate(
254
- { _id: orderId },
239
+ { _id: orderId, paymentId: { $ne: paymentId } },
255
240
  {
256
241
  $set: { paymentId, updated: new Date() },
257
242
  },
258
243
  { returnDocument: 'after' },
259
244
  );
260
245
 
246
+ if (!order) return null;
261
247
  await emit('ORDER_SET_PAYMENT_PROVIDER', {
262
248
  order,
263
249
  paymentProviderId,
@@ -267,3 +253,5 @@ export const configureOrdersModule = async ({
267
253
  },
268
254
  };
269
255
  };
256
+
257
+ export type OrdersModule = Awaited<ReturnType<typeof configureOrdersModule>>;
@@ -8,15 +8,17 @@ export interface OrderSettingsOrderPositionValidation<Product = unknown> {
8
8
  configuration?: { key: string; value: string }[];
9
9
  }
10
10
 
11
- export interface OrdersSettingsOptions {
12
- ensureUserHasCart?: boolean;
13
- orderNumberHashFn?: (order: Order, index: number) => string;
14
- validateOrderPosition?: <UnchainedAPI = unknown>(
11
+ export interface OrdersSettings {
12
+ ensureUserHasCart: boolean;
13
+ orderNumberHashFn: (order: Order, index: number) => string;
14
+ validateOrderPosition: <UnchainedAPI = unknown>(
15
15
  validationParams: OrderSettingsOrderPositionValidation,
16
16
  unchainedAPI: UnchainedAPI,
17
17
  ) => Promise<void>;
18
- lockOrderDuringCheckout?: boolean;
18
+ lockOrderDuringCheckout: boolean;
19
+ configureSettings: (options?: OrdersSettingsOptions) => void;
19
20
  }
21
+ export type OrdersSettingsOptions = Omit<Partial<OrdersSettings>, 'configureSettings'>;
20
22
 
21
23
  export const defaultValidateOrderPosition = async ({ product }, { modules }: any) => {
22
24
  if (!modules.products.isActive(product)) {
@@ -24,21 +26,20 @@ export const defaultValidateOrderPosition = async ({ product }, { modules }: any
24
26
  }
25
27
  };
26
28
 
27
- export const ordersSettings = {
28
- ensureUserHasCart: null,
29
- orderNumberHashFn: null,
30
- validateOrderPosition: null,
29
+ export const ordersSettings: OrdersSettings = {
30
+ ensureUserHasCart: false,
31
+ orderNumberHashFn: generateRandomHash,
32
+ validateOrderPosition: defaultValidateOrderPosition,
31
33
  lockOrderDuringCheckout: false,
32
-
33
34
  configureSettings({
34
- ensureUserHasCart = false,
35
- orderNumberHashFn = generateRandomHash,
36
- validateOrderPosition = defaultValidateOrderPosition,
37
- lockOrderDuringCheckout = false,
38
- }: OrdersSettingsOptions = {}) {
39
- this.ensureUserHasCart = ensureUserHasCart;
40
- this.orderNumberHashFn = orderNumberHashFn;
41
- this.validateOrderPosition = validateOrderPosition;
42
- this.lockOrderDuringCheckout = lockOrderDuringCheckout;
35
+ ensureUserHasCart,
36
+ orderNumberHashFn,
37
+ validateOrderPosition,
38
+ lockOrderDuringCheckout,
39
+ } = {}) {
40
+ this.ensureUserHasCart = ensureUserHasCart || false;
41
+ this.orderNumberHashFn = orderNumberHashFn || generateRandomHash;
42
+ this.validateOrderPosition = validateOrderPosition || defaultValidateOrderPosition;
43
+ this.lockOrderDuringCheckout = lockOrderDuringCheckout || false;
43
44
  },
44
45
  };