@pisell/pisellos 0.0.479 → 0.0.481

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 (147) hide show
  1. package/dist/core/index.d.ts +3 -2
  2. package/dist/core/index.js +7 -0
  3. package/dist/effects/index.d.ts +2 -2
  4. package/dist/effects/index.js +34 -81
  5. package/dist/model/strategy/adapter/promotion/evaluator.js +99 -26
  6. package/dist/model/strategy/adapter/walletPass/type.d.ts +9 -2
  7. package/dist/model/strategy/adapter/walletPass/utils.d.ts +6 -6
  8. package/dist/model/strategy/adapter/walletPass/utils.js +111 -72
  9. package/dist/modules/Customer/index.js +1 -1
  10. package/dist/modules/Discount/index.d.ts +6 -2
  11. package/dist/modules/Discount/index.js +14 -8
  12. package/dist/modules/Order/index.d.ts +1 -1
  13. package/dist/modules/Order/index.js +18 -13
  14. package/dist/modules/Payment/index.d.ts +4 -0
  15. package/dist/modules/Payment/index.js +774 -649
  16. package/dist/modules/Payment/walletpass.js +44 -17
  17. package/dist/modules/Product/index.d.ts +1 -1
  18. package/dist/modules/Product/types.d.ts +2 -0
  19. package/dist/modules/ProductList/index.d.ts +3 -0
  20. package/dist/modules/ProductList/index.js +9 -7
  21. package/dist/modules/Rules/index.d.ts +2 -2
  22. package/dist/modules/Rules/index.js +37 -31
  23. package/dist/modules/Rules/types.d.ts +2 -2
  24. package/dist/modules/Schedule/index.d.ts +9 -0
  25. package/dist/modules/Schedule/index.js +15 -2
  26. package/dist/plugins/app-types/app/app.d.ts +1 -0
  27. package/dist/plugins/request.d.ts +2 -0
  28. package/dist/server/index.d.ts +107 -2
  29. package/dist/server/index.js +1507 -279
  30. package/dist/server/modules/index.d.ts +6 -0
  31. package/dist/server/modules/index.js +7 -0
  32. package/dist/server/modules/menu/index.d.ts +19 -0
  33. package/dist/server/modules/menu/index.js +221 -71
  34. package/dist/server/modules/order/index.d.ts +87 -0
  35. package/dist/server/modules/order/index.js +916 -0
  36. package/dist/server/modules/order/types.d.ts +530 -0
  37. package/dist/server/modules/order/types.js +141 -0
  38. package/dist/server/modules/order/utils/filterBookings.d.ts +6 -0
  39. package/dist/server/modules/order/utils/filterBookings.js +350 -0
  40. package/dist/server/modules/order/utils/filterOrders.d.ts +15 -0
  41. package/dist/server/modules/order/utils/filterOrders.js +226 -0
  42. package/dist/server/modules/products/index.d.ts +117 -5
  43. package/dist/server/modules/products/index.js +1450 -240
  44. package/dist/server/modules/products/types.d.ts +25 -1
  45. package/dist/server/modules/products/types.js +3 -0
  46. package/dist/server/modules/resource/index.d.ts +86 -0
  47. package/dist/server/modules/resource/index.js +1128 -0
  48. package/dist/server/modules/resource/types.d.ts +121 -0
  49. package/dist/server/modules/resource/types.js +47 -0
  50. package/dist/server/modules/schedule/index.d.ts +19 -0
  51. package/dist/server/modules/schedule/index.js +229 -68
  52. package/dist/server/utils/product.d.ts +5 -0
  53. package/dist/server/utils/product.js +71 -31
  54. package/dist/solution/BookingTicket/index.d.ts +10 -2
  55. package/dist/solution/BookingTicket/index.js +41 -28
  56. package/dist/solution/BookingTicket/utils/scan/index.js +1 -1
  57. package/dist/solution/Checkout/index.d.ts +1 -0
  58. package/dist/solution/Checkout/index.js +286 -188
  59. package/dist/solution/Checkout/utils/index.d.ts +2 -1
  60. package/dist/solution/Checkout/utils/index.js +6 -4
  61. package/dist/solution/RegisterAndLogin/config.js +340 -1
  62. package/dist/solution/Sales/index.d.ts +96 -0
  63. package/dist/solution/Sales/index.js +566 -0
  64. package/dist/solution/Sales/types.d.ts +67 -0
  65. package/dist/solution/Sales/types.js +26 -0
  66. package/dist/solution/ShopDiscount/index.d.ts +1 -0
  67. package/dist/solution/ShopDiscount/index.js +35 -22
  68. package/dist/solution/ShopDiscount/types.d.ts +6 -0
  69. package/dist/solution/ShopDiscount/utils.d.ts +9 -0
  70. package/dist/solution/ShopDiscount/utils.js +21 -27
  71. package/dist/solution/index.d.ts +2 -1
  72. package/dist/solution/index.js +2 -1
  73. package/dist/types/index.d.ts +5 -0
  74. package/lib/core/index.d.ts +3 -2
  75. package/lib/core/index.js +4 -0
  76. package/lib/effects/index.d.ts +2 -2
  77. package/lib/effects/index.js +22 -31
  78. package/lib/model/strategy/adapter/promotion/evaluator.js +57 -8
  79. package/lib/model/strategy/adapter/walletPass/type.d.ts +9 -2
  80. package/lib/model/strategy/adapter/walletPass/utils.d.ts +6 -6
  81. package/lib/model/strategy/adapter/walletPass/utils.js +115 -48
  82. package/lib/modules/Customer/index.js +1 -1
  83. package/lib/modules/Discount/index.d.ts +6 -2
  84. package/lib/modules/Discount/index.js +3 -1
  85. package/lib/modules/Order/index.d.ts +1 -1
  86. package/lib/modules/Order/index.js +20 -18
  87. package/lib/modules/Payment/index.d.ts +4 -0
  88. package/lib/modules/Payment/index.js +134 -66
  89. package/lib/modules/Payment/walletpass.js +23 -4
  90. package/lib/modules/Product/index.d.ts +1 -1
  91. package/lib/modules/Product/types.d.ts +2 -0
  92. package/lib/modules/ProductList/index.d.ts +3 -0
  93. package/lib/modules/ProductList/index.js +2 -2
  94. package/lib/modules/Rules/index.d.ts +2 -2
  95. package/lib/modules/Rules/index.js +69 -73
  96. package/lib/modules/Rules/types.d.ts +2 -2
  97. package/lib/modules/Schedule/index.d.ts +9 -0
  98. package/lib/modules/Schedule/index.js +11 -0
  99. package/lib/plugins/app-types/app/app.d.ts +1 -0
  100. package/lib/plugins/request.d.ts +2 -0
  101. package/lib/server/index.d.ts +107 -2
  102. package/lib/server/index.js +773 -51
  103. package/lib/server/modules/index.d.ts +6 -0
  104. package/lib/server/modules/index.js +16 -2
  105. package/lib/server/modules/menu/index.d.ts +19 -0
  106. package/lib/server/modules/menu/index.js +121 -2
  107. package/lib/server/modules/order/index.d.ts +87 -0
  108. package/lib/server/modules/order/index.js +543 -0
  109. package/lib/server/modules/order/types.d.ts +530 -0
  110. package/lib/server/modules/order/types.js +34 -0
  111. package/lib/server/modules/order/utils/filterBookings.d.ts +6 -0
  112. package/lib/server/modules/order/utils/filterBookings.js +320 -0
  113. package/lib/server/modules/order/utils/filterOrders.d.ts +15 -0
  114. package/lib/server/modules/order/utils/filterOrders.js +197 -0
  115. package/lib/server/modules/products/index.d.ts +117 -5
  116. package/lib/server/modules/products/index.js +799 -62
  117. package/lib/server/modules/products/types.d.ts +25 -1
  118. package/lib/server/modules/products/types.js +1 -0
  119. package/lib/server/modules/resource/index.d.ts +86 -0
  120. package/lib/server/modules/resource/index.js +557 -0
  121. package/lib/server/modules/resource/types.d.ts +121 -0
  122. package/lib/server/modules/resource/types.js +35 -0
  123. package/lib/server/modules/schedule/index.d.ts +19 -0
  124. package/lib/server/modules/schedule/index.js +141 -12
  125. package/lib/server/utils/product.d.ts +5 -0
  126. package/lib/server/utils/product.js +56 -27
  127. package/lib/solution/BookingTicket/index.d.ts +10 -2
  128. package/lib/solution/BookingTicket/index.js +10 -2
  129. package/lib/solution/BookingTicket/utils/scan/index.js +0 -1
  130. package/lib/solution/Checkout/index.d.ts +1 -0
  131. package/lib/solution/Checkout/index.js +399 -331
  132. package/lib/solution/Checkout/utils/index.d.ts +2 -1
  133. package/lib/solution/Checkout/utils/index.js +6 -4
  134. package/lib/solution/RegisterAndLogin/config.js +266 -1
  135. package/lib/solution/Sales/index.d.ts +96 -0
  136. package/lib/solution/Sales/index.js +416 -0
  137. package/lib/solution/Sales/types.d.ts +67 -0
  138. package/lib/solution/Sales/types.js +35 -0
  139. package/lib/solution/ShopDiscount/index.d.ts +1 -0
  140. package/lib/solution/ShopDiscount/index.js +14 -6
  141. package/lib/solution/ShopDiscount/types.d.ts +6 -0
  142. package/lib/solution/ShopDiscount/utils.d.ts +9 -0
  143. package/lib/solution/ShopDiscount/utils.js +6 -10
  144. package/lib/solution/index.d.ts +2 -1
  145. package/lib/solution/index.js +4 -2
  146. package/lib/types/index.d.ts +5 -0
  147. package/package.json +1 -1
