@pisell/pisellos 2.2.101 → 2.2.103

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.
@@ -38,10 +38,72 @@ __export(utils_exports, {
38
38
  getMainProductPrice: () => getMainProductPrice,
39
39
  getProductQuantity: () => getProductQuantity,
40
40
  processVouchers: () => processVouchers,
41
- recalculateVouchers: () => recalculateVouchers
41
+ recalculateVouchers: () => recalculateVouchers,
42
+ resolveWalletPassLineKey: () => resolveWalletPassLineKey
42
43
  });
43
44
  module.exports = __toCommonJS(utils_exports);
44
45
  var import_decimal = __toESM(require("decimal.js"));
46
+ var getProductQuantity = (product) => {
47
+ return product.quantity || product.product_quantity || 1;
48
+ };
49
+ function resolveWalletPassLineKey(product, indexInOrder) {
50
+ const m = (product == null ? void 0 : product.metadata) || {};
51
+ const u1 = m.product_unique;
52
+ if (u1 != null && String(u1).length > 0)
53
+ return String(u1);
54
+ const u2 = m.unique_identification_number;
55
+ if (u2 != null && String(u2).length > 0)
56
+ return String(u2);
57
+ if ((product == null ? void 0 : product.id) != null && String(product.id).length > 0)
58
+ return `order_item:${product.id}`;
59
+ if ((product == null ? void 0 : product.product_unique_string) != null && String(product.product_unique_string).length > 0) {
60
+ return String(product.product_unique_string);
61
+ }
62
+ return `order_line_${indexInOrder}`;
63
+ }
64
+ function getExpandedOrderLineQuantity(p) {
65
+ if ((p == null ? void 0 : p._orderLineQuantity) != null && p._orderLineQuantity > 0)
66
+ return p._orderLineQuantity;
67
+ return getProductQuantity(p);
68
+ }
69
+ function getMaxPassSlotsForExpandedLine(maxPassesPerItem, p) {
70
+ if (maxPassesPerItem <= 0)
71
+ return Infinity;
72
+ return maxPassesPerItem * getExpandedOrderLineQuantity(p);
73
+ }
74
+ function computePassSlotsIncrement(deductAmount, deductQty, maxPassesPerItem, orderLineQuantity, currentUsage) {
75
+ if (maxPassesPerItem <= 0 || !deductAmount.greaterThan(0))
76
+ return 0;
77
+ const cap = maxPassesPerItem * orderLineQuantity;
78
+ const room = Math.max(0, cap - currentUsage);
79
+ if (room <= 0)
80
+ return 0;
81
+ const raw = Math.max(1, Math.ceil(Number(deductQty)) || 1);
82
+ return Math.min(raw, room);
83
+ }
84
+ function applyMaxPassUsageIncrements(usageMap, walletPassProductId, maxPassesPerItem, deductionDetails) {
85
+ deductionDetails.forEach((detail) => {
86
+ var _a;
87
+ const lineKey = detail.lineKey;
88
+ if (!lineKey || maxPassesPerItem <= 0)
89
+ return;
90
+ const orderLineQty = detail.orderLineQuantity != null && detail.orderLineQuantity > 0 ? detail.orderLineQuantity : 1;
91
+ const cur = ((_a = usageMap.get(walletPassProductId)) == null ? void 0 : _a.get(lineKey)) || 0;
92
+ const inc = computePassSlotsIncrement(
93
+ new import_decimal.default(detail.deductAmount),
94
+ detail.deductQuantity,
95
+ maxPassesPerItem,
96
+ orderLineQty,
97
+ cur
98
+ );
99
+ if (inc <= 0)
100
+ return;
101
+ if (!usageMap.has(walletPassProductId))
102
+ usageMap.set(walletPassProductId, /* @__PURE__ */ new Map());
103
+ const inner = usageMap.get(walletPassProductId);
104
+ inner.set(lineKey, cur + inc);
105
+ });
106
+ }
45
107
  var getRecommendedAmount = (voucher) => {
46
108
  console.log("voucher312", voucher);
47
109
  const { config, recommended_usage_amount, recommended_pure_product_usage_amount } = voucher;
@@ -82,30 +144,23 @@ var getApplicableProducts = (voucher, productsData) => {
82
144
  }
83
145
  return productsData.filter((p) => applicableProductIds.includes(p.product_id));
84
146
  };
