@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
@@ -1,6 +1,6 @@
1
1
  import Decimal from 'decimal.js';
2
2
  import { CartItem } from "../Cart";
3
- import type { OrderSubmitPayload, OrderSubmitProduct, OrderSummary, OrderTempOrder } from './types';
3
+ import type { OrderProductDiscountItem, OrderSubmitPayload, OrderSubmitProduct, OrderSummary, OrderTempOrder } from './types';
4
4
  import type { RulesParamsHooks } from '../Rules/types';
5
5
  import type { MapOrderPaymentsOptions, OrderPaymentData, OrderPaymentSource } from './types';
6
6
  /**
@@ -65,6 +65,37 @@ export declare function sumOptionUnitPrice(options?: Array<{
65
65
  *
66
66
  * 导出为纯函数方便单测直接驱动钩子,不依赖 OrderModule 实例。
67
67
  */
68
+ /** Rules calcDiscount 用手动价标记;undefined 表示交给 Rules 用 total/origin_total 推断 */
69
+ export declare function resolveRulesManualDiscountFlag(metadata: Record<string, any> | null | undefined): boolean | undefined;
70
+ /**
71
+ * 商品行折扣只保留后端 OrderProductDiscountItem 协议字段。
72
+ * Rules/券计算过程中的 `_num`、`config` 等运行态字段不应进入 tempOrder 或提交 payload。
73
+ */
74
+ export declare function normalizeOrderProductDiscountList(discountList?: unknown[] | null): OrderProductDiscountItem[];
75
+ /**
76
+ * 手动改价(price_override)时行级 original_price(composite 单价):
77
+ * 购物车划线价应对齐 metadata.origin._extend.origin_total(改价前单价 composite,如 40),
78
+ * 而非 bundle 子项 catalog 原价合成的 composedOriginalPrice(如 30)。
79
+ *
80
+ * origin_total 与 SkuDetailModal / cacheItem._extend 一致,为单价语义,不再除以 num。
81
+ */
82
+ export declare function resolveManualOverrideLineOriginalPrice(params: {
83
+ num?: number;
84
+ metadata?: Record<string, any> | null;
85
+ /** 已有行级 original_price(origin 被裁剪时兜底划线价) */
86
+ lineOriginalPrice?: string | number | null;
87
+ }, fallbackCompositeOriginal: string): string;
88
+ /**
89
+ * 计算商品行「每单位有效折扣」:discount_list 合计 + 被 Rules 剥离但仍 inPromotion 的差额。
90
+ *
91
+ * Rules.calcDiscount 会把 type=promotion 从 discount_list 去掉,但 metadata._promotion 仍保留;
92
+ * applyProductDiscountPrices 必须回读 _promotion,否则抬价/降价都会在第二步被 source 原价覆盖。
93
+ *
94
+ * @example
95
+ * resolveEffectivePerUnitDiscount({ metadata: { _promotion: { inPromotion: true, originalPrice: 1, finalPrice: 5 } }, discount_list: [] });
96
+ * // => -4
97
+ */
98
+ export declare function resolveEffectivePerUnitDiscount(product: Record<string, any>): number;
68
99
  export declare function createDefaultOrderRulesHooks(): RulesParamsHooks;
