@unchainedshop/plugins 2.0.0-rc.3 → 2.0.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.
Files changed (236) hide show
  1. package/jest.config.js +12 -0
  2. package/lib/delivery/pick-mup.js +1 -1
  3. package/lib/delivery/pick-mup.js.map +1 -1
  4. package/lib/enrollments/licensed.d.ts +4 -1
  5. package/lib/enrollments/licensed.js +1 -1
  6. package/lib/enrollments/licensed.js.map +1 -1
  7. package/lib/files/gridfs/gridfs-adapter.d.ts +1 -1
  8. package/lib/files/gridfs/gridfs-adapter.js +1 -1
  9. package/lib/files/gridfs/gridfs-adapter.js.map +1 -1
  10. package/lib/files/gridfs/gridfs-webhook.js +1 -1
  11. package/lib/files/gridfs/gridfs-webhook.js.map +1 -1
  12. package/lib/files/gridfs/index.js +12 -3
  13. package/lib/files/gridfs/index.js.map +1 -1
  14. package/lib/files/minio/minio-adapter.d.ts +1 -1
  15. package/lib/files/minio/minio-adapter.js +1 -1
  16. package/lib/files/minio/minio-adapter.js.map +1 -1
  17. package/lib/filters/local-search.d.ts +1 -1
  18. package/lib/payment/apple-iap/db/AppleTransactionsCollection.d.ts +1 -1
  19. package/lib/payment/apple-iap/index.d.ts +2 -2
  20. package/lib/payment/apple-iap/index.js +2 -2
  21. package/lib/payment/apple-iap/index.js.map +1 -1
  22. package/lib/payment/apple-iap/module/configureAppleTransactionsModule.d.ts +2 -2
  23. package/lib/payment/apple-iap/module/configureAppleTransactionsModule.js +1 -1
  24. package/lib/payment/apple-iap/module/configureAppleTransactionsModule.js.map +1 -1
  25. package/lib/payment/cryptopay/db/CryptopayTransactions.d.ts +1 -1
  26. package/lib/payment/cryptopay/index.d.ts +3 -3
  27. package/lib/payment/cryptopay/index.js +3 -3
  28. package/lib/payment/cryptopay/index.js.map +1 -1
  29. package/lib/payment/cryptopay/module/configureCryptopayModule.d.ts +2 -2
  30. package/lib/payment/cryptopay/module/configureCryptopayModule.js +1 -1
  31. package/lib/payment/cryptopay/module/configureCryptopayModule.js.map +1 -1
  32. package/lib/payment/cryptopay/plugin.d.ts +1 -1
  33. package/lib/payment/cryptopay/plugin.js +1 -1
  34. package/lib/payment/cryptopay/plugin.js.map +1 -1
  35. package/lib/payment/datatrans-v2/api/authorize.d.ts +1 -1
  36. package/lib/payment/datatrans-v2/api/authorizeAuthenticated.d.ts +1 -1
  37. package/lib/payment/datatrans-v2/api/cancel.d.ts +1 -1
  38. package/lib/payment/datatrans-v2/api/index.d.ts +8 -8
  39. package/lib/payment/datatrans-v2/api/index.js +9 -9
  40. package/lib/payment/datatrans-v2/api/index.js.map +1 -1
  41. package/lib/payment/datatrans-v2/api/init.d.ts +1 -1
  42. package/lib/payment/datatrans-v2/api/init.js +1 -1
  43. package/lib/payment/datatrans-v2/api/init.js.map +1 -1
  44. package/lib/payment/datatrans-v2/api/secureFields.d.ts +1 -1
  45. package/lib/payment/datatrans-v2/api/secureFields.js +1 -1
  46. package/lib/payment/datatrans-v2/api/secureFields.js.map +1 -1
  47. package/lib/payment/datatrans-v2/api/settle.d.ts +1 -1
  48. package/lib/payment/datatrans-v2/api/status.d.ts +1 -1
  49. package/lib/payment/datatrans-v2/api/validate.d.ts +1 -1
  50. package/lib/payment/datatrans-v2/index.d.ts +1 -1
  51. package/lib/payment/datatrans-v2/index.js +4 -4
  52. package/lib/payment/datatrans-v2/index.js.map +1 -1
  53. package/lib/payment/datatrans-v2/middleware.js +1 -1
  54. package/lib/payment/datatrans-v2/middleware.js.map +1 -1
  55. package/lib/payment/datatrans-v2/parseRegistrationData.d.ts +4 -4
  56. package/lib/payment/datatrans-v2/parseRegistrationData.js +1 -1
  57. package/lib/payment/datatrans-v2/parseRegistrationData.js.map +1 -1
  58. package/lib/payment/datatrans-v2/roundedAmountFromOrder.d.ts +2 -2
  59. package/lib/payment/postfinance-checkout/index.d.ts +1 -1
  60. package/lib/payment/postfinance-checkout/index.js +4 -4
  61. package/lib/payment/postfinance-checkout/index.js.map +1 -1
  62. package/lib/payment/postfinance-checkout/middleware.js +1 -1
  63. package/lib/payment/postfinance-checkout/middleware.js.map +1 -1
  64. package/lib/payment/postfinance-checkout/types.js +2 -2
  65. package/lib/payment/postfinance-checkout/types.js.map +1 -1
  66. package/lib/payment/postfinance-checkout/utils.d.ts +1 -1
  67. package/lib/payment/worldline-saferpay/index.js +1 -1
  68. package/lib/payment/worldline-saferpay/index.js.map +1 -1
  69. package/lib/payment/worldline-saferpay/worldline-saferpay-client/api/SaferpayClient.d.ts +4 -4
  70. package/lib/payment/worldline-saferpay/worldline-saferpay-client/api/SaferpayClient.js +1 -1
  71. package/lib/payment/worldline-saferpay/worldline-saferpay-client/api/SaferpayClient.js.map +1 -1
  72. package/lib/payment/worldline-saferpay/worldline-saferpay-client/index.d.ts +4 -4
  73. package/lib/payment/worldline-saferpay/worldline-saferpay-client/index.js +1 -1
  74. package/lib/payment/worldline-saferpay/worldline-saferpay-client/index.js.map +1 -1
  75. package/lib/payment/worldline-saferpay/worldline-saferpay-client/models/PaymentPageAssert.d.ts +4 -4
  76. package/lib/payment/worldline-saferpay/worldline-saferpay-client/models/PaymentPageInitialize.d.ts +4 -4
  77. package/lib/payment/worldline-saferpay/worldline-saferpay-client/models/TransactionCancel.d.ts +2 -2
  78. package/lib/plugins-index.d.ts +43 -42
  79. package/lib/plugins-index.js +51 -50
  80. package/lib/plugins-index.js.map +1 -1
  81. package/lib/pricing/delivery-swiss-tax.d.ts +1 -1
  82. package/lib/pricing/discount-100-off.d.ts +2 -1
  83. package/lib/pricing/discount-100-off.js +1 -1
  84. package/lib/pricing/discount-100-off.js.map +1 -1
  85. package/lib/pricing/discount-half-price-manual.d.ts +2 -1
  86. package/lib/pricing/discount-half-price-manual.js +1 -1
  87. package/lib/pricing/discount-half-price-manual.js.map +1 -1
  88. package/lib/pricing/discount-half-price.d.ts +2 -1
  89. package/lib/pricing/discount-half-price.js +1 -1
  90. package/lib/pricing/discount-half-price.js.map +1 -1
  91. package/lib/pricing/free-delivery.d.ts +1 -1
  92. package/lib/pricing/free-payment.d.ts +1 -1
  93. package/lib/pricing/order-delivery.d.ts +2 -1
  94. package/lib/pricing/order-delivery.js +1 -1
  95. package/lib/pricing/order-delivery.js.map +1 -1
  96. package/lib/pricing/order-discount.d.ts +10 -1
  97. package/lib/pricing/order-discount.js +6 -5
  98. package/lib/pricing/order-discount.js.map +1 -1
  99. package/lib/pricing/order-items-discount.js +5 -1
  100. package/lib/pricing/order-items-discount.js.map +1 -1
  101. package/lib/pricing/product-catalog-price.d.ts +2 -1
  102. package/lib/pricing/product-catalog-price.js +1 -1
  103. package/lib/pricing/product-catalog-price.js.map +1 -1
  104. package/lib/pricing/product-discount.d.ts +2 -1
  105. package/lib/pricing/product-discount.js +3 -3
  106. package/lib/pricing/product-discount.js.map +1 -1
  107. package/lib/pricing/product-price-rateconversion.d.ts +2 -1
  108. package/lib/pricing/product-price-rateconversion.js +1 -1
  109. package/lib/pricing/product-price-rateconversion.js.map +1 -1
  110. package/lib/pricing/product-price-round.d.ts +3 -1
  111. package/lib/pricing/product-price-round.js +3 -3
  112. package/lib/pricing/product-price-round.js.map +1 -1
  113. package/lib/pricing/product-swiss-tax.d.ts +8 -0
  114. package/lib/pricing/product-swiss-tax.js +3 -3
  115. package/lib/pricing/product-swiss-tax.js.map +1 -1
  116. package/lib/warehousing/eth-minter.js +1 -1
  117. package/lib/warehousing/eth-minter.js.map +1 -1
  118. package/lib/warehousing/google-sheets.d.ts +1 -1
  119. package/lib/warehousing/google-sheets.js +1 -1
  120. package/lib/warehousing/google-sheets.js.map +1 -1
  121. package/lib/worker/bulk-import.d.ts +1 -1
  122. package/lib/worker/email.d.ts +1 -1
  123. package/lib/worker/email.js +1 -1
  124. package/lib/worker/email.js.map +1 -1
  125. package/lib/worker/export-token.d.ts +2 -2
  126. package/lib/worker/external.d.ts +1 -1
  127. package/lib/worker/http-request.d.ts +1 -1
  128. package/lib/worker/message.d.ts +1 -1
  129. package/lib/worker/push-notification.d.ts +1 -0
  130. package/lib/worker/push-notification.js +73 -0
  131. package/lib/worker/push-notification.js.map +1 -0
  132. package/lib/worker/update-token-ownership.d.ts +2 -2
  133. package/lib/worker/zombie-killer.d.ts +1 -1
  134. package/package.json +22 -22
  135. package/src/delivery/pick-mup.ts +1 -1
  136. package/src/delivery/post.ts +1 -1
  137. package/src/delivery/send-message.ts +1 -1
  138. package/src/delivery/stores.ts +1 -1
  139. package/src/enrollments/licensed.ts +2 -2
  140. package/src/events/node-event-emitter.ts +1 -1
  141. package/src/events/redis.ts +1 -1
  142. package/src/files/gridfs/gridfs-adapter.ts +2 -2
  143. package/src/files/gridfs/gridfs-webhook.ts +1 -1
  144. package/src/files/gridfs/index.ts +14 -3
  145. package/src/files/minio/minio-adapter.ts +2 -2
  146. package/src/filters/local-search.ts +2 -2
  147. package/src/filters/strict-equal.ts +1 -1
  148. package/src/payment/apple-iap/adapter.ts +4 -4
  149. package/src/payment/apple-iap/db/AppleTransactionsCollection.ts +1 -1
  150. package/src/payment/apple-iap/index.ts +2 -2
  151. package/src/payment/apple-iap/module/configureAppleTransactionsModule.ts +2 -2
  152. package/src/payment/braintree.ts +1 -1
  153. package/src/payment/cryptopay/db/CryptopayTransactions.ts +1 -1
  154. package/src/payment/cryptopay/index.ts +3 -3
  155. package/src/payment/cryptopay/middleware.ts +4 -4
  156. package/src/payment/cryptopay/module/configureCryptopayModule.ts +2 -2
  157. package/src/payment/cryptopay/plugin.ts +4 -4
  158. package/src/payment/datatrans-v2/api/authorize.ts +1 -1
  159. package/src/payment/datatrans-v2/api/authorizeAuthenticated.ts +1 -1
  160. package/src/payment/datatrans-v2/api/cancel.ts +1 -1
  161. package/src/payment/datatrans-v2/api/index.ts +9 -9
  162. package/src/payment/datatrans-v2/api/init.ts +2 -2
  163. package/src/payment/datatrans-v2/api/secureFields.ts +2 -2
  164. package/src/payment/datatrans-v2/api/settle.ts +1 -1
  165. package/src/payment/datatrans-v2/api/status.ts +1 -1
  166. package/src/payment/datatrans-v2/api/validate.ts +1 -1
  167. package/src/payment/datatrans-v2/index.ts +6 -6
  168. package/src/payment/datatrans-v2/middleware.ts +3 -3
  169. package/src/payment/datatrans-v2/parseRegistrationData.ts +2 -2
  170. package/src/payment/datatrans-v2/roundedAmountFromOrder.ts +2 -2
  171. package/src/payment/invoice-prepaid.ts +1 -1
  172. package/src/payment/invoice.ts +1 -1
  173. package/src/payment/paypal-checkout.ts +1 -1
  174. package/src/payment/postfinance-checkout/index.ts +5 -5
  175. package/src/payment/postfinance-checkout/middleware.ts +3 -3
  176. package/src/payment/postfinance-checkout/utils.ts +1 -1
  177. package/src/payment/stripe.ts +2 -2
  178. package/src/payment/worldline-saferpay/index.ts +2 -2
  179. package/src/payment/worldline-saferpay/worldline-saferpay-client/api/SaferpayClient.ts +5 -5
  180. package/src/payment/worldline-saferpay/worldline-saferpay-client/index.ts +4 -4
  181. package/src/payment/worldline-saferpay/worldline-saferpay-client/models/PaymentPageAssert.ts +4 -4
  182. package/src/payment/worldline-saferpay/worldline-saferpay-client/models/PaymentPageInitialize.ts +4 -4
  183. package/src/payment/worldline-saferpay/worldline-saferpay-client/models/TransactionCancel.ts +2 -2
  184. package/src/plugins-index.ts +52 -51
  185. package/src/pricing/apply-rate.test.ts +92 -0
  186. package/src/pricing/configureProductPriceRounding.test.ts +44 -0
  187. package/src/pricing/delivery-swiss-tax.ts +1 -1
  188. package/src/pricing/discount-100-off.test.ts +31 -0
  189. package/src/pricing/discount-100-off.ts +2 -2
  190. package/src/pricing/discount-half-price-manual.test.ts +42 -0
  191. package/src/pricing/discount-half-price-manual.ts +2 -2
  192. package/src/pricing/discount-half-price.test.ts +40 -0
  193. package/src/pricing/discount-half-price.ts +2 -2
  194. package/src/pricing/free-delivery.test.ts +12 -0
  195. package/src/pricing/free-delivery.ts +1 -1
  196. package/src/pricing/free-payment.ts +1 -1
  197. package/src/pricing/getTaxRate.test.ts +69 -0
  198. package/src/pricing/licenced-enrollment.test.ts +37 -0
  199. package/src/pricing/order-delivery.test.ts +9 -0
  200. package/src/pricing/order-delivery.ts +2 -2
  201. package/src/pricing/order-discount.test.ts +206 -0
  202. package/src/pricing/order-discount.ts +7 -5
  203. package/src/pricing/order-items-discount.ts +5 -2
  204. package/src/pricing/order-items.ts +1 -1
  205. package/src/pricing/order-payment.ts +1 -1
  206. package/{tests/plugins-index.test.js → src/pricing/plugins-index.test.ts} +0 -0
  207. package/src/pricing/product-catalog-price.ts +2 -2
  208. package/src/pricing/product-discount.ts +4 -4
  209. package/src/pricing/product-price-rateconversion.ts +2 -2
  210. package/src/pricing/product-price-round.ts +5 -5
  211. package/src/pricing/product-swiss-tax.test.ts +141 -0
  212. package/src/pricing/product-swiss-tax.ts +4 -4
  213. package/src/pricing/roundToNext.test.ts +24 -0
  214. package/src/quotations/manual.ts +1 -1
  215. package/src/warehousing/eth-minter.ts +2 -2
  216. package/src/warehousing/google-sheets.ts +2 -2
  217. package/src/warehousing/store.ts +1 -1
  218. package/src/worker/bulk-import.ts +2 -2
  219. package/src/worker/email.ts +2 -2
  220. package/src/worker/enrollment-order-generator.ts +5 -5
  221. package/src/worker/export-token.ts +2 -2
  222. package/src/worker/external.ts +1 -1
  223. package/src/worker/heartbeat.ts +1 -1
  224. package/src/worker/http-request.ts +1 -1
  225. package/src/worker/message.ts +1 -1
  226. package/src/worker/push-notification.ts +106 -0
  227. package/src/worker/sms.ts +1 -1
  228. package/src/worker/update-coinbase-rates.ts +2 -2
  229. package/src/worker/update-ecb-rates.ts +2 -2
  230. package/src/worker/update-token-ownership.ts +2 -2
  231. package/src/worker/zombie-killer.ts +1 -1
  232. package/tsconfig.json +3 -25
  233. package/lib/pricing/utils/cache.d.ts +0 -8
  234. package/lib/pricing/utils/cache.js +0 -28
  235. package/lib/pricing/utils/cache.js.map +0 -1
  236. package/src/pricing/utils/cache.js +0 -32
