@pisell/pisellos 0.0.509 → 0.0.511

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.
@@ -0,0 +1,9 @@
1
+ // 导出评估器
2
+ export { PromotionEvaluator } from "./evaluator";
3
+
4
+ // 导出适配器
5
+ export { PromotionAdapter } from "./adapter";
6
+ export { default } from "./adapter";
7
+
8
+ // 导出策略配置示例常量
9
+ export { X_ITEMS_FOR_Y_PRICE_STRATEGY, BUY_X_GET_Y_FREE_STRATEGY } from "./examples";
@@ -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';
@@ -1,10 +1,10 @@
1
- function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
- function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
3
1
  function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
4
2
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
5
- function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
6
3
  function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
7
4
  function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
5
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
6
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
7
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
8
8
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
9
9
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
10
10
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -25,10 +25,10 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
25
25
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
26
26
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
27
27
  import { BaseModule } from "../BaseModule";
28
- import { generateDuration, getAllDiscountList, mergeRelationForms, buildSubmitPayload, createDefaultTempOrder, createDefaultOrderRulesHooks, createEmptySummary, formatDateTime, filterProductsForScanOrderMore, formatV1Product, isTempOrder } from "./utils";
28
+ import { generateDuration, getAllDiscountList, mergeRelationForms, buildSubmitPayload, createDefaultTempOrder, createDefaultOrderRulesHooks, createEmptySummary, createUuidV4, formatDateTime, filterProductsForScanOrderMore, formatV1Product, isTempOrder } from "./utils";
29
29
  import { isNormalProduct } from "../Product/utils";
30
30
  import dayjs from 'dayjs';
31
- import { getProductIdentityIndex, getSafeProductNum, isIdentityMatch, normalizeOrderProduct } from "../../solution/ScanOrder/utils";
31
+ import { buildProductLineFingerprint, getProductIdentityIndex, getSafeProductNum, isIdentityMatch, normalizeOrderProduct } from "../../solution/ScanOrder/utils";
32
32
  import { DiscountModule } from "../Discount";
33
33
  import { RulesModule } from "../Rules";
34
34
  import { UnavailableReason } from "../Rules/types";
@@ -387,6 +387,40 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
387
387
  this.window.localStorage.removeItem(key);
388
388
  return;
389
389
  }
390
+ if (Array.isArray(parsedData.products)) {
391
+ var _iterator = _createForOfIteratorHelper(parsedData.products),
392
+ _step;
393
+ try {
394
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
395
+ var p = _step.value;
396
+ if (!p || _typeof(p) !== 'object') continue;
397
+ if (!Array.isArray(p.product_option_item)) {
398
+ p.product_option_item = [];
399
+ }
400
+ if (!Array.isArray(p.product_bundle)) {
401
+ p.product_bundle = [];
402
+ }
403
+ // 不透明 identity 契约:旧缓存里可能没有 identity_key,
404
+ // 此处统一回填 UUID 并同步 metadata.unique_identification_number,
405
+ // 避免升级后 UI 侧持有的 rowKey 找不到对应行。
406
+ var row = p;
407
+ if (typeof row.identity_key !== 'string' || row.identity_key.length === 0) {
408
+ var newKey = createUuidV4();
409
+ row.identity_key = newKey;
410
+ if (!row.metadata || _typeof(row.metadata) !== 'object') {
411
+ row.metadata = {};
412
+ }
413
+ if (!row.metadata.unique_identification_number) {
414
+ row.metadata.unique_identification_number = newKey;
415
+ }
416
+ }
417
+ }
418
+ } catch (err) {
419
+ _iterator.e(err);
420
+ } finally {
421
+ _iterator.f();
422
+ }
423
+ }
390
424
  this.store.tempOrder = parsedData;
