@pisell/pisellos 2.3.101 → 2.3.103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  2. package/dist/model/strategy/adapter/dataVariant/evaluator.js +287 -101
  3. package/dist/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  4. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  5. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +10 -7
  6. package/dist/modules/Discount/index.d.ts +2 -0
  7. package/dist/modules/Discount/index.js +38 -5
  8. package/dist/modules/Discount/types.d.ts +11 -0
  9. package/dist/modules/Order/index.d.ts +29 -3
  10. package/dist/modules/Order/index.js +1105 -703
  11. package/dist/modules/Order/types.d.ts +14 -6
  12. package/dist/modules/Order/types.js +1 -1
  13. package/dist/modules/Order/utils/virtualSettlement.d.ts +63 -0
  14. package/dist/modules/Order/utils/virtualSettlement.js +284 -0
  15. package/dist/modules/Order/utils.d.ts +1 -0
  16. package/dist/modules/Order/utils.js +63 -24
  17. package/dist/modules/Product/types.d.ts +23 -0
  18. package/dist/modules/SalesSummary/index.d.ts +1 -0
  19. package/dist/modules/SalesSummary/index.js +4 -3
  20. package/dist/modules/SalesSummary/types.d.ts +1 -0
  21. package/dist/modules/SalesSummary/utils.d.ts +1 -0
  22. package/dist/modules/SalesSummary/utils.js +21 -1
  23. package/dist/solution/BaseSales/index.d.ts +10 -1
  24. package/dist/solution/BaseSales/index.js +1074 -746
  25. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  26. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +72 -9
  27. package/dist/solution/BookingByStep/index.d.ts +2 -2
  28. package/dist/solution/BookingTicket/utils/addProductDecision.js +2 -1
  29. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  30. package/lib/model/strategy/adapter/dataVariant/evaluator.js +137 -6
  31. package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  32. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +4 -0
  33. package/lib/modules/Discount/index.d.ts +2 -0
  34. package/lib/modules/Discount/index.js +31 -2
  35. package/lib/modules/Discount/types.d.ts +11 -0
  36. package/lib/modules/Order/index.d.ts +29 -3
  37. package/lib/modules/Order/index.js +326 -51
  38. package/lib/modules/Order/types.d.ts +14 -6
  39. package/lib/modules/Order/types.js +1 -1
  40. package/lib/modules/Order/utils/virtualSettlement.d.ts +63 -0
  41. package/lib/modules/Order/utils/virtualSettlement.js +262 -0
  42. package/lib/modules/Order/utils.d.ts +1 -0
  43. package/lib/modules/Order/utils.js +57 -20
  44. package/lib/modules/Product/types.d.ts +23 -0
  45. package/lib/modules/SalesSummary/index.d.ts +1 -0
  46. package/lib/modules/SalesSummary/index.js +4 -2
  47. package/lib/modules/SalesSummary/types.d.ts +1 -0
  48. package/lib/modules/SalesSummary/utils.d.ts +1 -0
  49. package/lib/modules/SalesSummary/utils.js +17 -1
  50. package/lib/solution/BaseSales/index.d.ts +10 -1
  51. package/lib/solution/BaseSales/index.js +228 -20
  52. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  53. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +38 -0
  54. package/lib/solution/BookingByStep/index.d.ts +2 -2
  55. package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -0
  56. 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';
@@ -117,7 +117,7 @@ export interface OrderLastGiftActions {
117
117
  }>;
118
118
  toRemove: string[];
119
119
  }
120
- /** onPromotionApplied 事件 payload */
120
+ /** onPromotionApplied 稳定态事件 payload(促销、折扣与 summary 均已完成)。 */
121
121
  export interface OrderPromotionAppliedPayload {
122
122
  unfulfilledPromotions: OrderUnfulfilledPromotion[];
123
123
  giftActions: OrderLastGiftActions;
@@ -131,7 +131,7 @@ export interface OrderPromotionAppliedPayload {
131
131
  product_variant_id: number;
132
132
  }>;
133
133
  }>;
134
- /** 处理后的商品列表 */
134
+ /** 折扣重算后的最终商品列表 */
135
135
  products: OrderProduct[];
136
136
  }
