@unchainedshop/plugins 2.2.3 → 2.3.0
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/payment/cryptopay/plugin.js +3 -2
- package/lib/payment/cryptopay/plugin.js.map +1 -1
- package/lib/payment/postfinance-checkout/types.js +2 -2
- package/lib/payment/postfinance-checkout/types.js.map +1 -1
- package/lib/pricing/order-discount.d.ts +2 -10
- package/lib/pricing/order-discount.js +12 -47
- package/lib/pricing/order-discount.js.map +1 -1
- package/lib/pricing/order-items-discount.js +3 -37
- package/lib/pricing/order-items-discount.js.map +1 -1
- package/lib/pricing/product-discount.d.ts +1 -2
- package/lib/pricing/product-discount.js +2 -5
- package/lib/pricing/product-discount.js.map +1 -1
- package/lib/pricing/product-price-round.d.ts +0 -1
- package/lib/pricing/product-price-round.js +2 -2
- package/lib/pricing/product-price-round.js.map +1 -1
- package/lib/warehousing/google-sheets.js +2 -2
- package/lib/warehousing/google-sheets.js.map +1 -1
- package/lib/worker/email.js +2 -2
- package/lib/worker/email.js.map +1 -1
- package/lib/worker/sms.js +7 -0
- package/lib/worker/sms.js.map +1 -1
- package/lib/worker/update-token-ownership.js +1 -1
- package/lib/worker/update-token-ownership.js.map +1 -1
- package/package.json +29 -26
- package/src/payment/cryptopay/plugin.ts +5 -3
- package/src/pricing/configureProductPriceRounding.test.ts +0 -2
- package/src/pricing/free-delivery.test.ts +1 -1
- package/src/pricing/order-delivery.test.ts +1 -1
- package/src/pricing/order-discount.test.ts +4 -203
- package/src/pricing/order-discount.ts +21 -65
- package/src/pricing/order-items-discount.ts +4 -45
- package/src/pricing/product-discount.ts +3 -6
- package/src/pricing/product-price-round.ts +2 -4
- package/src/warehousing/google-sheets.ts +2 -2
- package/src/worker/email.ts +2 -2
- package/src/worker/sms.ts +8 -0
- package/src/worker/update-token-ownership.ts +1 -1
- package/tsconfig.json +3 -7
- package/src/pricing/apply-rate.test.ts +0 -92
- package/src/pricing/getTaxRate.test.ts +0 -69
- package/src/pricing/roundToNext.test.ts +0 -24
|
@@ -1,206 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OrderDiscount } from "./order-discount.js";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
describe("resolveRatioAndTaxDivisorForPricingSheet", () => {
|
|
7
|
-
it('total is 0 and pricing is not provided', () => {
|
|
8
|
-
const result = resolveRatioAndTaxDivisorForPricingSheet(null, 0);
|
|
9
|
-
expect(result).toEqual({ ratio: 1, taxDivisor: 1 });
|
|
10
|
-
});
|
|
11
|
-
it('total is not 0 and pricing is not provided', () => {
|
|
12
|
-
const result = resolveRatioAndTaxDivisorForPricingSheet(null, 10);
|
|
13
|
-
expect(result).toEqual({ ratio: 1, taxDivisor: 1 });
|
|
14
|
-
});
|
|
15
|
-
it('total is 0 and pricing is provided', () => {
|
|
16
|
-
const pricing = {
|
|
17
|
-
taxSum: () => 10,
|
|
18
|
-
gross: () => 20,
|
|
19
|
-
};
|
|
20
|
-
const result = resolveRatioAndTaxDivisorForPricingSheet(pricing, 0);
|
|
21
|
-
expect(result).toEqual({ ratio: 1, taxDivisor: 1 });
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('gross - tax is 0', () => {
|
|
25
|
-
const pricing = {
|
|
26
|
-
taxSum: () => 10,
|
|
27
|
-
gross: () => 10,
|
|
28
|
-
};
|
|
29
|
-
const result = resolveRatioAndTaxDivisorForPricingSheet(pricing, 20);
|
|
30
|
-
expect(result).toEqual({ ratio: 0, taxDivisor: 0 });
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('gross - tax is not 0', () => {
|
|
34
|
-
const pricing = {
|
|
35
|
-
taxSum: () => 10,
|
|
36
|
-
gross: () => 20,
|
|
37
|
-
};
|
|
38
|
-
const result = resolveRatioAndTaxDivisorForPricingSheet(pricing, 20);
|
|
39
|
-
expect(result).toEqual({ ratio: 1, taxDivisor: 2 });
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('taxSum is 0', () => {
|
|
43
|
-
const pricing = {
|
|
44
|
-
taxSum: () => 0,
|
|
45
|
-
gross: () => 20,
|
|
46
|
-
};
|
|
47
|
-
const result = resolveRatioAndTaxDivisorForPricingSheet(pricing, 20);
|
|
48
|
-
expect(result).toEqual({ ratio: 1, taxDivisor: 1 });
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
describe("resolveAmountAndTax", () => {
|
|
56
|
-
|
|
57
|
-
it('ratio is 0 and taxDivisor is 0', () => {
|
|
58
|
-
const result = resolveAmountAndTax({ ratio: 0, taxDivisor: 0 }, 100);
|
|
59
|
-
expect(result).toEqual([0, 0]);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('ratio is not 0 and taxDivisor is 0', () => {
|
|
63
|
-
const result = resolveAmountAndTax({ ratio: 0.5, taxDivisor: 0 }, 100);
|
|
64
|
-
expect(result).toEqual([50, 0]);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('ratio is 0 and taxDivisor is not 0', () => {
|
|
68
|
-
const result = resolveAmountAndTax({ ratio: 0, taxDivisor: 2 }, 100);
|
|
69
|
-
expect(result).toEqual([0, 0]);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
it('ratio and taxDivisor are not 0', () => {
|
|
74
|
-
const result = resolveAmountAndTax({ ratio: 0.5, taxDivisor: 2 }, 100);
|
|
75
|
-
expect(result).toEqual([50, 25]);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('ratio and taxDivisor are not finite number', () => {
|
|
79
|
-
const result = resolveAmountAndTax({ ratio: Number.NaN, taxDivisor: Number.NaN }, 100);
|
|
80
|
-
expect(result).toEqual([0, 0]);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
describe("resolveAmountAndTax", () => {
|
|
88
|
-
it('shares are empty', () => {
|
|
89
|
-
const result = applyDiscountToMultipleShares([], 100);
|
|
90
|
-
expect(result).toEqual([0, 0]);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('shares have one share', () => {
|
|
94
|
-
const shares = [{ ratio: 0.5, taxDivisor: 2 }];
|
|
95
|
-
const result = applyDiscountToMultipleShares(shares, 100);
|
|
96
|
-
expect(result).toEqual([50, 25]);
|
|
3
|
+
describe("OrderDelivery ", () => {
|
|
4
|
+
it('isActivatedFor', () => {
|
|
5
|
+
expect(OrderDiscount.isActivatedFor({} as any)).toBeTruthy();
|
|
97
6
|
});
|
|
98
|
-
|
|
99
|
-
it('shares have multiple shares', () => {
|
|
100
|
-
const shares = [
|
|
101
|
-
{ ratio: 0.5, taxDivisor: 2 },
|
|
102
|
-
{ ratio: 0.2, taxDivisor: 1.5 },
|
|
103
|
-
];
|
|
104
|
-
const result = applyDiscountToMultipleShares(shares, 100);
|
|
105
|
-
expect(result).toEqual([70, 31.666666666666664]);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
7
|
})
|
|
109
|
-
|
|
110
|
-
describe('calculateAmountToSplit', () => {
|
|
111
|
-
it('calculates the correct amount to split when using a rate', () => {
|
|
112
|
-
const configuration = {
|
|
113
|
-
rate: 0.1,
|
|
114
|
-
alreadyDeductedForDiscount: 0,
|
|
115
|
-
amountLeft: 100,
|
|
116
|
-
};
|
|
117
|
-
const amount = 1000;
|
|
118
|
-
expect(calculateAmountToSplit(configuration, amount)).toBe(100);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('calculates the correct amount to split when using a fixed rate', () => {
|
|
122
|
-
const configuration = {
|
|
123
|
-
fixedRate: 50,
|
|
124
|
-
alreadyDeductedForDiscount: 0,
|
|
125
|
-
amountLeft: 100,
|
|
126
|
-
};
|
|
127
|
-
const amount = 1000;
|
|
128
|
-
expect(calculateAmountToSplit(configuration, amount)).toBe(50);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('calculates the correct amount to split when alreadyDeductedForDiscount is non-zero', () => {
|
|
132
|
-
const configuration = {
|
|
133
|
-
rate: 0.1,
|
|
134
|
-
alreadyDeductedForDiscount: 10,
|
|
135
|
-
amountLeft: 100,
|
|
136
|
-
};
|
|
137
|
-
const amount = 1000;
|
|
138
|
-
expect(calculateAmountToSplit(configuration, amount)).toBe(90);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
it('calculates the correct amount to split when amountLeft is less than the amount to deduct', () => {
|
|
143
|
-
const configuration = {
|
|
144
|
-
rate: 0.1,
|
|
145
|
-
alreadyDeductedForDiscount: 0,
|
|
146
|
-
amountLeft: 50,
|
|
147
|
-
};
|
|
148
|
-
const amount = 1000;
|
|
149
|
-
expect(calculateAmountToSplit(configuration, amount)).toBe(50);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('returns 0 when the amount to deduct is less than or equal to alreadyDeductedForDiscount', () => {
|
|
153
|
-
const configuration = {
|
|
154
|
-
rate: 0.1,
|
|
155
|
-
alreadyDeductedForDiscount: 100,
|
|
156
|
-
amountLeft: 100,
|
|
157
|
-
};
|
|
158
|
-
const amount = 1000;
|
|
159
|
-
expect(calculateAmountToSplit(configuration, amount)).toBe(0);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('returns 0 when the amount is less than or equal to 0', () => {
|
|
163
|
-
const configuration = {
|
|
164
|
-
rate: 0.1,
|
|
165
|
-
alreadyDeductedForDiscount: 0,
|
|
166
|
-
amountLeft: 100,
|
|
167
|
-
};
|
|
168
|
-
const amount = 0;
|
|
169
|
-
expect(calculateAmountToSplit(configuration, amount)).toBe(0);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it('returns 0 when amountLeft is 0', () => {
|
|
173
|
-
const configuration = {
|
|
174
|
-
rate: 0.1,
|
|
175
|
-
alreadyDeductedForDiscount: 0,
|
|
176
|
-
amountLeft: 0,
|
|
177
|
-
};
|
|
178
|
-
const amount = 1000;
|
|
179
|
-
expect(calculateAmountToSplit(configuration, amount)).toBe(0);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('returns 0 when amount is negative', () => {
|
|
183
|
-
const configuration = {
|
|
184
|
-
rate: 0.1,
|
|
185
|
-
alreadyDeductedForDiscount: 0,
|
|
186
|
-
amountLeft: 100,
|
|
187
|
-
};
|
|
188
|
-
const amount = -1000;
|
|
189
|
-
expect(calculateAmountToSplit(configuration, amount)).toBe(0);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it('returns 0 when configuration rate is negative', () => {
|
|
193
|
-
const configuration = {
|
|
194
|
-
rate: -0.1,
|
|
195
|
-
alreadyDeductedForDiscount: 0,
|
|
196
|
-
amountLeft: 100,
|
|
197
|
-
};
|
|
198
|
-
const amount = 1000;
|
|
199
|
-
expect(calculateAmountToSplit(configuration, amount)).toBe(0);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
})
|
|
@@ -1,55 +1,8 @@
|
|
|
1
1
|
import { IOrderPricingAdapter, OrderPricingRowCategory } from '@unchainedshop/types/orders.pricing.js';
|
|
2
2
|
import { OrderPricingDirector, OrderPricingAdapter } from '@unchainedshop/core-orders';
|
|
3
|
+
import { calculation as calcUtils } from '@unchainedshop/utils';
|
|
3
4
|
|
|
4
|
-
export const
|
|
5
|
-
if (total === 0 || !pricing) {
|
|
6
|
-
return {
|
|
7
|
-
ratio: 1,
|
|
8
|
-
taxDivisor: 1,
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
const tax = pricing.taxSum();
|
|
12
|
-
const gross = pricing.gross();
|
|
13
|
-
if (gross - tax === 0) {
|
|
14
|
-
return {
|
|
15
|
-
ratio: 0,
|
|
16
|
-
taxDivisor: 0,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
return {
|
|
20
|
-
ratio: gross / total,
|
|
21
|
-
taxDivisor: gross / (gross - tax),
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const resolveAmountAndTax = ({ ratio, taxDivisor }, amount) => {
|
|
26
|
-
const shareAmount = Number.isFinite(ratio) ? amount * ratio : 0;
|
|
27
|
-
const shareTaxAmount =
|
|
28
|
-
Number.isFinite(taxDivisor) && taxDivisor !== 0 ? shareAmount - shareAmount / taxDivisor : 0;
|
|
29
|
-
return [shareAmount, shareTaxAmount];
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// TODO: move to separate file because its used in multiple places
|
|
33
|
-
|
|
34
|
-
export const applyDiscountToMultipleShares = (shares, amount) => {
|
|
35
|
-
return shares.reduce(
|
|
36
|
-
([currentDiscountAmount, currentTaxAmount], share) => {
|
|
37
|
-
const [shareAmount, shareTaxAmount] = resolveAmountAndTax(share, amount);
|
|
38
|
-
return [currentDiscountAmount + shareAmount, currentTaxAmount + shareTaxAmount];
|
|
39
|
-
},
|
|
40
|
-
[0, 0],
|
|
41
|
-
);
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const calculateAmountToSplit = (configuration, amount) => {
|
|
45
|
-
const deductionAmount = configuration.rate ? amount * configuration.rate : configuration.fixedRate;
|
|
46
|
-
|
|
47
|
-
const leftInDiscount = Math.max(0, deductionAmount - (configuration.alreadyDeductedForDiscount || 0));
|
|
48
|
-
const leftToDeduct = Math.min(configuration.amountLeft, leftInDiscount);
|
|
49
|
-
return Math.max(0, leftToDeduct);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const OrderDiscount: IOrderPricingAdapter = {
|
|
5
|
+
export const OrderDiscount: IOrderPricingAdapter = {
|
|
53
6
|
...OrderPricingAdapter,
|
|
54
7
|
|
|
55
8
|
key: 'shop.unchained.pricing.order-discount',
|
|
@@ -84,18 +37,18 @@ const OrderDiscount: IOrderPricingAdapter = {
|
|
|
84
37
|
});
|
|
85
38
|
|
|
86
39
|
const itemShares = orderPositions.map((orderPosition) =>
|
|
87
|
-
resolveRatioAndTaxDivisorForPricingSheet(
|
|
40
|
+
calcUtils.resolveRatioAndTaxDivisorForPricingSheet(
|
|
88
41
|
modules.orders.positions.pricingSheet(orderPosition, order.currency, params.context),
|
|
89
42
|
totalAmountOfItems,
|
|
90
43
|
),
|
|
91
44
|
);
|
|
92
45
|
|
|
93
|
-
const deliveryShare = resolveRatioAndTaxDivisorForPricingSheet(
|
|
46
|
+
const deliveryShare = calcUtils.resolveRatioAndTaxDivisorForPricingSheet(
|
|
94
47
|
orderDelivery &&
|
|
95
48
|
modules.orders.deliveries.pricingSheet(orderDelivery, order.currency, params.context),
|
|
96
49
|
totalAmountOfPaymentAndDelivery,
|
|
97
50
|
);
|
|
98
|
-
const paymentShare = resolveRatioAndTaxDivisorForPricingSheet(
|
|
51
|
+
const paymentShare = calcUtils.resolveRatioAndTaxDivisorForPricingSheet(
|
|
99
52
|
orderPayment &&
|
|
100
53
|
modules.orders.payments.pricingSheet(orderPayment, order.currency, params.context),
|
|
101
54
|
totalAmountOfPaymentAndDelivery,
|
|
@@ -105,28 +58,31 @@ const OrderDiscount: IOrderPricingAdapter = {
|
|
|
105
58
|
|
|
106
59
|
params.discounts.forEach(({ configuration, discountId }) => {
|
|
107
60
|
// First, we deduce the discount from the items
|
|
108
|
-
let
|
|
109
|
-
|
|
61
|
+
let alreadyDeducted = 0;
|
|
62
|
+
|
|
63
|
+
const leftInDiscountToSplit = calcUtils.calculateAmountToSplit(
|
|
64
|
+
{ ...configuration, alreadyDeducted },
|
|
65
|
+
totalAmountOfItems,
|
|
66
|
+
);
|
|
67
|
+
const [itemsDiscountAmount, itemsTaxAmount] = calcUtils.applyDiscountToMultipleShares(
|
|
110
68
|
itemShares,
|
|
111
|
-
|
|
112
|
-
{ ...configuration, amountLeft, alreadyDeductedForDiscount },
|
|
113
|
-
totalAmountOfItems,
|
|
114
|
-
),
|
|
69
|
+
Math.max(0, Math.min(amountLeft, leftInDiscountToSplit)),
|
|
115
70
|
);
|
|
116
71
|
amountLeft -= itemsDiscountAmount;
|
|
117
|
-
|
|
72
|
+
alreadyDeducted += itemsDiscountAmount;
|
|
118
73
|
|
|
119
74
|
// After the items, we deduct the remaining discount from payment & delivery fees
|
|
75
|
+
const leftInFeesToSplit = calcUtils.calculateAmountToSplit(
|
|
76
|
+
{ ...configuration, alreadyDeducted },
|
|
77
|
+
totalAmountOfPaymentAndDelivery,
|
|
78
|
+
);
|
|
120
79
|
const [deliveryAndPaymentDiscountAmount, deliveryAndPaymentTaxAmount] =
|
|
121
|
-
applyDiscountToMultipleShares(
|
|
80
|
+
calcUtils.applyDiscountToMultipleShares(
|
|
122
81
|
[deliveryShare, paymentShare],
|
|
123
|
-
|
|
124
|
-
{ ...configuration, amountLeft, alreadyDeductedForDiscount },
|
|
125
|
-
totalAmountOfPaymentAndDelivery,
|
|
126
|
-
),
|
|
82
|
+
Math.max(0, Math.min(amountLeft, leftInFeesToSplit)),
|
|
127
83
|
);
|
|
128
84
|
amountLeft -= deliveryAndPaymentDiscountAmount;
|
|
129
|
-
|
|
85
|
+
alreadyDeducted += itemsDiscountAmount;
|
|
130
86
|
|
|
131
87
|
const discountAmount = itemsDiscountAmount + deliveryAndPaymentDiscountAmount;
|
|
132
88
|
const taxAmount = itemsTaxAmount + deliveryAndPaymentTaxAmount;
|
|
@@ -1,47 +1,6 @@
|
|
|
1
1
|
import { IOrderPricingAdapter, OrderPricingRowCategory } from '@unchainedshop/types/orders.pricing.js';
|
|
2
2
|
import { OrderPricingDirector, OrderPricingAdapter } from '@unchainedshop/core-orders';
|
|
3
|
-
|
|
4
|
-
const resolveRatioAndTaxDivisorForPricingSheet = (pricing, total) => {
|
|
5
|
-
if (total === 0 || !pricing) {
|
|
6
|
-
return {
|
|
7
|
-
ratio: 1,
|
|
8
|
-
taxDivisor: 1,
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
const tax = pricing.taxSum();
|
|
12
|
-
const gross = pricing.gross();
|
|
13
|
-
return {
|
|
14
|
-
ratio: gross / total,
|
|
15
|
-
taxDivisor: gross / (gross - tax),
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// TODO: move into separate file and share multiple places
|
|
20
|
-
const resolveAmountAndTax = ({ ratio, taxDivisor }, amount) => {
|
|
21
|
-
const shareAmount = Number.isFinite(ratio) ? amount * ratio : 0;
|
|
22
|
-
const shareTaxAmount = Number.isFinite(taxDivisor) ? shareAmount - shareAmount / taxDivisor : 0;
|
|
23
|
-
return [shareAmount, shareTaxAmount];
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
// TODO: move into separate file and share multiple places
|
|
27
|
-
const applyDiscountToMultipleShares = (shares, amount) => {
|
|
28
|
-
return shares.reduce(
|
|
29
|
-
([currentDiscountAmount, currentTaxAmount], share) => {
|
|
30
|
-
const [shareAmount, shareTaxAmount] = resolveAmountAndTax(share, amount);
|
|
31
|
-
return [currentDiscountAmount + shareAmount, currentTaxAmount + shareTaxAmount];
|
|
32
|
-
},
|
|
33
|
-
[0, 0],
|
|
34
|
-
);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// TODO: move into separate file and share multiple places
|
|
38
|
-
const calculateAmountToSplit = (configuration, amount) => {
|
|
39
|
-
const deductionAmount = configuration.rate
|
|
40
|
-
? amount * configuration.rate
|
|
41
|
-
: Math.min(configuration.fixedRate, amount);
|
|
42
|
-
|
|
43
|
-
return Math.max(0, deductionAmount - (configuration.alreadyDeducted || 0));
|
|
44
|
-
};
|
|
3
|
+
import { calculation as calcUtils } from '@unchainedshop/utils';
|
|
45
4
|
|
|
46
5
|
const OrderItemsDiscount: IOrderPricingAdapter = {
|
|
47
6
|
...OrderPricingAdapter,
|
|
@@ -72,7 +31,7 @@ const OrderItemsDiscount: IOrderPricingAdapter = {
|
|
|
72
31
|
});
|
|
73
32
|
|
|
74
33
|
const itemShares = orderPositions.map((orderPosition) =>
|
|
75
|
-
resolveRatioAndTaxDivisorForPricingSheet(
|
|
34
|
+
calcUtils.resolveRatioAndTaxDivisorForPricingSheet(
|
|
76
35
|
modules.orders.positions.pricingSheet(orderPosition, order.currency, params.context),
|
|
77
36
|
totalAmountOfItems,
|
|
78
37
|
),
|
|
@@ -82,9 +41,9 @@ const OrderItemsDiscount: IOrderPricingAdapter = {
|
|
|
82
41
|
|
|
83
42
|
params.discounts.forEach(({ configuration, discountId }) => {
|
|
84
43
|
// First, we deduce the discount from the items
|
|
85
|
-
const [itemsDiscountAmount, itemsTaxAmount] = applyDiscountToMultipleShares(
|
|
44
|
+
const [itemsDiscountAmount, itemsTaxAmount] = calcUtils.applyDiscountToMultipleShares(
|
|
86
45
|
itemShares,
|
|
87
|
-
calculateAmountToSplit({ ...configuration, alreadyDeducted }, totalAmountOfItems),
|
|
46
|
+
calcUtils.calculateAmountToSplit({ ...configuration, alreadyDeducted }, totalAmountOfItems),
|
|
88
47
|
);
|
|
89
48
|
alreadyDeducted = +itemsDiscountAmount;
|
|
90
49
|
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import type { Discount
|
|
1
|
+
import type { Discount } from '@unchainedshop/types/discount.js';
|
|
2
2
|
import {
|
|
3
3
|
IProductPricingAdapter,
|
|
4
4
|
ProductPricingRowCategory,
|
|
5
5
|
} from '@unchainedshop/types/products.pricing.js';
|
|
6
6
|
import { ProductPricingDirector, ProductPricingAdapter } from '@unchainedshop/core-products';
|
|
7
|
+
import { calculation as calcUtils } from '@unchainedshop/utils';
|
|
7
8
|
|
|
8
|
-
export const applyRate = (configuration: DiscountConfiguration, amount) => {
|
|
9
|
-
const { rate, fixedRate } = configuration;
|
|
10
|
-
return rate ? amount * rate : Math.min(fixedRate || 0, amount);
|
|
11
|
-
};
|
|
12
9
|
const ProductDiscount: IProductPricingAdapter = {
|
|
13
10
|
...ProductPricingAdapter,
|
|
14
11
|
|
|
@@ -27,7 +24,7 @@ const ProductDiscount: IProductPricingAdapter = {
|
|
|
27
24
|
const addDiscount = (discount: Discount, total: number, isTaxable: boolean) => {
|
|
28
25
|
const { configuration, discountId } = discount;
|
|
29
26
|
const { isNetPrice = false, ...meta } = configuration;
|
|
30
|
-
const amount = applyRate(configuration, total);
|
|
27
|
+
const amount = calcUtils.applyRate(configuration, total);
|
|
31
28
|
|
|
32
29
|
pricingAdapter.resultSheet().addDiscount({
|
|
33
30
|
amount: amount * -1,
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { IProductPricingAdapter } from '@unchainedshop/types/products.pricing.js';
|
|
2
2
|
import { ProductPricingAdapter, ProductPricingDirector } from '@unchainedshop/core-products';
|
|
3
|
+
import { calculation as calcUtils } from '@unchainedshop/utils';
|
|
3
4
|
|
|
4
|
-
export const roundToNext = (value, precision) => Math.ceil(value / precision) * precision;
|
|
5
|
-
// TODO: Move to types
|
|
6
|
-
// String is referencing to a currency
|
|
7
5
|
interface PriceRoundSettings {
|
|
8
6
|
configurations: Record<string, number>;
|
|
9
7
|
defaultPrecision: number;
|
|
@@ -61,7 +59,7 @@ export const ProductPriceRound: IProductPricingAdapter & {
|
|
|
61
59
|
const [productPrice] = calculation;
|
|
62
60
|
pricingAdapter.resultSheet().resetCalculation(params.calculationSheet);
|
|
63
61
|
pricingAdapter.resultSheet().addItem({
|
|
64
|
-
amount: roundToNext(productPrice.amount, roundPrecision) * quantity,
|
|
62
|
+
amount: calcUtils.roundToNext(productPrice.amount, roundPrecision) * quantity,
|
|
65
63
|
isTaxable: productPrice.isTaxable,
|
|
66
64
|
isNetPrice: productPrice.isNetPrice,
|
|
67
65
|
meta: { adapter: ProductPriceRound.key },
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import Sheets from 'node-sheets';
|
|
7
7
|
import { log, LogLevel } from '@unchainedshop/logger';
|
|
8
8
|
import 'abort-controller/polyfill.js';
|
|
9
|
-
import
|
|
9
|
+
import { LRUCache } from 'lru-cache';
|
|
10
10
|
import { IWarehousingAdapter } from '@unchainedshop/types/warehousing.js';
|
|
11
11
|
|
|
12
12
|
const { NODE_ENV, GOOGLE_SHEETS_ID, GOOGLE_SHEETS_PRIVATE_KEY_DATA } = process.env;
|
|
@@ -48,7 +48,7 @@ const updateGoogleCache = async (cache) => {
|
|
|
48
48
|
return null;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
const googleCache = new
|
|
51
|
+
const googleCache = new LRUCache({
|
|
52
52
|
max: 500,
|
|
53
53
|
ttl, // 1 second in dev
|
|
54
54
|
allowStale: true,
|
package/src/worker/email.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { WorkerDirector, WorkerAdapter } from '@unchainedshop/core-worker';
|
|
|
2
2
|
import { createLogger } from '@unchainedshop/logger';
|
|
3
3
|
import { IWorkerAdapter } from '@unchainedshop/types/worker.js';
|
|
4
4
|
import fs from 'fs';
|
|
5
|
-
import { join } from 'path';
|
|
5
|
+
import { join, isAbsolute } from 'path';
|
|
6
6
|
import os from 'os';
|
|
7
7
|
import open from 'open';
|
|
8
8
|
import nodemailer from 'nodemailer';
|
|
@@ -15,7 +15,7 @@ export const checkEmailInterceptionEnabled = () => {
|
|
|
15
15
|
|
|
16
16
|
const buildLink = ({ filename, content, href, contentType, encoding, path }) => {
|
|
17
17
|
if (path) {
|
|
18
|
-
return `<a href="${join(process.cwd(), path)}">${filename}</a>`;
|
|
18
|
+
return `<a href="${isAbsolute(path) ? path : join(process.cwd(), path)}">${filename}</a>`;
|
|
19
19
|
}
|
|
20
20
|
if (href) {
|
|
21
21
|
return `<a href="${href}">${filename}</a>`;
|
package/src/worker/sms.ts
CHANGED
|
@@ -7,6 +7,14 @@ const { TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_SMS_FROM } = process.env;
|
|
|
7
7
|
|
|
8
8
|
const logger = createLogger('unchained:plugins:worker:sms');
|
|
9
9
|
|
|
10
|
+
/* Potential: no need for twilio npm
|
|
11
|
+
curl -X POST "https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/Messages.json" \
|
|
12
|
+
--data-urlencode "From=+15017122661" \
|
|
13
|
+
--data-urlencode "Body=Hi there" \
|
|
14
|
+
--data-urlencode "To=+15558675310" \
|
|
15
|
+
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
|
|
16
|
+
*/
|
|
17
|
+
|
|
10
18
|
const SmsWorkerPlugin: IWorkerAdapter<
|
|
11
19
|
{
|
|
12
20
|
from?: string;
|
|
@@ -32,7 +32,7 @@ export const RefreshTokens: IWorkerAdapter<void, any> = {
|
|
|
32
32
|
const { modules } = unchainedAPI;
|
|
33
33
|
|
|
34
34
|
const tokens = await modules.warehousing.findTokens({});
|
|
35
|
-
const users = await modules.users.findUsers({ includeGuests: true });
|
|
35
|
+
const users = await modules.users.findUsers({ includeGuests: true, 'services.web3.verified': true });
|
|
36
36
|
const accounts = users.flatMap((user) => {
|
|
37
37
|
return user?.services?.web3?.flatMap((service) => {
|
|
38
38
|
if (service.verified) return [service.address];
|
package/tsconfig.json
CHANGED
|
@@ -4,13 +4,9 @@
|
|
|
4
4
|
"rootDir": "src",
|
|
5
5
|
"outDir": "lib",
|
|
6
6
|
"paths": {
|
|
7
|
-
"postfinancecheckout": [
|
|
8
|
-
"./src/payment/postfinance-checkout/silence-postfinancecheckout.d.ts"
|
|
9
|
-
],
|
|
7
|
+
"postfinancecheckout": ["./src/payment/postfinance-checkout/silence-postfinancecheckout.d.ts"]
|
|
10
8
|
}
|
|
11
9
|
},
|
|
12
10
|
"exclude": ["**/*.test.ts", "**/*.test.js", "tests"],
|
|
13
|
-
"include": [
|
|
14
|
-
|
|
15
|
-
]
|
|
16
|
-
}
|
|
11
|
+
"include": ["./src", "../utils/src/roundToNext.test.ts"]
|
|
12
|
+
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import {applyRate} from './product-discount.js'
|
|
2
|
-
describe('applyRate', () => {
|
|
3
|
-
it('applies the rate correctly when a rate is provided', () => {
|
|
4
|
-
const configuration = {
|
|
5
|
-
rate: 0.1
|
|
6
|
-
};
|
|
7
|
-
const amount = 100;
|
|
8
|
-
expect(applyRate(configuration, amount)).toBe(10);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('applies the fixed rate correctly when a fixed rate is provided', () => {
|
|
12
|
-
const configuration = {
|
|
13
|
-
fixedRate: 50
|
|
14
|
-
};
|
|
15
|
-
const amount = 100;
|
|
16
|
-
expect(applyRate(configuration, amount)).toBe(50);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('applies the fixed rate correctly when a fixed rate is provided and the amount is less than fixed rate', () => {
|
|
20
|
-
const configuration = {
|
|
21
|
-
fixedRate: 150
|
|
22
|
-
};
|
|
23
|
-
const amount = 100;
|
|
24
|
-
expect(applyRate(configuration, amount)).toBe(100);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('applies the rate correctly when rate is less than or equal to 0', () => {
|
|
28
|
-
const configuration = {
|
|
29
|
-
rate: -0.1
|
|
30
|
-
};
|
|
31
|
-
const amount = 100;
|
|
32
|
-
expect(applyRate(configuration, amount)).toBe(-10);
|
|
33
|
-
});
|
|
34
|
-
it('applies the rate correctly when only rate is provided and amount is negative', () => {
|
|
35
|
-
const configuration = {
|
|
36
|
-
rate: 0.1
|
|
37
|
-
};
|
|
38
|
-
const amount = -100;
|
|
39
|
-
expect(applyRate(configuration, amount)).toBe(-10);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
it('applies the rate correctly when only rate is provided and amount is negative', () => {
|
|
44
|
-
const configuration = {
|
|
45
|
-
rate: 0.1
|
|
46
|
-
};
|
|
47
|
-
const amount = -100;
|
|
48
|
-
expect(applyRate(configuration, amount)).toBe(-10);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
it('applies the rate correctly when only rate is provided and amount is negative', () => {
|
|
53
|
-
const configuration = {
|
|
54
|
-
rate: 0.1
|
|
55
|
-
};
|
|
56
|
-
const amount = -100;
|
|
57
|
-
expect(applyRate(configuration, amount)).toBe(-10);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
it('applies the rate correctly when only rate is provided and amount is negative', () => {
|
|
63
|
-
const configuration = {
|
|
64
|
-
rate: 0.1
|
|
65
|
-
};
|
|
66
|
-
const amount = -100;
|
|
67
|
-
expect(applyRate(configuration, amount)).toBe(-10);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
it('returns 0 when rate and fixed rate are not provided', () => {
|
|
72
|
-
const configuration = {};
|
|
73
|
-
const amount = 100;
|
|
74
|
-
expect(applyRate(configuration, amount)).toBe(0);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('applies the rate correctly when only rate is provided and amount is negative', () => {
|
|
78
|
-
const configuration = {
|
|
79
|
-
rate: 0.1
|
|
80
|
-
};
|
|
81
|
-
const amount = -100;
|
|
82
|
-
expect(applyRate(configuration, amount)).toBe(-10);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('returns 0 when rate and fixed rate are not provided', () => {
|
|
86
|
-
const configuration = {};
|
|
87
|
-
const amount = 100;
|
|
88
|
-
expect(applyRate(configuration, amount)).toBe(0);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|