@pisell/pisellos 0.0.511 → 0.0.513

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 (33) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  2. package/dist/modules/Order/index.d.ts +1 -1
  3. package/dist/modules/Order/index.js +79 -58
  4. package/dist/modules/Order/types.d.ts +11 -0
  5. package/dist/modules/Order/utils.d.ts +63 -11
  6. package/dist/modules/Order/utils.js +242 -43
  7. package/dist/modules/SalesSummary/utils.js +36 -69
  8. package/dist/modules/Summary/utils.js +6 -21
  9. package/dist/solution/BookingByStep/index.d.ts +1 -1
  10. package/dist/solution/BookingTicket/index.d.ts +1 -1
  11. package/dist/solution/ScanOrder/index.d.ts +3 -0
  12. package/dist/solution/ScanOrder/index.js +558 -498
  13. package/dist/solution/ScanOrder/types.d.ts +29 -2
  14. package/dist/solution/ScanOrder/utils.d.ts +18 -2
  15. package/dist/solution/ScanOrder/utils.js +111 -29
  16. package/dist/solution/VenueBooking/index.js +35 -27
  17. package/lib/model/strategy/adapter/promotion/index.js +0 -49
  18. package/lib/modules/Order/index.d.ts +1 -1
  19. package/lib/modules/Order/index.js +20 -7
  20. package/lib/modules/Order/types.d.ts +11 -0
  21. package/lib/modules/Order/utils.d.ts +63 -11
  22. package/lib/modules/Order/utils.js +149 -17
  23. package/lib/modules/SalesSummary/utils.js +16 -48
  24. package/lib/modules/Summary/utils.js +4 -18
  25. package/lib/solution/BookingByStep/index.d.ts +1 -1
  26. package/lib/solution/BookingTicket/index.d.ts +1 -1
  27. package/lib/solution/ScanOrder/index.d.ts +3 -0
  28. package/lib/solution/ScanOrder/index.js +30 -4
  29. package/lib/solution/ScanOrder/types.d.ts +29 -2
  30. package/lib/solution/ScanOrder/utils.d.ts +18 -2
  31. package/lib/solution/ScanOrder/utils.js +66 -15
  32. package/lib/solution/VenueBooking/index.js +13 -6
  33. package/package.json +1 -1
@@ -39,14 +39,39 @@ export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
39
39
  order_detail_id: number | null;
40
40
  num: number;
41
41
  product_option_item: any[];
42
- /** 券后单品单价(= 订单域实际成交单价)。未应用券时等同 original_price。 */
42
+ /**
43
+ * 券后 **行 composite 单价** = `metadata.main_product_selling_price`
44
+ * + Σ((bundle.bundle_selling_price ?? bundle.price) × (bundle.num ?? 1))
45
+ *
46
+ * 新语义 v2 下 `metadata.main_product_selling_price` 已经**含 option**、含主商品折扣,
47
+ * 因此本字段不再叠加 option。未应用券时等同 `original_price`。
48
+ * Rules 钩子、主商品计税、Summary 统一读 metadata,不以此字段反推。
49
+ */
43
50
  selling_price: string;
44
- /** 券前单品单价(= 店铺售价),不承载后台划线价语义。 */
51
+ /**
52
+ * 券前 **行 composite 单价** = `metadata.main_product_original_price`
53
+ * + Σ(bundle 原价 × num)
54
+ *
55
+ * 新语义 v2 下 `metadata.main_product_original_price` 已经**含 option**、不含折扣。
56
+ * 不承载后台划线价语义。
57
+ */
45
58
  original_price: string;
46
59
  tax_fee: string;
47
60
  is_charge_tax: number;
48
61
  discount_list: any[];
49
62
  product_bundle: any[];
63
+ /**
64
+ * 行级扩展 metadata。价格相关的权威字段:
65
+ *
66
+ * - `source_product_price`:主商品/variant 基础价(已应用报价单),**不含 option、不含折扣**。
67
+ * 是派生 `main_product_*` 的唯一源。variant 分支优先读 `metadata.origin.variant[vid].price`。
68
+ * - `main_product_original_price` = `source_product_price + Σ(option.price × option.num)`,
69
+ * **含 option、不含折扣**。
70
+ * - `main_product_selling_price` = `main_product_original_price − 主商品券 per-unit amount`,
71
+ * **含 option、含主商品折扣**。Rules 钩子 / Summary / 计税均以此为主商品权威源。
72
+ * - `price_schema_version`(当前 = 2):schema 版本 sentinel,用于跨端协商价格口径、
73
+ * 区分 v1 旧缓存以便 `normalizeOrderProduct` 触发迁移。
74
+ */
50
75
  metadata: Record<string, any>;
51
76
  /** 商品行备注(如顾客对单品的特殊要求) */
52
77
  note?: string;
