@pisell/pisellos 2.2.153 → 2.2.154

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 (80) hide show
  1. package/dist/core/index.js +1 -0
  2. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  3. package/dist/modules/Cart/utils/cartProduct.js +1 -1
  4. package/dist/modules/Order/index.d.ts +2 -0
  5. package/dist/modules/Order/index.js +231 -160
  6. package/dist/modules/Order/types.d.ts +19 -0
  7. package/dist/modules/Order/utils.js +7 -6
  8. package/dist/modules/Payment/index.d.ts +4 -0
  9. package/dist/modules/Payment/index.js +567 -505
  10. package/dist/modules/Payment/types.d.ts +29 -9
  11. package/dist/modules/SalesSummary/index.d.ts +7 -5
  12. package/dist/modules/SalesSummary/index.js +35 -11
  13. package/dist/plugins/app.d.ts +2 -0
  14. package/dist/server/index.d.ts +2 -5
  15. package/dist/server/index.js +58 -66
  16. package/dist/server/modules/index.d.ts +1 -1
  17. package/dist/server/modules/products/index.d.ts +12 -1
  18. package/dist/server/modules/products/index.js +169 -78
  19. package/dist/server/modules/products/types.d.ts +11 -0
  20. package/dist/server/modules/products/types.js +4 -0
  21. package/dist/server/utils/product.js +2 -2
  22. package/dist/solution/BaseSales/index.d.ts +26 -2
  23. package/dist/solution/BaseSales/index.js +342 -112
  24. package/dist/solution/BaseSales/types.d.ts +4 -4
  25. package/dist/solution/BaseSales/types.js +4 -4
  26. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +62 -0
  27. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +116 -0
  28. package/dist/solution/BaseSales/utils.js +3 -3
  29. package/dist/solution/BookingTicket/index.d.ts +11 -13
  30. package/dist/solution/BookingTicket/index.js +23 -37
  31. package/dist/solution/BookingTicket/types.d.ts +9 -6
  32. package/dist/solution/BookingTicket/types.js +6 -3
  33. package/dist/solution/BookingTicket/utils/cartView.d.ts +7 -12
  34. package/dist/solution/BookingTicket/utils/cartView.js +52 -14
  35. package/dist/solution/BookingTicket/utils/orderCustomer.d.ts +4 -0
  36. package/dist/solution/BookingTicket/utils/orderCustomer.js +31 -0
  37. package/dist/solution/Sales/index.d.ts +3 -0
  38. package/dist/solution/Sales/index.js +85 -43
  39. package/dist/solution/Sales/types.d.ts +3 -0
  40. package/dist/solution/ScanOrder/types.d.ts +4 -4
  41. package/dist/solution/ScanOrder/types.js +4 -4
  42. package/dist/solution/ScanOrder/utils.js +3 -3
  43. package/lib/core/index.js +1 -0
  44. package/lib/modules/Cart/utils/cartProduct.js +1 -1
  45. package/lib/modules/Order/index.d.ts +2 -0
  46. package/lib/modules/Order/index.js +39 -7
  47. package/lib/modules/Order/types.d.ts +19 -0
  48. package/lib/modules/Order/utils.js +4 -2
  49. package/lib/modules/Payment/index.d.ts +4 -0
  50. package/lib/modules/Payment/index.js +26 -2
  51. package/lib/modules/Payment/types.d.ts +29 -9
  52. package/lib/modules/SalesSummary/index.d.ts +7 -5
  53. package/lib/modules/SalesSummary/index.js +29 -9
  54. package/lib/plugins/app.d.ts +2 -0
  55. package/lib/server/index.d.ts +2 -5
  56. package/lib/server/index.js +38 -58
  57. package/lib/server/modules/index.d.ts +1 -1
  58. package/lib/server/modules/products/index.d.ts +12 -1
  59. package/lib/server/modules/products/index.js +69 -9
  60. package/lib/server/modules/products/types.d.ts +11 -0
  61. package/lib/server/utils/product.js +2 -2
  62. package/lib/solution/BaseSales/index.d.ts +26 -2
  63. package/lib/solution/BaseSales/index.js +169 -3
  64. package/lib/solution/BaseSales/types.d.ts +4 -4
  65. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +62 -0
  66. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +155 -0
  67. package/lib/solution/BaseSales/utils.js +3 -3
  68. package/lib/solution/BookingTicket/index.d.ts +11 -13
  69. package/lib/solution/BookingTicket/index.js +17 -27
  70. package/lib/solution/BookingTicket/types.d.ts +9 -6
  71. package/lib/solution/BookingTicket/utils/cartView.d.ts +7 -12
  72. package/lib/solution/BookingTicket/utils/cartView.js +44 -18
  73. package/lib/solution/BookingTicket/utils/orderCustomer.d.ts +4 -0
  74. package/lib/solution/BookingTicket/utils/orderCustomer.js +58 -0
  75. package/lib/solution/Sales/index.d.ts +3 -0
  76. package/lib/solution/Sales/index.js +50 -15
  77. package/lib/solution/Sales/types.d.ts +3 -0
  78. package/lib/solution/ScanOrder/types.d.ts +4 -4
  79. package/lib/solution/ScanOrder/utils.js +3 -3
  80. package/package.json +1 -1