69
100
  /**
70
101
  * 通过 session 类商品的开始时间结束时间生成商品的时长
@@ -140,4 +171,55 @@ export declare function formatV1Product(products: OrderSubmitProduct[]): {
140
171
  session: null;
141
172
  unique: string;
142
173
  }[];
174
+ /**
175
+ * 判断 holder_id 是否已分配(非空)。
176
+ *
177
+ * @example
178
+ * hasAssignedHolderId(12); // true
179
+ * hasAssignedHolderId([]); // false
180
+ */
181
+ export declare function hasAssignedHolderId(value: unknown): boolean;
182
+ /**
183
+ * 清空 tempOrder 购物车行上的 holder 分配(products / bookings / runtime origin)。
184
+ * 移除或更换下单客户时调用,与 booking 页换客户清 holder 行为对齐。
185
+ *
186
+ * @example
187
+ * clearTempOrderHolderAssignments(tempOrder);
188
+ */
189
+ export declare function clearTempOrderHolderAssignments(tempOrder: OrderTempOrder): boolean;
190
+ /**
191
+ * 读取购物车行的 stable uid(优先 metadata.unique_identification_number)。
192
+ *
193
+ * @example
194
+ * getOrderProductLineUid({ metadata: { unique_identification_number: 'line-1' } }); // 'line-1'
195
+ */
196
+ export declare function getOrderProductLineUid(product: Record<string, any> | null | undefined): string | null;
197
+ /**
198
+ * 判断展示字段是否为空(含 i18n 对象全空)。
199
+ *
200
+ * @example
201
+ * isEmptyOrderProductDisplayValue(''); // true
202
+ * isEmptyOrderProductDisplayValue({ auto: '桌台费' }); // false
203
+ */
204
+ export declare function isEmptyOrderProductDisplayValue(value: unknown): boolean;
205
+ /**
206
+ * calcDiscount / applyDiscount 回写时 Rules 往往不带 product_title 等展示字段;
207
+ * 用旧行补齐,避免编辑态 hydrate 后标题被冲掉。
208
+ *
209
+ * @example
210
+ * mergeOrderProductDisplayFields(
211
+ * { product_title: { auto: '桌台费' }, metadata: { unique_identification_number: 'u1' } },
212
+ * { selling_price: '10.00', metadata: { unique_identification_number: 'u1' } },
213
+ * );
214
+ */
215
+ export declare function mergeOrderProductDisplayFields(previous: Record<string, any>, next: Record<string, any>): Record<string, any>;
216
+ /**
217
+ * 按 uid 索引 tempOrder.products,供 applyDiscount 合并展示字段。
218
+ *
219
+ * @example
220
+ * indexOrderProductsByUid([{ metadata: { unique_identification_number: 'u1' } }]);
221
+ */
222
+ export declare function indexOrderProductsByUid(products: Array<Record<string, any>> | null | undefined): Map<string, Record<string, any>>;
143
223
  export { createEmptySummary } from '../../solution/ScanOrder/utils';
224
+ export { buildManualProductDiscountItem, ensureManualProductDiscountList, findManualProductDiscountItem, mergeManualProductDiscountIntoList, resolveManualDiscountMessage, resolveManualDiscountOriginTotal, resolveManualDiscountReasonFromSources, resolveSafeProductNum, shouldBuildManualProductDiscount, syncManualProductDiscountProductNum, stripManualProductDiscountItems, } from './utils/manualProductDiscount';
225
+ export type { ManualProductDiscountItem } from './utils/manualProductDiscount';
@@ -29,32 +29,54 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  // src/modules/Order/utils.ts
30
30
  var utils_exports = {};
31
31
  __export(utils_exports, {
32
+ buildManualProductDiscountItem: () => import_manualProductDiscount.buildManualProductDiscountItem,
32
33
  buildSubmitPayload: () => buildSubmitPayload,
34
+ clearTempOrderHolderAssignments: () => clearTempOrderHolderAssignments,
33
35
  composeLinePrice: () => composeLinePrice,
34
36
  createDefaultOrderRulesHooks: () => createDefaultOrderRulesHooks,
35
37
  createDefaultTempOrder: () => createDefaultTempOrder,
36
38
  createEmptySummary: () => import_utils2.createEmptySummary,
37
39
  createUuidV4: () => createUuidV4,
40
+ ensureManualProductDiscountList: () => import_manualProductDiscount.ensureManualProductDiscountList,
41
+ findManualProductDiscountItem: () => import_manualProductDiscount.findManualProductDiscountItem,
38
42
  formatDateTime: () => formatDateTime,
39
43
  formatV1Product: () => formatV1Product,
40
44
  generateDuration: () => generateDuration,
41
45
  getAllDiscountList: () => getAllDiscountList,
46
+ getOrderProductLineUid: () => getOrderProductLineUid,
47
+ hasAssignedHolderId: () => hasAssignedHolderId,
48
+ indexOrderProductsByUid: () => indexOrderProductsByUid,
49
+ isEmptyOrderProductDisplayValue: () => isEmptyOrderProductDisplayValue,
42
50
  isTempOrder: () => isTempOrder,
43
51
  mapPaymentItemToOrderPayment: () => mapPaymentItemToOrderPayment,
44
52
  mapPaymentItemsToOrderPayments: () => mapPaymentItemsToOrderPayments,
53
+ mergeManualProductDiscountIntoList: () => import_manualProductDiscount.mergeManualProductDiscountIntoList,
54
+ mergeOrderProductDisplayFields: () => mergeOrderProductDisplayFields,
45
55
  mergeRelationForms: () => mergeRelationForms,
46
56
  normalizeBookingIsAll: () => normalizeBookingIsAll,
47
57
  normalizeBookingSubType: () => normalizeBookingSubType,
58
+ normalizeOrderProductDiscountList: () => normalizeOrderProductDiscountList,
48
59
  normalizeSubmitBooking: () => normalizeSubmitBooking,
49
60
  normalizeSubmitCollectPaxValue: () => normalizeSubmitCollectPaxValue,
61
+ resolveEffectivePerUnitDiscount: () => resolveEffectivePerUnitDiscount,
62
+ resolveManualDiscountMessage: () => import_manualProductDiscount.resolveManualDiscountMessage,
63
+ resolveManualDiscountOriginTotal: () => import_manualProductDiscount.resolveManualDiscountOriginTotal,
64
+ resolveManualDiscountReasonFromSources: () => import_manualProductDiscount.resolveManualDiscountReasonFromSources,
65
+ resolveManualOverrideLineOriginalPrice: () => resolveManualOverrideLineOriginalPrice,
66
+ resolveRulesManualDiscountFlag: () => resolveRulesManualDiscountFlag,
67
+ resolveSafeProductNum: () => import_manualProductDiscount.resolveSafeProductNum,
50
68
  resolveSubmitCollectPax: () => resolveSubmitCollectPax,
51
- sumOptionUnitPrice: () => sumOptionUnitPrice
69
+ shouldBuildManualProductDiscount: () => import_manualProductDiscount.shouldBuildManualProductDiscount,
70
+ stripManualProductDiscountItems: () => import_manualProductDiscount.stripManualProductDiscountItems,
71
+ sumOptionUnitPrice: () => sumOptionUnitPrice,
72
+ syncManualProductDiscountProductNum: () => import_manualProductDiscount.syncManualProductDiscountProductNum
52
73
  });
