@pisell/pisellos 2.1.130 → 2.1.131

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 (36) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  2. package/dist/modules/Order/index.d.ts +3 -6
  3. package/dist/modules/Order/index.js +119 -41
  4. package/dist/modules/Order/types.d.ts +23 -5
  5. package/dist/modules/Order/types.js +2 -0
  6. package/dist/modules/Order/utils.d.ts +66 -11
  7. package/dist/modules/Order/utils.js +281 -45
  8. package/dist/modules/SalesSummary/utils.js +33 -68
  9. package/dist/modules/ScanOrderLogger/providers/feishu.js +168 -60
  10. package/dist/modules/ScanOrderLogger/types.d.ts +6 -0
  11. package/dist/modules/Summary/utils.js +6 -21
  12. package/dist/solution/ScanOrder/index.d.ts +31 -6
  13. package/dist/solution/ScanOrder/index.js +1062 -498
  14. package/dist/solution/ScanOrder/types.d.ts +52 -2
  15. package/dist/solution/ScanOrder/types.js +16 -1
  16. package/dist/solution/ScanOrder/utils.d.ts +41 -5
  17. package/dist/solution/ScanOrder/utils.js +214 -33
  18. package/dist/solution/VenueBooking/index.d.ts +2 -5
  19. package/dist/solution/VenueBooking/index.js +35 -27
  20. package/lib/modules/Order/index.d.ts +3 -6
  21. package/lib/modules/Order/index.js +109 -30
  22. package/lib/modules/Order/types.d.ts +23 -5
  23. package/lib/modules/Order/utils.d.ts +66 -11
  24. package/lib/modules/Order/utils.js +181 -16
  25. package/lib/modules/SalesSummary/utils.js +13 -47
  26. package/lib/modules/ScanOrderLogger/providers/feishu.js +100 -34
  27. package/lib/modules/ScanOrderLogger/types.d.ts +6 -0
  28. package/lib/modules/Summary/utils.js +4 -18
  29. package/lib/solution/ScanOrder/index.d.ts +31 -6
  30. package/lib/solution/ScanOrder/index.js +315 -14
  31. package/lib/solution/ScanOrder/types.d.ts +52 -2
  32. package/lib/solution/ScanOrder/utils.d.ts +41 -5
  33. package/lib/solution/ScanOrder/utils.js +150 -20
  34. package/lib/solution/VenueBooking/index.d.ts +2 -5
  35. package/lib/solution/VenueBooking/index.js +13 -6
  36. package/package.json +1 -1
@@ -45,7 +45,7 @@ import { extractResourceIds, buildResourceProductMap } from "./utils/resource";
45
45
  import { buildTimeSlotGrid, isBusinessHoursCrossDay, generateTimeLabels } from "./utils/timeSlot";
46
46
  import { buildDateRangeSummary } from "./utils/dateSummary";
47
47
  import { mergeConsecutiveSlots, expandMergedSlotToIndividual, buildVenueIdentityKey, buildVenueBookingEntry, buildPriceBreakdown } from "./utils/slotMerge";
48
- import { createUuidV4 } from "../../modules/Order/utils";
48
+ import { composeLinePrice, createUuidV4, sumOptionUnitPrice } from "../../modules/Order/utils";
49
49
  import { OrderModule } from "../../modules/Order";
50
50
  import { RegisterAndLoginHooks } from "../RegisterAndLogin/types";
51
51
  import Decimal from 'decimal.js';
@@ -2027,7 +2027,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2027
2027
  key: "setDiscountSelected",