391
425
  } catch (_unused2) {
392
426
  var _this$window;
@@ -591,31 +625,59 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
591
625
  key: "addProductToOrder",
592
626
  value: function () {
593
627
  var _addProductToOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7(product) {
594
- var tempOrder, normalizedProduct, productIndex, targetProduct;
628
+ var tempOrder, hasExplicitIdentityKey, normalizedProduct, productIndex, targetProduct, incomingFingerprint, matchedIndex, _normalizedProduct, _targetProduct, _normalizedProduct2;
595
629
  return _regeneratorRuntime().wrap(function _callee7$(_context7) {
596
630
  while (1) switch (_context7.prev = _context7.next) {
597
631
  case 0:
598
632
  tempOrder = this.ensureTempOrder();
599
- normalizedProduct = normalizeOrderProduct(product);
600
- productIndex = getProductIdentityIndex(tempOrder.products, normalizedProduct);
601
- if (productIndex === -1) {
602
- tempOrder.products.push(normalizedProduct);
633
+ hasExplicitIdentityKey = typeof product.identity_key === 'string' && product.identity_key.length > 0;
634
+ if (hasExplicitIdentityKey) {
635
+ // 调用方自持 identity_key(如 VenueBooking 外部生成)→ 走严格 identity 合并。
636
+ normalizedProduct = normalizeOrderProduct(product);
637
+ productIndex = getProductIdentityIndex(tempOrder.products, normalizedProduct);
638
+ if (productIndex === -1) {
639
+ tempOrder.products.push(normalizedProduct);
640
+ } else {
641
+ targetProduct = tempOrder.products[productIndex];
642
+ tempOrder.products[productIndex] = _objectSpread(_objectSpread(_objectSpread({}, targetProduct), normalizedProduct), {}, {
643
+ num: getSafeProductNum(targetProduct.num + normalizedProduct.num),
644
+ _origin: normalizedProduct._origin || targetProduct._origin
645
+ });
646
+ }
603
647
  } else {
604
- targetProduct = tempOrder.products[productIndex];
605
- tempOrder.products[productIndex] = _objectSpread(_objectSpread(_objectSpread({}, targetProduct), normalizedProduct), {}, {
606
- num: getSafeProductNum(targetProduct.num + normalizedProduct.num),
607
- _origin: normalizedProduct._origin || targetProduct._origin
648
+ // identity_key:按 SKU + 内容指纹(options + bundle)匹配既有行以累加数量;
649
+ // 命中时保留已有 identity_key,未命中才由 normalizeOrderProduct 自动生成 UUID。
650
+ incomingFingerprint = buildProductLineFingerprint(product.product_option_item, product.product_bundle);
651
+ matchedIndex = tempOrder.products.findIndex(function (item) {
652
+ if (item.product_id !== product.product_id) return false;
653
+ if (item.product_variant_id !== product.product_variant_id) return false;
654
+ var existedFingerprint = buildProductLineFingerprint(item.product_option_item, item.product_bundle);
655
+ return existedFingerprint === incomingFingerprint;
608
656
  });
657
+ if (matchedIndex === -1) {
658
+ _normalizedProduct = normalizeOrderProduct(product);
659
+ tempOrder.products.push(_normalizedProduct);
660
+ } else {
661
+ _targetProduct = tempOrder.products[matchedIndex];
662
+ _normalizedProduct2 = normalizeOrderProduct(_objectSpread(_objectSpread({}, product), {}, {
663
+ identity_key: _targetProduct.identity_key
664
+ }));
665
+ tempOrder.products[matchedIndex] = _objectSpread(_objectSpread(_objectSpread({}, _targetProduct), _normalizedProduct2), {}, {
666
+ identity_key: _targetProduct.identity_key,
667
+ num: getSafeProductNum(_targetProduct.num + _normalizedProduct2.num),
668
+ _origin: _normalizedProduct2._origin || _targetProduct._origin
669
+ });
670
+ }
609
671
  }
610
672
  this.applyDiscount();
611
- _context7.next = 7;
673
+ _context7.next = 6;
612
674
  return this.recalculateSummary({
613
675
  createIfMissing: true
614
676
  });
615
- case 7:
677
+ case 6:
616
678
  this.persistTempOrder();
617
679
  return _context7.abrupt("return", tempOrder.products);
618
- case 9:
680
+ case 8:
619
681
  case "end":
620
682
  return _context7.stop();
621
683
  }
@@ -630,22 +692,26 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
630
692
  key: "updateProductInOrder",
631
693
  value: function () {
632
694
  var _updateProductInOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee8(params) {
633
- var product_id, product_variant_id, updates, tempOrder, productIndex, targetProduct, nextProduct;
695
+ var product_id, product_variant_id, updates, identity_key, product_option_item, product_bundle, tempOrder, identityLookup, productIndex, targetProduct, nextProduct;
634
696
  return _regeneratorRuntime().wrap(function _callee8$(_context8) {
635
697
  while (1) switch (_context8.prev = _context8.next) {
636
698
  case 0:
637
- product_id = params.product_id, product_variant_id = params.product_variant_id, updates = params.updates;
699
+ product_id = params.product_id, product_variant_id = params.product_variant_id, updates = params.updates, identity_key = params.identity_key, product_option_item = params.product_option_item, product_bundle = params.product_bundle;
638
700
  tempOrder = this.ensureTempOrder();
639
- productIndex = getProductIdentityIndex(tempOrder.products, {
701
+ identityLookup = {
640
702
  product_id: product_id,
641
703
  product_variant_id: product_variant_id
642
- });
704
+ };
705
+ if (identity_key !== undefined) identityLookup.identity_key = identity_key;
706
+ if (product_option_item !== undefined) identityLookup.product_option_item = product_option_item;
707
+ if (product_bundle !== undefined) identityLookup.product_bundle = product_bundle;
708
+ productIndex = getProductIdentityIndex(tempOrder.products, identityLookup);
643
709
  if (!(productIndex === -1)) {
644
- _context8.next = 5;
710
+ _context8.next = 9;
645
711
  break;
646
712
  }
647
713
  throw new Error('[Order] 目标商品不存在,无法更新');
648
- case 5:
714
+ case 9:
649
715
  targetProduct = tempOrder.products[productIndex];
650
716
  nextProduct = _objectSpread(_objectSpread(_objectSpread({}, targetProduct), updates), {}, {
651
717
  product_id: product_id,
@@ -654,14 +720,14 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
654
720
  nextProduct.num = getSafeProductNum(nextProduct.num);
655
721
  tempOrder.products[productIndex] = nextProduct;
656
722
  this.applyDiscount();
657
- _context8.next = 12;
723
+ _context8.next = 16;
658
724
  return this.recalculateSummary({
659
725
  createIfMissing: true
660
726
  });
661
- case 12:
727
+ case 16:
662
728
  this.persistTempOrder();
663
729
  return _context8.abrupt("return", tempOrder.products);
664
- case 14:
730
+ case 18:
665
731
  case "end":
666
732
  return _context8.stop();
667
733
  }
@@ -676,32 +742,23 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
676
742
  key: "removeProductFromOrder",
677
743
  value: function () {
678
744
  var _removeProductFromOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee9(identity) {
679
- var tempOrder, beforeProducts, removedByStrictIdentity;
745
+ var tempOrder;
680
746
  return _regeneratorRuntime().wrap(function _callee9$(_context9) {
681
747
  while (1) switch (_context9.prev = _context9.next) {
682
748
  case 0:
683
749
  tempOrder = this.ensureTempOrder();
684
- beforeProducts = tempOrder.products;
685
750
  tempOrder.products = tempOrder.products.filter(function (item) {
686
751
  return !isIdentityMatch(item, identity);
687
752
  });
688
- removedByStrictIdentity = beforeProducts.length - tempOrder.products.length;
689
- if (removedByStrictIdentity === 0 && identity.identity_key) {
690
- tempOrder.products = tempOrder.products.filter(function (item) {
691
- var isSameProduct = String(item.product_id) === String(identity.product_id) && String(item.product_variant_id) === String(identity.product_variant_id);
692
- var hasNoIdentityKey = !item.identity_key;
693
- return !(isSameProduct && hasNoIdentityKey);
694
- });
695
- }
696
753
  this.applyDiscount();
697
- _context9.next = 8;
754
+ _context9.next = 5;
698
755
  return this.recalculateSummary({
699
756
  createIfMissing: true
700
757
  });
701
- case 8:
758
+ case 5:
702
759
  this.persistTempOrder();
703
760
  return _context9.abrupt("return", tempOrder.products);
704
- case 10:
761
+ case 7:
705
762
  case "end":
706
763
  return _context9.stop();
707
764
  }
@@ -1135,46 +1192,46 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
1135
1192
  */
1136
1193
  function populateSavedAmounts(productList, discountList) {
1137
1194
  var savedMap = new Map();
1138
- var _iterator = _createForOfIteratorHelper(productList),
1139
- _step;
1195
+ var _iterator2 = _createForOfIteratorHelper(productList),
1196
+ _step2;
1140
1197
  try {
1141
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
1142
- var product = _step.value;
1198
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1199
+ var product = _step2.value;
1143
1200
  var qty = product.num || 1;
1144
- var _iterator3 = _createForOfIteratorHelper(product.discount_list || []),
1145
- _step3;
1201
+ var _iterator4 = _createForOfIteratorHelper(product.discount_list || []),
1202
+ _step4;
1146
1203
  try {
1147
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1204
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
1148
1205
  var _pd$discount, _pd$metadata;
1149
- var pd = _step3.value;
1206
+ var pd = _step4.value;
1150
1207
  var discountKey = ((_pd$discount = pd.discount) === null || _pd$discount === void 0 ? void 0 : _pd$discount.resource_id) || pd.id;
1151
1208
  if (discountKey == null) continue;
1152
1209
  var amount = new Decimal(pd.amount || 0).times(qty).plus(((_pd$metadata = pd.metadata) === null || _pd$metadata === void 0 ? void 0 : _pd$metadata.product_discount_difference) || 0);
1153
1210
  savedMap.set(discountKey, (savedMap.get(discountKey) || new Decimal(0)).plus(amount));
1154
1211
  }
1155
1212
  } catch (err) {
1156
- _iterator3.e(err);
1213
+ _iterator4.e(err);
1157
1214
  } finally {
1158
- _iterator3.f();
1215
+ _iterator4.f();
1159
1216
  }
1160
1217
  }
1161
1218
  } catch (err) {
1162
- _iterator.e(err);
1219
+ _iterator2.e(err);
1163
1220
  } finally {
1164
- _iterator.f();
1221
+ _iterator2.f();
1165
1222
  }
1166
- var _iterator2 = _createForOfIteratorHelper(discountList),
1167
- _step2;
1223
+ var _iterator3 = _createForOfIteratorHelper(discountList),
1224
+ _step3;
1168
1225
  try {
1169
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1170
- var d = _step2.value;
1226
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1227
+ var d = _step3.value;
1171
1228
  var key = d.id;
1172
1229
  d.savedAmount = d.isSelected && key != null && savedMap.has(key) ? savedMap.get(key).toNumber() : 0;
1173
1230
  }
1174
1231
  } catch (err) {
1175
- _iterator2.e(err);
1232
+ _iterator3.e(err);
1176
1233
  } finally {
1177
- _iterator2.f();
1234
+ _iterator3.f();
1178
1235
  }
1179
1236
  }
1180
1237
  }]);
@@ -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
  */
@@ -43,6 +52,8 @@ export interface SubmitScanOrderProduct {
43
52
  discount_list: any[];
44
53
  product_bundle: any[];
45
54
  metadata: Record<string, any>;
55
+ /** 商品行备注 */
56
+ note?: string;
46
57
  }
47
58
  export interface SubmitScanOrderSummary {
48
59
  product_quantity: number;
@@ -210,11 +221,7 @@ export interface OrderModuleAPI {
210
221
  updateTempOrderBuzzer: (buzzer: string) => string;
211
222
  updateTempOrderContactsInfo: (contactsInfo: any[]) => any[];
212
223
  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[]>;
224
+ updateProductInOrder: (params: UpdateProductInOrderParams) => Promise<ScanOrderOrderProduct[]>;
218
225
  removeProductFromOrder: (identity: ScanOrderOrderProductIdentity) => Promise<ScanOrderOrderProduct[]>;
219
226
  persistTempOrder: () => void;
220
227
  submitTempOrder: <T = any>(params?: {
@@ -6,6 +6,8 @@ export var OrderHooks = /*#__PURE__*/function (OrderHooks) {
6
6
  return OrderHooks;
7
7
  }({});
8
8
 
9
+ /** 更新购物车行:仅传 SKU 时命中同 SKU 第一行;多行同 SKU 须传 identity_key / 选项指纹等 */
10
+
9
11
  /**
10
12
  * 订单信息
11
13
  */
@@ -81,6 +81,7 @@ export declare function formatV1Product(products: ScanOrderSubmitProduct[]): {
81
81
  product_id: number | null;
82
82
  product_variant_id: number;
83
83
  num: number;
84
+ note: string;
84
85
  rowKey: number | null;
85
86
  session: null;
86
87
  unique: string;
@@ -18,7 +18,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
18
18
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
19
19
  import dayjs from "dayjs";
20
20
  import Decimal from 'decimal.js';
21
- import { createEmptySummary } from "../../solution/ScanOrder/utils";
21
+ import { buildProductLineFingerprint, createEmptySummary } from "../../solution/ScanOrder/utils";
22
22
  /**
23
23
  * OrderModule 默认 Rules 钩子工厂。
24
24
  *
@@ -47,7 +47,11 @@ export function createDefaultOrderRulesHooks() {
47
47
  var _product$_origin, _product$_origin2, _product$_origin3, _product$_origin4;
48
48
  return {
49
49
  id: product.product_id,
50
- _id: product.identity_key ? "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(product.identity_key) : "".concat(product.product_id, "_").concat(product.product_variant_id),
50
+ // Rules 引擎用 _id 作为 processedProductsMap 键;必须与购物车行级 identity 一致,
51
+ // 否则同 SKU 不同小料会在 calcDiscount 重组时互相覆盖。
52
+ // 不透明 identity 契约下,normalizeOrderProduct / restoreTempOrderFromStorage 已保证 identity_key 必存在;
53
+ // 留 fingerprint 分支仅作 Rules 单测里直接传裸 product 时的兜底。
54
+ _id: product.identity_key ? "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(product.identity_key) : "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(buildProductLineFingerprint(product.product_option_item, product.product_bundle)),
51
55
  price: product.selling_price,
52
56
  total: new Decimal(product.selling_price || 0).times(product.num || 1).toNumber(),
53
57
  origin_total: new Decimal(product.original_price || product.selling_price || 0).times(product.num || 1).toNumber(),
@@ -168,6 +172,29 @@ export function formatDateTime(date) {
168
172
  function normalizeSubmitPlatform(platform) {
169
173
  return (platform === null || platform === void 0 ? void 0 : platform.toLowerCase()) === 'pc' ? 'PC' : 'H5';
170
174
  }
175
+
176
+ // 出站重命名:后端 checkout 协议字段 option_group_item_id;
177
+ // tempOrder / UI 运行时一律使用 product_option_item_id。仅保留后端契约字段,
178
+ // 与 src/modules/Cart/utils/cartProduct.ts#formatOptionsToOrigin 形状一致。
179
+ function formatSubmitOptionItems(options) {
180
+ if (!Array.isArray(options)) return [];
181
+ return options.map(function (d) {
182
+ var _d$option_group_item_;
183
+ return {
184
+ num: d === null || d === void 0 ? void 0 : d.num,
185
+ option_group_item_id: (_d$option_group_item_ = d === null || d === void 0 ? void 0 : d.option_group_item_id) !== null && _d$option_group_item_ !== void 0 ? _d$option_group_item_ : d === null || d === void 0 ? void 0 : d.product_option_item_id,
186
+ option_group_id: d === null || d === void 0 ? void 0 : d.option_group_id
187
+ };
188
+ });
189
+ }
190
+ function formatSubmitBundleItems(bundle) {
191
+ if (!Array.isArray(bundle)) return [];
192
+ return bundle.map(function (b) {
193
+ return _objectSpread(_objectSpread({}, b), {}, {
194
+ option: formatSubmitOptionItems(b === null || b === void 0 ? void 0 : b.option)
195
+ });
196
+ });
197
+ }
171
198
  function normalizeSubmitProduct(product) {
172
199
  var _origin = product._origin,
173
200
  identity_key = product.identity_key,
@@ -194,9 +221,9 @@ function normalizeSubmitProduct(product) {
194
221
  return _objectSpread(_objectSpread(_objectSpread({}, submitProduct), bookingUid ? {
195
222
  booking_uid: bookingUid
196
223
  } : {}), {}, {
197
- product_option_item: submitProduct.product_option_item || [],
224
+ product_option_item: formatSubmitOptionItems(submitProduct.product_option_item),
198
225
  discount_list: submitProduct.discount_list || [],
199
- product_bundle: submitProduct.product_bundle || [],
226
+ product_bundle: formatSubmitBundleItems(submitProduct.product_bundle),
200
227
  metadata: cleanMetadata,
201
228
  // 出站兼容:后端仍消费 payment_price 字段,从 selling_price(券后单价)派生。
202
229
  payment_price: submitProduct.selling_price
@@ -400,6 +427,7 @@ export function filterProductsForScanOrderMore(products) {
400
427
  }
401
428
  export function formatV1Product(products) {
402
429
  return products.map(function (product) {
430
+ var _product$note;
403
431
  return {
404
432
  bundle: product.product_bundle,
405
433
  key: product.product_id,
@@ -407,6 +435,7 @@ export function formatV1Product(products) {
407
435
  product_id: product.product_id,
408
436
  product_variant_id: product.product_variant_id,
409
437
  num: product.num,
438
+ note: String((_product$note = product.note) !== null && _product$note !== void 0 ? _product$note : ''),
410
439
  rowKey: product.product_id,
411
440
  session: null,
412
441
  unique: createUuidV4()
@@ -1,6 +1,7 @@
1
1
  import { Module, ModuleOptions, PisellCore } from '../../types';
2
2
  import { BaseModule } from '../../modules/BaseModule';
3
3
  import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderScanCodeResult } from './types';
4
+ import type { UpdateProductInOrderParams } from '../../modules/Order/types';
4
5
  import type { Discount } from '../../modules/Discount/types';
5
6
  import { type CartItemSummary, type PaxInfo, type QuantityCheckResult, type QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
6
7
  import type { StrategyConfig } from '../../model/strategy/type';
@@ -85,11 +86,12 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
85
86
  private buildSubmitPayloadEnhancer;
86
87
  submitScanOrder<T = any>(): Promise<T>;
87
88
  addProductToOrder(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
88
- updateProductInOrder(params: {
89
- product_id: number | null;
90
- product_variant_id: number;
91
- updates: Partial<ScanOrderOrderProduct>;
92
- }): Promise<ScanOrderOrderProduct[]>;
89
+ updateProductInOrder(params: UpdateProductInOrderParams): Promise<ScanOrderOrderProduct[]>;
90
+ /**
91
+ * 设置单行商品备注(与整单 `updateTempOrderNote` 区分)。
92
+ * 多行同 SKU 时必须传入与删除/更新一致的 identity(如 `identity_key`)。
93
+ */
94
+ setOrderProductLineNote(identity: ScanOrderOrderProductIdentity, note: string): Promise<ScanOrderOrderProduct[]>;
93
95
  removeProductFromOrder(identity: ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
94
96
  private loadRuntimeConfigs;
95
97
  private syncItemRuleConfigsFromDineInConfig;