@pisell/pisellos 0.0.493 → 0.0.495
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/modules/Cart/utils/cartProduct.js +1 -0
- package/dist/modules/Order/index.d.ts +5 -0
- package/dist/modules/Order/index.js +70 -5
- package/dist/modules/Order/utils.js +12 -2
- package/dist/modules/Product/index.d.ts +1 -1
- package/dist/modules/Quotation/index.d.ts +8 -0
- package/dist/modules/Quotation/index.js +46 -13
- package/dist/modules/Schedule/getDateIsInSchedule.js +11 -18
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/ScanOrder/utils.js +22 -3
- package/dist/solution/VenueBooking/index.d.ts +8 -9
- package/dist/solution/VenueBooking/index.js +614 -567
- package/dist/solution/VenueBooking/types.d.ts +7 -0
- package/dist/solution/VenueBooking/utils/slotMerge.d.ts +13 -2
- package/dist/solution/VenueBooking/utils/slotMerge.js +92 -15
- package/lib/modules/Cart/utils/cartProduct.js +1 -0
- package/lib/modules/Order/index.d.ts +5 -0
- package/lib/modules/Order/index.js +37 -1
- package/lib/modules/Order/utils.js +13 -0
- package/lib/modules/Product/index.d.ts +1 -1
- package/lib/modules/Quotation/index.d.ts +8 -0
- package/lib/modules/Quotation/index.js +27 -6
- package/lib/modules/Schedule/getDateIsInSchedule.js +9 -11
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/ScanOrder/utils.js +20 -3
- package/lib/solution/VenueBooking/index.d.ts +8 -9
- package/lib/solution/VenueBooking/index.js +82 -71
- package/lib/solution/VenueBooking/types.d.ts +7 -0
- package/lib/solution/VenueBooking/utils/slotMerge.d.ts +13 -2
- package/lib/solution/VenueBooking/utils/slotMerge.js +67 -13
- package/package.json +1 -1
|
@@ -92,6 +92,13 @@ export interface MergedSlotGroup {
|
|
|
92
92
|
slotCount: number;
|
|
93
93
|
slots: VenueSlotSelection[];
|
|
94
94
|
}
|
|
95
|
+
export interface PriceBreakdownEntry {
|
|
96
|
+
start_time: string;
|
|
97
|
+
end_time: string;
|
|
98
|
+
unit_price: number;
|
|
99
|
+
quotation_shelf_id: number;
|
|
100
|
+
quantity: number;
|
|
101
|
+
}
|
|
95
102
|
export interface VenueBookingState {
|
|
96
103
|
entryContext: VenueBookingEntryContext | null;
|
|
97
104
|
status: VenueBookingStatus;
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import type { VenueSlotSelection, MergedSlotGroup, ResourceProductMapping, VenueResourceRawData } from '../types';
|
|
1
|
+
import type { VenueSlotSelection, MergedSlotGroup, PriceBreakdownEntry, ResourceProductMapping, VenueResourceRawData } from '../types';
|
|
2
2
|
import type { ScanOrderOrderProduct } from '../../ScanOrder/types';
|
|
3
3
|
export declare function buildVenueIdentityKey(resourceId: number | string, groupIndex: number): string;
|
|
4
4
|
export declare function mergeConsecutiveSlots(slots: VenueSlotSelection[]): MergedSlotGroup[];
|
|
5
|
+
export declare function buildPriceBreakdown(params: {
|
|
6
|
+
group: MergedSlotGroup;
|
|
7
|
+
productId: number;
|
|
8
|
+
quotation?: {
|
|
9
|
+
getQuotationShelfId: (p: {
|
|
10
|
+
productId: number;
|
|
11
|
+
datetime: string;
|
|
12
|
+
}) => number;
|
|
13
|
+
};
|
|
14
|
+
}): PriceBreakdownEntry[];
|
|
5
15
|
export interface BuildVenueBookingParams {
|
|
6
16
|
group: MergedSlotGroup;
|
|
7
17
|
resourceId: number | string;
|
|
@@ -13,6 +23,7 @@ export interface BuildVenueBookingParams {
|
|
|
13
23
|
export declare function buildVenueBookingEntry(params: BuildVenueBookingParams): Record<string, any>;
|
|
14
24
|
/**
|
|
15
25
|
* 从一条已合并的订单商品还原出独立的时段列表。
|
|
16
|
-
*
|
|
26
|
+
* 优先使用 metadata.price_breakdown 还原每个时段的精确价格,
|
|
27
|
+
* 回退到按 selling_price / slot_count 均分。
|
|
17
28
|
*/
|
|
18
29
|
export declare function expandMergedSlotToIndividual(product: ScanOrderOrderProduct, slotDurationMinutes: number): VenueSlotSelection[];
|
|
@@ -1,3 +1,4 @@
|
|
|
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; } } }; }
|
|
1
2
|
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
2
3
|
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."); }
|
|
3
4
|
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); }
|
|
@@ -49,8 +50,47 @@ export function mergeConsecutiveSlots(slots) {
|
|
|
49
50
|
});
|
|
50
51
|
return groups;
|
|
51
52
|
}
|
|
53
|
+
export function buildPriceBreakdown(params) {
|
|
54
|
+
var group = params.group,
|
|
55
|
+
productId = params.productId,
|
|
56
|
+
quotation = params.quotation;
|
|
57
|
+
if (!group.slots.length) return [];
|
|
58
|
+
var entries = [];
|
|
59
|
+
var _iterator = _createForOfIteratorHelper(group.slots),
|
|
60
|
+
_step;
|
|
61
|
+
try {
|
|
62
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
63
|
+
var slot = _step.value;
|
|
64
|
+
var unitPrice = Number(slot.price || '0');
|
|
65
|
+
var shelfId = quotation ? quotation.getQuotationShelfId({
|
|
66
|
+
productId: productId,
|
|
67
|
+
datetime: slot.startTime
|
|
68
|
+
}) : 0;
|
|
69
|
+
var startHm = dayjs(slot.startTime, 'YYYY-MM-DD HH:mm').format('HH:mm');
|
|
70
|
+
var endHm = dayjs(slot.endTime, 'YYYY-MM-DD HH:mm').format('HH:mm');
|
|
71
|
+
var last = entries[entries.length - 1];
|
|
72
|
+
if (last && last.unit_price === unitPrice && last.quotation_shelf_id === shelfId && last.end_time === startHm) {
|
|
73
|
+
last.end_time = endHm;
|
|
74
|
+
last.quantity += 1;
|
|
75
|
+
} else {
|
|
76
|
+
entries.push({
|
|
77
|
+
start_time: startHm,
|
|
78
|
+
end_time: endHm,
|
|
79
|
+
unit_price: unitPrice,
|
|
80
|
+
quotation_shelf_id: shelfId,
|
|
81
|
+
quantity: 1
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} catch (err) {
|
|
86
|
+
_iterator.e(err);
|
|
87
|
+
} finally {
|
|
88
|
+
_iterator.f();
|
|
89
|
+
}
|
|
90
|
+
return entries;
|
|
91
|
+
}
|
|
52
92
|
export function buildVenueBookingEntry(params) {
|
|
53
|
-
var _rawResource$form_id
|
|
93
|
+
var _rawResource$form_id;
|
|
54
94
|
var group = params.group,
|
|
55
95
|
resourceId = params.resourceId,
|
|
56
96
|
mapping = params.mapping,
|
|
@@ -82,7 +122,7 @@ export function buildVenueBookingEntry(params) {
|
|
|
82
122
|
main_field: mapping.resourceName,
|
|
83
123
|
form_id: (_rawResource$form_id = rawResource === null || rawResource === void 0 ? void 0 : rawResource.form_id) !== null && _rawResource$form_id !== void 0 ? _rawResource$form_id : mapping.formId,
|
|
84
124
|
relation_id: resourceId,
|
|
85
|
-
capacity:
|
|
125
|
+
capacity: 1,
|
|
86
126
|
metadata: {}
|
|
87
127
|
}],
|
|
88
128
|
relation_products: [],
|
|
@@ -99,7 +139,8 @@ export function buildVenueBookingEntry(params) {
|
|
|
99
139
|
|
|
100
140
|
/**
|
|
101
141
|
* 从一条已合并的订单商品还原出独立的时段列表。
|
|
102
|
-
*
|
|
142
|
+
* 优先使用 metadata.price_breakdown 还原每个时段的精确价格,
|
|
143
|
+
* 回退到按 selling_price / slot_count 均分。
|
|
103
144
|
*/
|
|
104
145
|
export function expandMergedSlotToIndividual(product, slotDurationMinutes) {
|
|
105
146
|
var meta = product.metadata || {};
|
|
@@ -108,21 +149,57 @@ export function expandMergedSlotToIndividual(product, slotDurationMinutes) {
|
|
|
108
149
|
var startTime = meta.start_time;
|
|
109
150
|
var endTime = meta.end_time;
|
|
110
151
|
if (!startTime || !endTime) return [];
|
|
111
|
-
var
|
|
112
|
-
var
|
|
113
|
-
var perSlotPrice = slotCount > 0 ? totalPrice.div(slotCount).toFixed(2) : totalPrice.toFixed(2);
|
|
152
|
+
var breakdown = meta.price_breakdown;
|
|
153
|
+
var datePrefix = dayjs(startTime, 'YYYY-MM-DD HH:mm').format('YYYY-MM-DD');
|
|
114
154
|
var result = [];
|
|
115
155
|
var cursor = dayjs(startTime, 'YYYY-MM-DD HH:mm');
|
|
116
156
|
var end = dayjs(endTime, 'YYYY-MM-DD HH:mm');
|
|
117
|
-
|
|
118
|
-
var
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
157
|
+
if (breakdown !== null && breakdown !== void 0 && breakdown.length) {
|
|
158
|
+
var priceMap = new Map();
|
|
159
|
+
var _iterator2 = _createForOfIteratorHelper(breakdown),
|
|
160
|
+
_step2;
|
|
161
|
+
try {
|
|
162
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
163
|
+
var entry = _step2.value;
|
|
164
|
+
var entryCursor = dayjs("".concat(datePrefix, " ").concat(entry.start_time), 'YYYY-MM-DD HH:mm');
|
|
165
|
+
var entryEnd = dayjs("".concat(datePrefix, " ").concat(entry.end_time), 'YYYY-MM-DD HH:mm');
|
|
166
|
+
while (entryCursor.isBefore(entryEnd)) {
|
|
167
|
+
priceMap.set(entryCursor.format('HH:mm'), entry.unit_price);
|
|
168
|
+
entryCursor = entryCursor.add(slotDurationMinutes, 'minute');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
} catch (err) {
|
|
172
|
+
_iterator2.e(err);
|
|
173
|
+
} finally {
|
|
174
|
+
_iterator2.f();
|
|
175
|
+
}
|
|
176
|
+
while (cursor.isBefore(end)) {
|
|
177
|
+
var _priceMap$get;
|
|
178
|
+
var slotEnd = cursor.add(slotDurationMinutes, 'minute');
|
|
179
|
+
var hm = cursor.format('HH:mm');
|
|
180
|
+
var price = (_priceMap$get = priceMap.get(hm)) !== null && _priceMap$get !== void 0 ? _priceMap$get : 0;
|
|
181
|
+
result.push({
|
|
182
|
+
resourceId: resourceId,
|
|
183
|
+
startTime: cursor.format('YYYY-MM-DD HH:mm'),
|
|
184
|
+
endTime: slotEnd.format('YYYY-MM-DD HH:mm'),
|
|
185
|
+
price: new Decimal(price).toFixed(2)
|
|
186
|
+
});
|
|
187
|
+
cursor = slotEnd;
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
var slotCount = meta.slot_count || 1;
|
|
191
|
+
var totalPrice = new Decimal(product.selling_price || '0');
|
|
192
|
+
var perSlotPrice = slotCount > 0 ? totalPrice.div(slotCount).toFixed(2) : totalPrice.toFixed(2);
|
|
193
|
+
while (cursor.isBefore(end)) {
|
|
194
|
+
var _slotEnd = cursor.add(slotDurationMinutes, 'minute');
|
|
195
|
+
result.push({
|
|
196
|
+
resourceId: resourceId,
|
|
197
|
+
startTime: cursor.format('YYYY-MM-DD HH:mm'),
|
|
198
|
+
endTime: _slotEnd.format('YYYY-MM-DD HH:mm'),
|
|
199
|
+
price: perSlotPrice
|
|
200
|
+
});
|
|
201
|
+
cursor = _slotEnd;
|
|
202
|
+
}
|
|
126
203
|
}
|
|
127
204
|
return result;
|
|
128
205
|
}
|
|
@@ -341,6 +341,7 @@ var formatBundleToOrigin = (bundle) => {
|
|
|
341
341
|
option: formatOptionsToOrigin(getBundleValueByKey("option")),
|
|
342
342
|
discount_list: d.discount_list,
|
|
343
343
|
"bundle_selling_price": d == null ? void 0 : d.price,
|
|
344
|
+
"custom_price": d == null ? void 0 : d.price,
|
|
344
345
|
metadata: {
|
|
345
346
|
custom_product_bundle_map_id: d._id,
|
|
346
347
|
product_discount_difference
|
|
@@ -15,6 +15,11 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
15
15
|
private cacheId;
|
|
16
16
|
private salesSummaryModuleName;
|
|
17
17
|
private rulesHooksOverride?;
|
|
18
|
+
/**
|
|
19
|
+
* Populate `savedAmount` on each discount based on product-level discount details.
|
|
20
|
+
* Only selected discounts get a non-zero value.
|
|
21
|
+
*/
|
|
22
|
+
static populateSavedAmounts(productList: Array<Record<string, any>>, discountList: Array<Record<string, any>>): void;
|
|
18
23
|
constructor(name?: string, version?: string);
|
|
19
24
|
initialize(core: PisellCore, options: ModuleOptions): Promise<void>;
|
|
20
25
|
/**
|
|
@@ -47,6 +47,28 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
47
47
|
this.defaultName = "order";
|
|
48
48
|
this.defaultVersion = "1.0.0";
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Populate `savedAmount` on each discount based on product-level discount details.
|
|
52
|
+
* Only selected discounts get a non-zero value.
|
|
53
|
+
*/
|
|
54
|
+
static populateSavedAmounts(productList, discountList) {
|
|
55
|
+
var _a, _b;
|
|
56
|
+
const savedMap = /* @__PURE__ */ new Map();
|
|
57
|
+
for (const product of productList) {
|
|
58
|
+
const qty = product.num || 1;
|
|
59
|
+
for (const pd of product.discount_list || []) {
|
|
60
|
+
const discountKey = ((_a = pd.discount) == null ? void 0 : _a.resource_id) || pd.id;
|
|
61
|
+
if (discountKey == null)
|
|
62
|
+
continue;
|
|
63
|
+
const amount = new import_decimal.default(pd.amount || 0).times(qty).plus(((_b = pd.metadata) == null ? void 0 : _b.product_discount_difference) || 0);
|
|
64
|
+
savedMap.set(discountKey, (savedMap.get(discountKey) || new import_decimal.default(0)).plus(amount));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
for (const d of discountList) {
|
|
68
|
+
const key = d.id;
|
|
69
|
+
d.savedAmount = d.isSelected && key != null && savedMap.has(key) ? savedMap.get(key).toNumber() : 0;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
50
72
|
async initialize(core, options) {
|
|
51
73
|
var _a;
|
|
52
74
|
this.core = core;
|
|
@@ -151,7 +173,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
151
173
|
original_price: values.original_price !== void 0 ? String(values.original_price) : product.original_price,
|
|
152
174
|
discount_list: values.discount_list ?? product.discount_list,
|
|
153
175
|
num: values.quantity ?? product.num,
|
|
154
|
-
product_bundle: values.bundle ?? product.product_bundle
|
|
176
|
+
product_bundle: values.bundle ?? product.product_bundle,
|
|
177
|
+
metadata: {
|
|
178
|
+
...product.metadata || {},
|
|
179
|
+
...values.main_product_selling_price !== void 0 ? { main_product_selling_price: String(values.main_product_selling_price) } : {}
|
|
180
|
+
}
|
|
155
181
|
})
|
|
156
182
|
};
|
|
157
183
|
}
|
|
@@ -247,6 +273,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
247
273
|
tempOrder.products = result.productList;
|
|
248
274
|
}
|
|
249
275
|
if (result == null ? void 0 : result.discountList) {
|
|
276
|
+
OrderModule.populateSavedAmounts(result.productList || tempOrder.products, result.discountList);
|
|
250
277
|
(_f = this.store.discount) == null ? void 0 : _f.setDiscountList(result.discountList);
|
|
251
278
|
tempOrder.discount_list = result.discountList.filter((d) => d.isSelected);
|
|
252
279
|
}
|
|
@@ -425,9 +452,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
425
452
|
}
|
|
426
453
|
async removeProductFromOrder(identity) {
|
|
427
454
|
const tempOrder = this.ensureTempOrder();
|
|
455
|
+
const beforeProducts = tempOrder.products;
|
|
428
456
|
tempOrder.products = tempOrder.products.filter(
|
|
429
457
|
(item) => !(0, import_utils3.isIdentityMatch)(item, identity)
|
|
430
458
|
);
|
|
459
|
+
const removedByStrictIdentity = beforeProducts.length - tempOrder.products.length;
|
|
460
|
+
if (removedByStrictIdentity === 0 && identity.identity_key) {
|
|
461
|
+
tempOrder.products = tempOrder.products.filter((item) => {
|
|
462
|
+
const isSameProduct = String(item.product_id) === String(identity.product_id) && String(item.product_variant_id) === String(identity.product_variant_id);
|
|
463
|
+
const hasNoIdentityKey = !item.identity_key;
|
|
464
|
+
return !(isSameProduct && hasNoIdentityKey);
|
|
465
|
+
});
|
|
466
|
+
}
|
|
431
467
|
this.applyDiscount();
|
|
432
468
|
await this.recalculateSummary({ createIfMissing: true });
|
|
433
469
|
this.persistTempOrder();
|
|
@@ -110,6 +110,19 @@ function normalizeSubmitProduct(product) {
|
|
|
110
110
|
if (rawMetadata.unique_identification_number) {
|
|
111
111
|
cleanMetadata.unique_identification_number = rawMetadata.unique_identification_number;
|
|
112
112
|
}
|
|
113
|
+
const priceMetaKeys = [
|
|
114
|
+
"main_product_original_price",
|
|
115
|
+
"main_product_selling_price",
|
|
116
|
+
"source_product_price"
|
|
117
|
+
];
|
|
118
|
+
for (const key of priceMetaKeys) {
|
|
119
|
+
if (rawMetadata[key] !== void 0) {
|
|
120
|
+
cleanMetadata[key] = rawMetadata[key];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (rawMetadata.price_breakdown) {
|
|
124
|
+
cleanMetadata.price_breakdown = rawMetadata.price_breakdown;
|
|
125
|
+
}
|
|
113
126
|
return {
|
|
114
127
|
...submitProduct,
|
|
115
128
|
...bookingUid ? { booking_uid: bookingUid } : {},
|
|
@@ -49,5 +49,5 @@ export declare class Product extends BaseModule implements Module {
|
|
|
49
49
|
getCategories(): ProductCategory[];
|
|
50
50
|
setOtherParams(key: string, value: any): void;
|
|
51
51
|
getOtherParams(): any;
|
|
52
|
-
getProductType(): "
|
|
52
|
+
getProductType(): "normal" | "duration" | "session";
|
|
53
53
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Module, PisellCore, ModuleOptions } from '../../types';
|
|
2
2
|
import { BaseModule } from '../BaseModule';
|
|
3
|
+
import type { ScheduleItem } from '../Schedule/types';
|
|
3
4
|
import type { QuotationItem } from './types';
|
|
4
5
|
export type { QuotationItem, QuotationProductData, QuotationSchedule, QuotationState } from './types';
|
|
5
6
|
export declare class QuotationModule extends BaseModule implements Module {
|
|
@@ -7,6 +8,7 @@ export declare class QuotationModule extends BaseModule implements Module {
|
|
|
7
8
|
protected defaultVersion: string;
|
|
8
9
|
private request;
|
|
9
10
|
private store;
|
|
11
|
+
private scheduleResolver?;
|
|
10
12
|
constructor(name?: string, version?: string);
|
|
11
13
|
initialize(core: PisellCore, options: ModuleOptions): Promise<void>;
|
|
12
14
|
loadQuotations(params?: {
|
|
@@ -26,6 +28,11 @@ export declare class QuotationModule extends BaseModule implements Module {
|
|
|
26
28
|
variantId?: number;
|
|
27
29
|
datetime: string;
|
|
28
30
|
}): string | null;
|
|
31
|
+
getQuotationShelfId(params: {
|
|
32
|
+
productId: number;
|
|
33
|
+
variantId?: number;
|
|
34
|
+
datetime: string;
|
|
35
|
+
}): number;
|
|
29
36
|
/**
|
|
30
37
|
* Batch pre-compute quotation prices for a set of products across multiple time points.
|
|
31
38
|
* Key format: `${productId}:${timePoint}`
|
|
@@ -35,6 +42,7 @@ export declare class QuotationModule extends BaseModule implements Module {
|
|
|
35
42
|
productIds: number[];
|
|
36
43
|
timePoints: string[];
|
|
37
44
|
}): Map<string, string | null>;
|
|
45
|
+
setScheduleResolver(resolver: (id: number) => ScheduleItem | undefined): void;
|
|
38
46
|
private isQuotationActiveAt;
|
|
39
47
|
private findProductData;
|
|
40
48
|
}
|
|
@@ -77,6 +77,18 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
|
|
|
77
77
|
}
|
|
78
78
|
return null;
|
|
79
79
|
}
|
|
80
|
+
getQuotationShelfId(params) {
|
|
81
|
+
const { productId, variantId, datetime } = params;
|
|
82
|
+
for (const quotation of this.store.list) {
|
|
83
|
+
if (!this.isQuotationActiveAt(quotation, datetime))
|
|
84
|
+
continue;
|
|
85
|
+
const match = this.findProductData(quotation.product_data, productId, variantId);
|
|
86
|
+
if (!match || match.value === 0)
|
|
87
|
+
continue;
|
|
88
|
+
return quotation.id;
|
|
89
|
+
}
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
80
92
|
/**
|
|
81
93
|
* Batch pre-compute quotation prices for a set of products across multiple time points.
|
|
82
94
|
* Key format: `${productId}:${timePoint}`
|
|
@@ -97,16 +109,25 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
|
|
|
97
109
|
}
|
|
98
110
|
return map;
|
|
99
111
|
}
|
|
112
|
+
setScheduleResolver(resolver) {
|
|
113
|
+
this.scheduleResolver = resolver;
|
|
114
|
+
}
|
|
100
115
|
isQuotationActiveAt(quotation, datetime) {
|
|
101
116
|
var _a;
|
|
102
117
|
if (!((_a = quotation.schedule) == null ? void 0 : _a.length))
|
|
103
118
|
return false;
|
|
104
|
-
const scheduleItems = quotation.schedule.map((s) =>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
119
|
+
const scheduleItems = quotation.schedule.map((s) => {
|
|
120
|
+
var _a2;
|
|
121
|
+
const full = (_a2 = this.scheduleResolver) == null ? void 0 : _a2.call(this, s.id);
|
|
122
|
+
if (full)
|
|
123
|
+
return full;
|
|
124
|
+
return {
|
|
125
|
+
...s,
|
|
126
|
+
repeat_type: s.repeat_type || "none",
|
|
127
|
+
repeat_rule: s.repeat_rule || null,
|
|
128
|
+
time_slot: s.time_slot || []
|
|
129
|
+
};
|
|
130
|
+
});
|
|
110
131
|
return (0, import_getDateIsInSchedule.getDateIsInSchedule)(datetime, scheduleItems);
|
|
111
132
|
}
|
|
112
133
|
findProductData(productData, productId, variantId) {
|
|
@@ -70,7 +70,7 @@ var isInStandardSchedule = (targetDate, targetDateString, targetTimeString, sche
|
|
|
70
70
|
}
|
|
71
71
|
const startDate = (0, import_dayjs.default)(schedule.start_time);
|
|
72
72
|
const endDate = (0, import_dayjs.default)(schedule.end_time);
|
|
73
|
-
const isInBasicRange = targetDate.isSameOrAfter(startDate) && targetDate.
|
|
73
|
+
const isInBasicRange = targetDate.isSameOrAfter(startDate) && targetDate.isBefore(endDate);
|
|
74
74
|
if (schedule.repeat_type === "none") {
|
|
75
75
|
return isInBasicRange;
|
|
76
76
|
}
|
|
@@ -80,16 +80,14 @@ var isInTimeSlotsSchedule = (targetDate, targetDateString, targetTimeString, sch
|
|
|
80
80
|
if (!schedule.start_time) {
|
|
81
81
|
return false;
|
|
82
82
|
}
|
|
83
|
-
const
|
|
84
|
-
if (
|
|
83
|
+
const scheduleStartDate = (0, import_dayjs.default)(schedule.start_time.split(" ")[0]);
|
|
84
|
+
if (!isDateInTimeSlotsSchedule(targetDate, schedule, scheduleStartDate)) {
|
|
85
85
|
return false;
|
|
86
86
|
}
|
|
87
87
|
for (const timeSlot of schedule.time_slot) {
|
|
88
|
-
const slotStart = `${
|
|
89
|
-
const slotEnd = `${
|
|
90
|
-
|
|
91
|
-
const slotEndDate = (0, import_dayjs.default)(slotEnd);
|
|
92
|
-
if (targetDate.isSameOrAfter(slotStartDate) && targetDate.isSameOrBefore(slotEndDate)) {
|
|
88
|
+
const slotStart = (0, import_dayjs.default)(`${targetDateString} ${timeSlot.start_time}:00`);
|
|
89
|
+
const slotEnd = (0, import_dayjs.default)(`${targetDateString} ${timeSlot.end_time}:00`);
|
|
90
|
+
if (targetDate.isSameOrAfter(slotStart) && targetDate.isBefore(slotEnd)) {
|
|
93
91
|
return true;
|
|
94
92
|
}
|
|
95
93
|
}
|
|
@@ -104,7 +102,7 @@ var isInDesignationSchedule = (targetDate, targetDateString, targetTimeString, s
|
|
|
104
102
|
const endDateTime = `${designation.end_date} ${designation.end_time}:00`;
|
|
105
103
|
const startDate = (0, import_dayjs.default)(startDateTime);
|
|
106
104
|
const endDate = (0, import_dayjs.default)(endDateTime);
|
|
107
|
-
if (targetDate.isSameOrAfter(startDate) && targetDate.
|
|
105
|
+
if (targetDate.isSameOrAfter(startDate) && targetDate.isBefore(endDate)) {
|
|
108
106
|
return true;
|
|
109
107
|
}
|
|
110
108
|
}
|
|
@@ -158,7 +156,7 @@ var isInDailyRepeat = (targetDate, startDate, endDate, repeatRule) => {
|
|
|
158
156
|
const targetTimeOfDay = targetDate.hour() * 3600 + targetDate.minute() * 60 + targetDate.second();
|
|
159
157
|
const startTimeOfDay = startDate.hour() * 3600 + startDate.minute() * 60 + startDate.second();
|
|
160
158
|
const endTimeOfDay = endDate.hour() * 3600 + endDate.minute() * 60 + endDate.second();
|
|
161
|
-
return targetTimeOfDay >= startTimeOfDay && targetTimeOfDay
|
|
159
|
+
return targetTimeOfDay >= startTimeOfDay && targetTimeOfDay < endTimeOfDay;
|
|
162
160
|
};
|
|
163
161
|
var isInWeeklyRepeat = (targetDate, startDate, endDate, repeatRule) => {
|
|
164
162
|
const targetDayOfWeek = targetDate.day();
|
|
@@ -175,7 +173,7 @@ var isInWeeklyRepeat = (targetDate, startDate, endDate, repeatRule) => {
|
|
|
175
173
|
const targetTimeOfDay = targetDate.hour() * 3600 + targetDate.minute() * 60 + targetDate.second();
|
|
176
174
|
const startTimeOfDay = startDate.hour() * 3600 + startDate.minute() * 60 + startDate.second();
|
|
177
175
|
const endTimeOfDay = endDate.hour() * 3600 + endDate.minute() * 60 + endDate.second();
|
|
178
|
-
return targetTimeOfDay >= startTimeOfDay && targetTimeOfDay
|
|
176
|
+
return targetTimeOfDay >= startTimeOfDay && targetTimeOfDay < endTimeOfDay;
|
|
179
177
|
};
|
|
180
178
|
var getScheduleStartEndTimePoints = (date, scheduleList) => {
|
|
181
179
|
if (!date || !scheduleList || scheduleList.length === 0) {
|
|
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
311
311
|
date: string;
|
|
312
312
|
status: string;
|
|
313
313
|
week: string;
|
|
314
|
-
weekNum: 0 |
|
|
314
|
+
weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
315
315
|
}[]>;
|
|
316
316
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
317
317
|
private getScheduleDataByIds;
|
|
@@ -358,7 +358,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
358
358
|
};
|
|
359
359
|
setOtherData(key: string, value: any): void;
|
|
360
360
|
getOtherData(key: string): any;
|
|
361
|
-
getProductTypeById(id: number): Promise<"
|
|
361
|
+
getProductTypeById(id: number): Promise<"normal" | "duration" | "session">;
|
|
362
362
|
/**
|
|
363
363
|
* 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
|
|
364
364
|
*
|
|
@@ -294,10 +294,27 @@ function getProductIdentityIndex(products, identity) {
|
|
|
294
294
|
return products.findIndex((item) => isIdentityMatch(item, identity));
|
|
295
295
|
}
|
|
296
296
|
function normalizeOrderProduct(product) {
|
|
297
|
+
var _a;
|
|
297
298
|
const metadata = { ...product.metadata || {} };
|
|
298
299
|
if (product.identity_key && !metadata.unique_identification_number) {
|
|
299
300
|
metadata.unique_identification_number = product.identity_key;
|
|
300
301
|
}
|
|
302
|
+
const resolvedOriginalPrice = product.original_price || "0.00";
|
|
303
|
+
const resolvedSellingPrice = product.selling_price || "0.00";
|
|
304
|
+
if (metadata.main_product_original_price === void 0) {
|
|
305
|
+
metadata.main_product_original_price = resolvedOriginalPrice;
|
|
306
|
+
}
|
|
307
|
+
if (metadata.main_product_selling_price === void 0) {
|
|
308
|
+
metadata.main_product_selling_price = resolvedSellingPrice;
|
|
309
|
+
}
|
|
310
|
+
if (metadata.source_product_price === void 0) {
|
|
311
|
+
metadata.source_product_price = ((_a = product._origin) == null ? void 0 : _a.original_price) ?? resolvedOriginalPrice;
|
|
312
|
+
}
|
|
313
|
+
const normalizedBundle = (product.product_bundle || []).map((item) => ({
|
|
314
|
+
...item,
|
|
315
|
+
bundle_selling_price: item.bundle_selling_price ?? item.price ?? "0.00",
|
|
316
|
+
custom_price: item.custom_price ?? item.bundle_selling_price ?? item.price ?? "0.00"
|
|
317
|
+
}));
|
|
301
318
|
return {
|
|
302
319
|
order_detail_id: product.order_detail_id || null,
|
|
303
320
|
product_id: product.product_id,
|
|
@@ -305,13 +322,13 @@ function normalizeOrderProduct(product) {
|
|
|
305
322
|
product_variant_id: product.product_variant_id,
|
|
306
323
|
identity_key: product.identity_key,
|
|
307
324
|
product_option_item: product.product_option_item || [],
|
|
308
|
-
selling_price:
|
|
309
|
-
original_price:
|
|
325
|
+
selling_price: resolvedSellingPrice,
|
|
326
|
+
original_price: resolvedOriginalPrice,
|
|
310
327
|
payment_price: product.payment_price || "0.00",
|
|
311
328
|
tax_fee: product.tax_fee || "0.00",
|
|
312
329
|
is_charge_tax: product.is_charge_tax ?? 0,
|
|
313
330
|
discount_list: product.discount_list || [],
|
|
314
|
-
product_bundle:
|
|
331
|
+
product_bundle: normalizedBundle,
|
|
315
332
|
metadata,
|
|
316
333
|
_origin: product._origin
|
|
317
334
|
};
|
|
@@ -60,14 +60,12 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
60
60
|
passed: boolean | null;
|
|
61
61
|
failures: QuantityCheckResult[];
|
|
62
62
|
};
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
collectionIds?: number[];
|
|
70
|
-
}): Promise<ProductData[]>;
|
|
63
|
+
loadAllProducts(): Promise<{
|
|
64
|
+
venueProducts: ProductData[];
|
|
65
|
+
addonProducts: ProductData[];
|
|
66
|
+
}>;
|
|
67
|
+
loadVenueProducts(): Promise<ProductData[]>;
|
|
68
|
+
loadAddonProducts(): Promise<ProductData[]>;
|
|
71
69
|
getVenueProducts(): ProductData[];
|
|
72
70
|
getAddonProductsList(): ProductData[];
|
|
73
71
|
loadQuotations(params?: {
|
|
@@ -107,6 +105,7 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
107
105
|
setSlotConfig(config: Partial<VenueBookingSlotConfig>): void;
|
|
108
106
|
getSlotConfig(): VenueBookingSlotConfig;
|
|
109
107
|
loadSchedules(): Promise<void>;
|
|
108
|
+
private injectScheduleResolverToQuotation;
|
|
110
109
|
getScheduleListByIds(ids: number[]): import("../../server").ScheduleItem[];
|
|
111
110
|
getTempOrder(): import("./types").ScanOrderTempOrder | null;
|
|
112
111
|
updateTempOrderNote(note: string): string;
|
|
@@ -140,7 +139,7 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
140
139
|
updates: Partial<ScanOrderOrderProduct>;
|
|
141
140
|
}): Promise<ScanOrderOrderProduct[]>;
|
|
142
141
|
removeProductFromOrder(identity: ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
|
|
143
|
-
getProductList(): Promise<
|
|
142
|
+
getProductList(): Promise<ProductData[]>;
|
|
144
143
|
private loadOpenDataConfig;
|
|
145
144
|
private loadRuntimeConfigs;
|
|
146
145
|
private fetchItemRuleConfigsByModelIds;
|