@@ -0,0 +1,26 @@
1
+ export var SalesHooks = /*#__PURE__*/function (SalesHooks) {
2
+ SalesHooks["onInited"] = "sales:onInited";
3
+ SalesHooks["onDestroy"] = "sales:onDestroy";
4
+ SalesHooks["onCurrentDayChanged"] = "sales:onCurrentDayChanged";
5
+ SalesHooks["onReservationListChanged"] = "sales:onReservationListChanged";
6
+ return SalesHooks;
7
+ }({});
8
+
9
+ /**
10
+ * 预订记录类型(暂用 OrderData 占位)
11
+ *
12
+ * TODO(Rolo): 等领导提供 reservationList 的目标结构后,
13
+ * 将 Server/Order 原始数据转换为真正的 Reservation DTO,
14
+ * 当前不要直接把 OrderData 当作最终 UI 数据结构。
15
+ */
16
+
17
+ /**
18
+ * Sales 解决方案状态
19
+ *
20
+ * - currentDay: 当前选择的日期,默认当天 00:00:00
21
+ * - reservationList: currentDay 对应的预约列表(数据来源于 Server/Order,转换逻辑待补)
22
+ */
23
+
24
+ /**
25
+ * Sales 解决方案最小 API 面
26
+ */
@@ -30,6 +30,7 @@ export declare class ShopDiscountImpl extends BaseModule implements Module {
30
30
  type?: 'form' | 'customer';
31
31
  [key: string]: any;
32
32
  }): void;