@@ -82,6 +82,9 @@ export declare class SalesImpl extends BaseModule implements Module, SalesModule
82
82
  private getResourceId;
83
83
  private getBookingAppointmentStatus;
84
84
  private getBookingOrderPaymentStatus;
85
+ private countBookingOrders;
86
+ private countCompletedBookings;
87
+ private groupBookingsByResource;
85
88
  private isBookingMatchedResource;
86
89
  private sortMatchedBookings;
87
90
  /**
@@ -409,6 +409,43 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
409
409
  var _booking$order$paymen, _booking$order;
410
410
  return String((_booking$order$paymen = (_booking$order = booking.order) === null || _booking$order === void 0 ? void 0 : _booking$order.payment_status) !== null && _booking$order$paymen !== void 0 ? _booking$order$paymen : '');
411
411
  }
412
+ }, {
413
+ key: "countBookingOrders",
414
+ value: function countBookingOrders(bookings) {
415
+ var orderIds = new Set();
416
+ bookings.forEach(function (booking) {
417
+ var _order_id, _booking$order2;
418
+ var orderId = (_order_id = booking.order_id) !== null && _order_id !== void 0 ? _order_id : (_booking$order2 = booking.order) === null || _booking$order2 === void 0 ? void 0 : _booking$order2.order_id;
419
+ if (orderId === undefined || orderId === null) return;
420
+ orderIds.add(String(orderId));
421
+ });
422
+ return orderIds.size;
423
+ }
424
+ }, {
425
+ key: "countCompletedBookings",
426
+ value: function countCompletedBookings(bookings) {
427
+ var _this2 = this;
428
+ return bookings.filter(function (booking) {
429
+ return _this2.getBookingAppointmentStatus(booking) === 'completed';
430
+ }).length;
431
+ }
432
+ }, {
433
+ key: "groupBookingsByResource",
434
+ value: function groupBookingsByResource(bookingList) {
435
+ var bookingMap = new Map();
436
+ bookingList.forEach(function (booking) {
437
+ if (!Array.isArray(booking.resources)) return;
438
+ booking.resources.forEach(function (resource) {
439
+ var relationId = resource === null || resource === void 0 ? void 0 : resource.relation_id;
440
+ if (relationId === undefined || relationId === null) return;
441
+ var key = String(relationId);
442
+ var list = bookingMap.get(key) || [];
443
+ list.push(booking);
444
+ bookingMap.set(key, list);
445
+ });
446
+ });
447
+ return bookingMap;
448
+ }
412
449
  }, {
413
450
  key: "isBookingMatchedResource",
414
451
  value: function isBookingMatchedResource(booking, resourceId) {
@@ -422,10 +459,10 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
422
459
  }, {
423
460
  key: "sortMatchedBookings",
424
461
  value: function sortMatchedBookings(bookings) {
425
- var _this2 = this;
462
+ var _this3 = this;
426
463
  return _toConsumableArray(bookings).sort(function (left, right) {
427
- var leftStartAt = _this2.toBookingDateTime(left.start_date, left.start_time).valueOf();
428
- var rightStartAt = _this2.toBookingDateTime(right.start_date, right.start_time).valueOf();
464
+ var leftStartAt = _this3.toBookingDateTime(left.start_date, left.start_time).valueOf();
465
+ var rightStartAt = _this3.toBookingDateTime(right.start_date, right.start_time).valueOf();
429
466
  return leftStartAt - rightStartAt;
430
467
  });
431
468
  }
@@ -440,17 +477,17 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
440
477
  }, {
441
478
  key: "pickBookingsForCurrentPoint",
442
479
  value: function pickBookingsForCurrentPoint(current, bookings) {
443
- var _this3 = this;
480
+ var _this4 = this;
444
481
  if (bookings.length === 0) return [];
445
482
  var currentDayStart = current.startOf('day');
446
483
  var currentDayEnd = current.endOf('day');
447
484
 
448
485
  // 仅保留与 current 当天有时间交集的预约,避免跨天误命中
449
486
  var dayScopedBookings = bookings.filter(function (booking) {
450
- var startAt = _this3.toBookingDateTime(booking.start_date, booking.start_time);
451
- var endAt = _this3.toBookingDateTime(booking.end_date, booking.end_time);
487
+ var startAt = _this4.toBookingDateTime(booking.start_date, booking.start_time);
488
+ var endAt = _this4.toBookingDateTime(booking.end_date, booking.end_time);
452
489
  if (!startAt.isValid() || !endAt.isValid()) return false;
453
- return _this3.isSameOrBefore(startAt, currentDayEnd) && _this3.isSameOrAfter(endAt, currentDayStart);
490
+ return _this4.isSameOrBefore(startAt, currentDayEnd) && _this4.isSameOrAfter(endAt, currentDayStart);
454
491
  });
455
492
  if (dayScopedBookings.length === 0) return [];
456
493
  var appendNextStartGroupIfNeeded = function appendNextStartGroupIfNeeded(selectedBookings) {
@@ -460,21 +497,21 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
460
497
  });
461
498
  if (!shouldAppendNextGroup) return selectedBookings;
462
499
  var selectedStartValues = new Set(selectedBookings.map(function (booking) {
463
- return _this3.toBookingDateTime(booking.start_date, booking.start_time);
500
+ return _this4.toBookingDateTime(booking.start_date, booking.start_time);
464
501
  }).filter(function (startAt) {
465
502
  return startAt.isValid();
466
503
  }).map(function (startAt) {
467
504
  return startAt.valueOf();
468
505
  }));
469
506
  var futureCandidates = dayScopedBookings.filter(function (booking) {
470
- var startAt = _this3.toBookingDateTime(booking.start_date, booking.start_time);
507
+ var startAt = _this4.toBookingDateTime(booking.start_date, booking.start_time);
471
508
  if (!startAt.isValid()) return false;
472
509
  return startAt.isAfter(current) && !selectedStartValues.has(startAt.valueOf());
473
510
  });
474
511
  if (futureCandidates.length === 0) return selectedBookings;
475
- var nextStartAt = _this3.toBookingDateTime(futureCandidates[0].start_date, futureCandidates[0].start_time).valueOf();
512
+ var nextStartAt = _this4.toBookingDateTime(futureCandidates[0].start_date, futureCandidates[0].start_time).valueOf();
476
513
  var nextStartGroup = futureCandidates.filter(function (booking) {
477
- var startAt = _this3.toBookingDateTime(booking.start_date, booking.start_time);
514
+ var startAt = _this4.toBookingDateTime(booking.start_date, booking.start_time);
478
515
  return startAt.isValid() && startAt.valueOf() === nextStartAt;
479
516
  });
480
517
  if (nextStartGroup.length === 0) return selectedBookings;
@@ -486,10 +523,10 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
486
523
 
487
524
  // active: current 处于 [startAt, endAt] 区间
488
525
  var activeBookings = dayScopedBookings.filter(function (booking) {
489
- var startAt = _this3.toBookingDateTime(booking.start_date, booking.start_time);
490
- var endAt = _this3.toBookingDateTime(booking.end_date, booking.end_time);
526
+ var startAt = _this4.toBookingDateTime(booking.start_date, booking.start_time);
527
+ var endAt = _this4.toBookingDateTime(booking.end_date, booking.end_time);
491
528
  if (!startAt.isValid() || !endAt.isValid()) return false;
492
- return _this3.isSameOrAfter(current, startAt) && _this3.isSameOrBefore(current, endAt);
529
+ return _this4.isSameOrAfter(current, startAt) && _this4.isSameOrBefore(current, endAt);
493
530
  });
494
531
  if (activeBookings.length > 0) return appendNextStartGroupIfNeeded(activeBookings);
495
532
 
@@ -501,13 +538,13 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
501
538
 
502
539
  // upcoming: 从未来预约里只取最早那一组(同 start_time)
503
540
  var upcoming = dayScopedBookings.filter(function (booking) {
504
- var startAt = _this3.toBookingDateTime(booking.start_date, booking.start_time);
541
+ var startAt = _this4.toBookingDateTime(booking.start_date, booking.start_time);
505
542
  return startAt.isValid() && startAt.isAfter(current) && startAt.isSame(current, 'day');
506
543
  });
507
544
  if (upcoming.length > 0) {
508
545
  var firstStartAt = this.toBookingDateTime(upcoming[0].start_date, upcoming[0].start_time).valueOf();
509
546
  var upcomingStartGroup = upcoming.filter(function (booking) {
510
- var startAt = _this3.toBookingDateTime(booking.start_date, booking.start_time);
547
+ var startAt = _this4.toBookingDateTime(booking.start_date, booking.start_time);
511
548
  return startAt.valueOf() === firstStartAt;
512
549
  });
513
550
  return appendNextStartGroupIfNeeded(upcomingStartGroup);
@@ -560,10 +597,10 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
560
597
  }, {
561
598
  key: "normalizeResourceBookings",
562
599
  value: function normalizeResourceBookings(current, deviceCurrent, bookingList) {
563
- var _this4 = this;
600
+ var _this5 = this;
564
601
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
565
602
  var normalizedBookings = bookingList.map(function (booking) {
566
- return _this4.normalizeMatchedBooking(current, deviceCurrent, booking, options);
603
+ return _this5.normalizeMatchedBooking(current, deviceCurrent, booking, options);
567
604
  }).filter(function (booking) {
568
605
  return Boolean(booking);
569
606
  }).filter(function (booking) {
@@ -693,7 +730,7 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
693
730
  var _getResourceBookingList = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(currentTime) {
694
731
  var _resourceResponse$dat,
695
732
  _resourceResponse$dat2,
696
- _this5 = this;
733
+ _this6 = this;
697
734
  var bookingList,
698
735
  deviceTime,
699
736
  current,
@@ -701,6 +738,7 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
701
738
  resourceResponse,
702
739
  resourceList,
703
740
  normalizedBookings,
741
+ rawBookingMap,
704
742
  bookingMap,
705
743
  list,
706
744
  _args5 = arguments;
@@ -745,26 +783,21 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
745
783
  case 14:
746
784
  // 全局先做 booking 标准化 + start_time 升序,后续映射直接复用
747
785
  normalizedBookings = this.normalizeResourceBookings(current, deviceCurrent, bookingList); // 建立 resourceId -> bookings[] 倒排索引,加速资源匹配
748
- bookingMap = new Map();
749
- normalizedBookings.forEach(function (booking) {
750
- if (!Array.isArray(booking.resources)) return;
751
- booking.resources.forEach(function (resource) {
752
- var relationId = resource === null || resource === void 0 ? void 0 : resource.relation_id;
753
- if (relationId === undefined || relationId === null) return;
754
- var key = String(relationId);
755
- var list = bookingMap.get(key) || [];
756
- list.push(booking);
757
- bookingMap.set(key, list);
758
- });
759
- });
760
-
761
- // 输出:每个资源都返回;bookings 可能是 0 / 1 / 多条(并发场景)
786
+ rawBookingMap = this.groupBookingsByResource(bookingList);
787
+ bookingMap = this.groupBookingsByResource(normalizedBookings); // 输出:每个资源都返回;bookings 可能是 0 / 1 / 多条(并发场景)
762
788
  list = resourceList.map(function (resource) {
763
- var resourceId = _this5.getResourceId(resource);
789
+ var resourceId = _this6.getResourceId(resource);
790
+ var rawMatchedBookings = rawBookingMap.get(String(resourceId)) || [];
764
791
  var matchedBookings = bookingMap.get(String(resourceId)) || [];
765
- var bookings = _this5.pickBookingsForCurrentPoint(current, matchedBookings);
792
+ var orderCount = _this6.countBookingOrders(rawMatchedBookings);
793
+ var bookingCount = rawMatchedBookings.length;
794
+ var compeleteBookingCount = _this6.countCompletedBookings(rawMatchedBookings);
795
+ var bookings = _this6.pickBookingsForCurrentPoint(current, matchedBookings);
766
796
  return _objectSpread(_objectSpread({}, resource), {}, {
767
797
  resource_id: resourceId,
798
+ orderCount: orderCount,
799
+ bookingCount: bookingCount,
800
+ compeleteBookingCount: compeleteBookingCount,
768
801
  bookings: bookings
769
802
  });
770
803
  });
@@ -796,9 +829,9 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
796
829
  var _getResourceBookingItem = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(params) {
797
830
  var _resourceResponse$dat3,
798
831
  _resourceResponse$dat4,
799
- _this6 = this,
832
+ _this7 = this,
800
833
  _params$bookingList;
801
- var current, deviceCurrent, resourceResponse, resourceList, targetResource, resourceId, matchedBookingList, completedBookingList, unpaidBookingList, bookings, completedBookings, unpaidBookings;
834
+ var current, deviceCurrent, resourceResponse, resourceList, targetResource, resourceId, matchedBookingList, completedBookingList, unpaidBookingList, bookings, completedBookings, unpaidBookings, orderCount, bookingCount, compeleteBookingCount;
802
835
  return _regeneratorRuntime().wrap(function _callee6$(_context6) {
803
836
  while (1) switch (_context6.prev = _context6.next) {
804
837
  case 0:
@@ -836,7 +869,7 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
836
869
  return _context6.abrupt("return", null);
837
870
  case 12:
838
871
  targetResource = resourceList.find(function (resource) {
839
- return String(_this6.getResourceId(resource)) === String(params.resourceId);
872
+ return String(_this7.getResourceId(resource)) === String(params.resourceId);
840
873
  });
841
874
  if (targetResource) {
842
875
  _context6.next = 15;
@@ -846,19 +879,22 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
846
879
  case 15:
847
880
  resourceId = this.getResourceId(targetResource);
848
881
  matchedBookingList = params.bookingList.filter(function (booking) {
849
- return _this6.isBookingMatchedResource(booking, resourceId);
882
+ return _this7.isBookingMatchedResource(booking, resourceId);
850
883
  });
851
884
  completedBookingList = matchedBookingList.filter(function (booking) {
852
- return _this6.getBookingAppointmentStatus(booking) === 'completed';
885
+ return _this7.getBookingAppointmentStatus(booking) === 'completed';
853
886
  });
854
887
  unpaidBookingList = matchedBookingList.filter(function (booking) {
855
- return _this6.getBookingOrderPaymentStatus(booking) === 'unpaid' || _this6.getBookingOrderPaymentStatus(booking) === 'payment_processing';
888
+ return _this7.getBookingOrderPaymentStatus(booking) === 'unpaid' || _this7.getBookingOrderPaymentStatus(booking) === 'payment_processing';
856
889
  });
857
890
  bookings = this.pickBookingsForCurrentPoint(current, this.normalizeResourceBookings(current, deviceCurrent, matchedBookingList));
858
891
  completedBookings = this.pickBookingsForCurrentPoint(current, this.normalizeResourceBookings(current, deviceCurrent, completedBookingList, {
859
892
  includeCompleted: true
860
893
  }));
861
894
  unpaidBookings = this.pickBookingsForCurrentPoint(current, this.normalizeResourceBookings(current, deviceCurrent, unpaidBookingList));
895
+ orderCount = this.countBookingOrders(matchedBookingList);
896
+ bookingCount = matchedBookingList.length;
897
+ compeleteBookingCount = completedBookingList.length;
862
898
  this.logger.addLog({
863
899
  type: 'info',
864
900
  title: 'getResourceBookingItem',
@@ -869,16 +905,22 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
869
905
  bookingList: (_params$bookingList = params.bookingList) === null || _params$bookingList === void 0 ? void 0 : _params$bookingList.length,
870
906
  bookings: bookings.length,
871
907
  completedBookings: completedBookings.length,
872
- unpaidBookings: unpaidBookings.length
908
+ unpaidBookings: unpaidBookings.length,
909
+ orderCount: orderCount,
910
+ bookingCount: bookingCount,
911
+ compeleteBookingCount: compeleteBookingCount
873
912
  }
874
913
  });
875
914
  return _context6.abrupt("return", _objectSpread(_objectSpread({}, targetResource), {}, {
876
915
  resource_id: resourceId,
916
+ orderCount: orderCount,
917
+ bookingCount: bookingCount,
918
+ compeleteBookingCount: compeleteBookingCount,
877
919
  bookings: bookings,
878
920
  completedBookings: completedBookings,
879
921
  unpaidBookings: unpaidBookings
880
922
  }));
881
- case 24:
923
+ case 27:
882
924
  case "end":
883
925
  return _context6.stop();
884
926
  }
@@ -30,6 +30,9 @@ export interface SalesResourceMatchedBooking extends Omit<BookingData, 'status'>
30
30
  }
31
31
  export interface SalesResourceBookingItem extends Omit<ResourceData, 'bookings'> {
32
32
  resource_id: ResourceId;
33
+ orderCount: number;
34
+ bookingCount: number;
35
+ compeleteBookingCount: number;
33
36
  bookings: SalesResourceMatchedBooking[];
34
37
  }
35
38
  export interface SalesResourceBookingItemWithGroups extends SalesResourceBookingItem {
@@ -85,13 +85,13 @@ export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
85
85
  * 出站 payload 版本的商品行。
86
86
  *
87
87
  * 与 tempOrder 内部 `ScanOrderOrderProduct` 的字段差异:
88
- * - `product_option_item[*]`:内部为 `{ product_option_item_id, option_group_id, num, price, ... }`,
89
- * 出站由 `normalizeSubmitProduct` 重命名为 `{ option_group_item_id, option_group_id, num }`
88
+ * - `product_option_item[*]`:内部为 `{ option_group_item_id, option_group_id, num, price, ... }`,
89
+ * 出站保留 `{ option_group_item_id, option_group_id, num }`
90
90
  * (后端 checkout 协议;丢弃 `price` 等运行时辅助字段)。
91
91
  * - `product_bundle[*].option[*]`:同上重命名规则。
92
92
  *
93
- * 运行时(UI 显示、加购合并、指纹、持久化)全部消费内部字段名 `product_option_item_id`,
94
- * 仅在 SDK 提交边界做一次出站映射,不影响 opaque identity 契约。
93
+ * 运行时(UI 显示、加购合并、指纹、持久化)与提交边界统一消费字段名
94
+ * `option_group_item_id`,保持 tempOrder 与后端协议一致。
95
95
  */
