@pisell/pisellos 2.1.85 → 2.1.87

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 (111) hide show
  1. package/dist/index.d.ts +0 -1
  2. package/dist/index.js +0 -1
  3. package/dist/modules/Cart/types.d.ts +0 -2
  4. package/dist/modules/Cart/utils/cartProduct.js +0 -11
  5. package/dist/modules/Cart/utils/changePrice.js +6 -0
  6. package/dist/modules/Discount/index.d.ts +1 -0
  7. package/dist/modules/Discount/index.js +2 -1
  8. package/dist/modules/Discount/types.d.ts +0 -15
  9. package/dist/modules/Payment/index.d.ts +1 -2
  10. package/dist/modules/Payment/index.js +7 -10
  11. package/dist/modules/Payment/utils.js +0 -3
  12. package/dist/modules/Payment/walletpass.d.ts +0 -23
  13. package/dist/modules/Payment/walletpass.js +95 -191
  14. package/dist/modules/Rules/index.d.ts +2 -7
  15. package/dist/modules/Rules/index.js +19 -141
  16. package/dist/modules/Rules/types.d.ts +0 -1
  17. package/dist/modules/Schedule/getDateIsInSchedule.d.ts +32 -0
  18. package/dist/modules/Schedule/getDateIsInSchedule.js +747 -0
  19. package/dist/modules/Schedule/index.d.ts +1 -1
  20. package/dist/modules/Schedule/index.js +2 -0
  21. package/dist/modules/Summary/index.js +47 -5
  22. package/dist/modules/Summary/types.d.ts +0 -2
  23. package/dist/modules/Summary/utils.d.ts +1 -7
  24. package/dist/modules/Summary/utils.js +23 -33
  25. package/dist/plugins/window.d.ts +0 -2
  26. package/dist/solution/BookingByStep/index.d.ts +0 -1
  27. package/dist/solution/BookingByStep/index.js +84 -35
  28. package/dist/solution/Checkout/index.js +0 -2
  29. package/dist/solution/ShopDiscount/index.d.ts +0 -1
  30. package/dist/solution/ShopDiscount/index.js +3 -12
  31. package/dist/solution/ShopDiscount/types.d.ts +0 -1
  32. package/lib/index.d.ts +0 -1
  33. package/lib/index.js +1 -3
  34. package/lib/modules/Cart/types.d.ts +0 -2
  35. package/lib/modules/Cart/utils/cartProduct.js +0 -9
  36. package/lib/modules/Cart/utils/changePrice.js +5 -0
  37. package/lib/modules/Discount/index.d.ts +1 -0
  38. package/lib/modules/Discount/index.js +2 -1
  39. package/lib/modules/Discount/types.d.ts +0 -15
  40. package/lib/modules/Payment/index.d.ts +1 -2
  41. package/lib/modules/Payment/index.js +0 -1
  42. package/lib/modules/Payment/utils.js +0 -3
  43. package/lib/modules/Payment/walletpass.d.ts +0 -23
  44. package/lib/modules/Payment/walletpass.js +17 -94
  45. package/lib/modules/Rules/index.d.ts +2 -7
  46. package/lib/modules/Rules/index.js +149 -285
  47. package/lib/modules/Rules/types.d.ts +0 -1
  48. package/lib/modules/Schedule/getDateIsInSchedule.d.ts +32 -0
  49. package/lib/modules/Schedule/getDateIsInSchedule.js +451 -0
  50. package/lib/modules/Schedule/index.d.ts +1 -1
  51. package/lib/modules/Schedule/index.js +2 -0
  52. package/lib/modules/Summary/index.js +22 -9
  53. package/lib/modules/Summary/types.d.ts +0 -2
  54. package/lib/modules/Summary/utils.d.ts +1 -7
  55. package/lib/modules/Summary/utils.js +22 -28
  56. package/lib/plugins/window.d.ts +0 -2
  57. package/lib/solution/BookingByStep/index.d.ts +0 -1
  58. package/lib/solution/BookingByStep/index.js +34 -3
  59. package/lib/solution/Checkout/index.js +0 -2
  60. package/lib/solution/ShopDiscount/index.d.ts +0 -1
  61. package/lib/solution/ShopDiscount/index.js +2 -7
  62. package/lib/solution/ShopDiscount/types.d.ts +0 -1
  63. package/package.json +1 -1
  64. package/dist/model/index.d.ts +0 -1
  65. package/dist/model/index.js +0 -1
  66. package/dist/model/strategy/adapter/index.d.ts +0 -3
  67. package/dist/model/strategy/adapter/index.js +0 -4
  68. package/dist/model/strategy/adapter/type.d.ts +0 -28
  69. package/dist/model/strategy/adapter/type.js +0 -1
  70. package/dist/model/strategy/adapter/walletPass/evaluator.d.ts +0 -84
  71. package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -497
  72. package/dist/model/strategy/adapter/walletPass/example.d.ts +0 -4
  73. package/dist/model/strategy/adapter/walletPass/example.js +0 -258
  74. package/dist/model/strategy/adapter/walletPass/index.d.ts +0 -32
  75. package/dist/model/strategy/adapter/walletPass/index.js +0 -182
  76. package/dist/model/strategy/adapter/walletPass/locales.d.ts +0 -1
  77. package/dist/model/strategy/adapter/walletPass/locales.js +0 -23
  78. package/dist/model/strategy/adapter/walletPass/type.d.ts +0 -168
  79. package/dist/model/strategy/adapter/walletPass/type.js +0 -1
  80. package/dist/model/strategy/adapter/walletPass/utils.d.ts +0 -76
  81. package/dist/model/strategy/adapter/walletPass/utils.js +0 -1043
  82. package/dist/model/strategy/index.d.ts +0 -94
  83. package/dist/model/strategy/index.js +0 -551
  84. package/dist/model/strategy/strategy-example.d.ts +0 -5
  85. package/dist/model/strategy/strategy-example.js +0 -331
  86. package/dist/model/strategy/type.d.ts +0 -228
  87. package/dist/model/strategy/type.js +0 -94
  88. package/lib/model/index.d.ts +0 -1
  89. package/lib/model/index.js +0 -23
  90. package/lib/model/strategy/adapter/index.d.ts +0 -3
  91. package/lib/model/strategy/adapter/index.js +0 -45
  92. package/lib/model/strategy/adapter/type.d.ts +0 -28
  93. package/lib/model/strategy/adapter/type.js +0 -17
  94. package/lib/model/strategy/adapter/walletPass/evaluator.d.ts +0 -84
  95. package/lib/model/strategy/adapter/walletPass/evaluator.js +0 -421
  96. package/lib/model/strategy/adapter/walletPass/example.d.ts +0 -4
  97. package/lib/model/strategy/adapter/walletPass/example.js +0 -207
  98. package/lib/model/strategy/adapter/walletPass/index.d.ts +0 -32
  99. package/lib/model/strategy/adapter/walletPass/index.js +0 -142
  100. package/lib/model/strategy/adapter/walletPass/locales.d.ts +0 -1
  101. package/lib/model/strategy/adapter/walletPass/locales.js +0 -51
  102. package/lib/model/strategy/adapter/walletPass/type.d.ts +0 -168
  103. package/lib/model/strategy/adapter/walletPass/type.js +0 -17
  104. package/lib/model/strategy/adapter/walletPass/utils.d.ts +0 -76
  105. package/lib/model/strategy/adapter/walletPass/utils.js +0 -704
  106. package/lib/model/strategy/index.d.ts +0 -94
  107. package/lib/model/strategy/index.js +0 -413
  108. package/lib/model/strategy/strategy-example.d.ts +0 -5
  109. package/lib/model/strategy/strategy-example.js +0 -318
  110. package/lib/model/strategy/type.d.ts +0 -228
  111. package/lib/model/strategy/type.js +0 -44
