@pisell/pisellos 2.2.180 → 2.2.182

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 (175) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  2. package/dist/modules/BookingContext/index.d.ts +37 -0
  3. package/dist/modules/BookingContext/index.js +436 -0
  4. package/dist/modules/BookingContext/types.d.ts +102 -0
  5. package/dist/modules/BookingContext/types.js +51 -0
  6. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  7. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +276 -0
  8. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  9. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +137 -0
  10. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +75 -0
  11. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +215 -0
  12. package/dist/modules/BookingContext/utils/flexible.d.ts +28 -0
  13. package/dist/modules/BookingContext/utils/flexible.js +56 -0
  14. package/dist/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  15. package/dist/modules/BookingContext/utils/formatResourceList.js +38 -0
  16. package/dist/modules/BookingContext/utils/index.d.ts +11 -0
  17. package/dist/modules/BookingContext/utils/index.js +11 -0
  18. package/dist/modules/BookingContext/utils/noResource.d.ts +13 -0
  19. package/dist/modules/BookingContext/utils/noResource.js +77 -0
  20. package/dist/modules/BookingContext/utils/productExtend.d.ts +72 -0
  21. package/dist/modules/BookingContext/utils/productExtend.js +339 -0
  22. package/dist/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  23. package/dist/modules/BookingContext/utils/resourceErrors.js +74 -0
  24. package/dist/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  25. package/dist/modules/BookingContext/utils/resourceSelection.js +24 -0
  26. package/dist/modules/BookingContext/utils/resources.d.ts +80 -0
  27. package/dist/modules/BookingContext/utils/resources.js +486 -0
  28. package/dist/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  29. package/dist/modules/BookingContext/utils/serviceTimes.js +151 -0
  30. package/dist/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  31. package/dist/modules/BookingContext/utils/timeSlices.js +100 -0
  32. package/dist/modules/Customer/index.d.ts +6 -0
  33. package/dist/modules/Customer/index.js +129 -83
  34. package/dist/modules/Customer/types.d.ts +2 -0
  35. package/dist/modules/Discount/index.js +4 -3
  36. package/dist/modules/Discount/types.d.ts +1 -0
  37. package/dist/modules/Order/index.d.ts +101 -10
  38. package/dist/modules/Order/index.js +1444 -490
  39. package/dist/modules/Order/types.d.ts +201 -18
  40. package/dist/modules/Order/types.js +31 -0
  41. package/dist/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  42. package/dist/modules/Order/utils/manualProductDiscount.js +210 -0
  43. package/dist/modules/Order/utils.d.ts +83 -1
  44. package/dist/modules/Order/utils.js +405 -61
  45. package/dist/modules/Product/index.d.ts +1 -1
  46. package/dist/modules/Quotation/index.d.ts +0 -1
  47. package/dist/modules/Quotation/index.js +23 -21
  48. package/dist/modules/Rules/index.d.ts +4 -0
  49. package/dist/modules/Rules/index.js +43 -39
  50. package/dist/modules/Rules/types.d.ts +1 -0
  51. package/dist/modules/SalesSummary/index.js +4 -2
  52. package/dist/modules/SalesSummary/utils.js +21 -7
  53. package/dist/modules/Schedule/index.js +6 -2
  54. package/dist/modules/index.d.ts +1 -0
  55. package/dist/modules/index.js +2 -1
  56. package/dist/server/index.js +87 -29
  57. package/dist/server/modules/order/index.d.ts +23 -0
  58. package/dist/server/modules/order/index.js +123 -46
  59. package/dist/server/modules/order/utils/filterOrders.js +20 -6
  60. package/dist/server/modules/products/index.d.ts +1 -1
  61. package/dist/server/modules/products/index.js +130 -113
  62. package/dist/server/modules/schedule/index.js +13 -6
  63. package/dist/solution/BaseSales/index.d.ts +89 -7
  64. package/dist/solution/BaseSales/index.js +1489 -366
  65. package/dist/solution/BaseSales/types.d.ts +67 -1
  66. package/dist/solution/BaseSales/types.js +3 -1
  67. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +275 -0
  68. package/dist/solution/BaseSales/utils/cartPromotion.js +1258 -0
  69. package/dist/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
  70. package/dist/solution/BaseSales/utils/quotationPrice.js +237 -0
  71. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +68 -16
  72. package/dist/solution/BaseSales/utils.js +46 -8
  73. package/dist/solution/BookingByStep/index.d.ts +1 -1
  74. package/dist/solution/BookingTicket/index.d.ts +152 -2
  75. package/dist/solution/BookingTicket/index.js +848 -184
  76. package/dist/solution/BookingTicket/types.d.ts +2 -0
  77. package/dist/solution/BookingTicket/types.js +3 -0
  78. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +113 -0
  79. package/dist/solution/BookingTicket/utils/addProductDecision.js +346 -0
  80. package/dist/solution/BookingTicket/utils/cartView.js +4 -2
  81. package/dist/solution/ScanOrder/index.d.ts +9 -3
  82. package/dist/solution/ScanOrder/index.js +231 -128
  83. package/dist/solution/ScanOrder/utils.js +46 -8
  84. package/dist/solution/VenueBooking/index.d.ts +5 -2
  85. package/dist/solution/VenueBooking/index.js +103 -55
  86. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
  87. package/dist/solution/VenueBooking/utils/slotMerge.js +10 -0
  88. package/lib/model/strategy/adapter/promotion/index.js +49 -0
  89. package/lib/modules/BookingContext/index.d.ts +37 -0
  90. package/lib/modules/BookingContext/index.js +297 -0
  91. package/lib/modules/BookingContext/types.d.ts +102 -0
  92. package/lib/modules/BookingContext/types.js +34 -0
  93. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  94. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +271 -0
  95. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  96. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +141 -0
  97. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +75 -0
  98. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +198 -0
  99. package/lib/modules/BookingContext/utils/flexible.d.ts +28 -0
  100. package/lib/modules/BookingContext/utils/flexible.js +80 -0
  101. package/lib/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  102. package/lib/modules/BookingContext/utils/formatResourceList.js +50 -0
  103. package/lib/modules/BookingContext/utils/index.d.ts +11 -0
  104. package/lib/modules/BookingContext/utils/index.js +43 -0
  105. package/lib/modules/BookingContext/utils/noResource.d.ts +13 -0
  106. package/lib/modules/BookingContext/utils/noResource.js +90 -0
  107. package/lib/modules/BookingContext/utils/productExtend.d.ts +72 -0
  108. package/lib/modules/BookingContext/utils/productExtend.js +283 -0
  109. package/lib/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  110. package/lib/modules/BookingContext/utils/resourceErrors.js +80 -0
  111. package/lib/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  112. package/lib/modules/BookingContext/utils/resourceSelection.js +46 -0
  113. package/lib/modules/BookingContext/utils/resources.d.ts +80 -0
  114. package/lib/modules/BookingContext/utils/resources.js +377 -0
  115. package/lib/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  116. package/lib/modules/BookingContext/utils/serviceTimes.js +162 -0
  117. package/lib/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  118. package/lib/modules/BookingContext/utils/timeSlices.js +124 -0
  119. package/lib/modules/Customer/index.d.ts +6 -0
  120. package/lib/modules/Customer/index.js +26 -11
  121. package/lib/modules/Customer/types.d.ts +2 -0
  122. package/lib/modules/Discount/index.js +5 -1
  123. package/lib/modules/Discount/types.d.ts +1 -0
  124. package/lib/modules/Order/index.d.ts +101 -10
  125. package/lib/modules/Order/index.js +751 -114
  126. package/lib/modules/Order/types.d.ts +201 -18
  127. package/lib/modules/Order/types.js +1 -0
  128. package/lib/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  129. package/lib/modules/Order/utils/manualProductDiscount.js +206 -0
  130. package/lib/modules/Order/utils.d.ts +83 -1
  131. package/lib/modules/Order/utils.js +340 -22
  132. package/lib/modules/Product/index.d.ts +1 -1
  133. package/lib/modules/Quotation/index.d.ts +0 -1
  134. package/lib/modules/Quotation/index.js +18 -15
  135. package/lib/modules/Rules/index.d.ts +4 -0
  136. package/lib/modules/Rules/index.js +26 -27
  137. package/lib/modules/Rules/types.d.ts +1 -0
  138. package/lib/modules/SalesSummary/index.js +4 -2
  139. package/lib/modules/SalesSummary/utils.js +21 -7
  140. package/lib/modules/Schedule/index.js +3 -1
  141. package/lib/modules/index.d.ts +1 -0
  142. package/lib/modules/index.js +3 -1
  143. package/lib/server/index.js +41 -4
  144. package/lib/server/modules/order/index.d.ts +23 -0
  145. package/lib/server/modules/order/index.js +46 -14
  146. package/lib/server/modules/order/utils/filterOrders.js +12 -4
  147. package/lib/server/modules/products/index.d.ts +1 -1
  148. package/lib/server/modules/products/index.js +30 -20
  149. package/lib/server/modules/schedule/index.js +2 -1
  150. package/lib/solution/BaseSales/index.d.ts +89 -7
  151. package/lib/solution/BaseSales/index.js +742 -23
  152. package/lib/solution/BaseSales/types.d.ts +67 -1
  153. package/lib/solution/BaseSales/types.js +3 -1
  154. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +275 -0
  155. package/lib/solution/BaseSales/utils/cartPromotion.js +836 -0
  156. package/lib/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
  157. package/lib/solution/BaseSales/utils/quotationPrice.js +277 -0
  158. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +71 -12
  159. package/lib/solution/BaseSales/utils.js +46 -6
  160. package/lib/solution/BookingByStep/index.d.ts +1 -1
  161. package/lib/solution/BookingTicket/index.d.ts +152 -2
  162. package/lib/solution/BookingTicket/index.js +389 -9
  163. package/lib/solution/BookingTicket/types.d.ts +2 -0
  164. package/lib/solution/BookingTicket/types.js +6 -0
  165. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +113 -0
  166. package/lib/solution/BookingTicket/utils/addProductDecision.js +318 -0
  167. package/lib/solution/BookingTicket/utils/cartView.js +4 -2
  168. package/lib/solution/ScanOrder/index.d.ts +9 -3
  169. package/lib/solution/ScanOrder/index.js +147 -66
  170. package/lib/solution/ScanOrder/utils.js +46 -6
  171. package/lib/solution/VenueBooking/index.d.ts +5 -2
  172. package/lib/solution/VenueBooking/index.js +50 -14
  173. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
  174. package/lib/solution/VenueBooking/utils/slotMerge.js +10 -0
  175. package/package.json +1 -1