85
- var getTotalQuantityByProductId = (allProducts, productId) => {
86
- return allProducts.filter((p) => p.product_id === productId).reduce((sum, p) => sum + getProductQuantity(p), 0);
87
- };
88
147
  function processVouchers(applicableVouchers, orderTotalAmount, products) {
89
148
  console.log(products, "products123");
90
149
  const productsCopy = expandProductsWithBundleItems(products, true);
91
150
  let remainingOrderAmount = new import_decimal.default(orderTotalAmount);
92
- const getItemPassUsage = (usageMap, walletPassProductId, orderItemProductId) => {
151
+ const getItemPassUsage = (usageMap, walletPassProductId, lineKey) => {
93
152
  var _a;
94
- return ((_a = usageMap.get(walletPassProductId)) == null ? void 0 : _a.get(orderItemProductId)) || 0;
153
+ return ((_a = usageMap.get(walletPassProductId)) == null ? void 0 : _a.get(lineKey)) || 0;
95
154
  };
96
- const incrementItemPassUsage = (usageMap, walletPassProductId, orderItemProductId, count = 1) => {
97
- if (!usageMap.has(walletPassProductId)) {
98
- usageMap.set(walletPassProductId, /* @__PURE__ */ new Map());
99
- }
100
- const innerMap = usageMap.get(walletPassProductId);
101
- innerMap.set(orderItemProductId, (innerMap.get(orderItemProductId) || 0) + count);
102
- };
103
- const filterByMaxPassesPerItem = (products2, allProducts, usageMap, walletPassProductId, maxPassesPerItem) => {
155
+ const filterByMaxPassesPerItem = (products2, usageMap, walletPassProductId, maxPassesPerItem) => {
104
156
  if (maxPassesPerItem <= 0)
105
157
  return products2;
106
- return products2.filter(
107
- (p) => getItemPassUsage(usageMap, walletPassProductId, p.product_id) < maxPassesPerItem * getTotalQuantityByProductId(allProducts, p.product_id)
108
- );
158
+ return products2.filter((p) => {
159
+ const lineKey = p._walletPassLineKey;
160
+ if (!lineKey)
161
+ return true;
162
+ return getItemPassUsage(usageMap, walletPassProductId, lineKey) < getMaxPassSlotsForExpandedLine(maxPassesPerItem, p);
163
+ });
109
164
  };
110
165
  const calculateAvailableMaxAmount = (voucher, productsData, itemPassUsage) => {
111
166
  const { config } = voucher;
@@ -119,7 +174,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
119
174
  const amountField = deductTaxAndFee ? "remainingAmountWithTax" : "remainingAmountPure";
120
175
  let applicableProducts = getApplicableProducts(voucher, productsData).filter((p) => p[amountField].greaterThan(0));
121
176
  if (itemPassUsage) {
122
- applicableProducts = filterByMaxPassesPerItem(applicableProducts, productsData, itemPassUsage, voucher.product_id, maxPassesPerItem);
177
+ applicableProducts = filterByMaxPassesPerItem(applicableProducts, itemPassUsage, voucher.product_id, maxPassesPerItem);
123
178
  }
124
179
  if (applicableProducts.length === 0) {
125
180
  return new import_decimal.default(0);
@@ -185,7 +240,12 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
185
240
  if (maxPassesPerItem > 0 && itemPassUsage) {
186
241
  const deductTaxAndFee = (config == null ? void 0 : config.deductTaxAndFee) ?? true;
187
242
  const amountField = deductTaxAndFee ? "remainingAmountWithTax" : "remainingAmountPure";
188
- const availableAfterPassLimit = getApplicableProducts(voucher, productsData).filter((p) => p[amountField].greaterThan(0)).filter((p) => getItemPassUsage(itemPassUsage, product_id, p.product_id) < maxPassesPerItem * getTotalQuantityByProductId(productsData, p.product_id));
243
+ const availableAfterPassLimit = getApplicableProducts(voucher, productsData).filter((p) => p[amountField].greaterThan(0)).filter((p) => {
244
+ const lineKey = p._walletPassLineKey;
245
+ if (!lineKey)
246
+ return true;
247
+ return getItemPassUsage(itemPassUsage, product_id, lineKey) < getMaxPassSlotsForExpandedLine(maxPassesPerItem, p);
248
+ });
189
249
  if (availableAfterPassLimit.length === 0) {
190
250
  return { isAvailable: false, reasonCode: "max_passes_per_item_reached" };
191
251
  }
@@ -235,7 +295,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
235
295
  voucher,
236
296
  productsForRecommendation
237
297
  ).filter((p) => p[amountField].greaterThan(0));
238
- applicableProducts = filterByMaxPassesPerItem(applicableProducts, productsForRecommendation, itemPassUsageMap, product_id, maxPassesPerItem);
298
+ applicableProducts = filterByMaxPassesPerItem(applicableProducts, itemPassUsageMap, product_id, maxPassesPerItem);
239
299
  if (applicableProducts.length === 0)
240
300
  return false;
241
301
  const usageAmount = typeof voucher.edit_current_amount === "number" ? voucher.edit_current_amount : getRecommendedAmount(voucher);
@@ -313,6 +373,8 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
313
373
  product_id: product.product_id,
314
374
  parent_product_id: product.parent_product_id || null,
315
375
  is_bundle_item: product.is_bundle_item || false,
376
+ lineKey: product._walletPassLineKey,
377
+ orderLineQuantity: getExpandedOrderLineQuantity(product),
316
378
  deductAmount: actualDeductAmount.toNumber(),
317
379
  // 转换为数字
318
380
  deductQuantity: actualDeductQty
@@ -338,6 +400,8 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
338
400
  product_id: targetProduct.product_id,
339
401
  parent_product_id: targetProduct.parent_product_id || null,
340
402
  is_bundle_item: targetProduct.is_bundle_item || false,
403
+ lineKey: targetProduct._walletPassLineKey,
404
+ orderLineQuantity: getExpandedOrderLineQuantity(targetProduct),
341
405
  deductAmount: actualDeductAmount.toNumber(),
342
406
  deductQuantity: actualDeductQty
343
407
  });
@@ -346,9 +410,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
346
410
  if (totalDeducted.greaterThan(0)) {
347
411
  remainingOrderAmount = remainingOrderAmount.minus(totalDeducted);
348
412
  usedVoucherCounts.set(product_id, (usedVoucherCounts.get(product_id) || 0) + 1);
349
- deductionDetails.forEach((detail) => {
350
- incrementItemPassUsage(itemPassUsageMap, product_id, detail.product_id, detail.deductQuantity);
351
- });
413
+ applyMaxPassUsageIncrements(itemPassUsageMap, product_id, maxPassesPerItem, deductionDetails);
352
414
  recommendedVouchers.push({
353
415
  ...voucher,
354
416
  actualDeduction: totalDeducted.toNumber(),
@@ -391,23 +453,19 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
391
453
  let remainingOrderAmount = new import_decimal.default(orderTotalAmount);
392
454
  const selectedWithDetails = [];
393
455
  const itemPassUsageMap = /* @__PURE__ */ new Map();
394
- const getItemPassUsage = (walletPassProductId, orderItemProductId) => {
456
+ const getItemPassUsageRecalc = (walletPassProductId, lineKey) => {
395
457
  var _a;
396
- return ((_a = itemPassUsageMap.get(walletPassProductId)) == null ? void 0 : _a.get(orderItemProductId)) || 0;
458
+ return ((_a = itemPassUsageMap.get(walletPassProductId)) == null ? void 0 : _a.get(lineKey)) || 0;
397
459
  };
398
- const incrementItemPassUsage = (walletPassProductId, orderItemProductId, count = 1) => {
399
- if (!itemPassUsageMap.has(walletPassProductId)) {
400
- itemPassUsageMap.set(walletPassProductId, /* @__PURE__ */ new Map());
401
- }
402
- const innerMap = itemPassUsageMap.get(walletPassProductId);
403
- innerMap.set(orderItemProductId, (innerMap.get(orderItemProductId) || 0) + count);
404
- };
405
- const filterByMaxPassesPerItem = (products2, walletPassProductId, maxPassesPerItem) => {
460
+ const filterByMaxPassesPerItemRecalc = (products2, walletPassProductId, maxPassesPerItem) => {
406
461
  if (maxPassesPerItem <= 0)
407
462
  return products2;
408
- return products2.filter(
409
- (p) => getItemPassUsage(walletPassProductId, p.product_id) < maxPassesPerItem * getTotalQuantityByProductId(productsForCalc, p.product_id)
410
- );
463
+ return products2.filter((p) => {
464
+ const lineKey = p._walletPassLineKey;
465
+ if (!lineKey)
466
+ return true;
467
+ return getItemPassUsageRecalc(walletPassProductId, lineKey) < getMaxPassSlotsForExpandedLine(maxPassesPerItem, p);
468
+ });
411
469
  };
412
470
  selectedVouchers.forEach((selectedVoucher) => {
413
471
  const { config, id } = selectedVoucher;
@@ -418,7 +476,7 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
418
476
  selectedVoucher,
419
477
  productsForCalc
420
478
  ).filter((p) => p[amountField].greaterThan(0));
421
- applicableProducts = filterByMaxPassesPerItem(applicableProducts, selectedVoucher.product_id, maxPassesPerItem);
479
+ applicableProducts = filterByMaxPassesPerItemRecalc(applicableProducts, selectedVoucher.product_id, maxPassesPerItem);
422
480
  if (applicableProducts.length === 0) {
423
481
  selectedWithDetails.push({
424
482
  ...selectedVoucher,
@@ -461,6 +519,8 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
461
519
  product_id: product.product_id,
462
520
  parent_product_id: product.parent_product_id || null,
463
521
  is_bundle_item: product.is_bundle_item || false,
522
+ lineKey: product._walletPassLineKey,
523
+ orderLineQuantity: getExpandedOrderLineQuantity(product),
464
524
  deductAmount: actualDeductAmount.toNumber(),
465
525
  // 转换为数字
466
526
  deductQuantity: actualDeductQty
@@ -486,15 +546,15 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
486
546
  product_id: targetProduct.product_id,
487
547
  parent_product_id: targetProduct.parent_product_id || null,
488
548
  is_bundle_item: targetProduct.is_bundle_item || false,
549
+ lineKey: targetProduct._walletPassLineKey,
550
+ orderLineQuantity: getExpandedOrderLineQuantity(targetProduct),
489
551
  deductAmount: actualDeductAmount.toNumber(),
490
552
  deductQuantity: actualDeductQty
491
553
  });
492
554
  }
493
555
  const totalDeducted = maxDeduction.minus(deductionLeft);
494
556
  remainingOrderAmount = remainingOrderAmount.minus(totalDeducted);
495
- deductionDetails.forEach((detail) => {
496
- incrementItemPassUsage(selectedVoucher.product_id, detail.product_id, detail.deductQuantity);
497
- });
557
+ applyMaxPassUsageIncrements(itemPassUsageMap, selectedVoucher.product_id, maxPassesPerItem, deductionDetails);
498
558
  selectedWithDetails.push({
499
559
  ...selectedVoucher,
500
560
  actualDeduction: totalDeducted.toNumber(),
@@ -544,7 +604,7 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
544
604
  voucher,
545
605
  productsForCalc
546
606
  ).filter((p) => p[amountField].greaterThan(0));
547
- applicableProducts = filterByMaxPassesPerItem(applicableProducts, product_id, maxPassesPerItem);
607
+ applicableProducts = filterByMaxPassesPerItemRecalc(applicableProducts, product_id, maxPassesPerItem);
548
608
  if (applicableProducts.length === 0) {
549
609
  isAvailable = false;
550
610
  reasonCode = "not_meet_the_required_conditions";
@@ -649,14 +709,17 @@ var getBundleItemPrice = (bundleItem, parentQuantity, isDeductTaxAndFee) => {
649
709
  };
650
710
  var expandProductsWithBundleItems = (products, deductTaxAndFee) => {
651
711
  const expandedProducts = [];
652
- products.forEach((product) => {
712
+ products.forEach((product, indexInOrder) => {
653
713
  const productQuantity = getProductQuantity(product);
714
+ const parentLineKey = resolveWalletPassLineKey(product, indexInOrder);
654
715
  const unitPriceWithTax = getMainProductPrice(product, true);
655
716
  const unitPricePure = getMainProductPrice(product, false);
656
717
  expandedProducts.push({
657
718
  ...product,
658
719
  is_bundle_item: false,
659
720
  parent_product_id: null,
721
+ _walletPassLineKey: parentLineKey,
722
+ _orderLineQuantity: productQuantity,
660
723
  // 单价(用于按 quantity 计算抵扣)
661
724
  unitPriceWithTax: new import_decimal.default(unitPriceWithTax),
662
725
  unitPricePure: new import_decimal.default(unitPricePure),
@@ -671,6 +734,7 @@ var expandProductsWithBundleItems = (products, deductTaxAndFee) => {
671
734
  product.product_bundle.forEach((bundleItem) => {
672
735
  if (getBundleItemIsOriginalPrice(bundleItem)) {
673
736
  const bundleQuantity = bundleItem.num * productQuantity;
737
+ const bundleLineKey = `${parentLineKey}#bundle:${bundleItem.bundle_id}:${bundleItem.bundle_product_id}`;
674
738
  const bundleUnitPriceWithTax = new import_decimal.default(getBundleItemPrice(bundleItem, 1, true)).dividedBy(bundleItem.num);
675
739
  const bundleUnitPricePure = new import_decimal.default(getBundleItemPrice(bundleItem, 1, false)).dividedBy(bundleItem.num);
676
740
  expandedProducts.push({
@@ -681,6 +745,8 @@ var expandProductsWithBundleItems = (products, deductTaxAndFee) => {
681
745
  parent_product_id: product.product_id,
682
746
  quantity: bundleQuantity,
683
747
  // 子商品数量 * 主商品数量
748
+ _walletPassLineKey: bundleLineKey,
749
+ _orderLineQuantity: bundleQuantity,
684
750
  // 单价(用于按 quantity 计算抵扣)
685
751
  unitPriceWithTax: bundleUnitPriceWithTax,
686
752
  unitPricePure: bundleUnitPricePure,
@@ -697,9 +763,6 @@ var expandProductsWithBundleItems = (products, deductTaxAndFee) => {
697
763
  });
698
764
  return expandedProducts;
699
765
  };
700
- var getProductQuantity = (product) => {
701
- return product.quantity || product.product_quantity || 1;
702
- };
703
766
  var getBundleItemIsOriginalPrice = (item) => {
704
767
  return (item == null ? void 0 : item.price_type) === "markup" && (item == null ? void 0 : item.price_type_ext) === "product_price";
705
768
  };
@@ -723,5 +786,6 @@ var getBundleItemIsMarkupOrDiscountPrice = (item) => {
723
786
  getMainProductPrice,
724
787
  getProductQuantity,
725
788
  processVouchers,
726
- recalculateVouchers
789
+ recalculateVouchers,
790
+ resolveWalletPassLineKey
727
791
  });
@@ -45,6 +45,18 @@ module.exports = __toCommonJS(cartProduct_exports);
45
45
  var import_decimal = __toESM(require("decimal.js"));
46
46
  var import_utils = require("../../Product/utils");
47
47
  var import_utils2 = require("../../../solution/ShopDiscount/utils");
48
+ var toDiscountPayload = (discountItem) => {
49
+ var _a, _b;
50
+ return {
51
+ amount: discountItem.amount,
52
+ tag: discountItem.type,
53
+ par_value: (_a = discountItem.discount) == null ? void 0 : _a.percent,
54
+ config: discountItem.config,
55
+ metadata: {
56
+ discount_card_type: (_b = discountItem == null ? void 0 : discountItem.discount) == null ? void 0 : _b.discount_card_type
57
+ }
58
+ };
59
+ };
48
60
  var handleVariantProduct = (product) => {
49
61
  var _a;
50
62
  if (product == null ? void 0 : product.product_variant_id) {
@@ -190,18 +202,24 @@ var formatProductToCartItemOrigin = (params) => {
190
202
  var getProductTotalPrice = (params) => {
191
203
  const { product, bundle, options, discounts } = params;
192
204
  let price = Number(product.price);
205
+ const optionRows = (options == null ? void 0 : options.map((currentValue) => ({
206
+ unit: Number(currentValue.price ?? currentValue.add_price ?? 0),
207
+ num: Number(currentValue.num ?? currentValue.quantity ?? 1)
208
+ }))) ?? [];
193
209
  if (discounts == null ? void 0 : discounts.length) {
194
210
  discounts.forEach((currentValue) => {
195
211
  var _a;
196
- price = (0, import_utils2.getDiscountAmount)({
197
- amount: currentValue.amount,
198
- tag: currentValue.type,
199
- par_value: currentValue.discount.percent,
200
- config: currentValue.config,
201
- metadata: {
202
- discount_card_type: (_a = currentValue == null ? void 0 : currentValue.discount) == null ? void 0 : _a.discount_card_type
212
+ const payload = toDiscountPayload(currentValue);
213
+ price = (0, import_utils2.getDiscountAmount)(payload, price, price);
214
+ if (((_a = currentValue == null ? void 0 : currentValue.config) == null ? void 0 : _a.deductOptionPrice) && optionRows.length) {
215
+ for (let i = 0; i < optionRows.length; i++) {
216
+ const row = optionRows[i];
217
+ optionRows[i] = {
218
+ ...row,
219
+ unit: (0, import_utils2.getDiscountAmount)(payload, row.unit, row.unit)
220
+ };
203
221
  }
204
- }, price, price);
222
+ }
205
223
  });
206
224
  }
207
225
  if (bundle == null ? void 0 : bundle.length) {
@@ -209,10 +227,11 @@ var getProductTotalPrice = (params) => {
209
227
  return accumulator + Number(currentValue.price) * Number(currentValue.num);
210
228
  }, price);
211
229
  }
212
- if (options == null ? void 0 : options.length) {
213
- price = options.reduce((accumulator, currentValue) => {
214
- return accumulator + Number(currentValue.price) * Number(currentValue.num);
215
- }, price);
230
+ if (optionRows.length) {
231
+ price = optionRows.reduce(
232
+ (accumulator, row) => accumulator + row.unit * row.num,
233
+ price
234
+ );
216
235
  }
217
236
  return Math.max(0, price);
218
237
  };
@@ -119,6 +119,8 @@ export interface Discount {
119
119
  allowCrossProduct?: boolean;
120
120
  /** 可用商品数量上限 */
121
121
  applicableProductLimit?: number;
122
+ /** 是否抵扣单规格价格 (Option Price) */
123
+ deductOptionPrice?: boolean;
122
124
  };
123
125
  applicableProductIds?: number[];
124
126
  applicableProductDetails: ApplicableProductDetails[];
@@ -23,7 +23,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
23
23
  */
24
24
  private logError;
25
25
  createOrder(params: CommitOrderParams['query']): {
26
- type: "appointment_booking" | "virtual";
26
+ type: "virtual" | "appointment_booking";
27
27
  platform: string;
28
28
  sales_channel: string;
29
29
  order_sales_channel: string;
@@ -49,5 +49,5 @@ export declare class Product extends BaseModule implements Module {
49
49
  getCategories(): ProductCategory[];
50
50
  setOtherParams(key: string, value: any): void;
51
51
  getOtherParams(): any;
52
- getProductType(): "duration" | "session" | "normal";
52
+ getProductType(): "normal" | "duration" | "session";
53
53
  }