@pisell/pisellos 2.2.314 → 2.2.315
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/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/dist/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
- package/dist/model/strategy/adapter/itemRule/adapter.js +74 -7
- package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
- package/dist/model/strategy/adapter/itemRule/evaluator.js +13 -0
- package/dist/model/strategy/adapter/itemRule/type.d.ts +40 -1
- package/dist/model/strategy/adapter/itemRule/type.js +10 -0
- package/dist/modules/BookingContext/utils/productExtend.d.ts +7 -0
- package/dist/modules/BookingContext/utils/productExtend.js +62 -18
- package/dist/modules/BookingContext/utils/resources.js +1 -1
- package/dist/modules/BusinessAvailability/index.d.ts +30 -0
- package/dist/modules/BusinessAvailability/index.js +204 -0
- package/dist/modules/Cart/index.js +4 -3
- package/dist/modules/Cart/types.d.ts +2 -0
- package/dist/modules/Cart/utils/cartProduct.d.ts +3 -1
- package/dist/modules/Cart/utils/cartProduct.js +59 -32
- package/dist/modules/FulfillmentTiming/index.d.ts +11 -0
- package/dist/modules/FulfillmentTiming/index.js +407 -0
- package/dist/modules/FulfillmentTiming/types.d.ts +67 -0
- package/dist/modules/FulfillmentTiming/types.js +1 -0
- package/dist/modules/OpenData/types.d.ts +14 -0
- package/dist/modules/Order/index.d.ts +14 -2
- package/dist/modules/Order/index.js +856 -486
- package/dist/modules/Order/localEftposState.d.ts +13 -0
- package/dist/modules/Order/localEftposState.js +39 -0
- package/dist/modules/Order/pickupTiming.d.ts +46 -0
- package/dist/modules/Order/pickupTiming.js +53 -0
- package/dist/modules/Order/types.d.ts +30 -2
- package/dist/modules/Order/utils.js +25 -7
- package/dist/modules/Payment/index.js +9 -10
- package/dist/modules/Product/types.d.ts +11 -0
- package/dist/modules/ProductList/index.js +1 -1
- package/dist/modules/ResourcePlanner/planner.d.ts +2 -0
- package/dist/modules/ResourcePlanner/planner.js +332 -23
- package/dist/modules/ResourcePlanner/types.d.ts +29 -0
- package/dist/modules/Schedule/index.d.ts +8 -0
- package/dist/modules/Schedule/index.js +141 -39
- package/dist/modules/index.d.ts +1 -0
- package/dist/modules/index.js +1 -0
- package/dist/plugins/request.d.ts +7 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1536 -1309
- package/dist/server/modules/form/index.d.ts +19 -0
- package/dist/server/modules/form/index.js +205 -0
- package/dist/server/modules/form/types.d.ts +13 -0
- package/dist/server/modules/form/types.js +3 -0
- package/dist/server/modules/index.d.ts +3 -0
- package/dist/server/modules/index.js +4 -0
- package/dist/server/modules/order/index.d.ts +15 -0
- package/dist/server/modules/order/index.js +920 -688
- package/dist/server/modules/order/types.d.ts +1 -0
- package/dist/server/test.json +1 -1
- package/dist/server/utils/small-ticket.d.ts +1 -85
- package/dist/server/utils/small-ticket.js +2 -2542
- package/dist/shared/payment/loadPaymentMethods.d.ts +9 -0
- package/dist/shared/payment/loadPaymentMethods.js +66 -0
- package/dist/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
- package/dist/shared/receipt/customerInvoiceLanguages.js +60 -0
- package/dist/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
- package/dist/shared/receipt/loadCustomerInvoiceLayout.js +184 -0
- package/dist/shared/receipt/small-ticket.d.ts +96 -0
- package/dist/shared/receipt/small-ticket.js +2751 -0
- package/dist/shared/receipt/templateVisibility.d.ts +23 -0
- package/dist/shared/receipt/templateVisibility.js +64 -0
- package/dist/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
- package/dist/shared/sales/loadSalesOrderSnapshot.js +21 -0
- package/dist/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
- package/dist/solution/BaseSales/fulfillmentItemRules.js +750 -0
- package/dist/solution/BaseSales/index.d.ts +39 -16
- package/dist/solution/BaseSales/index.js +1754 -1154
- package/dist/solution/BaseSales/pickupTiming.d.ts +47 -0
- package/dist/solution/BaseSales/pickupTiming.js +616 -0
- package/dist/solution/BaseSales/types.d.ts +11 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +3 -0
- package/dist/solution/BookingByStep/index.d.ts +3 -1
- package/dist/solution/BookingByStep/index.js +8 -3
- package/dist/solution/BookingTicket/index.d.ts +8 -2
- package/dist/solution/BookingTicket/index.js +513 -436
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
- package/dist/solution/BookingTicket/utils/addProductDecision.js +1 -1
- package/dist/solution/BookingTicket/utils/cartView.js +3 -1
- package/dist/solution/OrderInvoicePreview/index.d.ts +66 -0
- package/dist/solution/OrderInvoicePreview/index.js +340 -0
- package/dist/solution/RegisterAndLogin/config.js +54 -11
- package/dist/solution/RegisterAndLogin/index.d.ts +2 -0
- package/dist/solution/RegisterAndLogin/index.js +1 -1
- package/dist/solution/RegisterAndLogin/utils.d.ts +12 -4
- package/dist/solution/RegisterAndLogin/utils.js +36 -16
- package/dist/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
- package/dist/solution/UnifiedBookingSales/businessAvailability.js +292 -0
- package/dist/solution/UnifiedBookingSales/index.d.ts +36 -4
- package/dist/solution/UnifiedBookingSales/index.js +1714 -905
- package/dist/solution/UnifiedBookingSales/types.d.ts +16 -2
- package/dist/solution/VenueBooking/index.d.ts +15 -2
- package/dist/solution/VenueBooking/index.js +1062 -785
- package/dist/solution/VenueBooking/types.d.ts +2 -1
- package/dist/solution/VenueBooking/types.js +1 -0
- package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
- package/dist/solution/VenueBooking/utils/dateSummary.js +7 -4
- package/dist/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
- package/dist/solution/VenueBooking/utils/smartPricing.js +273 -0
- package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
- package/dist/solution/VenueBooking/utils/timeSlot.js +6 -3
- package/dist/solution/index.d.ts +1 -0
- package/dist/solution/index.js +2 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +21 -1
- package/lib/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
- package/lib/model/strategy/adapter/itemRule/adapter.js +54 -4
- package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
- package/lib/model/strategy/adapter/itemRule/evaluator.js +9 -0
- package/lib/model/strategy/adapter/itemRule/type.d.ts +40 -1
- package/lib/model/strategy/adapter/itemRule/type.js +10 -0
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/BookingContext/utils/productExtend.d.ts +7 -0
- package/lib/modules/BookingContext/utils/productExtend.js +45 -2
- package/lib/modules/BookingContext/utils/resources.js +1 -1
- package/lib/modules/BusinessAvailability/index.d.ts +30 -0
- package/lib/modules/BusinessAvailability/index.js +146 -0
- package/lib/modules/Cart/index.js +4 -2
- package/lib/modules/Cart/types.d.ts +2 -0
- package/lib/modules/Cart/utils/cartProduct.d.ts +3 -1
- package/lib/modules/Cart/utils/cartProduct.js +39 -20
- package/lib/modules/FulfillmentTiming/index.d.ts +11 -0
- package/lib/modules/FulfillmentTiming/index.js +359 -0
- package/lib/modules/FulfillmentTiming/types.d.ts +67 -0
- package/lib/modules/FulfillmentTiming/types.js +5 -0
- package/lib/modules/OpenData/types.d.ts +14 -0
- package/lib/modules/Order/index.d.ts +14 -2
- package/lib/modules/Order/index.js +240 -38
- package/lib/modules/Order/localEftposState.d.ts +13 -0
- package/lib/modules/Order/localEftposState.js +44 -0
- package/lib/modules/Order/pickupTiming.d.ts +46 -0
- package/lib/modules/Order/pickupTiming.js +61 -0
- package/lib/modules/Order/types.d.ts +30 -2
- package/lib/modules/Order/utils.js +21 -5
- package/lib/modules/Payment/index.js +3 -4
- package/lib/modules/Product/types.d.ts +11 -0
- package/lib/modules/ProductList/index.js +1 -1
- package/lib/modules/ResourcePlanner/planner.d.ts +2 -0
- package/lib/modules/ResourcePlanner/planner.js +252 -8
- package/lib/modules/ResourcePlanner/types.d.ts +29 -0
- package/lib/modules/Schedule/index.d.ts +8 -0
- package/lib/modules/Schedule/index.js +68 -12
- package/lib/modules/index.d.ts +1 -0
- package/lib/modules/index.js +11 -0
- package/lib/plugins/request.d.ts +7 -0
- package/lib/server/index.d.ts +1 -0
- package/lib/server/index.js +158 -37
- package/lib/server/modules/form/index.d.ts +19 -0
- package/lib/server/modules/form/index.js +73 -0
- package/lib/server/modules/form/types.d.ts +13 -0
- package/lib/server/modules/form/types.js +9 -0
- package/lib/server/modules/index.d.ts +3 -0
- package/lib/server/modules/index.js +15 -1
- package/lib/server/modules/order/index.d.ts +15 -0
- package/lib/server/modules/order/index.js +114 -3
- package/lib/server/modules/order/types.d.ts +1 -0
- package/lib/server/test.json +1 -1
- package/lib/server/utils/small-ticket.d.ts +1 -85
- package/lib/server/utils/small-ticket.js +9 -2305
- package/lib/shared/payment/loadPaymentMethods.d.ts +9 -0
- package/lib/shared/payment/loadPaymentMethods.js +40 -0
- package/lib/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
- package/lib/shared/receipt/customerInvoiceLanguages.js +58 -0
- package/lib/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
- package/lib/shared/receipt/loadCustomerInvoiceLayout.js +124 -0
- package/lib/shared/receipt/small-ticket.d.ts +96 -0
- package/lib/shared/receipt/small-ticket.js +2546 -0
- package/lib/shared/receipt/templateVisibility.d.ts +23 -0
- package/lib/shared/receipt/templateVisibility.js +63 -0
- package/lib/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
- package/lib/shared/sales/loadSalesOrderSnapshot.js +22 -0
- package/lib/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
- package/lib/solution/BaseSales/fulfillmentItemRules.js +259 -0
- package/lib/solution/BaseSales/index.d.ts +39 -16
- package/lib/solution/BaseSales/index.js +333 -31
- package/lib/solution/BaseSales/pickupTiming.d.ts +47 -0
- package/lib/solution/BaseSales/pickupTiming.js +290 -0
- package/lib/solution/BaseSales/types.d.ts +11 -0
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +3 -0
- package/lib/solution/BookingByStep/index.d.ts +3 -1
- package/lib/solution/BookingByStep/index.js +7 -3
- package/lib/solution/BookingTicket/index.d.ts +8 -2
- package/lib/solution/BookingTicket/index.js +65 -6
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
- package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -1
- package/lib/solution/BookingTicket/utils/cartView.js +3 -1
- package/lib/solution/OrderInvoicePreview/index.d.ts +66 -0
- package/lib/solution/OrderInvoicePreview/index.js +246 -0
- package/lib/solution/RegisterAndLogin/config.js +57 -11
- package/lib/solution/RegisterAndLogin/index.d.ts +2 -0
- package/lib/solution/RegisterAndLogin/index.js +9 -1
- package/lib/solution/RegisterAndLogin/utils.d.ts +12 -4
- package/lib/solution/RegisterAndLogin/utils.js +24 -17
- package/lib/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
- package/lib/solution/UnifiedBookingSales/businessAvailability.js +138 -0
- package/lib/solution/UnifiedBookingSales/index.d.ts +36 -4
- package/lib/solution/UnifiedBookingSales/index.js +561 -74
- package/lib/solution/UnifiedBookingSales/types.d.ts +16 -2
- package/lib/solution/VenueBooking/index.d.ts +15 -2
- package/lib/solution/VenueBooking/index.js +243 -96
- package/lib/solution/VenueBooking/types.d.ts +2 -1
- package/lib/solution/VenueBooking/types.js +1 -0
- package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
- package/lib/solution/VenueBooking/utils/dateSummary.js +7 -4
- package/lib/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
- package/lib/solution/VenueBooking/utils/smartPricing.js +224 -0
- package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
- package/lib/solution/VenueBooking/utils/timeSlot.js +5 -2
- package/lib/solution/index.d.ts +1 -0
- package/lib/solution/index.js +11 -0
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ var _exportNames = {
|
|
|
8
8
|
};
|
|
9
9
|
exports.BaseSalesImpl = void 0;
|
|
10
10
|
var _BaseModule = require("../../modules/BaseModule");
|
|
11
|
+
var _localEftposState = require("../../modules/Order/localEftposState");
|
|
11
12
|
var _types = require("./types");
|
|
12
13
|
Object.keys(_types).forEach(function (key) {
|
|
13
14
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -21,6 +22,9 @@ Object.keys(_types).forEach(function (key) {
|
|
|
21
22
|
});
|
|
22
23
|
});
|
|
23
24
|
var _Order = require("../../modules/Order");
|
|
25
|
+
var _pickupTiming = require("../../modules/Order/pickupTiming");
|
|
26
|
+
var _pickupTiming2 = require("./pickupTiming");
|
|
27
|
+
var _fulfillmentItemRules = require("./fulfillmentItemRules");
|
|
24
28
|
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
25
29
|
var _lodashEs = require("lodash-es");
|
|
26
30
|
var _types2 = require("../BookingByStep/types");
|
|
@@ -499,6 +503,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
499
503
|
serverOrderChangeHydrateInFlight = null;
|
|
500
504
|
queuedServerOrderChanges = [];
|
|
501
505
|
serverOrderChangeSyncEnabled = false;
|
|
506
|
+
pickupTimingEnabled = false;
|
|
507
|
+
pickupTimingController;
|
|
508
|
+
fulfillmentItemRulesController;
|
|
502
509
|
constructor(name, version) {
|
|
503
510
|
super(name, version);
|
|
504
511
|
}
|
|
@@ -584,8 +591,12 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
584
591
|
}
|
|
585
592
|
this.queuedServerOrderChanges.push(snapshot);
|
|
586
593
|
}
|
|
594
|
+
shouldSyncServerOrderChanges() {
|
|
595
|
+
const payments = this.store.order?.getTempOrder()?.payments || [];
|
|
596
|
+
return this.serverOrderChangeSyncEnabled || payments.some(_localEftposState.isLocalFinalizedPayment) && !payments.some(_paymentUtils.isPendingOrderPayment);
|
|
597
|
+
}
|
|
587
598
|
async drainQueuedServerOrderChanges() {
|
|
588
|
-
if (!this.
|
|
599
|
+
if (!this.shouldSyncServerOrderChanges() || this.salesDetailLoadInFlightCount > 0 || this.serverOrderChangeHydrateInFlight || this.queuedServerOrderChanges.length === 0) return;
|
|
589
600
|
const changedOrders = this.queuedServerOrderChanges;
|
|
590
601
|
this.queuedServerOrderChanges = [];
|
|
591
602
|
await this.syncCurrentSalesDetailFromServerOrderChange({
|
|
@@ -593,8 +604,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
593
604
|
});
|
|
594
605
|
}
|
|
595
606
|
async syncCurrentSalesDetailFromServerOrderChange(payload) {
|
|
596
|
-
const
|
|
597
|
-
|
|
607
|
+
const fullSnapshotAfterFinalization = Array.isArray(payload?.list) && this.store.order?.getTempOrder()?.payments?.some(_localEftposState.isLocalFinalizedPayment);
|
|
608
|
+
const changedOrders = Array.isArray(payload) ? payload : Array.isArray(payload?.changedOrders) && payload.changedOrders.length > 0 ? payload.changedOrders : fullSnapshotAfterFinalization ? payload.list : payload?.data && typeof payload.data === 'object' ? [payload.data] : [];
|
|
609
|
+
if (!this.shouldSyncServerOrderChanges()) return;
|
|
598
610
|
|
|
599
611
|
// 显式详情加载期间 current 可能仍是上一单,先按订单身份 latest-only 缓存;
|
|
600
612
|
// load 完成后再用新的 current 过滤,避免恰好到达的最新支付快照丢失。
|
|
@@ -1037,7 +1049,30 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1037
1049
|
customerId: params.customerId,
|
|
1038
1050
|
channel: params.channel
|
|
1039
1051
|
});
|
|
1040
|
-
|
|
1052
|
+
const shouldAlignSelectedVariantPrice = handledByOsServer && this.preferAuthoritativeProductQueryPrice();
|
|
1053
|
+
return productIds.map((productId, index) => {
|
|
1054
|
+
const authoritativeProduct = productId === null ? null : productsById.get(productId) || null;
|
|
1055
|
+
if (!shouldAlignSelectedVariantPrice || !authoritativeProduct) return authoritativeProduct;
|
|
1056
|
+
const selectedProduct = selectedProducts[index];
|
|
1057
|
+
const selectedVariantId = this.getSelectedProductVariantId(selectedProduct);
|
|
1058
|
+
if (!selectedVariantId || this.getSelectedProductVariantId(authoritativeProduct) === selectedVariantId) {
|
|
1059
|
+
return authoritativeProduct;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// OS 返回的是目录商品;已命中的智能价格不能被规格基础价覆盖。
|
|
1063
|
+
const appliedFields = authoritativeProduct._dataVariant?.appliedFields;
|
|
1064
|
+
if (Array.isArray(appliedFields) && ['price', 'selling_price', 'original_price', 'base_price'].some(field => appliedFields.includes(field))) {
|
|
1065
|
+
return authoritativeProduct;
|
|
1066
|
+
}
|
|
1067
|
+
const selectedVariant = Array.isArray(authoritativeProduct.variant) ? authoritativeProduct.variant.find(variant => Number(variant?.id) === selectedVariantId) : undefined;
|
|
1068
|
+
const selectedPrice = [selectedVariant?.price, selectedVariant?.selling_price, selectedVariant?.base_price, params.priceQueries[index].fallback_price, selectedProduct.price, selectedProduct.selling_price, selectedProduct.original_price].find(value => (typeof value === 'number' || typeof value === 'string' && value.trim() !== '') && Number.isFinite(Number(value)));
|
|
1069
|
+
|
|
1070
|
+
// 每行独立保留所选规格价格(含 0 元),避免同商品多规格共用目录对象串价。
|
|
1071
|
+
return selectedPrice === undefined ? authoritativeProduct : {
|
|
1072
|
+
...authoritativeProduct,
|
|
1073
|
+
price: selectedPrice
|
|
1074
|
+
};
|
|
1075
|
+
});
|
|
1041
1076
|
}
|
|
1042
1077
|
const queryPayload = this.buildPriceQueryPayload({
|
|
1043
1078
|
ids,
|
|
@@ -1157,6 +1192,98 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1157
1192
|
return this.otherParams?.channel;
|
|
1158
1193
|
}
|
|
1159
1194
|
|
|
1195
|
+
/** Only solutions opting into Pickup Timing supply effective OpenData. */
|
|
1196
|
+
async loadPickupTimingOpenData(_force) {
|
|
1197
|
+
return {};
|
|
1198
|
+
}
|
|
1199
|
+
async loadFulfillmentItemRuleOpenData() {
|
|
1200
|
+
const openData = this.otherParams?.openData ?? this.otherParams?.dineInConfig;
|
|
1201
|
+
return openData && typeof openData === 'object' && !Array.isArray(openData) ? openData : null;
|
|
1202
|
+
}
|
|
1203
|
+
getFulfillmentItemRulesController() {
|
|
1204
|
+
if (!this.fulfillmentItemRulesController) {
|
|
1205
|
+
this.fulfillmentItemRulesController = new _fulfillmentItemRules.FulfillmentItemRulesController({
|
|
1206
|
+
getOrder: () => {
|
|
1207
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1208
|
+
return this.store.order;
|
|
1209
|
+
},
|
|
1210
|
+
getProducts: () => this.store.products,
|
|
1211
|
+
loadOpenData: () => this.loadFulfillmentItemRuleOpenData(),
|
|
1212
|
+
getScope: () => this.getPickupTimingScope(),
|
|
1213
|
+
getOtherParams: () => this.otherParams,
|
|
1214
|
+
fetchStrategyModels: ids => this.request.get('/promotion', {
|
|
1215
|
+
skip: 1,
|
|
1216
|
+
num: 99,
|
|
1217
|
+
status: 'active',
|
|
1218
|
+
ids
|
|
1219
|
+
}),
|
|
1220
|
+
reportError: error => this.logWarning('履约费用策略执行失败,保留服务类型设置', {
|
|
1221
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1222
|
+
})
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
return this.fulfillmentItemRulesController;
|
|
1226
|
+
}
|
|
1227
|
+
isPickupTimingEnabled() {
|
|
1228
|
+
return this.pickupTimingEnabled && this.otherParams?.enablePickupTiming !== false;
|
|
1229
|
+
}
|
|
1230
|
+
getPickupTimingContextData(key) {
|
|
1231
|
+
const context = this.core?.context;
|
|
1232
|
+
const getData = context?.getData;
|
|
1233
|
+
return typeof getData === 'function' ? getData.call(context, key) : undefined;
|
|
1234
|
+
}
|
|
1235
|
+
getPickupTimingScope() {
|
|
1236
|
+
return JSON.stringify({
|
|
1237
|
+
shop: this.getPickupTimingContextData('shop_id'),
|
|
1238
|
+
businessCode: this.otherParams?.businessCode ?? this.otherParams?.business_code,
|
|
1239
|
+
channel: this.getSubmitOrderSalesChannel(),
|
|
1240
|
+
timezone: this.getPickupTimingContextData('timezone'),
|
|
1241
|
+
platform: (0, _platform.normalizeRuntimePlatform)(this.otherParams?.platform),
|
|
1242
|
+
cacheId: this.cacheId
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
resetPickupTimingCache() {
|
|
1246
|
+
this.pickupTimingController?.invalidate();
|
|
1247
|
+
}
|
|
1248
|
+
getPickupTimingController() {
|
|
1249
|
+
if (!this.pickupTimingController) {
|
|
1250
|
+
this.pickupTimingController = new _pickupTiming2.PickupTimingController({
|
|
1251
|
+
getOrder: () => {
|
|
1252
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1253
|
+
return this.store.order;
|
|
1254
|
+
},
|
|
1255
|
+
setServiceType: serviceType => this.setServiceType(serviceType),
|
|
1256
|
+
getSchedule: () => this.store.schedule,
|
|
1257
|
+
loadOpenData: force => this.loadPickupTimingOpenData(force),
|
|
1258
|
+
getTimezone: () => String(this.getPickupTimingContextData('timezone') ?? ''),
|
|
1259
|
+
getScope: () => this.getPickupTimingScope(),
|
|
1260
|
+
isPos: () => (0, _platform.normalizeRuntimePlatform)(this.otherParams?.platform) === 'pos'
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
return this.pickupTimingController;
|
|
1264
|
+
}
|
|
1265
|
+
getPickupTimingAvailability(params) {
|
|
1266
|
+
return this.getPickupTimingController().getAvailability(params);
|
|
1267
|
+
}
|
|
1268
|
+
getPickupTimingSelection() {
|
|
1269
|
+
return this.getPickupTimingController().getSelection();
|
|
1270
|
+
}
|
|
1271
|
+
setPickupTimingSelection(selection) {
|
|
1272
|
+
return this.getPickupTimingController().setSelection(selection);
|
|
1273
|
+
}
|
|
1274
|
+
validatePickupTimingSelection(selection) {
|
|
1275
|
+
return this.getPickupTimingController().validate(selection);
|
|
1276
|
+
}
|
|
1277
|
+
preparePickupTimingForCheckout(options) {
|
|
1278
|
+
if (!this.isPickupTimingEnabled()) {
|
|
1279
|
+
return Promise.resolve({
|
|
1280
|
+
serviceType: String(this.getTempOrder()?.metadata?.shop_service_data?.service_type || ''),
|
|
1281
|
+
mode: 'asap'
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
return this.getPickupTimingController().prepare(options);
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1160
1287
|
/** Subclasses with target-scoped OpenData override this guard before reusing the cache. */
|
|
1161
1288
|
isInvoiceOpenDataCacheCurrent() {
|
|
1162
1289
|
return true;
|
|
@@ -1438,6 +1565,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1438
1565
|
return isChanged;
|
|
1439
1566
|
}
|
|
1440
1567
|
async initialize(core, options = {}) {
|
|
1568
|
+
this.resetPickupTimingCache();
|
|
1441
1569
|
this.core = core;
|
|
1442
1570
|
this.initializeOptions = options || {};
|
|
1443
1571
|
this.paymentNumberDevicePrefix = null;
|
|
@@ -1490,6 +1618,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1490
1618
|
this.core.effects.emit(`${this.name}:onInited`, {});
|
|
1491
1619
|
}
|
|
1492
1620
|
async destroy() {
|
|
1621
|
+
this.resetPickupTimingCache();
|
|
1622
|
+
this.fulfillmentItemRulesController?.invalidate();
|
|
1493
1623
|
this.serverOrderChangeUnsubscribe?.();
|
|
1494
1624
|
this.serverOrderChangeUnsubscribe = null;
|
|
1495
1625
|
this.paymentMethodsChangedUnsubscribe?.();
|
|
@@ -1589,9 +1719,12 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1589
1719
|
/** 获取根 booking(is_next === 0 / is_root === 1),多个时取第一个。 */
|
|
1590
1720
|
getRootBooking() {
|
|
1591
1721
|
if (!this.currentSalesDetail) return null;
|
|
1592
|
-
if (this.currentSalesDetail.rootBooking
|
|
1722
|
+
if (this.currentSalesDetail.rootBooking && !(0, _pickupTiming.isFulfillmentTimingBooking)(this.currentSalesDetail.rootBooking)) {
|
|
1723
|
+
return this.currentSalesDetail.rootBooking;
|
|
1724
|
+
}
|
|
1593
1725
|
const bookings = this.currentSalesDetail.bookings || [];
|
|
1594
1726
|
return bookings.find(booking => {
|
|
1727
|
+
if ((0, _pickupTiming.isFulfillmentTimingBooking)(booking)) return false;
|
|
1595
1728
|
const parentId = booking?.parent_id;
|
|
1596
1729
|
return parentId === 0 || parentId === null || parentId === undefined;
|
|
1597
1730
|
}) || null;
|
|
@@ -1704,9 +1837,26 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1704
1837
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1705
1838
|
return this.store.order.updateTempOrderPickupReferenceMode(mode);
|
|
1706
1839
|
}
|
|
1707
|
-
setServiceType(serviceType) {
|
|
1840
|
+
async setServiceType(serviceType) {
|
|
1708
1841
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1709
|
-
|
|
1842
|
+
const serviceData = this.store.order.updateTempOrderServiceType(serviceType);
|
|
1843
|
+
await this.getFulfillmentItemRulesController().apply(serviceType);
|
|
1844
|
+
// 费用规则可能增删商品;即使没有普通促销,也要同步页面的购物车和金额快照。
|
|
1845
|
+
const tempOrder = this.getTempOrder();
|
|
1846
|
+
if (tempOrder) await this.effectsEmit('onTempOrderReplaced', {
|
|
1847
|
+
tempOrder
|
|
1848
|
+
});
|
|
1849
|
+
return serviceData;
|
|
1850
|
+
}
|
|
1851
|
+
getPickupTimingBooking() {
|
|
1852
|
+
return this.store.order?.getPickupTimingBooking() || null;
|
|
1853
|
+
}
|
|
1854
|
+
setPickupTimingBooking(input) {
|
|
1855
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1856
|
+
return this.store.order.setPickupTimingBooking(input);
|
|
1857
|
+
}
|
|
1858
|
+
clearPickupTimingBooking() {
|
|
1859
|
+
this.store.order?.clearPickupTimingBooking();
|
|
1710
1860
|
}
|
|
1711
1861
|
updateTempOrderContactsInfo(contactsInfo) {
|
|
1712
1862
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
@@ -1788,6 +1938,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1788
1938
|
async clearOrderCartLines() {
|
|
1789
1939
|
try {
|
|
1790
1940
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1941
|
+
this.fulfillmentItemRulesController?.invalidate();
|
|
1791
1942
|
const tempOrder = await this.store.order.clearOrderCartLines();
|
|
1792
1943
|
if (this.currentSalesDetail) {
|
|
1793
1944
|
this.currentSalesDetail = {
|
|
@@ -1815,6 +1966,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1815
1966
|
/** 切换法币 / WalletPass 单位时清空商品、折扣与支付状态,保留客户。 */
|
|
1816
1967
|
async clearOrderForSettlementSwitch() {
|
|
1817
1968
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1969
|
+
this.fulfillmentItemRulesController?.invalidate();
|
|
1818
1970
|
const tempOrder = await this.store.order.clearOrderForSettlementSwitch();
|
|
1819
1971
|
if (this.currentSalesDetail) {
|
|
1820
1972
|
this.currentSalesDetail = {
|
|
@@ -2402,7 +2554,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2402
2554
|
// Deprecated compatibility alias. New BaseSales callers should use submitSalesOrder.
|
|
2403
2555
|
return this.submitSalesOrder(params);
|
|
2404
2556
|
}
|
|
2405
|
-
|
|
2557
|
+
buildVirtualSettlementOrderData() {
|
|
2406
2558
|
if (!this.store.order) return null;
|
|
2407
2559
|
const tempOrder = this.store.order.getTempOrder();
|
|
2408
2560
|
if (!this.isActiveVirtualSettlementOrder(tempOrder)) return null;
|
|
@@ -2411,6 +2563,21 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2411
2563
|
if (!snapshot || !Number.isFinite(currencyProductId) || currencyProductId <= 0) {
|
|
2412
2564
|
throw new Error('Virtual currency settlement configuration is invalid.');
|
|
2413
2565
|
}
|
|
2566
|
+
return {
|
|
2567
|
+
snapshot,
|
|
2568
|
+
currencyProductId,
|
|
2569
|
+
currencyCode: String(tempOrder?.currency_code || ''),
|
|
2570
|
+
currencySymbol: String(tempOrder?.currency_symbol || ''),
|
|
2571
|
+
currencyFormat: String(tempOrder?.currency_format || 'symbol_first')
|
|
2572
|
+
};
|
|
2573
|
+
}
|
|
2574
|
+
async buildVirtualSettlementSubmitData() {
|
|
2575
|
+
const settlement = this.buildVirtualSettlementOrderData();
|
|
2576
|
+
if (!settlement || !this.store.order) return null;
|
|
2577
|
+
const tempOrder = this.store.order.getTempOrder();
|
|
2578
|
+
const {
|
|
2579
|
+
currencyProductId
|
|
2580
|
+
} = settlement;
|
|
2414
2581
|
const summary = await this.store.order.recalculateSummary({
|
|
2415
2582
|
createIfMissing: true
|
|
2416
2583
|
});
|
|
@@ -2425,17 +2592,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2425
2592
|
});
|
|
2426
2593
|
}
|
|
2427
2594
|
const asset = this.store.order.getVirtualCurrencyList().find(item => Number(item?.product_id) === currencyProductId);
|
|
2428
|
-
const currencyCode = String(tempOrder?.currency_code || '');
|
|
2429
|
-
const currencySymbol = String(tempOrder?.currency_symbol || '');
|
|
2430
|
-
const currencyFormat = String(tempOrder?.currency_format || 'symbol_first');
|
|
2431
2595
|
if (amount.lte(0)) {
|
|
2432
2596
|
return {
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
currencyProductId,
|
|
2436
|
-
currencyCode,
|
|
2437
|
-
currencySymbol,
|
|
2438
|
-
currencyFormat
|
|
2597
|
+
...settlement,
|
|
2598
|
+
payments: []
|
|
2439
2599
|
};
|
|
2440
2600
|
}
|
|
2441
2601
|
if (!asset) {
|
|
@@ -2489,12 +2649,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2489
2649
|
};
|
|
2490
2650
|
}
|
|
2491
2651
|
return {
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
currencyProductId,
|
|
2495
|
-
currencyCode,
|
|
2496
|
-
currencySymbol,
|
|
2497
|
-
currencyFormat
|
|
2652
|
+
...settlement,
|
|
2653
|
+
payments: [payment]
|
|
2498
2654
|
};
|
|
2499
2655
|
}
|
|
2500
2656
|
|
|
@@ -2508,11 +2664,48 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2508
2664
|
if (!this.store.order) {
|
|
2509
2665
|
throw new Error('BaseSales 解决方案需要 order 模块支持');
|
|
2510
2666
|
}
|
|
2511
|
-
|
|
2667
|
+
if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
|
|
2668
|
+
freeze: true
|
|
2669
|
+
});
|
|
2670
|
+
const isDeferredPayment = params?.paymentExecution === 'deferred';
|
|
2671
|
+
const virtualPaymentSettlement = isDeferredPayment ? null : await this.buildVirtualSettlementSubmitData();
|
|
2672
|
+
const virtualSettlement = isDeferredPayment ? this.buildVirtualSettlementOrderData() : virtualPaymentSettlement;
|
|
2512
2673
|
// this.store.order.persistTempOrder();
|
|
2513
|
-
const inferredPaymentStatus = this.getSubmitPaymentStatus(params?.paymentStatus);
|
|
2674
|
+
const inferredPaymentStatus = isDeferredPayment ? undefined : this.getSubmitPaymentStatus(params?.paymentStatus);
|
|
2514
2675
|
const smallTicketDataFlag = params?.smallTicketDataFlag ?? this.getDefaultCheckoutSmallTicketDataFlag();
|
|
2515
|
-
const
|
|
2676
|
+
const virtualSettlementEnhancePayload = virtualSettlement ? (payload, ctx) => {
|
|
2677
|
+
const callerPayload = params?.enhancePayload ? params.enhancePayload(payload, ctx) : payload;
|
|
2678
|
+
const currencySettlementConfig = callerPayload.metadata?.currency_settlement_config || {};
|
|
2679
|
+
return {
|
|
2680
|
+
...callerPayload,
|
|
2681
|
+
metadata: {
|
|
2682
|
+
...(callerPayload.metadata || {}),
|
|
2683
|
+
currency_settlement_config: {
|
|
2684
|
+
...currencySettlementConfig,
|
|
2685
|
+
settlement_type: 'virtual_currency',
|
|
2686
|
+
settlement_ids: [virtualSettlement.currencyProductId],
|
|
2687
|
+
currency_display_snapshot: (0, _lodashEs.cloneDeep)(currencySettlementConfig.currency_display_snapshot ?? (0, _virtualSettlement.buildCurrencyDisplaySnapshot)(virtualSettlement.snapshot))
|
|
2688
|
+
}
|
|
2689
|
+
},
|
|
2690
|
+
currency_code: virtualSettlement.currencyCode,
|
|
2691
|
+
currency_symbol: virtualSettlement.currencySymbol,
|
|
2692
|
+
currency_format: virtualSettlement.currencyFormat
|
|
2693
|
+
};
|
|
2694
|
+
} : params?.enhancePayload;
|
|
2695
|
+
const configuredEnhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(virtualSettlementEnhancePayload);
|
|
2696
|
+
// Apply this last so neither a stale draft status nor a caller enhancer can
|
|
2697
|
+
// turn deferred submission into payment. The live wallet selection is untouched.
|
|
2698
|
+
const enhancePayload = isDeferredPayment ? (payload, ctx) => {
|
|
2699
|
+
const enhancedPayload = configuredEnhancePayload ? configuredEnhancePayload(payload, ctx) : payload;
|
|
2700
|
+
const {
|
|
2701
|
+
payment_status: _paymentStatus,
|
|
2702
|
+
...orderPayload
|
|
2703
|
+
} = enhancedPayload;
|
|
2704
|
+
return {
|
|
2705
|
+
...orderPayload,
|
|
2706
|
+
payments: []
|
|
2707
|
+
};
|
|
2708
|
+
} : configuredEnhancePayload;
|
|
2516
2709
|
const submitParams = {
|
|
2517
2710
|
cacheId: this.cacheId,
|
|
2518
2711
|
platform: this.otherParams?.platform,
|
|
@@ -2520,8 +2713,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2520
2713
|
channel: this.getSubmitOrderSalesChannel(),
|
|
2521
2714
|
type: this.otherParams?.type,
|
|
2522
2715
|
request_unique_idempotency_token: this.store.order.generateIdempotencyToken(),
|
|
2523
|
-
...(
|
|
2524
|
-
payments:
|
|
2716
|
+
...(isDeferredPayment ? {
|
|
2717
|
+
payments: []
|
|
2718
|
+
} : virtualPaymentSettlement ? {
|
|
2719
|
+
payments: virtualPaymentSettlement.payments
|
|
2525
2720
|
} : params?.payments !== undefined ? {
|
|
2526
2721
|
payments: params.payments
|
|
2527
2722
|
} : {}),
|
|
@@ -2531,7 +2726,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2531
2726
|
...(smallTicketDataFlag !== undefined ? {
|
|
2532
2727
|
smallTicketDataFlag
|
|
2533
2728
|
} : {}),
|
|
2534
|
-
...(virtualSettlement ? {
|
|
2729
|
+
...(isDeferredPayment || virtualSettlement ? {
|
|
2535
2730
|
confirmPendingVoucherPayments: false
|
|
2536
2731
|
} : params?.confirmPendingVoucherPayments !== undefined ? {
|
|
2537
2732
|
confirmPendingVoucherPayments: params.confirmPendingVoucherPayments
|
|
@@ -2562,10 +2757,109 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2562
2757
|
};
|
|
2563
2758
|
return this.shouldUseCheckoutSyncTask() ? this.store.order.submitTempOrder(submitParams) : this.store.order.submitTempOrderAsync(submitParams);
|
|
2564
2759
|
}
|
|
2760
|
+
pendingLocalEftposFinalizations = new Map();
|
|
2761
|
+
async finalizeLocalEftposPayment(params) {
|
|
2762
|
+
const key = `${params.saleId}:${params.paymentNumber}`;
|
|
2763
|
+
// If SQLite rejects the write, retry this known result before another payment can start.
|
|
2764
|
+
this.pendingLocalEftposFinalizations.set(key, params);
|
|
2765
|
+
const response = await this.request.post('/local/finalizeLocalEftposPayment', {
|
|
2766
|
+
sale_id: params.saleId,
|
|
2767
|
+
payment_number: params.paymentNumber,
|
|
2768
|
+
result: params.result,
|
|
2769
|
+
failed_transaction_numbers: params.failedTransactionNumbers
|
|
2770
|
+
}, {
|
|
2771
|
+
osServer: true,
|
|
2772
|
+
customToast: () => {}
|
|
2773
|
+
});
|
|
2774
|
+
if (response?.code !== 200 || !response?.data?.order) {
|
|
2775
|
+
throw new Error(response?.message || '本地支付收尾失败,请刷新订单后重试');
|
|
2776
|
+
}
|
|
2777
|
+
this.pendingLocalEftposFinalizations.delete(key);
|
|
2778
|
+
const {
|
|
2779
|
+
order,
|
|
2780
|
+
payment
|
|
2781
|
+
} = response.data;
|
|
2782
|
+
const temp = this.getTempOrder();
|
|
2783
|
+
const isCurrentOrder = String(temp?.external_sale_number || temp?.order_id) === String(params.saleId) || temp?.order_id && String(temp.order_id) === String(order.order_id);
|
|
2784
|
+
if (isCurrentOrder) {
|
|
2785
|
+
// Persisted by the local route already. Saving a draft here would re-enable protection.
|
|
2786
|
+
if (temp?.payments?.some(item => String(item.payment_number) === params.paymentNumber)) {
|
|
2787
|
+
await this.updateOrderPayment(params.paymentNumber, payment, {
|
|
2788
|
+
persistDraft: false,
|
|
2789
|
+
submitWhenPaid: false
|
|
2790
|
+
});
|
|
2791
|
+
}
|
|
2792
|
+
if ((0, _localEftposState.requiresLocalPaymentRefresh)(order)) {
|
|
2793
|
+
// Set the in-memory gate before the GET so a failed refresh also blocks this page.
|
|
2794
|
+
const currentTemp = this.getTempOrder();
|
|
2795
|
+
if (currentTemp) currentTemp.metadata = {
|
|
2796
|
+
...currentTemp.metadata,
|
|
2797
|
+
...order.metadata
|
|
2798
|
+
};
|
|
2799
|
+
try {
|
|
2800
|
+
await this.loadSalesDetail({
|
|
2801
|
+
orderId: order.order_id,
|
|
2802
|
+
forceRemote: true,
|
|
2803
|
+
merge: false
|
|
2804
|
+
});
|
|
2805
|
+
} catch {
|
|
2806
|
+
throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
} else if ((0, _localEftposState.requiresLocalPaymentRefresh)(order)) {
|
|
2810
|
+
const refreshed = await this.store.order?.getSalesOrderByLookup({
|
|
2811
|
+
lookup: order.order_id,
|
|
2812
|
+
forceRemote: true
|
|
2813
|
+
});
|
|
2814
|
+
if (refreshed?.code !== 200) throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
|
|
2815
|
+
}
|
|
2816
|
+
return response.data;
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
/** Entry gate also reads SQLite state, so stale sessions/restarts cannot bypass it. */
|
|
2820
|
+
async ensureSalesOrderReadyForPayment() {
|
|
2821
|
+
const temp = this.getTempOrder();
|
|
2822
|
+
const unfinished = [...this.pendingLocalEftposFinalizations.values()].filter(params => String(params.saleId) === String(temp?.external_sale_number) || String(params.saleId) === String(temp?.order_id));
|
|
2823
|
+
if (unfinished.length > 0) {
|
|
2824
|
+
for (const params of unfinished) await this.finalizeLocalEftposPayment(params);
|
|
2825
|
+
throw new Error('订单已更新,请确认商品和金额后重新付款');
|
|
2826
|
+
}
|
|
2827
|
+
const lookup = temp?.order_id || temp?.external_sale_number;
|
|
2828
|
+
let localOrder = null;
|
|
2829
|
+
if (lookup && this.core?.server?.hasRoute?.('post', '/shop/local/orderPaymentReadiness')) {
|
|
2830
|
+
const response = await this.request.post('/local/orderPaymentReadiness', {
|
|
2831
|
+
sale_id: lookup
|
|
2832
|
+
}, {
|
|
2833
|
+
osServer: true,
|
|
2834
|
+
customToast: () => {}
|
|
2835
|
+
});
|
|
2836
|
+
if (response?.code !== 200) throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
|
|
2837
|
+
localOrder = response.data;
|
|
2838
|
+
}
|
|
2839
|
+
if (!(0, _localEftposState.requiresLocalPaymentRefresh)(temp) && !(0, _localEftposState.requiresLocalPaymentRefresh)(localOrder)) return;
|
|
2840
|
+
const orderId = localOrder?.order_id || temp?.order_id;
|
|
2841
|
+
if (!orderId || String(orderId) === String(temp?.external_sale_number)) {
|
|
2842
|
+
throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
|
|
2843
|
+
}
|
|
2844
|
+
try {
|
|
2845
|
+
await this.loadSalesDetail({
|
|
2846
|
+
orderId,
|
|
2847
|
+
forceRemote: true,
|
|
2848
|
+
merge: false
|
|
2849
|
+
});
|
|
2850
|
+
} catch {
|
|
2851
|
+
throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
|
|
2852
|
+
}
|
|
2853
|
+
// The initiating UI may have captured the old amount before this await.
|
|
2854
|
+
throw new Error('订单已刷新,请确认商品和金额后重新付款');
|
|
2855
|
+
}
|
|
2565
2856
|
async saveSalesOrderDraft(params) {
|
|
2566
2857
|
if (!this.store.order) {
|
|
2567
2858
|
throw new Error('BaseSales 解决方案需要 order 模块支持');
|
|
2568
2859
|
}
|
|
2860
|
+
if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
|
|
2861
|
+
freeze: false
|
|
2862
|
+
});
|
|
2569
2863
|
return this.store.order.saveTempOrderAsDraft({
|
|
2570
2864
|
cacheId: this.cacheId,
|
|
2571
2865
|
platform: params?.platform ?? this.otherParams?.platform,
|
|
@@ -2581,6 +2875,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2581
2875
|
if (!this.store.order) {
|
|
2582
2876
|
throw new Error('BaseSales 解决方案需要 order 模块支持');
|
|
2583
2877
|
}
|
|
2878
|
+
if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
|
|
2879
|
+
freeze: true
|
|
2880
|
+
});
|
|
2584
2881
|
const inferredPaymentStatus = this.getSubmitPaymentStatus(params?.paymentStatus);
|
|
2585
2882
|
const smallTicketDataFlag = params?.smallTicketDataFlag ?? this.getDefaultCheckoutSmallTicketDataFlag();
|
|
2586
2883
|
const enhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(params?.enhancePayload);
|
|
@@ -3508,6 +3805,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
3508
3805
|
if (!Number.isFinite(actualPaidAmount) || actualPaidAmount + 0.01 < amount) {
|
|
3509
3806
|
throw new Error('顾客实收现金不能小于支付金额');
|
|
3510
3807
|
}
|
|
3808
|
+
if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
|
|
3809
|
+
freeze: true
|
|
3810
|
+
});
|
|
3511
3811
|
this.window?.interaction?.utils?.postMessageToApp?.({
|
|
3512
3812
|
module: 'till',
|
|
3513
3813
|
key: 'open_till',
|
|
@@ -3887,7 +4187,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
3887
4187
|
async addProductToOrder(product, booking, options) {
|
|
3888
4188
|
try {
|
|
3889
4189
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
3890
|
-
const products = await this.store.order.addProductToOrder(product, booking, options);
|
|
4190
|
+
const products = options === undefined ? await this.store.order.addProductToOrder(product, booking) : await this.store.order.addProductToOrder(product, booking, options);
|
|
3891
4191
|
// // 需要叠加
|
|
3892
4192
|
// if (this.hooks.onAddProductOverlay) {
|
|
3893
4193
|
// const res = this.hooks.onAddProductOverlay(是否叠加, product)
|
|
@@ -3976,7 +4276,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
3976
4276
|
async removeProductsFromOrder(identities, options) {
|
|
3977
4277
|
try {
|
|
3978
4278
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
3979
|
-
return await this.store.order.removeProductsFromOrder(identities, options);
|
|
4279
|
+
return options === undefined ? await this.store.order.removeProductsFromOrder(identities) : await this.store.order.removeProductsFromOrder(identities, options);
|
|
3980
4280
|
} catch (error) {
|
|
3981
4281
|
throw error;
|
|
3982
4282
|
}
|
|
@@ -4061,6 +4361,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
4061
4361
|
async setOtherParams(params, {
|
|
4062
4362
|
cover = false
|
|
4063
4363
|
} = {}) {
|
|
4364
|
+
const previousPickupTimingScope = this.getPickupTimingScope();
|
|
4064
4365
|
if (cover) {
|
|
4065
4366
|
this.otherParams = {
|
|
4066
4367
|
...params
|
|
@@ -4072,6 +4373,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
4072
4373
|
};
|
|
4073
4374
|
}
|
|
4074
4375
|
this.cacheId = this.otherParams?.cacheId;
|
|
4376
|
+
if (previousPickupTimingScope !== this.getPickupTimingScope()) this.resetPickupTimingCache();
|
|
4075
4377
|
await this.syncOtherParamsToSubModules(params, {
|
|
4076
4378
|
cover
|
|
4077
4379
|
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { OrderModule } from '../../modules/Order';
|
|
2
|
+
import type { ShopServiceType } from '../../modules/Order/types';
|
|
3
|
+
import type { ScheduleModule } from '../../modules/Schedule';
|
|
4
|
+
import { type PickupTimingAvailability, type PickupTimingSelection, type PickupTimingValidationResult } from '../../modules/FulfillmentTiming';
|
|
5
|
+
interface PickupTimingHost {
|
|
6
|
+
getOrder: () => OrderModule;
|
|
7
|
+
setServiceType?: (serviceType: ShopServiceType) => unknown | Promise<unknown>;
|
|
8
|
+
getSchedule: () => ScheduleModule | undefined;
|
|
9
|
+
loadOpenData: (force: boolean) => Promise<Record<string, unknown>>;
|
|
10
|
+
getTimezone: () => string;
|
|
11
|
+
getScope: () => string;
|
|
12
|
+
isPos: () => boolean;
|
|
13
|
+
now?: () => Date;
|
|
14
|
+
}
|
|
15
|
+
/** Reuses runtime configuration and schedules; every calculation still uses the live clock. */
|
|
16
|
+
export declare class PickupTimingController {
|
|
17
|
+
private readonly host;
|
|
18
|
+
private latest?;
|
|
19
|
+
private runtime?;
|
|
20
|
+
private writeSequence;
|
|
21
|
+
constructor(host: PickupTimingHost);
|
|
22
|
+
private now;
|
|
23
|
+
/** A new solution context or an explicit settings refresh invalidates pending work too. */
|
|
24
|
+
invalidate(): void;
|
|
25
|
+
private assertCurrentRuntime;
|
|
26
|
+
private getRuntime;
|
|
27
|
+
private loadConfig;
|
|
28
|
+
private loadSchedules;
|
|
29
|
+
/** Preserve an existing POS choice without adding it to the shared settings cache. */
|
|
30
|
+
private getEffectiveConfig;
|
|
31
|
+
private snapshot;
|
|
32
|
+
getAvailability(params?: {
|
|
33
|
+
date?: string;
|
|
34
|
+
force?: boolean;
|
|
35
|
+
}): Promise<PickupTimingAvailability>;
|
|
36
|
+
getSelection(): PickupTimingSelection;
|
|
37
|
+
private validateSnapshot;
|
|
38
|
+
validate(selection: PickupTimingSelection): Promise<PickupTimingValidationResult>;
|
|
39
|
+
setSelection(selection: PickupTimingSelection, options?: {
|
|
40
|
+
frozen?: boolean;
|
|
41
|
+
}): Promise<PickupTimingSelection>;
|
|
42
|
+
/** Called before a new checkout/payment; payment callbacks keep their already prepared appointment. */
|
|
43
|
+
prepare(options?: {
|
|
44
|
+
freeze?: boolean;
|
|
45
|
+
}): Promise<PickupTimingSelection>;
|
|
46
|
+
}
|
|
47
|
+
export {};
|