@@ -2,15 +2,117 @@ import { CartItem } from '../Cart/types';
2
2
  import type { DiscountModule } from '../Discount';
3
3
  import type { RulesModule } from '../Rules';
4
4
  import type { Discount } from '../Discount/types';
5
+ import type { UnavailableReason } from '../Rules/types';
5
6
  import type { SubmitPayloadEnhancer } from './utils';
6
7
  import type { PaymentItem } from '../Payment/types';
7
8
  import type { ICustomer } from '../AccountList/types';
9
+ import type { OrderProductDiscountItem } from '../../server/modules/order/types';
10
+ export type { OrderProductDiscountItem } from '../../server/modules/order/types';
8
11
  export declare enum OrderHooks {
9
12
  OnOrderCreate = "order:onOrderCreate",
10
13
  OnOrderUpdate = "order:onOrderUpdate",
11
14
  OnOrderCancel = "order:onOrderCancel",
12
15
  OnOrderStatusChange = "order:onOrderStatusChange",
13
- OnOrderCustomerChange = "order:onOrderCustomerChange"
16
+ OnOrderCustomerChange = "order:onOrderCustomerChange",
17
+ OnPromotionApplied = "order:onPromotionApplied"
18
+ }
19
+ /**
20
+ * 促销评估器协议(OS 与 PromotionEvaluator 之间的桥接接口)。
21
+ *
22
+ * 与 `pisell_os/src/model/strategy/adapter/promotion/evaluator.ts` 中的
23
+ * `PromotionEvaluator` 实例结构保持兼容。SalesSdkProvider 会从 `appHelper.utils.promotionEvaluator`
24
+ * 读取实例并通过 `setPromotionEvaluator` 注入到 OrderModule。
25
+ *
26
+ * 这里只声明 OrderModule 需要调用的子集,避免反向依赖具体 evaluator 实现。
27
+ */
28
+ export interface OrderPromotionEvaluator {
29
+ evaluateCartWithPricing(input: {
30
+ products: any[];
31
+ channel?: string;
32
+ }): any;
33
+ getProductsApplicableStrategies(input: {
34
+ products: any[];
35
+ channel?: string;
36
+ }, matchVariant?: boolean): any[];
37
+ }
38
+ /** 赠品解析回调 context(OS → SDK 的请求体) */
39
+ export interface OrderGiftSelectContext {
40
+ strategyId: string;
41
+ strategyName: string | Record<string, string>;
42
+ giftCount: number;
43
+ giftOptions: Array<{
44
+ product_id: number;
45
+ product_variant_id: number;
46
+ }>;
47
+ /** 触发此赠品的主商品 metadata.unique_identification_number 列表 */
48
+ sourceProductIds: string[];
49
+ }
50
+ /**
51
+ * 赠品解析回调签名(SDK → OS 的返回值)。
52
+ *
53
+ * - 单选项:SDK 内部自动构造商品,不弹窗
54
+ * - 多选项:SDK 弹窗等用户确认后构造
55
+ * - 用户取消:抛错或返回空数组(OS 视为放弃本次添加)
56
+ *
57
+ * 返回的 OrderProduct 必须是完整的购物车行(含 metadata._giftInfo 标记),OS 会直接 push 入 tempOrder.products。
58
+ */
59
+ export type OrderGiftSelectResolver = (ctx: OrderGiftSelectContext) => Promise<Partial<OrderProduct>[] | null>;
60
+ /** 未满足的促销策略(购物车底部 alert 渲染源) */
61
+ export interface OrderUnfulfilledPromotion {
62
+ strategyId: string;
63
+ strategyName: string | Record<string, string>;
64
+ actionType: string;
65
+ needQuantity: number;
66
+ currentQuantity: number;
67
+ requiredQuantity: number;
68
+ eligibleProducts: Array<{
69
+ product_id: number;
70
+ product_variant_id: number;
71
+ }>;
72
+ strategyMetadata?: any;
73
+ display?: {
74
+ text: string | Record<string, string>;
75
+ type: string;
76
+ };
77
+ }
78
+ /** 上一次 applyPromotion 计算出的赠品操作(仅供调试/读取使用) */
79
+ export interface OrderLastGiftActions {
80
+ toAdd: Array<{
81
+ strategyId: string;
82
+ strategyName: string | Record<string, string>;
83
+ giftCount: number;
84
+ giftOptions: Array<{
85
+ product_id: number;
86
+ product_variant_id: number;
87
+ }>;
88
+ sourceProductIds: string[];
89
+ }>;
90
+ toReduce: Array<{
91
+ strategyId: string;
92
+ items: Array<{
93
+ uid: string;
94
+ currentQuantity: number;
95
+ newQuantity: number;
96
+ }>;
97
+ }>;
98
+ toRemove: string[];
99
+ }
100
+ /** onPromotionApplied 事件 payload */
101
+ export interface OrderPromotionAppliedPayload {
102
+ unfulfilledPromotions: OrderUnfulfilledPromotion[];
103
+ giftActions: OrderLastGiftActions;
104
+ /** evaluator 返回的赠品摘要 */
105
+ gifts: Array<{
106
+ strategyId: string;
107
+ strategyName: string | Record<string, string>;
108
+ giftCount: number;
109
+ giftOptions: Array<{
110
+ product_id: number;
111
+ product_variant_id: number;
112
+ }>;
113
+ }>;
114
+ /** 处理后的商品列表 */
115
+ products: OrderProduct[];
14
116
  }
