@pisell/pisellos 0.10.7 → 0.10.9

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 (124) hide show
  1. package/dist/core/index.js +0 -1
  2. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  3. package/dist/model/strategy/adapter/dataVariant/evaluator.js +287 -101
  4. package/dist/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  5. package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -2
  6. package/dist/model/strategy/adapter/walletPass/type.d.ts +5 -0
  7. package/dist/model/strategy/adapter/walletPass/utils.js +57 -26
  8. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +18 -12
  9. package/dist/modules/BookingContext/utils/productExtend.js +5 -9
  10. package/dist/modules/BookingContext/utils/timeSlices.js +24 -3
  11. package/dist/modules/Customer/index.d.ts +4 -0
  12. package/dist/modules/Customer/index.js +91 -59
  13. package/dist/modules/Customer/types.d.ts +2 -0
  14. package/dist/modules/Discount/index.d.ts +2 -0
  15. package/dist/modules/Discount/index.js +38 -5
  16. package/dist/modules/Discount/types.d.ts +11 -0
  17. package/dist/modules/Order/index.d.ts +32 -6
  18. package/dist/modules/Order/index.js +1165 -819
  19. package/dist/modules/Order/types.d.ts +32 -4
  20. package/dist/modules/Order/types.js +11 -0
  21. package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
  22. package/dist/modules/Order/utils/discountProductLineIdentity.js +227 -0
  23. package/dist/modules/Order/utils/virtualSettlement.d.ts +56 -0
  24. package/dist/modules/Order/utils/virtualSettlement.js +271 -0
  25. package/dist/modules/Order/utils.js +89 -48
  26. package/dist/modules/Payment/types.d.ts +2 -0
  27. package/dist/modules/Payment/utils.js +4 -1
  28. package/dist/modules/Payment/walletpass.d.ts +11 -0
  29. package/dist/modules/Payment/walletpass.js +235 -60
  30. package/dist/modules/Product/types.d.ts +23 -0
  31. package/dist/modules/ProductList/index.d.ts +15 -2
  32. package/dist/modules/ProductList/index.js +92 -13
  33. package/dist/modules/Rules/index.js +125 -52
  34. package/dist/modules/SalesSummary/index.d.ts +1 -0
  35. package/dist/modules/SalesSummary/index.js +4 -3
  36. package/dist/modules/SalesSummary/types.d.ts +1 -0
  37. package/dist/modules/SalesSummary/utils.d.ts +1 -0
  38. package/dist/modules/SalesSummary/utils.js +28 -2
  39. package/dist/server/index.d.ts +15 -0
  40. package/dist/server/index.js +894 -781
  41. package/dist/server/modules/order/index.d.ts +2 -0
  42. package/dist/server/modules/order/index.js +261 -96
  43. package/dist/server/modules/order/types.d.ts +1 -1
  44. package/dist/server/utils/small-ticket.js +2 -1
  45. package/dist/solution/BaseSales/index.d.ts +41 -7
  46. package/dist/solution/BaseSales/index.js +1405 -974
  47. package/dist/solution/BaseSales/utils/cartPromotion.js +26 -3
  48. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  49. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +79 -13
  50. package/dist/solution/BaseSales/utils.js +31 -20
  51. package/dist/solution/BookingByStep/index.d.ts +3 -3
  52. package/dist/solution/BookingTicket/index.d.ts +5 -1
  53. package/dist/solution/BookingTicket/index.js +221 -162
  54. package/dist/solution/BookingTicket/types.d.ts +3 -0
  55. package/dist/solution/BookingTicket/utils/addProductDecision.js +2 -1
  56. package/dist/solution/BookingTicket/utils/cartView.js +44 -32
  57. package/dist/solution/Sales/index.d.ts +1 -0
  58. package/dist/solution/Sales/index.js +16 -2
  59. package/dist/solution/ScanOrder/index.js +25 -64
  60. package/dist/solution/ScanOrder/utils.js +31 -20
  61. package/dist/solution/UnifiedBookingSales/index.d.ts +5 -4
  62. package/dist/solution/UnifiedBookingSales/index.js +51 -39
  63. package/lib/core/index.js +0 -1
  64. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  65. package/lib/model/strategy/adapter/dataVariant/evaluator.js +170 -7
  66. package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  67. package/lib/model/strategy/adapter/walletPass/evaluator.js +0 -2
  68. package/lib/model/strategy/adapter/walletPass/type.d.ts +5 -0
  69. package/lib/model/strategy/adapter/walletPass/utils.js +62 -11
  70. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +6 -1
  71. package/lib/modules/BookingContext/utils/productExtend.js +4 -3
  72. package/lib/modules/BookingContext/utils/timeSlices.js +18 -3
  73. package/lib/modules/Customer/index.d.ts +4 -0
  74. package/lib/modules/Customer/index.js +11 -0
  75. package/lib/modules/Customer/types.d.ts +2 -0
  76. package/lib/modules/Discount/index.d.ts +2 -0
  77. package/lib/modules/Discount/index.js +37 -3
  78. package/lib/modules/Discount/types.d.ts +11 -0
  79. package/lib/modules/Order/index.d.ts +32 -6
  80. package/lib/modules/Order/index.js +518 -148
  81. package/lib/modules/Order/types.d.ts +32 -4
  82. package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
  83. package/lib/modules/Order/utils/discountProductLineIdentity.js +170 -0
  84. package/lib/modules/Order/utils/virtualSettlement.d.ts +56 -0
  85. package/lib/modules/Order/utils/virtualSettlement.js +300 -0
  86. package/lib/modules/Order/utils.js +65 -21
  87. package/lib/modules/Payment/types.d.ts +2 -0
  88. package/lib/modules/Payment/utils.js +5 -1
  89. package/lib/modules/Payment/walletpass.d.ts +11 -0
  90. package/lib/modules/Payment/walletpass.js +198 -17
  91. package/lib/modules/Product/types.d.ts +23 -0
  92. package/lib/modules/ProductList/index.d.ts +15 -2
  93. package/lib/modules/ProductList/index.js +85 -3
  94. package/lib/modules/Rules/index.js +100 -20
  95. package/lib/modules/SalesSummary/index.d.ts +1 -0
  96. package/lib/modules/SalesSummary/index.js +10 -2
  97. package/lib/modules/SalesSummary/types.d.ts +1 -0
  98. package/lib/modules/SalesSummary/utils.d.ts +1 -0
  99. package/lib/modules/SalesSummary/utils.js +30 -2
  100. package/lib/server/index.d.ts +15 -0
  101. package/lib/server/index.js +105 -14
  102. package/lib/server/modules/order/index.d.ts +2 -0
  103. package/lib/server/modules/order/index.js +75 -5
  104. package/lib/server/modules/order/types.d.ts +1 -1
  105. package/lib/server/utils/small-ticket.js +1 -1
  106. package/lib/solution/BaseSales/index.d.ts +41 -7
  107. package/lib/solution/BaseSales/index.js +325 -39
  108. package/lib/solution/BaseSales/utils/cartPromotion.js +26 -2
  109. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  110. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +62 -12
  111. package/lib/solution/BaseSales/utils.js +29 -18
  112. package/lib/solution/BookingByStep/index.d.ts +3 -3
  113. package/lib/solution/BookingTicket/index.d.ts +5 -1
  114. package/lib/solution/BookingTicket/index.js +31 -6
  115. package/lib/solution/BookingTicket/types.d.ts +3 -0
  116. package/lib/solution/BookingTicket/utils/addProductDecision.js +2 -1
  117. package/lib/solution/BookingTicket/utils/cartView.js +43 -30
  118. package/lib/solution/Sales/index.d.ts +1 -0
  119. package/lib/solution/Sales/index.js +15 -3
  120. package/lib/solution/ScanOrder/index.js +17 -54
  121. package/lib/solution/ScanOrder/utils.js +29 -18
  122. package/lib/solution/UnifiedBookingSales/index.d.ts +5 -4
  123. package/lib/solution/UnifiedBookingSales/index.js +35 -26
  124. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import { CartItem } from '../Cart/types';