@@ -68,6 +93,8 @@ export interface ScanOrderSubmitProduct extends Omit<ScanOrderOrderProduct, '_or
68
93
  /**
69
94
  * 出站兼容字段:SDK 内部不再消费 payment_price,
70
95
  * 仅在提交后端时由 selling_price 派生,保持原有后端契约。
96
+ * 新语义 v2 下 selling_price 是 composite(含 option、含 bundle、含主商品折扣),
97
+ * 因此 payment_price 同样是 composite。
71
98
  */
72
99
  payment_price: string;
73
100
  }
@@ -108,10 +108,26 @@ export declare function isIdentityMatch(a: ScanOrderOrderProductIdentity, b: Sca
108
108
  */
109
109
  export declare function getProductIdentityIndex(products: ScanOrderOrderProduct[], identity: ScanOrderOrderProductIdentity): number;
110
110
  /**
111
- * 对外部传入的商品对象做归一化:
111
+ * 对外部传入的商品对象做归一化(v2 composite 语义):
112
112
  * - 补全可选字段默认值(未传则使用兜底值,避免后续计算时因 undefined 导致异常)
113
113
  * - 对 num 调用 getSafeProductNum 做安全处理
114
114
  * - 保留 _origin 供后续业务流程(如促销规则)使用
115
+ *
116
+ * 价格字段语义(metadata 权威源 + composite 派生):
117
+ * - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),**不含 option**、
118
+ * **不含折扣**。是推导 main_product_* 的起点。variant 分支优先读 `metadata.origin.variant[vid].price`。
119
+ * - `metadata.main_product_original_price`:`source + Σ(option.price × option.num)`,**含 option**、
120
+ * **不含折扣**。
121
+ * - `metadata.main_product_selling_price`:`main_product_original_price - 主商品券 per-unit amount`,
122
+ * **含 option**、**含折扣**。
123
+ * - 行级 `selling_price` = `main_product_selling_price + Σ(bundle_selling_price × num)`。
124
+ * - 行级 `original_price` = `main_product_original_price + Σ(bundle 原价 × num)`。
125
+ *
126
+ * 迁移与幂等:
127
+ * - `metadata.price_schema_version === 2` → 已新语义归一化,保留 main_product_* 原值(保留折扣)。
128
+ * - 其它情况(v1 / 缺字段 / 无 metadata)→ 按"main_product_selling_price 曾是 main-only"的旧约定
129
+ * 反推 legacyDiscount,再以新 source + options 基准重算。最终统一打上 `price_schema_version: 2`。
130
+ * - 因此多次 normalize 不会重复叠加 option/bundle。
115
131
  */
116
132
  export declare function normalizeOrderProduct(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): ScanOrderOrderProduct;
117
133
  /**
@@ -127,7 +143,7 @@ export declare function hasCustomCapacityProduct(products: ProductData[]): boole
127
143
  /**
128
144
  * 根据预约规则商品的 resource.type 计算桌台是否已被"占满"。
129
145
  * - single:只要有 `lastOrderId` 即视为占用
130
- * - multiple:当前时间落在 `capacity_list[i]` 的 `[start_at, end_at]`(inclusive)内的 pax 之和 > 总容量
146
+ * - multiple:当前时间落在 `capacity_list[i]` 的 `[start_at, end_at]`(inclusive)内的 pax 之和 >= 总容量
131
147
  * - 其他('capacity' / undefined):返回 false,不施加限制
132
148
  */
133
149
  export declare function computeResourceIsFull(params: {
@@ -12,7 +12,8 @@ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol
12
12
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
13
13
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
14
14
  import dayjs from 'dayjs';
15
- import { createUuidV4 } from "../../modules/Order/utils";
15
+ import Decimal from 'decimal.js';
16
+ import { composeLinePrice, createUuidV4, sumOptionUnitPrice } from "../../modules/Order/utils";
16
17
 
17
18
  /**
18
19
  * 构建金额全为 0 的空 summary。
@@ -451,13 +452,29 @@ export function getProductIdentityIndex(products, identity) {
451
452
  }
452
453
 
453
454
  /**
454
- * 对外部传入的商品对象做归一化:
455
+ * 对外部传入的商品对象做归一化(v2 composite 语义):
455
456
  * - 补全可选字段默认值(未传则使用兜底值,避免后续计算时因 undefined 导致异常)
456
457
  * - 对 num 调用 getSafeProductNum 做安全处理
457
458
  * - 保留 _origin 供后续业务流程(如促销规则)使用
459
+ *
460
+ * 价格字段语义(metadata 权威源 + composite 派生):
461
+ * - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),**不含 option**、
462
+ * **不含折扣**。是推导 main_product_* 的起点。variant 分支优先读 `metadata.origin.variant[vid].price`。
463
+ * - `metadata.main_product_original_price`:`source + Σ(option.price × option.num)`,**含 option**、
464
+ * **不含折扣**。
465
+ * - `metadata.main_product_selling_price`:`main_product_original_price - 主商品券 per-unit amount`,
466
+ * **含 option**、**含折扣**。
467
+ * - 行级 `selling_price` = `main_product_selling_price + Σ(bundle_selling_price × num)`。
468
+ * - 行级 `original_price` = `main_product_original_price + Σ(bundle 原价 × num)`。
469
+ *
470
+ * 迁移与幂等:
471
+ * - `metadata.price_schema_version === 2` → 已新语义归一化,保留 main_product_* 原值(保留折扣)。
472
+ * - 其它情况(v1 / 缺字段 / 无 metadata)→ 按"main_product_selling_price 曾是 main-only"的旧约定
473
+ * 反推 legacyDiscount,再以新 source + options 基准重算。最终统一打上 `price_schema_version: 2`。
474
+ * - 因此多次 normalize 不会重复叠加 option/bundle。
458
475
  */
459
476
  export function normalizeOrderProduct(product) {
460
- var _product$is_charge_ta;
477
+ var _metadata$origin, _variantList$find, _product$is_charge_ta;
461
478
  var metadata = _objectSpread({}, product.metadata || {});
462
479
  // 不透明 identity 契约:每条订单行必须带 identity_key。
463
480
  // 调用方未传时由 SDK 自动生成 UUID,后续 update/remove 只做严格比对,避免猜测合成 key。
@@ -465,40 +482,105 @@ export function normalizeOrderProduct(product) {
465
482
  if (!metadata.unique_identification_number) {
466
483
  metadata.unique_identification_number = resolvedIdentityKey;
467
484
  }
468
-
469
- // selling_price:券后成交单价;original_price:券前店铺售价。
470
- // 初次加购时两者相等(入口层应保证 caller 传的 original_price == selling_price);
471
- // 券应用后由 Rules 引擎只改动 selling_price,保留 original_price 以便还原 / 展示划线对比。
472
- // 注意:这里 caller 若显式传入了 original_price(例如 Rules 回写或单测场景),要尊重该值,
473
- // 让券后状态能正确通过再次 normalize。
474
- var resolvedSellingPrice = product.selling_price || '0.00';
475
- var resolvedOriginalPrice = product.original_price || resolvedSellingPrice;
476
- if (metadata.main_product_original_price === undefined) {
477
- metadata.main_product_original_price = resolvedOriginalPrice;
478
- }
479
- if (metadata.main_product_selling_price === undefined) {
480
- metadata.main_product_selling_price = resolvedSellingPrice;
481
- }
482
- if (metadata.source_product_price === undefined) {
483
- var _ref2, _product$_origin$pric, _product$_origin, _product$_origin2;
484
- metadata.source_product_price = (_ref2 = (_product$_origin$pric = (_product$_origin = product._origin) === null || _product$_origin === void 0 ? void 0 : _product$_origin.price) !== null && _product$_origin$pric !== void 0 ? _product$_origin$pric : (_product$_origin2 = product._origin) === null || _product$_origin2 === void 0 ? void 0 : _product$_origin2.base_price) !== null && _ref2 !== void 0 ? _ref2 : resolvedSellingPrice;
485
- }
486
485
  var normalizedBundle = (product.product_bundle || []).map(function (item) {
487
- var _ref3, _item$bundle_selling_, _ref4, _ref5, _item$custom_price;
486
+ var _ref2, _item$bundle_selling_, _ref3, _ref4, _item$custom_price;
488
487
  return _objectSpread(_objectSpread({}, item), {}, {
489
- bundle_selling_price: (_ref3 = (_item$bundle_selling_ = item.bundle_selling_price) !== null && _item$bundle_selling_ !== void 0 ? _item$bundle_selling_ : item.price) !== null && _ref3 !== void 0 ? _ref3 : '0.00',
490
- custom_price: (_ref4 = (_ref5 = (_item$custom_price = item.custom_price) !== null && _item$custom_price !== void 0 ? _item$custom_price : item.bundle_selling_price) !== null && _ref5 !== void 0 ? _ref5 : item.price) !== null && _ref4 !== void 0 ? _ref4 : '0.00'
488
+ bundle_selling_price: (_ref2 = (_item$bundle_selling_ = item.bundle_selling_price) !== null && _item$bundle_selling_ !== void 0 ? _item$bundle_selling_ : item.price) !== null && _ref2 !== void 0 ? _ref2 : '0.00',
489
+ custom_price: (_ref3 = (_ref4 = (_item$custom_price = item.custom_price) !== null && _item$custom_price !== void 0 ? _item$custom_price : item.bundle_selling_price) !== null && _ref4 !== void 0 ? _ref4 : item.price) !== null && _ref3 !== void 0 ? _ref3 : '0.00'
491
490
  });
492
491
  });
492
+ var normalizedOptions = product.product_option_item || [];
493
+ var optionSum = sumOptionUnitPrice(normalizedOptions);
494
+
495
+ // 1) 解析 source_product_price。
496
+ // 优先级:
497
+ // 1) metadata.source_product_price(v2 权威)
498
+ // 2) variantPrice(命中 variant_id,从 metadata.origin.variant[vid].price 读)
499
+ // 3) _origin.price / _origin.base_price(后端语义的基础价)
500
+ // 4) v1 兼容:无 v2 标记但存在 metadata.main_product_original_price(v1 main-only,即旧 source)
501
+ // 5) 入参 original_price(v1 addProduct 约定:original_price 为 pre-discount 基础价)
502
+ // 6) 入参 selling_price(最末兜底,新添加路径 caller 只给 selling_price)
503
+ var isV2 = metadata.price_schema_version === 2 || metadata.price_schema_version === '2';
504
+ var variantId = Number(product.product_variant_id || 0);
505
+ var variantList = variantId ? metadata === null || metadata === void 0 || (_metadata$origin = metadata.origin) === null || _metadata$origin === void 0 ? void 0 : _metadata$origin.variant : null;
506
+ var variantPrice = Array.isArray(variantList) ? (_variantList$find = variantList.find(function (v) {
507
+ return Number(v === null || v === void 0 ? void 0 : v.id) === variantId;
508
+ })) === null || _variantList$find === void 0 ? void 0 : _variantList$find.price : undefined;
509
+ var resolvedSource = function (_product$_origin, _product$_origin2, _ref5, _product$original_pri) {
510
+ if (metadata.source_product_price !== undefined) {
511
+ return String(metadata.source_product_price);
512
+ }
513
+ if (variantPrice !== undefined && variantPrice !== null) {
514
+ return String(variantPrice);
515
+ }
516
+ var originPrice = (_product$_origin = product._origin) === null || _product$_origin === void 0 ? void 0 : _product$_origin.price;
517
+ if (originPrice !== undefined && originPrice !== null) {
518
+ return String(originPrice);
519
+ }
520
+ var originBasePrice = (_product$_origin2 = product._origin) === null || _product$_origin2 === void 0 ? void 0 : _product$_origin2.base_price;
521
+ if (originBasePrice !== undefined && originBasePrice !== null) {
522
+ return String(originBasePrice);
523
+ }
524
+ if (!isV2 && metadata.main_product_original_price !== undefined) {
525
+ return String(metadata.main_product_original_price);
526
+ }
527
+ return (_ref5 = (_product$original_pri = product.original_price) !== null && _product$original_pri !== void 0 ? _product$original_pri : product.selling_price) !== null && _ref5 !== void 0 ? _ref5 : '0.00';
528
+ }();
529
+
530
+ // 2) 派生 main_product_original_price(含 option、不含折扣)
531
+ var mainOriginalDec = new Decimal(Number(resolvedSource) || 0).plus(optionSum);
532
+ var mainOriginalStr = mainOriginalDec.toDecimalPlaces(2).toFixed(2);
533
+
534
+ // 3) 派生 main_product_selling_price(含 option、含主商品折扣)
535
+ // - v2 数据:直接沿用 metadata.main_product_selling_price(保留折扣)
536
+ // - v1 metadata:main_product_selling_price 旧语义是 main-only(≈ source-level 折后价),
537
+ // 反推 legacyDiscount = main_original(旧) - main_selling(旧),再用新 main_original - legacyDiscount
538
+ // - v1 addProduct 入参:top-level selling_price < original_price 表示主商品折扣;
539
+ // 用差额作为 legacyDiscount 映射到新 main_selling
540
+ // - 其它:视为无折扣,main_selling = main_original
541
+ var mainSellingDec;
542
+ if (isV2 && metadata.main_product_selling_price != null) {
543
+ mainSellingDec = new Decimal(Number(metadata.main_product_selling_price) || 0);
544
+ } else if (metadata.main_product_selling_price != null && metadata.main_product_original_price != null) {
545
+ var legacyOriginal = new Decimal(Number(metadata.main_product_original_price) || 0);
546
+ var legacySelling = new Decimal(Number(metadata.main_product_selling_price) || 0);
547
+ var legacyDiscount = legacyOriginal.minus(legacySelling);
548
+ mainSellingDec = mainOriginalDec.minus(legacyDiscount);
549
+ } else if (product.original_price != null && product.selling_price != null && new Decimal(Number(product.original_price) || 0).greaterThan(new Decimal(Number(product.selling_price) || 0))) {
550
+ var topOriginal = new Decimal(Number(product.original_price) || 0);
551
+ var topSelling = new Decimal(Number(product.selling_price) || 0);
552
+ var _legacyDiscount = topOriginal.minus(topSelling);
553
+ mainSellingDec = mainOriginalDec.minus(_legacyDiscount);
554
+ } else {
555
+ mainSellingDec = mainOriginalDec;
556
+ }
557
+ var mainSellingStr = mainSellingDec.toDecimalPlaces(2).toFixed(2);
558
+
559
+ // 4) 落盘 metadata:三字段 + schema 版本 sentinel
560
+ metadata.source_product_price = resolvedSource;
561
+ metadata.main_product_original_price = mainOriginalStr;
562
+ metadata.main_product_selling_price = mainSellingStr;
563
+ metadata.price_schema_version = 2;
564
+
565
+ // 5) 合成行级 composite(main 已含 option,本步只叠 bundle)
566
+ var composedSellingPrice = composeLinePrice({
567
+ mainPrice: mainSellingStr,
568
+ bundle: normalizedBundle
569
+ });
570
+ var composedOriginalPrice = composeLinePrice({
571
+ mainPrice: mainOriginalStr,
572
+ bundle: normalizedBundle,
573
+ useOriginalBundle: true
574
+ });
493
575
  return {
494
576
  order_detail_id: product.order_detail_id || null,
495
577
  product_id: product.product_id,
496
578
  num: getSafeProductNum(product.num),
497
579
  product_variant_id: product.product_variant_id,
498
580
  identity_key: resolvedIdentityKey,
499
- product_option_item: product.product_option_item || [],
500
- selling_price: resolvedSellingPrice,
501
- original_price: resolvedOriginalPrice,
581
+ product_option_item: normalizedOptions,
582
+ selling_price: composedSellingPrice,
583
+ original_price: composedOriginalPrice,
502
584
  tax_fee: product.tax_fee || '0.00',
503
585
  is_charge_tax: (_product$is_charge_ta = product.is_charge_tax) !== null && _product$is_charge_ta !== void 0 ? _product$is_charge_ta : 0,
504
586
  discount_list: product.discount_list || [],
@@ -579,7 +661,7 @@ export function hasCustomCapacityProduct(products) {
579
661
  /**
580
662
  * 根据预约规则商品的 resource.type 计算桌台是否已被"占满"。
581
663
  * - single:只要有 `lastOrderId` 即视为占用
582
- * - multiple:当前时间落在 `capacity_list[i]` 的 `[start_at, end_at]`(inclusive)内的 pax 之和 > 总容量
664
+ * - multiple:当前时间落在 `capacity_list[i]` 的 `[start_at, end_at]`(inclusive)内的 pax 之和 >= 总容量
583
665
  * - 其他('capacity' / undefined):返回 false,不施加限制
584
666
  */
585
667
  export function computeResourceIsFull(params) {
@@ -611,7 +693,7 @@ export function computeResourceIsFull(params) {
611
693
  } finally {
612
694
  _iterator8.f();
613
695
  }
614
- return occupied > totalCapacity;
696
+ return occupied >= totalCapacity;
615
697
  }
616
698
 
617
699
  /**
@@ -45,7 +45,7 @@ import { extractResourceIds, buildResourceProductMap } from "./utils/resource";
45
45
  import { buildTimeSlotGrid, isBusinessHoursCrossDay, generateTimeLabels } from "./utils/timeSlot";
46
46
  import { buildDateRangeSummary } from "./utils/dateSummary";
47
47
  import { mergeConsecutiveSlots, expandMergedSlotToIndividual, buildVenueIdentityKey, buildVenueBookingEntry, buildPriceBreakdown } from "./utils/slotMerge";
48
- import { createUuidV4 } from "../../modules/Order/utils";
48
+ import { composeLinePrice, createUuidV4, sumOptionUnitPrice } from "../../modules/Order/utils";
49
49
  import { OrderModule } from "../../modules/Order";
50
50
  import { RegisterAndLoginHooks } from "../RegisterAndLogin/types";
51
51
  import Decimal from 'decimal.js';
@@ -2027,7 +2027,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2027
2027
  key: "setDiscountSelected",
2028
2028
  value: (function () {
2029
2029
  var _setDiscountSelected = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee21(params) {
2030
- var _tempOrder$holder, _this$store$order$get, _this$store$order$get2, list, beforeTarget, updated, updatedTarget, tempOrder, orderStore, discountModule, rulesModule, holders, nextDiscountList, _tempOrder$holder2, result, beforeSelectedIds, _iterator13, _step13, d, selectedResourceIds, _iterator14, _step14, _product$_origin, product, totalPerUnitDiscount, newSellingPrice, afterApplyTarget, finalSummary, finalProduct, finalTarget;
2030
+ var _tempOrder$holder, _this$store$order$get, _this$store$order$get2, list, beforeTarget, updated, updatedTarget, tempOrder, orderStore, discountModule, rulesModule, holders, nextDiscountList, _tempOrder$holder2, result, beforeSelectedIds, _iterator13, _step13, d, selectedResourceIds, _iterator14, _step14, _product$_origin, _product$metadata$sou, _product$metadata3, _product$metadata4, _product$original_pri, product, totalPerUnitDiscount, optionSum, sourcePrice, newSourceSellingPrice, newMainSellingPrice, afterApplyTarget, finalSummary, finalProduct, finalTarget;
2031
2031
  return _regeneratorRuntime().wrap(function _callee21$(_context21) {
2032
2032
  while (1) switch (_context21.prev = _context21.next) {
2033
2033
  case 0:
@@ -2116,7 +2116,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2116
2116
  _iterator14.s();
2117
2117
  case 21:
2118
2118
  if ((_step14 = _iterator14.n()).done) {
2119
- _context21.next = 32;
2119
+ _context21.next = 35;
2120
2120
  break;
2121
2121
  }
2122
2122
  product = _step14.value;
@@ -2124,7 +2124,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2124
2124
  _context21.next = 25;
2125
2125
  break;
2126
2126
  }
2127
- return _context21.abrupt("continue", 30);
2127
+ return _context21.abrupt("continue", 33);
2128
2128
  case 25:
2129
2129
  // 1. 把 product.discount_list 和当前选中的 discount 对齐(剔除已取消的券)
2130
2130
  product.discount_list = (product.discount_list || []).filter(function (pd) {
@@ -2133,45 +2133,53 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2133
2133
  return rid != null && selectedResourceIds.has(rid);
2134
2134
  });
2135
2135
 
2136
- // 2. 以 original_price 为基准重算 selling_price
2136
+ // 2. 以 source_product_price 为券作用基准:券作用于 source(不含 option),
2137
+ // 再把 option 加回得到含 option 的 main_product_selling_price,最后合成 composite。
2137
2138
  totalPerUnitDiscount = (product.discount_list || []).reduce(function (sum, pd) {
2138
2139
  return sum + (pd.amount || 0);
2139
2140
  }, 0);
2140
- newSellingPrice = new Decimal(product.original_price || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
2141
- product.selling_price = newSellingPrice;
2141
+ optionSum = sumOptionUnitPrice(product.product_option_item);
2142
+ sourcePrice = (_product$metadata$sou = (_product$metadata3 = product.metadata) === null || _product$metadata3 === void 0 ? void 0 : _product$metadata3.source_product_price) !== null && _product$metadata$sou !== void 0 ? _product$metadata$sou : ((_product$metadata4 = product.metadata) === null || _product$metadata4 === void 0 ? void 0 : _product$metadata4.main_product_original_price) != null ? new Decimal(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : (_product$original_pri = product.original_price) !== null && _product$original_pri !== void 0 ? _product$original_pri : '0';
2143
+ newSourceSellingPrice = new Decimal(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
2144
+ newMainSellingPrice = new Decimal(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
2142
2145
  if (product.metadata) {
2143
- product.metadata.main_product_selling_price = newSellingPrice;
2146
+ product.metadata.main_product_selling_price = newMainSellingPrice;
2147
+ product.metadata.price_schema_version = 2;
2144
2148
  }
2145
- case 30:
2149
+ product.selling_price = composeLinePrice({
2150
+ mainPrice: newMainSellingPrice,
2151
+ bundle: product.product_bundle
2152
+ });
2153
+ case 33:
2146
2154
  _context21.next = 21;
2147
2155
  break;
2148
- case 32:
2149
- _context21.next = 37;
2156
+ case 35:
2157
+ _context21.next = 40;
2150
2158
  break;
2151
- case 34:
2152
- _context21.prev = 34;
2153
- _context21.t0 = _context21["catch"](19);
2154
- _iterator14.e(_context21.t0);
2155
2159
  case 37:
2156
2160
  _context21.prev = 37;
2157
- _iterator14.f();
2158
- return _context21.finish(37);
2161
+ _context21.t0 = _context21["catch"](19);
2162
+ _iterator14.e(_context21.t0);
2159
2163
  case 40:
2164
+ _context21.prev = 40;
2165
+ _iterator14.f();
2166
+ return _context21.finish(40);
2167
+ case 43:
2160
2168
  OrderModule.populateSavedAmounts(tempOrder.products, nextDiscountList);
2161
- _context21.next = 43;
2169
+ _context21.next = 46;
2162
2170
  return discountModule === null || discountModule === void 0 ? void 0 : discountModule.setDiscountList(nextDiscountList);
2163
- case 43:
2171
+ case 46:
2164
2172
  tempOrder.discount_list = (nextDiscountList || []).filter(function (d) {
2165
2173
  return d.isSelected;
2166
2174
  });
2167
2175
  afterApplyTarget = this.store.order.getDiscountList().find(function (d) {
2168
2176
  return d.id === params.discountId;
2169
2177
  }) || null;
2170
- _context21.next = 47;
2178
+ _context21.next = 50;
2171
2179
  return this.store.order.recalculateSummary({
2172
2180
  createIfMissing: true
2173
2181
  });
2174
- case 47:
2182
+ case 50:
2175
2183
  this.store.order.persistTempOrder();
2176
2184
  finalSummary = ((_this$store$order$get = this.store.order.getTempOrder()) === null || _this$store$order$get === void 0 ? void 0 : _this$store$order$get.summary) || null;
2177
2185
  finalProduct = ((_this$store$order$get2 = this.store.order.getTempOrder()) === null || _this$store$order$get2 === void 0 || (_this$store$order$get2 = _this$store$order$get2.products) === null || _this$store$order$get2 === void 0 ? void 0 : _this$store$order$get2[0]) || null;
@@ -2180,16 +2188,16 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2180
2188
  return d.id === params.discountId;
2181
2189
  }) || null;
2182
2190
  return _context21.abrupt("return", this.store.order.getDiscountList());
2183
- case 55:
2184
- _context21.prev = 55;
2191
+ case 58:
2192
+ _context21.prev = 58;
2185
2193
  _context21.t1 = _context21["catch"](1);
2186
2194
  this.logMethodError('setDiscountSelected', _context21.t1);
2187
2195
  throw _context21.t1;
2188
- case 59:
2196
+ case 62:
2189
2197
  case "end":
2190
2198
  return _context21.stop();
2191
2199
  }
2192
- }, _callee21, this, [[1, 55], [19, 34, 37, 40]]);
2200
+ }, _callee21, this, [[1, 58], [19, 37, 40, 43]]);
2193
2201
  }));
2194
2202
  function setDiscountSelected(_x15) {
2195
2203
  return _setDiscountSelected.apply(this, arguments);
@@ -2336,7 +2344,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2336
2344
  key: "addProductToOrder",
2337
2345
  value: function () {
2338
2346
  var _addProductToOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee25(product) {
2339
- var _product$metadata3, _product$product_vari2, quotationPrice, products;
2347
+ var _product$metadata5, _product$product_vari2, quotationPrice, products;
2340
2348
  return _regeneratorRuntime().wrap(function _callee25$(_context25) {
2341
2349
  while (1) switch (_context25.prev = _context25.next) {
2342
2350
  case 0:
@@ -2351,7 +2359,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2351
2359
  }
2352
2360
  throw new Error('order 模块未初始化');
2353
2361
  case 4:
2354
- if (!((_product$metadata3 = product.metadata) !== null && _product$metadata3 !== void 0 && _product$metadata3.venue_booking) && this.store.quotation && product.product_id != null) {
2362
+ if (!((_product$metadata5 = product.metadata) !== null && _product$metadata5 !== void 0 && _product$metadata5.venue_booking) && this.store.quotation && product.product_id != null) {
2355
2363
  quotationPrice = this.store.quotation.getPriceForProduct({
2356
2364
  productId: product.product_id,
2357
2365
  variantId: (_product$product_vari2 = product.product_variant_id) !== null && _product$product_vari2 !== void 0 ? _product$product_vari2 : undefined,
@@ -1,49 +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/promotion/index.ts
30
- var promotion_exports = {};
31
- __export(promotion_exports, {
32
- BUY_X_GET_Y_FREE_STRATEGY: () => import_examples.BUY_X_GET_Y_FREE_STRATEGY,
33
- PromotionAdapter: () => import_adapter.PromotionAdapter,
34
- PromotionEvaluator: () => import_evaluator.PromotionEvaluator,
35
- X_ITEMS_FOR_Y_PRICE_STRATEGY: () => import_examples.X_ITEMS_FOR_Y_PRICE_STRATEGY,
36
- default: () => import_adapter2.default
37
- });
38
- module.exports = __toCommonJS(promotion_exports);
39
- var import_evaluator = require("./evaluator");
40
- var import_adapter = require("./adapter");
41
- var import_adapter2 = __toESM(require("./adapter"));
42
- var import_examples = require("./examples");
43
- // Annotate the CommonJS export names for ESM import in node:
44
- 0 && (module.exports = {
45
- BUY_X_GET_Y_FREE_STRATEGY,
46
- PromotionAdapter,
47
- PromotionEvaluator,
48
- X_ITEMS_FOR_Y_PRICE_STRATEGY
49
- });
@@ -82,7 +82,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
82
82
  enhancePayload?: SubmitPayloadEnhancer;
83
83
  }): Promise<T>;
84
84
  createOrder(params: CommitOrderParams['query']): {
85
- type: "virtual" | "appointment_booking";
85
+ type: "appointment_booking" | "virtual";
86
86
  platform: string;
87
87
  sales_channel: string;
88
88
  order_sales_channel: string;
@@ -289,7 +289,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
289
289
  return;
290
290
  }
291
291
  if (Array.isArray(parsedData.products)) {
292
- for (const p of parsedData.products) {
292
+ for (let i = 0; i < parsedData.products.length; i++) {
293
+ const p = parsedData.products[i];
293
294
  if (!p || typeof p !== "object")
294
295
  continue;
295
296
  if (!Array.isArray(p.product_option_item)) {
@@ -309,6 +310,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
309
310
  row.metadata.unique_identification_number = newKey;
310
311
  }
311
312
  }
313
+ parsedData.products[i] = (0, import_utils3.normalizeOrderProduct)(row);
312
314
  }
313
315
  }
314
316
  this.store.tempOrder = parsedData;
@@ -478,6 +480,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
478
480
  return tempOrder.products;
479
481
  }
480
482
  async updateProductInOrder(params) {
483
+ var _a, _b, _c;
481
484
  const {
482
485
  product_id,
483
486
  product_variant_id,
@@ -509,7 +512,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
509
512
  product_variant_id
510
513
  };
511
514
  nextProduct.num = (0, import_utils3.getSafeProductNum)(nextProduct.num);
512
- tempOrder.products[productIndex] = nextProduct;
515
+ const callerUpdatesTopPrice = Object.prototype.hasOwnProperty.call(updates || {}, "selling_price") || Object.prototype.hasOwnProperty.call(updates || {}, "original_price");
516
+ const callerUpdatesMainMeta = ((_a = updates == null ? void 0 : updates.metadata) == null ? void 0 : _a.main_product_selling_price) !== void 0 || ((_b = updates == null ? void 0 : updates.metadata) == null ? void 0 : _b.main_product_original_price) !== void 0 || ((_c = updates == null ? void 0 : updates.metadata) == null ? void 0 : _c.source_product_price) !== void 0;
517
+ if (callerUpdatesTopPrice && !callerUpdatesMainMeta) {
518
+ const existedMeta = nextProduct.metadata || {};
519
+ nextProduct.metadata = { ...existedMeta };
520
+ delete nextProduct.metadata.source_product_price;
521
+ delete nextProduct.metadata.main_product_selling_price;
522
+ delete nextProduct.metadata.main_product_original_price;
523
+ delete nextProduct.metadata.price_schema_version;
524
+ }
525
+ tempOrder.products[productIndex] = (0, import_utils3.normalizeOrderProduct)(nextProduct);
513
526
  this.applyDiscount();
514
527
  await this.recalculateSummary({ createIfMissing: true });
515
528
  this.persistTempOrder();
@@ -541,9 +554,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
541
554
  });
542
555
  let result;
543
556
  if (tempOrder.order_id) {
544
- let products = (0, import_utils.formatV1Product)(
545
- (0, import_utils.filterProductsForScanOrderMore)(payload.products)
546
- );
557
+ const products = (0, import_utils.filterProductsForScanOrderMore)(payload.products);
547
558
  const moreResult = await this.scanOrderMore({
548
559
  query: {
549
560
  order_id: tempOrder.order_id,
@@ -771,7 +782,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
771
782
  async submitScanOrder(params) {
772
783
  const { url, query } = params;
773
784
  const fetchUrl = url || "/order/sales/checkout";
774
- return this.request.post(fetchUrl, query);
785
+ return this.request.post(fetchUrl, query, { customToast: () => {
786
+ } });
775
787
  }
776
788
  async scanOrderMore(params) {
777
789
  const { url, query } = params;
@@ -780,7 +792,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
780
792
  products: query.products,
781
793
  request_unique_idempotency_token: query.request_unique_idempotency_token
782
794
  };
783
- return this.request.put(fetchUrl, requestBody);
795
+ return this.request.put(fetchUrl, requestBody, { customToast: () => {
796
+ } });
784
797
  }
785
798
  // TODO 获取详情的接口
786
799
  async getOrderInfoByRemote(order_id) {
@@ -44,8 +44,19 @@ export interface SubmitScanOrderProduct {
44
44
  num: number;
45
45
  product_variant_id: number;
46
46
  product_option_item: any[];
47
+ /**
48
+ * 行 composite 券后单价。
49
+ * 公式:`metadata.main_product_selling_price` + Σ(bundle_selling_price × num)。
50
+ * 主商品(含 option、含主商品折扣)的单价存在 `metadata.main_product_selling_price`。
51
+ */
47
52
  selling_price: string;
53
+ /**
54
+ * 行 composite 券前单价。
55
+ * 公式:`metadata.main_product_original_price` + Σ(bundle 原价 × num)。
56
+ * 主商品(含 option、不含折扣)的单价存在 `metadata.main_product_original_price`。
57
+ */
48
58
  original_price: string;
59
+ /** 出站兼容字段,直接由 `selling_price` 派生,语义同 composite。 */
49
60
  payment_price: string;
50
61
  tax_fee: string;
51
62
  is_charge_tax: number;