@pisell/pisellos 2.2.300 → 2.2.302

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ // 导出评估器
2
+ export { PromotionEvaluator } from "./evaluator";
3
+
4
+ // 导出适配器
5
+ export { PromotionAdapter } from "./adapter";
6
+ export { default } from "./adapter";
7
+
8
+ // 导出策略配置示例常量
9
+ export { X_ITEMS_FOR_Y_PRICE_STRATEGY, BUY_X_GET_Y_FREE_STRATEGY, ITEM_REWARD_STRATEGY } from "./examples";
@@ -294,10 +294,12 @@ function evaluateCandidateTimeGate(params) {
294
294
  };
295
295
  }
296
296
  if (policy.type === 'before_start') {
297
- // Flexible-duration candidates start at minute precision. Keep the current
298
- // minute selectable instead of treating the freshly generated candidate as
299
- // already started because the query clock still contains seconds.
300
- var hasNotReachedStart = product.isFlexibleDuration ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
297
+ // Flexible-duration candidates and POS fixed-duration anchors start at
298
+ // minute precision. Keep that current minute selectable instead of treating
299
+ // the freshly generated candidate as already started because the query
300
+ // clock still contains seconds.
301
+ var usesMinutePrecision = product.isFlexibleDuration || evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration';
302
+ var hasNotReachedStart = usesMinutePrecision ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
301
303
  if (hasNotReachedStart) return null;
302
304
  return {
303
305
  status: 'unavailable',
@@ -1179,7 +1181,8 @@ export function getProductTimeRanges(projection) {
1179
1181
  }
1180
1182
  return floorToMinute(evaluatedAt);
1181
1183
  }();
1182
- var durationAnchor = ceilToTenMinutes(toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone), projection.meta.timezone);
1184
+ var durationCandidateAnchor = toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone);
1185
+ var durationAnchor = runtimeOptions.useExactDurationCandidateMinute ? floorToMinute(durationCandidateAnchor) : ceilToTenMinutes(durationCandidateAnchor, projection.meta.timezone);
1183
1186
  var requestedStartTimes = resolveRequestedDurationStartTimes(product, request);
1184
1187
  var ranges = [];
1185
1188
  baseRanges.forEach(function (range) {
@@ -1445,6 +1448,7 @@ function buildEvaluationContext(params) {
1445
1448
  evaluatedAtMs: evaluatedAt,
1446
1449
  resourceIdSet: (_params$resourceIds2 = params.resourceIds) !== null && _params$resourceIds2 !== void 0 && _params$resourceIds2.length ? new Set(params.resourceIds.map(String)) : null,
1447
1450
  selectionsByGroupKey: selectionsByGroupKey,
1451
+ useExactDurationCandidateMinute: params.useExactDurationCandidateMinute === true,
1448
1452
  allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true
1449
1453
  };
1450
1454
  }
@@ -1933,6 +1937,7 @@ export function queryAvailabilityProjection(projection, request) {
1933
1937
  projection: projection,
1934
1938
  evaluatedAt: evaluatedAt,
1935
1939
  resourceIds: request.resourceIds,
1940
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1936
1941
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1937
1942
  });
1938
1943
  if (request.target === 'time') {
@@ -2022,6 +2027,7 @@ export function queryAvailabilityProjection(projection, request) {
2022
2027
  partySize: normalizedPartySize
2023
2028
  }, {
2024
2029
  evaluatedAt: evaluatedAt,
2030
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
2025
2031
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
2026
2032
  });
2027
2033
  var candidateGroupMap = new Map(candidateGroups.map(function (group) {
@@ -2222,6 +2228,7 @@ export function validateAvailabilitySelection(projection, params) {
2222
2228
  projection: projection,
2223
2229
  evaluatedAt: evaluatedAt,
2224
2230
  requirementSelections: params.requirementSelections,
2231
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
2225
2232
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
2226
2233
  })
2227
2234
  });
@@ -250,6 +250,13 @@ export interface GetProductTimeRangesRequest {
250
250
  }
