@pisell/pisellos 2.1.174 → 2.1.176
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 +0 -9
- package/dist/model/strategy/adapter/walletPass/evaluator.d.ts +0 -2
- package/dist/model/strategy/adapter/walletPass/evaluator.js +2 -4
- package/dist/modules/Discount/index.d.ts +3 -6
- package/dist/modules/Discount/index.js +23 -125
- package/dist/modules/Discount/types.d.ts +5 -34
- package/dist/modules/OpenData/types.d.ts +1 -0
- package/dist/modules/ProductList/index.js +13 -6
- package/dist/modules/Rules/index.d.ts +2 -12
- package/dist/modules/Rules/index.js +113 -377
- package/dist/modules/Rules/types.d.ts +2 -2
- package/dist/plugins/window.d.ts +0 -2
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/ScanOrder/index.d.ts +7 -5
- package/dist/solution/ScanOrder/index.js +123 -31
- package/dist/solution/ScanOrder/resourceSchedule.d.ts +12 -0
- package/dist/solution/ScanOrder/resourceSchedule.js +300 -0
- package/dist/solution/ScanOrder/types.d.ts +9 -1
- package/dist/solution/ShopDiscount/index.d.ts +0 -3
- package/dist/solution/ShopDiscount/index.js +78 -161
- package/dist/solution/ShopDiscount/utils.d.ts +0 -1
- package/dist/solution/ShopDiscount/utils.js +1 -40
- package/lib/model/strategy/adapter/walletPass/evaluator.d.ts +0 -2
- package/lib/model/strategy/adapter/walletPass/evaluator.js +2 -4
- package/lib/modules/Discount/index.d.ts +3 -6
- package/lib/modules/Discount/index.js +16 -66
- package/lib/modules/Discount/types.d.ts +5 -34
- package/lib/modules/OpenData/types.d.ts +1 -0
- package/lib/modules/ProductList/index.js +8 -1
- package/lib/modules/Rules/index.d.ts +2 -12
- package/lib/modules/Rules/index.js +69 -303
- package/lib/modules/Rules/types.d.ts +2 -2
- package/lib/plugins/window.d.ts +0 -2
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/ScanOrder/index.d.ts +7 -5
- package/lib/solution/ScanOrder/index.js +90 -12
- package/lib/solution/ScanOrder/resourceSchedule.d.ts +12 -0
- package/lib/solution/ScanOrder/resourceSchedule.js +272 -0
- package/lib/solution/ScanOrder/types.d.ts +9 -1
- package/lib/solution/ShopDiscount/index.d.ts +0 -3
- package/lib/solution/ShopDiscount/index.js +28 -78
- package/lib/solution/ShopDiscount/utils.d.ts +0 -1
- package/lib/solution/ShopDiscount/utils.js +1 -42
- package/package.json +1 -1
- package/dist/modules/Discount/availability.d.ts +0 -7
- package/dist/modules/Discount/availability.js +0 -52
- package/dist/modules/Discount/entitlementPass.d.ts +0 -34
- package/dist/modules/Discount/entitlementPass.js +0 -147
- package/dist/modules/Discount/entitlementState.d.ts +0 -8
- package/dist/modules/Discount/entitlementState.js +0 -205
- package/dist/modules/Rules/entitlementLines.d.ts +0 -8
- package/dist/modules/Rules/entitlementLines.js +0 -157
- package/lib/modules/Discount/availability.d.ts +0 -7
- package/lib/modules/Discount/availability.js +0 -91
- package/lib/modules/Discount/entitlementPass.d.ts +0 -34
- package/lib/modules/Discount/entitlementPass.js +0 -184
- package/lib/modules/Discount/entitlementState.d.ts +0 -8
- package/lib/modules/Discount/entitlementState.js +0 -206
- package/lib/modules/Rules/entitlementLines.d.ts +0 -8
- package/lib/modules/Rules/entitlementLines.js +0 -158
|
@@ -29,7 +29,7 @@ export interface RulesModuleAPI {
|
|
|
29
29
|
discountList: any[];
|
|
30
30
|
productList: any[];
|
|
31
31
|
holders: {
|
|
32
|
-
form_record_id: number
|
|
32
|
+
form_record_id: number;
|
|
33
33
|
}[];
|
|
34
34
|
isFormSubject: boolean;
|
|
35
35
|
}) => DiscountResult;
|
|
@@ -49,7 +49,7 @@ type ProductDetail = {
|
|
|
49
49
|
original_price?: number | string;
|
|
50
50
|
num?: number;
|
|
51
51
|
quantity: number;
|
|
52
|
-
holder_id?: number | string
|
|
52
|
+
holder_id?: number | string;
|
|
53
53
|
vouchersApplicable?: boolean;
|
|
54
54
|
startDate?: any;
|
|
55
55
|
};
|
package/lib/plugins/window.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Plugin } from '../types';
|
|
2
|
-
import type { WalletPassEvaluator } from '../model/strategy/adapter/walletPass/evaluator';
|
|
3
2
|
/**
|
|
4
3
|
* WindowPlugin 接口定义
|
|
5
4
|
*/
|
|
@@ -15,7 +14,6 @@ export interface WindowPlugin extends Plugin {
|
|
|
15
14
|
document: Partial<Document>;
|
|
16
15
|
history: History;
|
|
17
16
|
interaction?: any;
|
|
18
|
-
getWalletPassEvaluator?: () => WalletPassEvaluator | undefined;
|
|
19
17
|
getLocalStorage?: (key: string) => string | null;
|
|
20
18
|
}
|
|
21
19
|
/**
|
|
@@ -325,7 +325,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
325
325
|
date: string;
|
|
326
326
|
status: string;
|
|
327
327
|
week: string;
|
|
328
|
-
weekNum: 0 | 2 | 1 | 5 |
|
|
328
|
+
weekNum: 0 | 2 | 1 | 5 | 4 | 3 | 6;
|
|
329
329
|
}[]>;
|
|
330
330
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
331
331
|
private getScheduleDataByIds;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Module, ModuleOptions, PisellCore } from '../../types';
|
|
2
2
|
import { BaseModule } from '../../modules/BaseModule';
|
|
3
|
-
import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderAllowAddItemsInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderReservationResourceSelectInfo, ScanOrderScanCodeResult, ScanOrderSyncAdditionalOrderResult, ScanOrderTempOrder } from './types';
|
|
3
|
+
import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderFulfillmentModes, ScanOrderAllowAddItemsInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderReservationResourceSelectInfo, ScanOrderScanCodeResult, ScanOrderSyncAdditionalOrderResult, ScanOrderTempOrder } from './types';
|
|
4
4
|
import type { UpdateProductInOrderParams } from '../../modules/Order/types';
|
|
5
5
|
import type { Discount } from '../../modules/Discount/types';
|
|
6
6
|
import { type CartItemSummary, type PaxInfo, type QuantityCheckResult, type QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
|
|
@@ -75,6 +75,9 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
75
75
|
service_type: 'dine_in' | '';
|
|
76
76
|
pickup_reference_mode: 'counter_pickup' | 'table_service';
|
|
77
77
|
};
|
|
78
|
+
setFulfillmentMode(mode: string): Record<string, any> & {
|
|
79
|
+
service_type?: string | undefined;
|
|
80
|
+
};
|
|
78
81
|
setPickupRef(buzzer: string): string;
|
|
79
82
|
private ensureTempOrder;
|
|
80
83
|
addNewOrder(): Promise<ScanOrderTempOrder>;
|
|
@@ -116,6 +119,8 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
116
119
|
private validateBeforeSubmitByItemRule;
|
|
117
120
|
private refreshCartValidationPassed;
|
|
118
121
|
setItemRuleRuntimeConfig(config?: ScanOrderItemRuleRuntimeConfig): Promise<void>;
|
|
122
|
+
/** 只根据已加载的桌台和日程计算当前可用性,不改变数据加载与缓存行为。 */
|
|
123
|
+
private checkResourceSchedule;
|
|
119
124
|
private normalizeResourceState;
|
|
120
125
|
private resolveResourceSelectType;
|
|
121
126
|
private fetchResourceOccupyDetailsByResourceId;
|
|
@@ -147,10 +152,7 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
147
152
|
syncAdditionalOrderFromResource(resourceId?: string | null): Promise<ScanOrderSyncAdditionalOrderResult>;
|
|
148
153
|
getReservationResourceSelectType(): ScanOrderReservationResourceSelectInfo;
|
|
149
154
|
checkAllowAddItems(): ScanOrderAllowAddItemsInfo;
|
|
150
|
-
getFulfillmentModes():
|
|
151
|
-
enablePickup: boolean;
|
|
152
|
-
enableTableService: boolean;
|
|
153
|
-
};
|
|
155
|
+
getFulfillmentModes(): ScanOrderFulfillmentModes;
|
|
154
156
|
checkManualPickupRef(): {
|
|
155
157
|
enabled: boolean;
|
|
156
158
|
manualInputType?: string;
|
|
@@ -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);
|
|
@@ -577,6 +578,38 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
577
578
|
throw error;
|
|
578
579
|
}
|
|
579
580
|
}
|
|
581
|
+
// 新版履约方式直接保存配置值;旧取餐标识方式继续由 setPickupReferenceMode 处理。
|
|
582
|
+
setFulfillmentMode(mode) {
|
|
583
|
+
this.logMethodStart("setFulfillmentMode", { mode });
|
|
584
|
+
try {
|
|
585
|
+
const { handoverModes } = this.getFulfillmentModes();
|
|
586
|
+
const clearMode = mode === "" && (handoverModes == null ? void 0 : handoverModes.length) === 0;
|
|
587
|
+
if (!clearMode && !(handoverModes == null ? void 0 : handoverModes.includes(mode))) {
|
|
588
|
+
throw new Error("Fulfillment mode is not enabled");
|
|
589
|
+
}
|
|
590
|
+
if (!this.store.order)
|
|
591
|
+
throw new Error("order 模块未初始化");
|
|
592
|
+
const tempOrder = this.store.order.ensureTempOrder();
|
|
593
|
+
const serviceData = {
|
|
594
|
+
...(tempOrder.metadata || {}).shop_service_data || {}
|
|
595
|
+
};
|
|
596
|
+
if (clearMode) {
|
|
597
|
+
delete serviceData.service_type;
|
|
598
|
+
} else {
|
|
599
|
+
serviceData.service_type = mode;
|
|
600
|
+
}
|
|
601
|
+
tempOrder.metadata = {
|
|
602
|
+
...tempOrder.metadata || {},
|
|
603
|
+
shop_service_data: serviceData
|
|
604
|
+
};
|
|
605
|
+
this.store.order.persistTempOrder();
|
|
606
|
+
this.logMethodSuccess("setFulfillmentMode", { mode });
|
|
607
|
+
return tempOrder.metadata.shop_service_data;
|
|
608
|
+
} catch (error) {
|
|
609
|
+
this.logMethodError("setFulfillmentMode", error, { mode });
|
|
610
|
+
throw error;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
580
613
|
// 存储用户自定义取餐标识到 tempOrder.buzzer
|
|
581
614
|
setPickupRef(buzzer) {
|
|
582
615
|
this.logMethodStart("setPickupRef", {
|
|
@@ -975,16 +1008,19 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
975
1008
|
};
|
|
976
1009
|
}
|
|
977
1010
|
async submitScanOrder() {
|
|
978
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
1011
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
979
1012
|
this.logMethodStart("submitScanOrder");
|
|
980
1013
|
try {
|
|
981
1014
|
await this.validateBeforeSubmitByItemRule();
|
|
982
1015
|
if (!this.store.order) {
|
|
983
1016
|
throw new Error("scanOrder解决方案需要 order 模块支持");
|
|
984
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);
|
|
985
1021
|
const tempOrderForSubmit = this.store.order.ensureTempOrder();
|
|
986
1022
|
tempOrderForSubmit.delivery_type = "shop_service";
|
|
987
|
-
const resourceTableName = (
|
|
1023
|
+
const resourceTableName = (_c = (_b = this.store.resource) == null ? void 0 : _b.table_form_record) == null ? void 0 : _c.name;
|
|
988
1024
|
if (resourceTableName && typeof resourceTableName === "object") {
|
|
989
1025
|
tempOrderForSubmit.table_number = resourceTableName;
|
|
990
1026
|
} else {
|
|
@@ -994,15 +1030,15 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
994
1030
|
const enhancePayload = this.buildSubmitPayloadEnhancer();
|
|
995
1031
|
const result = await this.store.order.submitTempOrder({
|
|
996
1032
|
cacheId: this.cacheId,
|
|
997
|
-
platform: (
|
|
998
|
-
businessCode: (
|
|
999
|
-
channel: (
|
|
1000
|
-
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,
|
|
1001
1037
|
enhancePayload
|
|
1002
1038
|
});
|
|
1003
1039
|
const tempOrder = this.store.order.getTempOrder();
|
|
1004
1040
|
this.logMethodSuccess("submitScanOrder", {
|
|
1005
|
-
productCount: ((
|
|
1041
|
+
productCount: ((_h = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _h.length) || 0
|
|
1006
1042
|
});
|
|
1007
1043
|
return result;
|
|
1008
1044
|
} catch (error) {
|
|
@@ -1453,6 +1489,27 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1453
1489
|
strategyCount: Array.isArray(this.itemRuleRuntimeConfig.strategyConfigs) ? this.itemRuleRuntimeConfig.strategyConfigs.length : 0
|
|
1454
1490
|
});
|
|
1455
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
|
+
}
|
|
1456
1513
|
normalizeResourceState(detail, resourceSelectType, hasOrderId) {
|
|
1457
1514
|
var _a, _b, _c, _d;
|
|
1458
1515
|
const currentOrderId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.order_id);
|
|
@@ -1725,6 +1782,9 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1725
1782
|
}
|
|
1726
1783
|
const occupyDetails = await this.fetchResourceOccupyDetailsByResourceId(normalizedResourceId);
|
|
1727
1784
|
const occupyDetail = occupyDetails[0] ?? null;
|
|
1785
|
+
const scheduleBlocked = this.checkResourceSchedule(occupyDetail == null ? void 0 : occupyDetail.form_record);
|
|
1786
|
+
if (scheduleBlocked)
|
|
1787
|
+
return scheduleBlocked;
|
|
1728
1788
|
const resourceSelectType = this.resolveResourceSelectType(
|
|
1729
1789
|
(0, import_utils.toPositiveString)(occupyDetail == null ? void 0 : occupyDetail.form_id)
|
|
1730
1790
|
);
|
|
@@ -2083,16 +2143,34 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
2083
2143
|
this.logMethodSuccess("checkAllowAddItems", result);
|
|
2084
2144
|
return result;
|
|
2085
2145
|
}
|
|
2086
|
-
//
|
|
2146
|
+
// 新版履约方式配置存在时优先使用,缺失时保留旧取餐/送餐开关语义。
|
|
2087
2147
|
// 依赖 checkResourceAvailable 已缓存的 dineInConfig
|
|
2088
2148
|
getFulfillmentModes() {
|
|
2089
2149
|
var _a;
|
|
2090
2150
|
this.logMethodStart("getFulfillmentModes");
|
|
2091
2151
|
const dineInConfig = ((_a = this.otherParams) == null ? void 0 : _a.dineInConfig) || {};
|
|
2092
|
-
const
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2152
|
+
const configuredModes = dineInConfig["fulfillment.handover_mode"];
|
|
2153
|
+
let result;
|
|
2154
|
+
if (Object.prototype.hasOwnProperty.call(
|
|
2155
|
+
dineInConfig,
|
|
2156
|
+
"fulfillment.handover_mode"
|
|
2157
|
+
)) {
|
|
2158
|
+
const handoverModes = Array.isArray(configuredModes) ? Array.from(
|
|
2159
|
+
new Set(
|
|
2160
|
+
configuredModes.filter((mode) => typeof mode === "string").map((mode) => mode.trim()).filter(Boolean)
|
|
2161
|
+
)
|
|
2162
|
+
) : [];
|
|
2163
|
+
result = {
|
|
2164
|
+
enablePickup: handoverModes.includes("pick_up"),
|
|
2165
|
+
enableTableService: handoverModes.includes("table_service"),
|
|
2166
|
+
handoverModes
|
|
2167
|
+
};
|
|
2168
|
+
} else {
|
|
2169
|
+
result = {
|
|
2170
|
+
enablePickup: Boolean(dineInConfig["fulfillment.enable_pickup"]),
|
|
2171
|
+
enableTableService: Boolean(dineInConfig["fulfillment.enable_table_service"])
|
|
2172
|
+
};
|
|
2173
|
+
}
|
|
2096
2174
|
this.logMethodSuccess("getFulfillmentModes", result);
|
|
2097
2175
|
return result;
|
|
2098
2176
|
}
|
|
@@ -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
|
+
});
|
|
@@ -27,6 +27,12 @@ export interface ScanOrderConfig {
|
|
|
27
27
|
verifyResource: boolean;
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
+
export interface ScanOrderFulfillmentModes {
|
|
31
|
+
enablePickup: boolean;
|
|
32
|
+
enableTableService: boolean;
|
|
33
|
+
/** Present only when fulfillment.handover_mode is configured, including an empty list. */
|
|
34
|
+
handoverModes?: string[];
|
|
35
|
+
}
|
|
30
36
|
export interface ScanOrderOrderProductIdentity {
|
|
31
37
|
product_id: number | null;
|
|
32
38
|
product_variant_id: number;
|
|
@@ -186,8 +192,10 @@ export interface ScanOrderSubmitPayload extends Omit<ScanOrderTempOrder, 'platfo
|
|
|
186
192
|
}>;
|
|
187
193
|
products: ScanOrderSubmitProduct[];
|
|
188
194
|
}
|
|
189
|
-
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';
|
|
190
196
|
export interface ScanOrderTableFormRecord {
|
|
197
|
+
/** 桌台可用日程;未配置时不限制可用时段。 */
|
|
198
|
+
schedule?: Array<number | string> | null;
|
|
191
199
|
policy?: string | null;
|
|
192
200
|
partyroom_booking?: string | null;
|
|
193
201
|
capacity?: number | string | null;
|
|
@@ -12,8 +12,6 @@ export declare class ShopDiscountImpl extends BaseModule implements Module {
|
|
|
12
12
|
private store;
|
|
13
13
|
private options;
|
|
14
14
|
private hooks?;
|
|
15
|
-
private entitlementPassEnabled;
|
|
16
|
-
setEntitlementPassEnabled(enabled: boolean): void;
|
|
17
15
|
constructor(name?: string, version?: string);
|
|
18
16
|
initialize(core: PisellCore, options: any): Promise<void>;
|
|
19
17
|
destroy(): Promise<void>;
|
|
@@ -44,7 +42,6 @@ export declare class ShopDiscountImpl extends BaseModule implements Module {
|
|
|
44
42
|
batchSearchByProductIds(productIds: number[]): Promise<Discount[]>;
|
|
45
43
|
scanCode(code: string, customerId?: number): Promise<{
|
|
46
44
|
isAvailable: boolean;
|
|
47
|
-
isAccepted?: boolean;
|
|
48
45
|
productList: Record<string, any>[];
|
|
49
46
|
discountList: Discount[];
|
|
50
47
|
type: "server" | "clientCalc";
|