@pisell/pisellos 0.10.7 → 0.10.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/dist/core/index.js +0 -1
  2. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  3. package/dist/model/strategy/adapter/dataVariant/evaluator.js +287 -101
  4. package/dist/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  5. package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -2
  6. package/dist/model/strategy/adapter/walletPass/type.d.ts +5 -0
  7. package/dist/model/strategy/adapter/walletPass/utils.js +57 -26
  8. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +18 -12
  9. package/dist/modules/BookingContext/utils/productExtend.js +5 -9
  10. package/dist/modules/BookingContext/utils/timeSlices.js +24 -3
  11. package/dist/modules/Customer/index.d.ts +4 -0
  12. package/dist/modules/Customer/index.js +91 -59
  13. package/dist/modules/Customer/types.d.ts +2 -0
  14. package/dist/modules/Discount/index.d.ts +2 -0
  15. package/dist/modules/Discount/index.js +38 -5
  16. package/dist/modules/Discount/types.d.ts +11 -0
  17. package/dist/modules/Order/index.d.ts +32 -6
  18. package/dist/modules/Order/index.js +1165 -819
  19. package/dist/modules/Order/types.d.ts +32 -4
  20. package/dist/modules/Order/types.js +11 -0
  21. package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
  22. package/dist/modules/Order/utils/discountProductLineIdentity.js +227 -0
  23. package/dist/modules/Order/utils/virtualSettlement.d.ts +56 -0
  24. package/dist/modules/Order/utils/virtualSettlement.js +271 -0
  25. package/dist/modules/Order/utils.js +89 -48
  26. package/dist/modules/Payment/types.d.ts +2 -0
  27. package/dist/modules/Payment/utils.js +4 -1
  28. package/dist/modules/Payment/walletpass.d.ts +11 -0
  29. package/dist/modules/Payment/walletpass.js +235 -60
  30. package/dist/modules/Product/types.d.ts +23 -0
  31. package/dist/modules/ProductList/index.d.ts +15 -2
  32. package/dist/modules/ProductList/index.js +92 -13
  33. package/dist/modules/Rules/index.js +125 -52
  34. package/dist/modules/SalesSummary/index.d.ts +1 -0
  35. package/dist/modules/SalesSummary/index.js +4 -3
  36. package/dist/modules/SalesSummary/types.d.ts +1 -0
  37. package/dist/modules/SalesSummary/utils.d.ts +1 -0
  38. package/dist/modules/SalesSummary/utils.js +28 -2
  39. package/dist/server/index.d.ts +15 -0
  40. package/dist/server/index.js +894 -781
  41. package/dist/server/modules/order/index.d.ts +2 -0
  42. package/dist/server/modules/order/index.js +261 -96
  43. package/dist/server/modules/order/types.d.ts +1 -1
  44. package/dist/server/utils/small-ticket.js +2 -1
  45. package/dist/solution/BaseSales/index.d.ts +41 -7
  46. package/dist/solution/BaseSales/index.js +1405 -974
  47. package/dist/solution/BaseSales/utils/cartPromotion.js +26 -3
  48. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  49. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +79 -13
  50. package/dist/solution/BaseSales/utils.js +31 -20
  51. package/dist/solution/BookingByStep/index.d.ts +3 -3
  52. package/dist/solution/BookingTicket/index.d.ts +5 -1
  53. package/dist/solution/BookingTicket/index.js +221 -162
  54. package/dist/solution/BookingTicket/types.d.ts +3 -0
  55. package/dist/solution/BookingTicket/utils/addProductDecision.js +2 -1
  56. package/dist/solution/BookingTicket/utils/cartView.js +44 -32
  57. package/dist/solution/Sales/index.d.ts +1 -0
  58. package/dist/solution/Sales/index.js +16 -2
  59. package/dist/solution/ScanOrder/index.js +25 -64
  60. package/dist/solution/ScanOrder/utils.js +31 -20
  61. package/dist/solution/UnifiedBookingSales/index.d.ts +5 -4
  62. package/dist/solution/UnifiedBookingSales/index.js +51 -39
  63. package/lib/core/index.js +0 -1
  64. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  65. package/lib/model/strategy/adapter/dataVariant/evaluator.js +170 -7
  66. package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  67. package/lib/model/strategy/adapter/walletPass/evaluator.js +0 -2
  68. package/lib/model/strategy/adapter/walletPass/type.d.ts +5 -0
  69. package/lib/model/strategy/adapter/walletPass/utils.js +62 -11
  70. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +6 -1
  71. package/lib/modules/BookingContext/utils/productExtend.js +4 -3
  72. package/lib/modules/BookingContext/utils/timeSlices.js +18 -3
  73. package/lib/modules/Customer/index.d.ts +4 -0
  74. package/lib/modules/Customer/index.js +11 -0
  75. package/lib/modules/Customer/types.d.ts +2 -0
  76. package/lib/modules/Discount/index.d.ts +2 -0
  77. package/lib/modules/Discount/index.js +37 -3
  78. package/lib/modules/Discount/types.d.ts +11 -0
  79. package/lib/modules/Order/index.d.ts +32 -6
  80. package/lib/modules/Order/index.js +518 -148
  81. package/lib/modules/Order/types.d.ts +32 -4
  82. package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
  83. package/lib/modules/Order/utils/discountProductLineIdentity.js +170 -0
  84. package/lib/modules/Order/utils/virtualSettlement.d.ts +56 -0
  85. package/lib/modules/Order/utils/virtualSettlement.js +300 -0
  86. package/lib/modules/Order/utils.js +65 -21
  87. package/lib/modules/Payment/types.d.ts +2 -0
  88. package/lib/modules/Payment/utils.js +5 -1
  89. package/lib/modules/Payment/walletpass.d.ts +11 -0
  90. package/lib/modules/Payment/walletpass.js +198 -17
  91. package/lib/modules/Product/types.d.ts +23 -0
  92. package/lib/modules/ProductList/index.d.ts +15 -2
  93. package/lib/modules/ProductList/index.js +85 -3
  94. package/lib/modules/Rules/index.js +100 -20
  95. package/lib/modules/SalesSummary/index.d.ts +1 -0
  96. package/lib/modules/SalesSummary/index.js +10 -2
  97. package/lib/modules/SalesSummary/types.d.ts +1 -0
  98. package/lib/modules/SalesSummary/utils.d.ts +1 -0
  99. package/lib/modules/SalesSummary/utils.js +30 -2
  100. package/lib/server/index.d.ts +15 -0
  101. package/lib/server/index.js +105 -14
  102. package/lib/server/modules/order/index.d.ts +2 -0
  103. package/lib/server/modules/order/index.js +75 -5
  104. package/lib/server/modules/order/types.d.ts +1 -1
  105. package/lib/server/utils/small-ticket.js +1 -1
  106. package/lib/solution/BaseSales/index.d.ts +41 -7
  107. package/lib/solution/BaseSales/index.js +325 -39
  108. package/lib/solution/BaseSales/utils/cartPromotion.js +26 -2
  109. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  110. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +62 -12
  111. package/lib/solution/BaseSales/utils.js +29 -18
  112. package/lib/solution/BookingByStep/index.d.ts +3 -3
  113. package/lib/solution/BookingTicket/index.d.ts +5 -1
  114. package/lib/solution/BookingTicket/index.js +31 -6
  115. package/lib/solution/BookingTicket/types.d.ts +3 -0
  116. package/lib/solution/BookingTicket/utils/addProductDecision.js +2 -1
  117. package/lib/solution/BookingTicket/utils/cartView.js +43 -30
  118. package/lib/solution/Sales/index.d.ts +1 -0
  119. package/lib/solution/Sales/index.js +15 -3
  120. package/lib/solution/ScanOrder/index.js +17 -54
  121. package/lib/solution/ScanOrder/utils.js +29 -18
  122. package/lib/solution/UnifiedBookingSales/index.d.ts +5 -4
  123. package/lib/solution/UnifiedBookingSales/index.js +35 -26
  124. package/package.json +1 -1
