@pisell/pisellos 2.2.291 → 2.2.293

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 (174) hide show
  1. package/dist/core/index.d.ts +7 -0
  2. package/dist/core/index.js +108 -65
  3. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  4. package/dist/model/strategy/adapter/itemRule/adapter.js +135 -35
  5. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  6. package/dist/model/strategy/adapter/itemRule/evaluator.js +25 -1
  7. package/dist/model/strategy/adapter/itemRule/type.d.ts +44 -0
  8. package/dist/model/strategy/adapter/itemRule/type.js +19 -1
  9. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  10. package/dist/modules/BookingContext/index.d.ts +3 -0
  11. package/dist/modules/BookingContext/index.js +42 -13
  12. package/dist/modules/BookingContext/types.d.ts +4 -4
  13. package/dist/modules/BookingContext/types.js +3 -3
  14. package/dist/modules/OpenData/types.d.ts +1 -0
  15. package/dist/modules/Order/index.d.ts +18 -3
  16. package/dist/modules/Order/index.js +885 -485
  17. package/dist/modules/Order/salesNotes.d.ts +31 -0
  18. package/dist/modules/Order/salesNotes.js +492 -0
  19. package/dist/modules/Order/types.d.ts +93 -5
  20. package/dist/modules/Order/types.js +5 -0
  21. package/dist/modules/Order/utils.d.ts +12 -0
  22. package/dist/modules/Order/utils.js +96 -31
  23. package/dist/modules/Product/types.d.ts +2 -0
  24. package/dist/modules/ProductList/clientDataVariants.d.ts +50 -0
  25. package/dist/modules/ProductList/clientDataVariants.js +216 -0
  26. package/dist/modules/ProductList/index.d.ts +18 -3
  27. package/dist/modules/ProductList/index.js +220 -38
  28. package/dist/modules/ProductList/types.d.ts +10 -0
  29. package/dist/modules/Quotation/index.d.ts +22 -0
  30. package/dist/modules/Quotation/index.js +293 -28
  31. package/dist/modules/ResourcePlanner/index.d.ts +0 -22
  32. package/dist/modules/ResourcePlanner/index.js +1 -180
  33. package/dist/modules/ResourcePlanner/localClock.d.ts +33 -0
  34. package/dist/modules/ResourcePlanner/localClock.js +183 -0
  35. package/dist/modules/ResourcePlanner/planner.d.ts +5 -14
  36. package/dist/modules/ResourcePlanner/planner.js +2111 -958
  37. package/dist/modules/ResourcePlanner/types.d.ts +359 -187
  38. package/dist/modules/ResourcePlanner/types.js +33 -1
  39. package/dist/plugins/request.d.ts +1 -0
  40. package/dist/server/index.d.ts +17 -2
  41. package/dist/server/index.js +1134 -932
  42. package/dist/server/modules/floor-plan/index.d.ts +4 -0
  43. package/dist/server/modules/floor-plan/index.js +240 -98
  44. package/dist/server/modules/menu/index.js +48 -23
  45. package/dist/server/modules/order/index.d.ts +17 -7
  46. package/dist/server/modules/order/index.js +419 -207
  47. package/dist/server/modules/products/index.d.ts +10 -4
  48. package/dist/server/modules/products/index.js +177 -84
  49. package/dist/server/modules/resource/index.js +21 -13
  50. package/dist/server/utils/product.d.ts +1 -1
  51. package/dist/server/utils/product.js +186 -22
  52. package/dist/server/utils/small-ticket.d.ts +9 -1
  53. package/dist/server/utils/small-ticket.js +131 -84
  54. package/dist/solution/BaseSales/index.d.ts +26 -3
  55. package/dist/solution/BaseSales/index.js +1384 -905
  56. package/dist/solution/BaseSales/types.d.ts +2 -0
  57. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +3 -0
  58. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +10 -3
  59. package/dist/solution/BaseSales/utils.js +6 -3
  60. package/dist/solution/BookingByStep/index.d.ts +4 -4
  61. package/dist/solution/BookingTicket/index.d.ts +1 -1
  62. package/dist/solution/BookingTicket/index.js +4 -2
  63. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +2 -1
  64. package/dist/solution/BookingTicket/utils/addProductDecision.js +6 -3
  65. package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
  66. package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
  67. package/dist/solution/RegisterAndLogin/config.js +95 -40
  68. package/dist/solution/RegisterAndLogin/index.js +4 -1
  69. package/dist/solution/ScanOrder/index.d.ts +1 -0
  70. package/dist/solution/ScanOrder/index.js +31 -27
  71. package/dist/solution/ScanOrder/types.d.ts +2 -0
  72. package/dist/solution/ScanOrder/utils.d.ts +1 -0
  73. package/dist/solution/ScanOrder/utils.js +8 -3
  74. package/dist/solution/UnifiedBookingSales/index.d.ts +128 -74
  75. package/dist/solution/UnifiedBookingSales/index.js +3877 -963
  76. package/dist/solution/UnifiedBookingSales/remoteOccupancyCache.d.ts +49 -0
  77. package/dist/solution/UnifiedBookingSales/remoteOccupancyCache.js +430 -0
  78. package/dist/solution/UnifiedBookingSales/types.d.ts +161 -77
  79. package/dist/solution/UnifiedBookingSales/types.js +4 -9
  80. package/dist/solution/VenueBooking/index.d.ts +3 -0
  81. package/dist/solution/VenueBooking/index.js +549 -497
  82. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  83. package/dist/solution/VenueBooking/utils/dateSummary.js +3 -1
  84. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +2 -0
  85. package/dist/solution/VenueBooking/utils/slotMerge.js +3 -1
  86. package/dist/utils/platform.d.ts +8 -0
  87. package/dist/utils/platform.js +15 -0
  88. package/lib/core/index.d.ts +7 -0
  89. package/lib/core/index.js +20 -2
  90. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  91. package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
  92. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  93. package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
  94. package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
  95. package/lib/model/strategy/adapter/itemRule/type.js +19 -1
  96. package/lib/modules/BookingContext/index.d.ts +3 -0
  97. package/lib/modules/BookingContext/index.js +35 -8
  98. package/lib/modules/BookingContext/types.d.ts +4 -4
  99. package/lib/modules/BookingContext/types.js +3 -3
  100. package/lib/modules/OpenData/types.d.ts +1 -0
  101. package/lib/modules/Order/index.d.ts +18 -3
  102. package/lib/modules/Order/index.js +325 -28
  103. package/lib/modules/Order/salesNotes.d.ts +31 -0
  104. package/lib/modules/Order/salesNotes.js +382 -0
  105. package/lib/modules/Order/types.d.ts +93 -5
  106. package/lib/modules/Order/types.js +4 -0
  107. package/lib/modules/Order/utils.d.ts +12 -0
  108. package/lib/modules/Order/utils.js +85 -16
  109. package/lib/modules/Product/types.d.ts +2 -0
  110. package/lib/modules/ProductList/clientDataVariants.d.ts +50 -0
  111. package/lib/modules/ProductList/clientDataVariants.js +204 -0
  112. package/lib/modules/ProductList/index.d.ts +18 -3
  113. package/lib/modules/ProductList/index.js +137 -8
  114. package/lib/modules/ProductList/types.d.ts +10 -0
  115. package/lib/modules/Quotation/index.d.ts +22 -0
  116. package/lib/modules/Quotation/index.js +158 -11
  117. package/lib/modules/ResourcePlanner/index.d.ts +0 -22
  118. package/lib/modules/ResourcePlanner/index.js +9 -129
  119. package/lib/modules/ResourcePlanner/localClock.d.ts +33 -0
  120. package/lib/modules/ResourcePlanner/localClock.js +205 -0
  121. package/lib/modules/ResourcePlanner/planner.d.ts +5 -14
  122. package/lib/modules/ResourcePlanner/planner.js +1807 -783
  123. package/lib/modules/ResourcePlanner/types.d.ts +359 -187
  124. package/lib/modules/ResourcePlanner/types.js +13 -1
  125. package/lib/plugins/request.d.ts +1 -0
  126. package/lib/server/index.d.ts +17 -2
  127. package/lib/server/index.js +149 -21
  128. package/lib/server/modules/floor-plan/index.d.ts +4 -0
  129. package/lib/server/modules/floor-plan/index.js +60 -7
  130. package/lib/server/modules/menu/index.js +26 -4
  131. package/lib/server/modules/order/index.d.ts +17 -7
  132. package/lib/server/modules/order/index.js +194 -57
  133. package/lib/server/modules/products/index.d.ts +10 -4
  134. package/lib/server/modules/products/index.js +93 -23
  135. package/lib/server/modules/resource/index.js +12 -2
  136. package/lib/server/utils/product.d.ts +1 -1
  137. package/lib/server/utils/product.js +163 -3
  138. package/lib/server/utils/small-ticket.d.ts +9 -1
  139. package/lib/server/utils/small-ticket.js +123 -79
  140. package/lib/solution/BaseSales/index.d.ts +26 -3
  141. package/lib/solution/BaseSales/index.js +396 -70
  142. package/lib/solution/BaseSales/types.d.ts +2 -0
  143. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +3 -0
  144. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +9 -2
  145. package/lib/solution/BaseSales/utils.js +3 -0
  146. package/lib/solution/BookingByStep/index.d.ts +4 -4
  147. package/lib/solution/BookingTicket/index.d.ts +1 -1
  148. package/lib/solution/BookingTicket/index.js +2 -1
  149. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +2 -1
  150. package/lib/solution/BookingTicket/utils/addProductDecision.js +5 -2
  151. package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
  152. package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
  153. package/lib/solution/RegisterAndLogin/config.js +49 -8
  154. package/lib/solution/RegisterAndLogin/index.js +4 -1
  155. package/lib/solution/ScanOrder/index.d.ts +1 -0
  156. package/lib/solution/ScanOrder/index.js +5 -1
  157. package/lib/solution/ScanOrder/types.d.ts +2 -0
  158. package/lib/solution/ScanOrder/utils.d.ts +1 -0
  159. package/lib/solution/ScanOrder/utils.js +4 -0
  160. package/lib/solution/UnifiedBookingSales/index.d.ts +128 -74
  161. package/lib/solution/UnifiedBookingSales/index.js +2592 -424
  162. package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.d.ts +49 -0
  163. package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.js +316 -0
  164. package/lib/solution/UnifiedBookingSales/types.d.ts +161 -77
  165. package/lib/solution/UnifiedBookingSales/types.js +4 -6
  166. package/lib/solution/VenueBooking/index.d.ts +3 -0
  167. package/lib/solution/VenueBooking/index.js +33 -9
  168. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  169. package/lib/solution/VenueBooking/utils/dateSummary.js +3 -1
  170. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +2 -0
  171. package/lib/solution/VenueBooking/utils/slotMerge.js +3 -1
  172. package/lib/utils/platform.d.ts +8 -0
  173. package/lib/utils/platform.js +22 -0
  174. package/package.json +1 -1
