@unchainedshop/core 5.0.0-alpha.10 → 5.0.0-alpha.11
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.
- package/lib/bulk-exporter/handlers/exportUsersHandler.js +1 -0
- package/lib/directors/BasePricingSheet.d.ts +2 -0
- package/lib/directors/DeliveryPricingSheet.js +9 -4
- package/lib/directors/EnrollmentAdapter.d.ts +11 -1
- package/lib/directors/EnrollmentAdapter.js +7 -1
- package/lib/directors/EnrollmentDirector.d.ts +2 -1
- package/lib/directors/EnrollmentDirector.js +6 -4
- package/lib/directors/OrderPricingSheet.js +6 -7
- package/lib/directors/PaymentPricingSheet.js +9 -4
- package/lib/directors/ProductPricingAdapter.d.ts +1 -0
- package/lib/directors/ProductPricingDirector.js +1 -0
- package/lib/directors/ProductPricingSheet.js +7 -4
- package/lib/directors/QuotationAdapter.js +5 -2
- package/lib/factory/registerEnrollment.d.ts +8 -1
- package/lib/factory/registerEnrollment.js +12 -14
- package/lib/factory/registerQuotation.d.ts +2 -1
- package/lib/factory/registerQuotation.js +3 -2
- package/lib/plugins/PluginRegistry.d.ts +1 -1
- package/lib/plugins/PluginRegistry.js +8 -2
- package/lib/services/addCartQuotation.d.ts +9 -13
- package/lib/services/addCartQuotation.js +43 -38
- package/lib/services/calculateDiscountTotal.d.ts +5 -1
- package/lib/services/calculateDiscountTotal.js +36 -28
- package/lib/services/checkoutOrder.js +4 -0
- package/lib/services/index.d.ts +8 -0
- package/lib/services/index.js +8 -0
- package/lib/services/initializeEnrollment.d.ts +1 -1
- package/lib/services/initializeEnrollment.js +11 -0
- package/lib/services/migrateOrderCart.js +2 -2
- package/lib/services/migrateUserData.js +3 -0
- package/lib/services/processEnrollment.js +6 -3
- package/lib/services/processOrder.js +4 -4
- package/lib/services/reserveOrderQuotationsForCheckout.d.ts +8 -0
- package/lib/services/reserveOrderQuotationsForCheckout.js +49 -0
- package/lib/services/simulateConfigurablePriceRange.js +1 -1
- package/lib/services/simulateDeliveryPricing.js +1 -1
- package/lib/services/simulatePaymentPricing.js +1 -1
- package/lib/services/suspendEnrollment.d.ts +5 -0
- package/lib/services/suspendEnrollment.js +21 -0
- package/lib/services/terminateEnrollment.d.ts +6 -2
- package/lib/services/terminateEnrollment.js +27 -7
- package/lib/services/updateCartItem.d.ts +7 -7
- package/lib/services/updateCartItem.js +28 -25
- package/lib/services/updateEnrollmentPlan.d.ts +5 -0
- package/lib/services/updateEnrollmentPlan.js +26 -0
- package/lib/services/validateOrder.js +7 -2
- package/package.json +22 -22
- package/lib/errors/common.d.ts +0 -568
- package/lib/errors/common.js +0 -789
- package/lib/errors/index.d.ts +0 -1
- package/lib/errors/index.js +0 -1
- package/lib/services/addCartDiscount.d.ts +0 -10
- package/lib/services/addCartDiscount.js +0 -27
- package/lib/services/addCartItem.d.ts +0 -15
- package/lib/services/addCartItem.js +0 -41
- package/lib/services/addEmail.d.ts +0 -7
- package/lib/services/addEmail.js +0 -17
- package/lib/services/addProductAssignment.d.ts +0 -3
- package/lib/services/addProductAssignment.js +0 -63
- package/lib/services/authenticateWithPassword.d.ts +0 -15
- package/lib/services/authenticateWithPassword.js +0 -34
- package/lib/services/changePassword.d.ts +0 -10
- package/lib/services/changePassword.js +0 -19
- package/lib/services/countOrdersWithFilters.d.ts +0 -3
- package/lib/services/countOrdersWithFilters.js +0 -25
- package/lib/services/createAssortment.d.ts +0 -7
- package/lib/services/createAssortment.js +0 -10
- package/lib/services/createBookmark.d.ts +0 -8
- package/lib/services/createBookmark.js +0 -21
- package/lib/services/createDeliveryProvider.d.ts +0 -6
- package/lib/services/createDeliveryProvider.js +0 -19
- package/lib/services/createEnrollment.d.ts +0 -17
- package/lib/services/createEnrollment.js +0 -33
- package/lib/services/createProduct.d.ts +0 -7
- package/lib/services/createProduct.js +0 -8
- package/lib/services/createProductBundleItem.d.ts +0 -5
- package/lib/services/createProductBundleItem.js +0 -25
- package/lib/services/createProductReview.d.ts +0 -8
- package/lib/services/createProductReview.js +0 -12
- package/lib/services/deleteDeadCarts.d.ts +0 -2
- package/lib/services/deleteDeadCarts.js +0 -17
- package/lib/services/deliverOrder.d.ts +0 -5
- package/lib/services/deliverOrder.js +0 -26
- package/lib/services/findActiveWorkTypes.d.ts +0 -2
- package/lib/services/findActiveWorkTypes.js +0 -6
- package/lib/services/findDeliveryInterfaces.d.ts +0 -7
- package/lib/services/findDeliveryInterfaces.js +0 -13
- package/lib/services/findOrdersWithFilters.d.ts +0 -9
- package/lib/services/findOrdersWithFilters.js +0 -25
- package/lib/services/findPaymentInterfaces.d.ts +0 -7
- package/lib/services/findPaymentInterfaces.js +0 -13
- package/lib/services/findWarehousingInterfaces.d.ts +0 -7
- package/lib/services/findWarehousingInterfaces.js +0 -13
- package/lib/services/getDeliveryDiscounts.d.ts +0 -8
- package/lib/services/getDeliveryDiscounts.js +0 -14
- package/lib/services/getPaymentDiscounts.d.ts +0 -8
- package/lib/services/getPaymentDiscounts.js +0 -14
- package/lib/services/getShopInfo.d.ts +0 -25
- package/lib/services/getShopInfo.js +0 -47
- package/lib/services/impersonateUser.d.ts +0 -8
- package/lib/services/impersonateUser.js +0 -20
- package/lib/services/loginAsGuest.d.ts +0 -10
- package/lib/services/loginAsGuest.js +0 -19
- package/lib/services/obfuscateWorkerData.d.ts +0 -4
- package/lib/services/obfuscateWorkerData.js +0 -4
- package/lib/services/orderPricingAccessors.d.ts +0 -18
- package/lib/services/orderPricingAccessors.js +0 -29
- package/lib/services/payOrder.d.ts +0 -5
- package/lib/services/payOrder.js +0 -25
- package/lib/services/registerUser.d.ts +0 -14
- package/lib/services/registerUser.js +0 -44
- package/lib/services/removeBookmark.d.ts +0 -6
- package/lib/services/removeBookmark.js +0 -10
- package/lib/services/removeCartItem.d.ts +0 -6
- package/lib/services/removeCartItem.js +0 -19
- package/lib/services/resetPasswordWithMigration.d.ts +0 -14
- package/lib/services/resetPasswordWithMigration.js +0 -31
- package/lib/services/resolveWorkType.d.ts +0 -1
- package/lib/services/resolveWorkType.js +0 -7
- package/lib/services/searchProductsWithAssortment.d.ts +0 -19
- package/lib/services/searchProductsWithAssortment.js +0 -17
- package/lib/services/toggleBookmark.d.ts +0 -8
- package/lib/services/toggleBookmark.js +0 -33
- package/lib/services/updateCart.d.ts +0 -15
- package/lib/services/updateCart.js +0 -27
- package/lib/services/updateEnrollment.d.ts +0 -13
- package/lib/services/updateEnrollment.js +0 -36
- package/lib/services/verifyEmailWithMigration.d.ts +0 -15
- package/lib/services/verifyEmailWithMigration.js +0 -23
|
@@ -3,6 +3,8 @@ export interface PricingDiscount {
|
|
|
3
3
|
discountId: string;
|
|
4
4
|
amount: number;
|
|
5
5
|
currencyCode: string;
|
|
6
|
+
isTaxable: boolean;
|
|
7
|
+
isNetPrice: boolean;
|
|
6
8
|
}
|
|
7
9
|
export interface IPricingSheet<Calculation extends PricingCalculation> extends IBasePricingSheet<Calculation> {
|
|
8
10
|
discountPrices: (discountId?: string) => PricingDiscount[];
|
|
@@ -28,10 +28,12 @@ export const DeliveryPricingSheet = (params) => {
|
|
|
28
28
|
meta,
|
|
29
29
|
});
|
|
30
30
|
},
|
|
31
|
-
addTax({ amount, rate, meta }) {
|
|
31
|
+
addTax({ amount, rate, baseCategory, discountId, meta }) {
|
|
32
32
|
basePricingSheet.calculation.push({
|
|
33
33
|
amount,
|
|
34
34
|
category: DeliveryPricingRowCategory.Tax,
|
|
35
|
+
baseCategory,
|
|
36
|
+
discountId,
|
|
35
37
|
isNetPrice: false,
|
|
36
38
|
isTaxable: false,
|
|
37
39
|
meta,
|
|
@@ -54,17 +56,20 @@ export const DeliveryPricingSheet = (params) => {
|
|
|
54
56
|
.filter(Boolean);
|
|
55
57
|
return [...new Set(discountIds)]
|
|
56
58
|
.map((discountId) => {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
+
const taxAmount = pricingSheet.taxSum({
|
|
60
|
+
baseCategory: DeliveryPricingRowCategory.Discount,
|
|
59
61
|
discountId,
|
|
60
62
|
});
|
|
63
|
+
const amount = pricingSheet.sum({ category: DeliveryPricingRowCategory.Discount, discountId }) + taxAmount;
|
|
61
64
|
if (!amount) {
|
|
62
65
|
return null;
|
|
63
66
|
}
|
|
64
67
|
return {
|
|
65
68
|
discountId,
|
|
66
69
|
amount: Math.round(amount),
|
|
67
|
-
currencyCode,
|
|
70
|
+
currencyCode: pricingSheet.currencyCode,
|
|
71
|
+
isTaxable: taxAmount !== 0,
|
|
72
|
+
isNetPrice: false,
|
|
68
73
|
};
|
|
69
74
|
})
|
|
70
75
|
.filter(Boolean);
|
|
@@ -2,6 +2,7 @@ import { type IBaseAdapter } from '@unchainedshop/utils';
|
|
|
2
2
|
import { type Enrollment, type EnrollmentOrderPositionTemplate, type EnrollmentPeriod, type EnrollmentPlan } from '@unchainedshop/core-enrollments';
|
|
3
3
|
import type { Product, ProductPlan } from '@unchainedshop/core-products';
|
|
4
4
|
import type { OrderPosition } from '@unchainedshop/core-orders';
|
|
5
|
+
import type { Modules } from '../modules.ts';
|
|
5
6
|
export interface EnrollmentContext {
|
|
6
7
|
enrollment: Enrollment;
|
|
7
8
|
product: Product;
|
|
@@ -16,11 +17,20 @@ export interface EnrollmentAdapterActions {
|
|
|
16
17
|
isOverdue: () => Promise<boolean>;
|
|
17
18
|
isValidForActivation: () => Promise<boolean>;
|
|
18
19
|
nextPeriod: () => Promise<EnrollmentPeriod | null>;
|
|
20
|
+
terminationDate: (params: {
|
|
21
|
+
referenceDate: Date;
|
|
22
|
+
}) => Promise<Date | null>;
|
|
23
|
+
transformPlanToNewPlan: (params: {
|
|
24
|
+
plan: EnrollmentPlan;
|
|
25
|
+
}) => Promise<EnrollmentPlan | null>;
|
|
19
26
|
}
|
|
20
27
|
export type IEnrollmentAdapter = IBaseAdapter & {
|
|
28
|
+
orderIndex?: number;
|
|
21
29
|
isActivatedFor: (productPlan?: ProductPlan) => boolean;
|
|
22
30
|
transformOrderItemToEnrollmentPlan: (orderPosition: OrderPosition, unchainedAPI: any) => Promise<EnrollmentPlan>;
|
|
23
|
-
actions: (params: EnrollmentContext
|
|
31
|
+
actions: (params: EnrollmentContext & {
|
|
32
|
+
modules: Modules;
|
|
33
|
+
}) => EnrollmentAdapterActions;
|
|
24
34
|
};
|
|
25
35
|
export declare const periodForReferenceDate: (referenceDate: Date, intervalCount?: number, interval?: string) => {
|
|
26
36
|
start: Date;
|
|
@@ -56,11 +56,17 @@ export const EnrollmentAdapter = {
|
|
|
56
56
|
}
|
|
57
57
|
return acc;
|
|
58
58
|
}, referenceDate);
|
|
59
|
-
|
|
59
|
+
const period = {
|
|
60
60
|
...periodForReferenceDate(lastEnd, plan.billingIntervalCount, plan.billingInterval),
|
|
61
61
|
isTrial: false,
|
|
62
62
|
};
|
|
63
|
+
if (enrollment?.expires && period.start.getTime() >= new Date(enrollment.expires).getTime()) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return period;
|
|
63
67
|
},
|
|
68
|
+
terminationDate: async ({ referenceDate }) => referenceDate,
|
|
69
|
+
transformPlanToNewPlan: async () => null,
|
|
64
70
|
};
|
|
65
71
|
},
|
|
66
72
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { IBaseDirector } from '@unchainedshop/utils';
|
|
2
2
|
import type { EnrollmentAdapterActions, EnrollmentContext, IEnrollmentAdapter } from './EnrollmentAdapter.ts';
|
|
3
3
|
import type { OrderPosition } from '@unchainedshop/core-orders';
|
|
4
|
-
import type { Product } from '@unchainedshop/core-products';
|
|
4
|
+
import type { Product, ProductPlan } from '@unchainedshop/core-products';
|
|
5
5
|
import type { Enrollment } from '@unchainedshop/core-enrollments';
|
|
6
6
|
import type { Modules } from '../modules.ts';
|
|
7
7
|
export type IEnrollmentDirector = IBaseDirector<IEnrollmentAdapter> & {
|
|
@@ -9,6 +9,7 @@ export type IEnrollmentDirector = IBaseDirector<IEnrollmentAdapter> & {
|
|
|
9
9
|
orderPosition: OrderPosition;
|
|
10
10
|
product: Product;
|
|
11
11
|
}, doc: Omit<Enrollment, 'configuration' | 'productId' | 'quantity' | 'status' | 'periods' | 'log' | '_id' | 'created'>, unchainedAPI: any) => Promise<Omit<Enrollment, 'status' | 'periods' | 'log' | '_id' | 'created'> & Pick<Partial<Enrollment>, '_id' | 'created'>>;
|
|
12
|
+
findSupportedAdapter: (productPlan?: ProductPlan) => IEnrollmentAdapter | null;
|
|
12
13
|
actions: (enrollmentContext: EnrollmentContext, unchainedAPI: {
|
|
13
14
|
modules: Modules;
|
|
14
15
|
}) => Promise<EnrollmentAdapterActions>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EnrollmentAdapter } from "./EnrollmentAdapter.js";
|
|
2
2
|
import { createLogger } from '@unchainedshop/logger';
|
|
3
3
|
import { registryDirector } from "./registryDirector.js";
|
|
4
|
+
import { createServiceError } from "../errors.js";
|
|
4
5
|
const logger = createLogger('unchained:core');
|
|
5
6
|
const findAppropriateAdapters = (productPlan) => EnrollmentDirector.getAdapters({
|
|
6
7
|
adapterFilter: (Adapter) => {
|
|
@@ -13,10 +14,11 @@ const findAppropriateAdapters = (productPlan) => EnrollmentDirector.getAdapters(
|
|
|
13
14
|
});
|
|
14
15
|
export const EnrollmentDirector = {
|
|
15
16
|
...registryDirector(EnrollmentAdapter.adapterType),
|
|
17
|
+
findSupportedAdapter: (productPlan) => findAppropriateAdapters(productPlan)?.[0] || null,
|
|
16
18
|
transformOrderItemToEnrollment: async ({ orderPosition, product }, doc, unchainedAPI) => {
|
|
17
|
-
const Adapter =
|
|
19
|
+
const Adapter = EnrollmentDirector.findSupportedAdapter(product.plan);
|
|
18
20
|
if (!Adapter) {
|
|
19
|
-
throw
|
|
21
|
+
throw createServiceError('EnrollmentPlanNotSupportedError', 'No suitable enrollment plugin available for this item');
|
|
20
22
|
}
|
|
21
23
|
const enrollmentPlan = await Adapter.transformOrderItemToEnrollmentPlan(orderPosition, unchainedAPI);
|
|
22
24
|
return {
|
|
@@ -27,9 +29,9 @@ export const EnrollmentDirector = {
|
|
|
27
29
|
},
|
|
28
30
|
actions: async (enrollmentContext, unchainedAPI) => {
|
|
29
31
|
const context = { ...enrollmentContext, ...unchainedAPI };
|
|
30
|
-
const Adapter =
|
|
32
|
+
const Adapter = EnrollmentDirector.findSupportedAdapter(enrollmentContext.product.plan);
|
|
31
33
|
if (!Adapter) {
|
|
32
|
-
throw
|
|
34
|
+
throw createServiceError('EnrollmentPlanNotSupportedError', 'No suitable enrollment plugin available for this plan configuration');
|
|
33
35
|
}
|
|
34
36
|
const adapter = Adapter.actions(context);
|
|
35
37
|
return adapter;
|
|
@@ -81,14 +81,11 @@ export const OrderPricingSheet = (params) => {
|
|
|
81
81
|
.filter(Boolean);
|
|
82
82
|
return [...new Set(discountIds)]
|
|
83
83
|
.map((discountId) => {
|
|
84
|
-
const
|
|
85
|
-
|
|
84
|
+
const taxAmount = pricingSheet.taxSum({
|
|
85
|
+
baseCategory: OrderPricingRowCategory.Discounts,
|
|
86
86
|
discountId,
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
baseCategory: OrderPricingRowCategory.Discounts,
|
|
90
|
-
discountId,
|
|
91
|
-
});
|
|
87
|
+
});
|
|
88
|
+
const amount = pricingSheet.sum({ category: OrderPricingRowCategory.Discounts, discountId }) + taxAmount;
|
|
92
89
|
if (!amount) {
|
|
93
90
|
return null;
|
|
94
91
|
}
|
|
@@ -96,6 +93,8 @@ export const OrderPricingSheet = (params) => {
|
|
|
96
93
|
discountId,
|
|
97
94
|
amount: Math.round(amount),
|
|
98
95
|
currencyCode: pricingSheet.currencyCode,
|
|
96
|
+
isTaxable: taxAmount !== 0,
|
|
97
|
+
isNetPrice: false,
|
|
99
98
|
};
|
|
100
99
|
})
|
|
101
100
|
.filter(Boolean);
|
|
@@ -29,10 +29,12 @@ export const PaymentPricingSheet = (params) => {
|
|
|
29
29
|
meta,
|
|
30
30
|
});
|
|
31
31
|
},
|
|
32
|
-
addTax({ amount, rate, meta }) {
|
|
32
|
+
addTax({ amount, rate, baseCategory, discountId, meta }) {
|
|
33
33
|
basePricingSheet.calculation.push({
|
|
34
34
|
category: PaymentPricingRowCategory.Tax,
|
|
35
35
|
amount,
|
|
36
|
+
baseCategory,
|
|
37
|
+
discountId,
|
|
36
38
|
isTaxable: false,
|
|
37
39
|
isNetPrice: false,
|
|
38
40
|
rate,
|
|
@@ -55,17 +57,20 @@ export const PaymentPricingSheet = (params) => {
|
|
|
55
57
|
.filter(Boolean);
|
|
56
58
|
return [...new Set(discountIds)]
|
|
57
59
|
.map((discountId) => {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
+
const taxAmount = pricingSheet.taxSum({
|
|
61
|
+
baseCategory: PaymentPricingRowCategory.Discount,
|
|
60
62
|
discountId,
|
|
61
63
|
});
|
|
64
|
+
const amount = pricingSheet.sum({ category: PaymentPricingRowCategory.Discount, discountId }) + taxAmount;
|
|
62
65
|
if (!amount) {
|
|
63
66
|
return null;
|
|
64
67
|
}
|
|
65
68
|
return {
|
|
66
69
|
discountId,
|
|
67
70
|
amount: Math.round(amount),
|
|
68
|
-
currencyCode:
|
|
71
|
+
currencyCode: pricingSheet.currencyCode,
|
|
72
|
+
isTaxable: taxAmount !== 0,
|
|
73
|
+
isNetPrice: false,
|
|
69
74
|
};
|
|
70
75
|
})
|
|
71
76
|
.filter(Boolean);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BasePricingSheet } from "./BasePricingSheet.js";
|
|
1
|
+
import { BasePricingSheet, } from "./BasePricingSheet.js";
|
|
2
2
|
export const ProductPricingRowCategory = {
|
|
3
3
|
Item: 'ITEM',
|
|
4
4
|
Discount: 'DISCOUNT',
|
|
@@ -62,17 +62,20 @@ export const ProductPricingSheet = (params) => {
|
|
|
62
62
|
.filter(Boolean);
|
|
63
63
|
return [...new Set(discountIds)]
|
|
64
64
|
.map((discountId) => {
|
|
65
|
-
const
|
|
66
|
-
|
|
65
|
+
const taxAmount = pricingSheet.taxSum({
|
|
66
|
+
baseCategory: ProductPricingRowCategory.Discount,
|
|
67
67
|
discountId,
|
|
68
68
|
});
|
|
69
|
+
const amount = pricingSheet.sum({ category: ProductPricingRowCategory.Discount, discountId }) + taxAmount;
|
|
69
70
|
if (!amount) {
|
|
70
71
|
return null;
|
|
71
72
|
}
|
|
72
73
|
return {
|
|
73
74
|
discountId,
|
|
74
75
|
amount: Math.round(amount),
|
|
75
|
-
currencyCode:
|
|
76
|
+
currencyCode: pricingSheet.currencyCode,
|
|
77
|
+
isTaxable: taxAmount !== 0,
|
|
78
|
+
isNetPrice: false,
|
|
76
79
|
};
|
|
77
80
|
})
|
|
78
81
|
.filter(Boolean);
|
|
@@ -12,7 +12,7 @@ export const QuotationAdapter = {
|
|
|
12
12
|
isActivatedFor: () => {
|
|
13
13
|
return false;
|
|
14
14
|
},
|
|
15
|
-
actions: () => {
|
|
15
|
+
actions: (params) => {
|
|
16
16
|
return {
|
|
17
17
|
configurationError: () => {
|
|
18
18
|
return QuotationError.NOT_IMPLEMENTED;
|
|
@@ -36,7 +36,10 @@ export const QuotationAdapter = {
|
|
|
36
36
|
return true;
|
|
37
37
|
},
|
|
38
38
|
transformItemConfiguration: async ({ quantity, configuration }) => {
|
|
39
|
-
|
|
39
|
+
const quotedQuantity = params?.quotation?.quantity;
|
|
40
|
+
if (quotedQuantity && (!quantity || quantity % quotedQuantity !== 0))
|
|
41
|
+
return null;
|
|
42
|
+
return { quantity, configuration: params?.quotation?.configuration ?? configuration };
|
|
40
43
|
},
|
|
41
44
|
};
|
|
42
45
|
},
|
|
@@ -2,8 +2,9 @@ import type { EnrollmentOrderPositionTemplate, EnrollmentPeriod, EnrollmentPlan
|
|
|
2
2
|
import type { ProductPlan } from '@unchainedshop/core-products';
|
|
3
3
|
import type { OrderPosition } from '@unchainedshop/core-orders';
|
|
4
4
|
import { type EnrollmentContext, type IPlugin } from '../core-index.ts';
|
|
5
|
-
export default function registerEnrollment({ adapterId, isActivatedFor, transformOrderItem, configurationForOrder, isOverdue, isValidForActivation, nextPeriod, }: {
|
|
5
|
+
export default function registerEnrollment({ adapterId, orderIndex, isActivatedFor, transformOrderItem, configurationForOrder, isOverdue, isValidForActivation, nextPeriod, terminationDate, transformPlanToNewPlan, }: {
|
|
6
6
|
adapterId: string;
|
|
7
|
+
orderIndex?: number;
|
|
7
8
|
isActivatedFor?: (productPlan?: ProductPlan) => boolean;
|
|
8
9
|
transformOrderItem?: (orderPosition: OrderPosition, unchainedAPI: any) => Promise<EnrollmentPlan>;
|
|
9
10
|
configurationForOrder: (params: {
|
|
@@ -15,4 +16,10 @@ export default function registerEnrollment({ adapterId, isActivatedFor, transfor
|
|
|
15
16
|
isOverdue?: (context: EnrollmentContext) => Promise<boolean>;
|
|
16
17
|
isValidForActivation?: (context: EnrollmentContext) => Promise<boolean>;
|
|
17
18
|
nextPeriod?: (context: EnrollmentContext) => Promise<EnrollmentPeriod | null>;
|
|
19
|
+
terminationDate?: (context: EnrollmentContext, params: {
|
|
20
|
+
referenceDate: Date;
|
|
21
|
+
}) => Promise<Date | null>;
|
|
22
|
+
transformPlanToNewPlan?: (context: EnrollmentContext, params: {
|
|
23
|
+
plan: EnrollmentPlan;
|
|
24
|
+
}) => Promise<EnrollmentPlan | null>;
|
|
18
25
|
}): IPlugin;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { EnrollmentAdapter, } from "../core-index.js";
|
|
2
2
|
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
3
|
-
export default function registerEnrollment({ adapterId, isActivatedFor, transformOrderItem, configurationForOrder, isOverdue, isValidForActivation, nextPeriod, }) {
|
|
3
|
+
export default function registerEnrollment({ adapterId, orderIndex, isActivatedFor, transformOrderItem, configurationForOrder, isOverdue, isValidForActivation, nextPeriod, terminationDate, transformPlanToNewPlan, }) {
|
|
4
4
|
const adapter = {
|
|
5
5
|
...EnrollmentAdapter,
|
|
6
6
|
key: `shop.unchained.enrollment.${adapterId}`,
|
|
7
7
|
label: 'Enrollment: ' + adapterId,
|
|
8
8
|
version: '1.0.0',
|
|
9
|
+
orderIndex: orderIndex ?? 0,
|
|
9
10
|
isActivatedFor: (productPlan) => {
|
|
10
11
|
return isActivatedFor ? isActivatedFor(productPlan) : true;
|
|
11
12
|
},
|
|
@@ -15,20 +16,17 @@ export default function registerEnrollment({ adapterId, isActivatedFor, transfor
|
|
|
15
16
|
: EnrollmentAdapter.transformOrderItemToEnrollmentPlan(orderPosition, unchainedAPI);
|
|
16
17
|
},
|
|
17
18
|
actions: (context) => {
|
|
19
|
+
const base = EnrollmentAdapter.actions(context);
|
|
18
20
|
return {
|
|
19
|
-
...
|
|
20
|
-
configurationForOrder:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
nextPeriod: async () => {
|
|
30
|
-
return nextPeriod ? nextPeriod(context) : EnrollmentAdapter.actions(context).nextPeriod();
|
|
31
|
-
},
|
|
21
|
+
...base,
|
|
22
|
+
configurationForOrder: (params) => configurationForOrder(params, context),
|
|
23
|
+
isOverdue: () => (isOverdue ? isOverdue(context) : base.isOverdue()),
|
|
24
|
+
isValidForActivation: () => isValidForActivation ? isValidForActivation(context) : base.isValidForActivation(),
|
|
25
|
+
nextPeriod: () => (nextPeriod ? nextPeriod(context) : base.nextPeriod()),
|
|
26
|
+
terminationDate: (params) => terminationDate ? terminationDate(context, params) : base.terminationDate(params),
|
|
27
|
+
transformPlanToNewPlan: (params) => transformPlanToNewPlan
|
|
28
|
+
? transformPlanToNewPlan(context, params)
|
|
29
|
+
: base.transformPlanToNewPlan(params),
|
|
32
30
|
};
|
|
33
31
|
},
|
|
34
32
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { QuotationItemConfiguration, QuotationProposal } from '@unchainedshop/core-quotations';
|
|
2
2
|
import { type QuotationContext, type IPlugin } from '../core-index.ts';
|
|
3
|
-
export default function registerQuotation({ adapterId, isManualRequestVerificationRequired, isManualProposalRequired, quote, submitRequest, verifyRequest, rejectRequest, transformItemConfiguration, }: {
|
|
3
|
+
export default function registerQuotation({ adapterId, orderIndex, isManualRequestVerificationRequired, isManualProposalRequired, quote, submitRequest, verifyRequest, rejectRequest, transformItemConfiguration, }: {
|
|
4
4
|
adapterId: string;
|
|
5
|
+
orderIndex?: number;
|
|
5
6
|
isManualRequestVerificationRequired?: boolean;
|
|
6
7
|
isManualProposalRequired?: boolean;
|
|
7
8
|
quote?: (context: QuotationContext) => Promise<QuotationProposal>;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { QuotationAdapter, } from "../core-index.js";
|
|
2
2
|
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
3
|
-
export default function registerQuotation({ adapterId, isManualRequestVerificationRequired, isManualProposalRequired, quote, submitRequest, verifyRequest, rejectRequest, transformItemConfiguration, }) {
|
|
3
|
+
export default function registerQuotation({ adapterId, orderIndex, isManualRequestVerificationRequired, isManualProposalRequired, quote, submitRequest, verifyRequest, rejectRequest, transformItemConfiguration, }) {
|
|
4
4
|
const adapter = {
|
|
5
5
|
...QuotationAdapter,
|
|
6
6
|
key: `shop.unchained.quotation.${adapterId}`,
|
|
7
7
|
label: 'Quotation: ' + adapterId,
|
|
8
8
|
version: '1.0.0',
|
|
9
|
+
orderIndex: orderIndex ?? 0,
|
|
9
10
|
isActivatedFor: () => {
|
|
10
11
|
return true;
|
|
11
12
|
},
|
|
@@ -36,7 +37,7 @@ export default function registerQuotation({ adapterId, isManualRequestVerificati
|
|
|
36
37
|
transformItemConfiguration: async (params) => {
|
|
37
38
|
return transformItemConfiguration
|
|
38
39
|
? transformItemConfiguration(params, context)
|
|
39
|
-
:
|
|
40
|
+
: QuotationAdapter.actions(context).transformItemConfiguration(params);
|
|
40
41
|
},
|
|
41
42
|
};
|
|
42
43
|
},
|
|
@@ -37,7 +37,7 @@ declare class PluginRegistry {
|
|
|
37
37
|
getAdapters(adapterType: symbol): IBaseAdapter[];
|
|
38
38
|
getAllAdapters(): IBaseAdapter[];
|
|
39
39
|
hasPlugin(key: string): boolean;
|
|
40
|
-
clear(): void;
|
|
40
|
+
clear(): () => void;
|
|
41
41
|
}
|
|
42
42
|
export declare const pluginRegistry: PluginRegistry;
|
|
43
43
|
export {};
|
|
@@ -114,9 +114,15 @@ class PluginRegistry {
|
|
|
114
114
|
return this.plugins.has(key);
|
|
115
115
|
}
|
|
116
116
|
clear() {
|
|
117
|
-
this
|
|
117
|
+
const { plugins, moduleFactories, skippedPlugins } = this;
|
|
118
|
+
this.plugins = new Map();
|
|
118
119
|
this.moduleFactories = [];
|
|
119
|
-
this.skippedPlugins
|
|
120
|
+
this.skippedPlugins = new Set();
|
|
121
|
+
return () => {
|
|
122
|
+
this.plugins = plugins;
|
|
123
|
+
this.moduleFactories = moduleFactories;
|
|
124
|
+
this.skippedPlugins = skippedPlugins;
|
|
125
|
+
};
|
|
120
126
|
}
|
|
121
127
|
}
|
|
122
128
|
export const pluginRegistry = new PluginRegistry();
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type
|
|
1
|
+
import { type Order, type OrderPosition } from '@unchainedshop/core-orders';
|
|
2
|
+
import { type Quotation } from '@unchainedshop/core-quotations';
|
|
3
3
|
import type { Modules } from '../modules.ts';
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
quantity
|
|
8
|
-
configuration
|
|
4
|
+
export declare function addCartQuotationService(this: Modules, { order, quotation, quantity, configuration, }: {
|
|
5
|
+
order: Order;
|
|
6
|
+
quotation: Quotation;
|
|
7
|
+
quantity?: number | null;
|
|
8
|
+
configuration?: {
|
|
9
9
|
key: string;
|
|
10
10
|
value: string;
|
|
11
|
-
}[];
|
|
12
|
-
|
|
13
|
-
countryCode: string;
|
|
14
|
-
context: unknown;
|
|
15
|
-
}
|
|
16
|
-
export declare function addCartQuotationService(this: Modules, params: AddCartQuotationParams): Promise<OrderPosition>;
|
|
11
|
+
}[] | null;
|
|
12
|
+
}, unchainedAPI?: Record<string, any>): Promise<OrderPosition>;
|
|
@@ -1,52 +1,57 @@
|
|
|
1
|
+
import { ordersSettings } from '@unchainedshop/core-orders';
|
|
1
2
|
import { QuotationStatus } from '@unchainedshop/core-quotations';
|
|
2
3
|
import { QuotationDirector } from "../directors/QuotationDirector.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const { orderId, quotationId, quantity, configuration, user, countryCode, context } = params;
|
|
8
|
-
if (quantity < 1) {
|
|
9
|
-
throw new OrderQuantityTooLowError({ quantity });
|
|
10
|
-
}
|
|
11
|
-
const quotation = await this.quotations.findQuotation({ quotationId });
|
|
12
|
-
if (!quotation) {
|
|
13
|
-
throw new QuotationNotFoundError({ quotationId });
|
|
14
|
-
}
|
|
4
|
+
import { createServiceError } from "../errors.js";
|
|
5
|
+
import { isQuotationReserved } from "./reserveOrderQuotationsForCheckout.js";
|
|
6
|
+
export async function addCartQuotationService({ order, quotation, quantity, configuration, }, unchainedAPI = {}) {
|
|
7
|
+
const context = { ...unchainedAPI, modules: this };
|
|
15
8
|
if (quotation.status !== QuotationStatus.PROPOSED) {
|
|
16
|
-
throw
|
|
9
|
+
throw createServiceError('QuotationWrongStatusError', `Quotation ${quotation._id} is ${quotation.status}, not PROPOSED`);
|
|
17
10
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
user,
|
|
21
|
-
countryCode,
|
|
22
|
-
});
|
|
23
|
-
if (!order) {
|
|
24
|
-
throw new OrderNotFoundError({ orderId: orderId || null });
|
|
11
|
+
if (quotation.currencyCode !== order.currencyCode) {
|
|
12
|
+
throw createServiceError('QuotationInvalidError', `Quotation ${quotation._id} is not in the currency of order ${order._id}`);
|
|
25
13
|
}
|
|
26
|
-
if (
|
|
27
|
-
throw
|
|
14
|
+
if (await isQuotationReserved.call(this, quotation._id, { exceptOrderId: order._id })) {
|
|
15
|
+
throw createServiceError('QuotationInvalidError', `Quotation ${quotation._id} is reserved by another order`);
|
|
28
16
|
}
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
const product = await this.products.findProduct({ productId: quotation.productId });
|
|
18
|
+
if (!product) {
|
|
19
|
+
throw createServiceError('ProductNotFoundError', `Product not found: ${quotation.productId}`);
|
|
31
20
|
}
|
|
21
|
+
const existingPosition = (await this.orders.positions.findOrderPositions({ orderId: order._id })).find((position) => position.quotationId === quotation._id);
|
|
22
|
+
const existingQuantity = existingPosition?.quantity || 0;
|
|
23
|
+
const requestedQuantity = existingQuantity + (quantity ?? quotation.quantity ?? 1);
|
|
32
24
|
const director = await QuotationDirector.actions({ quotation }, context);
|
|
33
25
|
const quotationConfiguration = await director.transformItemConfiguration({
|
|
34
|
-
quantity,
|
|
35
|
-
configuration,
|
|
26
|
+
quantity: requestedQuantity,
|
|
27
|
+
configuration: configuration ?? existingPosition?.configuration ?? [],
|
|
36
28
|
});
|
|
37
29
|
if (!quotationConfiguration) {
|
|
38
|
-
throw
|
|
30
|
+
throw createServiceError('QuotationItemConfigurationError', `Quotation ${quotation._id} does not take quantity ${requestedQuantity}`);
|
|
39
31
|
}
|
|
40
|
-
const
|
|
41
|
-
|
|
32
|
+
const lineQuantity = quotationConfiguration.quantity || requestedQuantity;
|
|
33
|
+
await ordersSettings.validateOrderPosition({
|
|
34
|
+
order,
|
|
35
|
+
product,
|
|
42
36
|
configuration: quotationConfiguration.configuration,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
37
|
+
quantityDiff: lineQuantity - existingQuantity,
|
|
38
|
+
}, context);
|
|
39
|
+
const position = existingPosition
|
|
40
|
+
? await this.orders.positions.updateProductItem({
|
|
41
|
+
orderPositionId: existingPosition._id,
|
|
42
|
+
quantity: lineQuantity,
|
|
43
|
+
configuration: quotationConfiguration.configuration ?? null,
|
|
44
|
+
})
|
|
45
|
+
: await this.orders.positions.addProductItem({
|
|
46
|
+
quantity: lineQuantity,
|
|
47
|
+
configuration: quotationConfiguration.configuration,
|
|
48
|
+
quotationId: quotation._id,
|
|
49
|
+
productId: quotation.productId,
|
|
50
|
+
originalProductId: quotation.productId,
|
|
51
|
+
orderId: order._id,
|
|
52
|
+
});
|
|
53
|
+
if (!position) {
|
|
54
|
+
throw createServiceError('OrderItemNotFoundError', `Order item not found: ${existingPosition?._id}`);
|
|
55
|
+
}
|
|
56
|
+
return position;
|
|
52
57
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { Order, OrderDiscount } from '@unchainedshop/core-orders';
|
|
2
2
|
import type { Modules } from '../modules.ts';
|
|
3
|
-
export declare function calculateDiscountTotalService(this: Modules, order: Order, orderDiscount: OrderDiscount
|
|
3
|
+
export declare function calculateDiscountTotalService(this: Modules, order: Order, orderDiscount: OrderDiscount, { useNetPrice }?: {
|
|
4
|
+
useNetPrice?: boolean;
|
|
5
|
+
}): Promise<{
|
|
4
6
|
amount: number;
|
|
5
7
|
currencyCode: string;
|
|
8
|
+
isTaxable: boolean;
|
|
9
|
+
isNetPrice: boolean;
|
|
6
10
|
}>;
|