@@ -366,9 +366,33 @@ function getProductLineNoteSignature(product) {
366
366
  const uid = getOrderProductUid(product);
367
367
  return uid ? `note:${uid}` : `note:${normalizedNote}`;
368
368
  }
369
+ function hasGoodPassDiscount(product) {
370
+ var _a, _b;
371
+ const productBundle = Array.isArray(product == null ? void 0 : product.product_bundle) ? product.product_bundle : [];
372
+ const extendedBundle = Array.isArray((_b = (_a = product == null ? void 0 : product._extend) == null ? void 0 : _a.other) == null ? void 0 : _b.bundle) ? product._extend.other.bundle : [];
373
+ const discountLists = [
374
+ product == null ? void 0 : product.discount_list,
375
+ ...productBundle.map((item) => item == null ? void 0 : item.discount_list),
376
+ ...extendedBundle.map((item) => item == null ? void 0 : item.discount_list)
377
+ ];
378
+ return discountLists.some(
379
+ (discountList) => Array.isArray(discountList) && discountList.some(
380
+ (item) => (item == null ? void 0 : item.type) === "good_pass" || (item == null ? void 0 : item.tag) === "good_pass"
381
+ )
382
+ );
383
+ }
369
384
  function getPromotionLineMergeBoundary(product) {
370
- var _a;
371
- if (((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.is_edit_for_runtime) !== true)
385
+ var _a, _b;
386
+ if ((product == null ? void 0 : product.product_id) === void 0 || (product == null ? void 0 : product.product_id) === null) {
387
+ return `custom:${getOrderProductUid(product)}`;
388
+ }
389
+ if (hasGoodPassDiscount(product)) {
390
+ return `good-pass:${getOrderProductUid(product)}`;
391
+ }
392
+ if (Number(((_a = product == null ? void 0 : product.product_sku) == null ? void 0 : _a.open_sold_weight) || 0) === 1) {
393
+ return `weighing:${getOrderProductUid(product)}`;
394
+ }
395
+ if (((_b = product == null ? void 0 : product.metadata) == null ? void 0 : _b.is_edit_for_runtime) !== true)
372
396
  return "";
373
397
  return `edit:${getOrderProductUid(product)}`;
374
398
  }
@@ -43,6 +43,7 @@ export interface BaseProductDetailPayload {
43
43
  original_price?: number | string;
44
44
  tax_fee?: number | string;
45
45
  is_charge_tax?: number;
46
+ metadata?: Record<string, any>;
46
47
  note?: string;
47
48
  [key: string]: any;
48
49
  }
@@ -56,6 +56,25 @@ function isBlankValue(value) {
56
56
  function firstNonBlank(...values) {
57
57
  return values.find((value) => !isBlankValue(value));
58
58
  }
59
+ function cloneFirstDataVariantIds(...values) {
60
+ const ids = values.find((value) => Array.isArray(value));
61
+ return Array.isArray(ids) ? [...ids] : void 0;
62
+ }
63
+ function appendDataVariantIds(base, ...values) {
64
+ const result = Array.isArray(base) ? [...base] : [];
65
+ const seen = new Set(result.map((id) => String(id)));
66
+ for (const value of values) {
67
+ const candidates = Array.isArray(value) ? value : [value];
68
+ for (const candidate of candidates) {
69
+ const id = Number(candidate);
70
+ if (!Number.isFinite(id) || id <= 0 || seen.has(String(id)))
71
+ continue;
72
+ result.push(id);
73
+ seen.add(String(id));
74
+ }
75
+ }
76
+ return Array.isArray(base) || result.length ? result : void 0;
77
+ }
59
78
  function normalizeOptionItems(optionItems) {
60
79
  if (!Array.isArray(optionItems))
61
80
  return [];
@@ -112,7 +131,7 @@ function findVariantById(origin, variantId) {
112
131
  return variants.find((variant) => Number(variant == null ? void 0 : variant.id) === variantId) || null;
113
132
  }
114
133
  function transformBaseProductToOrderProduct(params) {
115
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
134
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;
116
135
  const { payload, fallbackProductId = null } = params;
117
136
  if (!payload || typeof payload !== "object")
118
137
  return null;
@@ -131,6 +150,32 @@ function transformBaseProductToOrderProduct(params) {
131
150
  ...sourceProduct || {},
132
151
  ...callbackOrigin || {}
133
152
  };
153
+ const authoritativeDataVariantIds = cloneFirstDataVariantIds(
154
+ (_c = payload.metadata) == null ? void 0 : _c.data_variant_ids,
155
+ (_d = sourceProduct == null ? void 0 : sourceProduct.metadata) == null ? void 0 : _d.data_variant_ids,
156
+ (_e = callbackOrigin == null ? void 0 : callbackOrigin.metadata) == null ? void 0 : _e.data_variant_ids,
157
+ (_f = origin == null ? void 0 : origin.metadata) == null ? void 0 : _f.data_variant_ids
158
+ );
159
+ const selectedSettlementSnapshot = firstNonBlank(
160
+ payload.selected_settlement_snapshot,
161
+ (_g = payload.metadata) == null ? void 0 : _g.selected_settlement_snapshot,
162
+ (_i = (_h = payload._extend) == null ? void 0 : _h.metadata) == null ? void 0 : _i.selected_settlement_snapshot,
163
+ (_j = sourceProduct == null ? void 0 : sourceProduct.metadata) == null ? void 0 : _j.selected_settlement_snapshot,
164
+ (_l = (_k = sourceProduct == null ? void 0 : sourceProduct._extend) == null ? void 0 : _k.metadata) == null ? void 0 : _l.selected_settlement_snapshot,
165
+ (_m = callbackOrigin == null ? void 0 : callbackOrigin.metadata) == null ? void 0 : _m.selected_settlement_snapshot,
166
+ (_o = (_n = callbackOrigin == null ? void 0 : callbackOrigin._extend) == null ? void 0 : _n.metadata) == null ? void 0 : _o.selected_settlement_snapshot
167
+ );
168
+ const locallyAppliedVariantIds = authoritativeDataVariantIds === void 0 ? cloneFirstDataVariantIds(
169
+ (_p = payload._dataVariant) == null ? void 0 : _p.appliedVariantIds,
170
+ (_q = sourceProduct == null ? void 0 : sourceProduct._dataVariant) == null ? void 0 : _q.appliedVariantIds,
171
+ (_r = callbackOrigin == null ? void 0 : callbackOrigin._dataVariant) == null ? void 0 : _r.appliedVariantIds,
172
+ (_s = origin == null ? void 0 : origin._dataVariant) == null ? void 0 : _s.appliedVariantIds
173
+ ) : void 0;
174
+ const dataVariantIds = appendDataVariantIds(
175
+ authoritativeDataVariantIds,
176
+ locallyAppliedVariantIds,
177
+ selectedSettlementSnapshot == null ? void 0 : selectedSettlementSnapshot.data_variant_id
178
+ );
134
179
  const matchedVariant = findVariantById(callbackOrigin, productVariantId) ?? findVariantById(sourceProduct, productVariantId) ?? findVariantById(origin, productVariantId);
135
180
  const hasPriceOverride = payload.price_override !== void 0 && payload.price_override !== null && payload.price_override !== "";
136
181
  const catalogSourcePrice = (matchedVariant == null ? void 0 : matchedVariant.price) ?? (matchedVariant == null ? void 0 : matchedVariant.base_price) ?? (origin == null ? void 0 : origin.price) ?? (origin == null ? void 0 : origin.base_price) ?? (sourceProduct == null ? void 0 : sourceProduct.price) ?? (sourceProduct == null ? void 0 : sourceProduct.selling_price) ?? (sourceProduct == null ? void 0 : sourceProduct.base_price);
@@ -138,12 +183,12 @@ function transformBaseProductToOrderProduct(params) {
138
183
  hasPriceOverride ? catalogSourcePrice ?? payload.price ?? payload.selling_price : payload.price ?? payload.selling_price ?? catalogSourcePrice,
139
184
  "0.00"
140
185
  );
141
- const explicitLineTotal = payload.line_total ?? payload.total ?? ((_c = payload._extend) == null ? void 0 : _c.total);
186
+ const explicitLineTotal = payload.line_total ?? payload.total ?? ((_t = payload._extend) == null ? void 0 : _t.total);
142
187
  const hasExplicitLineTotal = Number.isFinite(Number(explicitLineTotal));
143
188
  const lineCompositeTotal = toPriceString(explicitLineTotal, sourceProductPrice);
144
189
  const productOptionItem = (0, import_utils.normalizeProductSkuOptions)(
145
190
  normalizeOptionItems(
146
- ((_d = payload.product_sku) == null ? void 0 : _d.option) ?? payload.option ?? payload.options ?? payload.product_option_item
191
+ ((_u = payload.product_sku) == null ? void 0 : _u.option) ?? payload.option ?? payload.options ?? payload.product_option_item
147
192
  )
148
193
  );
149
194
  const productBundle = normalizeBundleItems(
@@ -154,19 +199,19 @@ function transformBaseProductToOrderProduct(params) {
154
199
  const resolvedQuantity = toSafePositiveInt(payload.quantity ?? payload.num, 1);
155
200
  const originTotal = (0, import_manualProductDiscount.resolveManualDiscountOriginTotal)({
156
201
  originTotal: payload.origin_total,
157
- extendOriginTotal: (_e = payload._extend) == null ? void 0 : _e.origin_total,
158
- originExtendOriginTotal: (_f = origin == null ? void 0 : origin._extend) == null ? void 0 : _f.origin_total,
159
- sourceExtendOriginTotal: (_g = sourceProduct == null ? void 0 : sourceProduct._extend) == null ? void 0 : _g.origin_total,
202
+ extendOriginTotal: (_v = payload._extend) == null ? void 0 : _v.origin_total,
203
+ originExtendOriginTotal: (_w = origin == null ? void 0 : origin._extend) == null ? void 0 : _w.origin_total,
204
+ sourceExtendOriginTotal: (_x = sourceProduct == null ? void 0 : sourceProduct._extend) == null ? void 0 : _x.origin_total,
160
205
  catalogUnitPrice: (origin == null ? void 0 : origin.base_price) ?? (origin == null ? void 0 : origin.price) ?? (sourceProduct == null ? void 0 : sourceProduct.base_price) ?? (sourceProduct == null ? void 0 : sourceProduct.price),
161
206
  quantity: resolvedQuantity
162
207
  });
163
208
  const sellingTotal = Number(
164
- payload.line_total ?? payload.total ?? ((_h = payload._extend) == null ? void 0 : _h.total) ?? lineCompositeTotal
209
+ payload.line_total ?? payload.total ?? ((_y = payload._extend) == null ? void 0 : _y.total) ?? lineCompositeTotal
165
210
  );
166
211
  const discountReason = (0, import_manualProductDiscount.resolveManualDiscountReasonFromSources)({
167
212
  discountReason: payload.discount_reason,
168
- extendDiscountReason: (_i = payload._extend) == null ? void 0 : _i.discount_reason,
169
- originExtendDiscountReason: (_j = origin == null ? void 0 : origin._extend) == null ? void 0 : _j.discount_reason
213
+ extendDiscountReason: (_z = payload._extend) == null ? void 0 : _z.discount_reason,
214
+ originExtendDiscountReason: (_A = origin == null ? void 0 : origin._extend) == null ? void 0 : _A.discount_reason
170
215
  });
171
216
  const lineOriginalPrice = hasPriceOverride && Number.isFinite(originTotal) ? toPriceString(originTotal) : lineCompositeTotal;
172
217
  const manualDiscountList = (0, import_manualProductDiscount.shouldBuildManualProductDiscount)({
@@ -180,8 +225,8 @@ function transformBaseProductToOrderProduct(params) {
180
225
  sellingTotal: Number.isFinite(sellingTotal) ? sellingTotal : Number(lineCompositeTotal),
181
226
  quantity: resolvedQuantity,
182
227
  message: discountReason,
183
- discountway: (_k = payload._extend) == null ? void 0 : _k.discountway,
184
- discount_per: (_l = payload._extend) == null ? void 0 : _l.discount_per
228
+ discountway: (_B = payload._extend) == null ? void 0 : _B.discountway,
229
+ discount_per: (_C = payload._extend) == null ? void 0 : _C.discount_per
185
230
  })
186
231
  ) : payload.discount_list || [];
187
232
  const optionSum = (0, import_utils.sumOptionUnitPrice)(productOptionItem).toNumber();
@@ -206,6 +251,10 @@ function transformBaseProductToOrderProduct(params) {
206
251
  main_product_original_price: mainProductOriginalPrice,
207
252
  price_schema_version: 2,
208
253
  holder_config: sourceProduct == null ? void 0 : sourceProduct.holder_config,
254
+ ...dataVariantIds !== void 0 ? { data_variant_ids: dataVariantIds } : {},
255
+ ...selectedSettlementSnapshot ? {
256
+ selected_settlement_snapshot: selectedSettlementSnapshot
257
+ } : {},
209
258
  ...hasPriceOverride ? {
210
259
  price_override: String(payload.price_override),
211
260
  is_manual_discount: 1
@@ -217,7 +266,7 @@ function transformBaseProductToOrderProduct(params) {
217
266
  }
218
267
  const productTitle = {
219
268
  ...(sourceProduct == null ? void 0 : sourceProduct.title_i18n) || {},
220
- original: (sourceProduct == null ? void 0 : sourceProduct.title) || ""
269
+ original: (sourceProduct == null ? void 0 : sourceProduct.original_title) || (sourceProduct == null ? void 0 : sourceProduct.title) || ""
221
270
  };
222
271
  return {
223
272
  product_id: productId,
@@ -230,6 +279,7 @@ function transformBaseProductToOrderProduct(params) {
230
279
  },
231
280
  product_bundle: productBundle,
232
281
  discount_list: manualDiscountList,
282
+ ...payload.bundle_edit !== void 0 ? { bundle_edit: payload.bundle_edit } : {},
233
283
  // 折后行价由 normalizeOrderProduct 按 main + bundle 合成;手动改价时 bundle 已为分摊后单价
234
284
  selling_price: lineCompositeTotal,
235
285
  original_price: lineOriginalPrice,
@@ -60,33 +60,44 @@ function createEmptySummary() {
60
60
  };
61
61
  }
62
62
  function buildProductLineFingerprint(productOptionItem, productBundle) {
63
- const optArr = Array.isArray(productOptionItem) ? productOptionItem : [];
64
- const normalizedOpts = optArr.map((item) => ({
65
- option_group_item_id: Number(item == null ? void 0 : item.option_group_item_id) || 0,
66
- option_group_id: Number(item == null ? void 0 : item.option_group_id) || 0,
67
- num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
68
- price: String((item == null ? void 0 : item.add_price) ?? (item == null ? void 0 : item.price) ?? "")
69
- })).sort((p, q) => {
70
- if (p.option_group_item_id !== q.option_group_item_id) {
71
- return p.option_group_item_id - q.option_group_item_id;
72
- }
73
- if (p.option_group_id !== q.option_group_id)
74
- return p.option_group_id - q.option_group_id;
75
- if (p.num !== q.num)
76
- return p.num - q.num;
77
- return p.price.localeCompare(q.price);
78
- });
63
+ const normalizeOptions = (options) => {
64
+ const optionArr = Array.isArray(options) ? options : [];
65
+ return optionArr.map((item) => ({
66
+ option_group_item_id: Number(item == null ? void 0 : item.option_group_item_id) || 0,
67
+ option_group_id: Number(item == null ? void 0 : item.option_group_id) || 0,
68
+ num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
69
+ price: String((item == null ? void 0 : item.add_price) ?? (item == null ? void 0 : item.price) ?? "")
70
+ })).sort((p, q) => {
71
+ if (p.option_group_item_id !== q.option_group_item_id) {
72
+ return p.option_group_item_id - q.option_group_item_id;
73
+ }
74
+ if (p.option_group_id !== q.option_group_id) {
75
+ return p.option_group_id - q.option_group_id;
76
+ }
77
+ if (p.num !== q.num)
78
+ return p.num - q.num;
79
+ return p.price.localeCompare(q.price);
80
+ });
81
+ };
82
+ const normalizedOpts = normalizeOptions(productOptionItem);
79
83
  const bundleArr = Array.isArray(productBundle) ? productBundle : [];
80
84
  const normalizedBundles = bundleArr.map((item) => ({
81
85
  bundle_id: Number((item == null ? void 0 : item.bundle_id) ?? (item == null ? void 0 : item.id) ?? 0) || 0,
82
86
  product_id: Number(item == null ? void 0 : item.product_id) || 0,
83
- num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1
87
+ product_variant_id: Number((item == null ? void 0 : item.bundle_variant_id) ?? (item == null ? void 0 : item.product_variant_id)) || 0,
88
+ num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
89
+ option: normalizeOptions(item == null ? void 0 : item.option)
84
90
  })).sort((p, q) => {
85
91
  if (p.bundle_id !== q.bundle_id)
86
92
  return p.bundle_id - q.bundle_id;
87
93
  if (p.product_id !== q.product_id)
88
94
  return p.product_id - q.product_id;
89
- return p.num - q.num;
95
+ if (p.product_variant_id !== q.product_variant_id) {
96
+ return p.product_variant_id - q.product_variant_id;
97
+ }
98
+ if (p.num !== q.num)
99
+ return p.num - q.num;
100
+ return JSON.stringify(p.option).localeCompare(JSON.stringify(q.option));
90
101
  });
91
102
  return JSON.stringify([normalizedOpts, normalizedBundles]);
92
103
  }
@@ -67,7 +67,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
67
67
  product_ids?: number[];
68
68
  collection?: number | string[];
69
69
  schedule_date?: string;
70
- }): Promise<any>;
70
+ }): Promise<ProductData[]>;
71
71
  /**
72
72
  * 通过 schedule 来读取商品,适用于 session 类商品
73
73
  *
@@ -87,7 +87,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
87
87
  date: string;
88
88
  product_ids?: number[];
89
89
  category_ids?: number[];
90
- }): Promise<any>;
90
+ }): Promise<ProductData[]>;
91
91
  /**
92
92
  * 更新完商品数据、切换日期、或者在较后的流程里登录了,检测当前购物车里是否有商品,如果有,则需要更新购物车里的商品价格
93
93
  *
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
326
326
  date: string;
327
327
  status: string;
328
328
  week: string;
329
- weekNum: 0 | 5 | 2 | 1 | 6 | 4 | 3;
329
+ weekNum: 0 | 2 | 1 | 3 | 4 | 5 | 6;
330
330
  }[]>;
331
331
  submitTimeSlot(timeSlots: TimeSliceItem): void;
332
332
  private getScheduleDataByIds;
@@ -64,6 +64,8 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
64
64
  scanPromotionCode(code: string, customerId?: number): Promise<BaseSalesScanCodeResult>;
65
65
  private hydrateOrderCustomerFromScanDiscounts;
66
66
  private getDiscountCustomerId;
67
+ resolveCustomerById(customerId: string | number): Promise<ICustomer | null>;
68
+ /** 兼容既有优惠码扫码逻辑。 */
67
69
  private resolveCustomerByDiscountCustomerId;
68
70
  private findCustomerById;
69
71
  private normalizeCustomer;
@@ -126,7 +128,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
126
128
  loadProducts(params?: ILoadProductsParams, options?: {
127
129
  callback?: (result: any) => void;
128
130
  subscriberId?: string;
129
- }): Promise<any>;
131
+ }): Promise<ProductData[]>;
130
132
  /**
131
133
  * 获取加时商品列表。
132
134
  *
@@ -285,6 +287,8 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
285
287
  private buildOrderCustomerPayload;
286
288
  protected refreshDiscountConfigAfterOrderCustomerChange(customerId: number | null): Promise<void>;
287
289
  protected waitForOrderCustomerPromotionRefresh(): Promise<void>;
290
+ protected prepareProductPriceQueryContext(customerId?: number | string): Promise<void>;
291
+ protected preferAuthoritativeProductQueryPrice(): boolean;
288
292
  /**
289
293
  * 获取客户分页信息
290
294
  * @returns 分页信息
@@ -399,7 +399,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
399
399
  }
400
400
  return null;
401
401
  }
402
- async resolveCustomerByDiscountCustomerId(customerId) {
402
+ async resolveCustomerById(customerId) {
403
403
  var _a;
404
404
  const localCustomers = this.store.customer.getCustomers();
405
405
  const localCustomer = this.findCustomerById(localCustomers, customerId);
@@ -413,7 +413,23 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
413
413
  num: 1
414
414
  });
415
415
  const remoteCustomer = this.findCustomerById((result == null ? void 0 : result.list) || [], customerId) || ((_a = result == null ? void 0 : result.list) == null ? void 0 : _a[0]) || null;
416
- return remoteCustomer ? this.normalizeCustomer(remoteCustomer) : null;
416
+ if (remoteCustomer) {
417
+ return this.normalizeCustomer(remoteCustomer);
418
+ }
419
+ try {
420
+ const detailCustomer = await this.store.customer.queryCustomerDetail(customerId);
421
+ return detailCustomer ? this.normalizeCustomer(detailCustomer) : null;
422
+ } catch (error) {
423
+ console.warn(
424
+ "[BookingTicket] resolveCustomerById detail request failed",
425
+ { customerId, error }
426
+ );
427
+ return null;
428
+ }
429
+ }
430
+ /** 兼容既有优惠码扫码逻辑。 */
431
+ resolveCustomerByDiscountCustomerId(customerId) {
432
+ return this.resolveCustomerById(customerId);
417
433
  }
418
434
  findCustomerById(customers = [], customerId) {
419
435
  return customers.find((customer) => {
@@ -1020,6 +1036,18 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
1020
1036
  waitForOrderCustomerPromotionRefresh() {
1021
1037
  return this.orderCustomerPromotionRefreshInFlight || Promise.resolve();
1022
1038
  }
1039
+ async prepareProductPriceQueryContext(customerId) {
1040
+ await Promise.resolve();
1041
+ const normalizedCustomerId = Number(customerId || 0);
1042
+ const refreshTask = this.orderCustomerDiscountRefreshInFlight;
1043
+ const shouldWait = normalizedCustomerId > 1 && this.orderCustomerDiscountRefreshCustomerId === normalizedCustomerId && Boolean(refreshTask);
1044
+ if (shouldWait && refreshTask) {
1045
+ await refreshTask;
1046
+ }
1047
+ }
1048
+ preferAuthoritativeProductQueryPrice() {
1049
+ return true;
1050
+ }
1023
1051
  /**
1024
1052
  * 获取客户分页信息
1025
1053
  * @returns 分页信息
@@ -1599,10 +1627,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
1599
1627
  });
1600
1628
  }
1601
1629
  if (typeof this.store.order.addProductsToOrder === "function") {
1602
- return this.store.order.addProductsToOrder(orderLines, {
1603
- skipEditDiscountConfigRefresh: true,
1604
- skipDiscountRecalculation: true
1605
- });
1630
+ return this.store.order.addProductsToOrder(orderLines);
1606
1631
  }
1607
1632
  const result = [];
1608
1633
  for (const line of orderLines) {
@@ -118,12 +118,15 @@ export interface BookingTicketCartBookingView extends ISalesBooking {
118
118
  canAddTime: boolean;
119
119
  };
120
120
  }
121
+ export type BookingTicketCartLineView = BookingTicketCartBookingView | BookingTicketCartItemView;
121
122
  /**
122
123
  * BookingTicket 面向 UI 的购物车视图。
123
124
  */
124
125
  export interface BookingTicketCartView {
125
126
  bookings: BookingTicketCartBookingView[];
126
127
  items: BookingTicketCartItemView[];
128
+ /** 以 tempOrder.products 为唯一顺序真源的统一购物车行(旧到新)。 */
129
+ lines: BookingTicketCartLineView[];
127
130
  }
128
131
  /**
129
132
  * BookingTicket 面向 UI 的客户展示视图。
@@ -277,7 +277,7 @@ function transformDetailToProductAndBooking(cacheItem, ctx) {
277
277
  return { product: productInput, booking, cacheItem: preparedCacheItem };
278
278
  }
279
279
  function buildBasePayloadFromCacheItem(cacheItem, ctx) {
280
- var _a, _b, _c, _d;
280
+ var _a, _b, _c, _d, _e, _f;
281
281
  const other = ((_a = cacheItem == null ? void 0 : cacheItem._extend) == null ? void 0 : _a.other) || {};
282
282
  const quantity = (ctx == null ? void 0 : ctx.quantity) != null && ctx.quantity > 0 ? ctx.quantity : ((_b = cacheItem == null ? void 0 : cacheItem._extend) == null ? void 0 : _b.quantity) ?? 1;
283
283
  const resolvedPid = (cacheItem == null ? void 0 : cacheItem.product_id) ?? (cacheItem == null ? void 0 : cacheItem.id);
@@ -304,6 +304,7 @@ function buildBasePayloadFromCacheItem(cacheItem, ctx) {
304
304
  bundle_edit: extend == null ? void 0 : extend.bundle_edit,
305
305
  discount_reason: extend == null ? void 0 : extend.discount_reason,
306
306
  discount_list: cacheItem == null ? void 0 : cacheItem.discount_list,
307
+ selected_settlement_snapshot: ((_e = cacheItem == null ? void 0 : cacheItem.metadata) == null ? void 0 : _e.selected_settlement_snapshot) ?? ((_f = extend == null ? void 0 : extend.metadata) == null ? void 0 : _f.selected_settlement_snapshot),
307
308
  _extend: extend
308
309
  };
309
310
  }
@@ -86,29 +86,27 @@ function isGiftProductLine(line) {
86
86
  function buildCartView(lines, bookings, options = {}) {
87
87
  const productLines = Array.isArray(lines) ? lines : [];
88
88
  const bookingList = Array.isArray(bookings) ? bookings : [];
89
+ const childBookings = bookingList.filter((booking) => booking.parent_id !== 0);
90
+ const bookingsByProductUid = indexBookingsByProductUid(childBookings);
89
91
  const linesByUid = indexProductsByUid(productLines);
90
92
  const addTimeLinesByBookingUid = indexAddTimeProductsByBookingUid(productLines);
91
- const claimedUids = /* @__PURE__ */ new Set();
92
93
  const claimedAddTimeLines = /* @__PURE__ */ new Set();
93
- const cartBookings = bookingList.filter((booking) => booking.parent_id !== 0).reduce((acc, booking) => {
94
- const uid = booking == null ? void 0 : booking.product_uid;
94
+ childBookings.forEach((booking) => {
95
+ const bookingUid = getBookingUid(booking);
96
+ if (!bookingUid)
97
+ return;
98
+ (addTimeLinesByBookingUid[bookingUid] || []).forEach((line) => {
99
+ claimedAddTimeLines.add(line);
100
+ });
101
+ });
102
+ const claimedBookings = /* @__PURE__ */ new Set();
103
+ const cartBookings = [];
104
+ const items = [];
105
+ const orderedLines = [];
106
+ const buildBookingView = (booking, product) => {
95
107
  const bookingUid = getBookingUid(booking);
96
- let product = null;
97
- if (uid !== void 0 && uid !== null && uid !== "") {
98
- const key = String(uid);
99
- if (!claimedUids.has(key)) {
100
- const line = linesByUid[key];
101
- if (isGiftProductLine(line))
102
- return acc;
103
- if (line) {
104
- claimedUids.add(key);
105
- product = line;
106
- }
107
- }
108
- }
109
108
  const addTimeProduct = bookingUid ? addTimeLinesByBookingUid[bookingUid] || [] : [];
110
- addTimeProduct.forEach((line) => claimedAddTimeLines.add(line));
111
- acc.push({
109
+ return {
112
110
  ...booking,
113
111
  _extend: {
114
112
  product,
@@ -122,21 +120,36 @@ function buildCartView(lines, bookings, options = {}) {
122
120
  shopOpeningHours: options.shopOpeningHours
123
121
  })
124
122
  }
125
- });
126
- return acc;
127
- }, []);
128
- const items = productLines.filter((line) => {
123
+ };
124
+ };
125
+ productLines.forEach((line) => {
129
126
  var _a;
130
- if (isGiftProductLine(line))
131
- return false;
132
- if (claimedAddTimeLines.has(line))
133
- return false;
127
+ if (isGiftProductLine(line) || claimedAddTimeLines.has(line))
128
+ return;
134
129
  const uid = (_a = line.metadata) == null ? void 0 : _a.unique_identification_number;
135
- if (uid === void 0 || uid === null || uid === "")
136
- return true;
137
- return !claimedUids.has(String(uid));
130
+ const matchedBooking = uid === void 0 || uid === null || uid === "" ? void 0 : (bookingsByProductUid[String(uid)] || []).find(
131
+ (booking) => !claimedBookings.has(booking)
132
+ );
133
+ if (matchedBooking) {
134
+ claimedBookings.add(matchedBooking);
135
+ const bookingView = buildBookingView(matchedBooking, line);
136
+ cartBookings.push(bookingView);
137
+ orderedLines.push(bookingView);
138
+ return;
139
+ }
140
+ items.push(line);
141
+ orderedLines.push(line);
142
+ });
143
+ childBookings.forEach((booking) => {
144
+ if (claimedBookings.has(booking))
145
+ return;
146
+ const uid = booking == null ? void 0 : booking.product_uid;
147
+ const linkedProduct = uid === void 0 || uid === null || uid === "" ? null : linesByUid[String(uid)] || null;
148
+ if (isGiftProductLine(linkedProduct))
149
+ return;
150
+ cartBookings.push(buildBookingView(booking, null));
138
151
  });
139
- return { bookings: cartBookings, items };
152
+ return { bookings: cartBookings, items, lines: orderedLines };
140
153
  }
141
154
  function isWalkInCustomer(customer) {
142
155
  if (!customer)
@@ -95,6 +95,7 @@ export declare class SalesImpl extends BaseModule implements Module, SalesModule
95
95
  * 2) 若无 active,返回已超时且仍占用中的预约(允许并发多条)
96
96
  * 3) 若仍无,返回最近一组未来预约(同 start_time 的并发预约全部返回)
97
97
  * 4) 最后兜底返回一条(避免资源有历史预约时完全无反馈)
98
+ * - includeAllFuture 时,保留选中预约并返回当天全部后续预约;仅详情接口启用。
98
99
  */
99
100
  private pickBookingsForCurrentPoint;
100
101
  /**
@@ -316,8 +316,9 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
316
316
  * 2) 若无 active,返回已超时且仍占用中的预约(允许并发多条)
317
317
  * 3) 若仍无,返回最近一组未来预约(同 start_time 的并发预约全部返回)
318
318
  * 4) 最后兜底返回一条(避免资源有历史预约时完全无反馈)
319
+ * - includeAllFuture 时,保留选中预约并返回当天全部后续预约;仅详情接口启用。
319
320
  */
320
- pickBookingsForCurrentPoint(current, bookings) {
321
+ pickBookingsForCurrentPoint(current, bookings, options = {}) {
321
322
  if (bookings.length === 0)
322
323
  return [];
323
324
  const currentDayStart = current.startOf("day");
@@ -334,6 +335,13 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
334
335
  const appendNextStartGroupIfNeeded = (selectedBookings) => {
335
336
  if (selectedBookings.length === 0)
336
337
  return selectedBookings;
338
+ if (options.includeAllFuture) {
339
+ const allFutureBookings = dayScopedBookings.filter((booking) => {
340
+ const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
341
+ return startAt.isValid() && startAt.isAfter(current);
342
+ });
343
+ return [...selectedBookings, ...allFutureBookings];
344
+ }
337
345
  const shouldAppendNextGroup = selectedBookings.some(
338
346
  (booking) => booking.status === "reserved" || booking.status === "occupied"
339
347
  );
@@ -384,6 +392,8 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
384
392
  return startAt.isValid() && startAt.isAfter(current) && startAt.isSame(current, "day");
385
393
  });
386
394
  if (upcoming.length > 0) {
395
+ if (options.includeAllFuture)
396
+ return upcoming;
387
397
  const firstStartAt = this.toBookingDateTime(upcoming[0].start_date, upcoming[0].start_time).valueOf();
388
398
  const upcomingStartGroup = upcoming.filter((booking) => {
389
399
  const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
@@ -638,7 +648,8 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
638
648
  const unpaidBookingList = matchedBookingList.filter((booking) => this.isUnpaidBooking(booking));
639
649
  const bookings = this.pickBookingsForCurrentPoint(
640
650
  current,
641
- this.normalizeResourceBookings(current, deviceCurrent, matchedBookingList)
651
+ this.normalizeResourceBookings(current, deviceCurrent, matchedBookingList),
652
+ { includeAllFuture: true }
642
653
  );
643
654
  const completedBookings = completedBookingList.map((booking) => {
644
655
  return {
@@ -654,7 +665,8 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
654
665
  });
655
666
  const unpaidBookings = this.pickBookingsForCurrentPoint(
656
667
  current,
657
- this.normalizeResourceBookings(current, deviceCurrent, unpaidBookingList)
668
+ this.normalizeResourceBookings(current, deviceCurrent, unpaidBookingList),
669
+ { includeAllFuture: true }
658
670
  );
659
671
  const orderCount = this.countBookingOrders(statsBookingList);
660
672
  const bookingCount = statsBookingList.length;
@@ -1708,60 +1708,23 @@ var _ScanOrderImpl = class extends import_BaseSales.BaseSalesImpl {
1708
1708
  schedule_datetime: scheduleDatetime,
1709
1709
  cacheId: this.cacheId
1710
1710
  });
1711
- if (Array.isArray(loaded)) {
1712
- const matchedRuleProduct = (0, import_utils.findReservationRuleProductByResourceId)(
1713
- loaded,
1714
- normalizedResourceId
1715
- );
1716
- const ruleProductsForResource = matchedRuleProduct ? [matchedRuleProduct] : [];
1717
- this.enabledReservationRuleProducts = ruleProductsForResource;
1718
- const occupancyMinutes = (0, import_utils.pickFirstDurationMinutesFromProducts)(ruleProductsForResource);
1719
- if (occupancyMinutes !== void 0) {
1720
- tempOrder.metadata.table_occupancy_duration = occupancyMinutes;
1721
- }
1722
- if ((0, import_utils.hasCustomCapacityProduct)(ruleProductsForResource)) {
1723
- pendingRequestEntryPax = 1;
1724
- const paxBounds = (0, import_utils.pickFirstCustomCapacityPaxBounds)(ruleProductsForResource);
1725
- if ((paxBounds == null ? void 0 : paxBounds.min) !== void 0)
1726
- pendingRequestPaxMin = paxBounds.min;
1727
- if ((paxBounds == null ? void 0 : paxBounds.max) !== void 0)
1728
- pendingRequestPaxMax = paxBounds.max;
1729
- }
1730
- } else {
1731
- this.enabledReservationRuleProducts = [];
1732
- const error = loaded instanceof Error ? loaded : new Error("预约规则商品列表接口返回异常");
1733
- this.logMethodError("loadReservationRuleProducts", error, {
1734
- resourceId: normalizedResourceId,
1735
- reservationLinkIds,
1736
- scheduleDate,
1737
- scheduleDatetime,
1738
- cacheId: this.cacheId
1739
- });
1740
- if (Array.isArray(loaded)) {
1741
- this.enabledReservationRuleProducts = loaded;
1742
- const occupancyMinutes = (0, import_utils.pickFirstDurationMinutesFromProducts)(loaded);
1743
- if (occupancyMinutes !== void 0) {
1744
- tempOrder.metadata.table_occupancy_duration = occupancyMinutes;
1745
- }
1746
- if ((0, import_utils.hasCustomCapacityProduct)(loaded)) {
1747
- pendingRequestEntryPax = 1;
1748
- const paxBounds = (0, import_utils.pickFirstCustomCapacityPaxBounds)(loaded);
1749
- if ((paxBounds == null ? void 0 : paxBounds.min) !== void 0)
1750
- pendingRequestPaxMin = paxBounds.min;
1751
- if ((paxBounds == null ? void 0 : paxBounds.max) !== void 0)
1752
- pendingRequestPaxMax = paxBounds.max;
1753
- }
1754
- } else {
1755
- this.enabledReservationRuleProducts = [];
1756
- const error2 = loaded instanceof Error ? loaded : new Error("预约规则商品列表接口返回异常");
1757
- this.logMethodError("loadReservationRuleProducts", error2, {
1758
- resourceId,
1759
- reservationLinkIds,
1760
- scheduleDate,
1761
- scheduleDatetime,
1762
- cacheId: this.cacheId
1763
- });
1764
- }
1711
+ const matchedRuleProduct = (0, import_utils.findReservationRuleProductByResourceId)(
1712
+ loaded,
1713
+ normalizedResourceId
1714
+ );
1715
+ const ruleProductsForResource = matchedRuleProduct ? [matchedRuleProduct] : [];
1716
+ this.enabledReservationRuleProducts = ruleProductsForResource;
1717
+ const occupancyMinutes = (0, import_utils.pickFirstDurationMinutesFromProducts)(ruleProductsForResource);
1718
+ if (occupancyMinutes !== void 0) {
1719
+ tempOrder.metadata.table_occupancy_duration = occupancyMinutes;
1720
+ }
1721
+ if ((0, import_utils.hasCustomCapacityProduct)(ruleProductsForResource)) {
1722
+ pendingRequestEntryPax = 1;
1723
+ const paxBounds = (0, import_utils.pickFirstCustomCapacityPaxBounds)(ruleProductsForResource);
1724
+ if ((paxBounds == null ? void 0 : paxBounds.min) !== void 0)
1725
+ pendingRequestPaxMin = paxBounds.min;
1726
+ if ((paxBounds == null ? void 0 : paxBounds.max) !== void 0)
1727
+ pendingRequestPaxMax = paxBounds.max;
1765
1728
  }
1766
1729
  const occupyDetails = await this.fetchResourceOccupyDetailsByResourceId(normalizedResourceId);
1767
1730
  const occupyDetail = occupyDetails[0] ?? null;