2028
2028
  value: (function () {
2029
2029
  var _setDiscountSelected = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee21(params) {
2030
- var _tempOrder$holder, _this$store$order$get, _this$store$order$get2, list, beforeTarget, updated, updatedTarget, tempOrder, orderStore, discountModule, rulesModule, holders, nextDiscountList, _tempOrder$holder2, result, beforeSelectedIds, _iterator13, _step13, d, selectedResourceIds, _iterator14, _step14, _product$_origin, product, totalPerUnitDiscount, newSellingPrice, afterApplyTarget, finalSummary, finalProduct, finalTarget;
2030
+ var _tempOrder$holder, _this$store$order$get, _this$store$order$get2, list, beforeTarget, updated, updatedTarget, tempOrder, orderStore, discountModule, rulesModule, holders, nextDiscountList, _tempOrder$holder2, result, beforeSelectedIds, _iterator13, _step13, d, selectedResourceIds, _iterator14, _step14, _product$_origin, _product$metadata$sou, _product$metadata3, _product$metadata4, _product$original_pri, product, totalPerUnitDiscount, optionSum, sourcePrice, newSourceSellingPrice, newMainSellingPrice, afterApplyTarget, finalSummary, finalProduct, finalTarget;
2031
2031
  return _regeneratorRuntime().wrap(function _callee21$(_context21) {
2032
2032
  while (1) switch (_context21.prev = _context21.next) {
2033
2033
  case 0:
@@ -2116,7 +2116,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2116
2116
  _iterator14.s();
2117
2117
  case 21:
2118
2118
  if ((_step14 = _iterator14.n()).done) {
2119
- _context21.next = 32;
2119
+ _context21.next = 35;
2120
2120
  break;
2121
2121
  }
2122
2122
  product = _step14.value;
@@ -2124,7 +2124,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2124
2124
  _context21.next = 25;
2125
2125
  break;
2126
2126
  }
2127
- return _context21.abrupt("continue", 30);
2127
+ return _context21.abrupt("continue", 33);
2128
2128
  case 25:
2129
2129
  // 1. 把 product.discount_list 和当前选中的 discount 对齐(剔除已取消的券)
2130
2130
  product.discount_list = (product.discount_list || []).filter(function (pd) {
@@ -2133,45 +2133,53 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2133
2133
  return rid != null && selectedResourceIds.has(rid);
2134
2134
  });
2135
2135
 
2136
- // 2. 以 original_price 为基准重算 selling_price
2136
+ // 2. 以 source_product_price 为券作用基准:券作用于 source(不含 option),
2137
+ // 再把 option 加回得到含 option 的 main_product_selling_price,最后合成 composite。
2137
2138
  totalPerUnitDiscount = (product.discount_list || []).reduce(function (sum, pd) {
2138
2139
  return sum + (pd.amount || 0);
2139
2140
  }, 0);
2140
- newSellingPrice = new Decimal(product.original_price || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
2141
- product.selling_price = newSellingPrice;
2141
+ optionSum = sumOptionUnitPrice(product.product_option_item);
2142
+ sourcePrice = (_product$metadata$sou = (_product$metadata3 = product.metadata) === null || _product$metadata3 === void 0 ? void 0 : _product$metadata3.source_product_price) !== null && _product$metadata$sou !== void 0 ? _product$metadata$sou : ((_product$metadata4 = product.metadata) === null || _product$metadata4 === void 0 ? void 0 : _product$metadata4.main_product_original_price) != null ? new Decimal(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : (_product$original_pri = product.original_price) !== null && _product$original_pri !== void 0 ? _product$original_pri : '0';
2143
+ newSourceSellingPrice = new Decimal(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
2144
+ newMainSellingPrice = new Decimal(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
2142
2145
  if (product.metadata) {
2143
- product.metadata.main_product_selling_price = newSellingPrice;
2146
+ product.metadata.main_product_selling_price = newMainSellingPrice;
2147
+ product.metadata.price_schema_version = 2;
2144
2148
  }
2145
- case 30:
2149
+ product.selling_price = composeLinePrice({
2150
+ mainPrice: newMainSellingPrice,
2151
+ bundle: product.product_bundle
2152
+ });
2153
+ case 33:
2146
2154
  _context21.next = 21;
2147
2155
  break;
2148
- case 32:
2149
- _context21.next = 37;
2156
+ case 35:
2157
+ _context21.next = 40;
2150
2158
  break;
2151
- case 34:
2152
- _context21.prev = 34;
2153
- _context21.t0 = _context21["catch"](19);
2154
- _iterator14.e(_context21.t0);
2155
2159
  case 37:
2156
2160
  _context21.prev = 37;
2157
- _iterator14.f();
2158
- return _context21.finish(37);
2161
+ _context21.t0 = _context21["catch"](19);
2162
+ _iterator14.e(_context21.t0);
2159
2163
  case 40:
2164
+ _context21.prev = 40;
2165
+ _iterator14.f();
2166
+ return _context21.finish(40);
2167
+ case 43:
2160
2168
  OrderModule.populateSavedAmounts(tempOrder.products, nextDiscountList);
2161
- _context21.next = 43;
2169
+ _context21.next = 46;
2162
2170
  return discountModule === null || discountModule === void 0 ? void 0 : discountModule.setDiscountList(nextDiscountList);
2163
- case 43:
2171
+ case 46:
2164
2172
  tempOrder.discount_list = (nextDiscountList || []).filter(function (d) {
2165
2173
  return d.isSelected;
2166
2174
  });
2167
2175
  afterApplyTarget = this.store.order.getDiscountList().find(function (d) {
2168
2176
  return d.id === params.discountId;
2169
2177
  }) || null;
2170
- _context21.next = 47;
2178
+ _context21.next = 50;
2171
2179
  return this.store.order.recalculateSummary({
2172
2180
  createIfMissing: true
2173
2181
  });
2174
- case 47:
2182
+ case 50:
2175
2183
  this.store.order.persistTempOrder();
2176
2184
  finalSummary = ((_this$store$order$get = this.store.order.getTempOrder()) === null || _this$store$order$get === void 0 ? void 0 : _this$store$order$get.summary) || null;
2177
2185
  finalProduct = ((_this$store$order$get2 = this.store.order.getTempOrder()) === null || _this$store$order$get2 === void 0 || (_this$store$order$get2 = _this$store$order$get2.products) === null || _this$store$order$get2 === void 0 ? void 0 : _this$store$order$get2[0]) || null;
@@ -2180,16 +2188,16 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2180
2188
  return d.id === params.discountId;
2181
2189
  }) || null;
2182
2190
  return _context21.abrupt("return", this.store.order.getDiscountList());
2183
- case 55:
2184
- _context21.prev = 55;
2191
+ case 58:
2192
+ _context21.prev = 58;
2185
2193
  _context21.t1 = _context21["catch"](1);
2186
2194
  this.logMethodError('setDiscountSelected', _context21.t1);
2187
2195
  throw _context21.t1;
2188
- case 59:
2196
+ case 62:
2189
2197
  case "end":
2190
2198
  return _context21.stop();
2191
2199
  }
2192
- }, _callee21, this, [[1, 55], [19, 34, 37, 40]]);
2200
+ }, _callee21, this, [[1, 58], [19, 37, 40, 43]]);
2193
2201
  }));
