@unchainedshop/core-orders 1.1.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 (137) hide show
  1. package/.npm/package/README +7 -0
  2. package/.npm/package/npm-shrinkwrap.json +190 -0
  3. package/.versions +54 -0
  4. package/README.md +5 -0
  5. package/lib/db/OrderDeliveriesCollection.d.ts +3 -0
  6. package/lib/db/OrderDeliveriesCollection.js +8 -0
  7. package/lib/db/OrderDeliveriesCollection.js.map +1 -0
  8. package/lib/db/OrderDeliveriesSchema.d.ts +1 -0
  9. package/lib/db/OrderDeliveriesSchema.js +20 -0
  10. package/lib/db/OrderDeliveriesSchema.js.map +1 -0
  11. package/lib/db/OrderDiscountTrigger.d.ts +4 -0
  12. package/lib/db/OrderDiscountTrigger.js +6 -0
  13. package/lib/db/OrderDiscountTrigger.js.map +1 -0
  14. package/lib/db/OrderDiscountsCollection.d.ts +3 -0
  15. package/lib/db/OrderDiscountsCollection.js +11 -0
  16. package/lib/db/OrderDiscountsCollection.js.map +1 -0
  17. package/lib/db/OrderDiscountsSchema.d.ts +1 -0
  18. package/lib/db/OrderDiscountsSchema.js +12 -0
  19. package/lib/db/OrderDiscountsSchema.js.map +1 -0
  20. package/lib/db/OrderPaymentsCollection.d.ts +3 -0
  21. package/lib/db/OrderPaymentsCollection.js +8 -0
  22. package/lib/db/OrderPaymentsCollection.js.map +1 -0
  23. package/lib/db/OrderPaymentsSchema.d.ts +1 -0
  24. package/lib/db/OrderPaymentsSchema.js +20 -0
  25. package/lib/db/OrderPaymentsSchema.js.map +1 -0
  26. package/lib/db/OrderPositionsCollection.d.ts +3 -0
  27. package/lib/db/OrderPositionsCollection.js +11 -0
  28. package/lib/db/OrderPositionsCollection.js.map +1 -0
  29. package/lib/db/OrderPositionsSchema.d.ts +1 -0
  30. package/lib/db/OrderPositionsSchema.js +37 -0
  31. package/lib/db/OrderPositionsSchema.js.map +1 -0
  32. package/lib/db/OrdersCollection.d.ts +3 -0
  33. package/lib/db/OrdersCollection.js +33 -0
  34. package/lib/db/OrdersCollection.js.map +1 -0
  35. package/lib/db/OrdersSchema.d.ts +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 +2 -0
  39. package/lib/director/OrderDiscountAdapter.js +3 -0
  40. package/lib/director/OrderDiscountAdapter.js.map +1 -0
  41. package/lib/director/OrderDiscountDirector.d.ts +2 -0
  42. package/lib/director/OrderDiscountDirector.js +3 -0
  43. package/lib/director/OrderDiscountDirector.js.map +1 -0
  44. package/lib/director/OrderPricingAdapter.d.ts +3 -0
  45. package/lib/director/OrderPricingAdapter.js +25 -0
  46. package/lib/director/OrderPricingAdapter.js.map +1 -0
  47. package/lib/director/OrderPricingDirector.d.ts +2 -0
  48. package/lib/director/OrderPricingDirector.js +48 -0
  49. package/lib/director/OrderPricingDirector.js.map +1 -0
  50. package/lib/director/OrderPricingSheet.d.ts +3 -0
  51. package/lib/director/OrderPricingSheet.js +113 -0
  52. package/lib/director/OrderPricingSheet.js.map +1 -0
  53. package/lib/module/configureOrderDeliveriesModule.d.ts +7 -0
  54. package/lib/module/configureOrderDeliveriesModule.js +164 -0
  55. package/lib/module/configureOrderDeliveriesModule.js.map +1 -0
  56. package/lib/module/configureOrderDiscountsModule.d.ts +7 -0
  57. package/lib/module/configureOrderDiscountsModule.js +183 -0
  58. package/lib/module/configureOrderDiscountsModule.js.map +1 -0
  59. package/lib/module/configureOrderPaymentsModule.d.ts +7 -0
  60. package/lib/module/configureOrderPaymentsModule.js +229 -0
  61. package/lib/module/configureOrderPaymentsModule.js.map +1 -0
  62. package/lib/module/configureOrderPositionsModule.d.ts +7 -0
  63. package/lib/module/configureOrderPositionsModule.js +213 -0
  64. package/lib/module/configureOrderPositionsModule.js.map +1 -0
  65. package/lib/module/configureOrdersModule-mutations.d.ts +12 -0
  66. package/lib/module/configureOrdersModule-mutations.js +162 -0
  67. package/lib/module/configureOrdersModule-mutations.js.map +1 -0
  68. package/lib/module/configureOrdersModule-processing.d.ts +13 -0
  69. package/lib/module/configureOrdersModule-processing.js +343 -0
  70. package/lib/module/configureOrdersModule-processing.js.map +1 -0
  71. package/lib/module/configureOrdersModule-queries.d.ts +5 -0
  72. package/lib/module/configureOrdersModule-queries.js +55 -0
  73. package/lib/module/configureOrdersModule-queries.js.map +1 -0
  74. package/lib/module/configureOrdersModule-transformations.d.ts +5 -0
  75. package/lib/module/configureOrdersModule-transformations.js +108 -0
  76. package/lib/module/configureOrdersModule-transformations.js.map +1 -0
  77. package/lib/module/configureOrdersModule.d.ts +3 -0
  78. package/lib/module/configureOrdersModule.js +239 -0
  79. package/lib/module/configureOrdersModule.js.map +1 -0
  80. package/lib/orders-index.d.ts +11 -0
  81. package/lib/orders-index.js +12 -0
  82. package/lib/orders-index.js.map +1 -0
  83. package/lib/orders-settings.d.ts +20 -0
  84. package/lib/orders-settings.js +17 -0
  85. package/lib/orders-settings.js.map +1 -0
  86. package/lib/service/createUserCartService.d.ts +2 -0
  87. package/lib/service/createUserCartService.js +23 -0
  88. package/lib/service/createUserCartService.js.map +1 -0
  89. package/lib/service/migrateOrderCartService.d.ts +2 -0
  90. package/lib/service/migrateOrderCartService.js +10 -0
  91. package/lib/service/migrateOrderCartService.js.map +1 -0
  92. package/lib/service/orderServices.d.ts +2 -0
  93. package/lib/service/orderServices.js +7 -0
  94. package/lib/service/orderServices.js.map +1 -0
  95. package/package.js +33 -0
  96. package/package.json +43 -0
  97. package/plugins/discount-100-off.ts +44 -0
  98. package/plugins/discount-half-price-manual.ts +43 -0
  99. package/plugins/discount-half-price.ts +46 -0
  100. package/plugins/order-delivery.ts +45 -0
  101. package/plugins/order-discount.ts +158 -0
  102. package/plugins/order-items-discount.ts +116 -0
  103. package/plugins/order-items.ts +61 -0
  104. package/plugins/order-payment.ts +46 -0
  105. package/src/db/OrderDeliveriesCollection.ts +12 -0
  106. package/src/db/OrderDeliveriesSchema.js +24 -0
  107. package/src/db/OrderDiscountTrigger.ts +4 -0
  108. package/src/db/OrderDiscountsCollection.ts +15 -0
  109. package/src/db/OrderDiscountsSchema.js +15 -0
  110. package/src/db/OrderPaymentsCollection.ts +12 -0
  111. package/src/db/OrderPaymentsSchema.js +24 -0
  112. package/src/db/OrderPositionsCollection.ts +15 -0
  113. package/src/db/OrderPositionsSchema.js +41 -0
  114. package/src/db/OrdersCollection.ts +37 -0
  115. package/src/db/OrdersSchema.js +34 -0
  116. package/src/director/OrderDiscountAdapter.ts +5 -0
  117. package/src/director/OrderDiscountDirector.ts +4 -0
  118. package/src/director/OrderPricingAdapter.ts +41 -0
  119. package/src/director/OrderPricingDirector.ts +68 -0
  120. package/src/director/OrderPricingSheet.ts +138 -0
  121. package/src/module/configureOrderDeliveriesModule.ts +240 -0
  122. package/src/module/configureOrderDiscountsModule.ts +245 -0
  123. package/src/module/configureOrderPaymentsModule.ts +331 -0
  124. package/src/module/configureOrderPositionsModule.ts +329 -0
  125. package/src/module/configureOrdersModule-mutations.ts +230 -0
  126. package/src/module/configureOrdersModule-processing.ts +506 -0
  127. package/src/module/configureOrdersModule-queries.ts +71 -0
  128. package/src/module/configureOrdersModule-transformations.ts +145 -0
  129. package/src/module/configureOrdersModule.ts +359 -0
  130. package/src/orders-index.ts +15 -0
  131. package/src/orders-settings.ts +23 -0
  132. package/src/service/createUserCartService.ts +38 -0
  133. package/src/service/migrateOrderCartService.ts +22 -0
  134. package/src/service/orderServices.ts +8 -0
  135. package/tests/orders-index.test.ts +50 -0
  136. package/tsconfig.build.json +26 -0
  137. package/tsconfig.json +8 -0
