@pisell/pisellos 0.10.7 → 0.10.8

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 (57) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  2. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +12 -10
  3. package/dist/modules/Order/index.d.ts +12 -5
  4. package/dist/modules/Order/index.js +310 -210
  5. package/dist/modules/Order/types.d.ts +26 -3
  6. package/dist/modules/Order/types.js +11 -0
  7. package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
  8. package/dist/modules/Order/utils/discountProductLineIdentity.js +227 -0
  9. package/dist/modules/Rules/index.js +125 -52
  10. package/dist/modules/SalesSummary/utils.js +7 -1
  11. package/dist/server/index.d.ts +6 -0
  12. package/dist/server/index.js +810 -729
  13. package/dist/server/modules/order/index.d.ts +1 -0
  14. package/dist/server/modules/order/index.js +9 -2
  15. package/dist/server/modules/order/types.d.ts +1 -1
  16. package/dist/solution/BaseSales/index.d.ts +15 -5
  17. package/dist/solution/BaseSales/index.js +211 -159
  18. package/dist/solution/BaseSales/utils/cartPromotion.js +26 -3
  19. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +1 -1
  20. package/dist/solution/BaseSales/utils.js +31 -20
  21. package/dist/solution/BookingByStep/index.d.ts +1 -1
  22. package/dist/solution/BookingTicket/index.js +1 -4
  23. package/dist/solution/BookingTicket/types.d.ts +3 -0
  24. package/dist/solution/BookingTicket/utils/cartView.js +44 -32
  25. package/dist/solution/Sales/index.d.ts +1 -0
  26. package/dist/solution/Sales/index.js +16 -2
  27. package/dist/solution/ScanOrder/utils.js +31 -20
  28. package/dist/solution/UnifiedBookingSales/index.d.ts +5 -4
  29. package/dist/solution/UnifiedBookingSales/index.js +51 -39
  30. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +3 -1
  31. package/lib/modules/Order/index.d.ts +12 -5
  32. package/lib/modules/Order/index.js +148 -43
  33. package/lib/modules/Order/types.d.ts +26 -3
  34. package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
  35. package/lib/modules/Order/utils/discountProductLineIdentity.js +170 -0
  36. package/lib/modules/Rules/index.js +100 -20
  37. package/lib/modules/SalesSummary/utils.js +5 -1
  38. package/lib/server/index.d.ts +6 -0
  39. package/lib/server/index.js +51 -0
  40. package/lib/server/modules/order/index.d.ts +1 -0
  41. package/lib/server/modules/order/index.js +9 -3
  42. package/lib/server/modules/order/types.d.ts +1 -1
  43. package/lib/solution/BaseSales/index.d.ts +15 -5
  44. package/lib/solution/BaseSales/index.js +64 -16
  45. package/lib/solution/BaseSales/utils/cartPromotion.js +26 -2
  46. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +1 -1
  47. package/lib/solution/BaseSales/utils.js +29 -18
  48. package/lib/solution/BookingByStep/index.d.ts +1 -1
  49. package/lib/solution/BookingTicket/index.js +1 -4
  50. package/lib/solution/BookingTicket/types.d.ts +3 -0
  51. package/lib/solution/BookingTicket/utils/cartView.js +43 -30
  52. package/lib/solution/Sales/index.d.ts +1 -0
  53. package/lib/solution/Sales/index.js +15 -3
  54. package/lib/solution/ScanOrder/utils.js +29 -18
  55. package/lib/solution/UnifiedBookingSales/index.d.ts +5 -4
  56. package/lib/solution/UnifiedBookingSales/index.js +35 -26
  57. package/package.json +1 -1
@@ -366,7 +366,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
366
366
  var discountType = selectedDiscount.tag || selectedDiscount.type;
367
367
  return selectedDiscount.isEditMode === true && selectedDiscount.isSelected === true && ['good_pass', 'discount_card', 'product_discount_card'].includes(discountType);
368
368
  };