2194
2202
  function setDiscountSelected(_x15) {
2195
2203
  return _setDiscountSelected.apply(this, arguments);
@@ -2336,7 +2344,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2336
2344
  key: "addProductToOrder",
2337
2345
  value: function () {
2338
2346
  var _addProductToOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee25(product) {
2339
- var _product$metadata3, _product$product_vari2, quotationPrice, products;
2347
+ var _product$metadata5, _product$product_vari2, quotationPrice, products;
2340
2348
  return _regeneratorRuntime().wrap(function _callee25$(_context25) {
2341
2349
  while (1) switch (_context25.prev = _context25.next) {
2342
2350
  case 0:
@@ -2351,7 +2359,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2351
2359
  }
2352
2360
  throw new Error('order 模块未初始化');
2353
2361
  case 4:
2354
- if (!((_product$metadata3 = product.metadata) !== null && _product$metadata3 !== void 0 && _product$metadata3.venue_booking) && this.store.quotation && product.product_id != null) {
2362
+ if (!((_product$metadata5 = product.metadata) !== null && _product$metadata5 !== void 0 && _product$metadata5.venue_booking) && this.store.quotation && product.product_id != null) {
2355
2363
  quotationPrice = this.store.quotation.getPriceForProduct({
2356
2364
  productId: product.product_id,
2357
2365
  variantId: (_product$product_vari2 = product.product_variant_id) !== null && _product$product_vari2 !== void 0 ? _product$product_vari2 : undefined,
@@ -1,6 +1,6 @@
1
1
  import { Module, PisellCore, ModuleOptions } from '../../types';
2
2
  import { BaseModule } from '../BaseModule';
3
- import { OrderModuleAPI, CommitOrderParams, SubmitScanOrderParams, ScanOrderMoreParams, CheckoutOrderParams } from './types';
3
+ import { OrderModuleAPI, CommitOrderParams, SubmitScanOrderParams, ScanOrderMoreParams, CheckoutOrderParams, UpdateProductInOrderParams } from './types';
4
4
  import { CartItem } from '../Cart/types';
5
5
  import { type SubmitPayloadEnhancer } from './utils';
6
6
  import type { ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderSummary, ScanOrderTempOrder } from '../../solution/ScanOrder/types';
@@ -71,11 +71,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
71
71
  updateTempOrderBuzzer(buzzer: string): string;
72
72
  updateTempOrderContactsInfo(contactsInfo: any[]): any[];
73
73
  addProductToOrder(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
74
- updateProductInOrder(params: {
75
- product_id: number | null;
76
- product_variant_id: number;
77
- updates: Partial<ScanOrderOrderProduct>;
78
- }): Promise<ScanOrderOrderProduct[]>;
74
+ updateProductInOrder(params: UpdateProductInOrderParams): Promise<ScanOrderOrderProduct[]>;
79
75
  removeProductFromOrder(identity: ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
80
76
  submitTempOrder<T = any>(params?: {
81
77
  cacheId?: string;
@@ -119,3 +115,4 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
119
115
  getOrderInfoByRemote(order_id: number): Promise<any>;
120
116
  getLastOrderInfo(): Record<string, any> | undefined;
121
117
  }
118
+ export type { UpdateProductInOrderParams } from './types';
@@ -285,6 +285,31 @@ var OrderModule = class extends import_BaseModule.BaseModule {
285
285
  this.window.localStorage.removeItem(key);
286
286
  return;
287
287
  }
288
+ if (Array.isArray(parsedData.products)) {
289
+ for (let i = 0; i < parsedData.products.length; i++) {
290
+ const p = parsedData.products[i];
291
+ if (!p || typeof p !== "object")
292
+ continue;
293
+ if (!Array.isArray(p.product_option_item)) {
294
+ p.product_option_item = [];
295
+ }
296
+ if (!Array.isArray(p.product_bundle)) {
297
+ p.product_bundle = [];
298
+ }
299
+ const row = p;
300
+ if (typeof row.identity_key !== "string" || row.identity_key.length === 0) {
301
+ const newKey = (0, import_utils.createUuidV4)();
302
+ row.identity_key = newKey;
303
+ if (!row.metadata || typeof row.metadata !== "object") {
304
+ row.metadata = {};
305
+ }
306
+ if (!row.metadata.unique_identification_number) {
307
+ row.metadata.unique_identification_number = newKey;
308
+ }
309
+ }
310
+ parsedData.products[i] = (0, import_utils3.normalizeOrderProduct)(row);
311
+ }
312
+ }
288
313
  this.store.tempOrder = parsedData;
289
314
  } catch {
290
315
  (_b = (_a = this.window) == null ? void 0 : _a.localStorage) == null ? void 0 : _b.removeItem(key);
@@ -394,21 +419,57 @@ var OrderModule = class extends import_BaseModule.BaseModule {
394
419
  // ─── TempOrder: 商品 CRUD ───
395
420
  async addProductToOrder(product) {
396
421
  const tempOrder = this.ensureTempOrder();
397
- const normalizedProduct = (0, import_utils3.normalizeOrderProduct)(product);
398
- const productIndex = (0, import_utils3.getProductIdentityIndex)(
399
- tempOrder.products,
400
- normalizedProduct
401
- );
402
- if (productIndex === -1) {
403
- tempOrder.products.push(normalizedProduct);
422
+ const hasExplicitIdentityKey = typeof product.identity_key === "string" && product.identity_key.length > 0;
423
+ if (hasExplicitIdentityKey) {
424
+ const normalizedProduct = (0, import_utils3.normalizeOrderProduct)(product);
425
+ const productIndex = (0, import_utils3.getProductIdentityIndex)(
426
+ tempOrder.products,
427
+ normalizedProduct
428
+ );
429
+ if (productIndex === -1) {
430
+ tempOrder.products.push(normalizedProduct);
431
+ } else {
432
+ const targetProduct = tempOrder.products[productIndex];
433
+ tempOrder.products[productIndex] = {
434
+ ...targetProduct,
435
+ ...normalizedProduct,
436
+ num: (0, import_utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num),
437
+ _origin: normalizedProduct._origin || targetProduct._origin
438
+ };
439
+ }
404
440
  } else {
405
- const targetProduct = tempOrder.products[productIndex];
406
- tempOrder.products[productIndex] = {
407
- ...targetProduct,
408
- ...normalizedProduct,
409
- num: (0, import_utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num),
410
- _origin: normalizedProduct._origin || targetProduct._origin
411
- };
441
+ const incomingFingerprint = (0, import_utils3.buildProductLineFingerprint)(
442
+ product.product_option_item,
443
+ product.product_bundle
444
+ );
445
+ const matchedIndex = tempOrder.products.findIndex((item) => {
446
+ if (item.product_id !== product.product_id)
447
+ return false;
448
+ if (item.product_variant_id !== product.product_variant_id)
449
+ return false;
450
+ const existedFingerprint = (0, import_utils3.buildProductLineFingerprint)(
451
+ item.product_option_item,
452
+ item.product_bundle
453
+ );
454
+ return existedFingerprint === incomingFingerprint;
455
+ });
456
+ if (matchedIndex === -1) {
457
+ const normalizedProduct = (0, import_utils3.normalizeOrderProduct)(product);
458
+ tempOrder.products.push(normalizedProduct);
459
+ } else {
460
+ const targetProduct = tempOrder.products[matchedIndex];
461
+ const normalizedProduct = (0, import_utils3.normalizeOrderProduct)({
462
+ ...product,
463
+ identity_key: targetProduct.identity_key
464
+ });
465
+ tempOrder.products[matchedIndex] = {
466
+ ...targetProduct,
467
+ ...normalizedProduct,
468
+ identity_key: targetProduct.identity_key,
469
+ num: (0, import_utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num),
470
+ _origin: normalizedProduct._origin || targetProduct._origin
471
+ };
472
+ }
412
473
  }
413
474
  this.applyDiscount();
414
475
  await this.recalculateSummary({ createIfMissing: true });
@@ -416,12 +477,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
416
477
  return tempOrder.products;
417
478
  }
418
479
  async updateProductInOrder(params) {
419
- const { product_id, product_variant_id, updates } = params;
480
+ var _a, _b, _c;
481
+ const {
482
+ product_id,
483
+ product_variant_id,
484
+ updates,
485
+ identity_key,
486
+ product_option_item,
487
+ product_bundle
488
+ } = params;
420
489
  const tempOrder = this.ensureTempOrder();
421
- const productIndex = (0, import_utils3.getProductIdentityIndex)(tempOrder.products, {
490
+ const identityLookup = {
422
491
  product_id,
423
492
  product_variant_id
424
- });
493
+ };
494
+ if (identity_key !== void 0)
495
+ identityLookup.identity_key = identity_key;
496
+ if (product_option_item !== void 0)
497
+ identityLookup.product_option_item = product_option_item;
498
+ if (product_bundle !== void 0)
499
+ identityLookup.product_bundle = product_bundle;
500
+ const productIndex = (0, import_utils3.getProductIdentityIndex)(tempOrder.products, identityLookup);
425
501
  if (productIndex === -1) {
426
502
  throw new Error("[Order] 目标商品不存在,无法更新");
427
503
  }
@@ -433,7 +509,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
433
509
  product_variant_id
434
510
  };
435
511
  nextProduct.num = (0, import_utils3.getSafeProductNum)(nextProduct.num);
436
- tempOrder.products[productIndex] = nextProduct;
512
+ const callerUpdatesTopPrice = Object.prototype.hasOwnProperty.call(updates || {}, "selling_price") || Object.prototype.hasOwnProperty.call(updates || {}, "original_price");
513
+ const callerUpdatesMainMeta = ((_a = updates == null ? void 0 : updates.metadata) == null ? void 0 : _a.main_product_selling_price) !== void 0 || ((_b = updates == null ? void 0 : updates.metadata) == null ? void 0 : _b.main_product_original_price) !== void 0 || ((_c = updates == null ? void 0 : updates.metadata) == null ? void 0 : _c.source_product_price) !== void 0;
514
+ if (callerUpdatesTopPrice && !callerUpdatesMainMeta) {
515
+ const existedMeta = nextProduct.metadata || {};
516
+ nextProduct.metadata = { ...existedMeta };
517
+ delete nextProduct.metadata.source_product_price;
518
+ delete nextProduct.metadata.main_product_selling_price;
519
+ delete nextProduct.metadata.main_product_original_price;
520
+ delete nextProduct.metadata.price_schema_version;
521
+ }
522
+ tempOrder.products[productIndex] = (0, import_utils3.normalizeOrderProduct)(nextProduct);
437
523
  this.applyDiscount();
438
524
  await this.recalculateSummary({ createIfMissing: true });
439
525
  this.persistTempOrder();
@@ -441,18 +527,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
441
527
  }
442
528
  async removeProductFromOrder(identity) {
443
529
  const tempOrder = this.ensureTempOrder();
444
- const beforeProducts = tempOrder.products;
445
530
  tempOrder.products = tempOrder.products.filter(
446
531
  (item) => !(0, import_utils3.isIdentityMatch)(item, identity)
447
532
  );
448
- const removedByStrictIdentity = beforeProducts.length - tempOrder.products.length;
449
- if (removedByStrictIdentity === 0 && identity.identity_key) {
450
- tempOrder.products = tempOrder.products.filter((item) => {
451
- const isSameProduct = String(item.product_id) === String(identity.product_id) && String(item.product_variant_id) === String(identity.product_variant_id);
452
- const hasNoIdentityKey = !item.identity_key;
453
- return !(isSameProduct && hasNoIdentityKey);
454
- });
455
- }
456
533
  this.applyDiscount();
457
534
  await this.recalculateSummary({ createIfMissing: true });
458
535
  this.persistTempOrder();
@@ -474,7 +551,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
474
551
  });
475
552
  let result;
476
553
  if (tempOrder.order_id) {
477
- const products = (0, import_utils.formatV1Product)(payload.products);
554
+ const products = (0, import_utils.filterProductsForScanOrderMore)(payload.products);
478
555
  const moreResult = await this.scanOrderMore({
479
556
  query: {
480
557
  order_id: tempOrder.order_id,
@@ -700,7 +777,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
700
777
  async submitScanOrder(params) {
701
778
  const { url, query } = params;
702
779
  const fetchUrl = url || "/order/sales/checkout";
703
- return this.request.post(fetchUrl, query);
780
+ return this.request.post(fetchUrl, query, { customToast: () => {
781
+ } });
704
782
  }
705
783
  async scanOrderMore(params) {
706
784
  const { url, query } = params;
@@ -709,7 +787,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
709
787
  products: query.products,
710
788
  request_unique_idempotency_token: query.request_unique_idempotency_token
711
789
  };
712
- return this.request.put(fetchUrl, requestBody);
790
+ return this.request.put(fetchUrl, requestBody, { customToast: () => {
791
+ } });
713
792
  }
714
793
  // TODO 获取详情的接口
715
794
  async getOrderInfoByRemote(order_id) {
@@ -16,6 +16,15 @@ export interface OrderState {
16
16
  discount: DiscountModule | null;
17
17
  rules: RulesModule | null;
18
18
  }
19
+ /** 更新购物车行:仅传 SKU 时命中同 SKU 第一行;多行同 SKU 须传 identity_key / 选项指纹等 */
20
+ export interface UpdateProductInOrderParams {
21
+ product_id: number | null;
22
+ product_variant_id: number;
23
+ updates: Partial<ScanOrderOrderProduct>;
24
+ identity_key?: string;
25
+ product_option_item?: any[];
26
+ product_bundle?: any[];
27
+ }
19
28
  /**
20
29
  * 订单信息
21
30
  */
@@ -35,14 +44,27 @@ export interface SubmitScanOrderProduct {
35
44
  num: number;
36
45
  product_variant_id: number;
37
46
  product_option_item: any[];
47
+ /**
48
+ * 行 composite 券后单价。
49
+ * 公式:`metadata.main_product_selling_price` + Σ(bundle_selling_price × num)。
50
+ * 主商品(含 option、含主商品折扣)的单价存在 `metadata.main_product_selling_price`。
51
+ */
38
52
  selling_price: string;
53
+ /**
54
+ * 行 composite 券前单价。
55
+ * 公式:`metadata.main_product_original_price` + Σ(bundle 原价 × num)。
56
+ * 主商品(含 option、不含折扣)的单价存在 `metadata.main_product_original_price`。
57
+ */
39
58
  original_price: string;
59
+ /** 出站兼容字段,直接由 `selling_price` 派生,语义同 composite。 */
40
60
  payment_price: string;
41
61
  tax_fee: string;
42
62
  is_charge_tax: number;
43
63
  discount_list: any[];
44
64
  product_bundle: any[];
45
65
  metadata: Record<string, any>;
66
+ /** 商品行备注 */
67
+ note?: string;
46
68
  }
47
69
  export interface SubmitScanOrderSummary {
48
70
  product_quantity: number;
@@ -210,11 +232,7 @@ export interface OrderModuleAPI {
210
232
  updateTempOrderBuzzer: (buzzer: string) => string;
211
233
  updateTempOrderContactsInfo: (contactsInfo: any[]) => any[];
212
234
  addProductToOrder: (product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity) => Promise<ScanOrderOrderProduct[]>;
213
- updateProductInOrder: (params: {
214
- product_id: number | null;
215
- product_variant_id: number;
216
- updates: Partial<ScanOrderOrderProduct>;
217
- }) => Promise<ScanOrderOrderProduct[]>;
235
+ updateProductInOrder: (params: UpdateProductInOrderParams) => Promise<ScanOrderOrderProduct[]>;
218
236
  removeProductFromOrder: (identity: ScanOrderOrderProductIdentity) => Promise<ScanOrderOrderProduct[]>;
219
237
  persistTempOrder: () => void;
220
238
  submitTempOrder: <T = any>(params?: {
@@ -1,21 +1,66 @@
1
+ import Decimal from 'decimal.js';
1
2
  import { CartItem } from "../Cart";
2
3
  import type { ScanOrderSubmitPayload, ScanOrderSubmitProduct, ScanOrderSummary, ScanOrderTempOrder } from '../../solution/ScanOrder/types';
3
4
  import type { RulesParamsHooks } from '../Rules/types';
5
+ /**
6
+ * 把"含 option 的主商品单价"与 bundle 合成"单行 composite 单价"。
7
+ *
8
+ * 新语义 v2 约定:
9
+ * - `mainPrice` 必须是**已经包含 option 的主商品单价**(即 `metadata.main_product_selling_price`
10
+ * 或 `metadata.main_product_original_price`),option 价格不由本函数叠加。
11
+ * - 套餐价:Σ((bundle.bundle_selling_price ?? bundle.price) × (bundle.num ?? bundle.quantity ?? 1))
12
+ * 当 `useOriginalBundle=true` 时,改用 `bundle.original_price ?? bundle.product_price ?? bundle.price`。
13
+ * - 返回值:保留 2 位小数的字符串,方便直接写回 `selling_price` / `original_price` 字段。
14
+ *
15
+ * 被 `normalizeOrderProduct`、Rules setProduct 钩子、各 Solution 的 setDiscountSelected 共用,
16
+ * 保证合成逻辑单点来源。
17
+ */
18
+ export declare function composeLinePrice(params: {
19
+ mainPrice: string | number | null | undefined;
20
+ bundle?: Array<{
21
+ bundle_selling_price?: any;
22
+ price?: any;
23
+ num?: any;
24
+ quantity?: any;
25
+ original_price?: any;
26
+ product_price?: any;
27
+ }> | null;
28
+ useOriginalBundle?: boolean;
29
+ }): string;
30
+ /**
31
+ * 计算 option 单价合计:Σ(option.price × option.num)。
32
+ * 在新语义 v2 下,main_product_original_price = source_product_price + 本函数结果。
33
+ */
34
+ export declare function sumOptionUnitPrice(options?: Array<{
35
+ price?: any;
36
+ num?: any;
37
+ }> | null): Decimal;
4
38
  /**
5
39
  * OrderModule 默认 Rules 钩子工厂。
6
40
  *
7
- * 价格语义约定(订单域):
8
- * - `selling_price`:券后单品单价(实际成交单价)。初次加购 = `original_price`;券应用后由 Rules 引擎更新。
9
- * - `original_price`:券前单品单价(店铺售价)。不承载后台划线价语义。
10
- * - `payment_price`:已从内部字段移除;只在出站 payload 中由 `selling_price` 派生以兼容后端。
41
+ * 价格语义约定(订单域,v2 composite 口径):
42
+ * - `selling_price`:券后 **行 composite 单价**
43
+ * = `metadata.main_product_selling_price` + Σ(bundle_selling_price × num)。
44
+ * - `original_price`:券前 **行 composite 单价**
45
+ * = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
46
+ * - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
47
+ * 不含折扣。**权威源**。
48
+ * - `metadata.main_product_original_price` = source + Σ(option.price × option.num)(含 option、不含折扣)。
49
+ * - `metadata.main_product_selling_price` = main_original − 主商品券 per-unit amount(含 option、含折扣)。
50
+ * - `payment_price`:出站 payload 中由 `selling_price` 派生以兼容后端(composite)。
11
51
  *
12
- * Rules 钩子契约:
13
- * - `getProduct.total` = `selling_price × num`(当前成交总价)
14
- * - `getProduct.origin_total` = `original_price × num`(券前总价)
15
- * - `setProduct` 写回 `selling_price` 的优先级:
16
- * 1. `values.main_product_selling_price`(券应用分支,per-unit 券后主价)
17
- * 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
18
- * 3. `values.total / num`(仅当 Rules 只给出总价时的兜底)
52
+ * Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
53
+ * - `getProduct.price` / `getProduct.original_price` 回传 **source-level 主价**
54
+ * (`metadata.source_product_price`)。Rules 内部 `getProductTotalPrice` /
55
+ * `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
56
+ * - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
57
+ * total(source + option + bundle)对齐。
58
+ * - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
59
+ * 加回 Σoptions,重新合成含 option 的 main_product_* 并派生 composite。
60
+ * 优先级:
61
+ * 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
62
+ * 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
63
+ * 3. `values.total / num`(仅当 Rules 只给出总价时的兜底)
19
64
  *
20
65
  * 导出为纯函数方便单测直接驱动钩子,不依赖 OrderModule 实例。
21
66
  */
@@ -72,6 +117,15 @@ export declare function buildSubmitPayload(params: {
72
117
  type?: string;
73
118
  enhance?: SubmitPayloadEnhancer;
74
119
  }): ScanOrderSubmitPayload;
120
+ /** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
121
+ export declare function filterProductsForScanOrderMore(products: ScanOrderSubmitProduct[]): ScanOrderSubmitProduct[];
122
+ /**
123
+ * 历史 V1 加餐结构映射器。
124
+ *
125
+ * @deprecated 加餐(`PUT /order/order/product/:id`)已改为与正常 checkout 共用
126
+ * `ScanOrderSubmitProduct` 新结构(见 `OrderModule.submitTempOrder` 的加餐分支)。
127
+ * 本函数仅保留以兼容历史接入方,未来会移除。新代码请勿再调用。
128
+ */
75
129
  export declare function formatV1Product(products: ScanOrderSubmitProduct[]): {
76
130
  bundle: any[];
77
131
  key: number | null;
@@ -79,6 +133,7 @@ export declare function formatV1Product(products: ScanOrderSubmitProduct[]): {
79
133
  product_id: number | null;
80
134
  product_variant_id: number;
81
135
  num: number;
136
+ note: string;
82
137
  rowKey: number | null;
83
138
  session: null;
84
139
  unique: string;