@pisell/pisellos 0.0.504 → 0.0.506
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/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/ScanOrder/index.d.ts +12 -3
- package/dist/solution/ScanOrder/index.js +260 -152
- package/dist/solution/ScanOrder/types.d.ts +26 -22
- package/dist/solution/ScanOrder/types.js +5 -1
- package/dist/solution/ScanOrder/utils.d.ts +13 -1
- package/dist/solution/ScanOrder/utils.js +45 -6
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/ScanOrder/index.d.ts +12 -3
- package/lib/solution/ScanOrder/index.js +193 -104
- package/lib/solution/ScanOrder/types.d.ts +26 -22
- package/lib/solution/ScanOrder/utils.d.ts +13 -1
- package/lib/solution/ScanOrder/utils.js +37 -0
- package/package.json +1 -1
|
@@ -44,7 +44,7 @@ var import_utils2 = require("../../modules/Order/utils");
|
|
|
44
44
|
var import_dayjs = __toESM(require("dayjs"));
|
|
45
45
|
var import_itemRule = require("../../model/strategy/adapter/itemRule");
|
|
46
46
|
__reExport(ScanOrder_exports, require("./types"), module.exports);
|
|
47
|
-
var
|
|
47
|
+
var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
48
48
|
constructor(name, version) {
|
|
49
49
|
super(name, version);
|
|
50
50
|
this.defaultName = "scanOrder";
|
|
@@ -84,11 +84,11 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
84
84
|
}
|
|
85
85
|
serializeError(error) {
|
|
86
86
|
if (error instanceof Error) {
|
|
87
|
-
return {
|
|
87
|
+
return JSON.stringify({
|
|
88
88
|
name: error.name,
|
|
89
89
|
message: error.message,
|
|
90
90
|
stack: error.stack
|
|
91
|
-
};
|
|
91
|
+
});
|
|
92
92
|
}
|
|
93
93
|
return {
|
|
94
94
|
message: String(error)
|
|
@@ -496,11 +496,24 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
496
496
|
}
|
|
497
497
|
// ScanOrder 提交 payload enhancer:
|
|
498
498
|
// - 给所有 booking 注入 appointment_status: 'started'(扫码点餐语义)
|
|
499
|
+
// - 给所有 booking 的 metadata 注入 resource_select_type(来自预约规则商品的 resource.type)
|
|
499
500
|
// - 给第一条 booking 补 resources 与 product_uid(仅当存在 resource / rule product)
|
|
500
501
|
// - 追加一条 is_rule=true 的 rule product,与 booking 互相关联
|
|
501
502
|
buildSubmitPayloadEnhancer() {
|
|
502
503
|
const ruleProduct = this.enabledReservationRuleProducts[0];
|
|
503
504
|
const resourceState = this.store.resource;
|
|
505
|
+
const resourceSelectType = resourceState == null ? void 0 : resourceState.resourceSelectType;
|
|
506
|
+
const resolveResourceCapacity = () => {
|
|
507
|
+
var _a;
|
|
508
|
+
if (resourceSelectType === "single") {
|
|
509
|
+
const raw = (_a = resourceState == null ? void 0 : resourceState.table_form_record) == null ? void 0 : _a.capacity;
|
|
510
|
+
const num = Number(raw);
|
|
511
|
+
if (Number.isFinite(num) && num > 0)
|
|
512
|
+
return num;
|
|
513
|
+
return 1;
|
|
514
|
+
}
|
|
515
|
+
return 1;
|
|
516
|
+
};
|
|
504
517
|
return (payload, { bookingUuid, tempOrder }) => {
|
|
505
518
|
var _a;
|
|
506
519
|
const resourceId = tempOrder.resource_id ?? (resourceState == null ? void 0 : resourceState.relationId);
|
|
@@ -519,13 +532,19 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
519
532
|
main_field: mainField,
|
|
520
533
|
form_id: resourceState.tableFormId,
|
|
521
534
|
relation_id: resourceState.relationId ?? resourceId,
|
|
522
|
-
capacity:
|
|
535
|
+
capacity: resolveResourceCapacity(),
|
|
523
536
|
metadata: {}
|
|
524
537
|
} : void 0;
|
|
525
538
|
const ruleProductUid = ruleProduct ? (0, import_utils2.createUuidV4)() : void 0;
|
|
539
|
+
const bookingCapacityValue = resolveResourceCapacity();
|
|
526
540
|
const nextBookings = (payload.bookings || []).map((booking, idx) => ({
|
|
527
541
|
...booking,
|
|
528
542
|
appointment_status: "started",
|
|
543
|
+
metadata: {
|
|
544
|
+
...booking.metadata || {},
|
|
545
|
+
...resourceSelectType ? { resource_select_type: resourceSelectType } : {},
|
|
546
|
+
...resourceSelectType ? { capacity: [{ id: 0, value: bookingCapacityValue, name: "" }] } : {}
|
|
547
|
+
},
|
|
529
548
|
...idx === 0 && resourceEntry ? { resources: [resourceEntry] } : {},
|
|
530
549
|
...idx === 0 && ruleProductUid ? { product_uid: ruleProductUid } : {}
|
|
531
550
|
}));
|
|
@@ -1009,20 +1028,22 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1009
1028
|
strategyCount: Array.isArray(this.itemRuleRuntimeConfig.strategyConfigs) ? this.itemRuleRuntimeConfig.strategyConfigs.length : 0
|
|
1010
1029
|
});
|
|
1011
1030
|
}
|
|
1012
|
-
normalizeResourceState(
|
|
1013
|
-
var _a, _b;
|
|
1014
|
-
const
|
|
1015
|
-
const
|
|
1016
|
-
const
|
|
1017
|
-
const
|
|
1018
|
-
const
|
|
1019
|
-
const relationId = (0, import_utils.toPositiveString)(config == null ? void 0 : config.relation_id);
|
|
1020
|
-
const tableFormId = (0, import_utils.toPositiveString)(config == null ? void 0 : config.table_form_id);
|
|
1031
|
+
normalizeResourceState(detail, resourceSelectType, hasOrderId) {
|
|
1032
|
+
var _a, _b, _c, _d;
|
|
1033
|
+
const currentOrderId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.order_id);
|
|
1034
|
+
const lastOrderId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.last_order_id);
|
|
1035
|
+
const relationId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.form_record_id);
|
|
1036
|
+
const tableFormId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.form_id);
|
|
1037
|
+
const formRecord = (detail == null ? void 0 : detail.form_record) ?? null;
|
|
1021
1038
|
const allowSnack = ((_b = (_a = this.otherParams) == null ? void 0 : _a.dineInConfig) == null ? void 0 : _b["workflow.allow_add_items"]) || false;
|
|
1022
1039
|
const deskmateValid = false;
|
|
1023
|
-
const isExclusive =
|
|
1024
|
-
const isFull =
|
|
1025
|
-
|
|
1040
|
+
const isExclusive = resourceSelectType === "single";
|
|
1041
|
+
const isFull = (0, import_utils.computeResourceIsFull)({
|
|
1042
|
+
resourceSelectType,
|
|
1043
|
+
lastOrderId,
|
|
1044
|
+
capacityList: ((_d = (_c = detail == null ? void 0 : detail.resource_capacity) == null ? void 0 : _c[0]) == null ? void 0 : _d.capacity_list) ?? [],
|
|
1045
|
+
capacity: formRecord == null ? void 0 : formRecord.capacity
|
|
1046
|
+
});
|
|
1026
1047
|
let availabilityInfo = {
|
|
1027
1048
|
mode: "idle",
|
|
1028
1049
|
deskmate_valid: deskmateValid
|
|
@@ -1046,33 +1067,19 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1046
1067
|
};
|
|
1047
1068
|
}
|
|
1048
1069
|
} else if (lastOrderId) {
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
table_form_id: tableFormId,
|
|
1060
|
-
deskmate_valid: deskmateValid
|
|
1061
|
-
};
|
|
1062
|
-
}
|
|
1063
|
-
if (isBlock) {
|
|
1064
|
-
availabilityInfo = {
|
|
1065
|
-
mode: "resource_block",
|
|
1066
|
-
order_id: lastOrderId,
|
|
1067
|
-
relation_id: relationId,
|
|
1068
|
-
table_form_id: tableFormId,
|
|
1069
|
-
deskmate_valid: deskmateValid
|
|
1070
|
-
};
|
|
1070
|
+
const canFallthroughToIdle = resourceSelectType === "multiple" && !isFull;
|
|
1071
|
+
if (!canFallthroughToIdle) {
|
|
1072
|
+
availabilityInfo = {
|
|
1073
|
+
mode: "resource_busy",
|
|
1074
|
+
order_id: "0",
|
|
1075
|
+
relation_id: relationId,
|
|
1076
|
+
table_form_id: tableFormId,
|
|
1077
|
+
deskmate_valid: deskmateValid
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1071
1080
|
}
|
|
1072
1081
|
return {
|
|
1073
1082
|
...availabilityInfo,
|
|
1074
|
-
tableMaxNumber,
|
|
1075
|
-
orderCount,
|
|
1076
1083
|
currentOrderId,
|
|
1077
1084
|
lastOrderId,
|
|
1078
1085
|
relationId,
|
|
@@ -1081,27 +1088,46 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1081
1088
|
deskmateValid,
|
|
1082
1089
|
isExclusive,
|
|
1083
1090
|
isFull,
|
|
1084
|
-
|
|
1085
|
-
raw:
|
|
1086
|
-
table_form_record:
|
|
1091
|
+
resourceSelectType,
|
|
1092
|
+
raw: detail,
|
|
1093
|
+
table_form_record: formRecord
|
|
1087
1094
|
};
|
|
1088
1095
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1096
|
+
// 从首个预约规则商品的 product_resource.resources 中,按 form_id 匹配返回 type
|
|
1097
|
+
resolveResourceSelectType(formId) {
|
|
1098
|
+
var _a;
|
|
1099
|
+
const firstProduct = this.enabledReservationRuleProducts[0];
|
|
1100
|
+
const resources = ((_a = firstProduct == null ? void 0 : firstProduct.product_resource) == null ? void 0 : _a.resources) || [];
|
|
1101
|
+
const numericFormId = Number(formId);
|
|
1102
|
+
if (!Number.isFinite(numericFormId) || numericFormId <= 0)
|
|
1103
|
+
return void 0;
|
|
1104
|
+
const matched = resources.find((r) => Number(r == null ? void 0 : r.id) === numericFormId);
|
|
1105
|
+
return matched == null ? void 0 : matched.type;
|
|
1106
|
+
}
|
|
1107
|
+
async fetchResourceOccupyDetailByResourceId(resourceId) {
|
|
1108
|
+
var _a, _b, _c, _d;
|
|
1109
|
+
const formRecordId = Number(resourceId);
|
|
1110
|
+
if (!Number.isFinite(formRecordId) || formRecordId <= 0) {
|
|
1092
1111
|
throw new Error(`[ScanOrder] 非法桌台 resourceId: ${resourceId}`);
|
|
1093
1112
|
}
|
|
1113
|
+
const shopId = (_b = (_a = this.otherParams) == null ? void 0 : _a.getStateData) == null ? void 0 : _b.call(_a, "shop_id");
|
|
1114
|
+
if (!shopId) {
|
|
1115
|
+
throw new Error("[ScanOrder] 无法获取 shop_id");
|
|
1116
|
+
}
|
|
1094
1117
|
const response = await this.request.get(
|
|
1095
|
-
"/order/
|
|
1118
|
+
"/order/resource/occupy-detail",
|
|
1096
1119
|
{
|
|
1097
|
-
|
|
1098
|
-
|
|
1120
|
+
shop_id: shopId,
|
|
1121
|
+
"form_record_ids[]": formRecordId,
|
|
1122
|
+
with_resource_capacity_info: 1,
|
|
1123
|
+
with_resource_order_info: 1,
|
|
1124
|
+
with_resource_form_info: 1
|
|
1099
1125
|
}
|
|
1100
1126
|
);
|
|
1101
1127
|
if (!(response == null ? void 0 : response.status)) {
|
|
1102
|
-
throw new Error((response == null ? void 0 : response.message) || "
|
|
1128
|
+
throw new Error((response == null ? void 0 : response.message) || "获取资源占用详情失败");
|
|
1103
1129
|
}
|
|
1104
|
-
return (response == null ? void 0 : response.data)
|
|
1130
|
+
return ((_d = (_c = response == null ? void 0 : response.data) == null ? void 0 : _c.occupy_details) == null ? void 0 : _d[0]) ?? null;
|
|
1105
1131
|
}
|
|
1106
1132
|
// 检测当前链接是否可用
|
|
1107
1133
|
// 通过 resource_id + 店铺配置
|
|
@@ -1156,33 +1182,15 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1156
1182
|
if (outsideOperatingHours && closedBehaviorValue !== "show_menu_disabled") {
|
|
1157
1183
|
return makeShopClosed(closedMessage, closedBehaviorValue);
|
|
1158
1184
|
}
|
|
1159
|
-
const config = await this.fetchTableConfigByResourceId(resourceId);
|
|
1160
|
-
const resourceState = this.normalizeResourceState(config, hasOrderId);
|
|
1161
|
-
this.store.resource = resourceState;
|
|
1162
|
-
const availabilityInfo = {
|
|
1163
|
-
mode: resourceState.mode,
|
|
1164
|
-
order_id: resourceState.order_id,
|
|
1165
|
-
relation_id: resourceState.relationId,
|
|
1166
|
-
table_form_id: resourceState.tableFormId,
|
|
1167
|
-
deskmate_valid: resourceState.deskmate_valid,
|
|
1168
|
-
table_form_record: resourceState.table_form_record,
|
|
1169
|
-
policy: (_c = config == null ? void 0 : config.table_form_record) == null ? void 0 : _c.policy,
|
|
1170
|
-
partyroom_booking: (_d = config == null ? void 0 : config.table_form_record) == null ? void 0 : _d.partyroom_booking
|
|
1171
|
-
};
|
|
1172
1185
|
const tempOrder = this.ensureTempOrder();
|
|
1173
|
-
tempOrder.relation_id = resourceId || ((_e = this.otherParams) == null ? void 0 : _e.relation_id);
|
|
1174
|
-
tempOrder.table_form_id = resourceState.tableFormId;
|
|
1175
|
-
tempOrder.resource_id = resourceId;
|
|
1176
1186
|
const reservationLinkIds = (0, import_utils.collectLinkProductIdsFromReservationRules)(
|
|
1177
1187
|
dineInConfig["fulfillment.enabled_resource_rules"]
|
|
1178
1188
|
);
|
|
1189
|
+
let pendingRequestEntryPax;
|
|
1190
|
+
let pendingRequestPaxMin;
|
|
1191
|
+
let pendingRequestPaxMax;
|
|
1179
1192
|
if (reservationLinkIds.length === 0) {
|
|
1180
1193
|
this.enabledReservationRuleProducts = [];
|
|
1181
|
-
if (this.store.resource) {
|
|
1182
|
-
delete this.store.resource.requestEntryPax;
|
|
1183
|
-
delete this.store.resource.requestPaxMin;
|
|
1184
|
-
delete this.store.resource.requestPaxMax;
|
|
1185
|
-
}
|
|
1186
1194
|
} else {
|
|
1187
1195
|
tempOrder.metadata = { ...tempOrder.metadata || {} };
|
|
1188
1196
|
delete tempOrder.metadata.table_occupancy_duration;
|
|
@@ -1214,38 +1222,15 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1214
1222
|
tempOrder.metadata.table_occupancy_duration = occupancyMinutes;
|
|
1215
1223
|
}
|
|
1216
1224
|
if ((0, import_utils.hasCustomCapacityProduct)(loaded)) {
|
|
1217
|
-
|
|
1218
|
-
if (this.store.resource)
|
|
1219
|
-
this.store.resource.requestEntryPax = 1;
|
|
1220
|
-
delete availabilityInfo.requestPaxMin;
|
|
1221
|
-
delete availabilityInfo.requestPaxMax;
|
|
1222
|
-
if (this.store.resource) {
|
|
1223
|
-
delete this.store.resource.requestPaxMin;
|
|
1224
|
-
delete this.store.resource.requestPaxMax;
|
|
1225
|
-
}
|
|
1225
|
+
pendingRequestEntryPax = 1;
|
|
1226
1226
|
const paxBounds = (0, import_utils.pickFirstCustomCapacityPaxBounds)(loaded);
|
|
1227
|
-
if ((paxBounds == null ? void 0 : paxBounds.min) !== void 0)
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
}
|
|
1232
|
-
if ((paxBounds == null ? void 0 : paxBounds.max) !== void 0) {
|
|
1233
|
-
availabilityInfo.requestPaxMax = paxBounds.max;
|
|
1234
|
-
if (this.store.resource)
|
|
1235
|
-
this.store.resource.requestPaxMax = paxBounds.max;
|
|
1236
|
-
}
|
|
1237
|
-
} else if (this.store.resource) {
|
|
1238
|
-
delete this.store.resource.requestEntryPax;
|
|
1239
|
-
delete this.store.resource.requestPaxMin;
|
|
1240
|
-
delete this.store.resource.requestPaxMax;
|
|
1227
|
+
if ((paxBounds == null ? void 0 : paxBounds.min) !== void 0)
|
|
1228
|
+
pendingRequestPaxMin = paxBounds.min;
|
|
1229
|
+
if ((paxBounds == null ? void 0 : paxBounds.max) !== void 0)
|
|
1230
|
+
pendingRequestPaxMax = paxBounds.max;
|
|
1241
1231
|
}
|
|
1242
1232
|
} else {
|
|
1243
1233
|
this.enabledReservationRuleProducts = [];
|
|
1244
|
-
if (this.store.resource) {
|
|
1245
|
-
delete this.store.resource.requestEntryPax;
|
|
1246
|
-
delete this.store.resource.requestPaxMin;
|
|
1247
|
-
delete this.store.resource.requestPaxMax;
|
|
1248
|
-
}
|
|
1249
1234
|
void this.addScanOrderLog({
|
|
1250
1235
|
level: "error",
|
|
1251
1236
|
title: "[ScanOrder] enabled_reservation_rules product query failed",
|
|
@@ -1256,6 +1241,41 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1256
1241
|
});
|
|
1257
1242
|
}
|
|
1258
1243
|
}
|
|
1244
|
+
const occupyDetail = await this.fetchResourceOccupyDetailByResourceId(resourceId);
|
|
1245
|
+
const resourceSelectType = this.resolveResourceSelectType(
|
|
1246
|
+
(0, import_utils.toPositiveString)(occupyDetail == null ? void 0 : occupyDetail.form_id)
|
|
1247
|
+
);
|
|
1248
|
+
const resourceState = this.normalizeResourceState(
|
|
1249
|
+
occupyDetail,
|
|
1250
|
+
resourceSelectType,
|
|
1251
|
+
hasOrderId
|
|
1252
|
+
);
|
|
1253
|
+
this.store.resource = resourceState;
|
|
1254
|
+
if (pendingRequestEntryPax !== void 0) {
|
|
1255
|
+
this.store.resource.requestEntryPax = pendingRequestEntryPax;
|
|
1256
|
+
}
|
|
1257
|
+
if (pendingRequestPaxMin !== void 0) {
|
|
1258
|
+
this.store.resource.requestPaxMin = pendingRequestPaxMin;
|
|
1259
|
+
}
|
|
1260
|
+
if (pendingRequestPaxMax !== void 0) {
|
|
1261
|
+
this.store.resource.requestPaxMax = pendingRequestPaxMax;
|
|
1262
|
+
}
|
|
1263
|
+
const availabilityInfo = {
|
|
1264
|
+
mode: resourceState.mode,
|
|
1265
|
+
order_id: resourceState.order_id,
|
|
1266
|
+
relation_id: resourceState.relationId,
|
|
1267
|
+
table_form_id: resourceState.tableFormId,
|
|
1268
|
+
deskmate_valid: resourceState.deskmate_valid,
|
|
1269
|
+
table_form_record: resourceState.table_form_record,
|
|
1270
|
+
policy: (_c = occupyDetail == null ? void 0 : occupyDetail.form_record) == null ? void 0 : _c.policy,
|
|
1271
|
+
partyroom_booking: (_d = occupyDetail == null ? void 0 : occupyDetail.form_record) == null ? void 0 : _d.partyroom_booking,
|
|
1272
|
+
...this.store.resource.requestEntryPax !== void 0 ? { requestEntryPax: this.store.resource.requestEntryPax } : {},
|
|
1273
|
+
...this.store.resource.requestPaxMin !== void 0 ? { requestPaxMin: this.store.resource.requestPaxMin } : {},
|
|
1274
|
+
...this.store.resource.requestPaxMax !== void 0 ? { requestPaxMax: this.store.resource.requestPaxMax } : {}
|
|
1275
|
+
};
|
|
1276
|
+
tempOrder.relation_id = resourceId || ((_e = this.otherParams) == null ? void 0 : _e.relation_id);
|
|
1277
|
+
tempOrder.table_form_id = resourceState.tableFormId;
|
|
1278
|
+
tempOrder.resource_id = resourceId;
|
|
1259
1279
|
(_f = this.store.order) == null ? void 0 : _f.persistTempOrder();
|
|
1260
1280
|
if (availabilityInfo.mode === "idle") {
|
|
1261
1281
|
await this.addNewOrder();
|
|
@@ -1303,14 +1323,13 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1303
1323
|
persistedRelationId: tempOrder.relation_id,
|
|
1304
1324
|
persistedResourceId: tempOrder.resource_id,
|
|
1305
1325
|
deskmateValid: availabilityInfo.deskmate_valid,
|
|
1306
|
-
|
|
1307
|
-
tableMaxNumber: resourceState.tableMaxNumber,
|
|
1326
|
+
resourceSelectType: resourceState.resourceSelectType,
|
|
1308
1327
|
isExclusive: resourceState.isExclusive,
|
|
1309
1328
|
isFull: resourceState.isFull
|
|
1310
1329
|
});
|
|
1311
1330
|
return availabilityInfo;
|
|
1312
1331
|
} catch (error) {
|
|
1313
|
-
this.logMethodError("checkResourceAvailable", error, {
|
|
1332
|
+
this.logMethodError("checkResourceAvailable", error.message, {
|
|
1314
1333
|
resourceId
|
|
1315
1334
|
});
|
|
1316
1335
|
throw error;
|
|
@@ -1353,7 +1372,7 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1353
1372
|
});
|
|
1354
1373
|
return formattedRes;
|
|
1355
1374
|
} catch (error) {
|
|
1356
|
-
this.logMethodError("getProductList", error);
|
|
1375
|
+
this.logMethodError("getProductList", error.message);
|
|
1357
1376
|
throw error;
|
|
1358
1377
|
}
|
|
1359
1378
|
}
|
|
@@ -1367,6 +1386,69 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1367
1386
|
this.otherParams = { ...this.otherParams, ...params };
|
|
1368
1387
|
}
|
|
1369
1388
|
}
|
|
1389
|
+
getUIStateBucketKey() {
|
|
1390
|
+
if (!this.cacheId)
|
|
1391
|
+
return null;
|
|
1392
|
+
return `${_ScanOrderImpl.UI_STATE_KEY_PREFIX}${this.cacheId}`;
|
|
1393
|
+
}
|
|
1394
|
+
readUIStateBucket() {
|
|
1395
|
+
var _a;
|
|
1396
|
+
const key = this.getUIStateBucketKey();
|
|
1397
|
+
if (!key || !((_a = this.window) == null ? void 0 : _a.sessionStorage))
|
|
1398
|
+
return {};
|
|
1399
|
+
try {
|
|
1400
|
+
const raw = this.window.sessionStorage.getItem(key) || "{}";
|
|
1401
|
+
const parsed = JSON.parse(raw);
|
|
1402
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
1403
|
+
} catch {
|
|
1404
|
+
return {};
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
writeUIStateBucket(bucket) {
|
|
1408
|
+
var _a;
|
|
1409
|
+
const key = this.getUIStateBucketKey();
|
|
1410
|
+
if (!key || !((_a = this.window) == null ? void 0 : _a.sessionStorage))
|
|
1411
|
+
return;
|
|
1412
|
+
try {
|
|
1413
|
+
this.window.sessionStorage.setItem(key, JSON.stringify(bucket));
|
|
1414
|
+
} catch (error) {
|
|
1415
|
+
console.warn("[ScanOrder] writeUIStateBucket failed", error);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
setUIState(key, value) {
|
|
1419
|
+
if (!this.getUIStateBucketKey())
|
|
1420
|
+
return;
|
|
1421
|
+
const bucket = this.readUIStateBucket();
|
|
1422
|
+
bucket[key] = value;
|
|
1423
|
+
this.writeUIStateBucket(bucket);
|
|
1424
|
+
}
|
|
1425
|
+
getUIState(key) {
|
|
1426
|
+
if (!this.getUIStateBucketKey())
|
|
1427
|
+
return void 0;
|
|
1428
|
+
const bucket = this.readUIStateBucket();
|
|
1429
|
+
return bucket[key];
|
|
1430
|
+
}
|
|
1431
|
+
deleteUIState(key) {
|
|
1432
|
+
if (!this.getUIStateBucketKey())
|
|
1433
|
+
return;
|
|
1434
|
+
const bucket = this.readUIStateBucket();
|
|
1435
|
+
if (key in bucket) {
|
|
1436
|
+
delete bucket[key];
|
|
1437
|
+
this.writeUIStateBucket(bucket);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
// 整桶清空(用于扫新桌、提交成功、restoreOrder 等场景)
|
|
1441
|
+
clearUIState() {
|
|
1442
|
+
var _a;
|
|
1443
|
+
const key = this.getUIStateBucketKey();
|
|
1444
|
+
if (!key || !((_a = this.window) == null ? void 0 : _a.sessionStorage))
|
|
1445
|
+
return;
|
|
1446
|
+
try {
|
|
1447
|
+
this.window.sessionStorage.removeItem(key);
|
|
1448
|
+
} catch (error) {
|
|
1449
|
+
console.warn("[ScanOrder] clearUIState failed", error);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1370
1452
|
async setEntryPaxNumber(number) {
|
|
1371
1453
|
const pax = (0, import_utils2.normalizeSubmitCollectPaxValue)(number);
|
|
1372
1454
|
this.store.entryPaxNumber = pax;
|
|
@@ -1416,6 +1498,13 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1416
1498
|
return result;
|
|
1417
1499
|
}
|
|
1418
1500
|
};
|
|
1501
|
+
var ScanOrderImpl = _ScanOrderImpl;
|
|
1502
|
+
// ─── UI 状态缓存(按 cacheId 分桶,sessionStorage) ───
|
|
1503
|
+
//
|
|
1504
|
+
// 用于物料层持久化 UI 层面的轻量状态(如当前步骤、gate 标记、登录回跳意图等)。
|
|
1505
|
+
// 桶键:pisell.scanOrder.uiState:<cacheId>;内部以 JSON object 形式存储多个字段。
|
|
1506
|
+
// 无 cacheId 时所有方法自动降级为 no-op,上层不用判空。
|
|
1507
|
+
ScanOrderImpl.UI_STATE_KEY_PREFIX = "pisell.scanOrder.uiState:";
|
|
1419
1508
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1420
1509
|
0 && (module.exports = {
|
|
1421
1510
|
ScanOrderImpl,
|
|
@@ -141,10 +141,11 @@ export interface ScanOrderSubmitPayload extends Omit<ScanOrderTempOrder, 'platfo
|
|
|
141
141
|
}>;
|
|
142
142
|
products: ScanOrderSubmitProduct[];
|
|
143
143
|
}
|
|
144
|
-
export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | '
|
|
144
|
+
export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'additional_order_with_code' | 'additional_order';
|
|
145
145
|
export interface ScanOrderTableFormRecord {
|
|
146
146
|
policy?: string | null;
|
|
147
147
|
partyroom_booking?: string | null;
|
|
148
|
+
capacity?: number | string | null;
|
|
148
149
|
[key: string]: any;
|
|
149
150
|
}
|
|
150
151
|
export interface ScanOrderAvailabilityInfo {
|
|
@@ -156,7 +157,7 @@ export interface ScanOrderAvailabilityInfo {
|
|
|
156
157
|
errorTips?: string;
|
|
157
158
|
/** 透传 `availability.closed_behavior`,便于 UI 识别拦截类型(如 show_menu_disabled) */
|
|
158
159
|
closed_behavior?: string;
|
|
159
|
-
/** `/order/
|
|
160
|
+
/** `/order/resource/occupy-detail` 返回的 `form_record` 原样透出 */
|
|
160
161
|
table_form_record?: ScanOrderTableFormRecord | null;
|
|
161
162
|
policy?: string | null;
|
|
162
163
|
partyroom_booking?: string | null;
|
|
@@ -167,34 +168,36 @@ export interface ScanOrderAvailabilityInfo {
|
|
|
167
168
|
/** 首个 `capacity.type === 'custom'` 商品里 `custom[0]` 的 max(人数上限) */
|
|
168
169
|
requestPaxMax?: number;
|
|
169
170
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
/** `resource_capacity[i].capacity_list[j]` */
|
|
172
|
+
export interface ScanOrderResourceCapacitySlot {
|
|
173
|
+
start_at?: string;
|
|
174
|
+
end_at?: string;
|
|
175
|
+
pax?: number | string;
|
|
173
176
|
}
|
|
174
|
-
export interface
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
export interface ScanOrderResourceCapacity {
|
|
178
|
+
capacity?: number | string;
|
|
179
|
+
capacity_list?: ScanOrderResourceCapacitySlot[];
|
|
177
180
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
+
/** `/order/resource/occupy-detail` 单条 `occupy_details[i]` */
|
|
182
|
+
export interface ScanOrderResourceOccupyDetail {
|
|
183
|
+
form_record_id?: number | string | null;
|
|
184
|
+
form_id?: number | string | null;
|
|
181
185
|
order_id?: number | string | null;
|
|
182
186
|
last_order_id?: number | string | null;
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
table_snack?: ScanOrderTableSnackConfig[] | null;
|
|
186
|
-
order_number_prefix?: ScanOrderOrderNumberPrefixConfig[] | null;
|
|
187
|
+
resource_capacity?: ScanOrderResourceCapacity[] | null;
|
|
188
|
+
form_record?: ScanOrderTableFormRecord | null;
|
|
187
189
|
[key: string]: any;
|
|
188
190
|
}
|
|
189
|
-
export interface
|
|
191
|
+
export interface ScanOrderResourceOccupyDetailApiResponse {
|
|
190
192
|
status?: boolean;
|
|
191
193
|
code?: number;
|
|
192
194
|
message?: string;
|
|
193
|
-
data?:
|
|
195
|
+
data?: {
|
|
196
|
+
occupy_details?: ScanOrderResourceOccupyDetail[] | null;
|
|
197
|
+
} | null;
|
|
194
198
|
}
|
|
199
|
+
export type ScanOrderResourceSelectType = 'single' | 'multiple' | 'capacity';
|
|
195
200
|
export interface ScanOrderResourceState extends ScanOrderAvailabilityInfo {
|
|
196
|
-
tableMaxNumber: number;
|
|
197
|
-
orderCount: number;
|
|
198
201
|
relationId?: string;
|
|
199
202
|
tableFormId?: string;
|
|
200
203
|
currentOrderId?: string;
|
|
@@ -203,13 +206,14 @@ export interface ScanOrderResourceState extends ScanOrderAvailabilityInfo {
|
|
|
203
206
|
deskmateValid: boolean;
|
|
204
207
|
isExclusive: boolean;
|
|
205
208
|
isFull: boolean;
|
|
206
|
-
|
|
207
|
-
|
|
209
|
+
/** 来自首个预约规则商品 product_resource.resources 中与 form_id 匹配的 resource type */
|
|
210
|
+
resourceSelectType?: ScanOrderResourceSelectType;
|
|
211
|
+
raw: ScanOrderResourceOccupyDetail | null;
|
|
208
212
|
}
|
|
209
213
|
export interface ScanOrderState {
|
|
210
214
|
entryContext: ScanOrderEntryContext | null;
|
|
211
215
|
status: ScanOrderStatus;
|
|
212
|
-
config:
|
|
216
|
+
config: Record<string, any> | null;
|
|
213
217
|
resource: ScanOrderResourceState | null;
|
|
214
218
|
flow: Record<string, any>;
|
|
215
219
|
error: string | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderSummary, ScanOrderTempOrder } from './types';
|
|
1
|
+
import { ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderResourceCapacitySlot, ScanOrderResourceSelectType, ScanOrderSummary, ScanOrderTempOrder } from './types';
|
|
2
2
|
import type { CartItemSummary, ItemRuleBusinessData, PaxInfo, QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
|
|
3
3
|
import type { StrategyConfig } from '../../model/strategy/type';
|
|
4
4
|
import type { ProductData } from '../../modules/Product/types';
|
|
@@ -109,6 +109,18 @@ export declare function collectLinkProductIdsFromReservationRules(rules: unknown
|
|
|
109
109
|
export declare function pickFirstDurationMinutesFromProducts(products: ProductData[]): number | undefined;
|
|
110
110
|
/** 是否存在 capacity.type === 'custom' 的商品 */
|
|
111
111
|
export declare function hasCustomCapacityProduct(products: ProductData[]): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* 根据预约规则商品的 resource.type 计算桌台是否已被"占满"。
|
|
114
|
+
* - single:只要有 `lastOrderId` 即视为占用
|
|
115
|
+
* - multiple:当前时间落在 `capacity_list[i]` 的 `[start_at, end_at]`(inclusive)内的 pax 之和 > 总容量
|
|
116
|
+
* - 其他('capacity' / undefined):返回 false,不施加限制
|
|
117
|
+
*/
|
|
118
|
+
export declare function computeResourceIsFull(params: {
|
|
119
|
+
resourceSelectType?: ScanOrderResourceSelectType;
|
|
120
|
+
lastOrderId?: string;
|
|
121
|
+
capacityList?: ScanOrderResourceCapacitySlot[];
|
|
122
|
+
capacity?: number | string | null;
|
|
123
|
+
}): boolean;
|
|
112
124
|
/**
|
|
113
125
|
* 在商品列表中找到第一个 `capacity.type === 'custom'` 的商品,取其 `custom` 数组第一项的 min/max。
|
|
114
126
|
* 仅返回有限数字字段;若均无法解析则返回 `undefined`。
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
7
|
var __export = (target, all) => {
|
|
6
8
|
for (var name in all)
|
|
@@ -14,6 +16,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
14
16
|
}
|
|
15
17
|
return to;
|
|
16
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
|
+
));
|
|
17
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
28
|
|
|
19
29
|
// src/solution/ScanOrder/utils.ts
|
|
@@ -25,6 +35,7 @@ __export(utils_exports, {
|
|
|
25
35
|
buildProductKey: () => buildProductKey,
|
|
26
36
|
buildQuantityLimitIndex: () => buildQuantityLimitIndex,
|
|
27
37
|
collectLinkProductIdsFromReservationRules: () => collectLinkProductIdsFromReservationRules,
|
|
38
|
+
computeResourceIsFull: () => computeResourceIsFull,
|
|
28
39
|
createEmptySummary: () => createEmptySummary,
|
|
29
40
|
extractStrategyModelIdsFromTableConfig: () => extractStrategyModelIdsFromTableConfig,
|
|
30
41
|
getProductIdentityIndex: () => getProductIdentityIndex,
|
|
@@ -46,6 +57,7 @@ __export(utils_exports, {
|
|
|
46
57
|
toPriceString: () => toPriceString
|
|
47
58
|
});
|
|
48
59
|
module.exports = __toCommonJS(utils_exports);
|
|
60
|
+
var import_dayjs = __toESM(require("dayjs"));
|
|
49
61
|
function createEmptySummary() {
|
|
50
62
|
return {
|
|
51
63
|
product_quantity: 0,
|
|
@@ -411,6 +423,30 @@ function hasCustomCapacityProduct(products) {
|
|
|
411
423
|
return ((_a = p == null ? void 0 : p.capacity) == null ? void 0 : _a.type) === "custom";
|
|
412
424
|
});
|
|
413
425
|
}
|
|
426
|
+
function computeResourceIsFull(params) {
|
|
427
|
+
const { resourceSelectType, lastOrderId, capacityList, capacity } = params;
|
|
428
|
+
if (resourceSelectType === "single")
|
|
429
|
+
return Boolean(lastOrderId);
|
|
430
|
+
if (resourceSelectType !== "multiple")
|
|
431
|
+
return false;
|
|
432
|
+
const totalCapacity = Number(capacity);
|
|
433
|
+
if (!Number.isFinite(totalCapacity) || totalCapacity <= 0)
|
|
434
|
+
return false;
|
|
435
|
+
const now = (0, import_dayjs.default)();
|
|
436
|
+
let occupied = 0;
|
|
437
|
+
for (const slot of capacityList || []) {
|
|
438
|
+
const start = (0, import_dayjs.default)(slot == null ? void 0 : slot.start_at);
|
|
439
|
+
const end = (0, import_dayjs.default)(slot == null ? void 0 : slot.end_at);
|
|
440
|
+
if (!start.isValid() || !end.isValid())
|
|
441
|
+
continue;
|
|
442
|
+
if ((now.isAfter(start) || now.isSame(start)) && (now.isBefore(end) || now.isSame(end))) {
|
|
443
|
+
const pax = Number(slot == null ? void 0 : slot.pax);
|
|
444
|
+
if (Number.isFinite(pax) && pax > 0)
|
|
445
|
+
occupied += pax;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return occupied > totalCapacity;
|
|
449
|
+
}
|
|
414
450
|
function pickFirstCustomCapacityPaxBounds(products) {
|
|
415
451
|
for (const p of products) {
|
|
416
452
|
const cap = p == null ? void 0 : p.capacity;
|
|
@@ -446,6 +482,7 @@ function pickFirstCustomCapacityPaxBounds(products) {
|
|
|
446
482
|
buildProductKey,
|
|
447
483
|
buildQuantityLimitIndex,
|
|
448
484
|
collectLinkProductIdsFromReservationRules,
|
|
485
|
+
computeResourceIsFull,
|
|
449
486
|
createEmptySummary,
|
|
450
487
|
extractStrategyModelIdsFromTableConfig,
|
|
451
488
|
getProductIdentityIndex,
|