369
- var resolveReapplyEditModeDiscountPercent = function resolveReapplyEditModeDiscountPercent(originProduct, selectedDiscount) {
369
+ var resolveReapplyBookingDiscountPercent = function resolveReapplyBookingDiscountPercent(originProduct, selectedDiscount) {
370
370
  var _discount2;
371
371
  if (!shouldReapplyBookingDiscount(originProduct, selectedDiscount)) return undefined;
372
372
  var discountType = (selectedDiscount === null || selectedDiscount === void 0 ? void 0 : selectedDiscount.tag) || (selectedDiscount === null || selectedDiscount === void 0 ? void 0 : selectedDiscount.type);
@@ -454,6 +454,9 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
454
454
  bundleIndex: bundleIndex,
455
455
  // 虚拟商品属性
456
456
  price: Number(bundleItem.price || 0),
457
+ // 新增商品运行态通常带 _bundle_product_id;订单 hydrate 后只有
458
+ // bundle_product_id。Change time 必须兼容两种结构,否则 bundle
459
+ // 子项无法命中折扣卡的 limited_relation_product_data.product_ids。
457
460
  id: (_ref3 = (_bundleItem$bundle_pr = bundleItem.bundle_product_id) !== null && _bundleItem$bundle_pr !== void 0 ? _bundleItem$bundle_pr : bundleItem._bundle_product_id) !== null && _ref3 !== void 0 ? _ref3 : bundleItem.product_id,
458
461
  _id: "".concat(product._id, "_bundle_").concat(bundleIndex),
459
462
  parentId: product._id,
@@ -1095,11 +1098,10 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1095
1098
  if (isPersistedProduct && hasExistingWalletDiscount) {
1096
1099
  if (flatItem.type === 'main') {
1097
1100
  processedProductsMap.set(product._id, [originProduct]);
1098
- } else {
1099
- processedFlatItemsMap.set(flatItem._id, [_objectSpread(_objectSpread({}, flatItem), {}, {
1100
- processed: true
1101
- })]);
1102
1101
  }
1102
+ // bundle 虚拟项没有携带完整的历史价格字段。这里不写入 processed map,
1103
+ // 重组阶段会直接保留原始 bundleItem,避免把 bundle_selling_price
1104
+ // 覆盖为未折扣的 price,导致已支付金额再次进入应付。
1103
1105
  return;
1104
1106
  }
1105
1107
 
@@ -1184,19 +1186,42 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1184
1186
  return false;
1185
1187
  });
1186
1188
 
1187
- // 用户显式点击某张折扣卡时,本次选择优先于自动排序和扫码默认选择。
1189
+ // 用户显式点击某张卡券时,本次选择优先于自动排序和扫码默认选择。
1188
1190
  // 目标仍必须在当前商品的 applicableDiscounts 中,因此不会绕过 Holder、时间或商品范围校验。