15
117
  /**
16
118
  * tempOrder 上的下单客户协议字段视图。
@@ -48,6 +150,13 @@ export interface OrderCustomerChangePayload {
48
150
  patch: OrderCustomerView;
49
151
  snapshot: ICustomer | null;
50
152
  }
153
+ export interface OrderScanCodeResult {
154
+ isAvailable: boolean;
155
+ discountList: Discount[];
156
+ scannedDiscountList: Discount[];
157
+ type: 'server' | 'clientCalc';
158
+ unavailableReason?: UnavailableReason;
159
+ }
51
160
  export interface OrderProductIdentity {
52
161
  product_id: number | null;
53
162
  product_variant_id: number;
@@ -66,7 +175,7 @@ export interface OrderProduct extends OrderProductIdentity {
66
175
  original_price: string;
67
176
  tax_fee: string;
68
177
  is_charge_tax: number;
69
- discount_list: any[];
178
+ discount_list: OrderProductDiscountItem[];
70
179
  product_bundle: any[];
71
180
  booking_uid?: string;
72
181
  metadata: Record<string, any>;
@@ -103,11 +212,11 @@ export interface OrderSummary {
103
212
  export interface OrderTempOrder {
104
213
  order_id: number | null;
105
214
  external_sale_number: string;
106
- order_number: string;
107
- shop_order_number: string;
108
- shop_full_order_number: string;
215
+ order_number: string | null;
216
+ shop_order_number: string | null;
217
+ shop_full_order_number: string | null;
109
218
  type: string;
110
- business_code: string;
219
+ business_code?: string;
111
220
  platform: string;
112
221
  sales_channel: string;
113
222
  order_sales_channel: string;
@@ -142,7 +251,7 @@ export interface OrderTempOrder {
142
251
  bookings: any[];
143
252
  payments: any[];
144
253
  surcharges: any[];
145
- discount_list: any[];
254
+ discount_list?: any[];
146
255
  relation_forms: any[];
147
256
  contacts: any[];
148
257
  contacts_info: Record<string, any> | null;
@@ -158,7 +267,7 @@ export interface OrderSubmitProduct extends Omit<OrderProduct, 'unique_identific
158
267
  payment_price: string;
159
268
  product_sku: Record<string, any>;
160
269
  }
161
- export interface OrderSubmitPayload extends Omit<OrderTempOrder, 'platform' | 'products' | '_extend' | 'customer' | 'shop_full_order_number'> {
270
+ export interface OrderSubmitPayload extends Omit<OrderTempOrder, 'platform' | 'products' | '_extend' | 'customer' | 'discount_list'> {
162
271
  platform: string;
163
272
  request_unique_idempotency_token?: string;
164
273
  form_record_ids?: Array<{
@@ -177,16 +286,32 @@ export interface OrderState {
177
286
  discount: DiscountModule | null;
178
287
  rules: RulesModule | null;
179
288
  }
289
+ export interface ReplaceTempOrderOptions {
290
+ recalculateSummary?: boolean;
291
+ persist?: boolean;
292
+ saveDraft?: boolean;
293
+ }
294
+ export type AddProductBookingInput = Record<string, any>;
180
295
  /** 更新购物车行:仅传 SKU 时命中同 SKU 第一行;多行同 SKU 须传 unique_identification_number / 选项指纹等 */
