@pisell/pisellos 2.1.175 → 2.1.177
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.
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/solution/ScanOrder/index.d.ts +2 -0
- package/dist/solution/ScanOrder/index.js +65 -26
- package/dist/solution/ScanOrder/resourceSchedule.d.ts +12 -0
- package/dist/solution/ScanOrder/resourceSchedule.js +300 -0
- package/dist/solution/ScanOrder/types.d.ts +3 -1
- package/dist/solution/ShopDiscount/utils.js +8 -5
- package/lib/solution/ScanOrder/index.d.ts +2 -0
- package/lib/solution/ScanOrder/index.js +35 -7
- package/lib/solution/ScanOrder/resourceSchedule.d.ts +12 -0
- package/lib/solution/ScanOrder/resourceSchedule.js +272 -0
- package/lib/solution/ScanOrder/types.d.ts +3 -1
- package/lib/solution/ShopDiscount/utils.js +5 -5
- package/package.json +1 -1
|
@@ -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 } from "./examples";
|
|
@@ -119,6 +119,8 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
119
119
|
private validateBeforeSubmitByItemRule;
|
|
120
120
|
private refreshCartValidationPassed;
|
|
121
121
|
setItemRuleRuntimeConfig(config?: ScanOrderItemRuleRuntimeConfig): Promise<void>;
|
|
122
|
+
/** 只根据已加载的桌台和日程计算当前可用性,不改变数据加载与缓存行为。 */
|
|
123
|
+
private checkResourceSchedule;
|
|
122
124
|
private normalizeResourceState;
|
|
123
125
|
private resolveResourceSelectType;
|
|
124
126
|
private fetchResourceOccupyDetailsByResourceId;
|
|
@@ -38,6 +38,7 @@ import { ProductList } from "../../modules/ProductList";
|
|
|
38
38
|
import { ScheduleModule } from "../../modules/Schedule";
|
|
39
39
|
import { getDateIsInSchedule } from "../../modules/Schedule/getDateIsInSchedule";
|
|
40
40
|
import { composeLinePrice, createUuidV4, normalizeSubmitCollectPaxValue, sumOptionUnitPrice } from "../../modules/Order/utils";
|
|
41
|
+
import { evaluateResourceSchedules } from "./resourceSchedule";
|
|
41
42
|
import dayjs from 'dayjs';
|
|
42
43
|
import { ItemRuleEvaluator } from "../../model/strategy/adapter/itemRule";
|
|
43
44
|
export * from "./types";
|
|
@@ -1559,7 +1560,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1559
1560
|
key: "submitScanOrder",
|
|
1560
1561
|
value: function () {
|
|
1561
1562
|
var _submitScanOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee18() {
|
|
1562
|
-
var _this$store$resource, _this$otherParams6, _this$otherParams7, _this$otherParams8, _this$otherParams9, _tempOrder$products, tempOrderForSubmit, resourceTableName, enhancePayload, result, tempOrder;
|
|
1563
|
+
var _this$store$resource, _this$store$resource2, _this$otherParams6, _this$otherParams7, _this$otherParams8, _this$otherParams9, _tempOrder$products, scheduleBlocked, tempOrderForSubmit, resourceTableName, enhancePayload, result, tempOrder;
|
|
1563
1564
|
return _regeneratorRuntime().wrap(function _callee18$(_context18) {
|
|
1564
1565
|
while (1) switch (_context18.prev = _context18.next) {
|
|
1565
1566
|
case 0:
|
|
@@ -1574,9 +1575,16 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1574
1575
|
}
|
|
1575
1576
|
throw new Error('scanOrder解决方案需要 order 模块支持');
|
|
1576
1577
|
case 6:
|
|
1578
|
+
scheduleBlocked = this.checkResourceSchedule((_this$store$resource = this.store.resource) === null || _this$store$resource === void 0 ? void 0 : _this$store$resource.table_form_record);
|
|
1579
|
+
if (!scheduleBlocked) {
|
|
1580
|
+
_context18.next = 9;
|
|
1581
|
+
break;
|
|
1582
|
+
}
|
|
1583
|
+
throw new Error(scheduleBlocked.errorTips);
|
|
1584
|
+
case 9:
|
|
1577
1585
|
tempOrderForSubmit = this.store.order.ensureTempOrder();
|
|
1578
1586
|
tempOrderForSubmit.delivery_type = 'shop_service';
|
|
1579
|
-
resourceTableName = (_this$store$
|
|
1587
|
+
resourceTableName = (_this$store$resource2 = this.store.resource) === null || _this$store$resource2 === void 0 || (_this$store$resource2 = _this$store$resource2.table_form_record) === null || _this$store$resource2 === void 0 ? void 0 : _this$store$resource2.name;
|
|
1580
1588
|
if (resourceTableName && _typeof(resourceTableName) === 'object') {
|
|
1581
1589
|
tempOrderForSubmit.table_number = resourceTableName;
|
|
1582
1590
|
} else {
|
|
@@ -1584,7 +1592,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1584
1592
|
}
|
|
1585
1593
|
this.store.order.persistTempOrder();
|
|
1586
1594
|
enhancePayload = this.buildSubmitPayloadEnhancer();
|
|
1587
|
-
_context18.next =
|
|
1595
|
+
_context18.next = 17;
|
|
1588
1596
|
return this.store.order.submitTempOrder({
|
|
1589
1597
|
cacheId: this.cacheId,
|
|
1590
1598
|
platform: (_this$otherParams6 = this.otherParams) === null || _this$otherParams6 === void 0 ? void 0 : _this$otherParams6.platform,
|
|
@@ -1593,23 +1601,23 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1593
1601
|
type: (_this$otherParams9 = this.otherParams) === null || _this$otherParams9 === void 0 ? void 0 : _this$otherParams9.type,
|
|
1594
1602
|
enhancePayload: enhancePayload
|
|
1595
1603
|
});
|
|
1596
|
-
case
|
|
1604
|
+
case 17:
|
|
1597
1605
|
result = _context18.sent;
|
|
1598
1606
|
tempOrder = this.store.order.getTempOrder();
|
|
1599
1607
|
this.logMethodSuccess('submitScanOrder', {
|
|
1600
1608
|
productCount: (tempOrder === null || tempOrder === void 0 || (_tempOrder$products = tempOrder.products) === null || _tempOrder$products === void 0 ? void 0 : _tempOrder$products.length) || 0
|
|
1601
1609
|
});
|
|
1602
1610
|
return _context18.abrupt("return", result);
|
|
1603
|
-
case
|
|
1604
|
-
_context18.prev =
|
|
1611
|
+
case 23:
|
|
1612
|
+
_context18.prev = 23;
|
|
1605
1613
|
_context18.t0 = _context18["catch"](1);
|
|
1606
1614
|
this.logMethodError('submitScanOrder', _context18.t0);
|
|
1607
1615
|
throw _context18.t0;
|
|
1608
|
-
case
|
|
1616
|
+
case 27:
|
|
1609
1617
|
case "end":
|
|
1610
1618
|
return _context18.stop();
|
|
1611
1619
|
}
|
|
1612
|
-
}, _callee18, this, [[1,
|
|
1620
|
+
}, _callee18, this, [[1, 23]]);
|
|
1613
1621
|
}));
|
|
1614
1622
|
function submitScanOrder() {
|
|
1615
1623
|
return _submitScanOrder.apply(this, arguments);
|
|
@@ -2516,7 +2524,29 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2516
2524
|
return _setItemRuleRuntimeConfig.apply(this, arguments);
|
|
2517
2525
|
}
|
|
2518
2526
|
return setItemRuleRuntimeConfig;
|
|
2519
|
-
}()
|
|
2527
|
+
}() /** 只根据已加载的桌台和日程计算当前可用性,不改变数据加载与缓存行为。 */
|
|
2528
|
+
}, {
|
|
2529
|
+
key: "checkResourceSchedule",
|
|
2530
|
+
value: function checkResourceSchedule(formRecord) {
|
|
2531
|
+
var _this$core$getPlugin, _this$store$schedule, _coreState$core, _coreState$core2;
|
|
2532
|
+
var ids = formRecord === null || formRecord === void 0 ? void 0 : formRecord.schedule;
|
|
2533
|
+
if (!Array.isArray(ids) || !ids.length) return null;
|
|
2534
|
+
var coreState = (_this$core$getPlugin = this.core.getPlugin('shopStore')) === null || _this$core$getPlugin === void 0 ? void 0 : _this$core$getPlugin.get('core');
|
|
2535
|
+
var schedules = ((_this$store$schedule = this.store.schedule) === null || _this$store$schedule === void 0 ? void 0 : _this$store$schedule.getScheduleListByIds(ids.map(Number))) || [];
|
|
2536
|
+
var result = evaluateResourceSchedules({
|
|
2537
|
+
schedules: schedules,
|
|
2538
|
+
timeZone: coreState === null || coreState === void 0 || (_coreState$core = coreState.core) === null || _coreState$core === void 0 || (_coreState$core = _coreState$core.shop) === null || _coreState$core === void 0 ? void 0 : _coreState$core.timezone,
|
|
2539
|
+
now: new Date()
|
|
2540
|
+
});
|
|
2541
|
+
if (result.available) return null;
|
|
2542
|
+
var locale = String((coreState === null || coreState === void 0 ? void 0 : coreState.translateLocale) || (coreState === null || coreState === void 0 || (_coreState$core2 = coreState.core) === null || _coreState$core2 === void 0 || (_coreState$core2 = _coreState$core2.shop) === null || _coreState$core2 === void 0 ? void 0 : _coreState$core2.primary_locale) || 'en').toLowerCase();
|
|
2543
|
+
var errorTips = locale === 'zh-hk' || locale === 'zh-tw' ? '目前桌檯不在可用時段,請聯絡工作人員。' : locale.startsWith('zh') ? '当前桌台不在可用时段,请联系工作人员。' : 'This table is outside its available hours. Please contact staff.';
|
|
2544
|
+
return {
|
|
2545
|
+
mode: 'resource_block',
|
|
2546
|
+
table_form_record: formRecord,
|
|
2547
|
+
errorTips: errorTips
|
|
2548
|
+
};
|
|
2549
|
+
}
|
|
2520
2550
|
}, {
|
|
2521
2551
|
key: "normalizeResourceState",
|
|
2522
2552
|
value: function normalizeResourceState(detail, resourceSelectType, hasOrderId) {
|
|
@@ -2759,6 +2789,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2759
2789
|
error,
|
|
2760
2790
|
occupyDetails,
|
|
2761
2791
|
occupyDetail,
|
|
2792
|
+
scheduleBlocked,
|
|
2762
2793
|
resourceSelectType,
|
|
2763
2794
|
allowAddItems,
|
|
2764
2795
|
additionalOrderResult,
|
|
@@ -2930,13 +2961,21 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2930
2961
|
return this.fetchResourceOccupyDetailsByResourceId(normalizedResourceId);
|
|
2931
2962
|
case 50:
|
|
2932
2963
|
occupyDetails = _context37.sent;
|
|
2933
|
-
occupyDetail = (_occupyDetails$ = occupyDetails[0]) !== null && _occupyDetails$ !== void 0 ? _occupyDetails$ : null;
|
|
2964
|
+
occupyDetail = (_occupyDetails$ = occupyDetails[0]) !== null && _occupyDetails$ !== void 0 ? _occupyDetails$ : null;
|
|
2965
|
+
scheduleBlocked = this.checkResourceSchedule(occupyDetail === null || occupyDetail === void 0 ? void 0 : occupyDetail.form_record);
|
|
2966
|
+
if (!scheduleBlocked) {
|
|
2967
|
+
_context37.next = 55;
|
|
2968
|
+
break;
|
|
2969
|
+
}
|
|
2970
|
+
return _context37.abrupt("return", scheduleBlocked);
|
|
2971
|
+
case 55:
|
|
2972
|
+
// Step3: 结合预约规则商品的 product_resource.resources 与占用接口返回的 form_id,
|
|
2934
2973
|
// 计算当前桌台的 resourceSelectType(single/multiple/capacity)
|
|
2935
2974
|
resourceSelectType = this.resolveResourceSelectType(toPositiveString(occupyDetail === null || occupyDetail === void 0 ? void 0 : occupyDetail.form_id));
|
|
2936
2975
|
allowAddItems = toBoolean(dineInConfig === null || dineInConfig === void 0 ? void 0 : dineInConfig['sale.allow_add_items']);
|
|
2937
2976
|
additionalOrderResult = this.resolveAdditionalOrderFromOccupyDetail(occupyDetail, resourceSelectType, allowAddItems);
|
|
2938
2977
|
if (!(additionalOrderResult.reason === 'multiple_orders')) {
|
|
2939
|
-
_context37.next =
|
|
2978
|
+
_context37.next = 64;
|
|
2940
2979
|
break;
|
|
2941
2980
|
}
|
|
2942
2981
|
multipleOrdersState = _objectSpread(_objectSpread({}, this.normalizeResourceState(occupyDetail, resourceSelectType, hasOrderId)), {}, {
|
|
@@ -2957,7 +2996,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2957
2996
|
resourceSelectType: resourceSelectType
|
|
2958
2997
|
});
|
|
2959
2998
|
return _context37.abrupt("return", _availabilityInfo);
|
|
2960
|
-
case
|
|
2999
|
+
case 64:
|
|
2961
3000
|
// Step4: 用 occupyDetail + resourceSelectType 规整为 resourceState
|
|
2962
3001
|
resourceState = this.normalizeResourceState(occupyDetail, resourceSelectType, hasOrderId);
|
|
2963
3002
|
additionalOrderId = additionalOrderResult.order_id;
|
|
@@ -3006,12 +3045,12 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
3006
3045
|
|
|
3007
3046
|
// 空闲状态下自动准备本地临时订单,供后续“购物车式”商品操作使用
|
|
3008
3047
|
if (!(availabilityInfo.mode === 'idle')) {
|
|
3009
|
-
_context37.next =
|
|
3048
|
+
_context37.next = 79;
|
|
3010
3049
|
break;
|
|
3011
3050
|
}
|
|
3012
|
-
_context37.next =
|
|
3051
|
+
_context37.next = 79;
|
|
3013
3052
|
return this.addNewOrder();
|
|
3014
|
-
case
|
|
3053
|
+
case 79:
|
|
3015
3054
|
isAdditionalOrderMode = availabilityInfo.mode === 'additional_order' || availabilityInfo.mode === 'additional_order_with_code'; // 如果是加单模式,tempOrder 里需要记录目标订单 id,提交的时候走加单接口
|
|
3016
3055
|
if (isAdditionalOrderMode) {
|
|
3017
3056
|
tempOrder.order_id = additionalOrderId;
|
|
@@ -3027,13 +3066,13 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
3027
3066
|
} : {}));
|
|
3028
3067
|
return acc;
|
|
3029
3068
|
}, []) : []; // pax 由 setEntryPaxNumber 负责写入 itemRuleRuntimeConfig.pax
|
|
3030
|
-
_context37.next =
|
|
3069
|
+
_context37.next = 85;
|
|
3031
3070
|
return this.setItemRuleRuntimeConfig({
|
|
3032
3071
|
serviceType: (_this$otherParams16 = this.otherParams) === null || _this$otherParams16 === void 0 ? void 0 : _this$otherParams16.businessCode,
|
|
3033
3072
|
submissionIndex: isAdditionalOrderMode ? 1 : 0,
|
|
3034
3073
|
historicalItems: historicalItems
|
|
3035
3074
|
});
|
|
3036
|
-
case
|
|
3075
|
+
case 85:
|
|
3037
3076
|
// operating_hours 超出营业时段 + closed_behavior=show_menu_disabled:
|
|
3038
3077
|
// 允许浏览商品但 UI 层需拦截“下一步”,这里覆盖最终 mode 并回传错误提示
|
|
3039
3078
|
if (outsideOperatingHours && closedBehaviorValue === 'show_menu_disabled') {
|
|
@@ -3055,18 +3094,18 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
3055
3094
|
isFull: resourceState.isFull
|
|
3056
3095
|
});
|
|
3057
3096
|
return _context37.abrupt("return", availabilityInfo);
|
|
3058
|
-
case
|
|
3059
|
-
_context37.prev =
|
|
3097
|
+
case 90:
|
|
3098
|
+
_context37.prev = 90;
|
|
3060
3099
|
_context37.t0 = _context37["catch"](3);
|
|
3061
3100
|
this.logMethodError('checkResourceAvailable', _context37.t0.message, {
|
|
3062
3101
|
resourceId: normalizedResourceId
|
|
3063
3102
|
});
|
|
3064
3103
|
throw _context37.t0;
|
|
3065
|
-
case
|
|
3104
|
+
case 94:
|
|
3066
3105
|
case "end":
|
|
3067
3106
|
return _context37.stop();
|
|
3068
3107
|
}
|
|
3069
|
-
}, _callee37, this, [[3,
|
|
3108
|
+
}, _callee37, this, [[3, 90]]);
|
|
3070
3109
|
}));
|
|
3071
3110
|
function checkResourceAvailable(_x19) {
|
|
3072
3111
|
return _checkResourceAvailable.apply(this, arguments);
|
|
@@ -3371,13 +3410,13 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
3371
3410
|
key: "syncAdditionalOrderFromResource",
|
|
3372
3411
|
value: function () {
|
|
3373
3412
|
var _syncAdditionalOrderFromResource = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee43(resourceId) {
|
|
3374
|
-
var _ref10, _ref11, _ref12, _this$store$
|
|
3413
|
+
var _ref10, _ref11, _ref12, _this$store$resource3, _this$store$resource4, _occupyDetails$2, _this$store$resource5, _this$otherParams18, _this$store$order9;
|
|
3375
3414
|
var tempOrder, normalizedResourceId, _result, occupyDetails, occupyDetail, resourceSelectType, allowAddItems, result;
|
|
3376
3415
|
return _regeneratorRuntime().wrap(function _callee43$(_context43) {
|
|
3377
3416
|
while (1) switch (_context43.prev = _context43.next) {
|
|
3378
3417
|
case 0:
|
|
3379
3418
|
tempOrder = this.ensureTempOrder();
|
|
3380
|
-
normalizedResourceId = String((_ref10 = (_ref11 = (_ref12 = resourceId !== null && resourceId !== void 0 ? resourceId : tempOrder.resource_id) !== null && _ref12 !== void 0 ? _ref12 : (_this$store$
|
|
3419
|
+
normalizedResourceId = String((_ref10 = (_ref11 = (_ref12 = resourceId !== null && resourceId !== void 0 ? resourceId : tempOrder.resource_id) !== null && _ref12 !== void 0 ? _ref12 : (_this$store$resource3 = this.store.resource) === null || _this$store$resource3 === void 0 ? void 0 : _this$store$resource3.relationId) !== null && _ref11 !== void 0 ? _ref11 : (_this$store$resource4 = this.store.resource) === null || _this$store$resource4 === void 0 ? void 0 : _this$store$resource4.relation_id) !== null && _ref10 !== void 0 ? _ref10 : '').trim();
|
|
3381
3420
|
this.logMethodStart('syncAdditionalOrderFromResource', {
|
|
3382
3421
|
resourceId: normalizedResourceId
|
|
3383
3422
|
});
|
|
@@ -3397,7 +3436,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
3397
3436
|
case 9:
|
|
3398
3437
|
occupyDetails = _context43.sent;
|
|
3399
3438
|
occupyDetail = (_occupyDetails$2 = occupyDetails[0]) !== null && _occupyDetails$2 !== void 0 ? _occupyDetails$2 : null;
|
|
3400
|
-
resourceSelectType = ((_this$store$
|
|
3439
|
+
resourceSelectType = ((_this$store$resource5 = this.store.resource) === null || _this$store$resource5 === void 0 ? void 0 : _this$store$resource5.resourceSelectType) || this.resolveResourceSelectType(toPositiveString(occupyDetail === null || occupyDetail === void 0 ? void 0 : occupyDetail.form_id));
|
|
3401
3440
|
allowAddItems = toBoolean((_this$otherParams18 = this.otherParams) === null || _this$otherParams18 === void 0 || (_this$otherParams18 = _this$otherParams18.dineInConfig) === null || _this$otherParams18 === void 0 ? void 0 : _this$otherParams18['sale.allow_add_items']);
|
|
3402
3441
|
result = this.resolveAdditionalOrderFromOccupyDetail(occupyDetail, resourceSelectType, allowAddItems);
|
|
3403
3442
|
if (!(!result.matched || !result.order_id)) {
|
|
@@ -3437,9 +3476,9 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
3437
3476
|
}, {
|
|
3438
3477
|
key: "getReservationResourceSelectType",
|
|
3439
3478
|
value: function getReservationResourceSelectType() {
|
|
3440
|
-
var _this$store$
|
|
3479
|
+
var _this$store$resource6;
|
|
3441
3480
|
this.logMethodStart('getReservationResourceSelectType');
|
|
3442
|
-
var resourceSelectType = (_this$store$
|
|
3481
|
+
var resourceSelectType = (_this$store$resource6 = this.store.resource) === null || _this$store$resource6 === void 0 ? void 0 : _this$store$resource6.resourceSelectType;
|
|
3443
3482
|
var result = _objectSpread(_objectSpread({}, resourceSelectType ? {
|
|
3444
3483
|
resourceSelectType: resourceSelectType
|
|
3445
3484
|
} : {}), {}, {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ScheduleItem } from '../../modules/Schedule/types';
|
|
2
|
+
type Evaluation = {
|
|
3
|
+
available: boolean;
|
|
4
|
+
reason?: 'outside_schedule' | 'invalid_schedule' | 'invalid_timezone';
|
|
5
|
+
};
|
|
6
|
+
/** Current time is projected into the shop's calendar; host timezone is not used. */
|
|
7
|
+
export declare function evaluateResourceSchedules({ schedules, timeZone, now, }: {
|
|
8
|
+
schedules: ScheduleItem[];
|
|
9
|
+
timeZone: string;
|
|
10
|
+
now: Date;
|
|
11
|
+
}): Evaluation;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
2
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
3
|
+
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
4
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
5
|
+
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
6
|
+
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
7
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
8
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
9
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
10
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
11
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
12
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
13
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
14
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
15
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
16
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
17
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
18
|
+
import dayjs from 'dayjs';
|
|
19
|
+
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
|
|
20
|
+
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
|
|
21
|
+
import { getScheduleStartEndTimePoints } from "../../modules/Schedule/getDateIsInSchedule";
|
|
22
|
+
// Schedule's date expander uses these methods but does not initialize them itself.
|
|
23
|
+
dayjs.extend(isSameOrAfter);
|
|
24
|
+
dayjs.extend(isSameOrBefore);
|
|
25
|
+
var DAY = 24 * 60 * 60 * 1000;
|
|
26
|
+
function dateScalar(value) {
|
|
27
|
+
if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
28
|
+
throw new Error('Invalid schedule date');
|
|
29
|
+
}
|
|
30
|
+
var _value$split$map = value.split('-').map(Number),
|
|
31
|
+
_value$split$map2 = _slicedToArray(_value$split$map, 3),
|
|
32
|
+
year = _value$split$map2[0],
|
|
33
|
+
month = _value$split$map2[1],
|
|
34
|
+
day = _value$split$map2[2];
|
|
35
|
+
var result = new Date(0);
|
|
36
|
+
result.setUTCFullYear(year, month - 1, day);
|
|
37
|
+
result.setUTCHours(0, 0, 0, 0);
|
|
38
|
+
if (year < 1 || result.getUTCFullYear() !== year || result.getUTCMonth() !== month - 1 || result.getUTCDate() !== day) {
|
|
39
|
+
throw new Error('Invalid schedule date');
|
|
40
|
+
}
|
|
41
|
+
return result.getTime();
|
|
42
|
+
}
|
|
43
|
+
function timeScalar(value) {
|
|
44
|
+
if (typeof value !== 'string') throw new Error('Invalid schedule time');
|
|
45
|
+
var match = /^(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(value);
|
|
46
|
+
if (!match) throw new Error('Invalid schedule time');
|
|
47
|
+
var _match = _slicedToArray(match, 4),
|
|
48
|
+
hours = _match[1],
|
|
49
|
+
minutes = _match[2],
|
|
50
|
+
_match$ = _match[3],
|
|
51
|
+
seconds = _match$ === void 0 ? '0' : _match$;
|
|
52
|
+
if (Number(hours) > 23 || Number(minutes) > 59 || Number(seconds) > 59) {
|
|
53
|
+
throw new Error('Invalid schedule time');
|
|
54
|
+
}
|
|
55
|
+
return ((Number(hours) * 60 + Number(minutes)) * 60 + Number(seconds)) * 1000;
|
|
56
|
+
}
|
|
57
|
+
function datetimeScalar(value) {
|
|
58
|
+
var allowDateOnly = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
59
|
+
if (typeof value !== 'string') throw new Error('Invalid schedule datetime');
|
|
60
|
+
var parts = value.split(/[ T]/);
|
|
61
|
+
if (parts.length === 1 && allowDateOnly) return dateScalar(parts[0]);
|
|
62
|
+
if (parts.length !== 2) throw new Error('Invalid schedule datetime');
|
|
63
|
+
return dateScalar(parts[0]) + timeScalar(parts[1]);
|
|
64
|
+
}
|
|
65
|
+
function dayStart(value) {
|
|
66
|
+
return Math.floor(value / DAY) * DAY;
|
|
67
|
+
}
|
|
68
|
+
function dateLabel(value) {
|
|
69
|
+
return new Date(value).toISOString().slice(0, 10);
|
|
70
|
+
}
|
|
71
|
+
function absoluteRange(start, end, allDay) {
|
|
72
|
+
if (allDay) {
|
|
73
|
+
if (dayStart(end) < dayStart(start)) throw new Error('Reversed schedule');
|
|
74
|
+
start = dayStart(start);
|
|
75
|
+
// An explicit following-day midnight is already an exclusive day boundary.
|
|
76
|
+
end = end > start && end === dayStart(end) ? end : dayStart(end) + DAY;
|
|
77
|
+
}
|
|
78
|
+
if (end <= start) throw new Error('Empty or reversed schedule');
|
|
79
|
+
return {
|
|
80
|
+
start: start,
|
|
81
|
+
end: end
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function contains(range, now) {
|
|
85
|
+
return range.start <= now && now < range.end;
|
|
86
|
+
}
|
|
87
|
+
function normalizeDateRanges(value) {
|
|
88
|
+
if (value === undefined || value === null) return [];
|
|
89
|
+
if (!Array.isArray(value)) throw new Error('Invalid schedule date ranges');
|
|
90
|
+
return value.map(function (range) {
|
|
91
|
+
if (!range || dateScalar(range.end) < dateScalar(range.start)) {
|
|
92
|
+
throw new Error('Invalid schedule date range');
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
start: range.start,
|
|
96
|
+
end: range.end
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Reuse Schedule's date/include/exclude rules without its truncated clock ranges. */
|
|
102
|
+
function dateProbe(schedule, initialDate) {
|
|
103
|
+
var _rule$end, _rule$end2;
|
|
104
|
+
var probe = _objectSpread(_objectSpread({}, schedule), {}, {
|
|
105
|
+
type: 'time-slots',
|
|
106
|
+
start_time: "".concat(dateLabel(initialDate), " 00:00:00"),
|
|
107
|
+
time_slot: [{
|
|
108
|
+
id: 0,
|
|
109
|
+
start_time: '00:00',
|
|
110
|
+
end_time: '23:59'
|
|
111
|
+
}]
|
|
112
|
+
});
|
|
113
|
+
if (schedule.repeat_type === 'none') return probe;
|
|
114
|
+
if (schedule.repeat_type !== 'daily' && schedule.repeat_type !== 'weekly') {
|
|
115
|
+
throw new Error('Invalid schedule repeat type');
|
|
116
|
+
}
|
|
117
|
+
var rule = schedule.repeat_rule;
|
|
118
|
+
if (!rule || !Number.isInteger(rule.frequency) || rule.frequency < 1) {
|
|
119
|
+
throw new Error('Invalid schedule repeat frequency');
|
|
120
|
+
}
|
|
121
|
+
if (((_rule$end = rule.end) === null || _rule$end === void 0 ? void 0 : _rule$end.type) !== 'never' && ((_rule$end2 = rule.end) === null || _rule$end2 === void 0 ? void 0 : _rule$end2.type) !== 'date') {
|
|
122
|
+
throw new Error('Invalid schedule repeat end');
|
|
123
|
+
}
|
|
124
|
+
if (rule.end.type === 'date') dateScalar(rule.end.end_date);
|
|
125
|
+
var included = normalizeDateRanges(rule.included_date);
|
|
126
|
+
var excluded = normalizeDateRanges(rule.excluded_date);
|
|
127
|
+
if (schedule.repeat_type === 'weekly') {
|
|
128
|
+
if (!Array.isArray(rule.frequency_date) || !rule.frequency_date.length || rule.frequency_date.some(function (weekday) {
|
|
129
|
+
return !Number.isInteger(weekday) || weekday < 0 || weekday > 6;
|
|
130
|
+
})) {
|
|
131
|
+
throw new Error('Invalid schedule weekdays');
|
|
132
|
+
}
|
|
133
|
+
// Weekly frequency counts calendar weeks, not elapsed seven-day periods.
|
|
134
|
+
// Keep the real first date as an exclusion; included dates retain priority.
|
|
135
|
+
var weekStart = initialDate - new Date(initialDate).getUTCDay() * DAY;
|
|
136
|
+
probe.start_time = "".concat(dateLabel(weekStart), " 00:00:00");
|
|
137
|
+
if (weekStart < initialDate) {
|
|
138
|
+
excluded.push({
|
|
139
|
+
start: dateLabel(weekStart),
|
|
140
|
+
end: dateLabel(initialDate - DAY)
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
probe.repeat_rule = _objectSpread(_objectSpread({}, rule), {}, {
|
|
145
|
+
included_date: included,
|
|
146
|
+
excluded_date: excluded
|
|
147
|
+
});
|
|
148
|
+
return probe;
|
|
149
|
+
}
|
|
150
|
+
function recurringRangeAvailable(schedule, initialDate, offsets, now) {
|
|
151
|
+
var probe = dateProbe(schedule, initialDate);
|
|
152
|
+
var maxDaysBack = Math.ceil(Math.max.apply(Math, _toConsumableArray(offsets.map(function (range) {
|
|
153
|
+
return range.end;
|
|
154
|
+
}))) / DAY);
|
|
155
|
+
var today = dayStart(now);
|
|
156
|
+
var _loop = function _loop() {
|
|
157
|
+
var anchor = today - daysBack * DAY;
|
|
158
|
+
// Do not expand an entire year: only dates whose windows can contain now.
|
|
159
|
+
if (!offsets.some(function (range) {
|
|
160
|
+
return contains({
|
|
161
|
+
start: anchor + range.start,
|
|
162
|
+
end: anchor + range.end
|
|
163
|
+
}, now);
|
|
164
|
+
})) {
|
|
165
|
+
return 0; // continue
|
|
166
|
+
}
|
|
167
|
+
if (getScheduleStartEndTimePoints(dateLabel(anchor), [probe]).length > 0) return {
|
|
168
|
+
v: true
|
|
169
|
+
};
|
|
170
|
+
},
|
|
171
|
+
_ret;
|
|
172
|
+
for (var daysBack = 0; daysBack <= maxDaysBack; daysBack += 1) {
|
|
173
|
+
_ret = _loop();
|
|
174
|
+
if (_ret === 0) continue;
|
|
175
|
+
if (_ret) return _ret.v;
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
function scheduleAvailable(schedule, now) {
|
|
180
|
+
if (!schedule || _typeof(schedule) !== 'object') throw new Error('Invalid schedule');
|
|
181
|
+
var allDay = schedule.is_all === 1;
|
|
182
|
+
if (schedule.type === 'designation') {
|
|
183
|
+
var entries = Array.isArray(schedule.designation) ? schedule.designation : [schedule.designation];
|
|
184
|
+
if (!entries.length) throw new Error('Missing designated schedule');
|
|
185
|
+
// Designation stores explicit absolute intervals, including multi-day spans.
|
|
186
|
+
var ranges = entries.map(function (entry) {
|
|
187
|
+
if (!entry) throw new Error('Invalid designated schedule');
|
|
188
|
+
return absoluteRange(dateScalar(entry.start_date) + (allDay ? 0 : timeScalar(entry.start_time)), dateScalar(entry.end_date) + (allDay ? timeScalar(entry.end_time || '00:00') : timeScalar(entry.end_time)), allDay);
|
|
189
|
+
});
|
|
190
|
+
return ranges.some(function (range) {
|
|
191
|
+
return contains(range, now);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
if (schedule.type === 'standard') {
|
|
195
|
+
var range = absoluteRange(datetimeScalar(schedule.start_time, allDay), datetimeScalar(schedule.end_time, allDay), allDay);
|
|
196
|
+
if (schedule.repeat_type === 'none') return contains(range, now);
|
|
197
|
+
var initialDate = dayStart(range.start);
|
|
198
|
+
return recurringRangeAvailable(schedule, initialDate, [{
|
|
199
|
+
start: range.start - initialDate,
|
|
200
|
+
end: range.end - initialDate
|
|
201
|
+
}], now);
|
|
202
|
+
}
|
|
203
|
+
if (schedule.type === 'time-slots') {
|
|
204
|
+
var _initialDate = dayStart(datetimeScalar(schedule.start_time, true));
|
|
205
|
+
var offsets;
|
|
206
|
+
if (allDay) {
|
|
207
|
+
offsets = [{
|
|
208
|
+
start: 0,
|
|
209
|
+
end: DAY
|
|
210
|
+
}];
|
|
211
|
+
} else {
|
|
212
|
+
if (!Array.isArray(schedule.time_slot) || !schedule.time_slot.length) {
|
|
213
|
+
throw new Error('Missing schedule time slots');
|
|
214
|
+
}
|
|
215
|
+
offsets = schedule.time_slot.map(function (slot) {
|
|
216
|
+
var start = timeScalar(slot === null || slot === void 0 ? void 0 : slot.start_time);
|
|
217
|
+
var end = timeScalar(slot === null || slot === void 0 ? void 0 : slot.end_time);
|
|
218
|
+
if (start === end) throw new Error('Empty schedule time slot');
|
|
219
|
+
if (end < start) end += DAY;
|
|
220
|
+
return {
|
|
221
|
+
start: start,
|
|
222
|
+
end: end
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return recurringRangeAvailable(schedule, _initialDate, offsets, now);
|
|
227
|
+
}
|
|
228
|
+
throw new Error('Unsupported schedule type');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Current time is projected into the shop's calendar; host timezone is not used. */
|
|
232
|
+
export function evaluateResourceSchedules(_ref) {
|
|
233
|
+
var schedules = _ref.schedules,
|
|
234
|
+
timeZone = _ref.timeZone,
|
|
235
|
+
now = _ref.now;
|
|
236
|
+
var formatter;
|
|
237
|
+
try {
|
|
238
|
+
if (typeof timeZone !== 'string' || !timeZone.trim()) throw new Error('Missing timezone');
|
|
239
|
+
var options = {
|
|
240
|
+
timeZone: timeZone,
|
|
241
|
+
calendar: 'gregory',
|
|
242
|
+
numberingSystem: 'latn',
|
|
243
|
+
year: 'numeric',
|
|
244
|
+
month: '2-digit',
|
|
245
|
+
day: '2-digit',
|
|
246
|
+
hour: '2-digit',
|
|
247
|
+
minute: '2-digit',
|
|
248
|
+
second: '2-digit',
|
|
249
|
+
hourCycle: 'h23'
|
|
250
|
+
};
|
|
251
|
+
formatter = new Intl.DateTimeFormat('en-GB', options);
|
|
252
|
+
} catch (_unused) {
|
|
253
|
+
return {
|
|
254
|
+
available: false,
|
|
255
|
+
reason: 'invalid_timezone'
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
if (!(now instanceof Date) || !Number.isFinite(now.getTime()) || !Array.isArray(schedules) || !schedules.length) {
|
|
259
|
+
return {
|
|
260
|
+
available: false,
|
|
261
|
+
reason: 'invalid_schedule'
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
var parts = {};
|
|
265
|
+
formatter.formatToParts(now).forEach(function (part) {
|
|
266
|
+
parts[part.type] = part.value;
|
|
267
|
+
});
|
|
268
|
+
var localNow;
|
|
269
|
+
try {
|
|
270
|
+
localNow = datetimeScalar("".concat(parts.year, "-").concat(parts.month, "-").concat(parts.day, " ").concat(parts.hour, ":").concat(parts.minute, ":").concat(parts.second)) + now.getUTCMilliseconds();
|
|
271
|
+
} catch (_unused2) {
|
|
272
|
+
return {
|
|
273
|
+
available: false,
|
|
274
|
+
reason: 'invalid_schedule'
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
var invalid = false;
|
|
278
|
+
var _iterator = _createForOfIteratorHelper(schedules),
|
|
279
|
+
_step;
|
|
280
|
+
try {
|
|
281
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
282
|
+
var schedule = _step.value;
|
|
283
|
+
try {
|
|
284
|
+
if (scheduleAvailable(schedule, localNow)) return {
|
|
285
|
+
available: true
|
|
286
|
+
};
|
|
287
|
+
} catch (_unused3) {
|
|
288
|
+
invalid = true;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
} catch (err) {
|
|
292
|
+
_iterator.e(err);
|
|
293
|
+
} finally {
|
|
294
|
+
_iterator.f();
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
available: false,
|
|
298
|
+
reason: invalid ? 'invalid_schedule' : 'outside_schedule'
|
|
299
|
+
};
|
|
300
|
+
}
|
|
@@ -192,8 +192,10 @@ export interface ScanOrderSubmitPayload extends Omit<ScanOrderTempOrder, 'platfo
|
|
|
192
192
|
}>;
|
|
193
193
|
products: ScanOrderSubmitProduct[];
|
|
194
194
|
}
|
|
195
|
-
export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'multiple_orders' | 'additional_order_with_code' | 'additional_order';
|
|
195
|
+
export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'resource_block' | 'multiple_orders' | 'additional_order_with_code' | 'additional_order';
|
|
196
196
|
export interface ScanOrderTableFormRecord {
|
|
197
|
+
/** 桌台可用日程;未配置时不限制可用时段。 */
|
|
198
|
+
schedule?: Array<number | string> | null;
|
|
197
199
|
policy?: string | null;
|
|
198
200
|
partyroom_booking?: string | null;
|
|
199
201
|
capacity?: number | string | null;
|
|
@@ -261,10 +261,12 @@ var isInRepeatingSchedule = function isInRepeatingSchedule(targetDate, targetDat
|
|
|
261
261
|
|
|
262
262
|
// 每日重复逻辑
|
|
263
263
|
var isInDailyRepeat = function isInDailyRepeat(targetDate, startDate, endDate, repeatRule) {
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
// dayjs#diff 会截断不足一天的负差值;必须先比较完整时刻,避免开始日前的
|
|
265
|
+
// 当天时段被误判为第 0 天。
|
|
266
|
+
if (targetDate.isBefore(startDate)) {
|
|
266
267
|
return false;
|
|
267
268
|
}
|
|
269
|
+
var daysDiff = targetDate.diff(startDate, 'day');
|
|
268
270
|
|
|
269
271
|
// 检查频率
|
|
270
272
|
if (daysDiff % repeatRule.frequency !== 0) {
|
|
@@ -283,6 +285,10 @@ var isInDailyRepeat = function isInDailyRepeat(targetDate, startDate, endDate, r
|
|
|
283
285
|
|
|
284
286
|
// 每周重复逻辑
|
|
285
287
|
var isInWeeklyRepeat = function isInWeeklyRepeat(targetDate, startDate, endDate, repeatRule) {
|
|
288
|
+
// 同上:不足一周的负差值会被截断为 0,开始时刻前不能命中重复规则。
|
|
289
|
+
if (targetDate.isBefore(startDate)) {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
286
292
|
var targetDayOfWeek = targetDate.day(); // 0=周日, 1=周一, ..., 6=周六
|
|
287
293
|
|
|
288
294
|
// 检查是否在指定的星期几内
|
|
@@ -292,9 +298,6 @@ var isInWeeklyRepeat = function isInWeeklyRepeat(targetDate, startDate, endDate,
|
|
|
292
298
|
|
|
293
299
|
// 计算周差
|
|
294
300
|
var weeksDiff = targetDate.diff(startDate, 'week');
|
|
295
|
-
if (weeksDiff < 0) {
|
|
296
|
-
return false;
|
|
297
|
-
}
|
|
298
301
|
|
|
299
302
|
// 检查频率
|
|
300
303
|
if (weeksDiff % repeatRule.frequency !== 0) {
|
|
@@ -119,6 +119,8 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
119
119
|
private validateBeforeSubmitByItemRule;
|
|
120
120
|
private refreshCartValidationPassed;
|
|
121
121
|
setItemRuleRuntimeConfig(config?: ScanOrderItemRuleRuntimeConfig): Promise<void>;
|
|
122
|
+
/** 只根据已加载的桌台和日程计算当前可用性,不改变数据加载与缓存行为。 */
|
|
123
|
+
private checkResourceSchedule;
|
|
122
124
|
private normalizeResourceState;
|
|
123
125
|
private resolveResourceSelectType;
|
|
124
126
|
private fetchResourceOccupyDetailsByResourceId;
|
|
@@ -45,6 +45,7 @@ var import_ProductList = require("../../modules/ProductList");
|
|
|
45
45
|
var import_Schedule = require("../../modules/Schedule");
|
|
46
46
|
var import_getDateIsInSchedule = require("../../modules/Schedule/getDateIsInSchedule");
|
|
47
47
|
var import_utils2 = require("../../modules/Order/utils");
|
|
48
|
+
var import_resourceSchedule = require("./resourceSchedule");
|
|
48
49
|
var import_dayjs = __toESM(require("dayjs"));
|
|
49
50
|
var import_itemRule = require("../../model/strategy/adapter/itemRule");
|
|
50
51
|
__reExport(ScanOrder_exports, require("./types"), module.exports);
|
|
@@ -1007,16 +1008,19 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1007
1008
|
};
|
|
1008
1009
|
}
|
|
1009
1010
|
async submitScanOrder() {
|
|
1010
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
1011
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1011
1012
|
this.logMethodStart("submitScanOrder");
|
|
1012
1013
|
try {
|
|
1013
1014
|
await this.validateBeforeSubmitByItemRule();
|
|
1014
1015
|
if (!this.store.order) {
|
|
1015
1016
|
throw new Error("scanOrder解决方案需要 order 模块支持");
|
|
1016
1017
|
}
|
|
1018
|
+
const scheduleBlocked = this.checkResourceSchedule((_a = this.store.resource) == null ? void 0 : _a.table_form_record);
|
|
1019
|
+
if (scheduleBlocked)
|
|
1020
|
+
throw new Error(scheduleBlocked.errorTips);
|
|
1017
1021
|
const tempOrderForSubmit = this.store.order.ensureTempOrder();
|
|
1018
1022
|
tempOrderForSubmit.delivery_type = "shop_service";
|
|
1019
|
-
const resourceTableName = (
|
|
1023
|
+
const resourceTableName = (_c = (_b = this.store.resource) == null ? void 0 : _b.table_form_record) == null ? void 0 : _c.name;
|
|
1020
1024
|
if (resourceTableName && typeof resourceTableName === "object") {
|
|
1021
1025
|
tempOrderForSubmit.table_number = resourceTableName;
|
|
1022
1026
|
} else {
|
|
@@ -1026,15 +1030,15 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1026
1030
|
const enhancePayload = this.buildSubmitPayloadEnhancer();
|
|
1027
1031
|
const result = await this.store.order.submitTempOrder({
|
|
1028
1032
|
cacheId: this.cacheId,
|
|
1029
|
-
platform: (
|
|
1030
|
-
businessCode: (
|
|
1031
|
-
channel: (
|
|
1032
|
-
type: (
|
|
1033
|
+
platform: (_d = this.otherParams) == null ? void 0 : _d.platform,
|
|
1034
|
+
businessCode: (_e = this.otherParams) == null ? void 0 : _e.businessCode,
|
|
1035
|
+
channel: (_f = this.otherParams) == null ? void 0 : _f.channel,
|
|
1036
|
+
type: (_g = this.otherParams) == null ? void 0 : _g.type,
|
|
1033
1037
|
enhancePayload
|
|
1034
1038
|
});
|
|
1035
1039
|
const tempOrder = this.store.order.getTempOrder();
|
|
1036
1040
|
this.logMethodSuccess("submitScanOrder", {
|
|
1037
|
-
productCount: ((
|
|
1041
|
+
productCount: ((_h = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _h.length) || 0
|
|
1038
1042
|
});
|
|
1039
1043
|
return result;
|
|
1040
1044
|
} catch (error) {
|
|
@@ -1485,6 +1489,27 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1485
1489
|
strategyCount: Array.isArray(this.itemRuleRuntimeConfig.strategyConfigs) ? this.itemRuleRuntimeConfig.strategyConfigs.length : 0
|
|
1486
1490
|
});
|
|
1487
1491
|
}
|
|
1492
|
+
/** 只根据已加载的桌台和日程计算当前可用性,不改变数据加载与缓存行为。 */
|
|
1493
|
+
checkResourceSchedule(formRecord) {
|
|
1494
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1495
|
+
const ids = formRecord == null ? void 0 : formRecord.schedule;
|
|
1496
|
+
if (!Array.isArray(ids) || !ids.length)
|
|
1497
|
+
return null;
|
|
1498
|
+
const coreState = (_a = this.core.getPlugin("shopStore")) == null ? void 0 : _a.get("core");
|
|
1499
|
+
const schedules = ((_b = this.store.schedule) == null ? void 0 : _b.getScheduleListByIds(ids.map(Number))) || [];
|
|
1500
|
+
const result = (0, import_resourceSchedule.evaluateResourceSchedules)({
|
|
1501
|
+
schedules,
|
|
1502
|
+
timeZone: (_d = (_c = coreState == null ? void 0 : coreState.core) == null ? void 0 : _c.shop) == null ? void 0 : _d.timezone,
|
|
1503
|
+
now: /* @__PURE__ */ new Date()
|
|
1504
|
+
});
|
|
1505
|
+
if (result.available)
|
|
1506
|
+
return null;
|
|
1507
|
+
const locale = String(
|
|
1508
|
+
(coreState == null ? void 0 : coreState.translateLocale) || ((_f = (_e = coreState == null ? void 0 : coreState.core) == null ? void 0 : _e.shop) == null ? void 0 : _f.primary_locale) || "en"
|
|
1509
|
+
).toLowerCase();
|
|
1510
|
+
const errorTips = locale === "zh-hk" || locale === "zh-tw" ? "目前桌檯不在可用時段,請聯絡工作人員。" : locale.startsWith("zh") ? "当前桌台不在可用时段,请联系工作人员。" : "This table is outside its available hours. Please contact staff.";
|
|
1511
|
+
return { mode: "resource_block", table_form_record: formRecord, errorTips };
|
|
1512
|
+
}
|
|
1488
1513
|
normalizeResourceState(detail, resourceSelectType, hasOrderId) {
|
|
1489
1514
|
var _a, _b, _c, _d;
|
|
1490
1515
|
const currentOrderId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.order_id);
|
|
@@ -1757,6 +1782,9 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1757
1782
|
}
|
|
1758
1783
|
const occupyDetails = await this.fetchResourceOccupyDetailsByResourceId(normalizedResourceId);
|
|
1759
1784
|
const occupyDetail = occupyDetails[0] ?? null;
|
|
1785
|
+
const scheduleBlocked = this.checkResourceSchedule(occupyDetail == null ? void 0 : occupyDetail.form_record);
|
|
1786
|
+
if (scheduleBlocked)
|
|
1787
|
+
return scheduleBlocked;
|
|
1760
1788
|
const resourceSelectType = this.resolveResourceSelectType(
|
|
1761
1789
|
(0, import_utils.toPositiveString)(occupyDetail == null ? void 0 : occupyDetail.form_id)
|
|
1762
1790
|
);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ScheduleItem } from '../../modules/Schedule/types';
|
|
2
|
+
type Evaluation = {
|
|
3
|
+
available: boolean;
|
|
4
|
+
reason?: 'outside_schedule' | 'invalid_schedule' | 'invalid_timezone';
|
|
5
|
+
};
|
|
6
|
+
/** Current time is projected into the shop's calendar; host timezone is not used. */
|
|
7
|
+
export declare function evaluateResourceSchedules({ schedules, timeZone, now, }: {
|
|
8
|
+
schedules: ScheduleItem[];
|
|
9
|
+
timeZone: string;
|
|
10
|
+
now: Date;
|
|
11
|
+
}): Evaluation;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/solution/ScanOrder/resourceSchedule.ts
|
|
30
|
+
var resourceSchedule_exports = {};
|
|
31
|
+
__export(resourceSchedule_exports, {
|
|
32
|
+
evaluateResourceSchedules: () => evaluateResourceSchedules
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(resourceSchedule_exports);
|
|
35
|
+
var import_dayjs = __toESM(require("dayjs"));
|
|
36
|
+
var import_isSameOrAfter = __toESM(require("dayjs/plugin/isSameOrAfter"));
|
|
37
|
+
var import_isSameOrBefore = __toESM(require("dayjs/plugin/isSameOrBefore"));
|
|
38
|
+
var import_getDateIsInSchedule = require("../../modules/Schedule/getDateIsInSchedule");
|
|
39
|
+
import_dayjs.default.extend(import_isSameOrAfter.default);
|
|
40
|
+
import_dayjs.default.extend(import_isSameOrBefore.default);
|
|
41
|
+
var DAY = 24 * 60 * 60 * 1e3;
|
|
42
|
+
function dateScalar(value) {
|
|
43
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
44
|
+
throw new Error("Invalid schedule date");
|
|
45
|
+
}
|
|
46
|
+
const [year, month, day] = value.split("-").map(Number);
|
|
47
|
+
const result = /* @__PURE__ */ new Date(0);
|
|
48
|
+
result.setUTCFullYear(year, month - 1, day);
|
|
49
|
+
result.setUTCHours(0, 0, 0, 0);
|
|
50
|
+
if (year < 1 || result.getUTCFullYear() !== year || result.getUTCMonth() !== month - 1 || result.getUTCDate() !== day) {
|
|
51
|
+
throw new Error("Invalid schedule date");
|
|
52
|
+
}
|
|
53
|
+
return result.getTime();
|
|
54
|
+
}
|
|
55
|
+
function timeScalar(value) {
|
|
56
|
+
if (typeof value !== "string")
|
|
57
|
+
throw new Error("Invalid schedule time");
|
|
58
|
+
const match = /^(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(value);
|
|
59
|
+
if (!match)
|
|
60
|
+
throw new Error("Invalid schedule time");
|
|
61
|
+
const [, hours, minutes, seconds = "0"] = match;
|
|
62
|
+
if (Number(hours) > 23 || Number(minutes) > 59 || Number(seconds) > 59) {
|
|
63
|
+
throw new Error("Invalid schedule time");
|
|
64
|
+
}
|
|
65
|
+
return ((Number(hours) * 60 + Number(minutes)) * 60 + Number(seconds)) * 1e3;
|
|
66
|
+
}
|
|
67
|
+
function datetimeScalar(value, allowDateOnly = false) {
|
|
68
|
+
if (typeof value !== "string")
|
|
69
|
+
throw new Error("Invalid schedule datetime");
|
|
70
|
+
const parts = value.split(/[ T]/);
|
|
71
|
+
if (parts.length === 1 && allowDateOnly)
|
|
72
|
+
return dateScalar(parts[0]);
|
|
73
|
+
if (parts.length !== 2)
|
|
74
|
+
throw new Error("Invalid schedule datetime");
|
|
75
|
+
return dateScalar(parts[0]) + timeScalar(parts[1]);
|
|
76
|
+
}
|
|
77
|
+
function dayStart(value) {
|
|
78
|
+
return Math.floor(value / DAY) * DAY;
|
|
79
|
+
}
|
|
80
|
+
function dateLabel(value) {
|
|
81
|
+
return new Date(value).toISOString().slice(0, 10);
|
|
82
|
+
}
|
|
83
|
+
function absoluteRange(start, end, allDay) {
|
|
84
|
+
if (allDay) {
|
|
85
|
+
if (dayStart(end) < dayStart(start))
|
|
86
|
+
throw new Error("Reversed schedule");
|
|
87
|
+
start = dayStart(start);
|
|
88
|
+
end = end > start && end === dayStart(end) ? end : dayStart(end) + DAY;
|
|
89
|
+
}
|
|
90
|
+
if (end <= start)
|
|
91
|
+
throw new Error("Empty or reversed schedule");
|
|
92
|
+
return { start, end };
|
|
93
|
+
}
|
|
94
|
+
function contains(range, now) {
|
|
95
|
+
return range.start <= now && now < range.end;
|
|
96
|
+
}
|
|
97
|
+
function normalizeDateRanges(value) {
|
|
98
|
+
if (value === void 0 || value === null)
|
|
99
|
+
return [];
|
|
100
|
+
if (!Array.isArray(value))
|
|
101
|
+
throw new Error("Invalid schedule date ranges");
|
|
102
|
+
return value.map((range) => {
|
|
103
|
+
if (!range || dateScalar(range.end) < dateScalar(range.start)) {
|
|
104
|
+
throw new Error("Invalid schedule date range");
|
|
105
|
+
}
|
|
106
|
+
return { start: range.start, end: range.end };
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function dateProbe(schedule, initialDate) {
|
|
110
|
+
var _a, _b;
|
|
111
|
+
const probe = {
|
|
112
|
+
...schedule,
|
|
113
|
+
type: "time-slots",
|
|
114
|
+
start_time: `${dateLabel(initialDate)} 00:00:00`,
|
|
115
|
+
time_slot: [{ id: 0, start_time: "00:00", end_time: "23:59" }]
|
|
116
|
+
};
|
|
117
|
+
if (schedule.repeat_type === "none")
|
|
118
|
+
return probe;
|
|
119
|
+
if (schedule.repeat_type !== "daily" && schedule.repeat_type !== "weekly") {
|
|
120
|
+
throw new Error("Invalid schedule repeat type");
|
|
121
|
+
}
|
|
122
|
+
const rule = schedule.repeat_rule;
|
|
123
|
+
if (!rule || !Number.isInteger(rule.frequency) || rule.frequency < 1) {
|
|
124
|
+
throw new Error("Invalid schedule repeat frequency");
|
|
125
|
+
}
|
|
126
|
+
if (((_a = rule.end) == null ? void 0 : _a.type) !== "never" && ((_b = rule.end) == null ? void 0 : _b.type) !== "date") {
|
|
127
|
+
throw new Error("Invalid schedule repeat end");
|
|
128
|
+
}
|
|
129
|
+
if (rule.end.type === "date")
|
|
130
|
+
dateScalar(rule.end.end_date);
|
|
131
|
+
const included = normalizeDateRanges(rule.included_date);
|
|
132
|
+
const excluded = normalizeDateRanges(rule.excluded_date);
|
|
133
|
+
if (schedule.repeat_type === "weekly") {
|
|
134
|
+
if (!Array.isArray(rule.frequency_date) || !rule.frequency_date.length || rule.frequency_date.some((weekday) => !Number.isInteger(weekday) || weekday < 0 || weekday > 6)) {
|
|
135
|
+
throw new Error("Invalid schedule weekdays");
|
|
136
|
+
}
|
|
137
|
+
const weekStart = initialDate - new Date(initialDate).getUTCDay() * DAY;
|
|
138
|
+
probe.start_time = `${dateLabel(weekStart)} 00:00:00`;
|
|
139
|
+
if (weekStart < initialDate) {
|
|
140
|
+
excluded.push({ start: dateLabel(weekStart), end: dateLabel(initialDate - DAY) });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
probe.repeat_rule = {
|
|
144
|
+
...rule,
|
|
145
|
+
included_date: included,
|
|
146
|
+
excluded_date: excluded
|
|
147
|
+
};
|
|
148
|
+
return probe;
|
|
149
|
+
}
|
|
150
|
+
function recurringRangeAvailable(schedule, initialDate, offsets, now) {
|
|
151
|
+
const probe = dateProbe(schedule, initialDate);
|
|
152
|
+
const maxDaysBack = Math.ceil(Math.max(...offsets.map((range) => range.end)) / DAY);
|
|
153
|
+
const today = dayStart(now);
|
|
154
|
+
for (let daysBack = 0; daysBack <= maxDaysBack; daysBack += 1) {
|
|
155
|
+
const anchor = today - daysBack * DAY;
|
|
156
|
+
if (!offsets.some((range) => contains({ start: anchor + range.start, end: anchor + range.end }, now))) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if ((0, import_getDateIsInSchedule.getScheduleStartEndTimePoints)(dateLabel(anchor), [probe]).length > 0)
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
function scheduleAvailable(schedule, now) {
|
|
165
|
+
if (!schedule || typeof schedule !== "object")
|
|
166
|
+
throw new Error("Invalid schedule");
|
|
167
|
+
const allDay = schedule.is_all === 1;
|
|
168
|
+
if (schedule.type === "designation") {
|
|
169
|
+
const entries = Array.isArray(schedule.designation) ? schedule.designation : [schedule.designation];
|
|
170
|
+
if (!entries.length)
|
|
171
|
+
throw new Error("Missing designated schedule");
|
|
172
|
+
const ranges = entries.map((entry) => {
|
|
173
|
+
if (!entry)
|
|
174
|
+
throw new Error("Invalid designated schedule");
|
|
175
|
+
return absoluteRange(
|
|
176
|
+
dateScalar(entry.start_date) + (allDay ? 0 : timeScalar(entry.start_time)),
|
|
177
|
+
dateScalar(entry.end_date) + (allDay ? timeScalar(entry.end_time || "00:00") : timeScalar(entry.end_time)),
|
|
178
|
+
allDay
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
return ranges.some((range) => contains(range, now));
|
|
182
|
+
}
|
|
183
|
+
if (schedule.type === "standard") {
|
|
184
|
+
const range = absoluteRange(
|
|
185
|
+
datetimeScalar(schedule.start_time, allDay),
|
|
186
|
+
datetimeScalar(schedule.end_time, allDay),
|
|
187
|
+
allDay
|
|
188
|
+
);
|
|
189
|
+
if (schedule.repeat_type === "none")
|
|
190
|
+
return contains(range, now);
|
|
191
|
+
const initialDate = dayStart(range.start);
|
|
192
|
+
return recurringRangeAvailable(schedule, initialDate, [{
|
|
193
|
+
start: range.start - initialDate,
|
|
194
|
+
end: range.end - initialDate
|
|
195
|
+
}], now);
|
|
196
|
+
}
|
|
197
|
+
if (schedule.type === "time-slots") {
|
|
198
|
+
const initialDate = dayStart(datetimeScalar(schedule.start_time, true));
|
|
199
|
+
let offsets;
|
|
200
|
+
if (allDay) {
|
|
201
|
+
offsets = [{ start: 0, end: DAY }];
|
|
202
|
+
} else {
|
|
203
|
+
if (!Array.isArray(schedule.time_slot) || !schedule.time_slot.length) {
|
|
204
|
+
throw new Error("Missing schedule time slots");
|
|
205
|
+
}
|
|
206
|
+
offsets = schedule.time_slot.map((slot) => {
|
|
207
|
+
const start = timeScalar(slot == null ? void 0 : slot.start_time);
|
|
208
|
+
let end = timeScalar(slot == null ? void 0 : slot.end_time);
|
|
209
|
+
if (start === end)
|
|
210
|
+
throw new Error("Empty schedule time slot");
|
|
211
|
+
if (end < start)
|
|
212
|
+
end += DAY;
|
|
213
|
+
return { start, end };
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return recurringRangeAvailable(schedule, initialDate, offsets, now);
|
|
217
|
+
}
|
|
218
|
+
throw new Error("Unsupported schedule type");
|
|
219
|
+
}
|
|
220
|
+
function evaluateResourceSchedules({
|
|
221
|
+
schedules,
|
|
222
|
+
timeZone,
|
|
223
|
+
now
|
|
224
|
+
}) {
|
|
225
|
+
let formatter;
|
|
226
|
+
try {
|
|
227
|
+
if (typeof timeZone !== "string" || !timeZone.trim())
|
|
228
|
+
throw new Error("Missing timezone");
|
|
229
|
+
const options = {
|
|
230
|
+
timeZone,
|
|
231
|
+
calendar: "gregory",
|
|
232
|
+
numberingSystem: "latn",
|
|
233
|
+
year: "numeric",
|
|
234
|
+
month: "2-digit",
|
|
235
|
+
day: "2-digit",
|
|
236
|
+
hour: "2-digit",
|
|
237
|
+
minute: "2-digit",
|
|
238
|
+
second: "2-digit",
|
|
239
|
+
hourCycle: "h23"
|
|
240
|
+
};
|
|
241
|
+
formatter = new Intl.DateTimeFormat("en-GB", options);
|
|
242
|
+
} catch {
|
|
243
|
+
return { available: false, reason: "invalid_timezone" };
|
|
244
|
+
}
|
|
245
|
+
if (!(now instanceof Date) || !Number.isFinite(now.getTime()) || !Array.isArray(schedules) || !schedules.length) {
|
|
246
|
+
return { available: false, reason: "invalid_schedule" };
|
|
247
|
+
}
|
|
248
|
+
const parts = {};
|
|
249
|
+
formatter.formatToParts(now).forEach((part) => {
|
|
250
|
+
parts[part.type] = part.value;
|
|
251
|
+
});
|
|
252
|
+
let localNow;
|
|
253
|
+
try {
|
|
254
|
+
localNow = datetimeScalar(`${parts.year}-${parts.month}-${parts.day} ${parts.hour}:${parts.minute}:${parts.second}`) + now.getUTCMilliseconds();
|
|
255
|
+
} catch {
|
|
256
|
+
return { available: false, reason: "invalid_schedule" };
|
|
257
|
+
}
|
|
258
|
+
let invalid = false;
|
|
259
|
+
for (const schedule of schedules) {
|
|
260
|
+
try {
|
|
261
|
+
if (scheduleAvailable(schedule, localNow))
|
|
262
|
+
return { available: true };
|
|
263
|
+
} catch {
|
|
264
|
+
invalid = true;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return { available: false, reason: invalid ? "invalid_schedule" : "outside_schedule" };
|
|
268
|
+
}
|
|
269
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
270
|
+
0 && (module.exports = {
|
|
271
|
+
evaluateResourceSchedules
|
|
272
|
+
});
|
|
@@ -192,8 +192,10 @@ export interface ScanOrderSubmitPayload extends Omit<ScanOrderTempOrder, 'platfo
|
|
|
192
192
|
}>;
|
|
193
193
|
products: ScanOrderSubmitProduct[];
|
|
194
194
|
}
|
|
195
|
-
export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'multiple_orders' | 'additional_order_with_code' | 'additional_order';
|
|
195
|
+
export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'resource_block' | 'multiple_orders' | 'additional_order_with_code' | 'additional_order';
|
|
196
196
|
export interface ScanOrderTableFormRecord {
|
|
197
|
+
/** 桌台可用日程;未配置时不限制可用时段。 */
|
|
198
|
+
schedule?: Array<number | string> | null;
|
|
197
199
|
policy?: string | null;
|
|
198
200
|
partyroom_booking?: string | null;
|
|
199
201
|
capacity?: number | string | null;
|
|
@@ -183,10 +183,10 @@ var isInRepeatingSchedule = (targetDate, targetDateString, targetTimeString, sch
|
|
|
183
183
|
}
|
|
184
184
|
};
|
|
185
185
|
var isInDailyRepeat = (targetDate, startDate, endDate, repeatRule) => {
|
|
186
|
-
|
|
187
|
-
if (daysDiff < 0) {
|
|
186
|
+
if (targetDate.isBefore(startDate)) {
|
|
188
187
|
return false;
|
|
189
188
|
}
|
|
189
|
+
const daysDiff = targetDate.diff(startDate, "day");
|
|
190
190
|
if (daysDiff % repeatRule.frequency !== 0) {
|
|
191
191
|
return false;
|
|
192
192
|
}
|
|
@@ -196,14 +196,14 @@ var isInDailyRepeat = (targetDate, startDate, endDate, repeatRule) => {
|
|
|
196
196
|
return targetTimeOfDay >= startTimeOfDay && targetTimeOfDay <= endTimeOfDay;
|
|
197
197
|
};
|
|
198
198
|
var isInWeeklyRepeat = (targetDate, startDate, endDate, repeatRule) => {
|
|
199
|
+
if (targetDate.isBefore(startDate)) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
199
202
|
const targetDayOfWeek = targetDate.day();
|
|
200
203
|
if (!repeatRule.frequency_date.includes(targetDayOfWeek)) {
|
|
201
204
|
return false;
|
|
202
205
|
}
|
|
203
206
|
const weeksDiff = targetDate.diff(startDate, "week");
|
|
204
|
-
if (weeksDiff < 0) {
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
207
|
if (weeksDiff % repeatRule.frequency !== 0) {
|
|
208
208
|
return false;
|
|
209
209
|
}
|