2
2
  import type { DiscountModule } from '../Discount';
3
3
  import type { RulesModule } from '../Rules';
4
- import type { Discount } from '../Discount/types';
4
+ import type { Discount, VirtualCurrencyAsset } from '../Discount/types';
5
5
  import type { UnavailableReason } from '../Rules/types';
6
6
  import type { SubmitPayloadEnhancer } from './utils';
7
7
  import type { PaymentItem } from '../Payment/types';
@@ -194,6 +194,7 @@ export interface OrderProduct extends OrderProductIdentity {
194
194
  gift_card?: number;
195
195
  selling_price: string;
196
196
  original_price: string;
197
+ payment_price?: string;
197
198
  tax_fee: string;
198
199
  is_charge_tax: number;
199
200
  discount_list: OrderProductDiscountItem[];
@@ -275,6 +276,7 @@ export interface OrderTempOrder {
275
276
  products: OrderProduct[];
276
277
  bookings: any[];
277
278
  payments: any[];
279
+ refunds?: any[];
278
280
  surcharges: any[];
279
281
  discount_list?: any[];
280
282
  relation_forms: any[];
@@ -312,6 +314,7 @@ export interface OrderState {
312
314
  syncState?: OrderSyncState;
313
315
  discountList: any[];
314
316
  availableWalletIds?: number[];
317
+ virtualCurrencyList?: VirtualCurrencyAsset[];
315
318
  discount: DiscountModule | null;
316
319
  rules: RulesModule | null;
317
320
  }
@@ -321,6 +324,24 @@ export interface ReplaceTempOrderOptions {
321
324
  saveDraft?: boolean;
322
325
  }
323
326
  export type AddProductBookingInput = Record<string, any>;
327
+ /**
328
+ * 添加商品行时的顺序控制。
329
+ * 默认追加到 products 尾部;预约数量同步可插入到既有预约组的最新行之后,
330
+ * 避免步进器修改数量改变该组展示位置。
331
+ */
332
+ export interface AddProductToOrderOptions {
333
+ insertAfterProductUid?: string;
334
+ }
335
+ /**
336
+ * 删除商品后的可选位置保持策略。
337
+ * 预约合并行减量时仍删除最新真实行,再把剩余代表行移动到被删除代表行原位置。
338
+ */
339
+ export interface RemoveProductsFromOrderOptions {
340
+ preserveDisplayPosition?: {
341
+ remainingProductUid: string;
342
+ anchorProductUid: string;
343
+ };
344
+ }
324
345
  /** 更新购物车行:仅传 SKU 时命中同 SKU 第一行;多行同 SKU 须传 unique_identification_number / 选项指纹等 */
325
346
  export interface UpdateOrderProductParams {
326
347
  product_id: number | null;
@@ -691,6 +712,8 @@ export interface OrderModuleAPI {
691
712
  addNewOrder: () => Promise<OrderTempOrder>;
692
713
  restoreOrder: () => OrderTempOrder;
693
714
  getOrderProducts: () => OrderProduct[];
715
+ getVirtualCurrencyList: () => VirtualCurrencyAsset[];
716
+ clearOrderForSettlementSwitch: () => Promise<OrderTempOrder>;
694
717
  getOrderSummary: () => Promise<OrderSummary>;
695
718
  recalculateSummary: (options?: {
696
719
  createIfMissing?: boolean;
@@ -726,17 +749,22 @@ export interface OrderModuleAPI {
726
749
  updateTempOrderCustomer: (customer: UpdateTempOrderCustomerInput) => OrderSnapshot['customer'];
727
750
  updateTempOrderBuzzer: (buzzer: string) => string;
728
751
  updateTempOrderContactsInfo: (contactsInfo: Record<string, any> | null) => Record<string, any> | null;
729
- addProductToOrder: (product: Partial<OrderProduct> & OrderProductIdentity, booking?: AddProductBookingInput) => Promise<OrderProduct[]>;
752
+ addProductToOrder: (product: Partial<OrderProduct> & OrderProductIdentity, booking?: AddProductBookingInput, options?: AddProductToOrderOptions) => Promise<OrderProduct[]>;
730
753
  updateOrderProduct: (params: UpdateOrderProductParams) => Promise<OrderProduct[]>;
731
754
  /** 批量更新购物车行,末尾仅触发一次促销重算与 summary 刷新 */
732
755
  updateOrderProducts: (paramsList: UpdateOrderProductParams[]) => Promise<OrderProduct[]>;
733
756
  updateOrderProductQuantity: (params: UpdateOrderProductQuantityParams) => Promise<OrderProduct[]>;
734
757
  updateOrderBooking: (params: UpdateOrderBookingParams) => any[];
735
- removeProductFromOrder: (identity: OrderProductIdentity) => Promise<OrderProduct[]>;
758
+ removeProductFromOrder: (identity: OrderProductIdentity, options?: RemoveProductsFromOrderOptions) => Promise<OrderProduct[]>;
736
759
  /** 批量删除购物车行,末尾仅触发一次促销重算与 summary 刷新 */
737
- removeProductsFromOrder: (identities: OrderProductIdentity[]) => Promise<OrderProduct[]>;
760
+ removeProductsFromOrder: (identities: OrderProductIdentity[], options?: RemoveProductsFromOrderOptions) => Promise<OrderProduct[]>;
738
761
  /** 在显式开启时保存当前 tempOrder 的 sessionStorage 会话快照。 */
739
762
  persistTempOrder: () => void;
763
+ /**
764
+ * 删除当前 cacheId 的 tempOrder 会话快照,并阻止当前模块实例再次写入。
765
+ * 新模块实例初始化时会按 otherParams 重新启用持久化。
766
+ */
767
+ clearSessionStoragePersistedTempOrder: () => void;
740
768
  /** 取出一次待恢复的 sessionStorage tempOrder 快照。 */
741
769
  consumeSessionStorageRestore: () => Record<string, any> | null;
742
770
  /**
@@ -0,0 +1,45 @@
1
+ import type { OrderTempOrder } from '../types';
2
+ /**
3
+ * 商品券拆行的身份与回并工具。
4
+ *
5
+ * 背景:
6
+ * Rules.calcDiscount 应用 good_pass 时,会把一个数量行拆成若干「用券行」和
7
+ * 「普通余量行」。Rules 返回的拆分行可能复制同一份
8
+ * metadata.unique_identification_number,进而造成:
9
+ * - 按 UID 删除时同时命中多行;
10
+ * - UI 把不同券行视为同一个商品;
11
+ * - 后续商品更新无法准确定位目标行。
12
+ *
13
+ * 处理原则:
14
+ * 1. 拆分后每一行必须拥有独立 UID;
15
+ * 2. 原始拆分来源仅记录在 tempOrder._extend.productsByUid 的运行态索引中,
16
+ * 不写入商品 metadata,不污染提交协议;
17
+ * 3. 券被移除后,只回并被本工具确认来自同一折扣拆分源的行;
18
+ * 4. 预约、赠品、促销、手动折扣、备注、称重、holder 和已落库行均为硬边界。
19
+ *
20
+ * 两个导出函数都会原地更新 tempOrder。调用顺序必须是:
21
+ * ensureUniqueProductLineUids -> consolidateDiscountFreeProductLines。
22
+ */
23
+ /** productsByUid 运行态记录中用于关联同一次折扣拆分的字段。 */
24
+ export declare const DISCOUNT_SPLIT_ORIGIN_UID_KEY = "discountSplitOriginUid";
25
+ /**
26
+ * 修复 Rules 折扣拆行复制 UID 的问题,并为拆分行记录共同来源。
27
+ *
28
+ * 第一条商品保留原 UID,后续重复行生成新 UUID;对应的 productsByUid.runtime
29
+ * 会复制原行 runtime(包括 origin),以保证删除、编辑及展示字段回读仍可工作。
30
+ *
31
+ * 没有 UID 的裸商品不会被补写 UID。这是为了兼容 Rules/mock 的历史协议形状;
32
+ * 正常 Order 写路径会在 normalize 阶段提前创建 UID。
33
+ */
34
+ export declare function ensureUniqueProductLineUids(tempOrder: OrderTempOrder): void;
35
+ /**
36
+ * 把券移除后已经恢复原价的同源折扣拆分行重新合并。
37
+ *
38
+ * 此函数刻意不执行通用的「同 SKU 合并」:没有 discountSplitOriginUid 的普通行
39
+ * 可能是业务 hook、导入订单或其它流程主动拆开的,不能在折扣重算时擅自合并。
40
+ *
41
+ * payment_price、tax_fee、surcharge_fee 属于 summary 计算层的派生值。券行与普通行
42
+ * 在回并前可能暂时不同,因此它们不参与 mergeKey;原始价格、SKU/option/bundle
43
+ * 结构以及税务/商品类型配置仍参与比较,防止不同商品语义被误合并。
44
+ */
45
+ export declare function consolidateDiscountFreeProductLines(tempOrder: OrderTempOrder): void;
@@ -0,0 +1,170 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/modules/Order/utils/discountProductLineIdentity.ts
20
+ var discountProductLineIdentity_exports = {};
21
+ __export(discountProductLineIdentity_exports, {
22
+ DISCOUNT_SPLIT_ORIGIN_UID_KEY: () => DISCOUNT_SPLIT_ORIGIN_UID_KEY,
23
+ consolidateDiscountFreeProductLines: () => consolidateDiscountFreeProductLines,
24
+ ensureUniqueProductLineUids: () => ensureUniqueProductLineUids
25
+ });
26
+ module.exports = __toCommonJS(discountProductLineIdentity_exports);
27
+ var import_lodash_es = require("lodash-es");
28
+ var import_utils = require("../../../solution/ScanOrder/utils");
29
+ var import_orderCollectionIdentity = require("./orderCollectionIdentity");
30
+ var DISCOUNT_SPLIT_ORIGIN_UID_KEY = "discountSplitOriginUid";
31
+ function getProductLineUid(product) {
32
+ var _a;
33
+ if (!product || typeof product !== "object")
34
+ return null;
35
+ const uid = ((_a = product.metadata) == null ? void 0 : _a.unique_identification_number) ?? product.unique_identification_number;
36
+ if (uid === void 0 || uid === null || uid === "")
37
+ return null;
38
+ return String(uid);
39
+ }
40
+ function getProductSkuOptions(product) {
41
+ var _a;
42
+ return Array.isArray((_a = product.product_sku) == null ? void 0 : _a.option) ? product.product_sku.option : [];
43
+ }
44
+ function hasProductLineNote(product) {
45
+ return typeof product.note === "string" && product.note.trim().length > 0;
46
+ }
47
+ function isManualProductDiscountLine(product) {
48
+ var _a, _b;
49
+ return ((_a = product.metadata) == null ? void 0 : _a.is_manual_discount) === true || ((_b = product.metadata) == null ? void 0 : _b.is_manual_discount) === 1 || (product.discount_list || []).some((item) => (item == null ? void 0 : item.type) === "product");
50
+ }
51
+ function ensureProductsByUid(tempOrder) {
52
+ if (!tempOrder._extend || typeof tempOrder._extend !== "object") {
53
+ tempOrder._extend = { productsByUid: {} };
54
+ }
55
+ if (!tempOrder._extend.productsByUid) {
56
+ tempOrder._extend.productsByUid = {};
57
+ }
58
+ return tempOrder._extend.productsByUid;
59
+ }
60
+ function ensureUniqueProductLineUids(tempOrder) {
61
+ const usedUids = /* @__PURE__ */ new Set();
62
+ const productsByUid = ensureProductsByUid(tempOrder);
63
+ tempOrder.products = (tempOrder.products || []).map((product) => {
64
+ const sourceUid = getProductLineUid(product);
65
+ if (!sourceUid)
66
+ return product;
67
+ if (!usedUids.has(sourceUid)) {
68
+ usedUids.add(sourceUid);
69
+ return product;
70
+ }
71
+ let splitUid = (0, import_orderCollectionIdentity.createUuidV4)();
72
+ while (usedUids.has(splitUid)) {
73
+ splitUid = (0, import_orderCollectionIdentity.createUuidV4)();
74
+ }
75
+ product.metadata = {
76
+ ...product.metadata || {},
77
+ unique_identification_number: splitUid
78
+ };
79
+ const sourceRuntime = productsByUid[sourceUid] || {};
80
+ const discountSplitOriginUid = String(
81
+ sourceRuntime[DISCOUNT_SPLIT_ORIGIN_UID_KEY] || sourceUid
82
+ );
83
+ productsByUid[sourceUid] = {
84
+ ...sourceRuntime,
85
+ [DISCOUNT_SPLIT_ORIGIN_UID_KEY]: discountSplitOriginUid
86
+ };
87
+ productsByUid[splitUid] = {
88
+ ...(0, import_lodash_es.cloneDeep)(sourceRuntime),
89
+ [DISCOUNT_SPLIT_ORIGIN_UID_KEY]: discountSplitOriginUid
90
+ };
91
+ usedUids.add(splitUid);
92
+ return product;
93
+ });
94
+ }
95
+ function consolidateDiscountFreeProductLines(tempOrder) {
96
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
97
+ const consolidatedProducts = [];
98
+ const productIndexByKey = /* @__PURE__ */ new Map();
99
+ for (const product of tempOrder.products || []) {
100
+ const productBundle = Array.isArray(product.product_bundle) ? product.product_bundle : [];
101
+ const hasDiscount = (product.discount_list || []).length > 0 || productBundle.some((bundle) => ((bundle == null ? void 0 : bundle.discount_list) || []).length > 0);
102
+ const bookingUid = product.booking_uid ?? ((_a = product.metadata) == null ? void 0 : _a.booking_uid);
103
+ const bookingId = product.booking_id ?? ((_b = product.metadata) == null ? void 0 : _b.booking_id);
104
+ const orderDetailId = product.order_detail_id ?? product.orderDetailId;
105
+ const holderId = product.holder_id ?? ((_c = product.metadata) == null ? void 0 : _c.holder_id);
106
+ const hasMergeBoundary = hasDiscount || Boolean(((_d = product.metadata) == null ? void 0 : _d._giftInfo) || product._giftInfo) || Boolean((_e = product.metadata) == null ? void 0 : _e._promotion) || isManualProductDiscountLine(product) || hasProductLineNote(product) || Number(((_f = product.product_sku) == null ? void 0 : _f.open_sold_weight) || 0) === 1 || ((_g = product.metadata) == null ? void 0 : _g.is_edit_for_runtime) === true || bookingId !== void 0 && bookingId !== null && bookingId !== 0 && bookingId !== "0" || bookingUid !== void 0 && bookingUid !== null && String(bookingUid) !== "" || holderId !== void 0 && holderId !== null && String(holderId) !== "" || orderDetailId !== void 0 && orderDetailId !== null && orderDetailId !== "";
107
+ if (hasMergeBoundary) {
108
+ consolidatedProducts.push(product);
109
+ continue;
110
+ }
111
+ const productUid = getProductLineUid(product);
112
+ const discountSplitOriginUid = productUid ? (_j = (_i = (_h = tempOrder._extend) == null ? void 0 : _h.productsByUid) == null ? void 0 : _i[productUid]) == null ? void 0 : _j[DISCOUNT_SPLIT_ORIGIN_UID_KEY] : void 0;
113
+ if (!discountSplitOriginUid) {
114
+ consolidatedProducts.push(product);
115
+ continue;
116
+ }
117
+ const fingerprint = (0, import_utils.buildProductLineFingerprint)(
118
+ getProductSkuOptions(product),
119
+ productBundle
120
+ );
121
+ const priceSignature = JSON.stringify({
122
+ selling_price: String(product.selling_price ?? ""),
123
+ original_price: String(product.original_price ?? ""),
124
+ custom_price: String(product.custom_price ?? ""),
125
+ is_charge_tax: Number(product.is_charge_tax ?? 0),
126
+ gift_card: Number(product.gift_card ?? 0),
127
+ bundle_edit: Number(product.bundle_edit ?? 0),
128
+ price_schema_version: ((_k = product.metadata) == null ? void 0 : _k.price_schema_version) ?? "",
129
+ source_product_price: String(((_l = product.metadata) == null ? void 0 : _l.source_product_price) ?? ""),
130
+ main_product_selling_price: String(
131
+ ((_m = product.metadata) == null ? void 0 : _m.main_product_selling_price) ?? ""
132
+ ),
133
+ main_product_original_price: String(
134
+ ((_n = product.metadata) == null ? void 0 : _n.main_product_original_price) ?? ""
135
+ ),
136
+ bundle: productBundle.map((bundle) => ({
137
+ bundle_id: (bundle == null ? void 0 : bundle.bundle_id) ?? (bundle == null ? void 0 : bundle.id) ?? "",
138
+ product_id: (bundle == null ? void 0 : bundle.bundle_product_id) ?? (bundle == null ? void 0 : bundle._bundle_product_id) ?? (bundle == null ? void 0 : bundle.product_id) ?? "",
139
+ product_variant_id: (bundle == null ? void 0 : bundle.bundle_variant_id) ?? (bundle == null ? void 0 : bundle.variant_id) ?? (bundle == null ? void 0 : bundle.product_variant_id) ?? 0,
140
+ price: String((bundle == null ? void 0 : bundle.price) ?? ""),
141
+ original_price: String((bundle == null ? void 0 : bundle.original_price) ?? ""),
142
+ bundle_selling_price: String((bundle == null ? void 0 : bundle.bundle_selling_price) ?? "")
143
+ }))
144
+ });
145
+ const mergeKey = [
146
+ discountSplitOriginUid,
147
+ product.product_id,
148
+ product.product_variant_id ?? 0,
149
+ fingerprint,
150
+ priceSignature
151
+ ].join("#");
152
+ const matchedIndex = productIndexByKey.get(mergeKey);
153
+ if (matchedIndex === void 0) {
154
+ productIndexByKey.set(mergeKey, consolidatedProducts.length);
155
+ consolidatedProducts.push(product);
156
+ continue;
157
+ }
158
+ const matchedProduct = consolidatedProducts[matchedIndex];
159
+ matchedProduct.num = (0, import_utils.getSafeProductNum)(
160
+ Number(matchedProduct.num || 0) + Number(product.num || 0)
161
+ );
162
+ }
163
+ tempOrder.products = consolidatedProducts;
164
+ }
165
+ // Annotate the CommonJS export names for ESM import in node:
166
+ 0 && (module.exports = {
167
+ DISCOUNT_SPLIT_ORIGIN_UID_KEY,
168
+ consolidateDiscountFreeProductLines,
169
+ ensureUniqueProductLineUids
170
+ });
@@ -0,0 +1,56 @@
1
+ import type { OrderProduct, OrderTempOrder } from '../types';
2
+ export interface SelectedSettlementSnapshot extends Record<string, any> {
3
+ settlement_type: 'legal_currency' | 'virtual_currency';
4
+ currency_product_id?: number;
5
+ price: string | number;
6
+ unit_label?: any;
7
+ symbol?: any;
8
+ amount_format?: string;
9
+ }
10
+ export interface LegalCurrencySnapshot {
11
+ currency_code: string;
12
+ currency_symbol: string;
13
+ currency_format: string;
14
+ }
15
+ export declare function resolveSettlementDisplayValue(value: unknown): string;
16
+ export declare class OrderSettlementConflictError extends Error {
17
+ readonly currentSettlementKey: string;
18
+ readonly incomingSettlementKey: string;
19
+ readonly code = "ORDER_SETTLEMENT_CONFLICT";
20
+ constructor(currentSettlementKey: string, incomingSettlementKey: string);
21
+ }
22
+ export declare class VirtualCurrencyAssetNotFoundError extends Error {
23
+ readonly currencyProductId: number;
24
+ readonly code = "VIRTUAL_CURRENCY_ASSET_NOT_FOUND";
25
+ constructor(currencyProductId: number);
26
+ }
27
+ export declare class VirtualCurrencyBalanceError extends Error {
28
+ readonly balance: string;
29
+ readonly requiredAmount: string;
30
+ readonly code = "VIRTUAL_CURRENCY_BALANCE_INSUFFICIENT";
31
+ constructor(balance: string, requiredAmount: string);
32
+ }
33
+ export declare function getSelectedSettlementSnapshot(product: Partial<OrderProduct> | null | undefined): SelectedSettlementSnapshot | null;
34
+ export declare function getTempOrderSettlementSnapshot(tempOrder: OrderTempOrder | null | undefined): SelectedSettlementSnapshot | null;
35
+ export declare function isVirtualSettlementProduct(product: Partial<OrderProduct> | null | undefined): boolean;
36
+ export declare function getSettlementKey(snapshot: SelectedSettlementSnapshot | null | undefined): string | null;
37
+ export declare function getTempOrderSettlementKey(tempOrder: OrderTempOrder | null | undefined): string | null;
38
+ export declare function isVirtualSettlementOrder(tempOrder: OrderTempOrder | null | undefined): boolean;
39
+ /**
40
+ * 详情展示识别同时支持已提交订单的 currency_settlement_config。
41
+ * cart_settlement_* 是交易过程内部状态,服务端详情不保证返回。
42
+ */
43
+ export declare function isVirtualSettlementDisplayOrder(tempOrder: OrderTempOrder | null | undefined): boolean;
44
+ /**
45
+ * 将购物车锁定的结算单位提升为订单级状态。
46
+ * 商品行快照只负责价格归一化;展示与提交统一读取 tempOrder.currency_*。
47
+ */
48
+ export declare function applyTempOrderSettlementState(tempOrder: OrderTempOrder, snapshot: SelectedSettlementSnapshot): void;
49
+ /** 清空购物车结算锁,并恢复进入虚拟币结算前的店铺法币。 */
50
+ export declare function releaseTempOrderSettlementState(tempOrder: OrderTempOrder): void;
51
+ /**
52
+ * 将已选择虚拟币的订单商品行固化为最终价语义。
53
+ * 函数幂等,可安全用于加车、合并、hydrate 和提交前兜底。
54
+ */
55
+ export declare function normalizeVirtualSettlementOrderProduct<T extends Partial<OrderProduct>>(product: T): T;
56
+ export declare function normalizeVirtualSettlementProducts<T extends Partial<OrderProduct>>(products: T[]): T[];
@@ -0,0 +1,300 @@
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/modules/Order/utils/virtualSettlement.ts
30
+ var virtualSettlement_exports = {};
31
+ __export(virtualSettlement_exports, {
32
+ OrderSettlementConflictError: () => OrderSettlementConflictError,
33
+ VirtualCurrencyAssetNotFoundError: () => VirtualCurrencyAssetNotFoundError,
34
+ VirtualCurrencyBalanceError: () => VirtualCurrencyBalanceError,
35
+ applyTempOrderSettlementState: () => applyTempOrderSettlementState,
36
+ getSelectedSettlementSnapshot: () => getSelectedSettlementSnapshot,
37
+ getSettlementKey: () => getSettlementKey,
38
+ getTempOrderSettlementKey: () => getTempOrderSettlementKey,
39
+ getTempOrderSettlementSnapshot: () => getTempOrderSettlementSnapshot,
40
+ isVirtualSettlementDisplayOrder: () => isVirtualSettlementDisplayOrder,
41
+ isVirtualSettlementOrder: () => isVirtualSettlementOrder,
42
+ isVirtualSettlementProduct: () => isVirtualSettlementProduct,
43
+ normalizeVirtualSettlementOrderProduct: () => normalizeVirtualSettlementOrderProduct,
44
+ normalizeVirtualSettlementProducts: () => normalizeVirtualSettlementProducts,
45
+ releaseTempOrderSettlementState: () => releaseTempOrderSettlementState,
46
+ resolveSettlementDisplayValue: () => resolveSettlementDisplayValue
47
+ });
48
+ module.exports = __toCommonJS(virtualSettlement_exports);
49
+ var import_decimal = __toESM(require("decimal.js"));
50
+ function resolveSettlementDisplayValue(value) {
51
+ if (value === void 0 || value === null)
52
+ return "";
53
+ if (typeof value === "string" || typeof value === "number") {
54
+ return String(value);
55
+ }
56
+ const localized = value;
57
+ return String(
58
+ localized.auto ?? localized.default ?? localized.original ?? localized.en ?? localized["zh-CN"] ?? localized["zh-HK"] ?? ""
59
+ );
60
+ }
61
+ var OrderSettlementConflictError = class extends Error {
62
+ constructor(currentSettlementKey, incomingSettlementKey) {
63
+ super("Different currencies and WalletPass units cannot be mixed in one cart.");
64
+ this.currentSettlementKey = currentSettlementKey;
65
+ this.incomingSettlementKey = incomingSettlementKey;
66
+ this.code = "ORDER_SETTLEMENT_CONFLICT";
67
+ this.name = "OrderSettlementConflictError";
68
+ }
69
+ };
70
+ var VirtualCurrencyAssetNotFoundError = class extends Error {
71
+ constructor(currencyProductId) {
72
+ super("No matching virtual currency card is available.");
73
+ this.currencyProductId = currencyProductId;
74
+ this.code = "VIRTUAL_CURRENCY_ASSET_NOT_FOUND";
75
+ this.name = "VirtualCurrencyAssetNotFoundError";
76
+ }
77
+ };
78
+ var VirtualCurrencyBalanceError = class extends Error {
79
+ constructor(balance, requiredAmount) {
80
+ super("Insufficient virtual currency balance.");
81
+ this.balance = balance;
82
+ this.requiredAmount = requiredAmount;
83
+ this.code = "VIRTUAL_CURRENCY_BALANCE_INSUFFICIENT";
84
+ this.name = "VirtualCurrencyBalanceError";
85
+ }
86
+ };
87
+ function getSelectedSettlementSnapshot(product) {
88
+ var _a;
89
+ const snapshot = (_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.selected_settlement_snapshot;
90
+ if (!snapshot || typeof snapshot !== "object")
91
+ return null;
92
+ if (snapshot.settlement_type !== "legal_currency" && snapshot.settlement_type !== "virtual_currency") {
93
+ return null;
94
+ }
95
+ return snapshot;
96
+ }
97
+ function getTempOrderSettlementSnapshot(tempOrder) {
98
+ var _a, _b;
99
+ const snapshot = (_a = tempOrder == null ? void 0 : tempOrder.metadata) == null ? void 0 : _a.cart_settlement_snapshot;
100
+ if (snapshot && typeof snapshot === "object" && (snapshot.settlement_type === "legal_currency" || snapshot.settlement_type === "virtual_currency")) {
101
+ return snapshot;
102
+ }
103
+ return getSelectedSettlementSnapshot((_b = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _b[0]);
104
+ }
105
+ function isVirtualSettlementProduct(product) {
106
+ var _a;
107
+ return ((_a = getSelectedSettlementSnapshot(product)) == null ? void 0 : _a.settlement_type) === "virtual_currency";
108
+ }
109
+ function getSettlementKey(snapshot) {
110
+ if (!snapshot)
111
+ return null;
112
+ if (snapshot.settlement_type === "legal_currency")
113
+ return "legal_currency";
114
+ const currencyProductId = Number(snapshot.currency_product_id);
115
+ return Number.isFinite(currencyProductId) && currencyProductId > 0 ? `virtual_currency:${currencyProductId}` : null;
116
+ }
117
+ function getTempOrderSettlementKey(tempOrder) {
118
+ var _a, _b;
119
+ if (!((_a = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _a.length))
120
+ return null;
121
+ const storedKey = (_b = tempOrder.metadata) == null ? void 0 : _b.cart_settlement_key;
122
+ if (typeof storedKey === "string" && storedKey)
123
+ return storedKey;
124
+ return getSettlementKey(getTempOrderSettlementSnapshot(tempOrder)) || "legal_currency";
125
+ }
126
+ function isVirtualSettlementOrder(tempOrder) {
127
+ var _a;
128
+ return ((_a = getTempOrderSettlementKey(tempOrder)) == null ? void 0 : _a.startsWith("virtual_currency:")) === true;
129
+ }
130
+ function isVirtualSettlementDisplayOrder(tempOrder) {
131
+ var _a, _b;
132
+ return ((_b = (_a = tempOrder == null ? void 0 : tempOrder.metadata) == null ? void 0 : _a.currency_settlement_config) == null ? void 0 : _b.settlement_type) === "virtual_currency" || isVirtualSettlementOrder(tempOrder);
133
+ }
134
+ function getLegalCurrencySnapshot(tempOrder) {
135
+ var _a;
136
+ const snapshot = (_a = tempOrder.metadata) == null ? void 0 : _a.legal_currency_snapshot;
137
+ if (!snapshot || typeof snapshot !== "object")
138
+ return null;
139
+ return {
140
+ currency_code: String(snapshot.currency_code || ""),
141
+ currency_symbol: String(snapshot.currency_symbol || ""),
142
+ currency_format: String(snapshot.currency_format || "symbol_first")
143
+ };
144
+ }
145
+ function captureLegalCurrencySnapshot(tempOrder) {
146
+ tempOrder.metadata = tempOrder.metadata || {};
147
+ if (getLegalCurrencySnapshot(tempOrder))
148
+ return;
149
+ tempOrder.metadata.legal_currency_snapshot = {
150
+ currency_code: String(tempOrder.currency_code || ""),
151
+ currency_symbol: String(tempOrder.currency_symbol || ""),
152
+ currency_format: String(tempOrder.currency_format || "symbol_first")
153
+ };
154
+ }
155
+ function applyTempOrderSettlementState(tempOrder, snapshot) {
156
+ tempOrder.metadata = tempOrder.metadata || {};
157
+ const settlementKey = getSettlementKey(snapshot) || "legal_currency";
158
+ if (snapshot.settlement_type === "virtual_currency") {
159
+ captureLegalCurrencySnapshot(tempOrder);
160
+ const currencyProductId = Number(snapshot.currency_product_id);
161
+ tempOrder.metadata.currency_settlement_config = {
162
+ settlement_type: "virtual_currency",
163
+ settlement_ids: Number.isFinite(currencyProductId) && currencyProductId > 0 ? [currencyProductId] : []
164
+ };
165
+ } else {
166
+ delete tempOrder.metadata.currency_settlement_config;
167
+ }
168
+ tempOrder.metadata.cart_settlement_key = settlementKey;
169
+ tempOrder.metadata.cart_settlement_snapshot = { ...snapshot };
170
+ tempOrder.currency_code = resolveSettlementDisplayValue(snapshot.unit_label) || tempOrder.currency_code;
171
+ tempOrder.currency_symbol = resolveSettlementDisplayValue(snapshot.symbol) || tempOrder.currency_symbol;
172
+ tempOrder.currency_format = String(
173
+ snapshot.amount_format || tempOrder.currency_format || "symbol_first"
174
+ );
175
+ }
176
+ function releaseTempOrderSettlementState(tempOrder) {
177
+ tempOrder.metadata = tempOrder.metadata || {};
178
+ const legalCurrency = getLegalCurrencySnapshot(tempOrder);
179
+ if (legalCurrency) {
180
+ tempOrder.currency_code = legalCurrency.currency_code;
181
+ tempOrder.currency_symbol = legalCurrency.currency_symbol;
182
+ tempOrder.currency_format = legalCurrency.currency_format;
183
+ }
184
+ delete tempOrder.metadata.cart_settlement_key;
185
+ delete tempOrder.metadata.cart_settlement_snapshot;
186
+ delete tempOrder.metadata.currency_settlement_config;
187
+ }
188
+ function toMoney(value) {
189
+ try {
190
+ return new import_decimal.default(String(value ?? 0)).toDecimalPlaces(2).toFixed(2);
191
+ } catch {
192
+ return "0.00";
193
+ }
194
+ }
195
+ function zeroOptions(options) {
196
+ if (!Array.isArray(options))
197
+ return [];
198
+ return options.map((option) => ({
199
+ ...option,
200
+ add_price: 0
201
+ }));
202
+ }
203
+ function zeroBundles(bundles) {
204
+ if (!Array.isArray(bundles))
205
+ return [];
206
+ return bundles.map((bundle) => ({
207
+ ...bundle,
208
+ price: 0,
209
+ custom_price: 0,
210
+ bundle_selling_price: 0,
211
+ bundle_payment_price: 0,
212
+ surcharge_fee: 0,
213
+ tax_fee: 0,
214
+ original_tax_fee: 0,
215
+ is_charge_tax: 0,
216
+ discount_list: [],
217
+ relation_surcharge_ids: [],
218
+ option: zeroOptions(bundle == null ? void 0 : bundle.option),
219
+ metadata: {
220
+ ...(bundle == null ? void 0 : bundle.metadata) || {},
221
+ surcharge_fee: "0.00",
222
+ relation_surcharge_ids: [],
223
+ product_discount_difference: "",
224
+ tax_fee_rounding_remainder: "0.00",
225
+ surcharge_rounding_remainder: "0.00"
226
+ }
227
+ }));
228
+ }
229
+ function normalizeVirtualSettlementOrderProduct(product) {
230
+ var _a;
231
+ const snapshot = getSelectedSettlementSnapshot(product);
232
+ if ((snapshot == null ? void 0 : snapshot.settlement_type) !== "virtual_currency")
233
+ return product;
234
+ const virtualPrice = toMoney(snapshot.price);
235
+ const metadata = {
236
+ ...product.metadata || {},
237
+ source_product_price: virtualPrice,
238
+ main_product_original_price: virtualPrice,
239
+ main_product_selling_price: virtualPrice,
240
+ main_product_attached_bundle_selling_price: virtualPrice,
241
+ main_product_attached_bundle_payment_price: virtualPrice,
242
+ main_product_attached_bundle_surcharge_fee: "0.00",
243
+ main_product_attached_bundle_tax_fee: "0.00",
244
+ surcharge_rounding_remainder: "0.00",
245
+ tax_fee_rounding_remainder: "0.00",
246
+ relation_surcharge_ids: [],
247
+ average_discount_amount_rate: "1",
248
+ product_discount_difference: "",
249
+ discountable_flag: 0,
250
+ price_schema_version: 2,
251
+ selected_settlement_snapshot: {
252
+ ...snapshot,
253
+ price: virtualPrice
254
+ }
255
+ };
256
+ return {
257
+ ...product,
258
+ selling_price: virtualPrice,
259
+ original_price: virtualPrice,
260
+ payment_price: virtualPrice,
261
+ discount_list: [],
262
+ is_charge_tax: 0,
263
+ tax_fee: "0.00",
264
+ original_tax_fee: 0,
265
+ tax_fee_rounding_remainder: 0,
266
+ original_tax_fee_rounding_remainder: 0,
267
+ surcharge_fee: "0.00",
268
+ surcharge_rounding_remainder: 0,
269
+ relation_surcharge_ids: [],
270
+ product_sku: {
271
+ ...product.product_sku || {},
272
+ option: zeroOptions((_a = product.product_sku) == null ? void 0 : _a.option)
273
+ },
274
+ product_bundle: zeroBundles(product.product_bundle),
275
+ metadata
276
+ };
277
+ }
278
+ function normalizeVirtualSettlementProducts(products) {
279
+ return (products || []).map(
280
+ (product) => normalizeVirtualSettlementOrderProduct(product)
281
+ );
282
+ }
283
+ // Annotate the CommonJS export names for ESM import in node:
284
+ 0 && (module.exports = {
285
+ OrderSettlementConflictError,
286
+ VirtualCurrencyAssetNotFoundError,
287
+ VirtualCurrencyBalanceError,
288
+ applyTempOrderSettlementState,
289
+ getSelectedSettlementSnapshot,
290
+ getSettlementKey,
291
+ getTempOrderSettlementKey,
292
+ getTempOrderSettlementSnapshot,
293
+ isVirtualSettlementDisplayOrder,
294
+ isVirtualSettlementOrder,
295
+ isVirtualSettlementProduct,
296
+ normalizeVirtualSettlementOrderProduct,
297
+ normalizeVirtualSettlementProducts,
298
+ releaseTempOrderSettlementState,
299
+ resolveSettlementDisplayValue
300
+ });