@@ -101,6 +101,7 @@ Object.defineProperty(exports, "resolveSafeProductNum", {
101
101
  }
102
102
  });
103
103
  exports.resolveSubmitCollectPax = resolveSubmitCollectPax;
104
+ exports.resolveSubmitOrderType = resolveSubmitOrderType;
104
105
  Object.defineProperty(exports, "shouldBuildManualProductDiscount", {
105
106
  enumerable: true,
106
107
  get: function () {
@@ -125,6 +126,7 @@ var _decimal = _interopRequireDefault(require("decimal.js"));
125
126
  var _utils = require("../Holder/utils");
126
127
  var _utils2 = require("../../solution/ScanOrder/utils");
127
128
  var _orderCollectionIdentity = require("./utils/orderCollectionIdentity");
129
+ var _salesNotes = require("./salesNotes");
128
130
  var _manualProductDiscount = require("./utils/manualProductDiscount");
129
131
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
130
132
  /**
@@ -855,6 +857,11 @@ function normalizeSubmitPlatform(platform) {
855
857
  if (lower === 'h5') return 'H5';
856
858
  return value;
857
859
  }
860
+ function normalizeSubmitProductionCode(value) {
861
+ if (value === undefined || value === null) return undefined;
862
+ const productionCode = String(value).trim();
863
+ return productionCode || undefined;
864
+ }
858
865
 
859
866
  // 后端 checkout 协议字段 option_group_item_id;tempOrder 内部也保持同一字段名。
860
867
  function formatSubmitOptionItems(options) {
@@ -866,6 +873,9 @@ function formatSubmitOptionItems(options) {
866
873
  option_group_item_id: d?.option_group_item_id,
867
874
  option_group_id: d?.option_group_id
868
875
  };
876
+ const productionCode = normalizeSubmitProductionCode(d?.production_code);
877
+ delete option.production_code;
878
+ if (productionCode !== undefined) option.production_code = productionCode;
869
879
  const addPrice = d?.add_price ?? d?.price;
870
880
  if (addPrice !== undefined) option.add_price = String(addPrice);
871
881
  delete option.price;
@@ -906,9 +916,13 @@ function formatSubmitBundleItems(bundle) {
906
916
  const num = toBundleNumber(rawBundle.num ?? rawBundle.quantity, 1);
907
917
  const bundleMapId = resolveSubmitBundleMapId(rawBundle);
908
918
  const hasSubmitBundleDiscounts = Array.isArray(rawBundle.discount_list) && rawBundle.discount_list.length > 0;
919
+ const productionCode = normalizeSubmitProductionCode(rawBundle.production_code);
909
920
  return {
910
921
  is_charge_tax: rawBundle.is_charge_tax ?? 0,
911
922
  bundle_variant_id: rawBundle.bundle_variant_id ?? 0,
923
+ ...(productionCode !== undefined ? {
924
+ production_code: productionCode
925
+ } : {}),
912
926
  num,
913
927
  quantity: toBundleNumber(rawBundle.quantity ?? rawBundle.num, num),
914
928
  extension_id: rawBundle.extension_id ?? 0,
@@ -965,8 +979,10 @@ function normalizeSubmitProduct(product) {
965
979
  discountway: _deprecatedDiscountway,
966
980
  product_discount_reason: _deprecatedProductDiscountReason,
967
981
  discount_per: _deprecatedDiscountPer,
982
+ production_code: rawProductionCode,
968
983
  ...productRest
969
984
  } = submitProduct;
985
+ const productionCode = normalizeSubmitProductionCode(rawProductionCode);
970
986
  delete productRest[`product_${'option'}_item`];
971
987
  const rawMetadata = submitProduct.metadata || {};
972
988
  const bookingUid = rawMetadata.booking_uid;
@@ -1000,6 +1016,9 @@ function normalizeSubmitProduct(product) {
1000
1016
  };
1001
1017
  return {
1002
1018
  ...productRest,
1019
+ ...(productionCode !== undefined ? {
1020
+ production_code: productionCode
1021
+ } : {}),
1003
1022
  ...(bookingUid ? {
1004
1023
  booking_uid: bookingUid
1005
1024
  } : {}),
@@ -1110,6 +1129,7 @@ function createDefaultTempOrder(params) {
1110
1129
  request_unique_idempotency_token: '',
1111
1130
  vouchers: [],
1112
1131
  products: [],
1132
+ notes: [],
1113
1133
  bookings: [],
1114
1134
  payments: [],
1115
1135
  surcharges: [],
@@ -1119,10 +1139,58 @@ function createDefaultTempOrder(params) {
1119
1139
  holder: null,
1120
1140
  metadata: {},
1121
1141
  _extend: {
1122
- productsByUid: {}
1142
+ productsByUid: {},
1143
+ salesNotesState: {
1144
+ loaded: true,
1145
+ dirty: false
1146
+ }
1123
1147
  }
1124
1148
  };
1125
1149
  }
1150
+ function hasBoundBookingResource(bookings) {
1151
+ if (!Array.isArray(bookings)) return false;
1152
+ return bookings.some(booking => {
1153
+ if (!booking || typeof booking !== 'object') return false;
1154
+ if (Number(booking.parent_id) === 0) return false;
1155
+ const resources = booking.resources;
1156
+ if (!Array.isArray(resources)) return false;
1157
+ return resources.some(resource => {
1158
+ if (!resource || typeof resource !== 'object') return false;
1159
+ const relationId = String(resource.relation_id ?? '').trim();
1160
+ return relationId !== '' && relationId !== '0';
1161
+ });
1162
+ });
1163
+ }
1164
+ function isPersistedSubmitOrderId(orderId) {
1165
+ if (orderId === undefined || orderId === null || orderId === '') return false;
1166
+ const normalizedOrderId = Number(orderId);
1167
+ return Number.isFinite(normalizedOrderId) && normalizedOrderId > 0;
1168
+ }
1169
+
1170
+ /**
1171
+ * 解析 checkout 的订单类型。
1172
+ * dine_in 普通落库单在新增桌台资源后,即使原类型仍是 virtual,也必须按 table-order 提交。
1173
+ */
1174
+ function resolveSubmitOrderType(params) {
1175
+ const {
1176
+ requestedType,
1177
+ tempOrderType,
1178
+ orderId,
1179
+ businessCode,
1180
+ tempOrderBusinessCode,
1181
+ bookings
1182
+ } = params;
1183
+ const currentType = requestedType ?? tempOrderType;
1184
+ const resolvedBusinessCode = businessCode ?? tempOrderBusinessCode;
1185
+ if (isPersistedSubmitOrderId(orderId) && resolvedBusinessCode === 'dine_in' && currentType === 'virtual' && hasBoundBookingResource(bookings)) {
1186
+ return 'table-order';
1187
+ }
1188
+ if (currentType) return currentType;
1189
+ if (Array.isArray(bookings) && bookings.length > 0) {
1190
+ return businessCode === 'dine_in' ? 'table-order' : 'appointment_booking';
1191
+ }
1192
+ return 'virtual';
1193
+ }
1126
1194
  function buildSubmitPayload(params) {
1127
1195
  const {
1128
1196
  tempOrder,
@@ -1156,22 +1224,18 @@ function buildSubmitPayload(params) {
1156
1224
  total_refund_amount: _totalRefundAmount,
1157
1225
  create_date: _createDate,
1158
1226
  holder_id: _holderId,
1227
+ notes: _notes,
1159
1228
  ...tempOrderRest
1160
1229
  } = tempOrder;
1161
- let submitType = type ?? tempOrder.type;
1162
- if (!submitType) {
1163
- // 如果外部没有传递 types,根据订单里当前是否有 bookings 来决定是 appointment_booking 还是 virtual
1164
- if (tempOrder?.bookings?.length) {
1165
- // 260807 如果 biz 是堂食,type 使用table-order
1166
- if (businessCode === 'dine_in') {
1167
- submitType = 'table-order';
1168
- } else {
1169
- submitType = 'appointment_booking';
1170
- }
1171
- } else {
1172
- submitType = 'virtual';
1173
- }
1174
- }
1230
+ const resolvedBusinessCode = businessCode ?? tempOrder.business_code;
1231
+ const submitType = resolveSubmitOrderType({
1232
+ requestedType: type,
1233
+ tempOrderType: tempOrder.type,
1234
+ orderId: tempOrder.order_id,
1235
+ businessCode,
1236
+ tempOrderBusinessCode: tempOrder.business_code,
1237
+ bookings: tempOrder.bookings
1238
+ });
1175
1239
  const payload = {
1176
1240
  ...tempOrderRest,
1177
1241
  customer_id: tempOrder.customer_id ?? 1,
@@ -1185,7 +1249,7 @@ function buildSubmitPayload(params) {
1185
1249
  platform: normalizeSubmitPlatform(platform),
1186
1250
  request_unique_idempotency_token: params?.request_unique_idempotency_token || tempOrder.request_unique_idempotency_token || `${tempOrder.external_sale_number}_${now.getTime()}`,
1187
1251
  type: submitType,
1188
- business_code: businessCode ?? tempOrder.business_code,
1252
+ business_code: resolvedBusinessCode,
1189
1253
  sales_channel: tempOrder.sales_channel || 'my_pisel',
1190
1254
  order_sales_channel: channel ?? tempOrder.order_sales_channel ?? 'online_store',
1191
1255
  status: tempOrder.status || 'normal',
@@ -1218,6 +1282,11 @@ function buildSubmitPayload(params) {
1218
1282
  ...rest
1219
1283
  };
1220
1284
  })(),
1285
+ ...(tempOrder._extend?.salesNotesState?.dirty ? {
1286
+ notes: (0, _salesNotes.encodeSalesNotes)(tempOrder.notes || [], {
1287
+ allowUnresolvedOrderTarget: true
1288
+ })
1289
+ } : {}),
1221
1290
  products: (tempOrder.products || []).map(product => normalizeSubmitProduct(product))
1222
1291
  };
1223
1292
  if (!enhance) return payload;
@@ -77,6 +77,8 @@ export interface ProductData {
77
77
  is_gst: number;
78
78
  /** 商品编码 */
79
79
  code: string;
80
+ /** ERP/生产侧商品编码;有规格时以选中 Variant 的值为准 */
81
+ production_code?: string;
80
82
  /** 商品条码 */
81
83
  barcode: string;
82
84
  /** 是否支持配送 */
@@ -0,0 +1,50 @@
1
+ import type { PisellCore } from '../../types';
2
+ import type { RequestPlugin } from '../../plugins';
3
+ import type { ProductData } from '../Product/types';
4
+ export declare const PRODUCT_QUERY_DATA_VARIANT_RELATIONS: readonly ["category", "collection", "resourceRelation", "bundleGroup.bundleItem", "optionGroup.optionItem", "variantGroup.variantItem", "dataVariants"];
5
+ /**
6
+ * 判断当前商品查询是否会被本地 OS Server 接管。
7
+ *
8
+ * H5 RequestPlugin 即使收到 osServer=true 仍会直接请求远端接口,因此必须按
9
+ * RequestPlugin 实际 baseUrl 对应的已注册路由判断,不能只看请求选项。
10
+ */
11
+ export declare function isProductQueryHandledByOsServer(core: PisellCore | undefined, request: RequestPlugin | undefined): boolean;
12
+ export interface ResolveClientDataVariantsParams {
13
+ core: PisellCore | undefined;
14
+ otherParams?: Record<string, any>;
15
+ products: ProductData[];
16
+ queryPayload: Record<string, any>;
17
+ handledByOsServer: boolean;
18
+ scheduleList?: unknown;
19
+ menuList?: unknown;
20
+ /** Quote fast paths require hydrated relations; legacy list resolution does not. */
21
+ requireCompleteDataVariantRelations?: boolean;
22
+ /** Quote fast paths require every referenced rule; legacy list resolution is best-effort. */
23
+ requireEvaluatorReady?: boolean;
24
+ }
25
+ export type ResolveClientDataVariantsResult = {
26
+ status: 'handled-by-os-server' | 'empty' | 'data-variants-unavailable' | 'evaluator-unavailable' | 'evaluator-not-ready';
27
+ products: ProductData[];
28
+ } | {
29
+ status: 'resolved';
30
+ products: ProductData[];
31
+ } | {
32
+ status: 'error';
33
+ products: ProductData[];
34
+ error: unknown;
35
+ };
36
+ /**
37
+ * Strict client-side Data Variant resolution for quote fast paths.
38
+ *
39
+ * Unlike resolveClientDataVariants, callers can distinguish a complete local
40
+ * result from a capability/readiness/error fallback and decide to query the
41
+ * remote product endpoint instead.
42
+ */
43
+ export declare function tryResolveClientDataVariants({ core, otherParams, products, queryPayload, handledByOsServer, scheduleList: explicitScheduleList, menuList: explicitMenuList, requireCompleteDataVariantRelations, requireEvaluatorReady, }: ResolveClientDataVariantsParams): ResolveClientDataVariantsResult;
44
+ /**
45
+ * 未启用商品 OS 路由时,在客户端补做 Data Variant 解析。
46
+ *
47
+ * 商品列表和预约报价必须共用这个边界,避免 H5 的弹窗报价绕过客户端智能定价。
48
+ * OS Server 已接管时直接信任服务端结果,确保同一批商品只评估一次。
49
+ */
50
+ export declare function resolveClientDataVariants({ core, otherParams, products, queryPayload, handledByOsServer, scheduleList: explicitScheduleList, menuList: explicitMenuList, }: ResolveClientDataVariantsParams): ProductData[];
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PRODUCT_QUERY_DATA_VARIANT_RELATIONS = void 0;
7
+ exports.isProductQueryHandledByOsServer = isProductQueryHandledByOsServer;
8
+ exports.resolveClientDataVariants = resolveClientDataVariants;
9
+ exports.tryResolveClientDataVariants = tryResolveClientDataVariants;
10
+ const PRODUCT_QUERY_DATA_VARIANT_RELATIONS = exports.PRODUCT_QUERY_DATA_VARIANT_RELATIONS = ['category', 'collection', 'resourceRelation', 'bundleGroup.bundleItem', 'optionGroup.optionItem', 'variantGroup.variantItem', 'dataVariants'];
11
+
12
+ /**
13
+ * 判断当前商品查询是否会被本地 OS Server 接管。
14
+ *
15
+ * H5 RequestPlugin 即使收到 osServer=true 仍会直接请求远端接口,因此必须按
16
+ * RequestPlugin 实际 baseUrl 对应的已注册路由判断,不能只看请求选项。
17
+ */
18
+ function isProductQueryHandledByOsServer(core, request) {
19
+ const server = core?.server;
20
+ if (!server || typeof server.hasRoute !== 'function') return false;
21
+ const requestBaseUrl = String(request?.baseUrl || '/shop').replace(/\/+$/, '');
22
+ return server.hasRoute('post', `${requestBaseUrl}/product/query`) === true;
23
+ }
24
+ function getBundleItems(product) {
25
+ if (!Array.isArray(product.bundle_group)) return [];
26
+ return product.bundle_group.flatMap(group => Array.isArray(group?.bundle_item) ? group.bundle_item : []);
27
+ }
28
+ function hasCompleteDataVariantRelations(products) {
29
+ return products.every(product => Array.isArray(product?.data_variants));
30
+ }
31
+ function hasAnyDataVariants(products) {
32
+ return products.some(product => (product.data_variants?.length || 0) > 0 || getBundleItems(product).some(item => Array.isArray(item?.data_variants) && item.data_variants.length > 0));
33
+ }
34
+ function collectReferencedRuleIds(products) {
35
+ const ids = new Set();
36
+ const remember = variants => {
37
+ if (!Array.isArray(variants)) return;
38
+ variants.forEach(variant => {
39
+ const id = String(variant?.data_variant_rule_id ?? '').trim();
40
+ if (id) ids.add(id);
41
+ });
42
+ };
43
+ products.forEach(product => {
44
+ remember(product.data_variants);
45
+ getBundleItems(product).forEach(item => remember(item?.data_variants));
46
+ });
47
+ return ids;
48
+ }
49
+ function isEvaluatorReady(evaluator, products) {
50
+ if (typeof evaluator.isReady === 'function') {
51
+ if (evaluator.isReady() === false) return false;
52
+ }
53
+ if (evaluator.isReady === false || evaluator.ready === false) return false;
54
+
55
+ // The built-in evaluator is installed before its strategy request completes.
56
+ // A referenced Data Variant cannot be evaluated authoritatively until those
57
+ // configs have arrived. Evaluators without this capability remain compatible.
58
+ if (typeof evaluator.getStrategyConfigs === 'function') {
59
+ const configs = evaluator.getStrategyConfigs();
60
+ if (!Array.isArray(configs) || configs.length === 0) return false;
61
+ const availableRuleIds = new Set(configs.map(config => String(config?.metadata?.id ?? '').trim()).filter(Boolean));
62
+ return Array.from(collectReferencedRuleIds(products)).every(id => availableRuleIds.has(id));
63
+ }
64
+ return true;
65
+ }
66
+
67
+ /**
68
+ * Strict client-side Data Variant resolution for quote fast paths.
69
+ *
70
+ * Unlike resolveClientDataVariants, callers can distinguish a complete local
71
+ * result from a capability/readiness/error fallback and decide to query the
72
+ * remote product endpoint instead.
73
+ */
74
+ function tryResolveClientDataVariants({
75
+ core,
76
+ otherParams = {},
77
+ products,
78
+ queryPayload,
79
+ handledByOsServer,
80
+ scheduleList: explicitScheduleList,
81
+ menuList: explicitMenuList,
82
+ requireCompleteDataVariantRelations = true,
83
+ requireEvaluatorReady = true
84
+ }) {
85
+ if (handledByOsServer) {
86
+ return {
87
+ status: 'handled-by-os-server',
88
+ products
89
+ };
90
+ }
91
+ if (products.length === 0) {
92
+ return {
93
+ status: 'empty',
94
+ products
95
+ };
96
+ }
97
+ if (requireCompleteDataVariantRelations && !hasCompleteDataVariantRelations(products)) {
98
+ return {
99
+ status: 'data-variants-unavailable',
100
+ products
101
+ };
102
+ }
103
+
104
+ // Explicit empty arrays mean the query hydrated the relation and there is no
105
+ // rule to apply. This is an authoritative local base-price result even when
106
+ // no evaluator has been installed.
107
+ if (!hasAnyDataVariants(products)) {
108
+ return {
109
+ status: 'resolved',
110
+ products
111
+ };
112
+ }
113
+ const evaluator = core?.context?.dataVariantEvaluator;
114
+ if (!evaluator || typeof evaluator.resolveProducts !== 'function') {
115
+ return {
116
+ status: 'evaluator-unavailable',
117
+ products
118
+ };
119
+ }
120
+ try {
121
+ if (requireEvaluatorReady && !isEvaluatorReady(evaluator, products)) {
122
+ return {
123
+ status: 'evaluator-not-ready',
124
+ products
125
+ };
126
+ }
127
+ } catch (error) {
128
+ return {
129
+ status: 'error',
130
+ products,
131
+ error
132
+ };
133
+ }
134
+ const strategyContext = queryPayload.strategy_context && typeof queryPayload.strategy_context === 'object' ? queryPayload.strategy_context : {};
135
+ const fatherModule = String(otherParams.fatherModule || '').trim();
136
+ const scheduleModule = (fatherModule ? core?.getModule(`${fatherModule}_schedule`) : null) || core?.getModule('schedule');
137
+ const moduleScheduleList = scheduleModule?.getScheduleList?.();
138
+ const contextScheduleList = core?.context?.scheduleList;
139
+ const contextMenuList = core?.context?.menuList;
140
+ const businessData = {
141
+ products,
142
+ scheduleDateTime: queryPayload.schedule_datetime || queryPayload.schedule_date,
143
+ scheduleList: Array.isArray(explicitScheduleList) && explicitScheduleList.length > 0 ? explicitScheduleList : Array.isArray(moduleScheduleList) && moduleScheduleList.length > 0 ? moduleScheduleList : Array.isArray(contextScheduleList) ? contextScheduleList : [],
144
+ menuList: Array.isArray(explicitMenuList) ? explicitMenuList : Array.isArray(otherParams.menuList) ? otherParams.menuList : Array.isArray(contextMenuList) ? contextMenuList : [],
145
+ customerId: queryPayload.customer_id,
146
+ channel: strategyContext.channel,
147
+ orderType: strategyContext.orderType || strategyContext.order_type,
148
+ businessCode: strategyContext.business_code ?? strategyContext.businessCode,
149
+ availableWalletIds: strategyContext.available_wallet_ids,
150
+ custom: strategyContext
151
+ };
152
+ try {
153
+ const result = evaluator.resolveProducts(businessData);
154
+ if (!Array.isArray(result?.products)) {
155
+ return {
156
+ status: 'error',
157
+ products,
158
+ error: new Error('Data Variant evaluator returned an invalid product list')
159
+ };
160
+ }
161
+ return {
162
+ status: 'resolved',
163
+ products: result.products
164
+ };
165
+ } catch (error) {
166
+ return {
167
+ status: 'error',
168
+ products,
169
+ error
170
+ };
171
+ }
172
+ }
173
+
174
+ /**
175
+ * 未启用商品 OS 路由时,在客户端补做 Data Variant 解析。
176
+ *
177
+ * 商品列表和预约报价必须共用这个边界,避免 H5 的弹窗报价绕过客户端智能定价。
178
+ * OS Server 已接管时直接信任服务端结果,确保同一批商品只评估一次。
179
+ */
180
+ function resolveClientDataVariants({
181
+ core,
182
+ otherParams = {},
183
+ products,
184
+ queryPayload,
185
+ handledByOsServer,
186
+ scheduleList: explicitScheduleList,
187
+ menuList: explicitMenuList
188
+ }) {
189
+ const result = tryResolveClientDataVariants({
190
+ core,
191
+ otherParams,
192
+ products,
193
+ queryPayload,
194
+ handledByOsServer,
195
+ scheduleList: explicitScheduleList,
196
+ menuList: explicitMenuList,
197
+ requireCompleteDataVariantRelations: false,
198
+ requireEvaluatorReady: false
199
+ });
200
+ if (result.status === 'error') {
201
+ console.error('[ClientDataVariants] Data Variant 客户端解析失败', result.error);
202
+ }
203
+ return result.products;
204
+ }
@@ -1,6 +1,6 @@
1
1
  import { Module, PisellCore } from '../../types';
2
2
  import { BaseModule } from '../BaseModule';
3
- import { ProductListLoadProductsParams } from './types';
3
+ import { ProductListLoadProductsParams, ProductListStoreQueryParams } from './types';
4
4
  import { ProductData } from '../Product/types';
5
5
  export * from './types';
6
6
  export declare class ProductList extends BaseModule implements Module {
@@ -9,6 +9,7 @@ export declare class ProductList extends BaseModule implements Module {
9
9
  private store;
10
10
  private request;
11
11
  private otherParams;
12
+ private rawProductPriceSources;
12
13
  constructor(name?: string, version?: string);
13
14
  initialize(core: PisellCore, options: any): Promise<void>;
14
15
  /**
@@ -25,19 +26,33 @@ export declare class ProductList extends BaseModule implements Module {
25
26
  * @example
26
27
  * const products = await productList.getAddTimeProducts({ schedule_date: '2026-06-16' });
27
28
  */
28
- getAddTimeProducts(params?: ProductListLoadProductsParams): Promise<any>;
29
+ getAddTimeProducts(params?: ProductListLoadProductsParams): Promise<ProductData[]>;
29
30
  loadProducts({ category_ids, product_ids, collection, menu_list_ids, customer_id: paramsCustomerId, with_count, schedule_datetime, schedule_date, cacheId, with_schedule, extension_type, status, strategy_context, }?: ProductListLoadProductsParams, options?: {
30
31
  callback?: (result: any) => void;
31
32
  subscriberId?: string;
32
- }): Promise<any>;
33
+ }): Promise<ProductData[]>;
33
34
  loadProductsPrice({ ids, customer_id, schedule_date, channel, }: {
34
35
  ids?: number[];
35
36
  customer_id?: number;
36
37
  schedule_date?: string;
37
38
  channel?: string;
38
39
  }): Promise<any>;
40
+ /**
41
+ * Remember raw remote product records before client-side Data Variant
42
+ * evaluation. Quote-only reads can then always start from a clean baseline.
43
+ */
44
+ rememberRawProductQueryResult(products: Array<ProductData | Record<string, any>>): void;
45
+ private replaceRawProductQueryResult;
46
+ /**
47
+ * Return isolated raw price sources for the requested products.
48
+ *
49
+ * Missing IDs are intentionally omitted so callers can remotely fetch only
50
+ * the incomplete part of a batch quote.
51
+ */
52
+ getRawProductPriceSources(ids: number[]): Map<number, ProductData>;
39
53
  getProducts(): Promise<ProductData[]>;
40
54
  getProduct(id: number): Promise<ProductData | undefined>;
55
+ queryProducts(params?: ProductListStoreQueryParams): Promise<ProductData[]>;
41
56
  getProductByIds(ids: number[]): Promise<ProductData[] | undefined>;
42
57
  addProduct(products: ProductData[]): Promise<void>;
43
58
  selectProducts(products: ProductData[]): Promise<void>;