1189
- var explicitlySelectedDiscountCard = (options === null || options === void 0 ? void 0 : options.isSelected) === true && options.discountId !== undefined ? applicableDiscounts.find(function (discount) {
1191
+ var explicitlySelectedDiscount = (options === null || options === void 0 ? void 0 : options.isSelected) === true && options.discountId !== undefined ? applicableDiscounts.find(function (discount) {
1190
1192
  var discountType = discount.tag || discount.type;
1191
- return String(discount.id) === String(options.discountId) && ['discount_card', 'product_discount_card'].includes(discountType);
1193
+ return String(discount.id) === String(options.discountId) && ['good_pass', 'discount_card', 'product_discount_card'].includes(discountType);
1192
1194
  }) : undefined;
1195
+ // 折扣卡会复用于整条商品行;商品券必须继续按单张拆分,不能复用该分支。
1196
+ var explicitlySelectedDiscountCard = explicitlySelectedDiscount && (explicitlySelectedDiscount.tag || explicitlySelectedDiscount.type) !== 'good_pass' ? explicitlySelectedDiscount : undefined;
1197
+
1198
+ // 商品数量等变化会触发无 discountId 的重算。只要当前行已应用的折扣卡仍在
1199
+ // applicableDiscounts 中,就应保留该行选择,避免被自动排序中力度更大的卡替换。
1200
+ var appliedDiscountCardIds = new Set((product.discount_list || []).filter(function (item) {
1201
+ return ['discount_card', 'product_discount_card'].includes((item === null || item === void 0 ? void 0 : item.tag) || (item === null || item === void 0 ? void 0 : item.type));
1202
+ }).map(function (item) {
1203
+ var _ref12, _item$discount$resour, _item$discount;
1204
+ return (_ref12 = (_item$discount$resour = item === null || item === void 0 || (_item$discount = item.discount) === null || _item$discount === void 0 ? void 0 : _item$discount.resource_id) !== null && _item$discount$resour !== void 0 ? _item$discount$resour : item === null || item === void 0 ? void 0 : item.resource_id) !== null && _ref12 !== void 0 ? _ref12 : item === null || item === void 0 ? void 0 : item.id;
1205
+ }).filter(function (id) {
1206
+ return id !== undefined && id !== null;
1207
+ }).map(String));
1208
+ var appliedDiscountCard = options !== null && options !== void 0 && options.scan ? undefined : applicableDiscounts.find(function (discount) {
1209
+ var discountType = discount.tag || discount.type;
1210
+ return discount.isSelected === true && ['discount_card', 'product_discount_card'].includes(discountType) && appliedDiscountCardIds.has(String(discount.id));
1211
+ });
1193
1212
 
1194
- // 没有显式选择时保持现有行为:扫码且已选中的折扣卡优先,否则使用自动排序第一项。
1213
+ // 优先级:本次显式选择 > 当前行既有选择 > 扫码选择 > 自动排序第一项。
1195
1214
  var scannedSelectedDiscountCard = applicableDiscounts.find(function (n) {
1196
1215
  return n.isScan && n.isSelected && (n.tag || n.type) !== 'good_pass';
1197
1216
  });
1198
- var selectedDiscountCard = explicitlySelectedDiscountCard || scannedSelectedDiscountCard;
1199
- var selectedDiscount = selectedDiscountCard || applicableDiscounts[0];
1217
+ var selectedDiscountCard = explicitlySelectedDiscountCard || appliedDiscountCard || scannedSelectedDiscountCard;
1218
+ var selectedDiscount = explicitlySelectedDiscount || selectedDiscountCard || applicableDiscounts[0];
1219
+ var prioritizedApplicableDiscounts = explicitlySelectedDiscount && (explicitlySelectedDiscount.tag || explicitlySelectedDiscount.type) === 'good_pass' ? [explicitlySelectedDiscount].concat(_toConsumableArray(applicableDiscounts.filter(function (discount) {
1220
+ var discountType = discount.tag || discount.type;
1221
+ return discountType === 'good_pass' && String(discount.id) !== String(explicitlySelectedDiscount.id);
1222
+ })), _toConsumableArray(applicableDiscounts.filter(function (discount) {
1223
+ return (discount.tag || discount.type) !== 'good_pass';
1224
+ }))) : applicableDiscounts;
1200
1225
 
1201
1226
  // 如果是手动折扣,则不适用优惠券
1202
1227
  var isManualDiscount = false;
@@ -1207,8 +1232,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1207
1232
  isManualDiscount = typeof product.isManualDiscount === 'boolean' ? product.isManualDiscount : ((_product$discount_lis5 = product.discount_list) === null || _product$discount_lis5 === void 0 ? void 0 : _product$discount_lis5.some(function (item) {
1208
1233
  return item.type === 'product';
1209
1234
  })) || product.total != product.origin_total && (product.bundle || []).every(function (item) {
1210
- var _ref12;
1211
- return !((_ref12 = item.discount_list || []) !== null && _ref12 !== void 0 && _ref12.length);
1235
+ var _ref13;
1236
+ return !((_ref13 = item.discount_list || []) !== null && _ref13 !== void 0 && _ref13.length);
1212
1237
  }) && (!((_product$discount_lis6 = product.discount_list) !== null && _product$discount_lis6 !== void 0 && _product$discount_lis6.length) || ((_product11 = product) === null || _product11 === void 0 || (_product11 = _product11.discount_list) === null || _product11 === void 0 || (_product11$every = _product11.every) === null || _product11$every === void 0 ? void 0 : _product11$every.call(_product11, function (item) {
1213
1238
  return item.type === 'product';
1214
1239
  })));
@@ -1224,8 +1249,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1224
1249
  isManualDiscount = typeof parentProduct.isManualDiscount === 'boolean' ? parentProduct.isManualDiscount : ((_parentProduct$discou = parentProduct.discount_list) === null || _parentProduct$discou === void 0 ? void 0 : _parentProduct$discou.some(function (item) {
1225
1250
  return item.type === 'product';
1226
1251
  })) || parentProduct.total != parentProduct.origin_total && (parentProduct.bundle || []).every(function (item) {
1227
- var _ref13;
1228
- return !((_ref13 = item.discount_list || []) !== null && _ref13 !== void 0 && _ref13.length);
1252
+ var _ref14;
1253
+ return !((_ref14 = item.discount_list || []) !== null && _ref14 !== void 0 && _ref14.length);
1229
1254
  }) && (!((_parentProduct$discou2 = parentProduct.discount_list) !== null && _parentProduct$discou2 !== void 0 && _parentProduct$discou2.length) || (parentProduct === null || parentProduct === void 0 || (_parentProduct$discou3 = parentProduct.discount_list) === null || _parentProduct$discou3 === void 0 || (_parentProduct$discou4 = _parentProduct$discou3.every) === null || _parentProduct$discou4 === void 0 ? void 0 : _parentProduct$discou4.call(_parentProduct$discou3, function (item) {
1230
1255
  return item.type === 'product';
1231
1256
  })));
@@ -1237,8 +1262,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1237
1262
  var _product$discount_lis7;
1238
1263
  // 主商品:检查自己的 discount_list
1239
1264
  if (flatItem.type === 'main' && (_product$discount_lis7 = product.discount_list) !== null && _product$discount_lis7 !== void 0 && _product$discount_lis7.some(function (item) {
1240
- var _item$discount;
1241
- return ((_item$discount = item.discount) === null || _item$discount === void 0 ? void 0 : _item$discount.resource_id) === options.discountId;
1265
+ var _item$discount2;
1266
+ return ((_item$discount2 = item.discount) === null || _item$discount2 === void 0 ? void 0 : _item$discount2.resource_id) === options.discountId;
1242
1267
  })) {
1243
1268
  isManualDiscount = false;
1244
1269
  }
@@ -1246,11 +1271,11 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1246
1271
  if (flatItem.type === 'bundle') {
1247
1272
  var _product$discount_lis8, _flatItem$parentProdu7;
1248
1273
  if ((_product$discount_lis8 = product.discount_list) !== null && _product$discount_lis8 !== void 0 && _product$discount_lis8.some(function (item) {
1249
- var _item$discount2;
1250
- return ((_item$discount2 = item.discount) === null || _item$discount2 === void 0 ? void 0 : _item$discount2.resource_id) === options.discountId;
1251
- }) || (_flatItem$parentProdu7 = flatItem.parentProduct) !== null && _flatItem$parentProdu7 !== void 0 && (_flatItem$parentProdu7 = _flatItem$parentProdu7.discount_list) !== null && _flatItem$parentProdu7 !== void 0 && _flatItem$parentProdu7.some(function (item) {
1252
1274
  var _item$discount3;
1253
1275
  return ((_item$discount3 = item.discount) === null || _item$discount3 === void 0 ? void 0 : _item$discount3.resource_id) === options.discountId;
1276
+ }) || (_flatItem$parentProdu7 = flatItem.parentProduct) !== null && _flatItem$parentProdu7 !== void 0 && (_flatItem$parentProdu7 = _flatItem$parentProdu7.discount_list) !== null && _flatItem$parentProdu7 !== void 0 && _flatItem$parentProdu7.some(function (item) {
1277
+ var _item$discount4;
1278
+ return ((_item$discount4 = item.discount) === null || _item$discount4 === void 0 ? void 0 : _item$discount4.resource_id) === options.discountId;
1254
1279
  })) {
1255
1280
  isManualDiscount = false;
1256
1281
  }
@@ -1262,8 +1287,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1262
1287
  if (flatItem.type === 'main' && (_product$discount_lis9 = product.discount_list) !== null && _product$discount_lis9 !== void 0 && _product$discount_lis9.some(function (item) {
1263
1288
  var _options$selectedList2;
1264
1289
  return options === null || options === void 0 || (_options$selectedList2 = options.selectedList) === null || _options$selectedList2 === void 0 ? void 0 : _options$selectedList2.some(function (n) {
1265
- var _item$discount4;
1266
- return n.discountId === ((_item$discount4 = item.discount) === null || _item$discount4 === void 0 ? void 0 : _item$discount4.resource_id);
1290
+ var _item$discount5;
1291
+ return n.discountId === ((_item$discount5 = item.discount) === null || _item$discount5 === void 0 ? void 0 : _item$discount5.resource_id);
1267
1292
  });
1268
1293
  })) {
1269
1294
  isManualDiscount = false;
@@ -1274,14 +1299,14 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1274
1299
  if ((_product$discount_lis10 = product.discount_list) !== null && _product$discount_lis10 !== void 0 && _product$discount_lis10.some(function (item) {
1275
1300
  var _options$selectedList3;
1276
1301
  return options === null || options === void 0 || (_options$selectedList3 = options.selectedList) === null || _options$selectedList3 === void 0 ? void 0 : _options$selectedList3.some(function (n) {
1277
- var _item$discount5;
1278
- return n.discountId === ((_item$discount5 = item.discount) === null || _item$discount5 === void 0 ? void 0 : _item$discount5.resource_id);
1302
+ var _item$discount6;
1303
+ return n.discountId === ((_item$discount6 = item.discount) === null || _item$discount6 === void 0 ? void 0 : _item$discount6.resource_id);
1279
1304
  });
1280
1305
  }) || (_flatItem$parentProdu8 = flatItem.parentProduct) !== null && _flatItem$parentProdu8 !== void 0 && (_flatItem$parentProdu8 = _flatItem$parentProdu8.discount_list) !== null && _flatItem$parentProdu8 !== void 0 && _flatItem$parentProdu8.some(function (item) {
1281
1306
  var _options$selectedList4;
1282
1307
  return options === null || options === void 0 || (_options$selectedList4 = options.selectedList) === null || _options$selectedList4 === void 0 ? void 0 : _options$selectedList4.some(function (n) {
1283
- var _item$discount6;
1284
- return n.discountId === ((_item$discount6 = item.discount) === null || _item$discount6 === void 0 ? void 0 : _item$discount6.resource_id);
1308
+ var _item$discount7;
1309
+ return n.discountId === ((_item$discount7 = item.discount) === null || _item$discount7 === void 0 ? void 0 : _item$discount7.resource_id);
1285
1310
  });
1286
1311
  })) {
1287
1312
  isManualDiscount = false;
@@ -1318,8 +1343,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1318
1343
  discount_list: isManualDiscount ? _this4.resolveDiscountListForManualOverride(product.discount_list) : _this4.filterDiscountListByType(product.discount_list, 'promotion')
1319
1344
  }))]);