@@ -0,0 +1,37 @@
1
+ import { rangeMatcher } from "../enrollments/licensed.js";
2
+
3
+ describe('rangeMatcher', () => {
4
+ const now = new Date();
5
+
6
+ const tomorrow = new Date();
7
+ tomorrow.setDate(tomorrow.getDate() + 1);
8
+ const tomorrowTimestamp = tomorrow.getTime();
9
+ const yesterday = new Date();
10
+ yesterday.setDate(yesterday.getDate() - 1);
11
+ const yesterdayTimestamp = yesterday.getTime();
12
+
13
+ it('matches correctly when the date is within the range', () => {
14
+ const range = { start: yesterday, end: tomorrow };
15
+ const matcher = rangeMatcher(now);
16
+ expect(matcher(range)).toBe(true);
17
+ });
18
+
19
+ it('does not match when the date is before the start of the range', () => {
20
+ const range = { start: tomorrow, end: tomorrow };
21
+ const matcher = rangeMatcher(yesterday);
22
+ expect(matcher(range)).toBe(false);
23
+ });
24
+
25
+ it('does not match when the date is after the end of the range', () => {
26
+ const range = { start: yesterday, end: yesterday };
27
+ const matcher = rangeMatcher(tomorrow);
28
+ expect(matcher(range)).toBe(false);
29
+ });
30
+
31
+ it('matches correctly when the date is not provided', () => {
32
+ const range = { start: yesterdayTimestamp, end: tomorrowTimestamp };
33
+ const matcher = rangeMatcher();
34
+ expect(matcher(range)).toBe(true);
35
+ });
36
+ });
37
+
@@ -0,0 +1,9 @@
1
+ import { OrderDelivery } from "./order-delivery.js";
2
+
3
+
4
+ describe("OrderDelivery ", () => {
5
+
6
+ it('isActivatedFor', () => {
7
+ expect(OrderDelivery.isActivatedFor(undefined)).toBeTruthy();
8
+ });
9
+ })
@@ -1,7 +1,7 @@
1
- import { IOrderPricingAdapter } from '@unchainedshop/types/orders.pricing';
1
+ import { IOrderPricingAdapter } from '@unchainedshop/types/orders.pricing.js';
2
2
  import { OrderPricingDirector, OrderPricingAdapter } from '@unchainedshop/core-orders';