251
251
  export interface GetProductTimeRangesRuntimeOptions {
252
252
  evaluatedAt?: string;
253
+ /**
254
+ * Internal POS capability: fixed-duration candidates start from the stable
255
+ * context anchor's current minute instead of rounding up to ten minutes, and
256
+ * that minute remains selectable during before-start cutoff evaluation.
257
+ * Other callers keep the legacy alignment and strict second-level cutoff.
258
+ */
259
+ useExactDurationCandidateMinute?: boolean;
253
260
  /**
254
261
  * Internal POS capability: allow explicit duration/start overrides to append
255
262
  * a custom duration candidate for Session products. Fixed Session ranges are
@@ -229,6 +229,8 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
229
229
  updateTempOrderNote(note: string, sync: true): Promise<string>;
230
230
  updateTempOrderNote(note: string, sync: boolean): string | Promise<string>;
231
231
  updateRemoteOrderNote(orderId: number | string, note: string): void;
232
+ /** 存储用户自定义取餐标识到当前 tempOrder.buzzer。 */
233
+ setPickupRef(buzzer: string): string;
232
234
  updateTempOrderShopDiscount(amount: string | number): string;
233
235
  updateTempOrderDepositAmount(amount: string | number): OrderSummary;
234
236
  updateTempOrderContactsInfo(contactsInfo: Record<string, any> | null): Record<string, any> | null;
@@ -2107,6 +2107,14 @@ export var BaseSalesImpl = /*#__PURE__*/function (_BaseModule) {
2107
2107
  if (!this.store.order) throw new Error('order 模块未初始化');
2108
2108
  this.store.order.syncTempOrderNoteToRemote(orderId, note);
2109
2109
  }
2110
+
2111
+ /** 存储用户自定义取餐标识到当前 tempOrder.buzzer。 */
2112
+ }, {
2113
+ key: "setPickupRef",
2114
+ value: function setPickupRef(buzzer) {
2115
+ if (!this.store.order) throw new Error('order 模块未初始化');
2116
+ return this.store.order.updateTempOrderBuzzer(buzzer);
2117
+ }
2110
2118
  }, {
2111
2119
  key: "updateTempOrderShopDiscount",
2112
2120
  value: function updateTempOrderShopDiscount(amount) {
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
326
326
  date: string;
327
327
  status: string;
328
328
  week: string;
329
- weekNum: 0 | 2 | 3 | 1 | 5 | 6 | 4;
329
+ weekNum: 0 | 1 | 2 | 5 | 4 | 3 | 6;
330
330
  }[]>;
331
331
  submitTimeSlot(timeSlots: TimeSliceItem): void;
332
332
  private getScheduleDataByIds;
@@ -334,7 +334,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
334
334
  * 获取当前的客户搜索条件
335
335
  * @returns 当前搜索条件
336
336
  */
337
- getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
337
+ getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
338
338
  /**
339
339
  * 获取客户列表状态(包含滚动加载相关状态)
340
340
  * @returns 客户状态
@@ -453,19 +453,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
453
453
  * 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
454
454
  * 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
455
455
  */
456
- decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): {
457
- action: "reloadCatalog";
458
- } | {
459
- action: "add";
460
- cacheItem: any;
461
- } | {
462
- action: "requiresDetail";
463
- payload: AddProductRequiresDetailPayload;
464
- } | {
465
- action: "requiresBookingEdit";
466
- cacheItem: any;
467
- payload: import("./utils/addProductDecision").AddProductRequiresBookingEditPayload;
468
- };
456
+ decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
469
457
  /** 规格弹窗 callback 后的第二段决策。 */