@@ -0,0 +1,145 @@
1
+ import { Collection, FindOptions, Query } from '@unchainedshop/types/common';
2
+ import { Order, OrderTransformations } from '@unchainedshop/types/orders';
3
+ import { OrderPricingSheet } from '../director/OrderPricingSheet';
4
+
5
+ export const configureOrderModuleTransformations = ({
6
+ Orders,
7
+ }: {
8
+ Orders: Collection<Order>;
9
+ }): OrderTransformations => {
10
+ return {
11
+ discounted: async (order, orderDiscount, requestContext) => {
12
+ const { modules } = requestContext;
13
+
14
+ // Delivery discounts
15
+ const orderDelivery = await modules.orders.deliveries.findDelivery({
16
+ orderDeliveryId: order.deliveryId,
17
+ });
18
+ const orderDeliveryDiscounts = modules.orders.deliveries.discounts(
19
+ orderDelivery,
20
+ { order, orderDiscount },
21
+ requestContext,
22
+ );
23
+
24
+ // Payment discounts
25
+ const orderPayment = await modules.orders.payments.findOrderPayment({
26
+ orderPaymentId: order.paymentId,
27
+ });
28
+ const orderPaymentDiscounts = modules.orders.payments.discounts(
29
+ orderPayment,
30
+ { order, orderDiscount },
31
+ requestContext,
32
+ );
33
+
34
+ // Position discounts
35
+ const orderPositions = await modules.orders.positions.findOrderPositions({
36
+ orderId: order._id,
37
+ });
38
+ const orderPositionDiscounts = orderPositions.flatMap((orderPosition) =>
39
+ modules.orders.positions.discounts(orderPosition, { order, orderDiscount }, requestContext),
40
+ );
41
+
42
+ // order discounts
43
+ const pricingSheet = OrderPricingSheet({
44
+ calculation: order.calculation,
45
+ currency: order.currency,
46
+ });
47
+
48
+ const orderDiscounts = pricingSheet
49
+ .discountPrices(orderDiscount._id)
50
+ .map((discount) => ({ order, ...discount }));
51
+
52
+ // All discounts
53
+ const discounted = [
54
+ ...orderPaymentDiscounts,
55
+ ...orderDeliveryDiscounts,
56
+ ...orderPositionDiscounts,
57
+ ...orderDiscounts,
58
+ ].filter(Boolean);
59
+
60
+ return discounted;
61
+ },
62
+
63
+ discountTotal: async (order, orderDiscount, requestContext) => {
64
+ const { modules } = requestContext;
65
+ const orderDiscountId = orderDiscount._id;
66
+
67
+ // Delivery discounts
68
+ const orderDelivery = await modules.orders.deliveries.findDelivery({
69
+ orderDeliveryId: order.deliveryId,
70
+ });
71
+ const orderDeliveryDiscountSum =
72
+ orderDelivery &&
73
+ modules.orders.deliveries
74
+ .pricingSheet(orderDelivery, order.currency, requestContext)
75
+ .discountSum(orderDiscountId);
76
+
77
+ // Payment discounts
78
+ const orderPayment = await modules.orders.payments.findOrderPayment({
79
+ orderPaymentId: order.paymentId,
80
+ });
81
+ const orderPaymentDiscountSum =
82
+ orderPayment &&
83
+ modules.orders.payments
84
+ .pricingSheet(orderPayment, order.currency, requestContext)
85
+ .discountSum(orderDiscountId);
86
+
87
+ // Position discounts
88
+ const orderPositions = await modules.orders.positions.findOrderPositions({
89
+ orderId: order._id,
90
+ });
91
+ const orderPositionDiscounts = orderPositions.map((orderPosition) =>
92
+ modules.orders.positions
93
+ .pricingSheet(orderPosition, order.currency, requestContext)
94
+ .discountSum(orderDiscountId),
95
+ );
96
+
97
+ // order discounts
98
+ const orderDiscountSum = OrderPricingSheet({
99
+ calculation: order.calculation,
100
+ currency: order.currency,
101
+ }).discountSum(orderDiscountId);
102
+
103
+ const prices = [
104
+ orderDeliveryDiscountSum,
105
+ orderPaymentDiscountSum,
106
+ ...orderPositionDiscounts,
107
+ orderDiscountSum,
108
+ ];
109
+ const amount = prices.reduce((oldValue, price) => oldValue + (price || 0), 0);
110
+ return {
111
+ amount,
112
+ currency: order.currency,
113
+ };
114
+ },
115
+
116
+ isCart: (order) => {
117
+ return order.status === null;
118
+ },
119
+ cart: async ({ orderNumber, countryContext }, user) => {
120
+ const selector: Query = {
121
+ countryCode: countryContext || user.lastLogin.countryContext,
122
+ status: { $eq: null },
123
+ userId: user._id,
124
+ };
125
+
126
+ if (orderNumber) {
127
+ selector.orderNumber = orderNumber;
128
+ }
129
+
130
+ const options: FindOptions = {
131
+ sort: {
132
+ updated: -1,
133
+ },
134
+ };
135
+ return Orders.findOne(selector, options);
136
+ },
137
+
138
+ pricingSheet: (order) => {
139
+ return OrderPricingSheet({
140
+ calculation: order.calculation,
141
+ currency: order.currency,
142
+ });
143
+ },
144
+ };
145
+ };
@@ -0,0 +1,359 @@
1
+ import { Context } from '@unchainedshop/types/api';
2
+ import { ModuleInput, Update } from '@unchainedshop/types/common';
3
+ import { Order, OrderStatus, OrdersModule, OrdersSettingsOptions } from '@unchainedshop/types/orders';
4
+ import { OrderDelivery } from '@unchainedshop/types/orders.deliveries';
5
+ import { OrderPayment } from '@unchainedshop/types/orders.payments';
6
+ import { OrderPosition } from '@unchainedshop/types/orders.positions';
7
+ import { log } from '@unchainedshop/logger';
8
+ import { generateDbFilterById } from '@unchainedshop/utils';
9
+ import { OrderDeliveriesCollection } from '../db/OrderDeliveriesCollection';
10
+ import { OrderDiscountsCollection } from '../db/OrderDiscountsCollection';
11
+ import { OrderDiscountTrigger } from '../db/OrderDiscountTrigger';
12
+ import { OrderPaymentsCollection } from '../db/OrderPaymentsCollection';
13
+ import { OrderPositionsCollection } from '../db/OrderPositionsCollection';
14
+ import { OrdersCollection } from '../db/OrdersCollection';
15
+ import { OrderDiscountDirector } from '../director/OrderDiscountDirector';
16
+ import { OrderPricingDirector } from '../director/OrderPricingDirector';
17
+ import { ordersSettings } from '../orders-settings';
18
+ import { configureOrderDeliveriesModule } from './configureOrderDeliveriesModule';
19
+ import { configureOrderDiscountsModule } from './configureOrderDiscountsModule';
20
+ import { configureOrderPaymentsModule } from './configureOrderPaymentsModule';
21
+ import { configureOrderPositionsModule } from './configureOrderPositionsModule';
22
+ import { configureOrderModuleMutations } from './configureOrdersModule-mutations';
23
+ import { configureOrderModuleProcessing } from './configureOrdersModule-processing';
24
+ import { configureOrdersModuleQueries } from './configureOrdersModule-queries';
25
+ import { configureOrderModuleTransformations } from './configureOrdersModule-transformations';
26
+
27
+ export const configureOrdersModule = async ({
28
+ db,
29
+ options: orderOptions = {},
30
+ }: ModuleInput<OrdersSettingsOptions>): Promise<OrdersModule> => {
31
+ ordersSettings.configureSettings(orderOptions);
32
+
33
+ const Orders = await OrdersCollection(db);
34
+ const OrderDeliveries = await OrderDeliveriesCollection(db);
35
+ const OrderDiscounts = await OrderDiscountsCollection(db);
36
+ const OrderPayments = await OrderPaymentsCollection(db);
37
+ const OrderPositions = await OrderPositionsCollection(db);
38
+
39
+ const findOrderPositions = async (order: Order) =>
40
+ OrderPositions.find(
41
+ {
42
+ orderId: order._id,
43
+ quantity: { $gt: 0 },
44
+ },
45
+ {},
46
+ ).toArray();
47
+
48
+ const findOrderDelivery = async (order: Order) =>
49
+ OrderDeliveries.findOne(generateDbFilterById(order.deliveryId), {});
50
+
51
+ const findOrderPayment = async (order: Order) =>
52
+ OrderPayments.findOne(generateDbFilterById(order.paymentId), {});
53
+
54
+ const findNewOrderNumber = async (order: Order, index = 0) => {
55
+ const newHashID = ordersSettings.orderNumberHashFn(order, index);
56
+ if ((await Orders.countDocuments({ orderNumber: newHashID }, { limit: 1 })) === 0) {
57
+ return newHashID;
58
+ }
59
+ return findNewOrderNumber(order, index + 1);
60
+ };
61
+
62
+ const updateStatus: OrdersModule['updateStatus'] = async (
63
+ orderId,
64
+ { status, info },
65
+ requestContext,
66
+ ) => {
67
+ const selector = generateDbFilterById(orderId);
68
+ const order = await Orders.findOne(selector, {});
69
+
70
+ if (order.status === status) return order;
71
+
72
+ const date = new Date();
73
+ const $set: Partial<Order> = {
74
+ status,
75
+ updated: new Date(),
76
+ updatedBy: requestContext.userId,
77
+ };
78
+
79
+ switch (status) {
80
+ // explicitly use fallthrough here!
81
+ case OrderStatus.FULLFILLED:
82
+ if (!order.fullfilled) {
83
+ $set.fullfilled = date;
84
+ }
85
+ case OrderStatus.REJECTED: // eslint-disable-line no-fallthrough
86
+ if (!order.rejected) {
87
+ $set.rejected = date;
88
+ }
89
+ case OrderStatus.CONFIRMED: // eslint-disable-line no-fallthrough
90
+ if (!order.confirmed) {
91
+ $set.confirmed = date;
92
+ }
93
+ case OrderStatus.PENDING: // eslint-disable-line no-fallthrough
94
+ if (!order.ordered) {
95
+ $set.ordered = date;
96
+ }
97
+ if (!order.orderNumber) {
98
+ // Order Numbers can be set by the user
99
+ $set.orderNumber = await findNewOrderNumber(order);
100
+ }
101
+ break;
102
+ default:
103
+ break;
104
+ }
105
+
106
+ const modifier: Update<Order> = {
107
+ $set,
108
+ $push: {
109
+ log: {
110
+ date,
111
+ status,
112
+ info,
113
+ },
114
+ },
115
+ };
116
+
117
+ log(`New Status: ${status}`, { orderId });
118
+
119
+ await Orders.updateOne(selector, modifier);
120
+
121
+ return Orders.findOne(selector, {});
122
+ };
123
+
124
+ const updateDiscounts = async (order: Order, requestContext: Context) => {
125
+ const { modules } = requestContext;
126
+
127
+ // 1. go through existing order-discounts and check if discount still valid,
128
+ // those who are not valid anymore should get removed
129
+ const discounts = await modules.orders.discounts.findOrderDiscounts({
130
+ orderId: order._id,
131
+ });
132
+
133
+ await Promise.all(
134
+ discounts.map(async (discount) => {
135
+ const isValid = await modules.orders.discounts.isValid(discount, requestContext);
136
+
137
+ if (!isValid) {
138
+ await modules.orders.discounts.delete(discount._id, requestContext);
139
+ }
140
+ }),
141
+ );
142
+
143
+ // 2. run auto-system discount
144
+ const cleanedDiscounts = await modules.orders.discounts.findOrderDiscounts({
145
+ orderId: order._id,
146
+ });
147
+
148
+ const currentDiscountKeys = cleanedDiscounts.map(({ discountKey }) => discountKey);
149
+
150
+ const director = await OrderDiscountDirector.actions({ order }, requestContext);
151
+ const systemDiscounts = await director.findSystemDiscounts();
152
+
153
+ await Promise.all(
154
+ systemDiscounts
155
+ .filter((key) => currentDiscountKeys.indexOf(key) === -1)
156
+ .map((discountKey) =>
157
+ modules.orders.discounts.create(
158
+ {
159
+ orderId: order._id,
160
+ discountKey,
161
+ trigger: OrderDiscountTrigger.SYSTEM,
162
+ },
163
+ requestContext.userId,
164
+ ),
165
+ ),
166
+ );
167
+ };
168
+
169
+ const initProviders = async (order: Order, requestContext: Context) => {
170
+ const { modules } = requestContext;
171
+
172
+ let updatedOrder = order;
173
+
174
+ // Init delivery provider
175
+ const supportedDeliveryProviders = await modules.delivery.findSupported(
176
+ { order: updatedOrder },
177
+ requestContext,
178
+ );
179
+
180
+ const orderDelivery = await modules.orders.deliveries.findDelivery({
181
+ orderDeliveryId: updatedOrder.deliveryId,
182
+ });
183
+ const deliveryProviderId = orderDelivery?.deliveryProviderId;
184
+
185
+ const isAlreadyInitializedWithSupportedDeliveryProvider = supportedDeliveryProviders?.some(
186
+ (provider) => {
187
+ return provider._id === deliveryProviderId;
188
+ },
189
+ );
190
+
191
+ if (supportedDeliveryProviders?.length > 0 && !isAlreadyInitializedWithSupportedDeliveryProvider) {
192
+ const defaultOrderDeliveryProvider = await modules.delivery.determineDefault(
193
+ supportedDeliveryProviders,
194
+ { order: updatedOrder },
195
+ requestContext,
196
+ );
197
+ if (defaultOrderDeliveryProvider) {
198
+ updatedOrder = await modules.orders.setDeliveryProvider(
199
+ updatedOrder._id,
200
+ defaultOrderDeliveryProvider._id,
201
+ requestContext,
202
+ );
203
+ }
204
+ }
205
+
206
+ // Init payment provider
207
+ const supportedPaymentProviders = await modules.payment.paymentProviders.findSupported(
208
+ { order: updatedOrder },
209
+ requestContext,
210
+ );
211
+
212
+ const orderPayment = await modules.orders.payments.findOrderPayment({
213
+ orderPaymentId: updatedOrder.paymentId,
214
+ });
215
+ const paymentProviderId = orderPayment?.paymentProviderId;
216
+
217
+ const isAlreadyInitializedWithSupportedPaymentProvider = supportedPaymentProviders?.some(
218
+ (provider) => {
219
+ return provider._id === paymentProviderId;
220
+ },
221
+ );
222
+
223
+ if (supportedPaymentProviders?.length > 0 && !isAlreadyInitializedWithSupportedPaymentProvider) {
224
+ const paymentCredentials = await modules.payment.paymentCredentials.findPaymentCredentials(
225
+ { userId: updatedOrder.userId, isPreferred: true },
226
+ {
227
+ sort: {
228
+ created: -1,
229
+ },
230
+ },
231
+ );
232
+
233
+ const defaultOrderPaymentProvider = await modules.payment.paymentProviders.determineDefault(
234
+ supportedPaymentProviders,
235
+ { order: updatedOrder, paymentCredentials },
236
+ requestContext,
237
+ );
238
+
239
+ if (defaultOrderPaymentProvider) {
240
+ updatedOrder = await modules.orders.setPaymentProvider(
241
+ updatedOrder._id,
242
+ defaultOrderPaymentProvider._id,
243
+ requestContext,
244
+ );
245
+ }
246
+ }
247
+ return updatedOrder;
248
+ };
249
+
250
+ const updateCalculation: OrdersModule['updateCalculation'] = async (orderId, requestContext) => {
251
+ const { modules } = requestContext;
252
+
253
+ const selector = generateDbFilterById(orderId);
254
+ let order = (await Orders.findOne(selector, {})) as Order;
255
+
256
+ // Don't recalculate orders, only carts
257
+ if (order.status !== null) return order;
258
+
259
+ await updateDiscounts(order, requestContext);
260
+
261
+ order = await initProviders(order, requestContext);
262
+
263
+ let orderPositions = (await findOrderPositions(order)) as OrderPosition[];
264
+ orderPositions = await Promise.all(
265
+ orderPositions.map((orderPosition) =>
266
+ modules.orders.positions.updateCalculation(orderPosition, requestContext),
267
+ ),
268
+ );
269
+
270
+ let orderDelivery = (await findOrderDelivery(order)) as OrderDelivery;
271
+ if (orderDelivery) {
272
+ orderDelivery = await modules.orders.deliveries.updateCalculation(orderDelivery, requestContext);
273
+ }
274
+ let orderPayment = (await findOrderPayment(order)) as OrderPayment;
275
+ if (orderPayment) {
276
+ orderPayment = await modules.orders.payments.updateCalculation(orderPayment, requestContext);
277
+ }
278
+
279
+ orderPositions = await Promise.all(
280
+ orderPositions.map((orderPosition) =>
281
+ modules.orders.positions.updateScheduling(
282
+ { order, orderDelivery, orderPosition },
283
+ requestContext,
284
+ ),
285
+ ),
286
+ );
287
+
288
+ const pricing = await OrderPricingDirector.actions(
289
+ { order, orderPositions, orderDelivery, orderPayment },
290
+ requestContext,
291
+ );
292
+
293
+ const calculation = await pricing.calculate();
294
+
295
+ await Orders.updateOne(selector, {
296
+ $set: {
297
+ calculation,
298
+ updated: new Date(),
299
+ updatedBy: requestContext.userId,
300
+ },
301
+ });
302
+
303
+ return Orders.findOne(selector, {});
304
+ };
305
+
306
+ const orderQueries = configureOrdersModuleQueries({ Orders });
307
+ const orderTransformations = configureOrderModuleTransformations({
308
+ Orders,
309
+ });
310
+ const orderProcessing = configureOrderModuleProcessing({
311
+ Orders,
312
+ OrderDeliveries,
313
+ OrderPayments,
314
+ OrderPositions,
315
+ updateCalculation,
316
+ updateStatus,
317
+ });
318
+ const orderMutations = configureOrderModuleMutations({
319
+ Orders,
320
+ OrderDeliveries,
321
+ OrderPayments,
322
+ initProviders,
323
+ updateCalculation,
324
+ updateStatus,
325
+ });
326
+
327
+ const orderDiscountsModule = configureOrderDiscountsModule({
328
+ OrderDiscounts,
329
+ updateCalculation,
330
+ });
331
+
332
+ const orderPositionsModule = configureOrderPositionsModule({
333
+ OrderPositions,
334
+ updateCalculation,
335
+ });
336
+
337
+ const orderPaymentsModule = configureOrderPaymentsModule({
338
+ OrderPayments,
339
+ updateCalculation,
340
+ });
341
+
342
+ const orderDeliveriesModule = configureOrderDeliveriesModule({
343
+ OrderDeliveries,
344
+ updateCalculation,
345
+ });
346
+
347
+ return {
348
+ ...orderQueries,
349
+ ...orderTransformations,
350
+ ...orderProcessing,
351
+ ...orderMutations,
352
+
353
+ // Subentities
354
+ deliveries: orderDeliveriesModule,
355
+ discounts: orderDiscountsModule,
356
+ positions: orderPositionsModule,
357
+ payments: orderPaymentsModule,
358
+ };
359
+ };
@@ -0,0 +1,15 @@
1
+ export { configureOrdersModule } from './module/configureOrdersModule';
2
+ export { orderServices } from './service/orderServices';
3
+
4
+ export { OrderStatus } from '@unchainedshop/types/orders';
5
+ export { OrderDeliveryStatus } from '@unchainedshop/types/orders.deliveries';
6
+ export { OrderPaymentStatus } from '@unchainedshop/types/orders.payments';
7
+
8
+ export { OrderDiscountAdapter } from './director/OrderDiscountAdapter';
9
+ export { OrderDiscountDirector } from './director/OrderDiscountDirector';
10
+
11
+ export { OrderPricingAdapter } from './director/OrderPricingAdapter';
12
+ export { OrderPricingDirector } from './director/OrderPricingDirector';
13
+ export { OrderPricingSheet } from './director/OrderPricingSheet';
14
+
15
+ export { ordersSettings } from './orders-settings';
@@ -0,0 +1,23 @@
1
+ import { generateRandomHash } from '@unchainedshop/utils';
2
+
3
+ export const defaultValidateOrderPosition = ({ product }, { modules }) => {
4
+ if (!modules.products.isActive(product)) {
5
+ throw new Error('This product is inactive');
6
+ }
7
+ };
8
+
9
+ export const ordersSettings = {
10
+ ensureUserHasCart: null,
11
+ orderNumberHashFn: null,
12
+ validateOrderPosition: null,
13
+
14
+ configureSettings({
15
+ ensureUserHasCart = false,
16
+ orderNumberHashFn = generateRandomHash,
17
+ validateOrderPosition = defaultValidateOrderPosition,
18
+ } = {}) {
19
+ this.ensureUserHasCart = ensureUserHasCart;
20
+ this.orderNumberHashFn = orderNumberHashFn;
21
+ this.validateOrderPosition = validateOrderPosition;
22
+ },
23
+ };
@@ -0,0 +1,38 @@
1
+ import { CreateUserCartService } from '@unchainedshop/types/orders';
2
+
3
+ export const createUserCartService: CreateUserCartService = async (
4
+ { user, orderNumber, countryCode },
5
+ requestContext,
6
+ ) => {
7
+ const { countryContext, modules, services } = requestContext;
8
+
9
+ const normalizedCountryCode = countryCode || countryContext;
10
+
11
+ const currency = await services.countries.resolveDefaultCurrencyCode(
12
+ {
13
+ isoCode: normalizedCountryCode,
14
+ },
15
+ requestContext,
16
+ );
17
+
18
+ const order = await modules.orders.create(
19
+ {
20
+ orderNumber,
21
+ currency,
22
+ countryCode: normalizedCountryCode,
23
+ billingAddress: user.lastBillingAddress || user.profile?.address,
24
+ contact:
25
+ user.lastContact ||
26
+ (!user.guest
27
+ ? {
28
+ telNumber: user.profile?.phoneMobile,
29
+ emailAddress: modules.users.primaryEmail(user)?.address,
30
+ }
31
+ : {}),
32
+ },
33
+ user._id,
34
+ );
35
+
36
+ await modules.orders.initProviders(order, requestContext);
37
+ return order;
38
+ };
@@ -0,0 +1,22 @@
1
+ import { MigrateOrderCartsService } from '@unchainedshop/types/orders';
2
+
3
+ export const migrateOrderCartsService: MigrateOrderCartsService = async (
4
+ { fromUser, toUser, shouldMerge },
5
+ requestContext,
6
+ ) => {
7
+ const fromCart = await requestContext.modules.orders.cart(
8
+ { countryContext: requestContext.countryContext },
9
+ fromUser,
10
+ );
11
+ const toCart = await requestContext.modules.orders.cart(
12
+ { countryContext: requestContext.countryContext },
13
+ toUser,
14
+ );
15
+
16
+ if (!fromCart) {
17
+ // No cart, don't copy
18
+ return toCart;
19
+ }
20
+
21
+ return requestContext.modules.orders.migrateCart({ fromCart, shouldMerge, toCart }, requestContext);
22
+ };
@@ -0,0 +1,8 @@
1
+ import { OrderServices } from '@unchainedshop/types/orders';
2
+ import { migrateOrderCartsService } from './migrateOrderCartService';
3
+ import { createUserCartService } from './createUserCartService';
4
+
5
+ export const orderServices: OrderServices = {
6
+ migrateOrderCarts: migrateOrderCartsService,
7
+ createUserCart: createUserCartService,
8
+ };
@@ -0,0 +1,50 @@
1
+ import { assert } from 'chai';
2
+ import { initDb } from 'meteor/unchained:mongodb';
3
+ import { configureOrdersModule } from 'meteor/unchained:core-orders';
4
+ import { OrdersModule } from '@unchainedshop/types/orders';
5
+
6
+ describe('Test exports', () => {
7
+ let module: OrdersModule;
8
+
9
+ before(async () => {
10
+ const db = await initDb();
11
+ module = await configureOrdersModule({ db }).catch((error) => {
12
+ console.error(error);
13
+
14
+ throw error;
15
+ });
16
+ });
17
+
18
+ it('Insert order', async () => {
19
+ let order = await module.create(
20
+ {
21
+ billingAddress: {
22
+ lastName: 'Mustermann',
23
+ firstName: 'Max',
24
+ addressLine: 'Teststreet 11',
25
+ city: 'Zürich',
26
+ postalCode: '8009',
27
+ company: 'Unchained Commerce',
28
+ countryCode: 'CH',
29
+ },
30
+ orderNumber: 'Nr-1234123',
31
+ currency: 'CHF',
32
+ countryCode: 'CH',
33
+ },
34
+ 'Test-User-1'
35
+ );
36
+
37
+ assert.ok(order);
38
+ const orderId = order._id;
39
+ order = await module.findOrder({ orderId });
40
+
41
+ assert.ok(order);
42
+
43
+ const deletedCount = await module
44
+ .delete(orderId, 'Test-User-1')
45
+ .catch((error) => {
46
+ return 0;
47
+ });
48
+ assert.equal(deletedCount, 1);
49
+ });
50
+ });
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "allowJs": true,
4
+ "allowSyntheticDefaultImports": true,
5
+ "declaration": true,
6
+ "esModuleInterop": true,
7
+ "experimentalDecorators": true,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "lib": ["esnext"],
10
+ "module": "esnext",
11
+ "moduleResolution": "node",
12
+ "noImplicitReturns": true,
13
+ "noUnusedLocals": false,
14
+ "outDir": "lib",
15
+ "preserveWatchOutput": true,
16
+ "skipLibCheck": true,
17
+ "sourceMap": true,
18
+ "target": "esnext",
19
+ "types": ["node"],
20
+ "baseUrl": ".", // This must be specified if "paths" is.
21
+ "paths": {
22
+ "meteor/unchained:*": ["node_modules/@unchainedshop/types/index.d.ts"]
23
+ }
24
+ },
25
+ "include": ["src"]
26
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./tsconfig.build.json",
3
+ "compilerOptions": {
4
+ "noEmit": true,
5
+ "types": ["node", "mocha"]
6
+ },
7
+ "include": ["src", "tests", "plugins"]
8
+ }