@pisell/pisellos 2.2.314 → 2.2.316

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 (268) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +3 -1
  3. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  4. package/dist/model/strategy/adapter/itemRule/adapter.js +74 -7
  5. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  6. package/dist/model/strategy/adapter/itemRule/evaluator.js +13 -0
  7. package/dist/model/strategy/adapter/itemRule/type.d.ts +40 -1
  8. package/dist/model/strategy/adapter/itemRule/type.js +10 -0
  9. package/dist/model/strategy/adapter/promotion/evaluator.js +89 -104
  10. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +3 -1
  11. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +28 -4
  12. package/dist/modules/BookingContext/utils/productExtend.d.ts +7 -0
  13. package/dist/modules/BookingContext/utils/productExtend.js +62 -18
  14. package/dist/modules/BookingContext/utils/resources.js +1 -1
  15. package/dist/modules/BusinessAvailability/index.d.ts +30 -0
  16. package/dist/modules/BusinessAvailability/index.js +204 -0
  17. package/dist/modules/Cart/index.js +4 -3
  18. package/dist/modules/Cart/types.d.ts +2 -0
  19. package/dist/modules/Cart/utils/cartProduct.d.ts +3 -1
  20. package/dist/modules/Cart/utils/cartProduct.js +59 -32
  21. package/dist/modules/FulfillmentTiming/index.d.ts +11 -0
  22. package/dist/modules/FulfillmentTiming/index.js +407 -0
  23. package/dist/modules/FulfillmentTiming/types.d.ts +67 -0
  24. package/dist/modules/FulfillmentTiming/types.js +1 -0
  25. package/dist/modules/Holder/utils.d.ts +2 -0
  26. package/dist/modules/Holder/utils.js +32 -2
  27. package/dist/modules/OpenData/contactInfo.d.ts +20 -0
  28. package/dist/modules/OpenData/contactInfo.js +70 -0
  29. package/dist/modules/OpenData/index.d.ts +1 -0
  30. package/dist/modules/OpenData/index.js +1 -0
  31. package/dist/modules/OpenData/types.d.ts +23 -0
  32. package/dist/modules/Order/holderRelations.d.ts +14 -0
  33. package/dist/modules/Order/holderRelations.js +154 -0
  34. package/dist/modules/Order/index.d.ts +16 -4
  35. package/dist/modules/Order/index.js +926 -511
  36. package/dist/modules/Order/localEftposState.d.ts +13 -0
  37. package/dist/modules/Order/localEftposState.js +39 -0
  38. package/dist/modules/Order/pickupTiming.d.ts +46 -0
  39. package/dist/modules/Order/pickupTiming.js +53 -0
  40. package/dist/modules/Order/types.d.ts +49 -3
  41. package/dist/modules/Order/types.js +2 -0
  42. package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +1 -1
  43. package/dist/modules/Order/utils/discountProductLineIdentity.js +142 -7
  44. package/dist/modules/Order/utils/orderCollectionIdentity.js +24 -10
  45. package/dist/modules/Order/utils.d.ts +2 -1
  46. package/dist/modules/Order/utils.js +61 -17
  47. package/dist/modules/Payment/index.js +9 -10
  48. package/dist/modules/Product/types.d.ts +11 -0
  49. package/dist/modules/ProductList/index.js +1 -1
  50. package/dist/modules/ResourcePlanner/planner.d.ts +2 -0
  51. package/dist/modules/ResourcePlanner/planner.js +332 -23
  52. package/dist/modules/ResourcePlanner/types.d.ts +29 -0
  53. package/dist/modules/Rules/index.js +62 -61
  54. package/dist/modules/Schedule/index.d.ts +8 -0
  55. package/dist/modules/Schedule/index.js +141 -39
  56. package/dist/modules/index.d.ts +1 -0
  57. package/dist/modules/index.js +1 -0
  58. package/dist/plugins/request.d.ts +7 -0
  59. package/dist/server/index.d.ts +1 -0
  60. package/dist/server/index.js +1557 -1322
  61. package/dist/server/modules/form/index.d.ts +19 -0
  62. package/dist/server/modules/form/index.js +205 -0
  63. package/dist/server/modules/form/types.d.ts +13 -0
  64. package/dist/server/modules/form/types.js +3 -0
  65. package/dist/server/modules/index.d.ts +3 -0
  66. package/dist/server/modules/index.js +4 -0
  67. package/dist/server/modules/order/index.d.ts +19 -0
  68. package/dist/server/modules/order/index.js +1071 -774
  69. package/dist/server/modules/order/types.d.ts +4 -0
  70. package/dist/server/modules/products/index.d.ts +28 -7
  71. package/dist/server/modules/products/index.js +1297 -770
  72. package/dist/server/modules/products/replication.d.ts +8 -0
  73. package/dist/server/modules/products/replication.js +69 -0
  74. package/dist/server/modules/products/types.d.ts +12 -1
  75. package/dist/server/modules/products/types.js +4 -0
  76. package/dist/server/test.json +1 -1
  77. package/dist/server/utils/small-ticket.d.ts +1 -85
  78. package/dist/server/utils/small-ticket.js +2 -2542
  79. package/dist/shared/payment/loadPaymentMethods.d.ts +9 -0
  80. package/dist/shared/payment/loadPaymentMethods.js +66 -0
  81. package/dist/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  82. package/dist/shared/receipt/customerInvoiceLanguages.js +60 -0
  83. package/dist/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
  84. package/dist/shared/receipt/loadCustomerInvoiceLayout.js +184 -0
  85. package/dist/shared/receipt/small-ticket.d.ts +96 -0
  86. package/dist/shared/receipt/small-ticket.js +2763 -0
  87. package/dist/shared/receipt/templateVisibility.d.ts +26 -0
  88. package/dist/shared/receipt/templateVisibility.js +68 -0
  89. package/dist/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
  90. package/dist/shared/sales/loadSalesOrderSnapshot.js +21 -0
  91. package/dist/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  92. package/dist/solution/BaseSales/fulfillmentItemRules.js +750 -0
  93. package/dist/solution/BaseSales/index.d.ts +43 -16
  94. package/dist/solution/BaseSales/index.js +2028 -1247
  95. package/dist/solution/BaseSales/pickupTiming.d.ts +47 -0
  96. package/dist/solution/BaseSales/pickupTiming.js +616 -0
  97. package/dist/solution/BaseSales/types.d.ts +12 -0
  98. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -1
  99. package/dist/solution/BaseSales/utils/parseSalesResponse.js +10 -3
  100. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +14 -4
  101. package/dist/solution/BookingByStep/index.d.ts +4 -2
  102. package/dist/solution/BookingByStep/index.js +8 -3
  103. package/dist/solution/BookingTicket/index.d.ts +23 -3
  104. package/dist/solution/BookingTicket/index.js +867 -507
  105. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
  106. package/dist/solution/BookingTicket/utils/addProductDecision.js +1 -1
  107. package/dist/solution/BookingTicket/utils/cartView.js +3 -1
  108. package/dist/solution/OrderInvoicePreview/index.d.ts +66 -0
  109. package/dist/solution/OrderInvoicePreview/index.js +340 -0
  110. package/dist/solution/RegisterAndLogin/config.js +54 -11
  111. package/dist/solution/RegisterAndLogin/index.d.ts +2 -0
  112. package/dist/solution/RegisterAndLogin/index.js +1 -1
  113. package/dist/solution/RegisterAndLogin/utils.d.ts +12 -4
  114. package/dist/solution/RegisterAndLogin/utils.js +36 -16
  115. package/dist/solution/ScanOrder/index.js +65 -31
  116. package/dist/solution/ScanOrder/types.d.ts +3 -0
  117. package/dist/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
  118. package/dist/solution/UnifiedBookingSales/businessAvailability.js +292 -0
  119. package/dist/solution/UnifiedBookingSales/index.d.ts +36 -4
  120. package/dist/solution/UnifiedBookingSales/index.js +1715 -906
  121. package/dist/solution/UnifiedBookingSales/types.d.ts +16 -2
  122. package/dist/solution/VenueBooking/index.d.ts +15 -2
  123. package/dist/solution/VenueBooking/index.js +1062 -785
  124. package/dist/solution/VenueBooking/types.d.ts +2 -1
  125. package/dist/solution/VenueBooking/types.js +1 -0
  126. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  127. package/dist/solution/VenueBooking/utils/dateSummary.js +7 -4
  128. package/dist/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  129. package/dist/solution/VenueBooking/utils/smartPricing.js +273 -0
  130. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  131. package/dist/solution/VenueBooking/utils/timeSlot.js +6 -3
  132. package/dist/solution/index.d.ts +1 -0
  133. package/dist/solution/index.js +2 -1
  134. package/lib/index.d.ts +2 -0
  135. package/lib/index.js +21 -1
  136. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  137. package/lib/model/strategy/adapter/itemRule/adapter.js +54 -4
  138. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  139. package/lib/model/strategy/adapter/itemRule/evaluator.js +9 -0
  140. package/lib/model/strategy/adapter/itemRule/type.d.ts +40 -1
  141. package/lib/model/strategy/adapter/itemRule/type.js +10 -0
  142. package/lib/model/strategy/adapter/promotion/evaluator.js +9 -14
  143. package/lib/model/strategy/adapter/promotion/index.js +46 -1
  144. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +3 -1
  145. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +17 -1
  146. package/lib/modules/BookingContext/utils/productExtend.d.ts +7 -0
  147. package/lib/modules/BookingContext/utils/productExtend.js +45 -2
  148. package/lib/modules/BookingContext/utils/resources.js +1 -1
  149. package/lib/modules/BusinessAvailability/index.d.ts +30 -0
  150. package/lib/modules/BusinessAvailability/index.js +146 -0
  151. package/lib/modules/Cart/index.js +4 -2
  152. package/lib/modules/Cart/types.d.ts +2 -0
  153. package/lib/modules/Cart/utils/cartProduct.d.ts +3 -1
  154. package/lib/modules/Cart/utils/cartProduct.js +39 -20
  155. package/lib/modules/FulfillmentTiming/index.d.ts +11 -0
  156. package/lib/modules/FulfillmentTiming/index.js +359 -0
  157. package/lib/modules/FulfillmentTiming/types.d.ts +67 -0
  158. package/lib/modules/FulfillmentTiming/types.js +5 -0
  159. package/lib/modules/Holder/utils.d.ts +2 -0
  160. package/lib/modules/Holder/utils.js +27 -1
  161. package/lib/modules/OpenData/contactInfo.d.ts +20 -0
  162. package/lib/modules/OpenData/contactInfo.js +56 -0
  163. package/lib/modules/OpenData/index.d.ts +1 -0
  164. package/lib/modules/OpenData/index.js +12 -0
  165. package/lib/modules/OpenData/types.d.ts +23 -0
  166. package/lib/modules/Order/holderRelations.d.ts +14 -0
  167. package/lib/modules/Order/holderRelations.js +98 -0
  168. package/lib/modules/Order/index.d.ts +16 -4
  169. package/lib/modules/Order/index.js +284 -50
  170. package/lib/modules/Order/localEftposState.d.ts +13 -0
  171. package/lib/modules/Order/localEftposState.js +44 -0
  172. package/lib/modules/Order/pickupTiming.d.ts +46 -0
  173. package/lib/modules/Order/pickupTiming.js +61 -0
  174. package/lib/modules/Order/types.d.ts +49 -3
  175. package/lib/modules/Order/types.js +1 -0
  176. package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +1 -1
  177. package/lib/modules/Order/utils/discountProductLineIdentity.js +51 -2
  178. package/lib/modules/Order/utils/orderCollectionIdentity.js +5 -0
  179. package/lib/modules/Order/utils.d.ts +2 -1
  180. package/lib/modules/Order/utils.js +49 -11
  181. package/lib/modules/Payment/index.js +3 -4
  182. package/lib/modules/Product/types.d.ts +11 -0
  183. package/lib/modules/ProductList/index.js +1 -1
  184. package/lib/modules/ResourcePlanner/planner.d.ts +2 -0
  185. package/lib/modules/ResourcePlanner/planner.js +252 -8
  186. package/lib/modules/ResourcePlanner/types.d.ts +29 -0
  187. package/lib/modules/Rules/index.js +2 -1
  188. package/lib/modules/Schedule/index.d.ts +8 -0
  189. package/lib/modules/Schedule/index.js +68 -12
  190. package/lib/modules/index.d.ts +1 -0
  191. package/lib/modules/index.js +11 -0
  192. package/lib/plugins/request.d.ts +7 -0
  193. package/lib/server/index.d.ts +1 -0
  194. package/lib/server/index.js +166 -39
  195. package/lib/server/modules/form/index.d.ts +19 -0
  196. package/lib/server/modules/form/index.js +73 -0
  197. package/lib/server/modules/form/types.d.ts +13 -0
  198. package/lib/server/modules/form/types.js +9 -0
  199. package/lib/server/modules/index.d.ts +3 -0
  200. package/lib/server/modules/index.js +15 -1
  201. package/lib/server/modules/order/index.d.ts +19 -0
  202. package/lib/server/modules/order/index.js +160 -7
  203. package/lib/server/modules/order/types.d.ts +4 -0
  204. package/lib/server/modules/products/index.d.ts +28 -7
  205. package/lib/server/modules/products/index.js +226 -63
  206. package/lib/server/modules/products/replication.d.ts +8 -0
  207. package/lib/server/modules/products/replication.js +30 -0
  208. package/lib/server/modules/products/types.d.ts +12 -1
  209. package/lib/server/modules/products/types.js +3 -0
  210. package/lib/server/test.json +1 -1
  211. package/lib/server/utils/small-ticket.d.ts +1 -85
  212. package/lib/server/utils/small-ticket.js +9 -2305
  213. package/lib/shared/payment/loadPaymentMethods.d.ts +9 -0
  214. package/lib/shared/payment/loadPaymentMethods.js +40 -0
  215. package/lib/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  216. package/lib/shared/receipt/customerInvoiceLanguages.js +58 -0
  217. package/lib/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
  218. package/lib/shared/receipt/loadCustomerInvoiceLayout.js +124 -0
  219. package/lib/shared/receipt/small-ticket.d.ts +96 -0
  220. package/lib/shared/receipt/small-ticket.js +2555 -0
  221. package/lib/shared/receipt/templateVisibility.d.ts +26 -0
  222. package/lib/shared/receipt/templateVisibility.js +67 -0
  223. package/lib/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
  224. package/lib/shared/sales/loadSalesOrderSnapshot.js +22 -0
  225. package/lib/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  226. package/lib/solution/BaseSales/fulfillmentItemRules.js +259 -0
  227. package/lib/solution/BaseSales/index.d.ts +43 -16
  228. package/lib/solution/BaseSales/index.js +401 -33
  229. package/lib/solution/BaseSales/pickupTiming.d.ts +47 -0
  230. package/lib/solution/BaseSales/pickupTiming.js +290 -0
  231. package/lib/solution/BaseSales/types.d.ts +12 -0
  232. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -1
  233. package/lib/solution/BaseSales/utils/parseSalesResponse.js +7 -0
  234. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +16 -8
  235. package/lib/solution/BookingByStep/index.d.ts +4 -2
  236. package/lib/solution/BookingByStep/index.js +7 -3
  237. package/lib/solution/BookingTicket/index.d.ts +23 -3
  238. package/lib/solution/BookingTicket/index.js +197 -9
  239. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
  240. package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -1
  241. package/lib/solution/BookingTicket/utils/cartView.js +3 -1
  242. package/lib/solution/OrderInvoicePreview/index.d.ts +66 -0
  243. package/lib/solution/OrderInvoicePreview/index.js +246 -0
  244. package/lib/solution/RegisterAndLogin/config.js +57 -11
  245. package/lib/solution/RegisterAndLogin/index.d.ts +2 -0
  246. package/lib/solution/RegisterAndLogin/index.js +9 -1
  247. package/lib/solution/RegisterAndLogin/utils.d.ts +12 -4
  248. package/lib/solution/RegisterAndLogin/utils.js +24 -17
  249. package/lib/solution/ScanOrder/index.js +59 -20
  250. package/lib/solution/ScanOrder/types.d.ts +3 -0
  251. package/lib/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
  252. package/lib/solution/UnifiedBookingSales/businessAvailability.js +138 -0
  253. package/lib/solution/UnifiedBookingSales/index.d.ts +36 -4
  254. package/lib/solution/UnifiedBookingSales/index.js +562 -75
  255. package/lib/solution/UnifiedBookingSales/types.d.ts +16 -2
  256. package/lib/solution/VenueBooking/index.d.ts +15 -2
  257. package/lib/solution/VenueBooking/index.js +243 -96
  258. package/lib/solution/VenueBooking/types.d.ts +2 -1
  259. package/lib/solution/VenueBooking/types.js +1 -0
  260. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  261. package/lib/solution/VenueBooking/utils/dateSummary.js +7 -4
  262. package/lib/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  263. package/lib/solution/VenueBooking/utils/smartPricing.js +224 -0
  264. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  265. package/lib/solution/VenueBooking/utils/timeSlot.js +5 -2
  266. package/lib/solution/index.d.ts +1 -0
  267. package/lib/solution/index.js +11 -0
  268. package/package.json +1 -1