3
3
 
4
- const OrderDelivery: IOrderPricingAdapter = {
4
+ export const OrderDelivery: IOrderPricingAdapter = {
5
5
  ...OrderPricingAdapter,
6
6
 
7
7
  key: 'shop.unchained.pricing.order-delivery',
@@ -0,0 +1,206 @@
1
+ import { applyDiscountToMultipleShares, calculateAmountToSplit, resolveAmountAndTax, resolveRatioAndTaxDivisorForPricingSheet } from "./order-discount.js";
2
+
3
+
4
+
5
+ describe("OrderDiscount helpers ", () => {
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]);
97
+ });
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
+ })
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,7 +1,7 @@
1
- import { IOrderPricingAdapter, OrderPricingRowCategory } from '@unchainedshop/types/orders.pricing';
1
+ import { IOrderPricingAdapter, OrderPricingRowCategory } from '@unchainedshop/types/orders.pricing.js';
2
2
  import { OrderPricingDirector, OrderPricingAdapter } from '@unchainedshop/core-orders';
3
3
 
4
- const resolveRatioAndTaxDivisorForPricingSheet = (pricing, total) => {
4
+ export const resolveRatioAndTaxDivisorForPricingSheet = (pricing, total) => {
5
5
  if (total === 0 || !pricing) {
6
6
  return {
7
7
  ratio: 1,
@@ -22,14 +22,16 @@ const resolveRatioAndTaxDivisorForPricingSheet = (pricing, total) => {
22
22
  };
23
23
  };
24
24
 
25
- const resolveAmountAndTax = ({ ratio, taxDivisor }, amount) => {
25
+ export const resolveAmountAndTax = ({ ratio, taxDivisor }, amount) => {
26
26
  const shareAmount = Number.isFinite(ratio) ? amount * ratio : 0;
27
27
  const shareTaxAmount =
28
28
  Number.isFinite(taxDivisor) && taxDivisor !== 0 ? shareAmount - shareAmount / taxDivisor : 0;
29
29
  return [shareAmount, shareTaxAmount];
30
30
  };
31
31
 
32
- const applyDiscountToMultipleShares = (shares, amount) => {
32
+ // TODO: move to separate file because its used in multiple places
33
+
34
+ export const applyDiscountToMultipleShares = (shares, amount) => {
33
35
  return shares.reduce(
34
36
  ([currentDiscountAmount, currentTaxAmount], share) => {
35
37
  const [shareAmount, shareTaxAmount] = resolveAmountAndTax(share, amount);
@@ -39,7 +41,7 @@ const applyDiscountToMultipleShares = (shares, amount) => {
39
41
  );
40
42
  };
41
43
 
42
- const calculateAmountToSplit = (configuration, amount) => {
44
+ export const calculateAmountToSplit = (configuration, amount) => {
43
45
  const deductionAmount = configuration.rate ? amount * configuration.rate : configuration.fixedRate;
44
46
 
45
47
  const leftInDiscount = Math.max(0, deductionAmount - (configuration.alreadyDeductedForDiscount || 0));
@@ -1,6 +1,6 @@
1
- import { IOrderPricingAdapter, OrderPricingRowCategory } from '@unchainedshop/types/orders.pricing';
1
+ import { IOrderPricingAdapter, OrderPricingRowCategory } from '@unchainedshop/types/orders.pricing.js';
2
2
  import { OrderPricingDirector, OrderPricingAdapter } from '@unchainedshop/core-orders';
3
-
3
+ // TODO: move into separate file and share multiple places
4
4
  const resolveRatioAndTaxDivisorForPricingSheet = (pricing, total) => {
5
5
  if (total === 0 || !pricing) {
6
6
  return {
@@ -16,12 +16,14 @@ const resolveRatioAndTaxDivisorForPricingSheet = (pricing, total) => {
16
16
  };
17
17
  };
18
18
 
19
+ // TODO: move into separate file and share multiple places
19
20
  const resolveAmountAndTax = ({ ratio, taxDivisor }, amount) => {
20
21
  const shareAmount = Number.isFinite(ratio) ? amount * ratio : 0;
21
22
  const shareTaxAmount = Number.isFinite(taxDivisor) ? shareAmount - shareAmount / taxDivisor : 0;
22
23
  return [shareAmount, shareTaxAmount];
23
24
  };
24
25
 
26
+ // TODO: move into separate file and share multiple places
25
27
  const applyDiscountToMultipleShares = (shares, amount) => {
26
28
  return shares.reduce(
27
29
  ([currentDiscountAmount, currentTaxAmount], share) => {
@@ -32,6 +34,7 @@ const applyDiscountToMultipleShares = (shares, amount) => {
32
34
  );
33
35
  };
34
36
 
37
+ // TODO: move into separate file and share multiple places
35
38
  const calculateAmountToSplit = (configuration, amount) => {
36
39
  const deductionAmount = configuration.rate
37
40
  ? amount * configuration.rate
@@ -1,4 +1,4 @@
1
- import { IOrderPricingAdapter } from '@unchainedshop/types/orders.pricing';
1
+ import { IOrderPricingAdapter } from '@unchainedshop/types/orders.pricing.js';
2
2
  import { OrderPricingDirector, OrderPricingAdapter } from '@unchainedshop/core-orders';
3
3
 
4
4
  const OrderItems: IOrderPricingAdapter = {
@@ -1,4 +1,4 @@
1
- import { IOrderPricingAdapter } from '@unchainedshop/types/orders.pricing';
1
+ import { IOrderPricingAdapter } from '@unchainedshop/types/orders.pricing.js';
2
2
  import { OrderPricingDirector, OrderPricingAdapter } from '@unchainedshop/core-orders';
3
3
 
4
4
  const OrderPayment: IOrderPricingAdapter = {
@@ -1,7 +1,7 @@
1
- import { IProductPricingAdapter } from '@unchainedshop/types/products.pricing';
1
+ import { IProductPricingAdapter } from '@unchainedshop/types/products.pricing.js';
2
2
  import { ProductPricingDirector, ProductPricingAdapter } from '@unchainedshop/core-products';
3
3
 
4
- const ProductPrice: IProductPricingAdapter = {
4
+ export const ProductPrice: IProductPricingAdapter = {
5
5
  ...ProductPricingAdapter,
6
6
 
7
7
  key: 'shop.unchained.pricing.product-price',
@@ -1,13 +1,13 @@
1
- import type { Discount, DiscountConfiguration } from '@unchainedshop/types/discount';
1
+ import type { Discount, DiscountConfiguration } from '@unchainedshop/types/discount.js';
2
2
  import {
3
3
  IProductPricingAdapter,
4
4
  ProductPricingRowCategory,
5
- } from '@unchainedshop/types/products.pricing';
5
+ } from '@unchainedshop/types/products.pricing.js';
6
6
  import { ProductPricingDirector, ProductPricingAdapter } from '@unchainedshop/core-products';
7
7
 
8
- const applyRate = (configuration: DiscountConfiguration, amount) => {
8
+ export const applyRate = (configuration: DiscountConfiguration, amount) => {
9
9
  const { rate, fixedRate } = configuration;
10
- return rate ? amount * rate : Math.min(fixedRate, amount);
10
+ return rate ? amount * rate : Math.min(fixedRate || 0, amount);
11
11
  };
12
12
  const ProductDiscount: IProductPricingAdapter = {
13
13
  ...ProductPricingAdapter,
@@ -1,7 +1,7 @@
1
- import { IProductPricingAdapter } from '@unchainedshop/types/products.pricing';
1
+ import { IProductPricingAdapter } from '@unchainedshop/types/products.pricing.js';
2
2
  import { ProductPricingDirector, ProductPricingAdapter } from '@unchainedshop/core-products';
3
3
 
4
- const ProductPriceRateConversion: IProductPricingAdapter = {
4
+ export const ProductPriceRateConversion: IProductPricingAdapter = {
5
5
  ...ProductPricingAdapter,
6
6
 
7
7
  key: 'shop.unchained.pricing.rate-conversion',
@@ -1,8 +1,8 @@
1
- import { IProductPricingAdapter } from '@unchainedshop/types/products.pricing';
2
- import { ProductPricingDirector, ProductPricingAdapter } from '@unchainedshop/core-products';
3
-
4
- const roundToNext = (value, precision) => Math.ceil(value / precision) * precision;
1
+ import { IProductPricingAdapter } from '@unchainedshop/types/products.pricing.js';
2
+ import { ProductPricingAdapter, ProductPricingDirector } from '@unchainedshop/core-products';
5
3
 
4
+ export const roundToNext = (value, precision) => Math.ceil(value / precision) * precision;
5
+ // TODO: Move to types
6
6
  // String is referencing to a currency
7
7
  interface PriceRoundSettings {
8
8
  configurations: Record<string, number>;
@@ -10,7 +10,7 @@ interface PriceRoundSettings {
10
10
  skip: Array<string>;
11
11
  }
12
12
 
13
- const ProductPriceRoundSettings: PriceRoundSettings = {
13
+ export const ProductPriceRoundSettings: PriceRoundSettings = {
14
14
  configurations: {},
15
15
  defaultPrecision: 50,
16
16
  skip: [],
@@ -0,0 +1,141 @@
1
+ import { getTaxRate, isDeliveryAddressInSwitzerland, SwissTaxCategories } from './product-swiss-tax.js';
2
+
3
+ describe("ProductSwissTax", () => {
4
+ describe('SwissTaxCategories', () => {
5
+ it('DEFAULT rate', () => {
6
+ expect(SwissTaxCategories.DEFAULT.rate()).toBe(0.077);
7
+ });
8
+
9
+ it('REDUCED rate', () => {
10
+ expect(SwissTaxCategories.REDUCED.rate()).toBe(0.025);
11
+ });
12
+
13
+ it('SPECIAL rate', () => {
14
+ expect(SwissTaxCategories.SPECIAL.rate()).toBe(0.037);
15
+ });
16
+ });
17
+
18
+ describe('getTaxRate', () => {
19
+ it('default rate', () => {
20
+ const context: any = {
21
+ product: {
22
+ tags: []
23
+ },
24
+ provider: {
25
+ configuration: [],
26
+ },
27
+ };
28
+ expect(getTaxRate(context)).toBe(0.077);
29
+ });
30
+
31
+ it('reduced rate', () => {
32
+ const context: any = {
33
+ product: {
34
+ tags: ['swiss-tax-category:reduced']
35
+ },
36
+ provider: {
37
+ configuration: [
38
+ {
39
+ key: 'swiss-tax-category',
40
+ value: SwissTaxCategories.REDUCED.rate(),
41
+ },
42
+ ],
43
+ },
44
+ };
45
+ expect(getTaxRate(context)).toBe(0.025);
46
+ });
47
+
48
+ it('special rate', () => {
49
+ const context: any = {
50
+ product: {
51
+ tags: ['swiss-tax-category:special']
52
+ },
53
+ provider: {
54
+ configuration: [
55
+ {
56
+ key: 'swiss-tax-category',
57
+ value: SwissTaxCategories.SPECIAL.rate(),
58
+ },
59
+ ],
60
+ },
61
+ };
62
+ expect(getTaxRate(context)).toBe(0.037);
63
+ });
64
+
65
+ it('default rate', () => {
66
+ const context: any = {
67
+ product: {
68
+ tags: ['swiss-tax-category:default']
69
+ },
70
+ provider: {
71
+ configuration: [
72
+ {
73
+ key: 'swiss-tax-category',
74
+ value: SwissTaxCategories.DEFAULT.rate(),
75
+ },
76
+ ],
77
+ },
78
+ };
79
+ expect(getTaxRate(context)).toBe(0.077);
80
+ });
81
+
82
+ })
83
+
84
+ describe('isDeliveryAddressInSwitzerland', () => {
85
+ const context = {
86
+ modules: {
87
+ orders: {
88
+ deliveries: {
89
+ findDelivery: import.meta.jest.fn(async({orderDeliveryId}) =>{
90
+ if(orderDeliveryId === 'CH' || orderDeliveryId === 'LI' )
91
+ return {context: { address: { countryCode: 'CH'}}}
92
+ if(orderDeliveryId === null)
93
+ return {context: { address: null}}
94
+ return {context: { address: {countryCode: 'RT'}}}
95
+ })
96
+ }
97
+ }
98
+ },
99
+ order : {
100
+ deliveryId: 'CH',
101
+ billingAddress: {countryCode: 'LI'}
102
+ },
103
+ country: 'CH'
104
+ }
105
+ it('Should return true when passed country code CH', async () => {
106
+ expect(await isDeliveryAddressInSwitzerland({...context, country: 'ch', order: null})).toBe(true);
107
+ });
108
+
109
+ it('Should return true when passed country code LI', async () => {
110
+ expect(await isDeliveryAddressInSwitzerland({...context, country: 'LI', order: null})).toBe(true);
111
+ });
112
+
113
+ it('Should return false when country is neither CH nor LI and order is null', async () => {
114
+ expect(await isDeliveryAddressInSwitzerland({...context, country: 'ET', order: null})).toBe(false);
115
+ });
116
+
117
+ it('Order should take precedence over country parameter', async () => {
118
+ // not CH or LI order so returns false
119
+ expect(await isDeliveryAddressInSwitzerland({...context, country: 'CH', order : {
120
+ deliveryId: 'ET',
121
+ billingAddress: {countryCode: 'ET'}
122
+ }})).toBe(false);
123
+ });
124
+
125
+ it('If order is not from CH and LI but billingAddress is, it should take precedence over country ', async () => {
126
+ expect(await isDeliveryAddressInSwitzerland({...context, country: 'IT', order : {
127
+ deliveryId: null,
128
+ billingAddress: { countryCode: 'CH'}
129
+ }})).toBe(true);
130
+ });
131
+
132
+ it('Should return false if billingAddress is neither CH or LI and order does not have address', async () => {
133
+ expect(await isDeliveryAddressInSwitzerland({...context, country: null, order : {
134
+ deliveryId: null,
135
+ billingAddress: {countryCode: 'HH'}
136
+ }})).toBe(false);
137
+ });
138
+ });
139
+
140
+
141
+ })
@@ -2,7 +2,7 @@ import { ProductPricingDirector, ProductPricingAdapter } from '@unchainedshop/co
2
2
  import {
3
3
  IProductPricingAdapter,
4
4
  ProductPricingAdapterContext,
5
- } from '@unchainedshop/types/products.pricing';
5
+ } from '@unchainedshop/types/products.pricing.js';
6
6
 
7
7
  export const SwissTaxCategories = {
8
8
  DEFAULT: {
@@ -24,7 +24,7 @@ export const SwissTaxCategories = {
24
24
  },
25
25
  };
26
26
 
27
- const getTaxRate = (context: ProductPricingAdapterContext) => {
27
+ export const getTaxRate = (context: ProductPricingAdapterContext) => {
28
28
  const { product } = context;
29
29
 
30
30
  if (product.tags?.includes(SwissTaxCategories.REDUCED.tag)) {
@@ -36,7 +36,7 @@ const getTaxRate = (context: ProductPricingAdapterContext) => {
36
36
  return SwissTaxCategories.DEFAULT.rate();
37
37
  };
38
38
 
39
- const isDeliveryAddressInSwitzerland = async ({ order, country, modules }) => {
39
+ export const isDeliveryAddressInSwitzerland = async ({ order, country, modules }) => {
40
40
  let countryCode = country?.toUpperCase().trim();
41
41
 
42
42
  if (order) {
@@ -53,7 +53,7 @@ const isDeliveryAddressInSwitzerland = async ({ order, country, modules }) => {
53
53
  return countryCode === 'CH' || countryCode === 'LI';
54
54
  };
55
55
 
56
- const ProductSwissTax: IProductPricingAdapter = {
56
+ export const ProductSwissTax: IProductPricingAdapter = {
57
57
  ...ProductPricingAdapter,
58
58
 
59
59
  key: 'shop.unchained.pricing.product-swiss-tax',
@@ -0,0 +1,24 @@
1
+ import { roundToNext } from "./product-price-round.js";
2
+
3
+ describe('roundToNext', () => {
4
+ it('rounds to the next multiple of precision correctly when the value is positive', () => {
5
+ expect(roundToNext(5, 2)).toBe(6);
6
+ expect(roundToNext(10, 5)).toBe(10);
7
+ expect(roundToNext(13, 5)).toBe(15);
8
+ });
9
+
10
+ it('rounds to the next multiple of precision correctly when the value is negative', () => {
11
+ expect(roundToNext(-5, 2)).toBe(-4);
12
+ expect(roundToNext(-10, 5)).toBe(-10);
13
+ expect(roundToNext(-13, 5)).toBe(-10);
14
+ });
15
+
16
+ it('returns 0 when the value is 0', () => {
17
+ expect(roundToNext(0, 5)).toBe(0);
18
+ });
19
+
20
+ it('returns the same value when the precision is 1', () => {
21
+ expect(roundToNext(5, 1)).toBe(5);
22
+ });
23
+
24
+ });
@@ -1,4 +1,4 @@
1
- import { IQuotationAdapter } from '@unchainedshop/types/quotations';
1
+ import { IQuotationAdapter } from '@unchainedshop/types/quotations.js';
2
2
  import { QuotationDirector, QuotationAdapter } from '@unchainedshop/core-quotations';
3
3
 
4
4
  const ManualOffering: IQuotationAdapter = {
@@ -3,8 +3,8 @@ import {
3
3
  WarehousingAdapter,
4
4
  WarehousingProviderType,
5
5
  } from '@unchainedshop/core-warehousing';
6
- import { ProductType, ProductContractStandard } from '@unchainedshop/types/products';
7
- import { IWarehousingAdapter, WarehousingError } from '@unchainedshop/types/warehousing';
6
+ import { ProductType, ProductContractStandard } from '@unchainedshop/types/products.js';
7
+ import { IWarehousingAdapter, WarehousingError } from '@unchainedshop/types/warehousing.js';
8
8
  import { generateDbObjectId, systemLocale } from '@unchainedshop/utils';
9
9
 
10
10
  const { MINTER_TOKEN_OFFSET = '0' } = process.env;
@@ -5,9 +5,9 @@ import {
5
5
  } from '@unchainedshop/core-warehousing';
6
6
  import Sheets from 'node-sheets';
7
7
  import { log, LogLevel } from '@unchainedshop/logger';
8
- import 'abort-controller/polyfill';
8
+ import 'abort-controller/polyfill.js';
9
9
  import LRU from 'lru-cache';
10
- import { IWarehousingAdapter } from '@unchainedshop/types/warehousing';
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;
13
13
 
@@ -3,7 +3,7 @@ import {
3
3
  WarehousingAdapter,
4
4
  WarehousingProviderType,
5
5
  } from '@unchainedshop/core-warehousing';
6
- import { IWarehousingAdapter } from '@unchainedshop/types/warehousing';
6
+ import { IWarehousingAdapter } from '@unchainedshop/types/warehousing.js';
7
7
 
8
8
  const Store: IWarehousingAdapter = {
9
9
  ...WarehousingAdapter,
@@ -1,10 +1,10 @@
1
- import { IWorkerAdapter } from '@unchainedshop/types/worker';
1
+ import { IWorkerAdapter } from '@unchainedshop/types/worker.js';
2
2
  import { WorkerDirector, WorkerAdapter } from '@unchainedshop/core-worker';
3
3
  import { createLogger, LogLevel } from '@unchainedshop/logger';
4
4
  import fs from 'fs';
5
5
  import JSONStream from 'JSONStream';
6
6
  import { EventIterator } from 'event-iterator';
7
- import { UnchainedCore } from '@unchainedshop/types/core';
7
+ import { UnchainedCore } from '@unchainedshop/types/core.js';
8
8
 
9
9
  const logger = createLogger('unchained:platform:bulk-import');
10
10