@pisell/pisellos 0.0.479 → 0.0.480

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.
@@ -101,6 +101,18 @@ var getApplicableProducts = function getApplicableProducts(voucher, productsData
101
101
  });
102
102
  };
103
103
 
104
+ /**
105
+ * 计算指定 product_id 在展开后的商品列表中的总 quantity
106
+ * 处理同一 product_id 可能分散在多条记录中的情况(如3个独立的 quantity=1 条目)
107
+ */
108
+ var getTotalQuantityByProductId = function getTotalQuantityByProductId(allProducts, productId) {
109
+ return allProducts.filter(function (p) {
110
+ return p.product_id === productId;
111
+ }).reduce(function (sum, p) {
112
+ return sum + getProductQuantity(p);
113
+ }, 0);
114
+ };
115
+
104
116
  /**
105
117
  * 优惠券处理函数
106
118
  * @param applicableVouchers 可用的券列表
@@ -136,11 +148,11 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
136
148
  };
137
149
 
138
150
  // 按 maxPassesPerItem 过滤商品:排除已达到单商品可用卡券上限的商品
139
- // maxPassesPerItem 是 per-unit 的限制,总上限 = maxPassesPerItem × quantity
140
- var filterByMaxPassesPerItem = function filterByMaxPassesPerItem(products, usageMap, walletPassProductId, maxPassesPerItem) {
151
+ // maxPassesPerItem 是 per-unit 的限制,总上限 = maxPassesPerItem × 该 product_id 的总 quantity
152
+ var filterByMaxPassesPerItem = function filterByMaxPassesPerItem(products, allProducts, usageMap, walletPassProductId, maxPassesPerItem) {
141
153
  if (maxPassesPerItem <= 0) return products; // 0 = 不限制
142
154
  return products.filter(function (p) {
143
- return getItemPassUsage(usageMap, walletPassProductId, p.product_id) < maxPassesPerItem * getProductQuantity(p);
155
+ return getItemPassUsage(usageMap, walletPassProductId, p.product_id) < maxPassesPerItem * getTotalQuantityByProductId(allProducts, p.product_id);
144
156
  });
145
157
  };
146
158
  // ================================================================
@@ -177,7 +189,7 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
177
189
 
178
190
  // 按 maxPassesPerItem 过滤:排除已达到单商品可用卡券上限的商品
179
191
  if (itemPassUsage) {
180
- applicableProducts = filterByMaxPassesPerItem(applicableProducts, itemPassUsage, voucher.product_id, maxPassesPerItem);
192
+ applicableProducts = filterByMaxPassesPerItem(applicableProducts, productsData, itemPassUsage, voucher.product_id, maxPassesPerItem);
181
193
  }
182
194
  if (applicableProducts.length === 0) {
183
195
  return new Decimal(0);
@@ -219,9 +231,9 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
219
231
  }, new Decimal(0));
220
232
  }
221
233
  } else {
222
- // 非跨商品券:只能抵扣单个商品(剩余金额最高的)
234
+ // 非跨商品券:选择单价最高的商品(优先抵扣高价商品)
223
235
  var maxProduct = applicableProducts.reduce(function (max, p) {
224
- return p[amountField].greaterThan(max[amountField]) ? p : max;
236
+ return p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max;
225
237
  });
226
238
  // maxPassesPerItem 限制每张券最多抵扣的单位数
227
239
  if (maxPassesPerItem > 0) {
@@ -289,7 +301,7 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
289
301
  var availableAfterPassLimit = getApplicableProducts(voucher, productsData).filter(function (p) {
290
302
  return p[amountField].greaterThan(0);
291
303
  }).filter(function (p) {
292
- return getItemPassUsage(itemPassUsage, product_id, p.product_id) < maxPassesPerItem * getProductQuantity(p);
304
+ return getItemPassUsage(itemPassUsage, product_id, p.product_id) < maxPassesPerItem * getTotalQuantityByProductId(productsData, p.product_id);
293
305
  });
294
306
  if (availableAfterPassLimit.length === 0) {
295
307
  return {
@@ -386,7 +398,7 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
386
398
  });
387
399
 
388
400
  // 按 maxPassesPerItem 过滤:排除已达到单商品可用卡券上限的商品
389
- applicableProducts = filterByMaxPassesPerItem(applicableProducts, itemPassUsageMap, product_id, maxPassesPerItem);
401
+ applicableProducts = filterByMaxPassesPerItem(applicableProducts, productsForRecommendation, itemPassUsageMap, product_id, maxPassesPerItem);
390
402
  if (applicableProducts.length === 0) return false;
391
403
 
392
404
  // ========== 关键修改:在应用券之前,基于当前剩余金额计算 _available_max_amount ==========
@@ -428,9 +440,9 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
428
440
  }, new Decimal(0));
429
441
  }
430
442
  } else {
431
- // 非跨商品券:单个剩余金额最高的商品
443
+ // 非跨商品券:选择单价最高的商品(优先抵扣高价商品)
432
444
  var maxProduct = applicableProducts.reduce(function (max, p) {
433
- return p[amountField].greaterThan(max[amountField]) ? p : max;
445
+ return p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max;
434
446
  });
435
447
  // maxPassesPerItem 限制每张券最多抵扣的单位数
436
448
  if (maxPassesPerItem > 0) {
@@ -491,9 +503,9 @@ export function processVouchers(applicableVouchers, orderTotalAmount, products)
491
503
  _iterator3.f();
492
504
  }
493
505
  } else {
494
- // 非跨商品券:只抵扣一个商品(剩余金额最高的)
506
+ // 非跨商品券:选择单价最高的商品(优先抵扣高价商品)
495
507
  var targetProduct = applicableProducts.reduce(function (max, p) {
496
- return p[amountField].greaterThan(max[amountField]) ? p : max;
508
+ return p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max;
497
509
  });
498
510
 
499
511
  // maxPassesPerItem 限制每张券最多抵扣的单位数
@@ -629,7 +641,7 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
629
641
  var filterByMaxPassesPerItem = function filterByMaxPassesPerItem(products, walletPassProductId, maxPassesPerItem) {
630
642
  if (maxPassesPerItem <= 0) return products; // 0 = 不限制
631
643
  return products.filter(function (p) {
632
- return getItemPassUsage(walletPassProductId, p.product_id) < maxPassesPerItem * getProductQuantity(p);
644
+ return getItemPassUsage(walletPassProductId, p.product_id) < maxPassesPerItem * getTotalQuantityByProductId(productsForCalc, p.product_id);
633
645
  });
634
646
  };
635
647
 
@@ -717,9 +729,9 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
717
729
  _iterator4.f();
718
730
  }
719
731
  } else {
720
- // 非跨商品券:只抵扣一个商品(剩余金额最高的)
732
+ // 非跨商品券:选择单价最高的商品(优先抵扣高价商品)
721
733
  var targetProduct = applicableProducts.reduce(function (max, p) {
722
- return p[amountField].greaterThan(max[amountField]) ? p : max;
734
+ return p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max;
723
735
  });
724
736
 
725
737
  // maxPassesPerItem 限制每张券最多抵扣的单位数
@@ -864,9 +876,9 @@ export function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmo
864
876
  }, new Decimal(0));
865
877
  }
866
878
  } else {
867
- // 非跨商品券:单个剩余金额最高的商品
879
+ // 非跨商品券:选择单价最高的商品(优先抵扣高价商品)
868
880
  var maxProduct = applicableProducts.reduce(function (max, p) {
869
- return p[amountField].greaterThan(max[amountField]) ? p : max;
881
+ return p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max;
870
882
  });
871
883
  // maxPassesPerItem 限制每张券最多抵扣的单位数
872
884
  if (maxPassesPerItem > 0) {
@@ -86,6 +86,9 @@ var getApplicableProducts = (voucher, productsData) => {
86
86
  }
87
87
  return productsData.filter((p) => applicableProductIds.includes(p.product_id));
88
88
  };
89
+ var getTotalQuantityByProductId = (allProducts, productId) => {
90
+ return allProducts.filter((p) => p.product_id === productId).reduce((sum, p) => sum + getProductQuantity(p), 0);
91
+ };
89
92
  function processVouchers(applicableVouchers, orderTotalAmount, products) {
90
93
  console.log(products, "products123");
91
94
  const productsCopy = expandProductsWithBundleItems(products, true);
@@ -101,11 +104,11 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
101
104
  const innerMap = usageMap.get(walletPassProductId);
102
105
  innerMap.set(orderItemProductId, (innerMap.get(orderItemProductId) || 0) + count);
103
106
  };
104
- const filterByMaxPassesPerItem = (products2, usageMap, walletPassProductId, maxPassesPerItem) => {
107
+ const filterByMaxPassesPerItem = (products2, allProducts, usageMap, walletPassProductId, maxPassesPerItem) => {
105
108
  if (maxPassesPerItem <= 0)
106
109
  return products2;
107
110
  return products2.filter(
108
- (p) => getItemPassUsage(usageMap, walletPassProductId, p.product_id) < maxPassesPerItem * getProductQuantity(p)
111
+ (p) => getItemPassUsage(usageMap, walletPassProductId, p.product_id) < maxPassesPerItem * getTotalQuantityByProductId(allProducts, p.product_id)
109
112
  );
110
113
  };
111
114
  const calculateAvailableMaxAmount = (voucher, productsData, itemPassUsage) => {
@@ -120,7 +123,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
120
123
  const amountField = deductTaxAndFee ? "remainingAmountWithTax" : "remainingAmountPure";
121
124
  let applicableProducts = getApplicableProducts(voucher, productsData).filter((p) => p[amountField].greaterThan(0));
122
125
  if (itemPassUsage) {
123
- applicableProducts = filterByMaxPassesPerItem(applicableProducts, itemPassUsage, voucher.product_id, maxPassesPerItem);
126
+ applicableProducts = filterByMaxPassesPerItem(applicableProducts, productsData, itemPassUsage, voucher.product_id, maxPassesPerItem);
124
127
  }
125
128
  if (applicableProducts.length === 0) {
126
129
  return new import_decimal.default(0);
@@ -150,7 +153,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
150
153
  }
151
154
  } else {
152
155
  const maxProduct = applicableProducts.reduce(
153
- (max, p) => p[amountField].greaterThan(max[amountField]) ? p : max
156
+ (max, p) => p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max
154
157
  );
155
158
  if (maxPassesPerItem > 0) {
156
159
  finalApplicableAmount = import_decimal.default.min(
@@ -186,7 +189,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
186
189
  if (maxPassesPerItem > 0 && itemPassUsage) {
187
190
  const deductTaxAndFee = (config == null ? void 0 : config.deductTaxAndFee) ?? true;
188
191
  const amountField = deductTaxAndFee ? "remainingAmountWithTax" : "remainingAmountPure";
189
- const availableAfterPassLimit = getApplicableProducts(voucher, productsData).filter((p) => p[amountField].greaterThan(0)).filter((p) => getItemPassUsage(itemPassUsage, product_id, p.product_id) < maxPassesPerItem * getProductQuantity(p));
192
+ 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));
190
193
  if (availableAfterPassLimit.length === 0) {
191
194
  return { isAvailable: false, reasonCode: "max_passes_per_item_reached" };
192
195
  }
@@ -236,7 +239,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
236
239
  voucher,
237
240
  productsForRecommendation
238
241
  ).filter((p) => p[amountField].greaterThan(0));
239
- applicableProducts = filterByMaxPassesPerItem(applicableProducts, itemPassUsageMap, product_id, maxPassesPerItem);
242
+ applicableProducts = filterByMaxPassesPerItem(applicableProducts, productsForRecommendation, itemPassUsageMap, product_id, maxPassesPerItem);
240
243
  if (applicableProducts.length === 0)
241
244
  return false;
242
245
  const usageAmount = typeof voucher.edit_current_amount === "number" ? voucher.edit_current_amount : getRecommendedAmount(voucher);
@@ -269,7 +272,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
269
272
  }
270
273
  } else {
271
274
  const maxProduct = applicableProducts.reduce(
272
- (max, p) => p[amountField].greaterThan(max[amountField]) ? p : max
275
+ (max, p) => p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max
273
276
  );
274
277
  if (maxPassesPerItem > 0) {
275
278
  calculatedAvailableMaxAmount = import_decimal.default.min(
@@ -322,7 +325,7 @@ function processVouchers(applicableVouchers, orderTotalAmount, products) {
322
325
  }
323
326
  } else {
324
327
  const targetProduct = applicableProducts.reduce(
325
- (max, p) => p[amountField].greaterThan(max[amountField]) ? p : max
328
+ (max, p) => p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max
326
329
  );
327
330
  let maxDeductForProduct = targetProduct[amountField];
328
331
  if (maxPassesPerItem > 0) {
@@ -407,7 +410,7 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
407
410
  if (maxPassesPerItem <= 0)
408
411
  return products2;
409
412
  return products2.filter(
410
- (p) => getItemPassUsage(walletPassProductId, p.product_id) < maxPassesPerItem * getProductQuantity(p)
413
+ (p) => getItemPassUsage(walletPassProductId, p.product_id) < maxPassesPerItem * getTotalQuantityByProductId(productsForCalc, p.product_id)
411
414
  );
412
415
  };
413
416
  selectedVouchers.forEach((selectedVoucher) => {
@@ -470,7 +473,7 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
470
473
  }
471
474
  } else {
472
475
  const targetProduct = applicableProducts.reduce(
473
- (max, p) => p[amountField].greaterThan(max[amountField]) ? p : max
476
+ (max, p) => p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max
474
477
  );
475
478
  let maxDeductForProduct = targetProduct[amountField];
476
479
  if (maxPassesPerItem > 0) {
@@ -578,7 +581,7 @@ function recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, pr
578
581
  }
579
582
  } else {
580
583
  const maxProduct = applicableProducts.reduce(
581
- (max, p) => p[amountField].greaterThan(max[amountField]) ? p : max
584
+ (max, p) => p[unitPriceField].greaterThan(max[unitPriceField]) ? p : max
582
585
  );
583
586
  if (maxPassesPerItem > 0) {
584
587
  calculatedMaxAmount = import_decimal.default.min(
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "0.0.479",
4
+ "version": "0.0.480",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",