@@ -9,6 +9,7 @@ var _exportNames = {
9
9
  };
10
10
  exports.PaymentModule = void 0;
11
11
  exports.generateRequestUniqueId = generateRequestUniqueId;
12
+ var _loadPaymentMethods = require("../../shared/payment/loadPaymentMethods");
12
13
  var _BaseModule = require("../BaseModule");
13
14
  var _types = require("./types");
14
15
  Object.keys(_types).forEach(function (key) {
@@ -282,12 +283,10 @@ class PaymentModule extends _BaseModule.BaseModule {
282
283
  async getPayMethodListAsync() {
283
284
  this.logInfo('Starting getPayMethodListAsync');
284
285
  try {
285
- const response = await this.request.get('/pay/custom-payment/all', {
286
+ const payMethods = await (0, _loadPaymentMethods.loadPaymentMethods)(this.request, {
287
+ transport: 'os-server',
286
288
  filterPaymentMethods: true
287
- }, {
288
- osServer: true
289
289
  });
290
- const payMethods = response?.data || response || [];
291
290
  this.logInfo('getPayMethodListAsync completed successfully', {
292
291
  payMethods
293
292
  });
@@ -218,6 +218,17 @@ export interface ProductData {
218
218
  bundle?: any[];
219
219
  /** 商品选项组成 */
220
220
  options?: any[];
221
+ /** 单规格组;用于由已选 option 反查规格项名称、价格等商品快照字段。 */
222
+ option_group?: Array<{
223
+ id: number | string;
224
+ option_item?: Array<{
225
+ id: number | string;
226
+ name?: string | Record<string, any>;
227
+ title?: string | Record<string, any>;
228
+ [key: string]: any;
229
+ }>;
230
+ [key: string]: any;
231
+ }>;
221
232
  /** 商品原信息 */
222
233
  origin?: any;
223
234
  /** 容量 */
@@ -125,7 +125,7 @@ class ProductList extends _BaseModule.BaseModule {
125
125
  online_store: 'online-store',
126
126
  scan_to_order: 'online-store',
127
127
  'scan-to-order': 'online-store',
128
- scan_to_order_2: 'mobile_order',
128
+ scan_to_order_2: 'online-store',
129
129
  scan_to_order_3: 'scantoorder3'
130
130
  };
131
131
  const rawApplicationCode = this.otherParams?.channel;
@@ -1,5 +1,7 @@
1
1
  import type { AvailabilityProjection, AvailabilityProjectionInput, AvailabilityQuery, AvailabilityQueryResult, AvailabilitySelectionValidationParams, AvailabilitySelectionValidationResult, GetProductTimeRangesRequest, GetProductTimeRangesRuntimeOptions, ProductTimeRangeGroup } from './types';
2
2
  export declare function createAvailabilityProjection(input: AvailabilityProjectionInput): AvailabilityProjection;
3
+ /** Resolve the label without changing the real calendar timestamp. */
4
+ export declare function getDurationBusinessDate(projection: AvailabilityProjection, startAt: string): string;
3
5
  export declare function getProductTimeRanges(projection: AvailabilityProjection, request?: GetProductTimeRangesRequest, runtimeOptions?: GetProductTimeRangesRuntimeOptions): ProductTimeRangeGroup[];
4
6
  export declare function queryAvailabilityProjection(projection: AvailabilityProjection, request: AvailabilityQuery, runtimeOptions?: GetProductTimeRangesRuntimeOptions): AvailabilityQueryResult;
5
7
  export declare function validateAvailabilitySelection(projection: AvailabilityProjection, params: AvailabilitySelectionValidationParams, runtimeOptions?: GetProductTimeRangesRuntimeOptions): AvailabilitySelectionValidationResult;
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.createAvailabilityProjection = createAvailabilityProjection;
7
+ exports.getDurationBusinessDate = getDurationBusinessDate;
7
8
  exports.getProductTimeRanges = getProductTimeRanges;
8
9
  exports.queryAvailabilityProjection = queryAvailabilityProjection;
9
10
  exports.validateAvailabilitySelection = validateAvailabilitySelection;
@@ -162,7 +163,11 @@ function resolveCutOffPolicyIssue(policy) {
162
163
  return null;
163
164
  }
164
165
  function addLeadWindow(base, unit, unitType, _timezoneName) {
165
- if (unitType === 'days') return (0, _localClock.addLocalCalendarDays)(base, unit);
166
+ if (unitType === 'days') {
167
+ const leadDate = (0, _localClock.addLocalCalendarDays)(base, unit);
168
+ // Positive day lead times start at midnight; zero days keeps the current-time boundary.
169
+ return Math.trunc(unit) > 0 ? (0, _localClock.localDateToScalarStart)((0, _localClock.formatLocalDate)(leadDate)) : leadDate;
170
+ }
166
171
  if (unitType === 'hours') return (0, _localClock.addLocalHours)(base, unit);
167
172
  return (0, _localClock.addLocalMinutes)(base, unit);
168
173
  }
@@ -250,6 +255,18 @@ function evaluateCandidateTimeGate(params) {
250
255
  };
251
256
  }
252
257
  const policy = product.cutOffPolicy;
258
+ // Current duration items can be shown outside business hours. Their real
259
+ // interval must remain unavailable, including products with no resource groups.
260
+ if (evaluationContext.useDurationTimeGrid && product.kind === 'duration' && !projection.meta.defaults.operatingHours.windows.some(window => {
261
+ const range = normalizeAbsoluteRange(window);
262
+ return range && contains(range, candidateRange);
263
+ })) {
264
+ return {
265
+ status: 'unavailable',
266
+ reasonCodes: ['outside_operating_hours'],
267
+ conflictCode: 'booking_cutoff'
268
+ };
269
+ }
253
270
  if (!policy) return null;
254
271
  if (resolveCutOffPolicyIssue(policy)) {
255
272
  return {
@@ -286,8 +303,8 @@ function evaluateCandidateTimeGate(params) {
286
303
  // otherwise a minute refresh turns it into 0 capacity and incorrectly
287
304
  // advances a create flow to the next slot. The earlier `past` gate still
288
305
  // rejects the anchor once its booking range has ended.
289
- const isActivePosDurationAnchor = evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration' && !product.isFlexibleDuration && evaluationContext.durationCandidateAnchorAtMs === candidateRange.start;
290
- const usesMinutePrecision = product.isFlexibleDuration || evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration';
306
+ const isActivePosDurationAnchor = evaluationContext.useExactDurationCandidateMinute && !evaluationContext.enforceSaleCutoff && product.kind === 'duration' && !product.isFlexibleDuration && evaluationContext.durationCandidateAnchorAtMs === candidateRange.start;
307
+ const usesMinutePrecision = product.isFlexibleDuration || evaluationContext.useDurationTimeGrid || evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration';
291
308
  const hasNotReachedStart = isActivePosDurationAnchor || (usesMinutePrecision ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start);
292
309
  if (hasNotReachedStart) return null;
293
310
  return {
@@ -489,11 +506,34 @@ function normalizeOperatingHours(params) {
489
506
  }));
490
507
  const windows = normalizeWindows(sourceWindows);
491
508
  const excludedWindows = normalizeWindows(params.input?.excludedWindows || []);
509
+ // Keep original dates and opening anchors separately: the availability
510
+ // windows below may be clipped at midnight or merged without segment identity.
511
+ const periodMap = new Map();
512
+ const originalPeriods = params.input?.businessPeriods || [...sourceWindows, ...(params.input?.excludedWindows || [])].map(window => ({
513
+ businessDate: window.businessDate || window.startAt.slice(0, 10),
514
+ startAt: window.openingAnchorAt || window.startAt,
515
+ endAt: window.endAt
516
+ }));
517
+ originalPeriods.forEach(period => {
518
+ const range = normalizeAbsoluteRange(period);
519
+ if (!range) return;
520
+ const previous = periodMap.get(period.businessDate);
521
+ periodMap.set(period.businessDate, {
522
+ start: previous ? Math.min(previous.start, range.start) : range.start,
523
+ end: previous ? Math.max(previous.end, range.end) : range.end
524
+ });
525
+ });
526
+ const businessPeriods = Array.from(periodMap, ([businessDate, range]) => ({
527
+ businessDate,
528
+ startAt: formatDateTime(range.start, params.timezoneName, params.fixedOffsetMinutes),
529
+ endAt: formatDateTime(range.end, params.timezoneName, params.fixedOffsetMinutes)
530
+ })).sort((left, right) => left.startAt.localeCompare(right.startAt));
492
531
  return {
493
532
  source: params.input?.source || params.fallbackSource,
494
533
  scheduleIds: uniqById(params.input?.scheduleIds || []),
495
534
  missingScheduleIds: uniqById(params.input?.missingScheduleIds || []),
496
535
  windows,
536
+ businessPeriods,
497
537
  ...(excludedWindows.length > 0 ? {
498
538
  excludedWindows
499
539
  } : {})
@@ -992,6 +1032,162 @@ function createDurationTimeRangeWithEnd(product, start, bookingEnd, projection,
992
1032
  scheduleRefs: []
993
1033
  };
994
1034
  }
1035
+
1036
+ /** Resolve the label without changing the real calendar timestamp. */
1037
+ function getDurationBusinessDate(projection, startAt) {
1038
+ const start = toDateTime(startAt);
1039
+ const periods = projection.meta.defaults.operatingHours.businessPeriods || [];
1040
+ const period = [...periods].reverse().find(item => {
1041
+ const range = normalizeAbsoluteRange(item);
1042
+ return range && range.start <= start && start < range.end;
1043
+ });
1044
+ return period?.businessDate || startAt.slice(0, 10);
1045
+ }
1046
+ function getAlignedDurationRanges(params) {
1047
+ const {
1048
+ projection,
1049
+ product,
1050
+ request,
1051
+ runtimeOptions,
1052
+ dateRange,
1053
+ operatingRanges,
1054
+ baseRanges,
1055
+ resourceWindowIndex,
1056
+ fixedOffsetMinutes
1057
+ } = params;
1058
+ const step = projection.meta.defaults.slotStepMinutes;
1059
+ const now = floorToMinute(toDateTime(runtimeOptions.evaluatedAt || projection.meta.durationCandidateAnchorAt));
1060
+ if (!Number.isFinite(now)) throw availabilityError('INVALID_TARGET_FILTER', 'evaluatedAt 必须是有效时间');
1061
+ const nowAt = formatDateTime(now, projection.meta.timezone, fixedOffsetMinutes);
1062
+ const currentBusinessDate = getDurationBusinessDate(projection, nowAt);
1063
+ const inRequestedDays = date => date >= dateRange.startDate && date <= dateRange.endDate;
1064
+ const periods = (projection.meta.defaults.operatingHours.businessPeriods || []).filter(period => inRequestedDays(period.businessDate));
1065
+ // A prepared month includes tomorrow's windows too; the single-day UI must
1066
+ // receive the selected business cycle's end, not tomorrow's closing time.
1067
+ const operatingEndAt = dateRange.startDate === dateRange.endDate && periods.length ? periods.reduce((latest, period) => period.endAt > latest ? period.endAt : latest, periods[0].endAt) : undefined;
1068
+ const ranges = [];
1069
+ const duration = resolveRequestedDurationMinutes(product, request);
1070
+ const addRange = (start, end, businessDate) => {
1071
+ if (end <= start) return;
1072
+ const candidate = createDurationTimeRangeWithEnd(product, start, end, projection, fixedOffsetMinutes);
1073
+ candidate.businessDate = businessDate || getDurationBusinessDate(projection, candidate.startAt);
1074
+ if (inRequestedDays(candidate.businessDate)) ranges.push(candidate);
1075
+ };
1076
+ // A flexible end comes from resources that actually cover this exact start,
1077
+ // never from the next future window. Keep alternative real ends separate.
1078
+ const flexibleEnds = start => {
1079
+ const operating = operatingRanges.find(range => range.start <= start && start < range.end);
1080
+ if (!operating) return [];
1081
+ const businessDate = getDurationBusinessDate(projection, formatDateTime(start, projection.meta.timezone, fixedOffsetMinutes));
1082
+ const period = projection.meta.defaults.operatingHours.businessPeriods?.find(item => item.businessDate === businessDate);
1083
+ const operatingEnd = Math.min(operating.end, period ? toDateTime(period.endAt) : operating.end);
1084
+ const requiredGroups = (product.requirementGroups || []).filter(group => group.required !== false);
1085
+ const groups = requiredGroups.map(group => projection.resources.filter(resource => matchesRequirementGroup(group, resource, product, request.partySize)).filter(resource => !request.resourceIds?.length || request.resourceIds.some(id => sameId(id, resource.id))).flatMap(resource => (resourceWindowIndex.get(String(resource.id)) || []).filter(range => range.start <= start && start < range.end).map(range => Math.min(range.end, operatingEnd))));
1086
+ if (groups.some(ends => ends.length === 0)) return [];
1087
+ if (!groups.length) return [operatingEnd];
1088
+ return Array.from(new Set(groups.flat())).filter(end => groups.every(ends => ends.some(availableEnd => availableEnd >= end))).sort((left, right) => left - right);
1089
+ };
1090
+ if (product.isFlexibleDuration) {
1091
+ // Preserve the existing continuous-window UI, with the business-day label.
1092
+ periods.forEach(period => {
1093
+ const periodRange = normalizeAbsoluteRange(period);
1094
+ baseRanges.forEach(range => {
1095
+ const start = Math.max(range.start, periodRange.start, now);
1096
+ const end = Math.min(range.end, periodRange.end);
1097
+ if (start < end) addRange(start, end, period.businessDate);
1098
+ });
1099
+ });
1100
+ } else {
1101
+ periods.forEach(period => {
1102
+ const periodRange = normalizeAbsoluteRange(period);
1103
+ const anchor = 60 % step === 0 ? toDateStart(period.businessDate) : periodRange.start;
1104
+ baseRanges.forEach(range => {
1105
+ const lower = Math.max(range.start, periodRange.start, now);
1106
+ const upper = Math.min(range.end, periodRange.end);
1107
+ let cursor = anchor + Math.ceil((lower - anchor) / (step * 60000)) * step * 60000;
1108
+ for (; cursor + duration * 60000 <= upper; cursor += step * 60000) {
1109
+ addRange(cursor, cursor + duration * 60000, period.businessDate);
1110
+ }
1111
+ });
1112
+ });
1113
+ }
1114
+ let unavailableCurrentTime;
1115
+ if (inRequestedDays(currentBusinessDate)) {
1116
+ if (product.isFlexibleDuration) {
1117
+ const ends = flexibleEnds(now);
1118
+ ends.forEach(end => addRange(now, end, currentBusinessDate));
1119
+ if (!ends.length) {
1120
+ unavailableCurrentTime = {
1121
+ productId: product.id,
1122
+ startAt: nowAt,
1123
+ date: formatDate(now),
1124
+ businessDate: currentBusinessDate,
1125
+ startTime: formatTime(now),
1126
+ status: 'unavailable',
1127
+ reasonCodes: [operatingRanges.some(range => range.start <= now && now < range.end) ? 'outside_resource_window' : 'outside_operating_hours']
1128
+ };
1129
+ }
1130
+ } else {
1131
+ // Even outside a working window the fixed product has a real end. Query
1132
+ // reports unavailable; POS manual capabilities remain a separate policy.
1133
+ addRange(now, now + duration * 60000, currentBusinessDate);
1134
+ }
1135
+ }
1136
+ const rememberedAt = request.rememberedStartAtByProductId?.[String(product.id)];
1137
+ if (rememberedAt !== undefined) {
1138
+ const start = toDateTime(rememberedAt);
1139
+ if (!Number.isFinite(start)) throw availabilityError('INVALID_TARGET_FILTER', '记忆开始时间必须是完整日期时间');
1140
+ if (product.isFlexibleDuration) {
1141
+ flexibleEnds(start).forEach(end => addRange(start, end));
1142
+ } else {
1143
+ addRange(start, start + duration * 60000);
1144
+ }
1145
+ }
1146
+ const editingAt = request.editingStartAtByProductId?.[String(product.id)];
1147
+ if (editingAt !== undefined) {
1148
+ const start = toDateTime(editingAt);
1149
+ const editingDuration = Number(request.durationMinutesByProductId?.[String(product.id)]);
1150
+ if (!Number.isFinite(start) || !Number.isInteger(editingDuration) || editingDuration <= 0) {
1151
+ throw availabilityError('INVALID_TARGET_FILTER', '编辑时间必须包含完整开始日期时间和明确的正整数时长');
1152
+ }
1153
+ // Editing restores the original interval, including its actual overnight
1154
+ // date. It neither adopts the current grid nor recomputes a flexible end.
1155
+ if (request.allowOutsideOperatingHoursForRequestedStartTimes || operatingRanges.some(range => range.start <= start && start < range.end)) {
1156
+ addRange(start, addMinutesZoned(start, editingDuration, projection.meta.timezone));
1157
+ }
1158
+ }
1159
+
1160
+ // Explicit custom input keeps its existing start + requested duration
1161
+ // semantics. Remembered input above must never use this default-30 path.
1162
+ if (dateRange.startDate === dateRange.endDate) {
1163
+ resolveRequestedDurationStartTimes(product, request).forEach(startTime => {
1164
+ const sameDayStart = toDateTimeInDate(dateRange.startDate, startTime);
1165
+ const period = periods.find(item => item.businessDate === dateRange.startDate);
1166
+ const periodRange = period ? normalizeAbsoluteRange(period) : null;
1167
+ const nextDayStart = (0, _localClock.addLocalCalendarDays)(sameDayStart, 1);
1168
+ // HH:mm is entered within a selected business day, whose early hours
1169
+ // may belong to the next calendar day. Do not move other out-of-hours
1170
+ // manual input to tomorrow merely because the business closes overnight.
1171
+ const start = periodRange && !(periodRange.start <= sameDayStart && sameDayStart < periodRange.end) && periodRange.start <= nextDayStart && nextDayStart < periodRange.end ? nextDayStart : sameDayStart;
1172
+ if (request.allowOutsideOperatingHoursForRequestedStartTimes || operatingRanges.some(range => range.start <= start && start < range.end)) {
1173
+ addRange(start, start + duration * 60000);
1174
+ }
1175
+ });
1176
+ }
1177
+ return {
1178
+ productId: product.id,
1179
+ title: product.title,
1180
+ kind: product.kind,
1181
+ slotStepMinutes: step,
1182
+ ...(operatingEndAt ? {
1183
+ operatingEndAt
1184
+ } : {}),
1185
+ ranges: dedupeProductRanges(ranges),
1186
+ ...(unavailableCurrentTime ? {
1187
+ unavailableCurrentTime
1188
+ } : {})
1189
+ };
1190
+ }
995
1191
  function getProductTimeRanges(projection, request = {}, runtimeOptions = {}) {
996
1192
  const normalizedPartySize = normalizePartySize(request.partySize);
997
1193
  const dateRange = resolveProjectionDateRange(projection, request.dateRange);
@@ -1044,6 +1240,19 @@ function getProductTimeRanges(projection, request = {}, runtimeOptions = {}) {
1044
1240
  includeExcludedWindows: allowExcludedScheduleDateOverride
1045
1241
  })).reduce((current, ranges) => current === null ? ranges : intersectRangeLists(current, ranges), null) || [] : null;
1046
1242
  const baseRanges = resourceRanges === null ? operatingRanges : intersectRangeLists(resourceRanges, operatingRanges);
1243
+ if (runtimeOptions.useDurationTimeGrid) {
1244
+ return getAlignedDurationRanges({
1245
+ projection,
1246
+ product,
1247
+ request,
1248
+ runtimeOptions,
1249
+ dateRange,
1250
+ operatingRanges,
1251
+ baseRanges,
1252
+ resourceWindowIndex,
1253
+ fixedOffsetMinutes
1254
+ });
1255
+ }
1047
1256
  const durationMinutes = resolveRequestedDurationMinutes(product, request);
1048
1257
  const flexibleStartAt = (() => {
1049
1258
  if (!product.isFlexibleDuration) return undefined;
@@ -1265,7 +1474,9 @@ function buildEvaluationContext(params) {
1265
1474
  selectionsByGroupKey,
1266
1475
  useExactDurationCandidateMinute: params.useExactDurationCandidateMinute === true,
1267
1476
  durationCandidateAnchorAtMs: Number.isFinite(durationCandidateAnchorAt) ? floorToMinute(durationCandidateAnchorAt) : null,
1268
- allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true
1477
+ allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true,
1478
+ useDurationTimeGrid: params.useDurationTimeGrid === true,
1479
+ enforceSaleCutoff: params.enforceSaleCutoff === true
1269
1480
  };
1270
1481
  }
1271
1482
  function summarizeStatuses(statuses) {
@@ -1672,6 +1883,8 @@ function queryAvailabilityProjection(projection, request, runtimeOptions = {}) {
1672
1883
  projection,
1673
1884
  evaluatedAt,
1674
1885
  resourceIds: request.resourceIds,
1886
+ useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
1887
+ enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
1675
1888
  useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1676
1889
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1677
1890
  });
@@ -1748,6 +1961,8 @@ function queryAvailabilityProjection(projection, request, runtimeOptions = {}) {
1748
1961
  partySize: normalizedPartySize
1749
1962
  }, {
1750
1963
  evaluatedAt,
1964
+ useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
1965
+ enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
1751
1966
  useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1752
1967
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1753
1968
  });
@@ -1772,7 +1987,8 @@ function queryAvailabilityProjection(projection, request, runtimeOptions = {}) {
1772
1987
  candidateRangeCache,
1773
1988
  evaluationContext
1774
1989
  });
1775
- const aggregate = byDate.get(candidate.date) || {
1990
+ const candidateDate = runtimeOptions.useDurationTimeGrid ? candidate.businessDate || candidate.date : candidate.date;
1991
+ const aggregate = byDate.get(candidateDate) || {
1776
1992
  availableCount: 0,
1777
1993
  totalCount: 0,
1778
1994
  maxPartySize: 0,
@@ -1790,8 +2006,24 @@ function queryAvailabilityProjection(projection, request, runtimeOptions = {}) {
1790
2006
  aggregate.maxCapacity += evaluated.maxCapacity;
1791
2007
  pushStatusAggregate(aggregate.statusAggregate, evaluated.status);
1792
2008
  evaluated.reasonCodes.forEach(reasonCode => aggregate.reasonCodeSet.add(reasonCode));
1793
- byDate.set(candidate.date, aggregate);
2009
+ byDate.set(candidateDate, aggregate);
1794
2010
  });
2011
+ if (group.unavailableCurrentTime) {
2012
+ const current = group.unavailableCurrentTime;
2013
+ const aggregate = byDate.get(current.businessDate) || {
2014
+ availableCount: 0,
2015
+ totalCount: 0,
2016
+ maxPartySize: 0,
2017
+ remainingCapacity: 0,
2018
+ maxCapacity: 0,
2019
+ reasonCodeSet: new Set(),
2020
+ statusAggregate: createStatusAggregate()
2021
+ };
2022
+ aggregate.totalCount += 1;
2023
+ pushStatusAggregate(aggregate.statusAggregate, 'unavailable');
2024
+ current.reasonCodes.forEach(reason => aggregate.reasonCodeSet.add(reason));
2025
+ byDate.set(current.businessDate, aggregate);
2026
+ }
1795
2027
  const dates = enumerateDates(dateRange.startDate, dateRange.endDate).map(date => {
1796
2028
  const aggregate = byDate.get(date);
1797
2029
  return {
@@ -1849,10 +2081,20 @@ function queryAvailabilityProjection(projection, request, runtimeOptions = {}) {
1849
2081
  maxPartySize = Math.max(maxPartySize, evaluated.maxPartySize);
1850
2082
  pushStatusAggregate(productStatusAggregate, evaluated.status);
1851
2083
  evaluated.reasonCodes.forEach(reasonCode => productReasonCodeSet.add(reasonCode));
1852
- const dateAggregate = dateStatusMap.get(candidate.date) || createStatusAggregate();
2084
+ const candidateDate = runtimeOptions.useDurationTimeGrid ? candidate.businessDate || candidate.date : candidate.date;
2085
+ const dateAggregate = dateStatusMap.get(candidateDate) || createStatusAggregate();
1853
2086
  pushStatusAggregate(dateAggregate, evaluated.status);
1854
- dateStatusMap.set(candidate.date, dateAggregate);
2087
+ dateStatusMap.set(candidateDate, dateAggregate);
1855
2088
  });
2089
+ if (group.unavailableCurrentTime) {
2090
+ const current = group.unavailableCurrentTime;
2091
+ totalTimeCount += 1;
2092
+ pushStatusAggregate(productStatusAggregate, 'unavailable');
2093
+ current.reasonCodes.forEach(reason => productReasonCodeSet.add(reason));
2094
+ const dateAggregate = dateStatusMap.get(current.businessDate) || createStatusAggregate();
2095
+ pushStatusAggregate(dateAggregate, 'unavailable');
2096
+ dateStatusMap.set(current.businessDate, dateAggregate);
2097
+ }
1856
2098
  const availableDateCount = Array.from(dateStatusMap.values()).filter(aggregate => {
1857
2099
  const status = summarizeStatusAggregate(aggregate);
1858
2100
  return status === 'available' || status === 'limited';
@@ -1921,6 +2163,8 @@ function validateAvailabilitySelection(projection, params, runtimeOptions = {})
1921
2163
  projection,
1922
2164
  evaluatedAt,
1923
2165
  requirementSelections: params.requirementSelections,
2166
+ useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
2167
+ enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
1924
2168
  useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1925
2169
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1926
2170
  })
@@ -92,6 +92,9 @@ export interface AvailabilityProduct {
92
92
  raw?: Record<string, any>;
93
93
  }
94
94
  export interface AvailabilityResourceWindow extends AvailabilityAbsoluteRange {
95
+ /** Original business day and opening anchor, before coverage clipping. */
96
+ businessDate?: string;
97
+ openingAnchorAt?: string;
95
98
  source?: string;
96
99
  raw?: Record<string, any>;
97
100
  }
@@ -101,10 +104,15 @@ export interface AvailabilityOperatingHoursSnapshot {
101
104
  scheduleIds: AvailabilityId[];
102
105
  missingScheduleIds: AvailabilityId[];
103
106
  windows: AvailabilityResourceWindow[];
107
+ /** Complete business cycles; lunch gaps remain in windows, not in this envelope. */
108
+ businessPeriods?: AvailabilityBusinessPeriod[];
104
109
  /** Schedule windows omitted only because their date is excluded. POS may use
105
110
  * these to surface an unavailable, manually selectable candidate. */
106
111
  excludedWindows?: AvailabilityResourceWindow[];
107
112
  }
113
+ export interface AvailabilityBusinessPeriod extends AvailabilityAbsoluteRange {
114
+ businessDate: string;
115
+ }
108
116
  export interface AvailabilityResource {
109
117
  id: AvailabilityId;
110
118
  formId?: AvailabilityId;
@@ -212,6 +220,17 @@ export interface ProductTimeRange extends AvailabilityDisplayRange {
212
220
  bookingEndAt: string;
213
221
  scheduleRefs: AvailabilityScheduleRef[];
214
222
  primaryScheduleRef?: AvailabilityScheduleRef;
223
+ /** Business-day label. date/startAt keep the actual calendar date. */
224
+ businessDate?: string;
225
+ }
226
+ export interface UnavailableCurrentTime {
227
+ productId: AvailabilityId;
228
+ startAt: string;
229
+ date: string;
230
+ businessDate: string;
231
+ startTime: string;
232
+ status: 'unavailable';
233
+ reasonCodes: string[];
215
234
  }
216
235
  export interface ProductTimeRangeGroup {
217
236
  productId: AvailabilityId;
@@ -221,6 +240,8 @@ export interface ProductTimeRangeGroup {
221
240
  /** 单日查询对应营业窗口的最终结束时刻,不受资源排班是否为空影响。 */
222
241
  operatingEndAt?: string;
223
242
  ranges: ProductTimeRange[];
243
+ /** A display-only current item when flexible duration has no valid end. Never submit it. */
244
+ unavailableCurrentTime?: UnavailableCurrentTime;
224
245
  }
225
246
  export interface AvailabilityAssignment extends AvailabilityAbsoluteRange {
226
247
  productId: AvailabilityId;
@@ -242,6 +263,10 @@ export interface GetProductTimeRangesRequest {
242
263
  partySize?: number;
243
264
  durationMinutesByProductId?: Record<string, number>;
244
265
  durationStartTimesByProductId?: Record<string, string[]>;
266
+ /** Restore only the exact remembered start; recompute the end from current product/windows. */
267
+ rememberedStartAtByProductId?: Record<string, string>;
268
+ /** Edit only: preserve the full actual start plus an explicit durationMinutesByProductId. */
269
+ editingStartAtByProductId?: Record<string, string>;
245
270
  /**
246
271
  * POS 手工输入时间的兼容开关:只为明确请求的 start time 补候选,
247
272
  * 不改变常规候选列表仍按营业时间生成的规则。
@@ -250,6 +275,10 @@ export interface GetProductTimeRangesRequest {
250
275
  }
251
276
  export interface GetProductTimeRangesRuntimeOptions {
252
277
  evaluatedAt?: string;
278
+ /** Enabled by the POS/Kiosk facade only; other consumers retain their existing grid. */
279
+ useDurationTimeGrid?: boolean;
280
+ /** Automatic remembered selection must not use POS opening-minute cutoff exceptions. */
281
+ enforceSaleCutoff?: boolean;
253
282
  /**
254
283
  * Internal POS capability: fixed-duration candidates start from the stable
255
284
  * context anchor's current minute instead of rounding up to ten minutes, and
@@ -8,6 +8,7 @@ var _BaseModule = require("../BaseModule");
8
8
  var _types = require("./types");
9
9
  var _utils = require("../../solution/ShopDiscount/utils");
10
10
  var _utils2 = require("../Cart/utils");
11
+ var _utils3 = require("../Holder/utils");
11
12
  var _decimal = _interopRequireDefault(require("decimal.js"));
12
13
  var _lodashEs = require("lodash-es");
13
14
  var _dayjs = _interopRequireDefault(require("dayjs"));
@@ -59,7 +60,7 @@ class RulesModule extends _BaseModule.BaseModule {
59
60
  if (discount.holder?.holder_type !== 'form') return true;
60
61
 
61
62
  // getProduct 会裁剪商品字段,从原始商品读取配置,套餐子项沿用父商品。
62
- const holderConfig = holderSource?.holder_config ?? holderSource?.metadata?.holder_config ?? holderSource?.origin?.holder_config ?? holderSource?.metadata?.origin?.holder_config ?? holderSource?._origin?.holder_config ?? holderSource?._extend?.holder_config ?? holderSource?._extend?.product?.holder_config ?? holderSource?._extend?.product?.metadata?.holder_config;
63
+ const holderConfig = (0, _utils3.resolveProductHolderConfig)(holderSource);
63
64
  const holderStatus = holderConfig?.status;
64
65
  const holderEnabled = holderStatus === true || ['enable', '1'].includes(String(holderStatus).trim().toLowerCase());
65
66
  if (!holderEnabled || holderConfig?.resource_id === undefined || holderConfig?.resource_id === null || holderConfig?.resource_id === '') {
@@ -10,6 +10,10 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
10
10
  private openCache;
11
11
  private fatherModule;
12
12
  private hasLoadedScheduleList;
13
+ private scheduleListPromise;
14
+ private scheduleListRequestVersion;
15
+ private scheduleCatalogScope;
16
+ private otherParams;
13
17
  constructor(name?: string, version?: string);
14
18
  initialize(core: PisellCore, options: ModuleOptions): Promise<void>;
15
19
  /**
@@ -19,6 +23,9 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
19
23
  * scheduleModule.updateOtherParams({ openCache: true, cacheId: 'cache-2' });
20
24
  */
21
25
  updateOtherParams(params: Record<string, any>): void;
26
+ private syncScheduleCatalogScope;
27
+ private resetScheduleCatalog;
28
+ destroy(): void;
22
29
  /**
23
30
  * 加载当前店铺下所有 schedule
24
31
  *
@@ -27,6 +34,7 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
27
34
  loadAllSchedule(options?: {
28
35
  useCache?: boolean;
29
36
  }): Promise<void>;
37
+ private loadScheduleCatalog;
30
38
  setScheduleList(list: ScheduleItem[]): void;
31
39
  private syncScheduleMap;
32
40
  getScheduleList(): ScheduleItem[];