470
458
  decideAfterDetail(cacheItem: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
471
459
  /**
@@ -4293,6 +4293,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4293
4293
  allowOutsideOperatingHoursForRequestedStartTimes: true
4294
4294
  } : {}), {
4295
4295
  evaluatedAt: this.getAvailabilityRuntimeDateTime(),
4296
+ useExactDurationCandidateMinute: isPosAvailabilityRequest,
4296
4297
  allowSessionCustomRanges: isPosAvailabilityRequest,
4297
4298
  allowExcludedScheduleDateOverride: isPosAvailabilityRequest
4298
4299
  }).map(function (group) {
@@ -4332,6 +4333,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4332
4333
  this.assertContextualQueryFreshness(context, request);
4333
4334
  isPosAvailabilityRequest = String((_this$otherParams$pla2 = (_this$otherParams19 = this.otherParams) === null || _this$otherParams19 === void 0 ? void 0 : _this$otherParams19.platform) !== null && _this$otherParams$pla2 !== void 0 ? _this$otherParams$pla2 : '').trim().toLowerCase() === 'pos';
4334
4335
  result = queryAvailabilityProjection(projectionEntry.projection, request, {
4336
+ useExactDurationCandidateMinute: isPosAvailabilityRequest,
4335
4337
  allowExcludedScheduleDateOverride: isPosAvailabilityRequest
4336
4338
  });
4337
4339
  contextVersion = context.activeVersion;
@@ -4686,6 +4688,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4686
4688
  }, allowPosAvailabilityOverride ? {
4687
4689
  allowOutsideOperatingHoursForRequestedStartTimes: true
4688
4690
  } : {}) : {}) : {}), {
4691
+ useExactDurationCandidateMinute: allowPosAvailabilityOverride,
4689
4692
  allowSessionCustomRanges: allowPosAvailabilityOverride,
4690
4693
  allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
4691
4694
  }).flatMap(function (group) {
@@ -4721,6 +4724,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4721
4724
  partySize: partySize,
4722
4725
  bookingCount: bookingCount
4723
4726
  }, {
4727
+ useExactDurationCandidateMinute: allowPosAvailabilityOverride,
4724
4728
  allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
4725
4729
  });
4726
4730
  if (allowPosAvailabilityOverride && !validation.ok && validation.conflicts.every(function (conflict) {
@@ -281,10 +281,12 @@ function evaluateCandidateTimeGate(params) {
281
281
  };
282
282
  }
283
283
  if (policy.type === 'before_start') {
284
- // Flexible-duration candidates start at minute precision. Keep the current
285
- // minute selectable instead of treating the freshly generated candidate as
286
- // already started because the query clock still contains seconds.
287
- const hasNotReachedStart = product.isFlexibleDuration ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
284
+ // Flexible-duration candidates and POS fixed-duration anchors start at
285
+ // minute precision. Keep that current minute selectable instead of treating
286
+ // the freshly generated candidate as already started because the query
287
+ // clock still contains seconds.
288
+ const usesMinutePrecision = product.isFlexibleDuration || evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration';
289
+ const hasNotReachedStart = usesMinutePrecision ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
288
290
  if (hasNotReachedStart) return null;
289
291
  return {
290
292
  status: 'unavailable',
@@ -1050,7 +1052,8 @@ function getProductTimeRanges(projection, request = {}, runtimeOptions = {}) {
1050
1052
  }
1051
1053
  return floorToMinute(evaluatedAt);
1052
1054
  })();
1053
- const durationAnchor = ceilToTenMinutes(toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone), projection.meta.timezone);
1055
+ const durationCandidateAnchor = toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone);
1056
+ const durationAnchor = runtimeOptions.useExactDurationCandidateMinute ? floorToMinute(durationCandidateAnchor) : ceilToTenMinutes(durationCandidateAnchor, projection.meta.timezone);
1054
1057
  const requestedStartTimes = resolveRequestedDurationStartTimes(product, request);
1055
1058
  const ranges = [];
1056
1059
  baseRanges.forEach(range => {
@@ -1256,6 +1259,7 @@ function buildEvaluationContext(params) {
1256
1259
  evaluatedAtMs: evaluatedAt,
1257
1260
  resourceIdSet: params.resourceIds?.length ? new Set(params.resourceIds.map(String)) : null,
1258
1261
  selectionsByGroupKey,
1262
+ useExactDurationCandidateMinute: params.useExactDurationCandidateMinute === true,
1259
1263
  allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true
1260
1264
  };
1261
1265
  }
@@ -1663,6 +1667,7 @@ function queryAvailabilityProjection(projection, request, runtimeOptions = {}) {
1663
1667
  projection,
1664
1668
  evaluatedAt,
1665
1669
  resourceIds: request.resourceIds,
1670
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1666
1671
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1667
1672
  });
1668
1673
  if (request.target === 'time') {
@@ -1738,6 +1743,7 @@ function queryAvailabilityProjection(projection, request, runtimeOptions = {}) {
1738
1743
  partySize: normalizedPartySize
1739
1744
  }, {
1740
1745
  evaluatedAt,
1746
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1741
1747
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1742
1748
  });
1743
1749
  const candidateGroupMap = new Map(candidateGroups.map(group => [String(group.productId), group]));
@@ -1910,6 +1916,7 @@ function validateAvailabilitySelection(projection, params, runtimeOptions = {})
1910
1916
  projection,
1911
1917
  evaluatedAt,
1912
1918
  requirementSelections: params.requirementSelections,
1919
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1913
1920
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1914
1921
  })
1915
1922
  });
@@ -250,6 +250,13 @@ export interface GetProductTimeRangesRequest {
250
250
  }
251
251
  export interface GetProductTimeRangesRuntimeOptions {
252
252
  evaluatedAt?: string;
253
+ /**
254
+ * Internal POS capability: fixed-duration candidates start from the stable
255
+ * context anchor's current minute instead of rounding up to ten minutes, and
256
+ * that minute remains selectable during before-start cutoff evaluation.
257
+ * Other callers keep the legacy alignment and strict second-level cutoff.
258
+ */
259
+ useExactDurationCandidateMinute?: boolean;
253
260
  /**
254
261
  * Internal POS capability: allow explicit duration/start overrides to append
255
262
  * a custom duration candidate for Session products. Fixed Session ranges are
@@ -229,6 +229,8 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
229
229
  updateTempOrderNote(note: string, sync: true): Promise<string>;
230
230
  updateTempOrderNote(note: string, sync: boolean): string | Promise<string>;
231
231
  updateRemoteOrderNote(orderId: number | string, note: string): void;
232
+ /** 存储用户自定义取餐标识到当前 tempOrder.buzzer。 */
233
+ setPickupRef(buzzer: string): string;
232
234
  updateTempOrderShopDiscount(amount: string | number): string;
233
235
  updateTempOrderDepositAmount(amount: string | number): OrderSummary;
234
236
  updateTempOrderContactsInfo(contactsInfo: Record<string, any> | null): Record<string, any> | null;
@@ -1439,6 +1439,12 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1439
1439
  if (!this.store.order) throw new Error('order 模块未初始化');
1440
1440
  this.store.order.syncTempOrderNoteToRemote(orderId, note);
1441
1441
  }