137
137
  /**
@@ -205,6 +205,7 @@ export interface OrderProduct extends OrderProductIdentity {
205
205
  gift_card?: number;
206
206
  selling_price: string;
207
207
  original_price: string;
208
+ payment_price?: string;
208
209
  tax_fee: string;
209
210
  is_charge_tax: number;
210
211
  discount_list: OrderProductDiscountItem[];
@@ -353,6 +354,7 @@ export interface OrderTempOrder {
353
354
  notes: SalesNote[];
354
355
  bookings: any[];
355
356
  payments: any[];
357
+ refunds?: any[];
356
358
  surcharges: any[];
357
359
  discount_list?: any[];
358
360
  relation_forms: any[];
@@ -372,8 +374,9 @@ export interface OrderSubmitProduct extends Omit<OrderProduct, 'unique_identific
372
374
  payment_price: string;
373
375
  product_sku: OrderProductSku;
374
376
  }
375
- export interface OrderSubmitPayload extends Omit<OrderTempOrder, 'platform' | 'products' | 'notes' | '_extend' | 'customer' | 'discount_list' | 'created_at'> {
377
+ export interface OrderSubmitPayload extends Omit<OrderTempOrder, 'platform' | 'products' | 'notes' | '_extend' | 'customer' | 'discount_list' | 'created_at' | 'payment_status'> {
376
378
  platform: string;
379
+ payment_status?: string;
377
380
  created_at?: string | undefined;
378
381
  request_unique_idempotency_token?: string;
379
382
  form_record_ids?: Array<{
@@ -392,6 +395,7 @@ export interface OrderState {
392
395
  syncState?: OrderSyncState;
393
396
  discountList: any[];
394
397
  availableWalletIds?: number[];
398
+ virtualCurrencyList?: VirtualCurrencyAsset[];
395
399
  discount: DiscountModule | null;
396
400
  rules: RulesModule | null;
397
401
  }
@@ -530,7 +534,7 @@ export interface SubmitSalesOrderParams {
530
534
  sales_channel: string;
531
535
  order_sales_channel: string;
532
536
  status: string;
533
- payment_status: string;
537
+ payment_status?: string;
534
538
  shipping_status: string;
535
539
  customer_id: number | null;
536
540
  customer_name: string;
@@ -794,6 +798,8 @@ export interface OrderModuleAPI {
794
798
  addNewOrder: () => Promise<OrderTempOrder>;
795
799
  restoreOrder: () => OrderTempOrder;
796
800
  getOrderProducts: () => OrderProduct[];
801
+ getVirtualCurrencyList: () => VirtualCurrencyAsset[];
802
+ clearOrderForSettlementSwitch: () => Promise<OrderTempOrder>;
797
803
  getOrderSummary: () => Promise<OrderSummary>;
798
804
  recalculateSummary: (options?: {
799
805
  createIfMissing?: boolean;
@@ -864,6 +870,8 @@ export interface OrderModuleAPI {
864
870
  isTempOrderPersistEnabled: () => boolean;
865
871
  /** 提交 tempOrder 变更并触发 `{moduleName}:changed` 事件 */
866
872
  notifyTempOrderChanged: () => void;