96
96
  export interface ScanOrderSubmitProduct extends Omit<ScanOrderOrderProduct, '_origin' | 'identity_key'> {
97
97
  /**
@@ -14,13 +14,13 @@ export var ScanOrderHooks = /*#__PURE__*/function (ScanOrderHooks) {
14
14
  * 出站 payload 版本的商品行。
15
15
  *
16
16
  * 与 tempOrder 内部 `ScanOrderOrderProduct` 的字段差异:
17
- * - `product_option_item[*]`:内部为 `{ product_option_item_id, option_group_id, num, price, ... }`,
18
- * 出站由 `normalizeSubmitProduct` 重命名为 `{ option_group_item_id, option_group_id, num }`
17
+ * - `product_option_item[*]`:内部为 `{ option_group_item_id, option_group_id, num, price, ... }`,
18
+ * 出站保留 `{ option_group_item_id, option_group_id, num }`
19
19
  * (后端 checkout 协议;丢弃 `price` 等运行时辅助字段)。
20
20
  * - `product_bundle[*].option[*]`:同上重命名规则。
21
21
  *
22
- * 运行时(UI 显示、加购合并、指纹、持久化)全部消费内部字段名 `product_option_item_id`,
23
- * 仅在 SDK 提交边界做一次出站映射,不影响 opaque identity 契约。
22
+ * 运行时(UI 显示、加购合并、指纹、持久化)与提交边界统一消费字段名
23
+ * `option_group_item_id`,保持 tempOrder 与后端协议一致。
24
24
  */
25
25
 
26
26
  /**
@@ -381,14 +381,14 @@ export function buildProductLineFingerprint(productOptionItem, productBundle) {
381
381
  var normalizedOpts = optArr.map(function (item) {
382
382
  var _item$price;
383
383
  return {
384
- product_option_item_id: Number(item === null || item === void 0 ? void 0 : item.product_option_item_id) || 0,
384
+ option_group_item_id: Number(item === null || item === void 0 ? void 0 : item.option_group_item_id) || 0,
385
385
  option_group_id: Number(item === null || item === void 0 ? void 0 : item.option_group_id) || 0,
386
386
  num: typeof (item === null || item === void 0 ? void 0 : item.num) === 'number' && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
387
387
  price: String((_item$price = item === null || item === void 0 ? void 0 : item.price) !== null && _item$price !== void 0 ? _item$price : '')
388
388
  };
389
389
  }).sort(function (p, q) {
390
- if (p.product_option_item_id !== q.product_option_item_id) {
391
- return p.product_option_item_id - q.product_option_item_id;
390
+ if (p.option_group_item_id !== q.option_group_item_id) {
391
+ return p.option_group_item_id - q.option_group_item_id;
392
392
  }
393
393
  if (p.option_group_id !== q.option_group_id) return p.option_group_id - q.option_group_id;
394
394
  if (p.num !== q.num) return p.num - q.num;
package/lib/core/index.js CHANGED
@@ -50,6 +50,7 @@ var PisellOSCore = class {
50
50
  this.serverOptions = options.server;
51
51
  }
52
52
  this.initialize(options);
53
+ console.log("constructor1234");
53
54
  }
54
55
  initialize(options) {
55
56
  if (options == null ? void 0 : options.plugins) {
@@ -289,7 +289,7 @@ var formatOptionsToOrigin = (options) => {
289
289
  return options.map((d) => {
290
290
  return {
291
291
  num: d.num,
292
- option_group_item_id: d.product_option_item_id,
292
+ option_group_item_id: d.option_group_item_id,
293
293
  option_group_id: d.option_group_id
294
294
  };
295
295
  });
@@ -18,6 +18,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
18
18
  private cacheId;
19
19
  private salesSummaryModuleName;
20
20
  private rulesHooksOverride?;
21
+ private orderHooks?;
21
22
  private otherParams?;
22
23
  /**
23
24
  * Populate `savedAmount` on each discount based on product-level discount details.
@@ -143,6 +144,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
143
144
  * 视为 wallet pass;其它支付项保持不变。
144
145
  */
145
146
  updateVoucherOrderPayments(payments: OrderPaymentSource[]): OrderPaymentData[];
147
+ private shouldMergeProductToOrder;
146
148
  addProductToOrder(product: Partial<OrderProduct> & OrderProductIdentity, booking?: AddProductBookingInput): Promise<OrderProduct[]>;
147
149
  private hasGoodPassDiscount;
148
150
  updateProductInOrder(params: UpdateProductInOrderParams): Promise<OrderProduct[]>;
@@ -76,7 +76,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
76
76
  }
77
77
  }