1442
+
1443
+ /** 存储用户自定义取餐标识到当前 tempOrder.buzzer。 */
1444
+ setPickupRef(buzzer) {
1445
+ if (!this.store.order) throw new Error('order 模块未初始化');
1446
+ return this.store.order.updateTempOrderBuzzer(buzzer);
1447
+ }
1442
1448
  updateTempOrderShopDiscount(amount) {
1443
1449
  if (!this.store.order) throw new Error('order 模块未初始化');
1444
1450
  return this.store.order.updateTempOrderShopDiscount(amount);
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
326
326
  date: string;
327
327
  status: string;
328
328
  week: string;
329
- weekNum: 0 | 2 | 3 | 1 | 5 | 6 | 4;
329
+ weekNum: 0 | 1 | 2 | 5 | 4 | 3 | 6;
330
330
  }[]>;
331
331
  submitTimeSlot(timeSlots: TimeSliceItem): void;
332
332
  private getScheduleDataByIds;
@@ -334,7 +334,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
334
334
  * 获取当前的客户搜索条件
335
335
  * @returns 当前搜索条件
336
336
  */
337
- getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
337
+ getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
338
338
  /**
339
339
  * 获取客户列表状态(包含滚动加载相关状态)
340
340
  * @returns 客户状态
@@ -453,19 +453,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
453
453
  * 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
454
454
  * 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
455
455
  */
456
- decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): {
457
- action: "reloadCatalog";
458
- } | {
459
- action: "add";
460
- cacheItem: any;
461
- } | {
462
- action: "requiresDetail";
463
- payload: AddProductRequiresDetailPayload;
464
- } | {
465
- action: "requiresBookingEdit";
466
- cacheItem: any;
467
- payload: import("./utils/addProductDecision").AddProductRequiresBookingEditPayload;
468
- };
456
+ decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
469
457
  /** 规格弹窗 callback 后的第二段决策。 */
470
458
  decideAfterDetail(cacheItem: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
471
459
  /**
@@ -2873,6 +2873,7 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
2873
2873
  } : {})
2874
2874
  }, {
2875
2875
  evaluatedAt: this.getAvailabilityRuntimeDateTime(),
2876
+ useExactDurationCandidateMinute: isPosAvailabilityRequest,
2876
2877
  allowSessionCustomRanges: isPosAvailabilityRequest,
2877
2878
  allowExcludedScheduleDateOverride: isPosAvailabilityRequest
2878
2879
  }).map(group => ({
@@ -2891,6 +2892,7 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
2891
2892
  this.assertContextualQueryFreshness(context, request);
2892
2893
  const isPosAvailabilityRequest = String(this.otherParams?.platform ?? '').trim().toLowerCase() === 'pos';
2893
2894
  const result = (0, _ResourcePlanner.queryAvailabilityProjection)(projectionEntry.projection, request, {
2895
+ useExactDurationCandidateMinute: isPosAvailabilityRequest,
2894
2896
  allowExcludedScheduleDateOverride: isPosAvailabilityRequest
2895
2897
  });
2896
2898
  const contextVersion = context.activeVersion;
@@ -3149,6 +3151,7 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
3149
3151
  } : {})
3150
3152
  } : {})
3151
3153
  }, {
3154
+ useExactDurationCandidateMinute: allowPosAvailabilityOverride,
3152
3155
  allowSessionCustomRanges: allowPosAvailabilityOverride,
3153
3156
  allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
3154
3157
  }).flatMap(group => group.ranges);
@@ -3172,6 +3175,7 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
3172
3175
  partySize,
3173
3176
  bookingCount
3174
3177
  }, {
3178
+ useExactDurationCandidateMinute: allowPosAvailabilityOverride,
3175
3179
  allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
3176
3180
  });
3177
3181
  if (allowPosAvailabilityOverride && !validation.ok && validation.conflicts.every(conflict => POS_OVERRIDABLE_AVAILABILITY_CONFLICT_CODES.has(conflict.code))) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.2.300",
4
+ "version": "2.2.302",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",