@@ -1,704 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
- // If the importer is in node compatibility mode or this is not an ESM
21
- // file that has been converted to a CommonJS file using a Babel-
22
- // compatible transform (i.e. "__esModule" has not been set), then set
23
- // "default" to the CommonJS "module.exports" for node compatibility.
24
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
- mod
26
- ));
27
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
-
29
- // src/model/strategy/adapter/walletPass/utils.ts
30
- var utils_exports = {};
31
- __export(utils_exports, {
32
- getApplicableProductIds: () => getApplicableProductIds,
33
- getBundleItemDiscountDifference: () => getBundleItemDiscountDifference,
34
- getBundleItemIsDiscountPrice: () => getBundleItemIsDiscountPrice,
35
- getBundleItemIsMarkupOrDiscountPrice: () => getBundleItemIsMarkupOrDiscountPrice,
36
- getBundleItemIsMarkupPrice: () => getBundleItemIsMarkupPrice,
37
- getBundleItemIsOriginalPrice: () => getBundleItemIsOriginalPrice,
38
- getBundleItemPrice: () => getBundleItemPrice,
39
- getBundleItemTaxAndFeeRoundingRemainder: () => getBundleItemTaxAndFeeRoundingRemainder,
40
- getMainProductPrice: () => getMainProductPrice,
41
- getProductDiscountDifference: () => getProductDiscountDifference,
42
- getProductQuantity: () => getProductQuantity,
43
- getTaxAndFeeRoundingRemainder: () => getTaxAndFeeRoundingRemainder,
44
- processVouchers: () => processVouchers,
45
- recalculateVouchers: () => recalculateVouchers
46
- });
47
- module.exports = __toCommonJS(utils_exports);
48
- var import_decimal = __toESM(require("decimal.js"));
49
- var getRecommendedAmount = (voucher) => {
50
- console.log("voucher312", voucher);
51
- const { config, recommended_usage_amount, recommended_pure_product_usage_amount } = voucher;
52
- const deductTaxAndFee = (config == null ? void 0 : config.deductTaxAndFee) ?? true;
53
- return deductTaxAndFee ? recommended_usage_amount : recommended_pure_product_usage_amount ?? recommended_usage_amount;
54
- };
55
- var getApplicableProductIds = (voucher) => {
56
- const { available_product_type, available_product_ids } = voucher;
57
- const productType = available_product_type || "product_all";
58
- if (productType === "product_all") {
59
- return null;
60
- }
61
- if (productType === "product_collection" || productType === "products") {
62
- return available_product_ids || [];
63
- }
64
- return [];
65
- };
66
- var getApplicableProductsAmount = (voucher, productsData) => {
67
- const applicableProductIds = getApplicableProductIds(voucher);
68
- const { config } = voucher;
69
- const deductTaxAndFee = (config == null ? void 0 : config.deductTaxAndFee) ?? true;
70
- const amountField = deductTaxAndFee ? "remainingAmountWithTax" : "remainingAmountPure";
71
- if (applicableProductIds === null) {
72
- return productsData.filter((p) => p[amountField].greaterThan(0)).reduce((sum, p) => sum.plus(p[amountField]), new import_decimal.default(0));
73
- }
74
- if (applicableProductIds.length === 0) {
75
- return new import_decimal.default(0);
76
- }
77
- return productsData.filter((p) => applicableProductIds.includes(p.product_id) && p[amountField].greaterThan(0)).reduce((sum, p) => sum.plus(p[amountField]), new import_decimal.default(0));
78
- };
79
- var getApplicableProducts = (voucher, productsData) => {
80
- const applicableProductIds = getApplicableProductIds(voucher);
81
- if (applicableProductIds === null) {
82
- return productsData;
83
- }
84
- if (applicableProductIds.length === 0) {
85
- return [];
86
- }
87
- return productsData.filter((p) => applicableProductIds.includes(p.product_id));
88
- };
89
- function processVouchers(applicableVouchers, orderTotalAmount, products) {
90
- console.log(products, "products123");
91
- const productsCopy = expandProductsWithBundleItems(products, true);
92
- let remainingOrderAmount = new import_decimal.default(orderTotalAmount);
93
- const calculateAvailableMaxAmount = (voucher, productsData) => {
94
- const { config } = voucher;
95
- const { maxDeductionAmount = 0, allowCrossProduct = true, applicableProductLimit = 0, deductTaxAndFee = true } = config ?? {};
96
- const recommendedAmount = getRecommendedAmount(voucher);
97
- const baseAmount = import_decimal.default.min(
98
- new import_decimal.default(recommendedAmount),
99
- new import_decimal.default(maxDeductionAmount)
100
- );
101
- const unitPriceField = deductTaxAndFee ? "unitPriceWithTax" : "unitPricePure";
102
- const amountField = deductTaxAndFee ? "remainingAmountWithTax" : "remainingAmountPure";
103
- const applicableProducts = getApplicableProducts(voucher, productsData).filter((p) => p[amountField].greaterThan(0));
104
- if (applicableProducts.length === 0) {
105
- return new import_decimal.default(0);
106
- }
107
- let finalApplicableAmount = new import_decimal.default(0);
108
- if (allowCrossProduct) {
109
- if (applicableProductLimit > 0) {
110
- const sortedProducts = [...applicableProducts].sort((a, b) => a[amountField].comparedTo(b[amountField]) > 0 ? -1 : 1);
111
- let remainingLimit = applicableProductLimit;
112
- for (const product of sortedProducts) {
113
- if (remainingLimit <= 0)
114
- break;
115
- const currentAvailableQty = Math.ceil(product[amountField].dividedBy(product[unitPriceField]).toNumber());
116
- const deductQty = Math.min(currentAvailableQty, remainingLimit);
117
- const deductAmount = import_decimal.default.min(
118
- product[unitPriceField].times(deductQty),
119
- product[amountField]
120
- );
121
- finalApplicableAmount = finalApplicableAmount.plus(deductAmount);
122
- remainingLimit -= deductQty;
123
- }
124
- } else {
125
- finalApplicableAmount = applicableProducts.reduce(
126
- (sum, p) => sum.plus(p[amountField]),
127
- new import_decimal.default(0)
128
- );
129
- }
130
- } else {
131
- const maxProduct = applicableProducts.reduce(
132
- (max, p) => p[amountField].greaterThan(max[amountField]) ? p : max
133
- );
134
- const currentAvailableQty = Math.ceil(maxProduct[amountField].dividedBy(maxProduct[unitPriceField]).toNumber());
135
- const deductQty = applicableProductLimit > 0 ? Math.min(currentAvailableQty, applicableProductLimit) : currentAvailableQty;
136
- finalApplicableAmount = import_decimal.default.min(
137
- maxProduct[unitPriceField].times(deductQty),
138
- maxProduct[amountField]
139
- );
140
- }
141
- return import_decimal.default.min(baseAmount, finalApplicableAmount, remainingOrderAmount);
142
- };
143
- const isVoucherAvailable = (voucher, productsData, usedVoucherCounts2) => {
144
- const { config, id, product_id } = voucher;
145
- const recommendedAmount = getRecommendedAmount(voucher);
146
- if (recommendedAmount <= 0) {
147
- return { isAvailable: false, reasonCode: "not_meet_the_required_conditions" };
148
- }
149
- if (remainingOrderAmount.lessThanOrEqualTo(0)) {
150
- return { isAvailable: false, reasonCode: "exceeds_the_maximum_deduction_limit" };
151
- }
152
- const applicableAmount = getApplicableProductsAmount(voucher, productsData);
153
- if (applicableAmount.lessThanOrEqualTo(0)) {
154
- return { isAvailable: false, reasonCode: "not_meet_the_required_conditions" };
155
- }
156
- if (((config == null ? void 0 : config.maxUsagePerOrder) || 0) > 0) {
157
- const usedCount = usedVoucherCounts2.get(product_id) || 0;
158
- if (usedCount >= ((config == null ? void 0 : config.maxUsagePerOrder) || 0)) {
159
- return { isAvailable: false, reasonCode: "usage_limit_reached" };
160
- }
161
- }
162
- return { isAvailable: true };
163
- };
164
- const usedVoucherCountsForAll = /* @__PURE__ */ new Map();
165
- const allVouchersWithStatus = applicableVouchers.map((voucher) => {
166
- const _available_max_amount = calculateAvailableMaxAmount(
167
- voucher,
168
- productsCopy
169
- );
170
- const availabilityResult = isVoucherAvailable(
171
- voucher,
172
- productsCopy,
173
- usedVoucherCountsForAll
174
- );
175
- const _unified_available_status = availabilityResult.isAvailable ? 1 : 0;
176
- return {
177
- ...voucher,
178
- _available_max_amount: _available_max_amount.toNumber(),
179
- // 转换为数字
180
- _unified_available_status,
181
- ...availabilityResult.reasonCode && { reasonCode: availabilityResult.reasonCode }
182
- };
183
- });
184
- const recommendedVouchers = [];
185
- const usedVoucherCounts = /* @__PURE__ */ new Map();
186
- const productsForRecommendation = expandProductsWithBundleItems(products, true);
187
- remainingOrderAmount = new import_decimal.default(orderTotalAmount);
188
- const applyVoucher = (voucher) => {
189
- const availabilityCheck = isVoucherAvailable(
190
- voucher,
191
- productsForRecommendation,
192
- usedVoucherCounts
193
- );
194
- if (!availabilityCheck.isAvailable) {
195
- return false;
196
- }
197
- const { config, id, product_id } = voucher;
198
- const { maxDeductionAmount = 0, allowCrossProduct = true, applicableProductLimit = 0, deductTaxAndFee = true } = config ?? {};
199
- const unitPriceField = deductTaxAndFee ? "unitPriceWithTax" : "unitPricePure";
200
- const amountField = deductTaxAndFee ? "remainingAmountWithTax" : "remainingAmountPure";
201
- let applicableProducts = getApplicableProducts(
202
- voucher,
203
- productsForRecommendation
204
- ).filter((p) => p[amountField].greaterThan(0));
205
- if (applicableProducts.length === 0)
206
- return false;
207
- const usageAmount = typeof voucher.edit_current_amount === "number" ? voucher.edit_current_amount : getRecommendedAmount(voucher);
208
- const baseAmount = import_decimal.default.min(
209
- new import_decimal.default(usageAmount),
210
- new import_decimal.default(maxDeductionAmount)
211
- );
212
- let calculatedAvailableMaxAmount = new import_decimal.default(0);
213
- if (allowCrossProduct) {
214
- if (applicableProductLimit > 0) {
215
- const sortedProducts = [...applicableProducts].sort((a, b) => a[amountField].comparedTo(b[amountField]) > 0 ? -1 : 1);
216
- let remainingLimit = applicableProductLimit;
217
- for (const product of sortedProducts) {
218
- if (remainingLimit <= 0)
219
- break;
220
- const currentAvailableQty = Math.ceil(product[amountField].dividedBy(product[unitPriceField]).toNumber());
221
- const deductQty = Math.min(currentAvailableQty, remainingLimit);
222
- const deductAmount = import_decimal.default.min(
223
- product[unitPriceField].times(deductQty),
224
- product[amountField]
225
- );
226
- calculatedAvailableMaxAmount = calculatedAvailableMaxAmount.plus(deductAmount);
227
- remainingLimit -= deductQty;
228
- }
229
- } else {
230
- calculatedAvailableMaxAmount = applicableProducts.reduce(
231
- (sum, p) => sum.plus(p[amountField]),
232
- new import_decimal.default(0)
233
- );
234
- }
235
- } else {
236
- const maxProduct = applicableProducts.reduce(
237
- (max, p) => p[amountField].greaterThan(max[amountField]) ? p : max
238
- );
239
- const currentAvailableQty = Math.ceil(maxProduct[amountField].dividedBy(maxProduct[unitPriceField]).toNumber());
240
- const deductQty = applicableProductLimit > 0 ? Math.min(currentAvailableQty, applicableProductLimit) : currentAvailableQty;
241
- calculatedAvailableMaxAmount = import_decimal.default.min(
242
- maxProduct[unitPriceField].times(deductQty),
243
- maxProduct[amountField]
244
- );
245
- }
246
- const availableMaxAmount = import_decimal.default.min(
247
- baseAmount,
248
- calculatedAvailableMaxAmount,
249
- remainingOrderAmount
250
- );
251
- const maxDeduction = import_decimal.default.min(
252
- new import_decimal.default(usageAmount),
253
- new import_decimal.default(maxDeductionAmount)
254
- );
255
- let deductionLeft = maxDeduction;
256
- const deductionDetails = [];
257
- if (allowCrossProduct) {
258
- const sortedProducts = [...applicableProducts].sort(
259
- (a, b) => a[amountField].comparedTo(b[amountField]) > 0 ? -1 : 1
260
- );
261
- let remainingLimit = applicableProductLimit > 0 ? applicableProductLimit : Infinity;
262
- for (const product of sortedProducts) {
263
- if (deductionLeft.lessThanOrEqualTo(0) || remainingLimit <= 0)
264
- break;
265
- const currentAvailableQty = Math.ceil(product[amountField].dividedBy(product[unitPriceField]).toNumber());
266
- const availableQty = Math.min(currentAvailableQty, remainingLimit);
267
- const maxDeductForProduct = import_decimal.default.min(
268
- product[unitPriceField].times(availableQty),
269
- product[amountField]
270
- );
271
- const actualDeductAmount = import_decimal.default.min(deductionLeft, maxDeductForProduct);
272
- const actualDeductQty = Math.ceil(actualDeductAmount.dividedBy(product[unitPriceField]).toNumber());
273
- product[amountField] = product[amountField].minus(actualDeductAmount);
274
- deductionLeft = deductionLeft.minus(actualDeductAmount);
275
- remainingLimit -= actualDeductQty;
276
- deductionDetails.push({
277
- product_id: product.product_id,
278
- parent_product_id: product.parent_product_id || null,
279
- is_bundle_item: product.is_bundle_item || false,
280
- deductAmount: actualDeductAmount.toNumber(),
281
- // 转换为数字
282
- deductQuantity: actualDeductQty
283
- // 抵扣涉及的数量(用于记录)
284
- });
285
- }
286
- } else {
287
- const targetProduct = applicableProducts.reduce(
288
- (max, p) => p[amountField].greaterThan(max[amountField]) ? p : max
289
- );
290
- const currentAvailableQty = Math.ceil(targetProduct[amountField].dividedBy(targetProduct[unitPriceField]).toNumber());
291
- const availableQty = applicableProductLimit > 0 ? Math.min(currentAvailableQty, applicableProductLimit) : currentAvailableQty;
292
- const maxDeductForProduct = import_decimal.default.min(
293
- targetProduct[unitPriceField].times(availableQty),
294
- targetProduct[amountField]
295
- );
296
- const actualDeductAmount = import_decimal.default.min(deductionLeft, maxDeductForProduct);
297
- const actualDeductQty = Math.ceil(actualDeductAmount.dividedBy(targetProduct[unitPriceField]).toNumber());
298
- targetProduct[amountField] = targetProduct[amountField].minus(actualDeductAmount);
299
- deductionLeft = deductionLeft.minus(actualDeductAmount);
300
- deductionDetails.push({
301
- product_id: targetProduct.product_id,
302
- parent_product_id: targetProduct.parent_product_id || null,
303
- is_bundle_item: targetProduct.is_bundle_item || false,
304
- deductAmount: actualDeductAmount.toNumber(),
305
- // 转换为数字
306
- deductQuantity: actualDeductQty
307
- // 抵扣涉及的数量(用于记录)
308
- });
309
- }
310
- const totalDeducted = maxDeduction.minus(deductionLeft);
311
- if (totalDeducted.greaterThan(0)) {
312
- remainingOrderAmount = remainingOrderAmount.minus(totalDeducted);
313
- usedVoucherCounts.set(product_id, (usedVoucherCounts.get(product_id) || 0) + 1);
314
- recommendedVouchers.push({
315
- ...voucher,
316
- actualDeduction: totalDeducted.toNumber(),
317
- // 转换为数字
318
- deductionDetails,
319
- _available_max_amount: availableMaxAmount.toNumber(),
320
- // 转换为数字
321
- _unified_available_status: 1
322
- });
323
- return true;
324
- }
325
- return false;
326
- };
327
- applicableVouchers.forEach((voucher) => {
328
- applyVoucher(voucher);
329
- });
330
- const recommendedMap = /* @__PURE__ */ new Map();
331
- recommendedVouchers.forEach((v) => {
332
- recommendedMap.set(v.id, v);
333
- });
334
- const allWithEnhancedData = allVouchersWithStatus.map((voucher) => {
335
- if (recommendedMap.has(voucher.id)) {
336
- return recommendedMap.get(voucher.id);
337
- } else {
338
- return {
339
- ...voucher,
340
- actualDeduction: 0,
341
- deductionDetails: []
342
- // 保留 reasonCode(如果不可用的话)
343
- };
344
- }
345
- });
346
- return {
347
- recommended: recommendedVouchers,
348
- transformList: allWithEnhancedData
349
- };
350
- }
351
- function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, products) {
352
- const productsForCalc = expandProductsWithBundleItems(products, true);
353
- let remainingOrderAmount = new import_decimal.default(orderTotalAmount);
354
- const selectedWithDetails = [];
355
- selectedVouchers.forEach((selectedVoucher) => {
356
- const { config, id } = selectedVoucher;
357
- const { maxDeductionAmount, allowCrossProduct, applicableProductLimit, deductTaxAndFee = true } = config;
358
- const unitPriceField = deductTaxAndFee ? "unitPriceWithTax" : "unitPricePure";
359
- const amountField = deductTaxAndFee ? "remainingAmountWithTax" : "remainingAmountPure";
360
- let applicableProducts = getApplicableProducts(
361
- selectedVoucher,
362
- productsForCalc
363
- ).filter((p) => p[amountField].greaterThan(0));
364
- if (applicableProducts.length === 0) {
365
- selectedWithDetails.push({
366
- ...selectedVoucher,
367
- actualDeduction: 0,
368
- deductionDetails: [],
369
- _available_max_amount: 0,
370
- _unified_available_status: 0,
371
- reasonCode: "not_meet_the_required_conditions"
372
- });
373
- return;
374
- }
375
- const usageAmount = typeof selectedVoucher.edit_current_amount === "number" ? selectedVoucher.edit_current_amount : getRecommendedAmount(selectedVoucher);
376
- const maxDeduction = import_decimal.default.min(
377
- new import_decimal.default(usageAmount),
378
- new import_decimal.default(maxDeductionAmount),
379
- remainingOrderAmount
380
- );
381
- let deductionLeft = maxDeduction;
382
- const deductionDetails = [];
383
- if (allowCrossProduct) {
384
- const sortedProducts = [...applicableProducts].sort(
385
- (a, b) => a[amountField].comparedTo(b[amountField]) > 0 ? -1 : 1
386
- );
387
- let remainingLimit = applicableProductLimit > 0 ? applicableProductLimit : Infinity;
388
- for (const product of sortedProducts) {
389
- if (deductionLeft.lessThanOrEqualTo(0) || remainingLimit <= 0)
390
- break;
391
- const currentAvailableQty = Math.ceil(product[amountField].dividedBy(product[unitPriceField]).toNumber());
392
- const availableQty = Math.min(currentAvailableQty, remainingLimit);
393
- const maxDeductForProduct = import_decimal.default.min(
394
- product[unitPriceField].times(availableQty),
395
- product[amountField]
396
- );
397
- const actualDeductAmount = import_decimal.default.min(deductionLeft, maxDeductForProduct);
398
- const actualDeductQty = Math.ceil(actualDeductAmount.dividedBy(product[unitPriceField]).toNumber());
399
- product[amountField] = product[amountField].minus(actualDeductAmount);
400
- deductionLeft = deductionLeft.minus(actualDeductAmount);
401
- remainingLimit -= actualDeductQty;
402
- deductionDetails.push({
403
- product_id: product.product_id,
404
- parent_product_id: product.parent_product_id || null,
405
- is_bundle_item: product.is_bundle_item || false,
406
- deductAmount: actualDeductAmount.toNumber(),
407
- // 转换为数字
408
- deductQuantity: actualDeductQty
409
- // 抵扣涉及的数量(用于记录)
410
- });
411
- }
412
- } else {
413
- const targetProduct = applicableProducts.reduce(
414
- (max, p) => p[amountField].greaterThan(max[amountField]) ? p : max
415
- );
416
- const currentAvailableQty = Math.ceil(targetProduct[amountField].dividedBy(targetProduct[unitPriceField]).toNumber());
417
- const availableQty = applicableProductLimit > 0 ? Math.min(currentAvailableQty, applicableProductLimit) : currentAvailableQty;
418
- const maxDeductForProduct = import_decimal.default.min(
419
- targetProduct[unitPriceField].times(availableQty),
420
- targetProduct[amountField]
421
- );
422
- const actualDeductAmount = import_decimal.default.min(deductionLeft, maxDeductForProduct);
423
- const actualDeductQty = Math.ceil(actualDeductAmount.dividedBy(targetProduct[unitPriceField]).toNumber());
424
- targetProduct[amountField] = targetProduct[amountField].minus(actualDeductAmount);
425
- deductionLeft = deductionLeft.minus(actualDeductAmount);
426
- deductionDetails.push({
427
- product_id: targetProduct.product_id,
428
- parent_product_id: targetProduct.parent_product_id || null,
429
- is_bundle_item: targetProduct.is_bundle_item || false,
430
- deductAmount: actualDeductAmount.toNumber(),
431
- // 转换为数字
432
- deductQuantity: actualDeductQty
433
- // 抵扣涉及的数量(用于记录)
434
- });
435
- }
436
- const totalDeducted = maxDeduction.minus(deductionLeft);
437
- remainingOrderAmount = remainingOrderAmount.minus(totalDeducted);
438
- selectedWithDetails.push({
439
- ...selectedVoucher,
440
- actualDeduction: totalDeducted.toNumber(),
441
- // 转换为数字
442
- deductionDetails,
443
- _available_max_amount: totalDeducted.toNumber(),
444
- // 转换为数字
445
- _unified_available_status: totalDeducted.greaterThan(0) ? 1 : 0
446
- });
447
- });
448
- const selectedIds = new Set(selectedVouchers.map((v) => v.id));
449
- const usedVoucherCounts = /* @__PURE__ */ new Map();
450
- selectedVouchers.forEach((v) => {
451
- usedVoucherCounts.set(v.product_id, (usedVoucherCounts.get(v.product_id) || 0) + 1);
452
- });
453
- const allWithUpdatedStatus = allVouchers.map((voucher) => {
454
- if (selectedIds.has(voucher.id)) {
455
- const selectedDetail = selectedWithDetails.find(
456
- (v) => v.id === voucher.id
457
- );
458
- return selectedDetail || voucher;
459
- }
460
- const { config, id, product_id } = voucher;
461
- const { maxDeductionAmount, allowCrossProduct, applicableProductLimit, deductTaxAndFee = true } = config;
462
- const unitPriceField = deductTaxAndFee ? "unitPriceWithTax" : "unitPricePure";
463
- const amountField = deductTaxAndFee ? "remainingAmountWithTax" : "remainingAmountPure";
464
- const recommendedAmount = getRecommendedAmount(voucher);
465
- let isAvailable = true;
466
- let calculatedMaxAmount = new import_decimal.default(0);
467
- let reasonCode;
468
- if (recommendedAmount <= 0) {
469
- isAvailable = false;
470
- reasonCode = "not_meet_the_required_conditions";
471
- } else if (remainingOrderAmount.lessThanOrEqualTo(0)) {
472
- isAvailable = false;
473
- reasonCode = "exceeds_the_maximum_deduction_limit";
474
- } else {
475
- if (config.maxUsagePerOrder > 0) {
476
- const usedCount = usedVoucherCounts.get(product_id) || 0;
477
- if (usedCount >= config.maxUsagePerOrder) {
478
- isAvailable = false;
479
- reasonCode = "usage_limit_reached";
480
- }
481
- }
482
- if (isAvailable) {
483
- let applicableProducts = getApplicableProducts(
484
- voucher,
485
- productsForCalc
486
- ).filter((p) => p[amountField].greaterThan(0));
487
- if (applicableProducts.length === 0) {
488
- isAvailable = false;
489
- reasonCode = "not_meet_the_required_conditions";
490
- } else {
491
- const baseAmount = import_decimal.default.min(
492
- new import_decimal.default(recommendedAmount),
493
- new import_decimal.default(maxDeductionAmount)
494
- );
495
- if (allowCrossProduct) {
496
- if (applicableProductLimit > 0) {
497
- const sortedProducts = [...applicableProducts].sort((a, b) => a[amountField].comparedTo(b[amountField]) > 0 ? -1 : 1);
498
- let remainingLimit = applicableProductLimit;
499
- for (const product of sortedProducts) {
500
- if (remainingLimit <= 0)
501
- break;
502
- const currentAvailableQty = Math.ceil(product[amountField].dividedBy(product[unitPriceField]).toNumber());
503
- const deductQty = Math.min(currentAvailableQty, remainingLimit);
504
- const deductAmount = import_decimal.default.min(
505
- product[unitPriceField].times(deductQty),
506
- product[amountField]
507
- );
508
- calculatedMaxAmount = calculatedMaxAmount.plus(deductAmount);
509
- remainingLimit -= deductQty;
510
- }
511
- } else {
512
- calculatedMaxAmount = applicableProducts.reduce(
513
- (sum, p) => sum.plus(p[amountField]),
514
- new import_decimal.default(0)
515
- );
516
- }
517
- } else {
518
- const maxProduct = applicableProducts.reduce(
519
- (max, p) => p[amountField].greaterThan(max[amountField]) ? p : max
520
- );
521
- const currentAvailableQty = Math.ceil(maxProduct[amountField].dividedBy(maxProduct[unitPriceField]).toNumber());
522
- const deductQty = applicableProductLimit > 0 ? Math.min(currentAvailableQty, applicableProductLimit) : currentAvailableQty;
523
- calculatedMaxAmount = import_decimal.default.min(
524
- maxProduct[unitPriceField].times(deductQty),
525
- maxProduct[amountField]
526
- );
527
- }
528
- calculatedMaxAmount = import_decimal.default.min(
529
- baseAmount,
530
- calculatedMaxAmount,
531
- remainingOrderAmount
532
- );
533
- if (calculatedMaxAmount.lessThanOrEqualTo(0)) {
534
- isAvailable = false;
535
- reasonCode = "exceeds_the_maximum_deduction_limit";
536
- }
537
- }
538
- }
539
- }
540
- return {
541
- ...voucher,
542
- _available_max_amount: calculatedMaxAmount.toNumber(),
543
- // 转换为数字
544
- _unified_available_status: isAvailable ? 1 : 0,
545
- ...reasonCode && { reasonCode }
546
- };
547
- });
548
- return {
549
- allWithUpdatedStatus,
550
- selectedWithDetails
551
- };
552
- }
553
- var getTaxAndFeeRoundingRemainder = (product, isDeductTaxAndFee) => {
554
- var _a, _b;
555
- if (!isDeductTaxAndFee) {
556
- return 0;
557
- }
558
- let taxFeeRoundingRemainder = new import_decimal.default(0);
559
- if (product.is_price_include_tax !== 1) {
560
- taxFeeRoundingRemainder = new import_decimal.default(((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.tax_fee_rounding_remainder) || 0);
561
- }
562
- const surchargeFeeRoundingRemainder = new import_decimal.default(((_b = product == null ? void 0 : product.metadata) == null ? void 0 : _b.surcharge_rounding_remainder) || 0);
563
- return taxFeeRoundingRemainder.add(surchargeFeeRoundingRemainder).toNumber();
564
- };
565
- var getProductDiscountDifference = (product) => {
566
- var _a;
567
- return new import_decimal.default(((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.product_discount_difference) || 0).toNumber();
568
- };
569
- var getMainProductPrice = (product, isDeductTaxAndFee) => {
570
- var _a, _b, _c;
571
- let mainProductPrice = new import_decimal.default((product == null ? void 0 : product.main_product_selling_price) || ((_a = product.metadata) == null ? void 0 : _a.main_product_selling_price) || 0);
572
- for (let bundleItem of (product == null ? void 0 : product.product_bundle) || []) {
573
- if (getBundleItemIsMarkupOrDiscountPrice(bundleItem)) {
574
- const bundleItemPrice = new import_decimal.default(bundleItem.bundle_selling_price ?? 0);
575
- mainProductPrice = mainProductPrice.add(bundleItemPrice.times(bundleItem.num));
576
- }
577
- }
578
- let taxFee = new import_decimal.default((product == null ? void 0 : product.tax_fee) || ((_b = product == null ? void 0 : product.metadata) == null ? void 0 : _b.main_product_attached_bundle_tax_fee) || 0);
579
- if (product.is_price_include_tax === 1) {
580
- taxFee = new import_decimal.default(0);
581
- }
582
- const surchargeFee = new import_decimal.default(((_c = product == null ? void 0 : product.metadata) == null ? void 0 : _c.main_product_attached_bundle_surcharge_fee) || 0);
583
- const taxAndFeeTotal = taxFee.add(surchargeFee);
584
- if (isDeductTaxAndFee) {
585
- mainProductPrice = mainProductPrice.add(taxAndFeeTotal);
586
- }
587
- return mainProductPrice.toNumber();
588
- };
589
- var getBundleItemTaxAndFeeRoundingRemainder = (bundleItem, isDeductTaxAndFee) => {
590
- var _a, _b;
591
- if (!isDeductTaxAndFee) {
592
- return 0;
593
- }
594
- let taxFeeRoundingRemainder = new import_decimal.default(0);
595
- if (bundleItem.is_price_include_tax !== 1) {
596
- taxFeeRoundingRemainder = new import_decimal.default(((_a = bundleItem.metadata) == null ? void 0 : _a.tax_fee_rounding_remainder) || 0);
597
- }
598
- const surchargeFeeRoundingRemainder = new import_decimal.default(((_b = bundleItem.metadata) == null ? void 0 : _b.surcharge_rounding_remainder) || 0);
599
- return taxFeeRoundingRemainder.add(surchargeFeeRoundingRemainder).toNumber();
600
- };
601
- var getBundleItemDiscountDifference = (bundleItem) => {
602
- var _a;
603
- return new import_decimal.default(((_a = bundleItem.metadata) == null ? void 0 : _a.product_discount_difference) || 0).toNumber();
604
- };
605
- var getBundleItemPrice = (bundleItem, parentQuantity, isDeductTaxAndFee) => {
606
- var _a;
607
- const totalQuantity = bundleItem.num * parentQuantity;
608
- let bundleItemPrice = new import_decimal.default(bundleItem.bundle_selling_price ?? 0).times(totalQuantity);
609
- if (isDeductTaxAndFee) {
610
- let taxFee = new import_decimal.default(bundleItem.tax_fee ?? 0).times(totalQuantity);
611
- if (bundleItem.is_price_include_tax === 1) {
612
- taxFee = new import_decimal.default(0);
613
- }
614
- const surchargeFee = new import_decimal.default(((_a = bundleItem.metadata) == null ? void 0 : _a.surcharge_fee) ?? 0).times(totalQuantity);
615
- bundleItemPrice = bundleItemPrice.add(taxFee).add(surchargeFee);
616
- }
617
- return bundleItemPrice.toNumber();
618
- };
619
- var expandProductsWithBundleItems = (products, deductTaxAndFee) => {
620
- const expandedProducts = [];
621
- products.forEach((product) => {
622
- const productQuantity = getProductQuantity(product);
623
- const unitPriceWithTax = getMainProductPrice(product, true);
624
- const unitPricePure = getMainProductPrice(product, false);
625
- const roundingRemainderWithTax = getTaxAndFeeRoundingRemainder(product, true);
626
- const discountDifference = getProductDiscountDifference(product);
627
- expandedProducts.push({
628
- ...product,
629
- is_bundle_item: false,
630
- parent_product_id: null,
631
- // 单价(用于按 quantity 计算抵扣)
632
- unitPriceWithTax: new import_decimal.default(unitPriceWithTax),
633
- unitPricePure: new import_decimal.default(unitPricePure),
634
- // 剩余可抵扣数量
635
- remainingQuantity: productQuantity,
636
- // 含税费的剩余金额(单价 * 数量 + 舍入余数 - 商品差额)
637
- remainingAmountWithTax: new import_decimal.default(unitPriceWithTax).times(productQuantity).add(roundingRemainderWithTax).sub(discountDifference),
638
- // 纯商品金额(不含税费,也需要减去商品差额)
639
- remainingAmountPure: new import_decimal.default(unitPricePure).times(productQuantity).sub(discountDifference)
640
- });
641
- if (product.product_bundle && product.product_bundle.length > 0) {
642
- product.product_bundle.forEach((bundleItem) => {
643
- if (getBundleItemIsOriginalPrice(bundleItem)) {
644
- const bundleQuantity = bundleItem.num * productQuantity;
645
- const bundleUnitPriceWithTax = new import_decimal.default(getBundleItemPrice(bundleItem, 1, true)).dividedBy(bundleItem.num);
646
- const bundleUnitPricePure = new import_decimal.default(getBundleItemPrice(bundleItem, 1, false)).dividedBy(bundleItem.num);
647
- const bundleRoundingRemainder = getBundleItemTaxAndFeeRoundingRemainder(bundleItem, true);
648
- const bundleDiscountDifference = getBundleItemDiscountDifference(bundleItem);
649
- expandedProducts.push({
650
- ...bundleItem,
651
- product_id: bundleItem.bundle_product_id,
652
- // 使用 bundle_product_id 作为 product_id
653
- is_bundle_item: true,
654
- parent_product_id: product.product_id,
655
- quantity: bundleQuantity,
656
- // 子商品数量 * 主商品数量
657
- // 单价(用于按 quantity 计算抵扣)
658
- unitPriceWithTax: bundleUnitPriceWithTax,
659
- unitPricePure: bundleUnitPricePure,
660
- // 剩余可抵扣数量
661
- remainingQuantity: bundleQuantity,
662
- // 含税费的剩余金额(总价 + 舍入余数 - 商品差额)
663
- remainingAmountWithTax: new import_decimal.default(getBundleItemPrice(bundleItem, productQuantity, true)).add(bundleRoundingRemainder).sub(bundleDiscountDifference),
664
- // 纯商品金额(不含税费,也需要减去商品差额)
665
- remainingAmountPure: new import_decimal.default(getBundleItemPrice(bundleItem, productQuantity, false)).sub(bundleDiscountDifference)
666
- });
667
- }
668
- });
669
- }
670
- });
671
- return expandedProducts;
672
- };
673
- var getProductQuantity = (product) => {
674
- return product.quantity || product.product_quantity || 1;
675
- };
676
- var getBundleItemIsOriginalPrice = (item) => {
677
- return (item == null ? void 0 : item.price_type) === "markup" && (item == null ? void 0 : item.price_type_ext) === "product_price";
678
- };
679
- var getBundleItemIsMarkupPrice = (item) => {
680
- return (item == null ? void 0 : item.price_type) === "markup" && ((item == null ? void 0 : item.price_type_ext) === "" || !(item == null ? void 0 : item.price_type_ext));
681
- };
682
- var getBundleItemIsDiscountPrice = (item) => {
683
- return (item == null ? void 0 : item.price_type) === "markdown" && ((item == null ? void 0 : item.price_type_ext) === "" || !(item == null ? void 0 : item.price_type_ext));
684
- };
685
- var getBundleItemIsMarkupOrDiscountPrice = (item) => {
686
- return getBundleItemIsMarkupPrice(item) || getBundleItemIsDiscountPrice(item);
687
- };
688
- // Annotate the CommonJS export names for ESM import in node:
689
- 0 && (module.exports = {
690
- getApplicableProductIds,
691
- getBundleItemDiscountDifference,
692
- getBundleItemIsDiscountPrice,
693
- getBundleItemIsMarkupOrDiscountPrice,
694
- getBundleItemIsMarkupPrice,
695
- getBundleItemIsOriginalPrice,
696
- getBundleItemPrice,
697
- getBundleItemTaxAndFeeRoundingRemainder,
698
- getMainProductPrice,
699
- getProductDiscountDifference,
700
- getProductQuantity,
701
- getTaxAndFeeRoundingRemainder,
702
- processVouchers,
703
- recalculateVouchers
704
- });