78
78
  async initialize(core, options) {
79
- var _a;
79
+ var _a, _b, _c;
80
80
  this.core = core;
81
81
  this.store = options.store;
82
82
  if (!this.store.tempOrder) {
@@ -98,6 +98,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
98
98
  this.cacheId = otherParams.cacheId;
99
99
  this.salesSummaryModuleName = otherParams.salesSummaryModuleName;
100
100
  this.rulesHooksOverride = (_a = otherParams.rules) == null ? void 0 : _a.hooks;
101
+ this.orderHooks = options.hooks || ((_b = otherParams.order) == null ? void 0 : _b.hooks) || ((_c = otherParams.hooks) == null ? void 0 : _c.order);
101
102
  this.otherParams = otherParams;
102
103
  this.registerDiscountModules(options);
103
104
  this.restoreTempOrderFromStorage();
@@ -996,6 +997,22 @@ var OrderModule = class extends import_BaseModule.BaseModule {
996
997
  this.persistTempOrder();
997
998
  return tempOrder.payments;
998
999
  }
1000
+ async shouldMergeProductToOrder(params) {
1001
+ var _a;
1002
+ const onBeforeMergeProductToOrder = (_a = this.orderHooks) == null ? void 0 : _a.onBeforeMergeProductToOrder;
1003
+ if (!onBeforeMergeProductToOrder)
1004
+ return true;
1005
+ const result = await onBeforeMergeProductToOrder({
1006
+ ...params,
1007
+ defaultShouldMerge: true
1008
+ });
1009
+ if (typeof result === "boolean")
1010
+ return result;
1011
+ if (result && typeof result === "object" && typeof result.shouldMerge === "boolean") {
1012
+ return result.shouldMerge;
1013
+ }
1014
+ return true;
1015
+ }
999
1016
  // ─── TempOrder: 商品 CRUD ───
1000
1017
  async addProductToOrder(product, booking) {
1001
1018
  var _a;
@@ -1018,13 +1035,28 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1018
1035
  return false;
1019
1036
  if (item.product_variant_id !== productToAdd.product_variant_id)
1020
1037
  return false;
1021
- const existedFingerprint = (0, import_utils3.buildProductLineFingerprint)(
1038
+ const existedFingerprint2 = (0, import_utils3.buildProductLineFingerprint)(
1022
1039
  item.product_option_item,
1023
1040
  item.product_bundle
1024
1041
  );
1025
- return existedFingerprint === incomingFingerprint;
1042
+ return existedFingerprint2 === incomingFingerprint;
1026
1043
  });
1027
- if (matchedIndex === -1) {
1044
+ const matchedProduct = matchedIndex === -1 ? null : tempOrder.products[matchedIndex];
1045
+ const existedFingerprint = matchedProduct ? (0, import_utils3.buildProductLineFingerprint)(
1046
+ matchedProduct.product_option_item,
1047
+ matchedProduct.product_bundle
1048
+ ) : "";
1049
+ const shouldMerge = matchedProduct ? await this.shouldMergeProductToOrder({
1050
+ incomingProduct: productToAdd,
1051
+ normalizedIncoming,
1052
+ matchedProduct,
1053
+ matchedIndex,
1054
+ incomingFingerprint,
1055
+ existedFingerprint,
1056
+ tempOrder,
1057
+ booking
1058
+ }) : false;
1059
+ if (matchedIndex === -1 || !matchedProduct || !shouldMerge) {
1028
1060
  this.captureProductRuntime(
1029
1061
  tempOrder,
1030
1062
  productToAdd,
@@ -1039,7 +1071,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1039
1071
  }
1040
1072
  tempOrder.products.push(normalizedIncoming);
1041
1073
  } else {
1042
- const targetProduct = tempOrder.products[matchedIndex];
1074
+ const targetProduct = matchedProduct;
1043
1075
  const targetUid = (_a = targetProduct.metadata) == null ? void 0 : _a.unique_identification_number;
1044
1076
  const normalizedProduct = (0, import_utils3.normalizeOrderProduct)({
1045
1077
  ...productToAdd,
@@ -1592,7 +1624,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1592
1624
  // TODO 获取详情的接口
1593
1625
  async getOrderInfoByRemote(order_id) {
1594
1626
  const res = await this.request.get(`/order/sales/${order_id}`, {
1595
- with: ["products", "scheduleEvents", "payments", "customer", "summary", "contacts_info"]
1627
+ with: ["products", "bookings", "payments", "customer", "summary", "contacts_info"]
1596
1628
  });
1597
1629
  if (res.code === 200) {
1598
1630
  this.store.lastOrderInfo = res.data;
@@ -1716,7 +1748,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1716
1748
  }
1717
1749
  async getOrderInfo(order_id) {
1718
1750
  const res = await this.request.get(`/order/sales/${order_id}`, {
1719
- with: ["products", "scheduleEvents"]
1751
+ with: ["products", "bookings"]
1720
1752
  });
1721
1753
  return res;
1722
1754
  }
@@ -186,6 +186,25 @@ export interface UpdateProductInOrderParams {
186
186
  product_bundle?: any[];
187
187
  }
188
188
  export type AddProductBookingInput = Record<string, any>;
189
+ export interface OrderProductMergeDecisionContext {
190
+ incomingProduct: Partial<OrderProduct> & OrderProductIdentity;
191
+ normalizedIncoming: OrderProduct;
192
+ matchedProduct: OrderProduct;
193
+ matchedIndex: number;
194
+ incomingFingerprint: string;
195
+ existedFingerprint: string;
196
+ tempOrder: OrderTempOrder;
197
+ booking?: AddProductBookingInput;
198
+ defaultShouldMerge: boolean;
199
+ }
200
+ export type OrderProductMergeDecisionResult = boolean | {
201
+ shouldMerge: boolean;
202
+ reason?: string;
203
+ [key: string]: any;
204
+ };
205
+ export interface OrderHooksConfig {
206
+ onBeforeMergeProductToOrder?: (context: OrderProductMergeDecisionContext) => OrderProductMergeDecisionResult | Promise<OrderProductMergeDecisionResult>;
207
+ }
189
208
  /**
190
209
  * 订单信息
191
210
  */
@@ -250,7 +250,7 @@ function formatSubmitOptionItems(options) {
250
250
  return options.map((d) => {
251
251
  const option = {
252
252
  num: d == null ? void 0 : d.num,
253
- option_group_item_id: (d == null ? void 0 : d.option_group_item_id) ?? (d == null ? void 0 : d.product_option_item_id),
253
+ option_group_item_id: d == null ? void 0 : d.option_group_item_id,
254
254
  option_group_id: d == null ? void 0 : d.option_group_id
255
255
  };
256
256
  const addPrice = (d == null ? void 0 : d.add_price) ?? (d == null ? void 0 : d.price);
@@ -525,7 +525,9 @@ function buildSubmitPayload(params) {
525
525
  delivery_type: tempOrder.delivery_type || "nil",
526
526
  schedule_date: scheduleDate,
527
527
  created_at: tempOrder.created_at || formatDateTime(now),
528
- bookings: (tempOrder.bookings || []).map((booking) => normalizeSubmitBooking(booking)),
528
+ bookings: (tempOrder.bookings || []).filter(
529
+ (booking) => Number(booking.parent_id ?? 0) !== 0
530
+ ).map((booking) => normalizeSubmitBooking(booking)),
529
531
  payments: tempOrder.payments || [],
530
532
  // discount_list: tempOrder.discount_list || [],
531
533
  relation_forms: tempOrder.relation_forms || [],
@@ -25,6 +25,9 @@ export declare class PaymentModule extends BaseModule implements Module, Payment
25
25
  private dbManager;
26
26
  private logger;
27
27
  private voucherUpdateLockByOrderUuid;
28
+ private payMethodMemoryCache;
29
+ private payMethodListInFlight;
30
+ private isRefreshingPaymentMethods;
28
31
  protected otherParams: any;
29
32
  cash: CashPayment;
30
33
  eftpos: EftposPayment;
@@ -59,6 +62,7 @@ export declare class PaymentModule extends BaseModule implements Module, Payment
59
62
  * 获取支付方式列表
60
63
  */
61
64
  getPayMethodListAsync(): Promise<PaymentMethod[]>;
65
+ private loadPayMethodListAsync;
62
66
  /**
63
67
  * 后台刷新支付方式列表
64
68
  */
@@ -76,6 +76,9 @@ var PaymentModule = class extends import_BaseModule.BaseModule {
76
76
  this.defaultVersion = "1.0.0";
77
77
  // LoggerManager 实例
78
78
  this.voucherUpdateLockByOrderUuid = /* @__PURE__ */ new Map();
79
+ this.payMethodMemoryCache = null;
80
+ this.payMethodListInFlight = null;
81
+ this.isRefreshingPaymentMethods = false;
79
82
  this.otherParams = {};
80
83
  this.cash = new import_cash.CashPaymentImpl(this);
81
84
  this.eftpos = new import_eftpos.EftposPaymentImpl(this);
@@ -228,7 +231,20 @@ var PaymentModule = class extends import_BaseModule.BaseModule {
228
231
  * 获取支付方式列表
229
232
  */
230
233
  async getPayMethodListAsync() {
234
+ var _a;
231
235
  this.logInfo("Starting getPayMethodListAsync");
236
+ if ((_a = this.payMethodMemoryCache) == null ? void 0 : _a.length) {
237
+ return this.payMethodMemoryCache;
238
+ }
239
+ if (this.payMethodListInFlight) {
240
+ return this.payMethodListInFlight;
241
+ }
242
+ this.payMethodListInFlight = this.loadPayMethodListAsync().finally(() => {
243
+ this.payMethodListInFlight = null;
244
+ });
245
+ return this.payMethodListInFlight;
246
+ }
247
+ async loadPayMethodListAsync() {
232
248
  try {
233
249
  let cachedMethods = [];
234
250
  try {
@@ -238,12 +254,14 @@ var PaymentModule = class extends import_BaseModule.BaseModule {
238
254
  }
239
255
  const hasCache = cachedMethods.length > 0;
240
256
  if (hasCache) {
257
+ this.payMethodMemoryCache = cachedMethods;
241
258
  this.refreshPaymentMethodsInBackground(cachedMethods);
242
259
  return cachedMethods;
243
260
  }
244
261
  const response = await this.request.get("/pay/custom-payment/all");
245
- response.data = this.filterPayMethods(response.data);
262
+ response.data = await this.filterPayMethods(response.data);
246
263
  const payMethods = response.data || [];
264
+ this.payMethodMemoryCache = payMethods;
247
265
  try {
248
266
  for (const method of payMethods) {
249
267
  await this.dbManager.update("pay_method", method);
@@ -269,14 +287,18 @@ var PaymentModule = class extends import_BaseModule.BaseModule {
269
287
  * 后台刷新支付方式列表
270
288
  */
271
289
  async refreshPaymentMethodsInBackground(cachedMethods) {
290
+ if (this.isRefreshingPaymentMethods)
291
+ return;
292
+ this.isRefreshingPaymentMethods = true;
272
293
  this.logInfo("Starting refreshPaymentMethodsInBackground", {
273
294
  cachedMethodsCount: cachedMethods.length
274
295
  });
275
296
  try {
276
297
  console.log("[PaymentModule] 后台刷新支付方式列表...");
277
298
  const response = await this.request.get("/pay/custom-payment/all");
278
- response.data = this.filterPayMethods(response.data);
299
+ response.data = await this.filterPayMethods(response.data);
279
300
  const newPayMethods = response.data || [];
301
+ this.payMethodMemoryCache = newPayMethods;
280
302
  const hasChanges = this.hasPaymentMethodsChanged(
281
303
  cachedMethods,
282
304
  newPayMethods
@@ -310,6 +332,8 @@ var PaymentModule = class extends import_BaseModule.BaseModule {
310
332
  }
311
333
  } catch (error) {
312
334
  console.error("[PaymentModule] 后台刷新支付方式失败", error);
335
+ } finally {
336
+ this.isRefreshingPaymentMethods = false;
313
337
  }
314
338
  }
315
339
  /**