@pisell/pisellos 2.3.94 → 2.3.96
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/dataVariant/evaluator.js +13 -2
- package/dist/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
- package/dist/model/strategy/adapter/itemRule/adapter.js +135 -35
- package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
- package/dist/model/strategy/adapter/itemRule/evaluator.js +25 -1
- package/dist/model/strategy/adapter/itemRule/type.d.ts +44 -0
- package/dist/model/strategy/adapter/itemRule/type.js +19 -1
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/modules/Order/index.d.ts +20 -3
- package/dist/modules/Order/index.js +931 -508
- package/dist/modules/Order/salesNotes.d.ts +31 -0
- package/dist/modules/Order/salesNotes.js +492 -0
- package/dist/modules/Order/types.d.ts +91 -5
- package/dist/modules/Order/types.js +5 -0
- package/dist/modules/Order/utils.d.ts +12 -0
- package/dist/modules/Order/utils.js +75 -26
- package/dist/modules/ProductList/index.d.ts +2 -1
- package/dist/modules/ProductList/index.js +100 -20
- package/dist/modules/ProductList/types.d.ts +10 -0
- package/dist/modules/SalesSummary/index.js +6 -4
- package/dist/server/index.d.ts +6 -0
- package/dist/server/index.js +57 -11
- package/dist/server/modules/products/index.d.ts +2 -2
- package/dist/server/modules/products/index.js +10 -9
- package/dist/server/utils/product.d.ts +1 -1
- package/dist/server/utils/product.js +186 -22
- package/dist/server/utils/small-ticket.js +23 -2
- package/dist/solution/BaseSales/index.d.ts +9 -1
- package/dist/solution/BaseSales/index.js +894 -706
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +3 -2
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
- package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
- package/dist/solution/RegisterAndLogin/config.js +95 -40
- package/dist/solution/RegisterAndLogin/index.js +4 -1
- package/dist/solution/ScanOrder/index.d.ts +1 -0
- package/dist/solution/ScanOrder/index.js +31 -27
- package/dist/solution/ScanOrder/utils.d.ts +1 -0
- package/dist/solution/ScanOrder/utils.js +2 -0
- package/dist/solution/UnifiedBookingSales/index.d.ts +15 -2
- package/dist/solution/UnifiedBookingSales/index.js +751 -483
- package/dist/solution/UnifiedBookingSales/types.d.ts +14 -1
- package/dist/solution/VenueBooking/index.d.ts +1 -0
- package/dist/solution/VenueBooking/index.js +8 -4
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +12 -2
- package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
- package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
- package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
- package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
- package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
- package/lib/model/strategy/adapter/itemRule/type.js +19 -1
- package/lib/modules/Order/index.d.ts +20 -3
- package/lib/modules/Order/index.js +358 -42
- package/lib/modules/Order/salesNotes.d.ts +31 -0
- package/lib/modules/Order/salesNotes.js +382 -0
- package/lib/modules/Order/types.d.ts +91 -5
- package/lib/modules/Order/types.js +4 -0
- package/lib/modules/Order/utils.d.ts +12 -0
- package/lib/modules/Order/utils.js +68 -16
- package/lib/modules/ProductList/index.d.ts +2 -1
- package/lib/modules/ProductList/index.js +47 -2
- package/lib/modules/ProductList/types.d.ts +10 -0
- package/lib/modules/SalesSummary/index.js +3 -1
- package/lib/server/index.d.ts +6 -0
- package/lib/server/index.js +47 -9
- package/lib/server/modules/products/index.d.ts +2 -2
- package/lib/server/modules/products/index.js +5 -4
- package/lib/server/utils/product.d.ts +1 -1
- package/lib/server/utils/product.js +163 -3
- package/lib/server/utils/small-ticket.js +22 -1
- package/lib/solution/BaseSales/index.d.ts +9 -1
- package/lib/solution/BaseSales/index.js +105 -1
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +3 -2
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
- package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
- package/lib/solution/RegisterAndLogin/config.js +49 -8
- package/lib/solution/RegisterAndLogin/index.js +4 -1
- package/lib/solution/ScanOrder/index.d.ts +1 -0
- package/lib/solution/ScanOrder/index.js +5 -1
- package/lib/solution/ScanOrder/utils.d.ts +1 -0
- package/lib/solution/ScanOrder/utils.js +1 -0
- package/lib/solution/UnifiedBookingSales/index.d.ts +15 -2
- package/lib/solution/UnifiedBookingSales/index.js +125 -1
- package/lib/solution/UnifiedBookingSales/types.d.ts +14 -1
- package/lib/solution/VenueBooking/index.d.ts +1 -0
- package/lib/solution/VenueBooking/index.js +5 -1
- package/package.json +1 -1
|
@@ -32,6 +32,7 @@ const LABELS = {
|
|
|
32
32
|
orderDiscount: 'Order discount',
|
|
33
33
|
manualDiscount: 'Manual discount',
|
|
34
34
|
payProcessingFee: 'Pay processing fee',
|
|
35
|
+
surchargeIncluded: 'Surcharge(Included)',
|
|
35
36
|
rounding: 'Rounding',
|
|
36
37
|
gross: 'Gross',
|
|
37
38
|
tare: 'Tare'
|
|
@@ -58,6 +59,7 @@ const LABELS = {
|
|
|
58
59
|
orderDiscount: '整单折扣',
|
|
59
60
|
manualDiscount: '手动折扣',
|
|
60
61
|
payProcessingFee: '支付手续费',
|
|
62
|
+
surchargeIncluded: '手续费(已含)',
|
|
61
63
|
rounding: '抹零',
|
|
62
64
|
gross: '重量',
|
|
63
65
|
tare: '去皮'
|
|
@@ -84,6 +86,7 @@ const LABELS = {
|
|
|
84
86
|
orderDiscount: '整單折扣',
|
|
85
87
|
manualDiscount: '手動折扣',
|
|
86
88
|
payProcessingFee: '支付手續費',
|
|
89
|
+
surchargeIncluded: '手續費(已含)',
|
|
87
90
|
rounding: '抹零',
|
|
88
91
|
gross: '重量',
|
|
89
92
|
tare: '去皮'
|
|
@@ -730,10 +733,17 @@ function buildResources(order, locale) {
|
|
|
730
733
|
function buildPaymentData(params) {
|
|
731
734
|
const payments = normalizeArray(params.order.payments);
|
|
732
735
|
return payments.filter(payment => isPrintablePayment(payment)).map(payment => {
|
|
736
|
+
const serviceFee = getPaymentServiceFee(payment);
|
|
733
737
|
const items = [{
|
|
734
738
|
item: paymentMethodName(payment, params.locale),
|
|
735
|
-
value: formatMoney(payment
|
|
739
|
+
value: formatMoney(resolveReceiptPaymentAmount(payment, serviceFee), params.currencySymbol)
|
|
736
740
|
}];
|
|
741
|
+
if (serviceFee.gt(0)) {
|
|
742
|
+
items.push({
|
|
743
|
+
item: label(params.locale, 'surchargeIncluded'),
|
|
744
|
+
value: formatMoney(serviceFee, params.currencySymbol)
|
|
745
|
+
});
|
|
746
|
+
}
|
|
737
747
|
const fundRecord = getFundRecord(payment);
|
|
738
748
|
if (fundRecord) {
|
|
739
749
|
items.push(...buildFundRecordPaymentItems({
|
|
@@ -758,6 +768,17 @@ function buildPaymentData(params) {
|
|
|
758
768
|
return items;
|
|
759
769
|
});
|
|
760
770
|
}
|
|
771
|
+
function getPaymentServiceFee(payment) {
|
|
772
|
+
return new _decimal.default(toMoneyNumber(payment.service_fee));
|
|
773
|
+
}
|
|
774
|
+
function resolveReceiptPaymentAmount(payment, serviceFee) {
|
|
775
|
+
const amount = new _decimal.default(toMoneyNumber(payment.amount ?? payment.origin_amount));
|
|
776
|
+
const hasAmount = payment.amount !== undefined && payment.amount !== null && payment.amount !== '';
|
|
777
|
+
const hasOriginAmount = payment.origin_amount !== undefined && payment.origin_amount !== null && payment.origin_amount !== '';
|
|
778
|
+
if (!hasAmount || !hasOriginAmount || serviceFee.lte(0)) return amount;
|
|
779
|
+
const originAmount = new _decimal.default(toMoneyNumber(payment.origin_amount));
|
|
780
|
+
return amount.eq(originAmount) ? amount.plus(serviceFee) : amount;
|
|
781
|
+
}
|
|
761
782
|
function buildFundRecordPaymentItems(params) {
|
|
762
783
|
const {
|
|
763
784
|
payment,
|
|
@@ -2,7 +2,7 @@ import { Module, ModuleOptions, PisellCore } from '../../types';
|
|
|
2
2
|
import { BaseModule } from '../../modules/BaseModule';
|
|
3
3
|
import { BaseSalesOrderProduct, BaseSalesOrderProductIdentity, BaseSalesPaymentStatus, BaseSalesUpdateOrderProductQuantityParams, BaseSalesCalculateProductBookingPriceParams, BaseSalesPriceRecalculationContextChange, BaseSalesProductBookingPriceResult, BaseSalesQuotationCustomerScopeInfo, BaseSalesScanCodeResult, BaseSalesCashPaymentConfig, BaseSalesPayCashParams, BaseSalesPayCashResult, BaseSalesCommitPaymentMethodParams, BaseSalesCommitPaymentMethodResult, BaseSalesConfirmWalletPaymentResult } from './types';
|
|
4
4
|
import { OrderModule } from '../../modules/Order';
|
|
5
|
-
import type { AddProductBookingInput, AddProductToOrderOptions, LoadSalesDetailParams, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder, OrderSummary, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, ReplaceTempOrderOptions } from '../../modules/Order/types';
|
|
5
|
+
import type { AddProductBookingInput, AddProductToOrderOptions, LoadSalesDetailParams, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder, OrderSummary, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, ReplaceTempOrderOptions, SalesNote, SalesNotesMutationSnapshot, SetSalesNoteInput, PickupReferenceMode, ShopServiceData, ShopServiceType } from '../../modules/Order/types';
|
|
6
6
|
import type { SubmitPayloadEnhancer } from '../../modules/Order/utils';
|
|
7
7
|
import type { Discount } from '../../modules/Discount/types';
|
|
8
8
|
import { RequestPlugin, WindowPlugin } from '../../plugins';
|
|
@@ -225,12 +225,20 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
225
225
|
getOrderSyncState(): import("../../modules/Order/types").OrderSyncState;
|
|
226
226
|
getOrderAmountSnapshot(): import("../../modules/Order/types").OrderAmountSnapshot | null;
|
|
227
227
|
getTempOrderNote(): string;
|
|
228
|
+
getSalesNotes(): SalesNote[];
|
|
229
|
+
createSalesNotesMutationSnapshot(): SalesNotesMutationSnapshot;
|
|
230
|
+
restoreSalesNotesMutationSnapshot(snapshot: SalesNotesMutationSnapshot): void;
|
|
231
|
+
setSalesNote(input: SetSalesNoteInput): Promise<SalesNote>;
|
|
232
|
+
removeSalesNote(uuid: string): Promise<void>;
|
|
233
|
+
clearSalesNotes(): Promise<void>;
|
|
228
234
|
updateTempOrderNote(note: string): string;
|
|
229
235
|
updateTempOrderNote(note: string, sync: true): Promise<string>;
|
|
230
236
|
updateTempOrderNote(note: string, sync: boolean): string | Promise<string>;
|
|
231
237
|
updateRemoteOrderNote(orderId: number | string, note: string): void;
|
|
232
238
|
updateTempOrderShopDiscount(amount: string | number): string;
|
|
233
239
|
updateTempOrderDepositAmount(amount: string | number): OrderSummary;
|
|
240
|
+
setPickupReferenceMode(mode: PickupReferenceMode): ShopServiceData;
|
|
241
|
+
setServiceType(serviceType: ShopServiceType): ShopServiceData;
|
|
234
242
|
updateTempOrderContactsInfo(contactsInfo: Record<string, any> | null): Record<string, any> | null;
|
|
235
243
|
/** @deprecated OrderModule 不再负责 tempOrder localStorage 持久化。 */
|
|
236
244
|
setEnableTempOrderPersist(enabled: boolean): void;
|
|
@@ -283,7 +283,56 @@ function mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey) {
|
|
|
283
283
|
loadedValue.forEach(appendOrReplaceByUid);
|
|
284
284
|
return result;
|
|
285
285
|
}
|
|
286
|
+
|
|
287
|
+
// checkout / realtime snapshots may reorder protocol arrays or append persistence fields.
|
|
288
|
+
// Compare only the Sales Note protocol fields so a matching remote echo can acknowledge dirty state.
|
|
289
|
+
function normalizeBaseSalesNotesForComparison(value, options) {
|
|
290
|
+
if (!Array.isArray(value)) return null;
|
|
291
|
+
const unresolvedOrderTargetUuid = String(options?.unresolvedOrderTargetUuid ?? '').trim();
|
|
292
|
+
return value.map(note => {
|
|
293
|
+
if (!note || typeof note !== 'object' || Array.isArray(note)) {
|
|
294
|
+
return (0, _lodashEs.cloneDeep)(note);
|
|
295
|
+
}
|
|
296
|
+
const noteRecord = note;
|
|
297
|
+
const relations = Array.isArray(noteRecord.note_relations) ? noteRecord.note_relations.map(relation => {
|
|
298
|
+
if (!relation || typeof relation !== 'object' || Array.isArray(relation)) {
|
|
299
|
+
return (0, _lodashEs.cloneDeep)(relation);
|
|
300
|
+
}
|
|
301
|
+
const shouldResolveOrderTarget = relation.is_primary === 0 && relation.relation_type === 'related_to' && relation.target_type === 'order' && String(relation.target_uuid ?? '').trim() === '' && unresolvedOrderTargetUuid.length > 0;
|
|
302
|
+
return {
|
|
303
|
+
uuid: relation.uuid,
|
|
304
|
+
relation_type: relation.relation_type,
|
|
305
|
+
target_type: relation.target_type,
|
|
306
|
+
target_uuid: shouldResolveOrderTarget ? unresolvedOrderTargetUuid : relation.target_uuid,
|
|
307
|
+
is_primary: relation.is_primary
|
|
308
|
+
};
|
|
309
|
+
}).sort((left, right) => String(left?.uuid ?? '').localeCompare(String(right?.uuid ?? ''))) : (0, _lodashEs.cloneDeep)(noteRecord.note_relations);
|
|
310
|
+
return {
|
|
311
|
+
uuid: noteRecord.uuid,
|
|
312
|
+
note_type: noteRecord.note_type,
|
|
313
|
+
content: {
|
|
314
|
+
text: (0, _lodashEs.cloneDeep)(noteRecord.content?.text)
|
|
315
|
+
},
|
|
316
|
+
importance: noteRecord.importance,
|
|
317
|
+
note_relations: relations
|
|
318
|
+
};
|
|
319
|
+
}).sort((left, right) => String(left?.uuid ?? '').localeCompare(String(right?.uuid ?? '')));
|
|
320
|
+
}
|
|
321
|
+
function areBaseSalesNotesEquivalent(currentValue, loadedValue, options) {
|
|
322
|
+
const currentNotes = normalizeBaseSalesNotesForComparison(currentValue, {
|
|
323
|
+
unresolvedOrderTargetUuid: options?.currentOrderTargetUuid
|
|
324
|
+
});
|
|
325
|
+
const loadedNotes = normalizeBaseSalesNotesForComparison(loadedValue);
|
|
326
|
+
return currentNotes !== null && loadedNotes !== null && (0, _lodashEs.isEqual)(currentNotes, loadedNotes);
|
|
327
|
+
}
|
|
286
328
|
function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, strategy) {
|
|
329
|
+
const loadedHasSalesNotes = Object.prototype.hasOwnProperty.call(loadedRecord || {}, 'notes');
|
|
330
|
+
const hasDirtyLocalSalesNotes = currentTempOrder?._extend?.salesNotesState?.dirty === true;
|
|
331
|
+
const incomingSalesNotesMatchLocal = loadedHasSalesNotes && areBaseSalesNotesEquivalent(currentTempOrder?.notes, loadedRecord.notes, {
|
|
332
|
+
currentOrderTargetUuid: loadedRecord?.shop_order_number || currentTempOrder?.shop_order_number
|
|
333
|
+
});
|
|
334
|
+
const shouldAwaitAuthoritativeSalesNotes = strategy === 'authoritative-incoming' && hasDirtyLocalSalesNotes && (Number(loadedRecord?.need_sync) === 1 || !incomingSalesNotesMatchLocal);
|
|
335
|
+
const preserveDirtyLocalSalesNotes = hasDirtyLocalSalesNotes && (strategy === 'preserve-local' || shouldAwaitAuthoritativeSalesNotes);
|
|
287
336
|
const normalizedLoadedRecord = normalizeBaseSalesRecordCollections(loadedRecord || {}, {
|
|
288
337
|
ensureUid: false
|
|
289
338
|
});
|
|
@@ -295,6 +344,12 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, str
|
|
|
295
344
|
});
|
|
296
345
|
const uidRemaps = [];
|
|
297
346
|
const mergedRecord = (0, _lodashEs.mergeWith)(normalizedCurrentTempOrder, normalizedLoadedRecord, (currentValue, loadedValue, key) => {
|
|
347
|
+
if (key === 'notes') {
|
|
348
|
+
if (preserveDirtyLocalSalesNotes && Array.isArray(currentValue)) {
|
|
349
|
+
return (0, _lodashEs.cloneDeep)(currentValue);
|
|
350
|
+
}
|
|
351
|
+
if (Array.isArray(loadedValue)) return (0, _lodashEs.cloneDeep)(loadedValue);
|
|
352
|
+
}
|
|
298
353
|
const collectionKind = getBaseSalesOrderCollectionKind(key);
|
|
299
354
|
if (collectionKind && Array.isArray(loadedValue)) {
|
|
300
355
|
return mergeBaseSalesOrderCollection(collectionKind, Array.isArray(currentValue) ? currentValue : [], loadedValue, strategy, uidRemaps);
|
|
@@ -318,7 +373,24 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, str
|
|
|
318
373
|
return undefined;
|
|
319
374
|
});
|
|
320
375
|
delete mergedRecord.request_unique_idempotency_token;
|
|
321
|
-
|
|
376
|
+
const normalizedMergedRecord = normalizeBaseSalesRecordCollections((0, _orderCollectionIdentity.applyOrderCollectionUidRemaps)(mergedRecord, uidRemaps));
|
|
377
|
+
normalizedMergedRecord._extend = {
|
|
378
|
+
...(normalizedMergedRecord._extend || {}),
|
|
379
|
+
salesNotesState: preserveDirtyLocalSalesNotes ? {
|
|
380
|
+
loaded: true,
|
|
381
|
+
dirty: true
|
|
382
|
+
} : loadedHasSalesNotes ? {
|
|
383
|
+
loaded: true,
|
|
384
|
+
dirty: normalizedLoadedRecord._extend?.salesNotesState?.dirty === true
|
|
385
|
+
} : {
|
|
386
|
+
loaded: false,
|
|
387
|
+
dirty: false
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
if (!loadedHasSalesNotes && !preserveDirtyLocalSalesNotes) {
|
|
391
|
+
delete normalizedMergedRecord.notes;
|
|
392
|
+
}
|
|
393
|
+
return normalizedMergedRecord;
|
|
322
394
|
}
|
|
323
395
|
function filterPendingPaymentsFromLoadedSalesDetail(sourceRecord) {
|
|
324
396
|
if (!sourceRecord || typeof sourceRecord !== 'object') return sourceRecord;
|
|
@@ -1426,6 +1498,30 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1426
1498
|
if (!this.store.order) return '';
|
|
1427
1499
|
return this.store.order.getTempOrderNote();
|
|
1428
1500
|
}
|
|
1501
|
+
getSalesNotes() {
|
|
1502
|
+
if (!this.store.order) return [];
|
|
1503
|
+
return this.store.order.getSalesNotes();
|
|
1504
|
+
}
|
|
1505
|
+
createSalesNotesMutationSnapshot() {
|
|
1506
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1507
|
+
return this.store.order.createSalesNotesMutationSnapshot();
|
|
1508
|
+
}
|
|
1509
|
+
restoreSalesNotesMutationSnapshot(snapshot) {
|
|
1510
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1511
|
+
this.store.order.restoreSalesNotesMutationSnapshot(snapshot);
|
|
1512
|
+
}
|
|
1513
|
+
async setSalesNote(input) {
|
|
1514
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1515
|
+
return this.store.order.setSalesNote(input);
|
|
1516
|
+
}
|
|
1517
|
+
async removeSalesNote(uuid) {
|
|
1518
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1519
|
+
await this.store.order.removeSalesNote(uuid);
|
|
1520
|
+
}
|
|
1521
|
+
async clearSalesNotes() {
|
|
1522
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1523
|
+
await this.store.order.clearSalesNotes();
|
|
1524
|
+
}
|
|
1429
1525
|
updateTempOrderNote(note, sync = false) {
|
|
1430
1526
|
try {
|
|
1431
1527
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
@@ -1447,6 +1543,14 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1447
1543
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1448
1544
|
return this.store.order.updateTempOrderDepositAmount(amount);
|
|
1449
1545
|
}
|
|
1546
|
+
setPickupReferenceMode(mode) {
|
|
1547
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1548
|
+
return this.store.order.updateTempOrderPickupReferenceMode(mode);
|
|
1549
|
+
}
|
|
1550
|
+
setServiceType(serviceType) {
|
|
1551
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1552
|
+
return this.store.order.updateTempOrderServiceType(serviceType);
|
|
1553
|
+
}
|
|
1450
1554
|
updateTempOrderContactsInfo(contactsInfo) {
|
|
1451
1555
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1452
1556
|
return this.store.order.updateTempOrderContactsInfo(contactsInfo);
|
|
@@ -191,9 +191,10 @@ function transformBaseProductToOrderProduct(params) {
|
|
|
191
191
|
metadata.unique_identification_number = String(uniqueIdentificationNumber);
|
|
192
192
|
}
|
|
193
193
|
// 从源头补充商品多语言标题
|
|
194
|
+
const productTitleI18n = sourceProduct?.title_i18n || {};
|
|
194
195
|
const productTitle = {
|
|
195
|
-
...
|
|
196
|
-
original: sourceProduct?.original_title || sourceProduct?.title || ''
|
|
196
|
+
...productTitleI18n,
|
|
197
|
+
original: productTitleI18n.original || sourceProduct?.original_title || sourceProduct?.title || ''
|
|
197
198
|
};
|
|
198
199
|
return {
|
|
199
200
|
product_id: productId,
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 |
|
|
329
|
+
weekNum: 0 | 2 | 1 | 3 | 4 | 5 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -345,7 +345,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
345
345
|
count: number;
|
|
346
346
|
left: number;
|
|
347
347
|
summaryCount: number;
|
|
348
|
-
status: "
|
|
348
|
+
status: "lots_of_space" | "filling_up_fast" | "sold_out";
|
|
349
349
|
}[];
|
|
350
350
|
/**
|
|
351
351
|
* 找到多个资源的公共可用时间段
|
|
@@ -23,7 +23,8 @@ function resolveCustomerDisplayName(customer) {
|
|
|
23
23
|
|
|
24
24
|
/** 将 ICustomer 格式化为写入 tempOrder 的协议字段。 */
|
|
25
25
|
function formatOrderCustomerPatch(customer) {
|
|
26
|
-
const
|
|
26
|
+
const c = customer;
|
|
27
|
+
const rawId = c.customer_id ?? c.customerId ?? customer.id;
|
|
27
28
|
const numericId = typeof rawId === 'number' ? rawId : rawId !== undefined && rawId !== null && rawId !== '' ? Number(rawId) : null;
|
|
28
29
|
return {
|
|
29
30
|
customer_id: Number.isFinite(numericId) ? numericId : null,
|
|
@@ -10,7 +10,11 @@ export interface ApiConfig {
|
|
|
10
10
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
11
11
|
transformParams?: (params: any) => any;
|
|
12
12
|
transformResponse?: (response: any) => any;
|
|
13
|
-
options?: Record<string, any
|
|
13
|
+
options?: Record<string, any> | ((params: any) => Record<string, any>);
|
|
14
|
+
}
|
|
15
|
+
export interface ApiCallerOptions {
|
|
16
|
+
baseUrl?: string;
|
|
17
|
+
shopDomain?: string;
|
|
14
18
|
}
|
|
15
19
|
/**
|
|
16
20
|
* 渠道配置接口
|
|
@@ -65,12 +69,14 @@ export declare function getChannelConfig(channel: string): ChannelConfig;
|
|
|
65
69
|
export declare class ApiCaller {
|
|
66
70
|
private request;
|
|
67
71
|
private config;
|
|
72
|
+
private options;
|
|
68
73
|
constructor(request: {
|
|
69
74
|
get: <T = any>(url: string, data?: any, options?: any) => Promise<T>;
|
|
70
75
|
post: <T = any>(url: string, data?: any, options?: any) => Promise<T>;
|
|
71
76
|
put: <T = any>(url: string, data?: any, options?: any) => Promise<T>;
|
|
72
77
|
delete: <T = any>(url: string, options?: any) => Promise<T>;
|
|
73
|
-
}, config: ChannelConfig);
|
|
78
|
+
}, config: ChannelConfig, options?: ApiCallerOptions);
|
|
79
|
+
private resolveUrl;
|
|
74
80
|
/**
|
|
75
81
|
* 执行 API 调用
|
|
76
82
|
*/
|
|
@@ -84,4 +90,4 @@ export declare function createApiCaller(request: {
|
|
|
84
90
|
post: <T = any>(url: string, data?: any, options?: any) => Promise<T>;
|
|
85
91
|
put: <T = any>(url: string, data?: any, options?: any) => Promise<T>;
|
|
86
92
|
delete: <T = any>(url: string, options?: any) => Promise<T>;
|
|
87
|
-
}, channel: string): ApiCaller;
|
|
93
|
+
}, channel: string, options?: ApiCallerOptions): ApiCaller;
|
|
@@ -15,6 +15,8 @@ exports.getChannelConfig = getChannelConfig;
|
|
|
15
15
|
* API 配置接口
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
const h5CustomerAuthApiNames = new Set(['sendEmailVerificationCode', 'sendEmailLoginCode', 'sendSmsRegisterCode', 'sendEmailRegisterLink', 'verifyEmailRegistrationLink', 'emailPasswordLogin', 'emailCodeRegister', 'phoneCodeRegister', 'resendEmailRegisterLink', 'checkEmailLinkCode', 'sendSmsLoginCode', 'phoneCodeLogin', 'guestLogin', 'checkEmailExists', 'checkEmailCode', 'checkMobileCode', 'phonePasswordLogin', 'sendPasswordResetEmail', 'sendPasswordResetSms', 'sendResetPasswordLink', 'checkResetPasswordCode', 'resetPasswordByCode', 'resetPasswordByEmail', 'resetPasswordByPhone', 'verifyCode', 'register', 'login', 'oauthLogin', 'facebookLogin', 'appleLogin']);
|
|
19
|
+
|
|
18
20
|
/**
|
|
19
21
|
* 渠道配置接口
|
|
20
22
|
*/
|
|
@@ -278,6 +280,31 @@ const onlineStoreConfig = {
|
|
|
278
280
|
})
|
|
279
281
|
}
|
|
280
282
|
};
|
|
283
|
+
function withH5AuthPrefix(config) {
|
|
284
|
+
const nextConfig = {};
|
|
285
|
+
Object.entries(config).forEach(([key, apiConfig]) => {
|
|
286
|
+
if (!apiConfig.url.startsWith('/auth/')) {
|
|
287
|
+
nextConfig[key] = apiConfig;
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
nextConfig[key] = {
|
|
291
|
+
...apiConfig,
|
|
292
|
+
url: apiConfig.url.startsWith('/h5/') ? apiConfig.url : `/h5${apiConfig.url}`,
|
|
293
|
+
options: params => {
|
|
294
|
+
const {
|
|
295
|
+
withCredentials,
|
|
296
|
+
...baseOptions
|
|
297
|
+
} = (typeof apiConfig.options === 'function' ? apiConfig.options(params) : apiConfig.options) || {};
|
|
298
|
+
return {
|
|
299
|
+
...baseOptions,
|
|
300
|
+
prefix: false
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
});
|
|
305
|
+
return nextConfig;
|
|
306
|
+
}
|
|
307
|
+
const h5OnlineStoreConfig = withH5AuthPrefix(onlineStoreConfig);
|
|
281
308
|
|
|
282
309
|
/**
|
|
283
310
|
* 默认配置(通用配置)
|
|
@@ -1066,6 +1093,7 @@ const shopWebposConfig = {
|
|
|
1066
1093
|
*/
|
|
1067
1094
|
const channelConfigMap = exports.channelConfigMap = {
|
|
1068
1095
|
'online-store': onlineStoreConfig,
|
|
1096
|
+
'online-store-h5': h5OnlineStoreConfig,
|
|
1069
1097
|
'default': defaultConfig,
|
|
1070
1098
|
'webpos': webposConfig,
|
|
1071
1099
|
'shop.webpos': shopWebposConfig
|
|
@@ -1083,9 +1111,16 @@ function getChannelConfig(channel) {
|
|
|
1083
1111
|
* 负责根据配置执行 API 调用
|
|
1084
1112
|
*/
|
|
1085
1113
|
class ApiCaller {
|
|
1086
|
-
constructor(request, config) {
|
|
1114
|
+
constructor(request, config, options = {}) {
|
|
1087
1115
|
this.request = request;
|
|
1088
1116
|
this.config = config;
|
|
1117
|
+
this.options = options;
|
|
1118
|
+
}
|
|
1119
|
+
resolveUrl(url) {
|
|
1120
|
+
if (!this.options.baseUrl || !url.startsWith('/h5/auth/')) {
|
|
1121
|
+
return url;
|
|
1122
|
+
}
|
|
1123
|
+
return `${this.options.baseUrl.replace(/\/$/, '')}${url}`;
|
|
1089
1124
|
}
|
|
1090
1125
|
|
|
1091
1126
|
/**
|
|
@@ -1111,6 +1146,12 @@ class ApiCaller {
|
|
|
1111
1146
|
...options,
|
|
1112
1147
|
...additionalOptions
|
|
1113
1148
|
};
|
|
1149
|
+
if (apiConfig.url.startsWith('/h5/auth/') && h5CustomerAuthApiNames.has(apiName)) {
|
|
1150
|
+
requestOptions.h5CustomerAuth = true;
|
|
1151
|
+
if (this.options.shopDomain) {
|
|
1152
|
+
requestOptions.h5AuthShopDomain = this.options.shopDomain;
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1114
1155
|
|
|
1115
1156
|
// 处理动态 headers
|
|
1116
1157
|
if (requestOptions.headers && typeof requestOptions.headers === 'function') {
|
|
@@ -1123,19 +1164,19 @@ class ApiCaller {
|
|
|
1123
1164
|
switch (apiConfig.method) {
|
|
1124
1165
|
case 'GET':
|
|
1125
1166
|
if (transformedParams && Object.keys(transformedParams).length > 0) {
|
|
1126
|
-
response = await this.request.get(apiConfig.url, transformedParams, requestOptions);
|
|
1167
|
+
response = await this.request.get(this.resolveUrl(apiConfig.url), transformedParams, requestOptions);
|
|
1127
1168
|
} else {
|
|
1128
|
-
response = await this.request.get(apiConfig.url, undefined, requestOptions);
|
|
1169
|
+
response = await this.request.get(this.resolveUrl(apiConfig.url), undefined, requestOptions);
|
|
1129
1170
|
}
|
|
1130
1171
|
break;
|
|
1131
1172
|
case 'POST':
|
|
1132
|
-
response = await this.request.post(apiConfig.url, transformedParams, requestOptions);
|
|
1173
|
+
response = await this.request.post(this.resolveUrl(apiConfig.url), transformedParams, requestOptions);
|
|
1133
1174
|
break;
|
|
1134
1175
|
case 'PUT':
|
|
1135
|
-
response = await this.request.put(apiConfig.url, transformedParams, requestOptions);
|
|
1176
|
+
response = await this.request.put(this.resolveUrl(apiConfig.url), transformedParams, requestOptions);
|
|
1136
1177
|
break;
|
|
1137
1178
|
case 'DELETE':
|
|
1138
|
-
response = await this.request.delete(apiConfig.url, requestOptions);
|
|
1179
|
+
response = await this.request.delete(this.resolveUrl(apiConfig.url), requestOptions);
|
|
1139
1180
|
break;
|
|
1140
1181
|
default:
|
|
1141
1182
|
throw new Error(`不支持的 HTTP 方法: ${apiConfig.method}`);
|
|
@@ -1150,7 +1191,7 @@ class ApiCaller {
|
|
|
1150
1191
|
* 创建 API 调用器
|
|
1151
1192
|
*/
|
|
1152
1193
|
exports.ApiCaller = ApiCaller;
|
|
1153
|
-
function createApiCaller(request, channel) {
|
|
1194
|
+
function createApiCaller(request, channel, options) {
|
|
1154
1195
|
const config = getChannelConfig(channel);
|
|
1155
|
-
return new ApiCaller(request, config);
|
|
1196
|
+
return new ApiCaller(request, config, options);
|
|
1156
1197
|
}
|
|
@@ -227,7 +227,10 @@ class RegisterAndLoginImpl extends _BaseModule.BaseModule {
|
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
// 创建 API 调用器
|
|
230
|
-
this.apiCaller = (0, _config.createApiCaller)(this.request, this.channel
|
|
230
|
+
this.apiCaller = (0, _config.createApiCaller)(this.request, this.channel, {
|
|
231
|
+
baseUrl: this.otherParams.h5AuthBaseUrl,
|
|
232
|
+
shopDomain: this.otherParams.h5AuthShopDomain
|
|
233
|
+
});
|
|
231
234
|
|
|
232
235
|
// 尝试从本地存储恢复登录状态
|
|
233
236
|
await this.restoreLoginState();
|
|
@@ -1200,7 +1200,11 @@ class ScanOrderImpl extends _BaseSales.BaseSalesImpl {
|
|
|
1200
1200
|
return sourceMap;
|
|
1201
1201
|
}
|
|
1202
1202
|
getItemRuleRuntimeConfig() {
|
|
1203
|
-
|
|
1203
|
+
const runtimeConfig = this.itemRuleRuntimeConfig || {};
|
|
1204
|
+
return {
|
|
1205
|
+
...runtimeConfig,
|
|
1206
|
+
channel: runtimeConfig.channel ?? runtimeConfig.custom?.channel ?? this.otherParams?.channel
|
|
1207
|
+
};
|
|
1204
1208
|
}
|
|
1205
1209
|
async ensureItemRuleConfigsLoaded() {
|
|
1206
1210
|
if (this.itemRuleConfigs.length > 0) return this.itemRuleConfigs;
|
|
@@ -333,6 +333,7 @@ function buildItemRuleBusinessData(params) {
|
|
|
333
333
|
cartItems,
|
|
334
334
|
historicalItems,
|
|
335
335
|
serviceType: runtimeConfig.serviceType || 'dine-in',
|
|
336
|
+
channel: runtimeConfig.channel ?? runtimeConfig.custom?.channel,
|
|
336
337
|
submissionIndex: typeof runtimeConfig.submissionIndex === 'number' ? toNonNegativeInt(runtimeConfig.submissionIndex) : tempOrder.order_id ? 1 : 0,
|
|
337
338
|
custom: runtimeConfig.custom || {},
|
|
338
339
|
strategyConfigs: itemRuleConfigs
|
|
@@ -2,10 +2,11 @@ import type { Module, ModuleOptions, PisellCore } from '../../types';
|
|
|
2
2
|
import type { ProductData } from '../../modules';
|
|
3
3
|
import type { OpenDataConfig } from '../../modules/OpenData';
|
|
4
4
|
import type { LoadScheduleAvailableDateParams, ScheduleItem } from '../../modules/Schedule/types';
|
|
5
|
-
import type { ProductListLoadProductsParams } from '../../modules/ProductList';
|
|
5
|
+
import type { ProductListLoadProductsParams, ProductListStoreQueryParams } from '../../modules/ProductList';
|
|
6
6
|
import type { AvailabilityDateRange, AvailabilityOccupancy, AvailabilityProduct, AvailabilityResource, GetProductTimeRangesRequest } from '../../modules/ResourcePlanner';
|
|
7
|
-
import type { AvailabilityContextRef, ContextualAvailabilityQuery, ContextualAvailabilityQueryResult, ContextualCommitAvailabilitySelectionParams, ContextualProductTimeRangeGroup, UnifiedBookingSalesAddRetailProductParams, UnifiedBookingSalesApplyPlannerDiscountsParams, UnifiedBookingSalesCommitAvailabilitySelectionResult, UnifiedBookingSalesDiscountResult, UnifiedBookingSalesLoadProductsByScheduleDateParams, UnifiedBookingSalesLoadOpenDataParams, UnifiedBookingSalesPrepareAvailabilityProjectionParams, UnifiedBookingSalesPolicyResponse, UnifiedBookingSalesStageRetailProductsParams, UnifiedBookingSalesState } from './types';
|
|
7
|
+
import type { AvailabilityContextRef, ContextualAvailabilityQuery, ContextualAvailabilityQueryResult, ContextualCommitAvailabilitySelectionParams, ContextualProductTimeRangeGroup, UnifiedBookingSalesAddRetailProductParams, UnifiedBookingSalesApplyPlannerDiscountsParams, UnifiedBookingSalesCommitAvailabilitySelectionResult, UnifiedBookingSalesDiscountResult, UnifiedBookingSalesLoadProductsByScheduleDateParams, UnifiedBookingSalesLoadOpenDataParams, UnifiedBookingSalesPrepareAvailabilityProjectionParams, UnifiedBookingSalesPolicyResponse, UnifiedBookingSalesResolveProductAllergyRequirementParams, UnifiedBookingSalesStageRetailProductsParams, UnifiedBookingSalesState } from './types';
|
|
8
8
|
import { BookingTicket } from '../BookingTicket';
|
|
9
|
+
import type { AllergyRequirement } from '../../model/strategy/adapter/itemRule';
|
|
9
10
|
export * from './types';
|
|
10
11
|
export { AvailabilityError } from '../../modules/ResourcePlanner';
|
|
11
12
|
/**
|
|
@@ -76,6 +77,9 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
76
77
|
private availabilityRemoteResourceQuerySequence;
|
|
77
78
|
private availabilityRemoteResourceEpoch;
|
|
78
79
|
private availabilityCommitLocks;
|
|
80
|
+
private allergyItemRuleEvaluator;
|
|
81
|
+
private allergyItemRuleConfigs;
|
|
82
|
+
private allergyItemRuleConfigsPromise;
|
|
79
83
|
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
80
84
|
protected getSubmitOrderSalesChannel(): string;
|
|
81
85
|
private createAvailabilityFacadeError;
|
|
@@ -147,6 +151,14 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
147
151
|
*/
|
|
148
152
|
loadOpenData(params: UnifiedBookingSalesLoadOpenDataParams): Promise<OpenDataConfig>;
|
|
149
153
|
getOpenData(): Promise<OpenDataConfig | null>;
|
|
154
|
+
private resetAllergyItemRuleState;
|
|
155
|
+
private fetchAllergyItemRuleConfigs;
|
|
156
|
+
private ensureAllergyItemRuleConfigsLoaded;
|
|
157
|
+
/**
|
|
158
|
+
* 评估当前渠道与商品是否命中 ALLERGY_CHECK。
|
|
159
|
+
* 只返回优先级最高 Action 中当前商品 Target 的 dataSource,不跨商品或 Action 合并。
|
|
160
|
+
*/
|
|
161
|
+
resolveProductAllergyRequirement(params: UnifiedBookingSalesResolveProductAllergyRequirementParams): Promise<AllergyRequirement | null>;
|
|
150
162
|
/**
|
|
151
163
|
* Load a resource policy without depending on the legacy appointmentBooking solution.
|
|
152
164
|
*/
|
|
@@ -159,6 +171,7 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
159
171
|
callback?: (result: any) => void;
|
|
160
172
|
subscriberId?: string;
|
|
161
173
|
}): Promise<ProductData[]>;
|
|
174
|
+
queryProducts(params?: ProductListStoreQueryParams): Promise<ProductData[]>;
|
|
162
175
|
/** Date-first entry point. It delegates protocol details and cache ownership to ScheduleModule. */
|
|
163
176
|
loadScheduleAvailableDate(params: LoadScheduleAvailableDateParams): Promise<import("../../modules/Date/types").ITime[]>;
|
|
164
177
|
/**
|