@pisell/pisellos 2.1.129 → 2.1.131
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/modules/Order/index.d.ts +7 -6
- package/dist/modules/Order/index.js +137 -42
- package/dist/modules/Order/types.d.ts +32 -6
- package/dist/modules/Order/types.js +2 -0
- package/dist/modules/Order/utils.d.ts +73 -11
- package/dist/modules/Order/utils.js +304 -52
- package/dist/modules/SalesSummary/utils.js +33 -68
- package/dist/modules/ScanOrderLogger/providers/feishu.js +168 -60
- package/dist/modules/ScanOrderLogger/types.d.ts +6 -0
- package/dist/modules/Summary/utils.js +6 -21
- package/dist/solution/ScanOrder/index.d.ts +57 -8
- package/dist/solution/ScanOrder/index.js +1531 -583
- package/dist/solution/ScanOrder/types.d.ts +86 -26
- package/dist/solution/ScanOrder/types.js +20 -1
- package/dist/solution/ScanOrder/utils.d.ts +53 -5
- package/dist/solution/ScanOrder/utils.js +257 -37
- package/dist/solution/VenueBooking/index.d.ts +30 -10
- package/dist/solution/VenueBooking/index.js +460 -217
- package/dist/solution/VenueBooking/types.d.ts +23 -0
- package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -1
- package/dist/solution/VenueBooking/utils/dateSummary.js +1 -1
- package/dist/solution/VenueBooking/utils/resource.d.ts +11 -1
- package/dist/solution/VenueBooking/utils/resource.js +57 -21
- package/dist/solution/VenueBooking/utils/slotMerge.d.ts +5 -0
- package/dist/solution/VenueBooking/utils/slotMerge.js +33 -12
- package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -1
- package/dist/solution/VenueBooking/utils/timeSlot.js +259 -62
- package/lib/modules/Order/index.d.ts +7 -6
- package/lib/modules/Order/index.js +123 -31
- package/lib/modules/Order/types.d.ts +32 -6
- package/lib/modules/Order/utils.d.ts +73 -11
- package/lib/modules/Order/utils.js +203 -28
- package/lib/modules/SalesSummary/utils.js +13 -47
- package/lib/modules/ScanOrderLogger/providers/feishu.js +100 -34
- package/lib/modules/ScanOrderLogger/types.d.ts +6 -0
- package/lib/modules/Summary/utils.js +4 -18
- package/lib/solution/ScanOrder/index.d.ts +57 -8
- package/lib/solution/ScanOrder/index.js +713 -117
- package/lib/solution/ScanOrder/types.d.ts +86 -26
- package/lib/solution/ScanOrder/utils.d.ts +53 -5
- package/lib/solution/ScanOrder/utils.js +186 -19
- package/lib/solution/VenueBooking/index.d.ts +30 -10
- package/lib/solution/VenueBooking/index.js +206 -51
- package/lib/solution/VenueBooking/types.d.ts +23 -0
- package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -1
- package/lib/solution/VenueBooking/utils/dateSummary.js +1 -1
- package/lib/solution/VenueBooking/utils/resource.d.ts +11 -1
- package/lib/solution/VenueBooking/utils/resource.js +15 -4
- package/lib/solution/VenueBooking/utils/slotMerge.d.ts +5 -0
- package/lib/solution/VenueBooking/utils/slotMerge.js +29 -12
- package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -1
- package/lib/solution/VenueBooking/utils/timeSlot.js +182 -43
- package/package.json +1 -1
|
@@ -107,10 +107,32 @@ function buildPriceBreakdown(params) {
|
|
|
107
107
|
return entries;
|
|
108
108
|
}
|
|
109
109
|
function buildVenueBookingEntry(params) {
|
|
110
|
-
const { group, resourceId, mapping, rawResource, bookingUuid, productUid } = params;
|
|
110
|
+
const { group, resourceId, mapping, rawResource, bookingUuid, productUid, childResources } = params;
|
|
111
111
|
const startMoment = (0, import_dayjs.default)(group.startTime, "YYYY-MM-DD HH:mm");
|
|
112
112
|
const endMoment = (0, import_dayjs.default)(group.endTime, "YYYY-MM-DD HH:mm");
|
|
113
113
|
const duration = endMoment.diff(startMoment, "minute");
|
|
114
|
+
const resourceEntry = {
|
|
115
|
+
relation_type: "form",
|
|
116
|
+
like_status: "common",
|
|
117
|
+
id: resourceId,
|
|
118
|
+
main_field: mapping.resourceName,
|
|
119
|
+
form_id: (rawResource == null ? void 0 : rawResource.form_id) ?? mapping.formId,
|
|
120
|
+
relation_id: resourceId,
|
|
121
|
+
capacity: 1,
|
|
122
|
+
metadata: {}
|
|
123
|
+
};
|
|
124
|
+
if (childResources && childResources.length) {
|
|
125
|
+
resourceEntry.children = childResources.map((child) => ({
|
|
126
|
+
relation_type: "form",
|
|
127
|
+
like_status: "common",
|
|
128
|
+
id: child.resourceId,
|
|
129
|
+
main_field: child.main_field || "",
|
|
130
|
+
form_id: child.form_id ?? child.formId,
|
|
131
|
+
relation_id: child.resourceId,
|
|
132
|
+
capacity: child.capacity ?? 1,
|
|
133
|
+
metadata: {}
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
114
136
|
return {
|
|
115
137
|
schedule_event_id: null,
|
|
116
138
|
appointment_status: "new",
|
|
@@ -126,23 +148,15 @@ function buildVenueBookingEntry(params) {
|
|
|
126
148
|
is_all: false,
|
|
127
149
|
schedule_id: 0,
|
|
128
150
|
product_uid: productUid,
|
|
129
|
-
resources: [
|
|
130
|
-
relation_type: "form",
|
|
131
|
-
like_status: "common",
|
|
132
|
-
id: resourceId,
|
|
133
|
-
main_field: mapping.resourceName,
|
|
134
|
-
form_id: (rawResource == null ? void 0 : rawResource.form_id) ?? mapping.formId,
|
|
135
|
-
relation_id: resourceId,
|
|
136
|
-
capacity: 1,
|
|
137
|
-
metadata: {}
|
|
138
|
-
}],
|
|
151
|
+
resources: [resourceEntry],
|
|
139
152
|
relation_products: [],
|
|
140
153
|
relation_forms: [],
|
|
141
154
|
holder: null,
|
|
142
155
|
metadata: {
|
|
143
156
|
unique_identification_number: bookingUuid,
|
|
144
157
|
venue_booking: true,
|
|
145
|
-
resource_id: resourceId
|
|
158
|
+
resource_id: resourceId,
|
|
159
|
+
product_id: mapping.productId
|
|
146
160
|
}
|
|
147
161
|
};
|
|
148
162
|
}
|
|
@@ -155,6 +169,7 @@ function expandMergedSlotToIndividual(product, slotDurationMinutes) {
|
|
|
155
169
|
const endTime = meta.end_time;
|
|
156
170
|
if (!startTime || !endTime)
|
|
157
171
|
return [];
|
|
172
|
+
const productId = Number(product.product_id);
|
|
158
173
|
const breakdown = meta.price_breakdown;
|
|
159
174
|
const result = [];
|
|
160
175
|
let cursor = (0, import_dayjs.default)(startTime, "YYYY-MM-DD HH:mm");
|
|
@@ -175,6 +190,7 @@ function expandMergedSlotToIndividual(product, slotDurationMinutes) {
|
|
|
175
190
|
const price = priceMap.get(hm) ?? 0;
|
|
176
191
|
result.push({
|
|
177
192
|
resourceId,
|
|
193
|
+
productId,
|
|
178
194
|
startTime: cursor.format("YYYY-MM-DD HH:mm"),
|
|
179
195
|
endTime: slotEnd.format("YYYY-MM-DD HH:mm"),
|
|
180
196
|
price: new import_decimal.default(price).toFixed(2)
|
|
@@ -189,6 +205,7 @@ function expandMergedSlotToIndividual(product, slotDurationMinutes) {
|
|
|
189
205
|
const slotEnd = cursor.add(slotDurationMinutes, "minute");
|
|
190
206
|
result.push({
|
|
191
207
|
resourceId,
|
|
208
|
+
productId,
|
|
192
209
|
startTime: cursor.format("YYYY-MM-DD HH:mm"),
|
|
193
210
|
endTime: slotEnd.format("YYYY-MM-DD HH:mm"),
|
|
194
211
|
price: perSlotPrice
|
|
@@ -26,7 +26,7 @@ export declare function buildTimeSlotGrid(params: {
|
|
|
26
26
|
date: string;
|
|
27
27
|
config: VenueBookingSlotConfig;
|
|
28
28
|
rawResources: VenueResourceRawData[];
|
|
29
|
-
resourceProductMap: Map<number | string, ResourceProductMapping>;
|
|
29
|
+
resourceProductMap: Map<number | string, ResourceProductMapping[]>;
|
|
30
30
|
quotationPriceMap?: Map<string, string | null>;
|
|
31
31
|
}): VenueTimeSlotGrid;
|
|
32
32
|
export {};
|
|
@@ -38,6 +38,7 @@ __export(timeSlot_exports, {
|
|
|
38
38
|
});
|
|
39
39
|
module.exports = __toCommonJS(timeSlot_exports);
|
|
40
40
|
var import_dayjs = __toESM(require("dayjs"));
|
|
41
|
+
var import_decimal = __toESM(require("decimal.js"));
|
|
41
42
|
function isBusinessHoursCrossDay(config) {
|
|
42
43
|
const [startH, startM] = config.businessStartTime.split(":").map(Number);
|
|
43
44
|
const [endH, endM] = config.businessEndTime.split(":").map(Number);
|
|
@@ -122,64 +123,202 @@ function computeSlotStatus(params) {
|
|
|
122
123
|
return { status: "partially_occupied", remainingCapacity: remaining };
|
|
123
124
|
return { status: "available", remainingCapacity: remaining };
|
|
124
125
|
}
|
|
126
|
+
function mergeSubSlots(subSlots) {
|
|
127
|
+
const priority = {
|
|
128
|
+
available: 5,
|
|
129
|
+
partially_occupied: 4,
|
|
130
|
+
occupied: 3,
|
|
131
|
+
unavailable: 2,
|
|
132
|
+
past: 1
|
|
133
|
+
};
|
|
134
|
+
let best = subSlots[0];
|
|
135
|
+
for (const slot of subSlots) {
|
|
136
|
+
if ((priority[slot.status] ?? 0) > (priority[best.status] ?? 0))
|
|
137
|
+
best = slot;
|
|
138
|
+
}
|
|
139
|
+
let minPrice = null;
|
|
140
|
+
for (const slot of subSlots) {
|
|
141
|
+
if (slot.price == null)
|
|
142
|
+
continue;
|
|
143
|
+
const decimal = new import_decimal.default(slot.price || "0");
|
|
144
|
+
if (!minPrice || decimal.lt(minPrice))
|
|
145
|
+
minPrice = decimal;
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
startTime: best.startTime,
|
|
149
|
+
endTime: best.endTime,
|
|
150
|
+
status: best.status,
|
|
151
|
+
price: minPrice ? minPrice.toFixed(2) : null,
|
|
152
|
+
resourceId: best.resourceId,
|
|
153
|
+
resourceFormId: best.resourceFormId,
|
|
154
|
+
capacity: best.capacity,
|
|
155
|
+
remainingCapacity: best.remainingCapacity
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function buildProductSlots(params) {
|
|
159
|
+
const {
|
|
160
|
+
date,
|
|
161
|
+
config,
|
|
162
|
+
resource,
|
|
163
|
+
mapping,
|
|
164
|
+
timeLabels,
|
|
165
|
+
timesForDate,
|
|
166
|
+
events,
|
|
167
|
+
resCapacity,
|
|
168
|
+
now,
|
|
169
|
+
crossDay,
|
|
170
|
+
quotationPriceMap,
|
|
171
|
+
childRawResources,
|
|
172
|
+
childTimesCache,
|
|
173
|
+
childEventsCache,
|
|
174
|
+
config_businessStartHour
|
|
175
|
+
} = params;
|
|
176
|
+
const slots = [];
|
|
177
|
+
for (const label of timeLabels) {
|
|
178
|
+
const [h] = label.split(":").map(Number);
|
|
179
|
+
const isNextDay = crossDay && h < config_businessStartHour;
|
|
180
|
+
const slotDate = isNextDay ? (0, import_dayjs.default)(date).add(1, "day").format("YYYY-MM-DD") : date;
|
|
181
|
+
const slotStart = (0, import_dayjs.default)(`${slotDate} ${label}`);
|
|
182
|
+
const slotEnd = slotStart.add(config.slotDurationMinutes, "minute");
|
|
183
|
+
let status;
|
|
184
|
+
let remainingCapacity = null;
|
|
185
|
+
if (slotStart.isBefore(now)) {
|
|
186
|
+
status = "past";
|
|
187
|
+
} else if (!isSlotWithinResourceTimes(slotStart, slotEnd, timesForDate)) {
|
|
188
|
+
status = "unavailable";
|
|
189
|
+
} else {
|
|
190
|
+
const result = computeSlotStatus({
|
|
191
|
+
slotStart,
|
|
192
|
+
slotEnd,
|
|
193
|
+
events,
|
|
194
|
+
resourceType: mapping.resourceType,
|
|
195
|
+
capacity: resCapacity
|
|
196
|
+
});
|
|
197
|
+
status = result.status;
|
|
198
|
+
remainingCapacity = result.remainingCapacity;
|
|
199
|
+
if (status !== "occupied" && childRawResources && childRawResources.length) {
|
|
200
|
+
for (let i = 0; i < childRawResources.length; i++) {
|
|
201
|
+
const child = childRawResources[i];
|
|
202
|
+
const childTimes = (childTimesCache == null ? void 0 : childTimesCache[i]) ?? getResourceTimesForDate(child, date, config);
|
|
203
|
+
const childEvents = (childEventsCache == null ? void 0 : childEventsCache[i]) ?? collectEventsForDate(child, date, config);
|
|
204
|
+
if (!isSlotWithinResourceTimes(slotStart, slotEnd, childTimes)) {
|
|
205
|
+
status = "unavailable";
|
|
206
|
+
remainingCapacity = null;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
const childType = child.type || "single";
|
|
210
|
+
const childResult = computeSlotStatus({
|
|
211
|
+
slotStart,
|
|
212
|
+
slotEnd,
|
|
213
|
+
events: childEvents,
|
|
214
|
+
resourceType: childType,
|
|
215
|
+
capacity: child.capacity ?? 1
|
|
216
|
+
});
|
|
217
|
+
if (childResult.status === "occupied") {
|
|
218
|
+
status = "occupied";
|
|
219
|
+
remainingCapacity = 0;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
if (childResult.status === "partially_occupied" && status === "available") {
|
|
223
|
+
status = "partially_occupied";
|
|
224
|
+
remainingCapacity = Math.min(
|
|
225
|
+
remainingCapacity ?? childResult.remainingCapacity,
|
|
226
|
+
childResult.remainingCapacity
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const isBookable = status === "available" || status === "partially_occupied";
|
|
233
|
+
const slotStartStr = slotStart.format("YYYY-MM-DD HH:mm");
|
|
234
|
+
slots.push({
|
|
235
|
+
startTime: slotStartStr,
|
|
236
|
+
endTime: slotEnd.format("YYYY-MM-DD HH:mm"),
|
|
237
|
+
status,
|
|
238
|
+
price: isBookable ? (quotationPriceMap == null ? void 0 : quotationPriceMap.get(`${mapping.productId}:${slotStartStr}`)) ?? mapping.price : null,
|
|
239
|
+
resourceId: resource.resourceId,
|
|
240
|
+
resourceFormId: resource.formId,
|
|
241
|
+
capacity: status === "past" || status === "unavailable" ? null : resCapacity,
|
|
242
|
+
remainingCapacity,
|
|
243
|
+
productId: mapping.productId
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return slots;
|
|
247
|
+
}
|
|
125
248
|
function buildTimeSlotGrid(params) {
|
|
126
249
|
const { date, config, rawResources, resourceProductMap, quotationPriceMap } = params;
|
|
127
250
|
const timeLabels = generateTimeLabels(config);
|
|
128
251
|
const now = (0, import_dayjs.default)();
|
|
129
252
|
const crossDay = isBusinessHoursCrossDay(config);
|
|
253
|
+
const config_businessStartHour = Number(config.businessStartTime.split(":")[0]);
|
|
254
|
+
const rawResourceById = /* @__PURE__ */ new Map();
|
|
255
|
+
for (const item of rawResources)
|
|
256
|
+
rawResourceById.set(item.resourceId, item);
|
|
130
257
|
const resources = [];
|
|
131
258
|
for (const resource of rawResources) {
|
|
132
|
-
const
|
|
133
|
-
if (!
|
|
259
|
+
const mappings = resourceProductMap.get(resource.resourceId);
|
|
260
|
+
if (!mappings || !mappings.length)
|
|
134
261
|
continue;
|
|
135
262
|
const timesForDate = getResourceTimesForDate(resource, date, config);
|
|
136
263
|
const events = collectEventsForDate(resource, date, config);
|
|
137
264
|
const resCapacity = resource.capacity ?? 1;
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
remainingCapacity = result.remainingCapacity;
|
|
161
|
-
}
|
|
162
|
-
const isBookable = status === "available" || status === "partially_occupied";
|
|
163
|
-
const slotStartStr = slotStart.format("YYYY-MM-DD HH:mm");
|
|
164
|
-
slots.push({
|
|
165
|
-
startTime: slotStartStr,
|
|
166
|
-
endTime: slotEnd.format("YYYY-MM-DD HH:mm"),
|
|
167
|
-
status,
|
|
168
|
-
price: isBookable ? (quotationPriceMap == null ? void 0 : quotationPriceMap.get(`${mapping.productId}:${slotStartStr}`)) ?? mapping.price : null,
|
|
169
|
-
resourceId: resource.resourceId,
|
|
170
|
-
resourceFormId: resource.formId,
|
|
171
|
-
capacity: status === "past" || status === "unavailable" ? null : resCapacity,
|
|
172
|
-
remainingCapacity
|
|
265
|
+
const combined = resource.combined_resource;
|
|
266
|
+
const isCombined = !!(combined && combined.status === 1 && Array.isArray(combined.resource_ids) && combined.resource_ids.length);
|
|
267
|
+
const childRawResources = isCombined ? combined.resource_ids.map((id) => rawResourceById.get(id)).filter((r) => !!r) : void 0;
|
|
268
|
+
const childTimesCache = childRawResources == null ? void 0 : childRawResources.map((child) => getResourceTimesForDate(child, date, config));
|
|
269
|
+
const childEventsCache = childRawResources == null ? void 0 : childRawResources.map((child) => collectEventsForDate(child, date, config));
|
|
270
|
+
const subRows = mappings.map((mapping) => {
|
|
271
|
+
const productSlots = buildProductSlots({
|
|
272
|
+
date,
|
|
273
|
+
config,
|
|
274
|
+
resource,
|
|
275
|
+
mapping,
|
|
276
|
+
timeLabels,
|
|
277
|
+
timesForDate,
|
|
278
|
+
events,
|
|
279
|
+
resCapacity,
|
|
280
|
+
now,
|
|
281
|
+
crossDay,
|
|
282
|
+
quotationPriceMap,
|
|
283
|
+
childRawResources,
|
|
284
|
+
childTimesCache,
|
|
285
|
+
childEventsCache,
|
|
286
|
+
config_businessStartHour
|
|
173
287
|
});
|
|
288
|
+
return {
|
|
289
|
+
productId: mapping.productId,
|
|
290
|
+
productTitle: mapping.productTitle,
|
|
291
|
+
price: mapping.price,
|
|
292
|
+
slots: productSlots
|
|
293
|
+
};
|
|
294
|
+
});
|
|
295
|
+
const hasMultipleProducts = subRows.length > 1;
|
|
296
|
+
const primary = mappings[0];
|
|
297
|
+
let outerSlots;
|
|
298
|
+
if (hasMultipleProducts) {
|
|
299
|
+
outerSlots = timeLabels.map((_label, slotIndex) => {
|
|
300
|
+
const group = subRows.map((row2) => row2.slots[slotIndex]);
|
|
301
|
+
return mergeSubSlots(group);
|
|
302
|
+
});
|
|
303
|
+
} else {
|
|
304
|
+
outerSlots = subRows[0].slots.map((slot) => ({ ...slot, productId: void 0 }));
|
|
174
305
|
}
|
|
175
|
-
|
|
306
|
+
const row = {
|
|
176
307
|
resourceId: resource.resourceId,
|
|
177
308
|
resourceFormId: resource.formId,
|
|
178
|
-
resourceName: resource.main_field ||
|
|
179
|
-
productId:
|
|
180
|
-
productTitle:
|
|
181
|
-
slots
|
|
182
|
-
}
|
|
309
|
+
resourceName: resource.main_field || primary.resourceName,
|
|
310
|
+
productId: primary.productId,
|
|
311
|
+
productTitle: primary.productTitle,
|
|
312
|
+
slots: outerSlots
|
|
313
|
+
};
|
|
314
|
+
if (hasMultipleProducts) {
|
|
315
|
+
row.products = subRows;
|
|
316
|
+
row.hasMultipleProducts = true;
|
|
317
|
+
}
|
|
318
|
+
if (isCombined && combined) {
|
|
319
|
+
row.combinedResource = { resourceIds: [...combined.resource_ids] };
|
|
320
|
+
}
|
|
321
|
+
resources.push(row);
|
|
183
322
|
}
|
|
184
323
|
const productOrder = /* @__PURE__ */ new Map();
|
|
185
324
|
for (const row of resources) {
|