53
74
  module.exports = __toCommonJS(utils_exports);
54
75
  var import_dayjs = __toESM(require("dayjs"));
55
76
  var import_decimal = __toESM(require("decimal.js"));
56
77
  var import_utils = require("../../solution/ScanOrder/utils");
57
78
  var import_utils2 = require("../../solution/ScanOrder/utils");
79
+ var import_manualProductDiscount = require("./utils/manualProductDiscount");
58
80
  function composeLinePrice(params) {
59
81
  const { mainPrice, bundle, useOriginalBundle } = params;
60
82
  let total = new import_decimal.default(Number(mainPrice) || 0);
@@ -80,11 +102,146 @@ function sumOptionUnitPrice(options) {
80
102
  }
81
103
  return total;
82
104
  }
105
+ function resolveRulesManualDiscountFlag(metadata) {
106
+ if (!metadata)
107
+ return void 0;
108
+ if (metadata.is_manual_discount === true || metadata.is_manual_discount === 1) {
109
+ return true;
110
+ }
111
+ const priceOverride = metadata.price_override;
112
+ if (priceOverride !== void 0 && priceOverride !== null && priceOverride !== "") {
113
+ return true;
114
+ }
115
+ return void 0;
116
+ }
117
+ function normalizeOrderProductDiscountAmount(amount) {
118
+ if (amount === void 0 || amount === null)
119
+ return void 0;
120
+ return String(amount);
121
+ }
122
+ function normalizeOrderProductDiscountList(discountList) {
123
+ if (!Array.isArray(discountList))
124
+ return [];
125
+ return discountList.filter((item) => !!item && typeof item === "object").map((item) => {
126
+ const normalized = {
127
+ discount_id: Number.isFinite(Number(item.discount_id)) ? Number(item.discount_id) : 0
128
+ };
129
+ if (item.order_discount_id === null) {
130
+ normalized.order_discount_id = null;
131
+ } else if (item.order_discount_id !== void 0) {
132
+ const orderDiscountId = Number(item.order_discount_id);
133
+ if (Number.isFinite(orderDiscountId)) {
134
+ normalized.order_discount_id = orderDiscountId;
135
+ }
136
+ }
137
+ if (item.type !== void 0)
138
+ normalized.type = item.type;
139
+ const amount = normalizeOrderProductDiscountAmount(item.amount);
140
+ if (amount !== void 0)
141
+ normalized.amount = amount;
142
+ if (item.discount && typeof item.discount === "object") {
143
+ normalized.discount = { ...item.discount };
144
+ }
145
+ if (item.metadata === null) {
146
+ normalized.metadata = null;
147
+ } else if (item.metadata && typeof item.metadata === "object") {
148
+ normalized.metadata = { ...item.metadata };
149
+ }
150
+ return normalized;
151
+ });
152
+ }
153
+ function resolveManualOverrideLineOriginalPrice(params, fallbackCompositeOriginal) {
154
+ var _a, _b;
155
+ const metadata = params.metadata || {};
156
+ const priceOverride = metadata.price_override;
157
+ if (priceOverride === void 0 || priceOverride === null || priceOverride === "") {
158
+ return fallbackCompositeOriginal;
159
+ }
160
+ const refTotal = (_b = (_a = metadata.origin) == null ? void 0 : _a._extend) == null ? void 0 : _b.origin_total;
161
+ if (refTotal !== void 0 && refTotal !== null && refTotal !== "") {
162
+ const parsed = Number(refTotal);
163
+ if (Number.isFinite(parsed)) {
164
+ return new import_decimal.default(parsed).toDecimalPlaces(2).toFixed(2);
165
+ }
166
+ }
167
+ const lineOriginal = params.lineOriginalPrice;
168
+ if (lineOriginal !== void 0 && lineOriginal !== null && lineOriginal !== "") {
169
+ const parsedLine = Number(lineOriginal);
170
+ const parsedFallback = Number(fallbackCompositeOriginal);
171
+ if (Number.isFinite(parsedLine) && Number.isFinite(parsedFallback) && parsedLine > parsedFallback) {
172
+ return new import_decimal.default(parsedLine).toDecimalPlaces(2).toFixed(2);
173
+ }
174
+ }
175
+ return fallbackCompositeOriginal;
176
+ }
177
+ function resolveEffectivePerUnitDiscount(product) {
178
+ const discountList = Array.isArray(product == null ? void 0 : product.discount_list) ? product.discount_list : [];
179
+ const fromList = discountList.reduce(
180
+ (sum, discount) => sum + Number((discount == null ? void 0 : discount.amount) || 0),
181
+ 0
182
+ );
183
+ const hasPromoDiscountItem = discountList.some((item) => (item == null ? void 0 : item.type) === "promotion");
184
+ if (hasPromoDiscountItem)
185
+ return fromList;
186
+ const metadata = (product == null ? void 0 : product.metadata) || {};
187
+ const optionSum = sumOptionUnitPrice(product == null ? void 0 : product.product_option_item).toNumber();
188
+ if (metadata.source_product_price != null && metadata.main_product_selling_price != null) {
189
+ const source = Number(metadata.source_product_price);
190
+ const selling = Number(metadata.main_product_selling_price) - optionSum;
191
+ if (Number.isFinite(source) && Number.isFinite(selling) && source !== selling) {
192
+ return fromList + (source - selling);
193
+ }
194
+ }
195
+ const promo = metadata._promotion;
196
+ if ((promo == null ? void 0 : promo.inPromotion) !== true)
197
+ return fromList;
198
+ const originalPrice = Number(promo.originalPrice);
199
+ const finalPrice = Number(promo.finalPrice);
200
+ if (!Number.isFinite(originalPrice) || !Number.isFinite(finalPrice))
201
+ return fromList;
202
+ return fromList + (originalPrice - finalPrice);
203
+ }
83
204
  function createDefaultOrderRulesHooks() {
84
205
  const toUnitPriceString = (totalLike, num) => {
85
206
  const effectiveNum = Number(num) > 0 ? Number(num) : 1;
86
207
  return new import_decimal.default(Number(totalLike) || 0).dividedBy(effectiveNum).toDecimalPlaces(2).toString();
87
208
  };
209
+ const getBundleIdentity = (bundle) => {
210
+ return [
211
+ bundle.bundle_id ?? bundle.id ?? "",
212
+ bundle.bundle_product_id ?? bundle._bundle_product_id ?? bundle.product_id ?? "",
213
+ bundle.bundle_variant_id ?? bundle.variant_id ?? bundle.product_variant_id ?? 0,
214
+ bundle.bundle_group_id ?? bundle.group_id ?? ""
215
+ ].join("|");
216
+ };
217
+ const mergeRulesBundlePrices = (currentBundle, rulesBundle) => {
218
+ if (!Array.isArray(rulesBundle))
219
+ return rulesBundle;
220
+ const currentByIdentity = /* @__PURE__ */ new Map();
221
+ (currentBundle || []).forEach((bundle) => {
222
+ if (!bundle || typeof bundle !== "object")
223
+ return;
224
+ currentByIdentity.set(getBundleIdentity(bundle), bundle);
225
+ });
226
+ return rulesBundle.map((bundle) => {
227
+ if (!bundle || typeof bundle !== "object")
228
+ return bundle;
229
+ const current = currentByIdentity.get(getBundleIdentity(bundle));
230
+ if (!current)
231
+ return bundle;
232
+ const isProductPriceBundle = (bundle.price_type_ext ?? current.price_type_ext) === "product_price";
233
+ if (!isProductPriceBundle)
234
+ return bundle;
235
+ const sourcePrice = current.price ?? current.custom_price ?? current.original_price ?? current.bundle_selling_price;
236
+ const originalPrice = current.original_price ?? current.product_price ?? current.price ?? current.custom_price ?? sourcePrice;
237
+ return {
238
+ ...bundle,
239
+ ...sourcePrice !== void 0 ? { price: sourcePrice } : {},
240
+ ...originalPrice !== void 0 ? { original_price: originalPrice } : {},
241
+ ...current.original_total !== void 0 ? { original_total: current.original_total } : {}
242
+ };
243
+ });
244
+ };
88
245
  return {
89
246
  getProduct: (product) => {
90
247
  var _a, _b, _c, _d, _e, _f;
@@ -114,7 +271,7 @@ function createDefaultOrderRulesHooks() {
114
271
  id: product.product_id,
115
272
  // Rules 引擎用 _id 作为 processedProductsMap 键;必须与购物车行级 identity 一致,
116
273
  // 否则同 SKU 不同小料会在 calcDiscount 重组时互相覆盖。
117
- // 不透明 identity 契约下,normalizeOrderProduct / restoreTempOrderFromStorage 已保证唯一值存在;
274
+ // 不透明 identity 契约下,normalizeOrderProduct / hydrate 已保证唯一值存在;
118
275
  // 留 fingerprint 分支仅作 Rules 单测里直接传裸 product 时的兜底。
119
276
  _id: ((_a = product.metadata) == null ? void 0 : _a.unique_identification_number) ? `${product.product_id}_${product.product_variant_id}_${product.metadata.unique_identification_number}` : `${product.product_id}_${product.product_variant_id}_${(0, import_utils.buildProductLineFingerprint)(
120
277
  product.product_option_item,
@@ -135,9 +292,14 @@ function createDefaultOrderRulesHooks() {
135
292
  bundle: product.product_bundle || [],
136
293
  booking_id: ((_b = product.metadata) == null ? void 0 : _b.booking_id) || null,
137
294
  isClient: false,
138
- isManualDiscount: ((_c = product.metadata) == null ? void 0 : _c.is_manual_discount) || false,
139
- holder_id: (_d = product.metadata) == null ? void 0 : _d.holder_id,
140
- startDate: ((_e = product.metadata) == null ? void 0 : _e.start_date) || ((_f = product.metadata) == null ? void 0 : _f.startDate)
295
+ // 勿写死 false:否则 Rules 不会走 total≠origin_total 的手动价推断,
296
+ // 无券时会把 bundle 价还原成 original_price(手动改价套餐会从 20 回到 30)。
297
+ isManualDiscount: resolveRulesManualDiscountFlag(metadataAny),
298
+ holder_id: (_c = product.metadata) == null ? void 0 : _c.holder_id,
299
+ startDate: ((_d = product.metadata) == null ? void 0 : _d.start_date) || ((_e = product.metadata) == null ? void 0 : _e.startDate),
300
+ main_product_selling_price: metadataAny.main_product_selling_price !== void 0 ? new import_decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSum).toDecimalPlaces(2).toString() : void 0,
301
+ inPromotion: ((_f = metadataAny._promotion) == null ? void 0 : _f.inPromotion) === true,
302
+ _promotion: metadataAny._promotion
141
303
  };
142
304
  },
143
305
  setProduct: (product, values) => {
@@ -150,7 +312,7 @@ function createDefaultOrderRulesHooks() {
150
312
  const nextSourceOriginalPrice = values.original_price !== void 0 ? String(values.original_price) : String(existedSource);
151
313
  const nextMainSellingPrice = new import_decimal.default(Number(nextSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
152
314
  const nextMainOriginalPrice = new import_decimal.default(Number(nextSourceOriginalPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
153
- const nextBundle = values.bundle ?? product.product_bundle;
315
+ const nextBundle = values.bundle !== void 0 ? mergeRulesBundlePrices(product.product_bundle, values.bundle) : product.product_bundle;
154
316
  const composedSellingPrice = composeLinePrice({
155
317
  mainPrice: nextMainSellingPrice,
156
318
  bundle: nextBundle
@@ -160,10 +322,14 @@ function createDefaultOrderRulesHooks() {
160
322
  bundle: nextBundle,
161
323
  useOriginalBundle: true
162
324
  });
325
+ const finalOriginalPrice = resolveManualOverrideLineOriginalPrice(
326
+ { num: nextNum, metadata: metadataAny, lineOriginalPrice: product.original_price },
327
+ composedOriginalPrice
328
+ );
163
329
  return {
164
330
  ...product,
165
331
  selling_price: composedSellingPrice,
166
- original_price: composedOriginalPrice,
332
+ original_price: finalOriginalPrice,
167
333
  discount_list: values.discount_list ?? product.discount_list,
168
334
  num: values.quantity ?? product.num,
169
335
  product_bundle: nextBundle,
@@ -321,6 +487,11 @@ function normalizeSubmitProduct(product) {
321
487
  num,
322
488
  product_option_item: productOptionItem,
323
489
  surcharge_fee: _productSurchargeFee,
490
+ discount_amount: _deprecatedDiscountAmount,
491
+ discount_type: _deprecatedDiscountType,
492
+ discountway: _deprecatedDiscountway,
493
+ product_discount_reason: _deprecatedProductDiscountReason,
494
+ discount_per: _deprecatedDiscountPer,
324
495
  ...productRest
325
496
  } = submitProduct;
326
497
  const rawMetadata = submitProduct.metadata || {};
@@ -365,7 +536,7 @@ function normalizeSubmitProduct(product) {
365
536
  ...bookingUid ? { booking_uid: bookingUid } : {},
366
537
  product_quantity: toBundleNumber(num ?? submitProduct.product_quantity, 1),
367
538
  product_sku: productSku,
368
- discount_list: submitProduct.discount_list || [],
539
+ discount_list: normalizeOrderProductDiscountList(submitProduct.discount_list),
369
540
  product_bundle: formatSubmitBundleItems(submitProduct.product_bundle),
370
541
  metadata: cleanMetadata,
371
542
  // 出站兼容:后端消费 payment_price 字段,这里从 selling_price 直接派生。
@@ -425,22 +596,23 @@ function createDefaultTempOrder(params) {
425
596
  return {
426
597
  order_id: null,
427
598
  external_sale_number: "",
428
- order_number: "",
429
- shop_order_number: "",
430
- shop_full_order_number: "",
431
- type: "appointment_booking",
432
- business_code: "appointment_booking",
599
+ order_number: null,
600
+ shop_order_number: null,
601
+ shop_full_order_number: null,
602
+ type: "",
603
+ business_code: void 0,
433
604
  platform: "h5",
434
605
  sales_channel: "my_pisel",
435
606
  order_sales_channel: "online_store",
436
607
  status: "normal",
437
608
  payment_status: "payment_processing",
438
609
  shipping_status: "unfulfilled",
439
- customer_id: null,
610
+ customer_id: 0,
440
611
  customer_name: "",
441
612
  country_calling_code: "",
442
613
  phone: "",
443
614
  email: "",
615
+ customer: null,
444
616
  is_price_include_tax: 1,
445
617
  tax_title: "",
446
618
  tax_country_code: "",
@@ -460,7 +632,6 @@ function createDefaultTempOrder(params) {
460
632
  bookings: [],
461
633
  payments: [],
462
634
  surcharges: [],
463
- discount_list: [],
464
635
  relation_forms: [],
465
636
  contacts: [],
466
637
  contacts_info: null,
@@ -472,6 +643,7 @@ function createDefaultTempOrder(params) {
472
643
  };
473
644
  }
474
645
  function buildSubmitPayload(params) {
646
+ var _a;
475
647
  const {
476
648
  tempOrder,
477
649
  cacheId,
@@ -497,7 +669,7 @@ function buildSubmitPayload(params) {
497
669
  shop_service_type: _shopServiceType,
498
670
  start_time: _startTime,
499
671
  customer: _customer,
500
- shop_full_order_number: _shopFullOrderNumber,
672
+ discount_list: _discountList,
501
673
  tax_fee: _rootTaxFee,
502
674
  total_amount: _totalAmount,
503
675
  total_refund_amount: _totalRefundAmount,
@@ -505,12 +677,25 @@ function buildSubmitPayload(params) {
505
677
  holder_id: _holderId,
506
678
  ...tempOrderRest
507
679
  } = tempOrder;
680
+ let submitType = type ?? tempOrder.type;
681
+ if (!submitType) {
682
+ if ((_a = tempOrder == null ? void 0 : tempOrder.bookings) == null ? void 0 : _a.length) {
683
+ submitType = "appointment_booking";
684
+ } else {
685
+ submitType = "virtual";
686
+ }
687
+ }
508
688
  const payload = {
509
689
  ...tempOrderRest,
690
+ customer_id: tempOrder.customer_id ?? 1,
691
+ customer_name: tempOrder.customer_name || "Select a customer",
692
+ order_number: null,
693
+ shop_order_number: null,
694
+ shop_full_order_number: null,
510
695
  platform: normalizeSubmitPlatform(platform),
511
696
  request_unique_idempotency_token: tempOrder.request_unique_idempotency_token || `${tempOrder.external_sale_number}_${now.getTime()}`,
512
- type: type ?? tempOrder.type ?? "table-order",
513
- business_code: businessCode ?? tempOrder.business_code ?? "table-order",
697
+ type: submitType,
698
+ business_code: businessCode ?? tempOrder.business_code,
514
699
  sales_channel: tempOrder.sales_channel || "my_pisel",
515
700
  order_sales_channel: channel ?? tempOrder.order_sales_channel ?? "online_store",
516
701
  status: tempOrder.status || "normal",
@@ -525,12 +710,11 @@ function buildSubmitPayload(params) {
525
710
  note: tempOrder.note || "",
526
711
  delivery_type: tempOrder.delivery_type || "nil",
527
712
  schedule_date: scheduleDate,
528
- created_at: tempOrder.created_at || formatDateTime(now),
713
+ // created_at: tempOrder.created_at || formatDateTime(now), 和后端协定这个字段先不提交到接口
529
714
  bookings: (tempOrder.bookings || []).filter(
530
- (booking) => Number(booking.parent_id ?? 0) !== 0
715
+ (booking) => Number(booking.parent_id) !== 0
531
716
  ).map((booking) => normalizeSubmitBooking(booking)),
532
717
  payments: tempOrder.payments || [],
533
- // discount_list: tempOrder.discount_list || [],
534
718
  relation_forms: tempOrder.relation_forms || [],
535
719
  // contacts: tempOrder.contacts || [],
536
720
  contacts_info: tempOrder.contacts_info && !Array.isArray(tempOrder.contacts_info) ? tempOrder.contacts_info : null,
@@ -611,26 +795,160 @@ function formatV1Product(products) {
611
795
  };
612
796
  });
613
797
  }
798
+ function hasAssignedHolderId(value) {
799
+ if (value === void 0 || value === null || value === "")
800
+ return false;
801
+ if (Array.isArray(value))
802
+ return value.length > 0;
803
+ return true;
804
+ }
805
+ function clearTempOrderHolderAssignments(tempOrder) {
806
+ var _a;
807
+ let changed = false;
808
+ const resetHolderField = (target, key = "holder_id") => {
809
+ if (!hasAssignedHolderId(target[key]))
810
+ return;
811
+ target[key] = null;
812
+ changed = true;
813
+ };
814
+ for (const product of tempOrder.products || []) {
815
+ if (product.metadata && typeof product.metadata === "object") {
816
+ resetHolderField(product.metadata);
817
+ }
818
+ }
819
+ for (const booking of tempOrder.bookings || []) {
820
+ const bookingRecord = booking;
821
+ if (booking.metadata && typeof booking.metadata === "object") {
822
+ resetHolderField(booking.metadata);
823
+ }
824
+ if (bookingRecord.holder !== void 0 && bookingRecord.holder !== null) {
825
+ delete bookingRecord.holder;
826
+ changed = true;
827
+ }
828
+ }
829
+ const productsByUid = (_a = tempOrder._extend) == null ? void 0 : _a.productsByUid;
830
+ if (productsByUid && typeof productsByUid === "object") {
831
+ for (const entry of Object.values(productsByUid)) {
832
+ const origin = entry == null ? void 0 : entry.origin;
833
+ if (!origin || typeof origin !== "object")
834
+ continue;
835
+ if (origin.metadata && typeof origin.metadata === "object") {
836
+ resetHolderField(origin.metadata);
837
+ }
838
+ if (origin._extend && typeof origin._extend === "object") {
839
+ resetHolderField(origin._extend);
840
+ }
841
+ }
842
+ }
843
+ return changed;
844
+ }
845
+ function getOrderProductLineUid(product) {
846
+ var _a;
847
+ if (!product || typeof product !== "object")
848
+ return null;
849
+ const uid = ((_a = product.metadata) == null ? void 0 : _a.unique_identification_number) ?? product.unique_identification_number;
850
+ if (uid === void 0 || uid === null || uid === "")
851
+ return null;
852
+ return String(uid);
853
+ }
854
+ function isEmptyOrderProductDisplayValue(value) {
855
+ if (value === void 0 || value === null)
856
+ return true;
857
+ if (typeof value === "string")
858
+ return value.trim() === "";
859
+ if (typeof value === "object") {
860
+ const record = value;
861
+ return !Object.values(record).some(
862
+ (item) => typeof item === "string" && item.trim() !== ""
863
+ );
864
+ }
865
+ return false;
866
+ }
867
+ function mergeOrderProductDisplayFields(previous, next) {
868
+ const merged = { ...next };
869
+ const displayFields = [
870
+ "product_title",
871
+ "product_name",
872
+ "product_cover",
873
+ "cover",
874
+ "variant_title",
875
+ "product_sku"
876
+ ];
877
+ displayFields.forEach((field) => {
878
+ if (isEmptyOrderProductDisplayValue(merged[field]) && !isEmptyOrderProductDisplayValue(previous[field])) {
879
+ merged[field] = previous[field];
880
+ }
881
+ });
882
+ if (previous.metadata || next.metadata) {
883
+ merged.metadata = {
884
+ ...previous.metadata || {},
885
+ ...next.metadata || {}
886
+ };
887
+ ["product_title", "product_name"].forEach((field) => {
888
+ var _a;
889
+ if (isEmptyOrderProductDisplayValue(merged.metadata[field]) && !isEmptyOrderProductDisplayValue((_a = previous.metadata) == null ? void 0 : _a[field])) {
890
+ merged.metadata[field] = previous.metadata[field];
891
+ }
892
+ });
893
+ }
894
+ if (previous._extend && !merged._extend) {
895
+ merged._extend = previous._extend;
896
+ }
897
+ return merged;
898
+ }
899
+ function indexOrderProductsByUid(products) {
900
+ const map = /* @__PURE__ */ new Map();
901
+ (products || []).forEach((product, index) => {
902
+ const uid = getOrderProductLineUid(product);
903
+ if (uid) {
904
+ map.set(uid, product);
905
+ return;
906
+ }
907
+ map.set(`__index__:${index}`, product);
908
+ });
909
+ return map;
910
+ }
614
911
  // Annotate the CommonJS export names for ESM import in node:
615
912
  0 && (module.exports = {
913
+ buildManualProductDiscountItem,
616
914
  buildSubmitPayload,
915
+ clearTempOrderHolderAssignments,
617
916
  composeLinePrice,
618
917
  createDefaultOrderRulesHooks,
619
918
  createDefaultTempOrder,
620
919
  createEmptySummary,
621
920
  createUuidV4,
921
+ ensureManualProductDiscountList,
922
+ findManualProductDiscountItem,
622
923
  formatDateTime,
623
924
  formatV1Product,
624
925
  generateDuration,
625
926
  getAllDiscountList,
927
+ getOrderProductLineUid,
928
+ hasAssignedHolderId,
929
+ indexOrderProductsByUid,
930
+ isEmptyOrderProductDisplayValue,
626
931
  isTempOrder,
627
932
  mapPaymentItemToOrderPayment,
628
933
  mapPaymentItemsToOrderPayments,
934
+ mergeManualProductDiscountIntoList,
935
+ mergeOrderProductDisplayFields,
629
936
  mergeRelationForms,
630
937
  normalizeBookingIsAll,
631
938
  normalizeBookingSubType,
939
+ normalizeOrderProductDiscountList,
632
940
  normalizeSubmitBooking,
633
941
  normalizeSubmitCollectPaxValue,
942
+ resolveEffectivePerUnitDiscount,
943
+ resolveManualDiscountMessage,
944
+ resolveManualDiscountOriginTotal,
945
+ resolveManualDiscountReasonFromSources,
946
+ resolveManualOverrideLineOriginalPrice,
947
+ resolveRulesManualDiscountFlag,
948
+ resolveSafeProductNum,
634
949
  resolveSubmitCollectPax,
635
- sumOptionUnitPrice
950
+ shouldBuildManualProductDiscount,
951
+ stripManualProductDiscountItems,
952
+ sumOptionUnitPrice,
953
+ syncManualProductDiscountProductNum
636
954
  });
@@ -49,5 +49,5 @@ export declare class Product extends BaseModule implements Module {
49
49
  getCategories(): ProductCategory[];
50
50
  setOtherParams(key: string, value: any): void;
51
51
  getOtherParams(): any;
52
- getProductType(): "normal" | "duration" | "session";
52
+ getProductType(): "duration" | "session" | "normal";
53
53
  }
@@ -47,7 +47,6 @@ export declare class QuotationModule extends BaseModule implements Module {
47
47
  customer_id?: number | string;
48
48
  }): Map<string, string | null>;
49
49
  setScheduleResolver(resolver: (id: number) => ScheduleItem | undefined): void;
50
- private filterQuotationsByCustomer;
51
50
  private isQuotationVisibleForCustomer;
52
51
  private hasValidCustomerId;
53
52
  private isQuotationActiveAt;