873
+ /** PC/H5 为在线店铺;其它或缺失平台统一按 POS 处理。 */
874
+ isOnlineStorePlatform: () => boolean;
867
875
  submitTempOrder: <T = any>(params?: {
868
876
  cacheId?: string;
869
877
  platform?: string;
@@ -971,7 +979,7 @@ export interface OrderModuleAPI {
971
979
  */
972
980
  appendPromotionTags: <T extends Record<string, any>>(products: T[]) => T[];
973
981
  /**
974
- * 应用购物车促销(评估 → 差异化赠品 → 写回 tempOrder.products → emit onPromotionApplied)。
982
+ * 应用购物车促销(评估 → 差异化赠品 → 折扣/summary 重算 → emit onPromotionApplied)。
975
983
  *
976
984
  * 自动在 addProductToOrder / updateOrderProductQuantity / removeProductFromOrder /
977
985
  * clearOrderCartLines / setOrderCustomer 等写路径末尾触发,业务一般无需手动调用。
@@ -40,7 +40,7 @@ let OrderHooks = exports.OrderHooks = /*#__PURE__*/function (OrderHooks) {
40
40
  */
41
41
  /** 未满足的促销策略(购物车底部 alert 渲染源) */
42
42
  /** 上一次 applyPromotion 计算出的赠品操作(仅供调试/读取使用) */
43
- /** onPromotionApplied 事件 payload */
43
+ /** onPromotionApplied 稳定态事件 payload(促销、折扣与 summary 均已完成)。 */
44
44
  /**
45
45
  * tempOrder 上的下单客户协议字段视图。
46
46
  * 这些字段会随订单提交到后端。
@@ -0,0 +1,63 @@
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 interface CurrencyDisplaySnapshot {
16
+ amount_format: string;
17
+ symbol: unknown;
18
+ unit_label: unknown;
19
+ }
20
+ export declare function buildCurrencyDisplaySnapshot(snapshot: Pick<SelectedSettlementSnapshot, 'amount_format' | 'symbol' | 'unit_label'>): CurrencyDisplaySnapshot;
21
+ export declare function resolveSettlementDisplayValue(value: unknown): string;
22
+ export declare class OrderSettlementConflictError extends Error {
23
+ readonly currentSettlementKey: string;
24
+ readonly incomingSettlementKey: string;
25
+ readonly code = "ORDER_SETTLEMENT_CONFLICT";
26
+ constructor(currentSettlementKey: string, incomingSettlementKey: string);
27
+ }
28
+ export declare class VirtualCurrencyAssetNotFoundError extends Error {
29
+ readonly currencyProductId: number;
30
+ readonly code = "VIRTUAL_CURRENCY_ASSET_NOT_FOUND";
31
+ constructor(currencyProductId: number);
32
+ }
33
+ export declare class VirtualCurrencyBalanceError extends Error {
34
+ readonly balance: string;
35
+ readonly requiredAmount: string;
36
+ readonly code = "VIRTUAL_CURRENCY_BALANCE_INSUFFICIENT";
37
+ constructor(balance: string, requiredAmount: string);
38
+ }
39
+ export declare function getSelectedSettlementSnapshot(product: Partial<OrderProduct> | null | undefined): SelectedSettlementSnapshot | null;
40
+ export declare function getTempOrderSettlementSnapshot(tempOrder: OrderTempOrder | null | undefined): SelectedSettlementSnapshot | null;
41
+ export declare function isVirtualSettlementProduct(product: Partial<OrderProduct> | null | undefined): boolean;
42
+ export declare function getSettlementKey(snapshot: SelectedSettlementSnapshot | null | undefined): string | null;
43
+ export declare function getTempOrderSettlementKey(tempOrder: OrderTempOrder | null | undefined): string | null;
44
+ export declare function isVirtualSettlementOrder(tempOrder: OrderTempOrder | null | undefined): boolean;
45
+ /**
46
+ * 详情展示识别同时支持已提交订单的 currency_settlement_config。
47
+ * cart_settlement_* 是交易过程内部状态,服务端详情不保证返回。
48
+ */
49
+ export declare function isVirtualSettlementDisplayOrder(tempOrder: OrderTempOrder | null | undefined): boolean;
50
+ /**
51
+ * 将购物车锁定的结算单位提升为订单级状态。
52
+ * 商品行快照同时负责价格归一化和生成订单级多语言展示快照;
53
+ * 交易中的即时展示仍统一读取 tempOrder.currency_*。
54
+ */
55
+ export declare function applyTempOrderSettlementState(tempOrder: OrderTempOrder, snapshot: SelectedSettlementSnapshot): void;
56
+ /** 清空购物车结算锁,并恢复进入虚拟币结算前的店铺法币。 */
57
+ export declare function releaseTempOrderSettlementState(tempOrder: OrderTempOrder): void;
58
+ /**
59
+ * 将已选择虚拟币的订单商品行固化为最终价语义。
60
+ * 函数幂等,可安全用于加车、合并、hydrate 和提交前兜底。
61
+ */
62
+ export declare function normalizeVirtualSettlementOrderProduct<T extends Partial<OrderProduct>>(product: T): T;
63
+ export declare function normalizeVirtualSettlementProducts<T extends Partial<OrderProduct>>(products: T[]): T[];
@@ -0,0 +1,262 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.VirtualCurrencyBalanceError = exports.VirtualCurrencyAssetNotFoundError = exports.OrderSettlementConflictError = void 0;
7
+ exports.applyTempOrderSettlementState = applyTempOrderSettlementState;
8
+ exports.buildCurrencyDisplaySnapshot = buildCurrencyDisplaySnapshot;
9
+ exports.getSelectedSettlementSnapshot = getSelectedSettlementSnapshot;
10
+ exports.getSettlementKey = getSettlementKey;
11
+ exports.getTempOrderSettlementKey = getTempOrderSettlementKey;
12
+ exports.getTempOrderSettlementSnapshot = getTempOrderSettlementSnapshot;
13
+ exports.isVirtualSettlementDisplayOrder = isVirtualSettlementDisplayOrder;
14
+ exports.isVirtualSettlementOrder = isVirtualSettlementOrder;
15
+ exports.isVirtualSettlementProduct = isVirtualSettlementProduct;
16
+ exports.normalizeVirtualSettlementOrderProduct = normalizeVirtualSettlementOrderProduct;
17
+ exports.normalizeVirtualSettlementProducts = normalizeVirtualSettlementProducts;
18
+ exports.releaseTempOrderSettlementState = releaseTempOrderSettlementState;
19
+ exports.resolveSettlementDisplayValue = resolveSettlementDisplayValue;
20
+ var _decimal = _interopRequireDefault(require("decimal.js"));
21
+ var _lodashEs = require("lodash-es");
22
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
+ function buildCurrencyDisplaySnapshot(snapshot) {
24
+ return (0, _lodashEs.cloneDeep)({
25
+ amount_format: String(snapshot.amount_format || '').trim(),
26
+ symbol: snapshot.symbol ?? {},
27
+ unit_label: snapshot.unit_label ?? {}
28
+ });
29
+ }
30
+ function resolveSettlementDisplayValue(value) {
31
+ if (value === undefined || value === null) return '';
32
+ if (typeof value === 'string' || typeof value === 'number') {
33
+ return String(value);
34
+ }
35
+ const localized = value;
36
+ return String(localized.auto ?? localized.default ?? localized.original ?? localized.en ?? localized['zh-CN'] ?? localized['zh-HK'] ?? '');
37
+ }
38
+ class OrderSettlementConflictError extends Error {
39
+ code = 'ORDER_SETTLEMENT_CONFLICT';
40
+ constructor(currentSettlementKey, incomingSettlementKey) {
41
+ super('Different currencies and WalletPass units cannot be mixed in one cart.');
42
+ this.currentSettlementKey = currentSettlementKey;
43
+ this.incomingSettlementKey = incomingSettlementKey;
44
+ this.name = 'OrderSettlementConflictError';
45
+ }
46
+ }
47
+ exports.OrderSettlementConflictError = OrderSettlementConflictError;
48
+ class VirtualCurrencyAssetNotFoundError extends Error {
49
+ code = 'VIRTUAL_CURRENCY_ASSET_NOT_FOUND';
50
+ constructor(currencyProductId) {
51
+ super('No matching virtual currency card is available.');
52
+ this.currencyProductId = currencyProductId;
53
+ this.name = 'VirtualCurrencyAssetNotFoundError';
54
+ }
55
+ }
56
+ exports.VirtualCurrencyAssetNotFoundError = VirtualCurrencyAssetNotFoundError;
57
+ class VirtualCurrencyBalanceError extends Error {
58
+ code = 'VIRTUAL_CURRENCY_BALANCE_INSUFFICIENT';
59
+ constructor(balance, requiredAmount) {
60
+ super('Insufficient virtual currency balance.');
61
+ this.balance = balance;
62
+ this.requiredAmount = requiredAmount;
63
+ this.name = 'VirtualCurrencyBalanceError';
64
+ }
65
+ }
66
+ exports.VirtualCurrencyBalanceError = VirtualCurrencyBalanceError;
67
+ function getSelectedSettlementSnapshot(product) {
68
+ const snapshot = product?.metadata?.selected_settlement_snapshot;
69
+ if (!snapshot || typeof snapshot !== 'object') return null;
70
+ if (snapshot.settlement_type !== 'legal_currency' && snapshot.settlement_type !== 'virtual_currency') {
71
+ return null;
72
+ }
73
+ return snapshot;
74
+ }
75
+ function getTempOrderSettlementSnapshot(tempOrder) {
76
+ const snapshot = tempOrder?.metadata?.cart_settlement_snapshot;
77
+ if (snapshot && typeof snapshot === 'object' && (snapshot.settlement_type === 'legal_currency' || snapshot.settlement_type === 'virtual_currency')) {
78
+ return snapshot;
79
+ }
80
+ return getSelectedSettlementSnapshot(tempOrder?.products?.[0]);
81
+ }
82
+ function isVirtualSettlementProduct(product) {
83
+ return getSelectedSettlementSnapshot(product)?.settlement_type === 'virtual_currency';
84
+ }
85
+ function getSettlementKey(snapshot) {
86
+ if (!snapshot) return null;
87
+ if (snapshot.settlement_type === 'legal_currency') return 'legal_currency';
88
+ const currencyProductId = Number(snapshot.currency_product_id);
89
+ return Number.isFinite(currencyProductId) && currencyProductId > 0 ? `virtual_currency:${currencyProductId}` : null;
90
+ }
91
+ function getTempOrderSettlementKey(tempOrder) {
92
+ if (!tempOrder?.products?.length) return null;
93
+ const storedKey = tempOrder.metadata?.cart_settlement_key;
94
+ if (typeof storedKey === 'string' && storedKey) return storedKey;
95
+ return getSettlementKey(getTempOrderSettlementSnapshot(tempOrder)) || 'legal_currency';
96
+ }
97
+ function isVirtualSettlementOrder(tempOrder) {
98
+ return getTempOrderSettlementKey(tempOrder)?.startsWith('virtual_currency:') === true;
99
+ }
100
+
101
+ /**
102
+ * 详情展示识别同时支持已提交订单的 currency_settlement_config。
103
+ * cart_settlement_* 是交易过程内部状态,服务端详情不保证返回。
104
+ */
105
+ function isVirtualSettlementDisplayOrder(tempOrder) {
106
+ return tempOrder?.metadata?.currency_settlement_config?.settlement_type === 'virtual_currency' || isVirtualSettlementOrder(tempOrder);
107
+ }
108
+ function getLegalCurrencySnapshot(tempOrder) {
109
+ const snapshot = tempOrder.metadata?.legal_currency_snapshot;
110
+ if (!snapshot || typeof snapshot !== 'object') return null;
111
+ return {
112
+ currency_code: String(snapshot.currency_code || ''),
113
+ currency_symbol: String(snapshot.currency_symbol || ''),
114
+ currency_format: String(snapshot.currency_format || 'symbol_first')
115
+ };
116
+ }
117
+ function captureLegalCurrencySnapshot(tempOrder) {
118
+ tempOrder.metadata = tempOrder.metadata || {};
119
+ if (getLegalCurrencySnapshot(tempOrder)) return;
120
+ tempOrder.metadata.legal_currency_snapshot = {
121
+ currency_code: String(tempOrder.currency_code || ''),
122
+ currency_symbol: String(tempOrder.currency_symbol || ''),
123
+ currency_format: String(tempOrder.currency_format || 'symbol_first')
124
+ };
125
+ }
126
+
127
+ /**
128
+ * 将购物车锁定的结算单位提升为订单级状态。
129
+ * 商品行快照同时负责价格归一化和生成订单级多语言展示快照;
130
+ * 交易中的即时展示仍统一读取 tempOrder.currency_*。
131
+ */
132
+ function applyTempOrderSettlementState(tempOrder, snapshot) {
133
+ tempOrder.metadata = tempOrder.metadata || {};
134
+ const settlementKey = getSettlementKey(snapshot) || 'legal_currency';
135
+ if (snapshot.settlement_type === 'virtual_currency') {
136
+ captureLegalCurrencySnapshot(tempOrder);
137
+ const currencyProductId = Number(snapshot.currency_product_id);
138
+ const existingDisplaySnapshot = tempOrder.metadata.currency_settlement_config?.currency_display_snapshot;
139
+ tempOrder.metadata.currency_settlement_config = {
140
+ settlement_type: 'virtual_currency',
141
+ settlement_ids: Number.isFinite(currencyProductId) && currencyProductId > 0 ? [currencyProductId] : [],
142
+ currency_display_snapshot: existingDisplaySnapshot ? (0, _lodashEs.cloneDeep)(existingDisplaySnapshot) : buildCurrencyDisplaySnapshot(snapshot)
143
+ };
144
+ } else {
145
+ delete tempOrder.metadata.currency_settlement_config;
146
+ }
147
+ tempOrder.metadata.cart_settlement_key = settlementKey;
148
+ tempOrder.metadata.cart_settlement_snapshot = {
149
+ ...snapshot
150
+ };
151
+ tempOrder.currency_code = resolveSettlementDisplayValue(snapshot.unit_label) || tempOrder.currency_code;
152
+ tempOrder.currency_symbol = resolveSettlementDisplayValue(snapshot.symbol) || tempOrder.currency_symbol;
153
+ tempOrder.currency_format = String(snapshot.amount_format || tempOrder.currency_format || 'symbol_first');
154
+ }
155
+
156
+ /** 清空购物车结算锁,并恢复进入虚拟币结算前的店铺法币。 */
157
+ function releaseTempOrderSettlementState(tempOrder) {
158
+ tempOrder.metadata = tempOrder.metadata || {};
159
+ const legalCurrency = getLegalCurrencySnapshot(tempOrder);
160
+ if (legalCurrency) {
161
+ tempOrder.currency_code = legalCurrency.currency_code;
162
+ tempOrder.currency_symbol = legalCurrency.currency_symbol;
163
+ tempOrder.currency_format = legalCurrency.currency_format;
164
+ }
165
+ delete tempOrder.metadata.cart_settlement_key;
166
+ delete tempOrder.metadata.cart_settlement_snapshot;
167
+ delete tempOrder.metadata.currency_settlement_config;
168
+ }
169
+ function toMoney(value) {
170
+ try {
171
+ return new _decimal.default(String(value ?? 0)).toDecimalPlaces(2).toFixed(2);
172
+ } catch {
173
+ return '0.00';
174
+ }
175
+ }
176
+ function zeroOptions(options) {
177
+ if (!Array.isArray(options)) return [];
178
+ return options.map(option => ({
179
+ ...option,
180
+ add_price: 0
181
+ }));
182
+ }
183
+ function zeroBundles(bundles) {
184
+ if (!Array.isArray(bundles)) return [];
185
+ return bundles.map(bundle => ({
186
+ ...bundle,
187
+ price: 0,
188
+ custom_price: 0,
189
+ bundle_selling_price: 0,
190
+ bundle_payment_price: 0,
191
+ surcharge_fee: 0,
192
+ tax_fee: 0,
193
+ original_tax_fee: 0,
194
+ is_charge_tax: 0,
195
+ discount_list: [],
196
+ relation_surcharge_ids: [],
197
+ option: zeroOptions(bundle?.option),
198
+ metadata: {
199
+ ...(bundle?.metadata || {}),
200
+ surcharge_fee: '0.00',
201
+ relation_surcharge_ids: [],
202
+ product_discount_difference: '',
203
+ tax_fee_rounding_remainder: '0.00',
204
+ surcharge_rounding_remainder: '0.00'
205
+ }
206
+ }));
207
+ }
208
+
209
+ /**
210
+ * 将已选择虚拟币的订单商品行固化为最终价语义。
211
+ * 函数幂等,可安全用于加车、合并、hydrate 和提交前兜底。
212
+ */
213
+ function normalizeVirtualSettlementOrderProduct(product) {
214
+ const snapshot = getSelectedSettlementSnapshot(product);
215
+ if (snapshot?.settlement_type !== 'virtual_currency') return product;
216
+ const virtualPrice = toMoney(snapshot.price);
217
+ const metadata = {
218
+ ...(product.metadata || {}),
219
+ source_product_price: virtualPrice,
220
+ main_product_original_price: virtualPrice,
221
+ main_product_selling_price: virtualPrice,
222
+ main_product_attached_bundle_selling_price: virtualPrice,
223
+ main_product_attached_bundle_payment_price: virtualPrice,
224
+ main_product_attached_bundle_surcharge_fee: '0.00',
225
+ main_product_attached_bundle_tax_fee: '0.00',
226
+ surcharge_rounding_remainder: '0.00',
227
+ tax_fee_rounding_remainder: '0.00',
228
+ relation_surcharge_ids: [],
229
+ average_discount_amount_rate: '1',
230
+ product_discount_difference: '',
231
+ discountable_flag: 0,
232
+ price_schema_version: 2,
233
+ selected_settlement_snapshot: {
234
+ ...snapshot,
235
+ price: virtualPrice
236
+ }
237
+ };
238
+ return {
239
+ ...product,
240
+ selling_price: virtualPrice,
241
+ original_price: virtualPrice,
242
+ payment_price: virtualPrice,
243
+ discount_list: [],
244
+ is_charge_tax: 0,
245
+ tax_fee: '0.00',
246
+ original_tax_fee: 0,
247
+ tax_fee_rounding_remainder: 0,
248
+ original_tax_fee_rounding_remainder: 0,
249
+ surcharge_fee: '0.00',
250
+ surcharge_rounding_remainder: 0,
251
+ relation_surcharge_ids: [],
252
+ product_sku: {
253
+ ...(product.product_sku || {}),
254
+ option: zeroOptions(product.product_sku?.option)
255
+ },
256
+ product_bundle: zeroBundles(product.product_bundle),
257
+ metadata
258
+ };
259
+ }
260
+ function normalizeVirtualSettlementProducts(products) {
261
+ return (products || []).map(product => normalizeVirtualSettlementOrderProduct(product));
262
+ }
@@ -232,6 +232,7 @@ export declare function buildSubmitPayload(params: {
232
232
  type?: string;
233
233
  summary?: OrderSummary | null;
234
234
  request_unique_idempotency_token?: string;
235
+ includePaymentStatus?: boolean;
235
236
  enhance?: SubmitPayloadEnhancer;
236
237
  }): OrderSubmitPayload;
237
238
  export declare function mapPaymentItemToOrderPayment(paymentItem: OrderPaymentSource): OrderPaymentData;
@@ -864,7 +864,7 @@ function normalizeSubmitProductionCode(value) {
864
864
  }
865
865
 
866
866
  // 后端 checkout 协议字段 option_group_item_id;tempOrder 内部也保持同一字段名。
867
- function formatSubmitOptionItems(options) {
867
+ function formatSubmitOptionItems(options, formatOptions = {}) {
868
868
  if (!Array.isArray(options)) return [];
869
869
  return options.map(d => {
870
870
  const option = {
@@ -877,7 +877,11 @@ function formatSubmitOptionItems(options) {
877
877
  delete option.production_code;
878
878
  if (productionCode !== undefined) option.production_code = productionCode;
879
879
  const addPrice = d?.add_price ?? d?.price;
880
- if (addPrice !== undefined) option.add_price = String(addPrice);
880
+ if (formatOptions.virtualSettlementMode) {
881
+ option.add_price = 0;
882
+ } else if (addPrice !== undefined) {
883
+ option.add_price = String(addPrice);
884
+ }
881
885
  delete option.price;
882
886
  return option;
883
887
  });
@@ -894,7 +898,7 @@ function toMoneyString(value) {
894
898
  }
895
899
 
896
900
  // 出站补齐:只输出后端 checkout 协议字段,运行时/详情展示字段不进入 bundle payload。
897
- function formatSubmitBundleItems(bundle) {
901
+ function formatSubmitBundleItems(bundle, formatOptions = {}) {
898
902
  if (!Array.isArray(bundle)) return [];
899
903
  return bundle.map(b => {
900
904
  const rawBundle = b && typeof b === 'object' ? b : {};
@@ -906,10 +910,10 @@ function formatSubmitBundleItems(bundle) {
906
910
 
907
911
  // bundle_selling_price 出站存「正净额」:markdown 为 |price| − Σoptions(如 3.70),
908
912
  // markup/原价维持原值;与后端口径一致(price 仍为毛价)。
909
- const sellingPrice = getBundleSellingMagnitude(rawBundle).toFixed(2);
913
+ const sellingPrice = formatOptions.virtualSettlementMode ? '0.00' : getBundleSellingMagnitude(rawBundle).toFixed(2);
910
914
  // payment 价由整单折扣均摊层产出;缺省(无折扣)时与 selling 净额同义。
911
- const paymentPrice = rawBundle.bundle_payment_price !== undefined && rawBundle.bundle_payment_price !== null && rawBundle.bundle_payment_price !== '' ? toMoneyString(rawBundle.bundle_payment_price) : sellingPrice;
912
- const priceValue = rawBundle.price ?? rawBundle.custom_price ?? rawBundle.bundle_selling_price;
915
+ const paymentPrice = formatOptions.virtualSettlementMode ? '0.00' : rawBundle.bundle_payment_price !== undefined && rawBundle.bundle_payment_price !== null && rawBundle.bundle_payment_price !== '' ? toMoneyString(rawBundle.bundle_payment_price) : sellingPrice;
916
+ const priceValue = formatOptions.virtualSettlementMode ? 0 : rawBundle.price ?? rawBundle.custom_price ?? rawBundle.bundle_selling_price;
913
917
  const relationSurchargeIds = Array.isArray(rawBundle.relation_surcharge_ids) ? rawBundle.relation_surcharge_ids : Array.isArray(existedMetadata.relation_surcharge_ids) ? existedMetadata.relation_surcharge_ids : [];
914
918
  const surchargeFee = toMoneyString(rawBundle.surcharge_fee ?? existedMetadata.surcharge_fee);
915
919
  const productDiscountDifference = toBundleNumber(existedMetadata.product_discount_difference, 0);
@@ -918,7 +922,7 @@ function formatSubmitBundleItems(bundle) {
918
922
  const hasSubmitBundleDiscounts = Array.isArray(rawBundle.discount_list) && rawBundle.discount_list.length > 0;
919
923
  const productionCode = normalizeSubmitProductionCode(rawBundle.production_code);
920
924
  return {
921
- is_charge_tax: rawBundle.is_charge_tax ?? 0,
925
+ is_charge_tax: formatOptions.virtualSettlementMode ? 0 : rawBundle.is_charge_tax ?? 0,
922
926
  bundle_variant_id: rawBundle.bundle_variant_id ?? 0,
923
927
  ...(productionCode !== undefined ? {
924
928
  production_code: productionCode
@@ -932,7 +936,7 @@ function formatSubmitBundleItems(bundle) {
932
936
  price_type_ext: rawBundle.price_type_ext ?? rawBundle.custom_price_type_ext ?? '',
933
937
  bundle_selling_price: sellingPrice,
934
938
  bundle_payment_price: paymentPrice,
935
- option: formatSubmitOptionItems(rawBundle.option),
939
+ option: formatSubmitOptionItems(rawBundle.option, formatOptions),
936
940
  bundle_group_id: rawBundle?.bundle_group_id ?? rawBundle?.group_id,
937
941
  bundle_id: rawBundle?.bundle_id ?? rawBundle?.id,
938
942
  bundle_product_id: rawBundle?.bundle_product_id ?? rawBundle?._bundle_product_id,
@@ -942,9 +946,9 @@ function formatSubmitBundleItems(bundle) {
942
946
  ...(hasSubmitBundleDiscounts && bundleMapId !== undefined ? {
943
947
  custom_product_bundle_map_id: bundleMapId
944
948
  } : {}),
945
- surcharge_fee: surchargeFee,
946
- relation_surcharge_ids: relationSurchargeIds,
947
- product_discount_difference: productDiscountDifference
949
+ surcharge_fee: formatOptions.virtualSettlementMode ? '0.00' : surchargeFee,
950
+ relation_surcharge_ids: formatOptions.virtualSettlementMode ? [] : relationSurchargeIds,
951
+ product_discount_difference: formatOptions.virtualSettlementMode ? '' : productDiscountDifference
948
952
  }
949
953
  };
950
954
  });
@@ -964,9 +968,9 @@ function formatSubmitBundleItems(bundle) {
964
968
  * - `metadata.main_product_selling_price`:含 option、含主商品折扣。
965
969
  * - `metadata.price_schema_version`:schema 版本号(当前 = 2),用于跨端协商价格口径。
966
970
  *
967
- * 本函数不再改造价格字段形状,仅做字段/metadata 裁剪。
971
+ * 法币仅做字段/metadata 裁剪;虚拟币在出站前再次执行零加价与固定单价断言。
968
972
  */
969
- function normalizeSubmitProduct(product) {
973
+ function normalizeSubmitProduct(product, formatOptions = {}) {
970
974
  const {
971
975
  unique_identification_number: _runtimeUid,
972
976
  ...submitProduct
@@ -994,7 +998,7 @@ function normalizeSubmitProduct(product) {
994
998
  if (rawMetadata.unique_identification_number) {
995
999
  cleanMetadata.unique_identification_number = rawMetadata.unique_identification_number;
996
1000
  }
997
- const priceMetaKeys = ['main_product_original_price', 'main_product_selling_price', 'main_product_attached_bundle_selling_price', 'main_product_attached_bundle_payment_price', 'average_discount_amount_rate', 'source_product_price', 'main_product_attached_bundle_surcharge_fee', 'main_product_attached_bundle_tax_fee', 'surcharge_rounding_remainder', 'tax_fee_rounding_remainder', 'relation_surcharge_ids', 'discountable_flag', 'parent_unique_identification_number', 'product_add_schedule_time'];
1001
+ const priceMetaKeys = ['main_product_original_price', 'main_product_selling_price', 'main_product_attached_bundle_selling_price', 'main_product_attached_bundle_payment_price', 'average_discount_amount_rate', 'source_product_price', 'main_product_attached_bundle_surcharge_fee', 'main_product_attached_bundle_tax_fee', 'surcharge_rounding_remainder', 'tax_fee_rounding_remainder', 'relation_surcharge_ids', 'discountable_flag', 'price_schema_version', 'parent_unique_identification_number', 'product_add_schedule_time', 'data_variant_ids'];
998
1002
  for (const key of priceMetaKeys) {
999
1003
  if (rawMetadata[key] !== undefined) {
1000
1004
  cleanMetadata[key] = rawMetadata[key];
@@ -1010,12 +1014,36 @@ function normalizeSubmitProduct(product) {
1010
1014
  if (rawMetadata.holder_config !== undefined) {
1011
1015
  cleanMetadata.holder_config = rawMetadata.holder_config;
1012
1016
  }
1017
+ const virtualPrice = toMoneyString(rawMetadata.selected_settlement_snapshot?.price ?? submitProduct.selling_price);
1018
+ if (formatOptions.virtualSettlementMode) {
1019
+ Object.assign(cleanMetadata, {
1020
+ source_product_price: virtualPrice,
1021
+ main_product_original_price: virtualPrice,
1022
+ main_product_selling_price: virtualPrice,
1023
+ main_product_attached_bundle_selling_price: virtualPrice,
1024
+ main_product_attached_bundle_payment_price: virtualPrice,
1025
+ main_product_attached_bundle_surcharge_fee: '0.00',
1026
+ main_product_attached_bundle_tax_fee: '0.00',
1027
+ surcharge_rounding_remainder: '0.00',
1028
+ tax_fee_rounding_remainder: '0.00',
1029
+ relation_surcharge_ids: [],
1030
+ average_discount_amount_rate: '1',
1031
+ product_discount_difference: '',
1032
+ discountable_flag: 0,
1033
+ price_schema_version: 2
1034
+ });
1035
+ }
1013
1036
  const productSku = {
1014
1037
  ...(submitProduct.product_sku && typeof submitProduct.product_sku === 'object' ? submitProduct.product_sku : {}),
1015
- option: formatSubmitOptionItems(submitProduct.product_sku?.option)
1038
+ option: formatSubmitOptionItems(submitProduct.product_sku?.option, formatOptions)
1016
1039
  };
1017
1040
  return {
1018
1041
  ...productRest,
1042
+ ...(formatOptions.virtualSettlementMode ? {
1043
+ selling_price: virtualPrice,
1044
+ original_price: virtualPrice,
1045
+ is_charge_tax: 0
1046
+ } : {}),
1019
1047
  ...(productionCode !== undefined ? {
1020
1048
  production_code: productionCode
1021
1049
  } : {}),
@@ -1027,12 +1055,12 @@ function normalizeSubmitProduct(product) {
1027
1055
  } : {}),
1028
1056
  product_quantity: toBundleNumber(num ?? submitProduct.product_quantity, 1),
1029
1057
  product_sku: productSku,
1030
- discount_list: collectSubmitProductDiscountList(submitProduct),
1031
- product_bundle: formatSubmitBundleItems(submitProduct.product_bundle),
1058
+ discount_list: formatOptions.virtualSettlementMode ? [] : collectSubmitProductDiscountList(submitProduct),
1059
+ product_bundle: formatSubmitBundleItems(submitProduct.product_bundle, formatOptions),
1032
1060
  metadata: cleanMetadata,
1033
1061
  // 出站兼容:后端消费 payment_price 字段(行 composite 已减整单折扣均摊)。
1034
1062
  // 由整单折扣均摊层产出;缺省(无折扣)时与 selling_price 同义。
1035
- payment_price: submitProduct.payment_price ?? submitProduct.selling_price
1063
+ payment_price: formatOptions.virtualSettlementMode ? virtualPrice : submitProduct.payment_price ?? submitProduct.selling_price
1036
1064
  };
1037
1065
  }
1038
1066
  const SUBMIT_BOOKING_METADATA_WHITELIST = ['unique_identification_number', 'collect_pax', 'capacity', 'holder_id', 'resource_select_type', 'holder'];
@@ -1205,6 +1233,7 @@ function buildSubmitPayload(params) {
1205
1233
  } = params;
1206
1234
  const scheduleDate = tempOrder.schedule_date || tempOrder.created_at || formatDateTime(now);
1207
1235
  const bookingUuid = (0, _orderCollectionIdentity.createUuidV4)();
1236
+ const virtualSettlementMode = tempOrder.metadata?.currency_settlement_config?.settlement_type === 'virtual_currency';
1208
1237
  const {
1209
1238
  _extend: _extend,
1210
1239
  relation_id: _relationId,
@@ -1224,6 +1253,7 @@ function buildSubmitPayload(params) {
1224
1253
  total_refund_amount: _totalRefundAmount,
1225
1254
  create_date: _createDate,
1226
1255
  holder_id: _holderId,
1256
+ payment_status: _paymentStatus,
1227
1257
  notes: _notes,
1228
1258
  ...tempOrderRest
1229
1259
  } = tempOrder;
@@ -1253,7 +1283,9 @@ function buildSubmitPayload(params) {
1253
1283
  sales_channel: tempOrder.sales_channel || 'my_pisel',
1254
1284
  order_sales_channel: channel ?? tempOrder.order_sales_channel ?? 'online_store',
1255
1285
  status: tempOrder.status || 'normal',
1256
- payment_status: tempOrder.payment_status || 'payment_processing',
1286
+ ...(params.includePaymentStatus !== false ? {
1287
+ payment_status: tempOrder.payment_status || 'payment_processing'
1288
+ } : {}),
1257
1289
  // shipping_status: tempOrder.shipping_status || 'unfulfilled',
1258
1290
  is_price_include_tax: tempOrder.is_price_include_tax ?? 1,
1259
1291
  currency_format: tempOrder.currency_format || 'symbol_first',
@@ -1276,6 +1308,9 @@ function buildSubmitPayload(params) {
1276
1308
  const {
1277
1309
  collect_pax: _collectPax,
1278
1310
  table_occupancy_duration: _tableOccupancyDuration,
1311
+ cart_settlement_key: _cartSettlementKey,
1312
+ cart_settlement_snapshot: _cartSettlementSnapshot,
1313
+ legal_currency_snapshot: _legalCurrencySnapshot,
1279
1314
  ...rest
1280
1315
  } = tempOrder.metadata || {};
1281
1316
  return {
@@ -1287,7 +1322,9 @@ function buildSubmitPayload(params) {
1287
1322
  allowUnresolvedOrderTarget: true
1288
1323
  })
1289
1324
  } : {}),
1290
- products: (tempOrder.products || []).map(product => normalizeSubmitProduct(product))
1325
+ products: (tempOrder.products || []).map(product => normalizeSubmitProduct(product, {
1326
+ virtualSettlementMode
1327
+ }))
1291
1328
  };
1292
1329
  if (!enhance) return payload;
1293
1330
  const enhancedPayload = enhance(payload, {