@pisell/pisellos 0.0.510 → 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';
@@ -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";
@@ -400,6 +400,20 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
400
400
  if (!Array.isArray(p.product_bundle)) {
401
401
  p.product_bundle = [];
402
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
+ }
403
417
  }
404
418
  } catch (err) {
405
419
  _iterator.e(err);
@@ -611,31 +625,59 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
611
625
  key: "addProductToOrder",
612
626
  value: function () {
613
627
  var _addProductToOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7(product) {
614
- var tempOrder, normalizedProduct, productIndex, targetProduct;
628
+ var tempOrder, hasExplicitIdentityKey, normalizedProduct, productIndex, targetProduct, incomingFingerprint, matchedIndex, _normalizedProduct, _targetProduct, _normalizedProduct2;
615
629
  return _regeneratorRuntime().wrap(function _callee7$(_context7) {
616
630
  while (1) switch (_context7.prev = _context7.next) {
617
631
  case 0:
618
632
  tempOrder = this.ensureTempOrder();
619
- normalizedProduct = normalizeOrderProduct(product);
620
- productIndex = getProductIdentityIndex(tempOrder.products, normalizedProduct);
621
- if (productIndex === -1) {
622
- 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
+ }
623
647
  } else {
624
- targetProduct = tempOrder.products[productIndex];
625
- tempOrder.products[productIndex] = _objectSpread(_objectSpread(_objectSpread({}, targetProduct), normalizedProduct), {}, {
626
- num: getSafeProductNum(targetProduct.num + normalizedProduct.num),
627
- _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;
628
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
+ }
629
671
  }
630
672
  this.applyDiscount();
631
- _context7.next = 7;
673
+ _context7.next = 6;
632
674
  return this.recalculateSummary({
633
675
  createIfMissing: true
634
676
  });
635
- case 7:
677
+ case 6:
636
678
  this.persistTempOrder();
637
679
  return _context7.abrupt("return", tempOrder.products);
638
- case 9:
680
+ case 8:
639
681
  case "end":
640
682
  return _context7.stop();
641
683
  }
@@ -650,22 +692,26 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
650
692
  key: "updateProductInOrder",
651
693
  value: function () {
652
694
  var _updateProductInOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee8(params) {
653
- 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;
654
696
  return _regeneratorRuntime().wrap(function _callee8$(_context8) {
655
697
  while (1) switch (_context8.prev = _context8.next) {
656
698
  case 0:
657
- 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;
658
700
  tempOrder = this.ensureTempOrder();
659
- productIndex = getProductIdentityIndex(tempOrder.products, {
701
+ identityLookup = {
660
702
  product_id: product_id,
661
703
  product_variant_id: product_variant_id
662
- });
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);
663
709
  if (!(productIndex === -1)) {
664
- _context8.next = 5;
710
+ _context8.next = 9;
665
711
  break;
666
712
  }
667
713
  throw new Error('[Order] 目标商品不存在,无法更新');
668
- case 5:
714
+ case 9:
669
715
  targetProduct = tempOrder.products[productIndex];
670
716
  nextProduct = _objectSpread(_objectSpread(_objectSpread({}, targetProduct), updates), {}, {
671
717
  product_id: product_id,
@@ -674,14 +720,14 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
674
720
  nextProduct.num = getSafeProductNum(nextProduct.num);
675
721
  tempOrder.products[productIndex] = nextProduct;
676
722
  this.applyDiscount();
677
- _context8.next = 12;
723
+ _context8.next = 16;
678
724
  return this.recalculateSummary({
679
725
  createIfMissing: true
680
726
  });
681
- case 12:
727
+ case 16:
682
728
  this.persistTempOrder();
683
729
  return _context8.abrupt("return", tempOrder.products);
684
- case 14:
730
+ case 18:
685
731
  case "end":
686
732
  return _context8.stop();
687
733
  }
@@ -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;
@@ -49,6 +49,8 @@ export function createDefaultOrderRulesHooks() {
49
49
  id: product.product_id,
50
50
  // Rules 引擎用 _id 作为 processedProductsMap 键;必须与购物车行级 identity 一致,
51
51
  // 否则同 SKU 不同小料会在 calcDiscount 重组时互相覆盖。
52
+ // 不透明 identity 契约下,normalizeOrderProduct / restoreTempOrderFromStorage 已保证 identity_key 必存在;
53
+ // 留 fingerprint 分支仅作 Rules 单测里直接传裸 product 时的兜底。
52
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)),
53
55
  price: product.selling_price,
54
56
  total: new Decimal(product.selling_price || 0).times(product.num || 1).toNumber(),
@@ -170,6 +172,29 @@ export function formatDateTime(date) {
170
172
  function normalizeSubmitPlatform(platform) {
171
173
  return (platform === null || platform === void 0 ? void 0 : platform.toLowerCase()) === 'pc' ? 'PC' : 'H5';
172
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
+ }
173
198
  function normalizeSubmitProduct(product) {
174
199
  var _origin = product._origin,
175
200
  identity_key = product.identity_key,
@@ -196,9 +221,9 @@ function normalizeSubmitProduct(product) {
196
221
  return _objectSpread(_objectSpread(_objectSpread({}, submitProduct), bookingUid ? {
197
222
  booking_uid: bookingUid
198
223
  } : {}), {}, {
199
- product_option_item: submitProduct.product_option_item || [],
224
+ product_option_item: formatSubmitOptionItems(submitProduct.product_option_item),
200
225
  discount_list: submitProduct.discount_list || [],
201
- product_bundle: submitProduct.product_bundle || [],
226
+ product_bundle: formatSubmitBundleItems(submitProduct.product_bundle),
202
227
  metadata: cleanMetadata,
203
228
  // 出站兼容:后端仍消费 payment_price 字段,从 selling_price(券后单价)派生。
204
229
  payment_price: submitProduct.selling_price
@@ -402,6 +427,7 @@ export function filterProductsForScanOrderMore(products) {
402
427
  }
403
428
  export function formatV1Product(products) {
404
429
  return products.map(function (product) {
430
+ var _product$note;
405
431
  return {
406
432
  bundle: product.product_bundle,
407
433
  key: product.product_id,
@@ -409,6 +435,7 @@ export function formatV1Product(products) {
409
435
  product_id: product.product_id,
410
436
  product_variant_id: product.product_variant_id,
411
437
  num: product.num,
438
+ note: String((_product$note = product.note) !== null && _product$note !== void 0 ? _product$note : ''),
412
439
  rowKey: product.product_id,
413
440
  session: null,
414
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;