33
+ setOrderId(id?: number): void;
33
34
  calcDiscount(productList: Record<string, any>[], options?: SetDiscountSelectedParams): {
34
35
  productList: Record<string, any>[];
35
36
  discountList: Discount[];
@@ -57,7 +57,8 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
57
57
  filteredDiscountList: [],
58
58
  orderTotalAmount: 0,
59
59
  holders: [],
60
- bookingSubject: undefined
60
+ bookingSubject: undefined,
61
+ orderId: undefined
61
62
  };
62
63
  return _this;
63
64
  }
@@ -307,6 +308,11 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
307
308
  value: function setBookingSubject(bookingSubject) {
308
309
  this.store.bookingSubject = bookingSubject;
309
310
  }
311
+ }, {
312
+ key: "setOrderId",
313
+ value: function setOrderId(id) {
314
+ this.store.orderId = id;
315
+ }
310
316
 
311
317
  // 计算优惠券
312
318
  }, {
@@ -371,6 +377,7 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
371
377
 
372
378
  // 找到需要修改状态的优惠券
373
379
  var newDiscountList = discountList.map(function (discount) {
380
+ if (discount.isEditMode) return discount;
374
381
  if (selectionMap.has(discount.id)) {
375
382
  var targetIsSelected = selectionMap.get(discount.id);
376
383
  return _objectSpread(_objectSpread({}, discount), {}, {
@@ -443,7 +450,10 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
443
450
  case 0:
444
451
  _context6.prev = 0;
445
452
  _context6.next = 3;
446
- return (_this$store$discount4 = this.store.discount) === null || _this$store$discount4 === void 0 ? void 0 : _this$store$discount4.batchSearch(code, customerId);
453
+ return (_this$store$discount4 = this.store.discount) === null || _this$store$discount4 === void 0 ? void 0 : _this$store$discount4.batchSearch(code, {
454
+ customerId: customerId,
455
+ orderId: this.store.orderId
456
+ });
447
457
  case 3:
448
458
  _context6.t0 = _context6.sent;
449
459
  if (_context6.t0) {
@@ -504,9 +514,9 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
504
514
  productList: this.store.productList || [],
505
515
  oldDiscountList: this.getDiscountList(),
506
516
  newDiscountList: withScanList,
507
- orderTotalAmount: this.store.orderTotalAmount || 0,
508
517
  holders: this.store.holders || [],
509
- isFormSubject: ((_this$store$bookingSu2 = this.store.bookingSubject) === null || _this$store$bookingSu2 === void 0 ? void 0 : _this$store$bookingSu2.type) === 'form'
518
+ isFormSubject: ((_this$store$bookingSu2 = this.store.bookingSubject) === null || _this$store$bookingSu2 === void 0 ? void 0 : _this$store$bookingSu2.type) === 'form',
519
+ orderTotalAmount: this.store.orderTotalAmount || 0
510
520
  }) || {
511
521
  isAvailable: false,
512
522
  productList: this.store.productList || [],
@@ -785,24 +795,27 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
785
795
  key: "loadPrepareConfig",
786
796
  value: function () {
787
797
  var _loadPrepareConfig = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee10(params) {
788
- var _this$getCustomer2, _this$store$discount8, _this$getDiscountList, _this$store$discount9, _this$store$productLi2, customerId, goodPassList, scanDiscount, scanDiscountIds, newGoodPassList, newDiscountList, filteredDiscountList, _result3;
798
+ var _this$getCustomer2, _this$store$discount8, _this$getDiscountList, _this$store$discount9, _this$store$productLi2, orderId, customerId, goodPassList, scanDiscount, scanDiscountIds, newGoodPassList, newDiscountList, filteredDiscountList, _result3;
789
799
  return _regeneratorRuntime().wrap(function _callee10$(_context10) {
790
800
  while (1) switch (_context10.prev = _context10.next) {
791
801
  case 0:
792
802
  _context10.prev = 0;
803
+ orderId = this.store.orderId;
793
804
  customerId = params.customerId || ((_this$getCustomer2 = this.getCustomer()) === null || _this$getCustomer2 === void 0 ? void 0 : _this$getCustomer2.id); // if (customerId === 1 || !customerId) {
794
805
  // return
795
806
  // }
796
- _context10.next = 4;
797
- return (_this$store$discount8 = this.store.discount) === null || _this$store$discount8 === void 0 ? void 0 : _this$store$discount8.loadPrepareConfig({
807
+ _context10.next = 5;
808
+ return (_this$store$discount8 = this.store.discount) === null || _this$store$discount8 === void 0 ? void 0 : _this$store$discount8.loadPrepareConfig(_objectSpread({
798
809
  customer_id: customerId,
799
- action: 'create',
810
+ action: orderId ? 'update' : 'create',
800
811
  with_good_pass: 1,
801
812
  with_discount_card: 1,
802
813
  with_wallet_pass_holder: 1,
803
814
  request_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
804
- });
805
- case 4:
815
+ }, orderId ? {
816
+ order_id: orderId
817
+ } : {}));
818
+ case 5:
806
819
  goodPassList = _context10.sent;
807
820
  scanDiscount = (_this$getDiscountList = this.getDiscountList()) === null || _this$getDiscountList === void 0 ? void 0 : _this$getDiscountList.filter(function (item) {
808
821
  return item.isScan;
@@ -815,35 +828,35 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
815
828
  });
816
829
  newDiscountList = [].concat(_toConsumableArray(scanDiscount), _toConsumableArray(newGoodPassList || [])); // 存储原始优惠券列表
817
830
  this.store.originalDiscountList = newDiscountList;
818
- _context10.next = 12;
831
+ _context10.next = 13;
819
832
  return (_this$store$discount9 = this.store.discount) === null || _this$store$discount9 === void 0 ? void 0 : _this$store$discount9.setOriginalDiscountList(newDiscountList);
820
- case 12:
833
+ case 13:
821
834
  // 根据当前预约时间过滤优惠券列表
822
835
  filteredDiscountList = this.filterDiscountListByBookingTime(newDiscountList, this.store.currentBookingTime);
823
836
  this.store.filteredDiscountList = filteredDiscountList;
824
837
  this.setDiscountList(filteredDiscountList || []);
825
838
  if (!((_this$store$productLi2 = this.store.productList) !== null && _this$store$productLi2 !== void 0 && _this$store$productLi2.length)) {
826
- _context10.next = 19;
839
+ _context10.next = 20;
827
840
  break;
828
841
  }
829
842
  _result3 = this.calcDiscount(this.store.productList);
830
- _context10.next = 19;
843
+ _context10.next = 20;
831
844
  return this.core.effects.emit("".concat(this.name, ":onLoadPrepareCalcResult"), _result3);
832
- case 19:
833
- _context10.next = 21;
845
+ case 20:
846
+ _context10.next = 22;
834
847
  return this.core.effects.emit("".concat(this.name, ":onLoadDiscountList"), filteredDiscountList);
835
- case 21:
836
- _context10.next = 26;
848
+ case 22:
849
+ _context10.next = 27;
837
850
  break;
838
- case 23:
839
- _context10.prev = 23;
851
+ case 24:
852
+ _context10.prev = 24;
840
853
  _context10.t0 = _context10["catch"](0);
841
854
  console.error('[ShopDiscount] 加载准备配置出错:', _context10.t0);
842
- case 26:
855
+ case 27:
843
856
  case "end":
844
857
  return _context10.stop();
845
858
  }
846
- }, _callee10, this, [[0, 23]]);
859
+ }, _callee10, this, [[0, 24]]);
847
860
  }));
848
861
  function loadPrepareConfig(_x10) {
849
862
  return _loadPrepareConfig.apply(this, arguments);
@@ -36,6 +36,7 @@ export interface ShopDiscountState {
36
36
  type?: 'form' | 'customer';
37
37
  [key: string]: any;
38
38
  };
39
+ orderId?: number;
39
40
  }
40
41
  export interface SetDiscountSelectedParams {
41
42
  discountId: number;
@@ -44,4 +45,9 @@ export interface SetDiscountSelectedParams {
44
45
  discountId: number;
45
46
  isSelected: boolean;
46
47
  }[];
48
+ bookingSubject?: {
49
+ type?: 'form' | 'customer';
50
+ [key: string]: any;
51
+ };
52
+ orderId?: number;
47
53
  }
@@ -2,6 +2,15 @@ import { Discount } from "../../modules/Discount/types";
2
2
  export declare const uniqueById: <T>(arr: T[], key?: string) => T[];
3
3
  export declare const isNormalProductByDurationSchedule: (item: any) => boolean;
4
4
  export declare const isAllNormalProduct: (items: any[]) => boolean;
5
+ /**
6
+ * 获取折扣金额 基于折扣卡类型计算
7
+ * 商品券:直接返回商品价格
8
+ * 折扣卡:根据折扣卡类型计算 固定金额:直接返回折扣卡金额 百分比:根据折扣卡金额计算
9
+ * @param discount
10
+ * @param total
11
+ * @param price
12
+ * @returns
13
+ */
5
14
  /**
6
15
  * 获取折扣金额 基于折扣卡类型计算
7
16
  * 商品券:直接返回商品价格
@@ -30,6 +30,15 @@ export var isAllNormalProduct = function isAllNormalProduct(items) {
30
30
  });
31
31
  };
32
32
 
33
+ /**
34
+ * 获取折扣金额 基于折扣卡类型计算
35
+ * 商品券:直接返回商品价格
36
+ * 折扣卡:根据折扣卡类型计算 固定金额:直接返回折扣卡金额 百分比:根据折扣卡金额计算
37
+ * @param discount
38
+ * @param total
39
+ * @param price
40
+ * @returns
41
+ */
33
42
  /**
34
43
  * 获取折扣金额 基于折扣卡类型计算
35
44
  * 商品券:直接返回商品价格
@@ -40,38 +49,23 @@ export var isAllNormalProduct = function isAllNormalProduct(items) {
40
49
  * @returns
41
50
  */
42
51
  export var getDiscountAmount = function getDiscountAmount(discount, total, price) {
43
- var discountedPrice = 0;
44
-
52
+ var _discount$metadata;
45
53
  // 商品券
46
54
  if (discount.tag === 'good_pass') {
47
- discountedPrice = new Decimal(price).minus(new Decimal(price || 0)).toNumber();
48
- } else {
49
- var _discount$metadata;
50
- // 判断是否是固定金额
51
- var isFixedAmount = (discount === null || discount === void 0 || (_discount$metadata = discount.metadata) === null || _discount$metadata === void 0 ? void 0 : _discount$metadata.discount_card_type) === 'fixed_amount';
52
-
53
- // 固定金额 小于0时返回0
54
- if (isFixedAmount) {
55
- var _discount$amount;
56
- discountedPrice = Math.max(new Decimal(price).minus(new Decimal(((_discount$amount = discount.amount) !== null && _discount$amount !== void 0 ? _discount$amount : discount.par_value) || 0)).toNumber(), 0);
57
- } else {
58
- // 百分比:根据折扣卡金额计算
59
- discountedPrice = new Decimal(100).minus(discount.par_value || 0).div(100).mul(new Decimal(price)).toNumber();
60
- }
55
+ return new Decimal(price).minus(new Decimal(price || 0)).toNumber();
61
56
  }
62
57
 
63
- /*
64
- // 🔥 如果有 maxDeductionAmount 限制,确保折扣金额不超过限制
65
- if (discount.config?.maxDeductionAmount) {
66
- const actualDiscountAmount = new Decimal(price).minus(discountedPrice).toNumber();
67
- if (actualDiscountAmount > discount.config.maxDeductionAmount) {
68
- // 折扣金额超过限制,重新计算折扣后价格
69
- discountedPrice = new Decimal(price).minus(discount.config.maxDeductionAmount).toNumber();
70
- }
71
- }
72
- */
58
+ // 判断是否是固定金额
59
+ var isFixedAmount = (discount === null || discount === void 0 || (_discount$metadata = discount.metadata) === null || _discount$metadata === void 0 ? void 0 : _discount$metadata.discount_card_type) === 'fixed_amount';
60
+
61
+ // 固定金额 小于0时返回0
62
+ if (isFixedAmount) {
63
+ var _discount$amount;
64
+ return Math.max(new Decimal(price).minus(new Decimal(((_discount$amount = discount.amount) !== null && _discount$amount !== void 0 ? _discount$amount : discount.par_value) || 0)).toNumber(), 0);
65
+ }
73
66
 
74
- return discountedPrice;
67
+ // 百分比:根据折扣卡金额计算
68
+ return new Decimal(100).minus(discount.par_value || 0).div(100).mul(new Decimal(price)).toNumber();
75
69
  };
76
70
  export var getDiscountListAmountTotal = function getDiscountListAmountTotal(discount) {
77
71
  return discount.reduce(function (acc, cur) {
@@ -2,5 +2,6 @@ export * from './BuyTickets';
2
2
  export * from './BookingByStep';
3
3
  export * from './BookingTicket';
4
4
  export * from './ShopDiscount';
5
- export * from './Checkout';
6
5
  export * from './RegisterAndLogin';
6
+ export * from './Checkout';
7
+ export * from './Sales';
@@ -2,5 +2,6 @@ export * from "./BuyTickets";
2
2
  export * from "./BookingByStep";
3
3
  export * from "./BookingTicket";
4
4
  export * from "./ShopDiscount";
5
+ export * from "./RegisterAndLogin";
5
6
  export * from "./Checkout";
6
- export * from "./RegisterAndLogin";
7
+ export * from "./Sales";
@@ -50,6 +50,9 @@ export interface PisellCore {
50
50
  };
51
51
  context: BusinessContext;
52
52
  validateContext: (config: ModuleContextConfig) => boolean;
53
+ serverOptions?: ServerOptions;
54
+ server?: any;
55
+ setContext: (ctx: Partial<BusinessContext>) => void;
53
56
  }
54
57
  /**
55
58
  * 业务上下文接口
@@ -57,6 +60,7 @@ export interface PisellCore {
57
60
  export interface BusinessContext {
58
61
  userId?: string;
59
62
  companyId?: string;
63
+ locale?: string;
60
64
  [key: string]: any;
61
65
  }
62
66
  /**
@@ -90,6 +94,7 @@ export interface ServerModuleConfig {
90
94
  * Server 配置选项
91
95
  */
92
96
  export interface ServerOptions {
97
+ All_DATA_SOURCES: Record<string, any>;
93
98
  /** 要启用的模块列表 */
94
99
  modules?: string[] | ServerModuleConfig[];
95
100
  /** 是否自动初始化数据 */
@@ -1,4 +1,4 @@
1
- import { Plugin, PluginOptions, Module, ModuleOptions, PisellCore, PisellOSOptions, BusinessContext, ModuleContextConfig, InitializeServerOptions } from '../types';
1
+ import { Plugin, PluginOptions, Module, ModuleOptions, PisellCore, PisellOSOptions, BusinessContext, ModuleContextConfig, ServerOptions, InitializeServerOptions } from '../types';
2
2
  import { EffectsManager } from '../effects';
3
3
  /**
4
4
  * pisell OS 核心实现
@@ -11,7 +11,7 @@ declare class PisellOSCore implements PisellCore {
11
11
  private debug;
12
12
  context: BusinessContext;
13
13
  server: any;
14
- private serverOptions?;
14
+ serverOptions?: ServerOptions;
15
15
  constructor(options?: PisellOSOptions);
16
16
  private initialize;
17
17
  /**
@@ -29,6 +29,7 @@ declare class PisellOSCore implements PisellCore {
29
29
  getModuleExports<T = any>(name: string): T | null;
30
30
  hasModule(name: string): boolean;
31
31
  destroy(): Promise<void>;
32
+ setContext(ctx: Partial<BusinessContext>): void;
32
33
  /**
33
34
  * 验证上下文参数
34
35
  */
package/lib/core/index.js CHANGED
@@ -235,6 +235,10 @@ var PisellOSCore = class {
235
235
  this.plugins.clear();
236
236
  this.log("PisellOS 核心已销毁");
237
237
  }
238
+ setContext(ctx) {
239
+ this.context = { ...this.context, ...ctx };
240
+ this.log(`上下文已更新: ${JSON.stringify(Object.keys(ctx))}`);
241
+ }
238
242
  /**
239
243
  * 验证上下文参数
240
244
  */
@@ -5,11 +5,11 @@ type EffectCallback = (payload: any) => void | Promise<void | {
5
5
  type UnsubscribeFunction = () => void;
6
6
  declare class EffectsManager {
7
7
  private listeners;
8
- on(event: string, callback: EffectCallback, force?: boolean): UnsubscribeFunction;
8
+ on(event: string, callback: EffectCallback): UnsubscribeFunction;
9
9
  only(event: string, callback: EffectCallback): UnsubscribeFunction;
10
10
  off(event: string, callback: EffectCallback): void;
11
11
  offByModuleDestroy(module: string): void;
12
- once(event: string, callback: EffectCallback, force?: boolean): UnsubscribeFunction;
12
+ once(event: string, callback: EffectCallback): UnsubscribeFunction;
13
13
  emit(event: string, payload: any): Promise<{
14
14
  status: boolean;
15
15
  data: any;
@@ -26,36 +26,31 @@ var EffectsManager = class {
26
26
  constructor() {
27
27
  this.listeners = /* @__PURE__ */ new Map();
28
28
  }
29
- on(event, callback, force = true) {
29
+ on(event, callback) {
30
30
  var _a;
31
31
  if (!this.listeners.has(event))
32
- this.listeners.set(event, []);
33
- (_a = this.listeners.get(event)) == null ? void 0 : _a.push({ callback, force });
32
+ this.listeners.set(event, /* @__PURE__ */ new Set());
33
+ (_a = this.listeners.get(event)) == null ? void 0 : _a.add(callback);
34
34
  return () => {
35
35
  this.off(event, callback);
36
36
  };
37
37
  }
38
38
  // 设置单例监听器,只能存在一个,新的会替换旧的
39
39
  only(event, callback) {
40
- var _a;
41
- this.listeners.set(event, []);
42
- (_a = this.listeners.get(event)) == null ? void 0 : _a.push({ callback, force: false });
40
+ var _a, _b;
41
+ if (this.listeners.has(event)) {
42
+ (_a = this.listeners.get(event)) == null ? void 0 : _a.clear();
43
+ } else {
44
+ this.listeners.set(event, /* @__PURE__ */ new Set());
45
+ }
46
+ (_b = this.listeners.get(event)) == null ? void 0 : _b.add(callback);
43
47
  return () => {
44
48
  this.off(event, callback);
45
49
  };
46
50
  }
47
51
  off(event, callback) {
48
- const eventListeners = this.listeners.get(event);
49
- if (!(eventListeners == null ? void 0 : eventListeners.length))
50
- return;
51
- for (let index = eventListeners.length - 1; index >= 0; index--) {
52
- if (eventListeners[index].callback !== callback)
53
- continue;
54
- eventListeners.splice(index, 1);
55
- break;
56
- }
57
- if (!eventListeners.length)
58
- this.listeners.delete(event);
52
+ var _a;
53
+ (_a = this.listeners.get(event)) == null ? void 0 : _a.delete(callback);
59
54
  }
60
55
  // 模块销毁时,删除所有以模块名开头的监听
61
56
  offByModuleDestroy(module2) {
@@ -65,32 +60,28 @@ var EffectsManager = class {
65
60
  }
66
61
  });
67
62
  }
68
- once(event, callback, force = true) {
63
+ once(event, callback) {
69
64
  const wrapper = async (payload) => {
70
65
  await callback(payload);
71
66
  this.off(event, wrapper);
72
67
  };
73
- return this.on(event, wrapper, force);
68
+ return this.on(event, wrapper);
74
69
  }
75
70
  async emit(event, payload) {
76
- var _a;
77
71
  const callbacks = this.listeners.get(event);
78
- if (!(callbacks == null ? void 0 : callbacks.length))
72
+ if (!callbacks)
79
73
  return { status: true, data: [] };
80
- const forceCallbacks = callbacks.filter((listener) => listener.force).map((listener) => listener.callback);
81
- const topNormalListener = (_a = [...callbacks].reverse().find((listener) => !listener.force)) == null ? void 0 : _a.callback;
82
- const targetCallbacks = topNormalListener ? [...forceCallbacks, topNormalListener] : forceCallbacks;
83
- return new Promise(async (resolve) => {
84
- const res = [];
85
- for (const cb of targetCallbacks) {
74
+ const res = [];
75
+ await Promise.all(
76
+ Array.from(callbacks).reverse().map(async (cb) => {
86
77
  const result = await cb(payload);
87
78
  if (result !== void 0 && typeof result === "object" && "status" in result) {
88
79
  res.push(result);
89
80
  }
90
- }
91
- const isAllPass = res.every((r) => (r == null ? void 0 : r.status) !== false);
92
- resolve({ status: isAllPass, data: res });
93
- });
81
+ })
82
+ );
83
+ const isAllPass = res.every((r) => (r == null ? void 0 : r.status) !== false);
84
+ return { status: isAllPass, data: res };
94
85
  }
95
86
  clear() {
96
87
  this.listeners.clear();
@@ -512,14 +512,21 @@ var PromotionEvaluator = class {
512
512
  unitProducts.push({
513
513
  product,
514
514
  price: product.price,
515
- productId: product.id
515
+ productId: product.id,
516
+ sourceAvailableQty: availableQty
516
517
  });
517
518
  }
518
519
  }
519
520
  if (unitProducts.length === 0) {
520
521
  return { products: [], originalAmount: 0, finalAmount: 0 };
521
522
  }
522
- unitProducts.sort((a, b) => b.price - a.price);
523
+ unitProducts.sort((a, b) => {
524
+ const aIsMultiple = a.sourceAvailableQty > 0 && a.sourceAvailableQty % x === 0 ? 1 : 0;
525
+ const bIsMultiple = b.sourceAvailableQty > 0 && b.sourceAvailableQty % x === 0 ? 1 : 0;
526
+ if (aIsMultiple !== bIsMultiple)
527
+ return bIsMultiple - aIsMultiple;
528
+ return b.price - a.price;
529
+ });
523
530
  const totalUnits = unitProducts.length;
524
531
  const groupCount = cumulative ? Math.floor(totalUnits / x) : totalUnits >= x ? 1 : 0;
525
532
  const promotionUnits = groupCount * x;
@@ -573,7 +580,9 @@ var PromotionEvaluator = class {
573
580
  (sum, p) => sum.plus(p),
574
581
  new import_decimal.default(0)
575
582
  );
576
- const finalPricePerUnit = this.formatPrice(totalAllocated.div(promoQty));
583
+ const productOriginalAmount = new import_decimal.default(product.price).mul(promoQty);
584
+ const actualTotal = import_decimal.default.min(totalAllocated, productOriginalAmount);
585
+ const finalPricePerUnit = this.formatPrice(actualTotal.div(promoQty));
577
586
  result.push({
578
587
  ...product,
579
588
  quantity: promoQty,
@@ -584,9 +593,8 @@ var PromotionEvaluator = class {
584
593
  isSplit: false,
585
594
  matchedBundleIndex
586
595
  });
587
- const productOriginalAmount = new import_decimal.default(product.price).mul(promoQty);
588
596
  originalAmount = originalAmount.plus(productOriginalAmount);
589
- finalAmount = finalAmount.plus(totalAllocated);
597
+ finalAmount = finalAmount.plus(actualTotal);
590
598
  } else if (promoQty === 0 && remainingQty > 0) {
591
599
  result.push({
592
600
  ...product,
@@ -605,7 +613,9 @@ var PromotionEvaluator = class {
605
613
  (sum, p) => sum.plus(p),
606
614
  new import_decimal.default(0)
607
615
  );
608
- const finalPricePerUnit = this.formatPrice(totalAllocated.div(promoQty));
616
+ const promoOriginalAmount = new import_decimal.default(product.price).mul(promoQty);
617
+ const actualTotal = import_decimal.default.min(totalAllocated, promoOriginalAmount);
618
+ const finalPricePerUnit = this.formatPrice(actualTotal.div(promoQty));
609
619
  result.push({
610
620
  ...product,
611
621
  id: this.generateRandomId(),
@@ -618,9 +628,8 @@ var PromotionEvaluator = class {
618
628
  matchedBundleIndex,
619
629
  isSplit: true
620
630
  });
621
- const promoOriginalAmount = new import_decimal.default(product.price).mul(promoQty);
622
631
  originalAmount = originalAmount.plus(promoOriginalAmount);
623
- finalAmount = finalAmount.plus(totalAllocated);
632
+ finalAmount = finalAmount.plus(actualTotal);
624
633
  result.push({
625
634
  ...product,
626
635
  quantity: remainingQty,
@@ -636,6 +645,46 @@ var PromotionEvaluator = class {
636
645
  }
637
646
  processedQuantityMap.set(key, processedQty + availableQty);
638
647
  }
648
+ if (groupCount > 0) {
649
+ const expectedPromoTotal = new import_decimal.default(groupPrice).mul(groupCount);
650
+ const promoItems = result.filter((p) => p.inPromotion);
651
+ let actualPromoTotal = new import_decimal.default(0);
652
+ for (const p of promoItems) {
653
+ actualPromoTotal = actualPromoTotal.plus(
654
+ new import_decimal.default(p.finalPrice).mul(p.quantity)
655
+ );
656
+ }
657
+ const roundingDiff = actualPromoTotal.minus(expectedPromoTotal);
658
+ if (!roundingDiff.eq(0)) {
659
+ const adjustTarget = promoItems.find((p) => p.quantity === 1);
660
+ if (adjustTarget) {
661
+ adjustTarget.finalPrice = this.formatPrice(
662
+ new import_decimal.default(adjustTarget.finalPrice).minus(roundingDiff)
663
+ );
664
+ } else if (promoItems.length > 0) {
665
+ const lastPromo = promoItems[promoItems.length - 1];
666
+ const adjustedUnitPrice = this.formatPrice(
667
+ new import_decimal.default(lastPromo.finalPrice).minus(roundingDiff)
668
+ );
669
+ lastPromo.quantity -= 1;
670
+ lastPromo.isSplit = true;
671
+ result.push({
672
+ ...lastPromo,
673
+ id: this.generateRandomId(),
674
+ originalId: lastPromo.originalId || lastPromo.id,
675
+ quantity: 1,
676
+ finalPrice: adjustedUnitPrice,
677
+ isSplit: true
678
+ });
679
+ }
680
+ finalAmount = new import_decimal.default(0);
681
+ for (const p of result) {
682
+ finalAmount = finalAmount.plus(
683
+ new import_decimal.default(p.finalPrice).mul(p.quantity)
684
+ );
685
+ }
686
+ }
687
+ }
639
688
  return {
640
689
  products: result,
641
690
  originalAmount: originalAmount.toNumber(),
@@ -41,7 +41,7 @@ export interface Voucher {
41
41
  allowCrossProduct: boolean;
42
42
  /** 可用商品数量上限 (仅多商品) 默认为0,表示不限制商品数量。 */
43
43
  applicableProductLimit: number;
44
- /** 单商品可用卡券上限(同一 Wallet Pass 商品生成的卡券对同一商品的每个 unit 最多抵扣次数,总上限 = maxPassesPerItem × quantity)。默认为 0,表示不限制。 */
44
+ /** 单订单行每单位可用同一 Wallet Pass 券次数;该行总券次上限 = maxPassesPerItem × 该行 quantity(按行唯一键区分)。0 表示不限制。 */
45
45
  maxPassesPerItem: number;
46
46
  };
47
47
  }
@@ -50,6 +50,10 @@ export interface Voucher {
50
50
  */
51
51
  export interface Product {
52
52
  product_id: number;
53
+ /** 订单明细 id,参与行唯一键兜底解析 */
54
+ id?: number;
55
+ /** 行级唯一串,参与行唯一键解析 */
56
+ product_unique_string?: string;
53
57
  price: number;
54
58
  quantity: number;
55
59
  name?: string;
@@ -61,6 +65,9 @@ export interface Product {
61
65
  /** 主商品税费 */
62
66
  tax_fee: number;
63
67
  metadata: {
68
+ /** 行唯一标识,优先用于 Wallet Pass 按行配额 */
69
+ product_unique?: string;
70
+ unique_identification_number?: string;
64
71
  main_product_attached_bundle_tax_fee?: number;
65
72
  main_product_attached_bundle_surcharge_fee?: number;
66
73
  surcharge_rounding_remainder?: number;
@@ -132,7 +139,7 @@ export interface EvaluatorInput {
132
139
  allowCrossProduct: boolean;
133
140
  /** 可用商品数量上限 (仅多商品) 默认为0,表示不限制商品数量。 */
134
141
  applicableProductLimit: number;
135
- /** 单商品可用卡券上限(同一 Wallet Pass 商品生成的卡券对同一商品的每个 unit 最多抵扣次数,总上限 = maxPassesPerItem × quantity)。默认为 0,表示不限制。 */
142
+ /** 单订单行每单位可用同一 Wallet Pass 券次数;行总上限 = maxPassesPerItem × 该行 quantity(按行唯一键计)。0 表示不限制。 */
136
143
  maxPassesPerItem: number;
137
144
  }>[];
138
145
  }
@@ -1,4 +1,10 @@
1
1
  import { Product, Voucher } from './type';
2
+ /** 订单商品数量 */
3
+ export declare const getProductQuantity: (product: any) => any;
4
+ /**
5
+ * 订单商品行唯一键,用于 maxPassesPerItem 按行、按件配额(同 SPU 不同规格视为不同行)。
6
+ */
7
+ export declare function resolveWalletPassLineKey(product: any, indexInOrder: number): string;
2
8
  export declare const getApplicableProductIds: (voucher: Voucher) => number[] | null;
3
9
  /**
4
10
  * 优惠券处理函数
@@ -64,12 +70,6 @@ export declare const getBundleItemDiscountDifference: (bundleItem: any) => numbe
64
70
  * @returns 子商品总价格(不含舍入余数)
65
71
  */
66
72
  export declare const getBundleItemPrice: (bundleItem: any, parentQuantity: number, isDeductTaxAndFee: boolean) => number;
67
- /**
68
- * 获取商品数量
69
- * @param product 商品
70
- * @returns 商品数量
71
- */
72
- export declare const getProductQuantity: (product: any) => any;
73
73
  export declare const getBundleItemIsOriginalPrice: (item: any) => boolean;
74
74
  export declare const getBundleItemIsMarkupPrice: (item: any) => boolean;
75
75
  export declare const getBundleItemIsDiscountPrice: (item: any) => boolean;