181
- export interface UpdateProductInOrderParams {
296
+ export interface UpdateOrderProductParams {
182
297
  product_id: number | null;
183
298
  product_variant_id: number;
184
299
  updates: Partial<OrderProduct>;
185
300
  unique_identification_number?: string;
301
+ identity_key?: string;
186
302
  product_option_item?: any[];
187
303
  product_bundle?: any[];
304
+ booking?: AddProductBookingInput;
305
+ }
306
+ /** 仅更新购物车行数量;行定位语义与 updateOrderProduct / removeProductFromOrder 保持一致 */
307
+ export interface UpdateOrderProductQuantityParams extends OrderProductIdentity {
308
+ num: number;
309
+ identity_key?: string;
310
+ }
311
+ export interface UpdateOrderBookingParams {
312
+ unique_identification_number: string;
313
+ updates: AddProductBookingInput;
188
314
  }
189
- export type AddProductBookingInput = Record<string, any>;
190
315
  export interface OrderProductMergeDecisionContext {
191
316
  incomingProduct: Partial<OrderProduct> & OrderProductIdentity;
192
317
  normalizedIncoming: OrderProduct;
@@ -237,10 +362,11 @@ export interface SubmitSalesOrderParams {
237
362
  query: {
238
363
  order_id: number | null;
239
364
  external_sale_number: string;
240
- order_number: string;
241
- shop_order_number: string;
365
+ order_number: string | null;
366
+ shop_order_number: string | null;
367
+ shop_full_order_number: string | null;
242
368
  type: string;
243
- business_code: string;
369
+ business_code?: string;
244
370
  platform: string;
245
371
  request_unique_idempotency_token?: string;
246
372
  sales_channel: string;
@@ -272,7 +398,6 @@ export interface SubmitSalesOrderParams {
272
398
  bookings: OrderSubmitBooking[];
273
399
  payments: any[];
274
400
  surcharges?: any[];
275
- discount_list: any[];
276
401
  relation_forms: any[];
277
402
  form_record_ids?: OrderSubmitFormRecord[];
278
403
  contacts: any[];
@@ -351,6 +476,7 @@ export interface SyncPaymentsToOrderParams {
351
476
  paymentStatus?: SubmitSalesOrderParams['query']['payment_status'];
352
477
  submitWhenPaid?: boolean;
353
478
  smallTicketDataFlag?: number;
479
+ channel?: string;
354
480
  }
355
481
  export interface SyncPaymentsToOrderResult<T = any> {
356
482
  isFullyPaid: boolean;
@@ -447,6 +573,7 @@ export interface OrderModuleAPI {
447
573
  }) => void;
448
574
  getTempOrder: () => OrderTempOrder | null;
449
575
  ensureTempOrder: () => OrderTempOrder;
576
+ replaceTempOrder: (tempOrder: OrderTempOrder, options?: ReplaceTempOrderOptions) => Promise<OrderTempOrder>;
450
577
  addNewOrder: () => Promise<OrderTempOrder>;
451
578
  restoreOrder: () => OrderTempOrder;
452
579
  getOrderProducts: () => OrderProduct[];
@@ -459,15 +586,29 @@ export interface OrderModuleAPI {
459
586
  getOrderSyncState: () => OrderSyncState;
460
587
  getOrderAmountSnapshot: () => OrderAmountSnapshot | null;
461
588
  getTempOrderNote: () => string;
462
- updateTempOrderNote: (note: string) => string;
589
+ updateTempOrderNote: {
590
+ (note: string): string;
591
+ (note: string, sync: true): Promise<string>;
592
+ (note: string, sync: boolean): string | Promise<string>;
593
+ };
463
594
  updateTempOrderShopDiscount: (amount: string | number) => string;
464
595
  updateTempOrderCustomer: (customer: UpdateTempOrderCustomerInput) => OrderSnapshot['customer'];
465
596
  updateTempOrderBuzzer: (buzzer: string) => string;
466
597
  updateTempOrderContactsInfo: (contactsInfo: Record<string, any> | null) => Record<string, any> | null;
467
598
  addProductToOrder: (product: Partial<OrderProduct> & OrderProductIdentity, booking?: AddProductBookingInput) => Promise<OrderProduct[]>;
468
- updateProductInOrder: (params: UpdateProductInOrderParams) => Promise<OrderProduct[]>;
599
+ updateOrderProduct: (params: UpdateOrderProductParams) => Promise<OrderProduct[]>;
600
+ updateOrderProductQuantity: (params: UpdateOrderProductQuantityParams) => Promise<OrderProduct[]>;
601
+ updateOrderBooking: (params: UpdateOrderBookingParams) => any[];
469
602
  removeProductFromOrder: (identity: OrderProductIdentity) => Promise<OrderProduct[]>;
603
+ /** @deprecated no-op;OrderModule 不再负责 tempOrder localStorage 持久化。 */
470
604
  persistTempOrder: () => void;
605
+ /**
606
+ * 控制 IndexedDB 草稿(saveDraft)开关;localStorage tempOrder 持久化已废弃。
607
+ * BigSale 弹窗等场景传 false 可跳过 saveDraft。
608
+ */
609
+ setEnableTempOrderPersist: (enabled: boolean) => void;
610
+ /** 是否允许 saveDraft 写入 IndexedDB 草稿。 */
611
+ isTempOrderPersistEnabled: () => boolean;
471
612
  submitTempOrder: <T = any>(params?: {
472
613
  cacheId?: string;
473
614
  platform?: string;
@@ -517,10 +658,52 @@ export interface OrderModuleAPI {
517
658
  clearOrderCustomer: () => void;
518
659
  loadDiscountConfig: (params: {
519
660
  customerId: number;
520
- action?: 'create';
521
- }) => Promise<void>;
661
+ action?: 'create' | 'edit';
662
+ orderId?: number;
663
+ apply?: boolean;
664
+ }) => Promise<Discount[]>;
522
665
  getDiscountList: () => Discount[];
523
666
  applyDiscount: () => void;
667
+ /**
668
+ * 注入促销评估器。
669
+ *
670
+ * SalesSdkProvider 在初始化 bookingTicket 后会自动从 `appHelper.utils.promotionEvaluator`
671
+ * 读取实例并调用本方法注入。host 透明,业务 UI 不感知。
672
+ *
673
+ * @example
674
+ * order.setPromotionEvaluator(appHelper.utils.promotionEvaluator);
675
+ */
676
+ setPromotionEvaluator: (evaluator: OrderPromotionEvaluator | null) => void;
677
+ /**
678
+ * 注入赠品选择 resolver。OS 在 applyPromotion 内部当需要新增赠品时会 await 调用 resolver。
679
+ *
680
+ * 缺省时 OS 会 `console.warn` 并跳过新增(既有赠品的 reduce/remove 仍会执行)。
681
+ *
682
+ * @example
683
+ * order.setGiftSelectResolver((ctx) => giftSelectBridge.request(ctx));
684
+ */
685
+ setGiftSelectResolver: (resolver: OrderGiftSelectResolver | null) => void;
686
+ /**
687
+ * 为商品目录追加促销标签。
688
+ *
689
+ * @example
690
+ * const taggedProducts = order.appendPromotionTags(products);
691
+ */
692
+ appendPromotionTags: <T extends Record<string, any>>(products: T[]) => T[];
693
+ /**
694
+ * 应用购物车促销(评估 → 差异化赠品 → 写回 tempOrder.products → emit onPromotionApplied)。
695
+ *
696
+ * 自动在 addProductToOrder / updateOrderProductQuantity / removeProductFromOrder /
697
+ * clearOrderCartLines / setOrderCustomer 等写路径末尾触发,业务一般无需手动调用。
698
+ *
699
+ * 多选项赠品依赖 giftSelectResolver;如未注入则跳过且 console.warn。
700
+ * 内部以 `_isApplyingPromotion` flag 防递归。
701
+ */
702
+ applyPromotion: () => Promise<void>;
703
+ /** 读取上次 applyPromotion 产出的未满足促销提示 */
704
+ getUnfulfilledPromotions: () => OrderUnfulfilledPromotion[];
705
+ /** 读取上次 applyPromotion 产出的赠品操作 diff(toAdd / toReduce / toRemove) */
706
+ getLastGiftActions: () => OrderLastGiftActions | null;
524
707
  /**
525
708
  * 取消订单
526
709
  * @param params 取消订单参数
@@ -28,6 +28,7 @@ var OrderHooks = /* @__PURE__ */ ((OrderHooks2) => {
28
28
  OrderHooks2["OnOrderCancel"] = "order:onOrderCancel";
29
29
  OrderHooks2["OnOrderStatusChange"] = "order:onOrderStatusChange";
30
30
  OrderHooks2["OnOrderCustomerChange"] = "order:onOrderCustomerChange";
31
+ OrderHooks2["OnPromotionApplied"] = "order:onPromotionApplied";
31
32
  return OrderHooks2;
32
33
  })(OrderHooks || {});
33
34
  // Annotate the CommonJS export names for ESM import in node:
@@ -0,0 +1,106 @@
1
+ /** 解析商品行数量(checkout 协议 product_num 语义 = 当前行 num) */
2
+ export declare function resolveSafeProductNum(num?: number | null): number;
3
+ /**
4
+ * 将 discount_list 中 type=product 项的 product_num 同步为当前商品数量。
5
+ *
6
+ * @example
7
+ * syncManualProductDiscountProductNum(line.discount_list, line.num);
8
+ */
9
+ export declare function syncManualProductDiscountProductNum(discountList: any[] | undefined | null, productNum?: number | null): any[];
10
+ /** 从多源解析改价前行总价(与 cacheItem._extend.origin_total 语义一致) */
11
+ export declare function resolveManualDiscountOriginTotal(sources: {
12
+ originTotal?: unknown;
13
+ extendOriginTotal?: unknown;
14
+ originExtendOriginTotal?: unknown;
15
+ sourceExtendOriginTotal?: unknown;
16
+ catalogUnitPrice?: unknown;
17
+ quantity?: number;
18
+ }): number;
19
+ /** 从 payload / extend / origin 解析手动折扣原因 */
20
+ export declare function resolveManualDiscountReasonFromSources(sources: {
21
+ discountReason?: unknown;
22
+ extendDiscountReason?: unknown;
23
+ originExtendDiscountReason?: unknown;
24
+ }): string;
25
+ /** 是否带手动改价标记(price_override / is_manual_discount) */
26
+ export declare function hasManualProductDiscountFlag(metadata?: Record<string, any> | null): boolean;
27
+ /**
28
+ * normalize 兜底:手动改价但 discount_list 缺 type=product 时,按行级原价/折后价补写。
29
+ *
30
+ * @example
31
+ * ensureManualProductDiscountList({
32
+ * discountList: [],
33
+ * metadata: { price_override: '5', is_manual_discount: 1 },
34
+ * originalPrice: '11.00',
35
+ * sellingPrice: '5.00',
36
+ * quantity: 1,
37
+ * });
38
+ */
39
+ export declare function ensureManualProductDiscountList(params: {
40
+ discountList?: any[] | null;
41
+ metadata?: Record<string, any> | null;
42
+ originalPrice: string | number;
43
+ sellingPrice: string | number;
44
+ quantity?: number;
45
+ }): any[];
46
+ /** 商品手动折扣 discount_list 项(checkout 协议,type = product) */
47
+ export interface ManualProductDiscountItem {
48
+ amount: number;
49
+ type: 'product';
50
+ discount: {
51
+ message: string;
52
+ discountway: string;
53
+ product_num: number;
54
+ discount_per: string;
55
+ discount_type: 'discount' | 'change_price';
56
+ };
57
+ }
58
+ /**
59
+ * 从 discount_list 中取手动改价项(type = product)。
60
+ *
61
+ * @example
62
+ * const manual = findManualProductDiscountItem(product.discount_list);
63
+ * manual?.discount.message; // 折扣原因
64
+ */
65
+ export declare function findManualProductDiscountItem(discountList?: any[] | null): ManualProductDiscountItem | undefined;
66
+ /**
67
+ * 解析折扣原因:优先 discount_list[type=product].discount.message。
68
+ *
69
+ * @example
70
+ * resolveManualDiscountMessage(line.discount_list, line.metadata?.legacy_reason);
71
+ */
72
+ export declare function resolveManualDiscountMessage(discountList?: any[] | null, fallback?: string): string;
73
+ /** 去掉 discount_list 中已有的手动改价项,避免重复叠加 */
74
+ export declare function stripManualProductDiscountItems(discountList?: any[] | null): any[];
75
+ /**
76
+ * 由改价前后行总价构建手动折扣项;amount = |originTotal - sellingTotal|(行级差额)。
77
+ *
78
+ * @example
79
+ * buildManualProductDiscountItem({
80
+ * originTotal: 11,
81
+ * sellingTotal: 4,
82
+ * quantity: 1,
83
+ * message: 'VIP',
84
+ * });
85
+ */
86
+ export declare function buildManualProductDiscountItem(params: {
87
+ originTotal: number;
88
+ sellingTotal: number;
89
+ quantity?: number;
90
+ message?: string;
91
+ discountway?: string;
92
+ discount_per?: string;
93
+ }): ManualProductDiscountItem;
94
+ /**
95
+ * 将手动改价项合并进 discount_list(替换已有 type=product 项)。
96
+ *
97
+ * @example
98
+ * mergeManualProductDiscountIntoList(coupons, manualItem);
99
+ */
100
+ export declare function mergeManualProductDiscountIntoList(discountList: any[] | undefined | null, manualItem: ManualProductDiscountItem | null | undefined): any[];
101
+ /** 是否应写入手动改价 discount_list 项 */
102
+ export declare function shouldBuildManualProductDiscount(params: {
103
+ hasPriceOverride?: boolean;
104
+ originTotal?: number;
105
+ sellingTotal?: number;
106
+ }): boolean;
@@ -0,0 +1,206 @@
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/manualProductDiscount.ts
30
+ var manualProductDiscount_exports = {};
31
+ __export(manualProductDiscount_exports, {
32
+ buildManualProductDiscountItem: () => buildManualProductDiscountItem,
33
+ ensureManualProductDiscountList: () => ensureManualProductDiscountList,
34
+ findManualProductDiscountItem: () => findManualProductDiscountItem,
35
+ hasManualProductDiscountFlag: () => hasManualProductDiscountFlag,
36
+ mergeManualProductDiscountIntoList: () => mergeManualProductDiscountIntoList,
37
+ resolveManualDiscountMessage: () => resolveManualDiscountMessage,
38
+ resolveManualDiscountOriginTotal: () => resolveManualDiscountOriginTotal,
39
+ resolveManualDiscountReasonFromSources: () => resolveManualDiscountReasonFromSources,
40
+ resolveSafeProductNum: () => resolveSafeProductNum,
41
+ shouldBuildManualProductDiscount: () => shouldBuildManualProductDiscount,
42
+ stripManualProductDiscountItems: () => stripManualProductDiscountItems,
43
+ syncManualProductDiscountProductNum: () => syncManualProductDiscountProductNum
44
+ });
45
+ module.exports = __toCommonJS(manualProductDiscount_exports);
46
+ var import_decimal = __toESM(require("decimal.js"));
47
+ function resolveSafeProductNum(num) {
48
+ const parsed = Number(num);
49
+ if (!Number.isFinite(parsed) || parsed <= 0)
50
+ return 1;
51
+ return Math.floor(parsed);
52
+ }
53
+ function syncManualProductDiscountProductNum(discountList, productNum) {
54
+ const quantity = resolveSafeProductNum(productNum);
55
+ return (discountList || []).map((item) => {
56
+ if ((item == null ? void 0 : item.type) !== "product")
57
+ return item;
58
+ return {
59
+ ...item,
60
+ discount: {
61
+ ...item.discount || {},
62
+ product_num: quantity
63
+ }
64
+ };
65
+ });
66
+ }
67
+ function resolveManualDiscountOriginTotal(sources) {
68
+ const candidates = [
69
+ sources.originTotal,
70
+ sources.extendOriginTotal,
71
+ sources.originExtendOriginTotal,
72
+ sources.sourceExtendOriginTotal
73
+ ];
74
+ for (const candidate of candidates) {
75
+ if (candidate === void 0 || candidate === null || candidate === "")
76
+ continue;
77
+ const parsed = Number(candidate);
78
+ if (Number.isFinite(parsed))
79
+ return parsed;
80
+ }
81
+ const unit = Number(sources.catalogUnitPrice);
82
+ const quantity = sources.quantity ?? 1;
83
+ if (Number.isFinite(unit) && unit > 0) {
84
+ return new import_decimal.default(unit).mul(quantity).toNumber();
85
+ }
86
+ return NaN;
87
+ }
88
+ function resolveManualDiscountReasonFromSources(sources) {
89
+ for (const candidate of [
90
+ sources.discountReason,
91
+ sources.extendDiscountReason,
92
+ sources.originExtendDiscountReason
93
+ ]) {
94
+ if (candidate != null && String(candidate).trim() !== "") {
95
+ return String(candidate);
96
+ }
97
+ }
98
+ return "";
99
+ }
100
+ function hasManualProductDiscountFlag(metadata) {
101
+ if (!metadata)
102
+ return false;
103
+ const override = metadata.price_override;
104
+ if (override !== void 0 && override !== null && override !== "") {
105
+ return true;
106
+ }
107
+ return metadata.is_manual_discount === 1 || metadata.is_manual_discount === true;
108
+ }
109
+ function ensureManualProductDiscountList(params) {
110
+ var _a, _b, _c, _d, _e, _f, _g, _h;
111
+ const list = params.discountList || [];
112
+ const quantity = resolveSafeProductNum(params.quantity);
113
+ if (findManualProductDiscountItem(list)) {
114
+ return syncManualProductDiscountProductNum(list, quantity);
115
+ }
116
+ const metadata = params.metadata || {};
117
+ const originalNum = Number(params.originalPrice);
118
+ const sellingNum = Number(params.sellingPrice);
119
+ const hasPriceOverride = hasManualProductDiscountFlag(metadata);
120
+ const shouldBuild = shouldBuildManualProductDiscount({
121
+ hasPriceOverride,
122
+ originTotal: originalNum,
123
+ sellingTotal: sellingNum
124
+ });
125
+ if (!shouldBuild) {
126
+ return list;
127
+ }
128
+ if (!Number.isFinite(originalNum) || !Number.isFinite(sellingNum) || originalNum === sellingNum) {
129
+ return list;
130
+ }
131
+ const message = resolveManualDiscountMessage(
132
+ list,
133
+ resolveManualDiscountReasonFromSources({
134
+ extendDiscountReason: (_b = (_a = metadata.origin) == null ? void 0 : _a._extend) == null ? void 0 : _b.discount_reason,
135
+ originExtendDiscountReason: (_d = (_c = metadata.origin) == null ? void 0 : _c._extend) == null ? void 0 : _d.discount_reason
136
+ })
137
+ );
138
+ return mergeManualProductDiscountIntoList(
139
+ list,
140
+ buildManualProductDiscountItem({
141
+ originTotal: originalNum,
142
+ sellingTotal: sellingNum,
143
+ quantity,
144
+ message,
145
+ discountway: (_f = (_e = metadata.origin) == null ? void 0 : _e._extend) == null ? void 0 : _f.discountway,
146
+ discount_per: (_h = (_g = metadata.origin) == null ? void 0 : _g._extend) == null ? void 0 : _h.discount_per
147
+ })
148
+ );
149
+ }
150
+ function findManualProductDiscountItem(discountList) {
151
+ return (discountList || []).find((item) => (item == null ? void 0 : item.type) === "product");
152
+ }
153
+ function resolveManualDiscountMessage(discountList, fallback) {
154
+ var _a, _b;
155
+ const message = (_b = (_a = findManualProductDiscountItem(discountList)) == null ? void 0 : _a.discount) == null ? void 0 : _b.message;
156
+ if (message != null && String(message).trim() !== "") {
157
+ return String(message);
158
+ }
159
+ return fallback ?? "";
160
+ }
161
+ function stripManualProductDiscountItems(discountList) {
162
+ return (discountList || []).filter((item) => (item == null ? void 0 : item.type) !== "product");
163
+ }
164
+ function buildManualProductDiscountItem(params) {
165
+ const origin = new import_decimal.default(Number(params.originTotal) || 0);
166
+ const selling = new import_decimal.default(Number(params.sellingTotal) || 0);
167
+ const diff = origin.minus(selling);
168
+ const quantity = resolveSafeProductNum(params.quantity);
169
+ return {
170
+ amount: diff.abs().toDecimalPlaces(2).toNumber(),
171
+ type: "product",
172
+ discount: {
173
+ message: params.message ?? "",
174
+ discountway: params.discountway ?? "num",
175
+ product_num: quantity,
176
+ discount_per: params.discount_per ?? "",
177
+ discount_type: diff.isNegative() ? "change_price" : "discount"
178
+ }
179
+ };
180
+ }
181
+ function mergeManualProductDiscountIntoList(discountList, manualItem) {
182
+ const base = stripManualProductDiscountItems(discountList);
183
+ if (!manualItem)
184
+ return base;
185
+ if (manualItem.amount === 0 && !manualItem.discount.message)
186
+ return base;
187
+ return [...base, manualItem];
188
+ }
189
+ function shouldBuildManualProductDiscount(params) {
190
+ return Boolean(params.hasPriceOverride);
191
+ }
192
+ // Annotate the CommonJS export names for ESM import in node:
193
+ 0 && (module.exports = {
194
+ buildManualProductDiscountItem,
195
+ ensureManualProductDiscountList,
196
+ findManualProductDiscountItem,
197
+ hasManualProductDiscountFlag,
198
+ mergeManualProductDiscountIntoList,
199
+ resolveManualDiscountMessage,
200
+ resolveManualDiscountOriginTotal,
201
+ resolveManualDiscountReasonFromSources,
202
+ resolveSafeProductNum,
203
+ shouldBuildManualProductDiscount,
204
+ stripManualProductDiscountItems,
205
+ syncManualProductDiscountProductNum
206
+ });