1320
1345
  } else {
1321
- var _ref14, _product$_promotion$f, _product12, _product$origin_total;
1322
- var total = product.inPromotion ? (_ref14 = (_product$_promotion$f = (_product12 = product) === null || _product12 === void 0 || (_product12 = _product12._promotion) === null || _product12 === void 0 ? void 0 : _product12.finalPrice) !== null && _product$_promotion$f !== void 0 ? _product$_promotion$f : product.origin_total) !== null && _ref14 !== void 0 ? _ref14 : product.total : (_product$origin_total = product.origin_total) !== null && _product$origin_total !== void 0 ? _product$origin_total : product.total;
1346
+ var _ref15, _product$_promotion$f, _product12, _product$origin_total;
1347
+ var total = product.inPromotion ? (_ref15 = (_product$_promotion$f = (_product12 = product) === null || _product12 === void 0 || (_product12 = _product12._promotion) === null || _product12 === void 0 ? void 0 : _product12.finalPrice) !== null && _product$_promotion$f !== void 0 ? _product$_promotion$f : product.origin_total) !== null && _ref15 !== void 0 ? _ref15 : product.total : (_product$origin_total = product.origin_total) !== null && _product$origin_total !== void 0 ? _product$origin_total : product.total;
1323
1348
  var main_product_selling_price = product.price;
1324
1349
  if ((product.discount_list || []).some(function (item) {
1325
1350
  return item.type === 'promotion';
@@ -1380,7 +1405,44 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1380
1405
  if (flatItem.type === 'main') {
1381
1406
  // 主商品:保持原有逻辑
1382
1407
  if (splitCount < totalQuantity && isNeedSplit) {
1383
- var _product$origin_total2;
1408
+ var _product$origin_total2, _product$main_product2;
1409
+ var remainingQuantity = totalQuantity - splitCount;
1410
+ var applicableNonGoodPassById = new Map(applicableDiscounts.filter(function (discount) {
1411
+ return (discount.tag || discount.type) !== 'good_pass';
1412
+ }).map(function (discount) {
1413
+ return [String(discount.id), discount];
1414
+ }));
1415
+ var remainderDiscountList = (product.discount_list || []).filter(function (discount) {
1416
+ var _discount$discount$re, _discount$discount5;
1417
+ var discountType = discount.tag || discount.type;
1418
+ if (discountType === 'promotion') return true;
1419
+ if (discountType === 'good_pass') return false;
1420
+ var resourceId = (_discount$discount$re = (_discount$discount5 = discount.discount) === null || _discount$discount5 === void 0 ? void 0 : _discount$discount5.resource_id) !== null && _discount$discount$re !== void 0 ? _discount$discount$re : discount.id;
1421
+ return resourceId !== undefined && resourceId !== null && applicableNonGoodPassById.has(String(resourceId));
1422
+ }).map(function (discount) {
1423
+ var _discount$discount$re2, _discount$discount6;
1424
+ if ((discount.tag || discount.type) === 'promotion') return discount;
1425
+ var resourceId = (_discount$discount$re2 = (_discount$discount6 = discount.discount) === null || _discount$discount6 === void 0 ? void 0 : _discount$discount6.resource_id) !== null && _discount$discount$re2 !== void 0 ? _discount$discount$re2 : discount.id;
1426
+ var matchedDiscount = applicableNonGoodPassById.get(String(resourceId));
1427
+ if (matchedDiscount) {
1428
+ // 实际场景:3 件折扣卡商品中拆出 1 件改用商品券后,
1429
+ // 剩余 2 件仍在使用原折扣卡;必须同步登记折扣卡的使用状态,
1430
+ // 否则 updatedDiscountList 会把它改成未选中并清空 savedAmount。
1431
+ usedDiscounts.set(matchedDiscount.id, true);
1432
+ var appliedProducts = appliedDiscountProducts.get(matchedDiscount.id) || [];
1433
+ appliedProducts.push(_objectSpread(_objectSpread({}, discount), {}, {
1434
+ _num: remainingQuantity
1435
+ }));
1436
+ appliedDiscountProducts.set(matchedDiscount.id, appliedProducts);
1437
+ }
1438
+ return _objectSpread(_objectSpread({}, discount), {}, {
1439
+ // _num 是 Rules 运行态的行数量;Order 写回 tempOrder 时会裁剪该字段。
1440
+ _num: remainingQuantity
1441
+ });
1442
+ });
1443
+ var hasRetainedWalletDiscount = remainderDiscountList.some(function (discount) {
1444
+ return !['promotion', 'good_pass'].includes(discount.tag || discount.type);
1445
+ });
1384
1446
  var _total = (_product$origin_total2 = product.origin_total) !== null && _product$origin_total2 !== void 0 ? _product$origin_total2 : product.total;
1385
1447
  if ((product.discount_list || []).some(function (item) {
1386
1448
  return item.type === 'promotion';
@@ -1388,17 +1450,20 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1388
1450
  var _product$total2;
1389
1451
  _total = (_product$total2 = product.total) !== null && _product$total2 !== void 0 ? _product$total2 : product.origin_total;
1390
1452
  }
1391
- arr.push(_this4.hooks.setProduct(originProduct, {
1392
- discount_list: _this4.filterDiscountListByType(product.discount_list, 'promotion'),
1393
- quantity: totalQuantity - splitCount,
1453
+ arr.push(_this4.hooks.setProduct(originProduct, _objectSpread({
1454
+ // 商品券只替换被拆出的 splitCount 件。余量行原本仍有效的折扣卡
1455
+ // 不能随 good_pass 拆分一起清除;已取消或已失效的折扣不会进入此列表。
1456
+ discount_list: remainderDiscountList,
1457
+ quantity: remainingQuantity,
1394
1458
  _id: product._id.split('___')[0],
1395
1459
  total: _total
1396
- }));
1460
+ }, hasRetainedWalletDiscount ? {
1461
+ main_product_selling_price: (_product$main_product2 = product.main_product_selling_price) !== null && _product$main_product2 !== void 0 ? _product$main_product2 : product.price
1462
+ } : {})));
1397
1463
  }
1398
1464
  for (var i = 0; i < splitCount; i++) {
1399
1465
  var _originProduct4, _selectedDiscount$con, _product$options, _product$options2, _selectedDiscount$met, _selectedDiscount$met2, _reapplyDiscountPerce;
1400
- // 如果用过折扣卡,也就不存在拆分的情况了,这里直接使用上面计算出来的折扣卡
1401
- var _selectedDiscount = selectedDiscountCard || applicableDiscounts[i];
1466
+ var _selectedDiscount = isNeedSplit ? prioritizedApplicableDiscounts[i] : selectedDiscountCard || applicableDiscounts[i];
1402
1467
  // 标记优惠券为已使用
1403
1468
  usedDiscounts.set(_selectedDiscount.id, true);
1404
1469
  // 🔥 更新 product_id 使用计数
@@ -1440,9 +1505,9 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1440
1505
  amount = productAllocation.discountAmount;
1441
1506
  productDiscountDifference = productAllocation.difference;
1442
1507
  mainProductSellingPrice = Math.max(new Decimal(product.price).minus(amount).toNumber(), 0);
1443
- } else if (resolveReapplyEditModeDiscountPercent(originProduct, _selectedDiscount) !== undefined) {
1508
+ } else if (resolveReapplyBookingDiscountPercent(originProduct, _selectedDiscount) !== undefined) {
1444
1509
  // Change time 重套编辑态折扣卡时,历史 par_value 不是运行时折扣口径,优先使用后端快照里的 percent。
1445
- var percent = resolveReapplyEditModeDiscountPercent(originProduct, _selectedDiscount);
1510
+ var percent = resolveReapplyBookingDiscountPercent(originProduct, _selectedDiscount);
1446
1511
  reapplyDiscountPercent = new Decimal(percent).toFixed(2);
1447
1512
  mainProductSellingPrice = new Decimal(product.price || 0).mul(new Decimal(100).minus(percent)).div(100).toDecimalPlaces(2).toNumber();
1448
1513
  amount = new Decimal(product.price).minus(mainProductSellingPrice).toNumber();
@@ -1543,7 +1608,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1543
1608
  // 生成有折扣的商品(每张商品券对应 num: 1)
1544
1609
  for (var _i = 0; _i < discountNum; _i++) {
1545
1610
  var _selectedDiscount2$me;
1546
- var _selectedDiscount2 = applicableDiscounts[_i];
1611
+ var _selectedDiscount2 = prioritizedApplicableDiscounts[_i];
1547
1612
  usedDiscounts.set(_selectedDiscount2.id, true);
1548
1613
  // 🔥 更新 product_id 使用计数
1549
1614
  if ((_selectedDiscount2.tag || _selectedDiscount2.type) === 'good_pass') {
@@ -1610,7 +1675,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1610
1675
  }));
1611
1676
  }
1612
1677
  } else {
1613
- var _selectedDiscount3$me, _selectedDiscount3$me2, _flatItem$parentProdu9;
1678
+ var _selectedDiscount3$me, _selectedDiscount3$me2, _reapplyDiscountPerce2, _flatItem$parentProdu9;
1614
1679
  // 折扣卡:不拆分数量,直接应用
1615
1680
  var _selectedDiscount3 = selectedDiscountCard || applicableDiscounts[0];
1616
1681
  usedDiscounts.set(_selectedDiscount3.id, true);
@@ -1628,11 +1693,19 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1628
1693
  var targetProductTotal;
1629
1694
  var fixedAmountPerItem;
1630
1695
  var _productDiscountDifference;
1696
+ var _reapplyDiscountPercent;
1631
1697
  if (_isOrderLevel && _productAllocation) {
1632
1698
  // order_level:使用预计算的单价折扣金额(已经是单价,无需再除以数量)
1633
1699
  fixedAmountPerItem = _productAllocation.discountAmount;
1634
1700
  _productDiscountDifference = _productAllocation.difference;
1635
1701
  targetProductTotal = Math.max(new Decimal(_productOriginTotal).minus(fixedAmountPerItem).toNumber(), 0);
1702
+ } else if (resolveReapplyBookingDiscountPercent(originProduct, _selectedDiscount3) !== undefined) {
1703
+ // hydrate 后 par_value 可能是余额/原值(例如 3500),百分比口径以
1704
+ // 后端折扣快照 discount.percent 为准,与主商品重套逻辑保持一致。
1705
+ var _percent = resolveReapplyBookingDiscountPercent(originProduct, _selectedDiscount3);
1706
+ _reapplyDiscountPercent = new Decimal(_percent).toFixed(2);
1707
+ targetProductTotal = new Decimal(_productOriginTotal).mul(new Decimal(100).minus(_percent)).div(100).toDecimalPlaces(2).toNumber();
1708
+ fixedAmountPerItem = new Decimal(_productOriginTotal).minus(targetProductTotal).toNumber();
1636
1709
  } else {
1637
1710
  // item_level 或其他类型:使用原有逻辑
1638
1711
  targetProductTotal = getDiscountAmount(_selectedDiscount3, _productOriginTotal, _productOriginTotal);
@@ -1653,7 +1726,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1653
1726
  title: _selectedDiscount3.format_title,
1654
1727
  original_amount: product.original_price,
1655
1728
  product_id: product.id || product.product_id,
1656
- percent: _selectedDiscount3.par_value,
1729
+ percent: (_reapplyDiscountPerce2 = _reapplyDiscountPercent) !== null && _reapplyDiscountPerce2 !== void 0 ? _reapplyDiscountPerce2 : _selectedDiscount3.par_value,
1657
1730
  discount_product_id: _selectedDiscount3.product_id
1658
1731
  },
1659
1732
  metadata: _objectSpread({
@@ -1969,7 +2042,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1969
2042
  } else {
1970
2043
  // 🔥 没有子商品被拆分,使用原有逻辑
1971
2044
  mainProductArr.forEach(function (mainProduct) {
1972
- var _ref16, _mainProductData$main, _mainProductData$disc, _mainProductData$disc2, _mainProductData$disc3;
2045
+ var _ref17, _mainProductData$main, _mainProductData$disc, _mainProductData$disc2, _mainProductData$disc3;
1973
2046
  var mainProductData = _this4.hooks.getProduct(mainProduct);
1974
2047
 
1975
2048
  // 重组bundle
@@ -1984,9 +2057,9 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1984
2057
  } else {
1985
2058
  // 🔥 关键:拆分后的bundle item
1986
2059
  processedBundleItems.forEach(function (item) {
1987
- var _item$price, _ref15, _item$bundle_selling_;
2060
+ var _item$price, _ref16, _item$bundle_selling_;
1988
2061
  var nextBundlePrice = (_item$price = item.price) !== null && _item$price !== void 0 ? _item$price : bundleItem.price;
1989
- var nextBundleSellingPrice = (_ref15 = (_item$bundle_selling_ = item.bundle_selling_price) !== null && _item$bundle_selling_ !== void 0 ? _item$bundle_selling_ : item.price) !== null && _ref15 !== void 0 ? _ref15 : bundleItem.bundle_selling_price;
2062
+ var nextBundleSellingPrice = (_ref16 = (_item$bundle_selling_ = item.bundle_selling_price) !== null && _item$bundle_selling_ !== void 0 ? _item$bundle_selling_ : item.price) !== null && _ref16 !== void 0 ? _ref16 : bundleItem.bundle_selling_price;
1990
2063
  // 🔥 更新 discount_list 中的 num,使其与拆分后的 item.num 一致
1991
2064
  var updatedDiscountList = (item.discount_list || []).map(function (discount) {
1992
2065
  var _discount$metadata10;
@@ -2013,7 +2086,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
2013
2086
 
2014
2087
  // 主商品已经在前面的 setProduct 中应用过折扣;这里只替换 bundle,
2015
2088
  // 避免把主商品 discount_list 再扣一次。
2016
- var mainSellingPrice = (_ref16 = (_mainProductData$main = mainProductData.main_product_selling_price) !== null && _mainProductData$main !== void 0 ? _mainProductData$main : mainProductData.price) !== null && _ref16 !== void 0 ? _ref16 : 0;
2089
+ var mainSellingPrice = (_ref17 = (_mainProductData$main = mainProductData.main_product_selling_price) !== null && _mainProductData$main !== void 0 ? _mainProductData$main : mainProductData.price) !== null && _ref17 !== void 0 ? _ref17 : 0;
2017
2090
  var newTotal = Number(mainSellingPrice || 0);
2018
2091
  var newOriginTotal = Number(mainProductData.original_price || mainProductData.price || 0);
2019
2092
 
@@ -2162,14 +2235,14 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
2162
2235
  var ruleType = usageRules.type;
2163
2236
  // 套餐适用范围配置
2164
2237
  var packageScope = usageRules === null || usageRules === void 0 ? void 0 : usageRules.package_scope;
2165
- var _ref17 = packageScope || {},
2166
- scopeType = _ref17.type,
2167
- _ref17$exclude_bundle = _ref17.exclude_bundle_product_ids,
2168
- exclude_bundle_product_ids = _ref17$exclude_bundle === void 0 ? [] : _ref17$exclude_bundle,
2169
- _ref17$include_bundle = _ref17.include_bundle_product_ids,
2170
- include_bundle_product_ids = _ref17$include_bundle === void 0 ? [] : _ref17$include_bundle,
2171
- _ref17$filter = _ref17.filter,
2172
- filter = _ref17$filter === void 0 ? 0 : _ref17$filter;
2238
+ var _ref18 = packageScope || {},
2239
+ scopeType = _ref18.type,
2240
+ _ref18$exclude_bundle = _ref18.exclude_bundle_product_ids,
2241
+ exclude_bundle_product_ids = _ref18$exclude_bundle === void 0 ? [] : _ref18$exclude_bundle,
2242
+ _ref18$include_bundle = _ref18.include_bundle_product_ids,
2243
+ include_bundle_product_ids = _ref18$include_bundle === void 0 ? [] : _ref18$include_bundle,
2244
+ _ref18$filter = _ref18.filter,
2245
+ filter = _ref18$filter === void 0 ? 0 : _ref18$filter;
2173
2246
  var isMainProduct = flatItem.type === 'main'; // 单独购买
2174
2247
  var isBundleItem = flatItem.type === 'bundle'; // 套餐中购买
2175
2248
  var bundleMainProductId = (_flatItem$product = flatItem.product) === null || _flatItem$product === void 0 ? void 0 : _flatItem$product.product_id;
@@ -87,7 +87,13 @@ function getUnitOriginalTotal(product) {
87
87
  function isGeneratedVoucherProduct(product) {
88
88
  var record = product;
89
89
  var metadata = (record === null || record === void 0 ? void 0 : record.metadata) || {};
90
- return (record === null || record === void 0 ? void 0 : record.extension_type) === 'product_voucher' || metadata.parent_order_detail_id !== undefined || metadata.gift_card_type !== undefined;
90
+ var isGeneratedChild = metadata.parent_order_detail_id !== undefined || metadata.gift_card_type !== undefined;
91
+ if (isGeneratedChild) return true;
92
+
93
+ // `product_voucher` 既可能是当前购物车生成的零价子券,也可能是独立售卖的
94
+ // gift card。已有 order_detail_id 且没有 parent 标记的是后者,必须继续计价。
95
+ var isPersisted = (record === null || record === void 0 ? void 0 : record.order_detail_id) !== undefined && (record === null || record === void 0 ? void 0 : record.order_detail_id) !== null;
96
+ return (record === null || record === void 0 ? void 0 : record.extension_type) === 'product_voucher' && !isPersisted;
91
97
  }
92
98
  function buildSurchargeServiceItems(products) {
93
99
  return products.map(function (product) {
@@ -164,6 +164,12 @@ declare class Server {
164
164
  * 不影响当前界面展示,适用于切回前台、定时刷新等场景
165
165
  */
166
166
  refreshOrdersInBackground(): Promise<void>;
167
+ /**
168
+ * 编辑正式订单时强制查询 Server 最新快照并覆盖本地缓存。
169
+ * 商品成员增删由 OrderModule 在 SQLite/Store 更新完成后广播,
170
+ * UI 可复用 order:onRemoteProductMembershipChanged 处理冲突。
171
+ */
172
+ checkRemoteOrderProductMembership(orderId: string | number): Promise<void>;
167
173
  /**
168
174
  * 清空所有server模块的IndexedDB缓存
169
175
  * @returns Promise<void>