@pisell/pisellos 2.2.314 → 2.2.316
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/model/strategy/adapter/promotion/evaluator.js +89 -104
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +3 -1
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +28 -4
- 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/Holder/utils.d.ts +2 -0
- package/dist/modules/Holder/utils.js +32 -2
- package/dist/modules/OpenData/contactInfo.d.ts +20 -0
- package/dist/modules/OpenData/contactInfo.js +70 -0
- package/dist/modules/OpenData/index.d.ts +1 -0
- package/dist/modules/OpenData/index.js +1 -0
- package/dist/modules/OpenData/types.d.ts +23 -0
- package/dist/modules/Order/holderRelations.d.ts +14 -0
- package/dist/modules/Order/holderRelations.js +154 -0
- package/dist/modules/Order/index.d.ts +16 -4
- package/dist/modules/Order/index.js +926 -511
- 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 +49 -3
- package/dist/modules/Order/types.js +2 -0
- package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +1 -1
- package/dist/modules/Order/utils/discountProductLineIdentity.js +142 -7
- package/dist/modules/Order/utils/orderCollectionIdentity.js +24 -10
- package/dist/modules/Order/utils.d.ts +2 -1
- package/dist/modules/Order/utils.js +61 -17
- 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/Rules/index.js +62 -61
- 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 +1557 -1322
- 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 +19 -0
- package/dist/server/modules/order/index.js +1071 -774
- package/dist/server/modules/order/types.d.ts +4 -0
- package/dist/server/modules/products/index.d.ts +28 -7
- package/dist/server/modules/products/index.js +1297 -770
- package/dist/server/modules/products/replication.d.ts +8 -0
- package/dist/server/modules/products/replication.js +69 -0
- package/dist/server/modules/products/types.d.ts +12 -1
- package/dist/server/modules/products/types.js +4 -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 +2763 -0
- package/dist/shared/receipt/templateVisibility.d.ts +26 -0
- package/dist/shared/receipt/templateVisibility.js +68 -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 +43 -16
- package/dist/solution/BaseSales/index.js +2028 -1247
- package/dist/solution/BaseSales/pickupTiming.d.ts +47 -0
- package/dist/solution/BaseSales/pickupTiming.js +616 -0
- package/dist/solution/BaseSales/types.d.ts +12 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -1
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +10 -3
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +14 -4
- package/dist/solution/BookingByStep/index.d.ts +4 -2
- package/dist/solution/BookingByStep/index.js +8 -3
- package/dist/solution/BookingTicket/index.d.ts +23 -3
- package/dist/solution/BookingTicket/index.js +867 -507
- 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/ScanOrder/index.js +65 -31
- package/dist/solution/ScanOrder/types.d.ts +3 -0
- 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 +1715 -906
- 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/evaluator.js +9 -14
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +3 -1
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +17 -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/Holder/utils.d.ts +2 -0
- package/lib/modules/Holder/utils.js +27 -1
- package/lib/modules/OpenData/contactInfo.d.ts +20 -0
- package/lib/modules/OpenData/contactInfo.js +56 -0
- package/lib/modules/OpenData/index.d.ts +1 -0
- package/lib/modules/OpenData/index.js +12 -0
- package/lib/modules/OpenData/types.d.ts +23 -0
- package/lib/modules/Order/holderRelations.d.ts +14 -0
- package/lib/modules/Order/holderRelations.js +98 -0
- package/lib/modules/Order/index.d.ts +16 -4
- package/lib/modules/Order/index.js +284 -50
- 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 +49 -3
- package/lib/modules/Order/types.js +1 -0
- package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +1 -1
- package/lib/modules/Order/utils/discountProductLineIdentity.js +51 -2
- package/lib/modules/Order/utils/orderCollectionIdentity.js +5 -0
- package/lib/modules/Order/utils.d.ts +2 -1
- package/lib/modules/Order/utils.js +49 -11
- 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/Rules/index.js +2 -1
- 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 +166 -39
- 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 +19 -0
- package/lib/server/modules/order/index.js +160 -7
- package/lib/server/modules/order/types.d.ts +4 -0
- package/lib/server/modules/products/index.d.ts +28 -7
- package/lib/server/modules/products/index.js +226 -63
- package/lib/server/modules/products/replication.d.ts +8 -0
- package/lib/server/modules/products/replication.js +30 -0
- package/lib/server/modules/products/types.d.ts +12 -1
- package/lib/server/modules/products/types.js +3 -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 +2555 -0
- package/lib/shared/receipt/templateVisibility.d.ts +26 -0
- package/lib/shared/receipt/templateVisibility.js +67 -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 +43 -16
- package/lib/solution/BaseSales/index.js +401 -33
- package/lib/solution/BaseSales/pickupTiming.d.ts +47 -0
- package/lib/solution/BaseSales/pickupTiming.js +290 -0
- package/lib/solution/BaseSales/types.d.ts +12 -0
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -1
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +7 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +16 -8
- package/lib/solution/BookingByStep/index.d.ts +4 -2
- package/lib/solution/BookingByStep/index.js +7 -3
- package/lib/solution/BookingTicket/index.d.ts +23 -3
- package/lib/solution/BookingTicket/index.js +197 -9
- 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/ScanOrder/index.js +59 -20
- package/lib/solution/ScanOrder/types.d.ts +3 -0
- 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 +562 -75
- 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,11 @@ 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");
|
|
28
|
+
var _holderRelations = require("../../modules/Order/holderRelations");
|
|
29
|
+
var _contactInfo = require("../../modules/OpenData/contactInfo");
|
|
24
30
|
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
25
31
|
var _lodashEs = require("lodash-es");
|
|
26
32
|
var _types2 = require("../BookingByStep/types");
|
|
@@ -345,6 +351,38 @@ function areBaseSalesNotesEquivalent(currentValue, loadedValue, options) {
|
|
|
345
351
|
const loadedNotes = normalizeBaseSalesNotesForComparison(loadedValue);
|
|
346
352
|
return currentNotes !== null && loadedNotes !== null && (0, _lodashEs.isEqual)(currentNotes, loadedNotes);
|
|
347
353
|
}
|
|
354
|
+
function mergeBaseSalesHolderRelations(currentRecord, incomingRecord, strategy) {
|
|
355
|
+
if (!Array.isArray(incomingRecord.holder_relations)) {
|
|
356
|
+
return (0, _lodashEs.cloneDeep)(currentRecord.holder_relations);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// 仅保留商品集合合并实际留下的本地行关系;匹配的行沿用 incoming 快照。
|
|
360
|
+
// 未提供 products 的稀疏包不能据此判断哪些行已被删除或被本地保留。
|
|
361
|
+
const retainedProductUids = new Set();
|
|
362
|
+
if (Array.isArray(incomingRecord.products)) {
|
|
363
|
+
for (const product of currentRecord.products || []) {
|
|
364
|
+
const retained = !incomingRecord.products.some(incomingProduct => (0, _orderCollectionIdentity.isSameOrderCollectionItem)('product', product, incomingProduct)) && (strategy === 'preserve-local' || !(0, _orderCollectionIdentity.getOrderCollectionPersistentId)('product', product));
|
|
365
|
+
const uid = (0, _orderCollectionIdentity.getOrderCollectionReferenceUid)('product', product);
|
|
366
|
+
if (retained && uid) retainedProductUids.add(uid);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const belongsToRetainedProduct = relation => relation?.relation_model === 'order_detail' && retainedProductUids.has(String(relation.relation_uuid));
|
|
370
|
+
const selectedRelations = [...incomingRecord.holder_relations.filter(relation => !belongsToRetainedProduct(relation)), ...(Array.isArray(currentRecord.holder_relations) ? currentRecord.holder_relations.filter(belongsToRetainedProduct) : [])];
|
|
371
|
+
const result = [];
|
|
372
|
+
const indexByIdentity = new Map();
|
|
373
|
+
for (const relation of selectedRelations) {
|
|
374
|
+
const identityParts = [relation?.relation_model, relation?.relation_uuid, relation?.holder_type, relation?.holder_id];
|
|
375
|
+
const identity = identityParts.every(value => value !== undefined && value !== null) ? JSON.stringify(identityParts) : null;
|
|
376
|
+
const existingIndex = identity === null ? undefined : indexByIdentity.get(identity);
|
|
377
|
+
if (existingIndex !== undefined) {
|
|
378
|
+
result[existingIndex] = (0, _lodashEs.cloneDeep)(relation);
|
|
379
|
+
} else {
|
|
380
|
+
if (identity !== null) indexByIdentity.set(identity, result.length);
|
|
381
|
+
result.push((0, _lodashEs.cloneDeep)(relation));
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return result;
|
|
385
|
+
}
|
|
348
386
|
function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, strategy) {
|
|
349
387
|
const loadedHasOrderMetaList = Object.prototype.hasOwnProperty.call(loadedRecord || {}, 'order_meta_list');
|
|
350
388
|
const loadedHasSalesNotes = Object.prototype.hasOwnProperty.call(loadedRecord || {}, 'notes');
|
|
@@ -363,8 +401,12 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, str
|
|
|
363
401
|
const normalizedCurrentTempOrder = normalizeBaseSalesRecordCollections(currentTempOrder, {
|
|
364
402
|
ensureUid: false
|
|
365
403
|
});
|
|
404
|
+
const mergedHolderRelations = mergeBaseSalesHolderRelations(normalizedCurrentTempOrder, normalizedLoadedRecord, strategy);
|
|
366
405
|
const uidRemaps = [];
|
|
367
|
-
const mergedRecord = (0, _lodashEs.mergeWith)(normalizedCurrentTempOrder, normalizedLoadedRecord, (currentValue, loadedValue, key) => {
|
|
406
|
+
const mergedRecord = (0, _lodashEs.mergeWith)(normalizedCurrentTempOrder, normalizedLoadedRecord, (currentValue, loadedValue, key, object) => {
|
|
407
|
+
if (key === 'holder_relations' && object === normalizedCurrentTempOrder) {
|
|
408
|
+
return (0, _lodashEs.cloneDeep)(mergedHolderRelations);
|
|
409
|
+
}
|
|
368
410
|
// order_meta_list 是服务端/本地订单携带的完整业务快照。若 incoming
|
|
369
411
|
// 明确提供它,必须整体替换;若省略,则保留当前值,避免 snapshot
|
|
370
412
|
// 数组递归拼接后出现同 ID 的旧数据。
|
|
@@ -499,6 +541,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
499
541
|
serverOrderChangeHydrateInFlight = null;
|
|
500
542
|
queuedServerOrderChanges = [];
|
|
501
543
|
serverOrderChangeSyncEnabled = false;
|
|
544
|
+
pickupTimingEnabled = false;
|
|
545
|
+
pickupTimingController;
|
|
546
|
+
fulfillmentItemRulesController;
|
|
502
547
|
constructor(name, version) {
|
|
503
548
|
super(name, version);
|
|
504
549
|
}
|
|
@@ -584,8 +629,12 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
584
629
|
}
|
|
585
630
|
this.queuedServerOrderChanges.push(snapshot);
|
|
586
631
|
}
|
|
632
|
+
shouldSyncServerOrderChanges() {
|
|
633
|
+
const payments = this.store.order?.getTempOrder()?.payments || [];
|
|
634
|
+
return this.serverOrderChangeSyncEnabled || payments.some(_localEftposState.isLocalFinalizedPayment) && !payments.some(_paymentUtils.isPendingOrderPayment);
|
|
635
|
+
}
|
|
587
636
|
async drainQueuedServerOrderChanges() {
|
|
588
|
-
if (!this.
|
|
637
|
+
if (!this.shouldSyncServerOrderChanges() || this.salesDetailLoadInFlightCount > 0 || this.serverOrderChangeHydrateInFlight || this.queuedServerOrderChanges.length === 0) return;
|
|
589
638
|
const changedOrders = this.queuedServerOrderChanges;
|
|
590
639
|
this.queuedServerOrderChanges = [];
|
|
591
640
|
await this.syncCurrentSalesDetailFromServerOrderChange({
|
|
@@ -593,8 +642,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
593
642
|
});
|
|
594
643
|
}
|
|
595
644
|
async syncCurrentSalesDetailFromServerOrderChange(payload) {
|
|
596
|
-
const
|
|
597
|
-
|
|
645
|
+
const fullSnapshotAfterFinalization = Array.isArray(payload?.list) && this.store.order?.getTempOrder()?.payments?.some(_localEftposState.isLocalFinalizedPayment);
|
|
646
|
+
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] : [];
|
|
647
|
+
if (!this.shouldSyncServerOrderChanges()) return;
|
|
598
648
|
|
|
599
649
|
// 显式详情加载期间 current 可能仍是上一单,先按订单身份 latest-only 缓存;
|
|
600
650
|
// load 完成后再用新的 current 过滤,避免恰好到达的最新支付快照丢失。
|
|
@@ -1037,7 +1087,30 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1037
1087
|
customerId: params.customerId,
|
|
1038
1088
|
channel: params.channel
|
|
1039
1089
|
});
|
|
1040
|
-
|
|
1090
|
+
const shouldAlignSelectedVariantPrice = handledByOsServer && this.preferAuthoritativeProductQueryPrice();
|
|
1091
|
+
return productIds.map((productId, index) => {
|
|
1092
|
+
const authoritativeProduct = productId === null ? null : productsById.get(productId) || null;
|
|
1093
|
+
if (!shouldAlignSelectedVariantPrice || !authoritativeProduct) return authoritativeProduct;
|
|
1094
|
+
const selectedProduct = selectedProducts[index];
|
|
1095
|
+
const selectedVariantId = this.getSelectedProductVariantId(selectedProduct);
|
|
1096
|
+
if (!selectedVariantId || this.getSelectedProductVariantId(authoritativeProduct) === selectedVariantId) {
|
|
1097
|
+
return authoritativeProduct;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// OS 返回的是目录商品;已命中的智能价格不能被规格基础价覆盖。
|
|
1101
|
+
const appliedFields = authoritativeProduct._dataVariant?.appliedFields;
|
|
1102
|
+
if (Array.isArray(appliedFields) && ['price', 'selling_price', 'original_price', 'base_price'].some(field => appliedFields.includes(field))) {
|
|
1103
|
+
return authoritativeProduct;
|
|
1104
|
+
}
|
|
1105
|
+
const selectedVariant = Array.isArray(authoritativeProduct.variant) ? authoritativeProduct.variant.find(variant => Number(variant?.id) === selectedVariantId) : undefined;
|
|
1106
|
+
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)));
|
|
1107
|
+
|
|
1108
|
+
// 每行独立保留所选规格价格(含 0 元),避免同商品多规格共用目录对象串价。
|
|
1109
|
+
return selectedPrice === undefined ? authoritativeProduct : {
|
|
1110
|
+
...authoritativeProduct,
|
|
1111
|
+
price: selectedPrice
|
|
1112
|
+
};
|
|
1113
|
+
});
|
|
1041
1114
|
}
|
|
1042
1115
|
const queryPayload = this.buildPriceQueryPayload({
|
|
1043
1116
|
ids,
|
|
@@ -1157,6 +1230,98 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1157
1230
|
return this.otherParams?.channel;
|
|
1158
1231
|
}
|
|
1159
1232
|
|
|
1233
|
+
/** Only solutions opting into Pickup Timing supply effective OpenData. */
|
|
1234
|
+
async loadPickupTimingOpenData(_force) {
|
|
1235
|
+
return {};
|
|
1236
|
+
}
|
|
1237
|
+
async loadFulfillmentItemRuleOpenData() {
|
|
1238
|
+
const openData = this.otherParams?.openData ?? this.otherParams?.dineInConfig;
|
|
1239
|
+
return openData && typeof openData === 'object' && !Array.isArray(openData) ? openData : null;
|
|
1240
|
+
}
|
|
1241
|
+
getFulfillmentItemRulesController() {
|
|
1242
|
+
if (!this.fulfillmentItemRulesController) {
|
|
1243
|
+
this.fulfillmentItemRulesController = new _fulfillmentItemRules.FulfillmentItemRulesController({
|
|
1244
|
+
getOrder: () => {
|
|
1245
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1246
|
+
return this.store.order;
|
|
1247
|
+
},
|
|
1248
|
+
getProducts: () => this.store.products,
|
|
1249
|
+
loadOpenData: () => this.loadFulfillmentItemRuleOpenData(),
|
|
1250
|
+
getScope: () => this.getPickupTimingScope(),
|
|
1251
|
+
getOtherParams: () => this.otherParams,
|
|
1252
|
+
fetchStrategyModels: ids => this.request.get('/promotion', {
|
|
1253
|
+
skip: 1,
|
|
1254
|
+
num: 99,
|
|
1255
|
+
status: 'active',
|
|
1256
|
+
ids
|
|
1257
|
+
}),
|
|
1258
|
+
reportError: error => this.logWarning('履约费用策略执行失败,保留服务类型设置', {
|
|
1259
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1260
|
+
})
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
return this.fulfillmentItemRulesController;
|
|
1264
|
+
}
|
|
1265
|
+
isPickupTimingEnabled() {
|
|
1266
|
+
return this.pickupTimingEnabled && this.otherParams?.enablePickupTiming !== false;
|
|
1267
|
+
}
|
|
1268
|
+
getPickupTimingContextData(key) {
|
|
1269
|
+
const context = this.core?.context;
|
|
1270
|
+
const getData = context?.getData;
|
|
1271
|
+
return typeof getData === 'function' ? getData.call(context, key) : undefined;
|
|
1272
|
+
}
|
|
1273
|
+
getPickupTimingScope() {
|
|
1274
|
+
return JSON.stringify({
|
|
1275
|
+
shop: this.getPickupTimingContextData('shop_id'),
|
|
1276
|
+
businessCode: this.otherParams?.businessCode ?? this.otherParams?.business_code,
|
|
1277
|
+
channel: this.getSubmitOrderSalesChannel(),
|
|
1278
|
+
timezone: this.getPickupTimingContextData('timezone'),
|
|
1279
|
+
platform: (0, _platform.normalizeRuntimePlatform)(this.otherParams?.platform),
|
|
1280
|
+
cacheId: this.cacheId
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
resetPickupTimingCache() {
|
|
1284
|
+
this.pickupTimingController?.invalidate();
|
|
1285
|
+
}
|
|
1286
|
+
getPickupTimingController() {
|
|
1287
|
+
if (!this.pickupTimingController) {
|
|
1288
|
+
this.pickupTimingController = new _pickupTiming2.PickupTimingController({
|
|
1289
|
+
getOrder: () => {
|
|
1290
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1291
|
+
return this.store.order;
|
|
1292
|
+
},
|
|
1293
|
+
setServiceType: serviceType => this.setServiceType(serviceType),
|
|
1294
|
+
getSchedule: () => this.store.schedule,
|
|
1295
|
+
loadOpenData: force => this.loadPickupTimingOpenData(force),
|
|
1296
|
+
getTimezone: () => String(this.getPickupTimingContextData('timezone') ?? ''),
|
|
1297
|
+
getScope: () => this.getPickupTimingScope(),
|
|
1298
|
+
isPos: () => (0, _platform.normalizeRuntimePlatform)(this.otherParams?.platform) === 'pos'
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
return this.pickupTimingController;
|
|
1302
|
+
}
|
|
1303
|
+
getPickupTimingAvailability(params) {
|
|
1304
|
+
return this.getPickupTimingController().getAvailability(params);
|
|
1305
|
+
}
|
|
1306
|
+
getPickupTimingSelection() {
|
|
1307
|
+
return this.getPickupTimingController().getSelection();
|
|
1308
|
+
}
|
|
1309
|
+
setPickupTimingSelection(selection) {
|
|
1310
|
+
return this.getPickupTimingController().setSelection(selection);
|
|
1311
|
+
}
|
|
1312
|
+
validatePickupTimingSelection(selection) {
|
|
1313
|
+
return this.getPickupTimingController().validate(selection);
|
|
1314
|
+
}
|
|
1315
|
+
preparePickupTimingForCheckout(options) {
|
|
1316
|
+
if (!this.isPickupTimingEnabled()) {
|
|
1317
|
+
return Promise.resolve({
|
|
1318
|
+
serviceType: String(this.getTempOrder()?.metadata?.shop_service_data?.service_type || ''),
|
|
1319
|
+
mode: 'asap'
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
return this.getPickupTimingController().prepare(options);
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1160
1325
|
/** Subclasses with target-scoped OpenData override this guard before reusing the cache. */
|
|
1161
1326
|
isInvoiceOpenDataCacheCurrent() {
|
|
1162
1327
|
return true;
|
|
@@ -1438,6 +1603,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1438
1603
|
return isChanged;
|
|
1439
1604
|
}
|
|
1440
1605
|
async initialize(core, options = {}) {
|
|
1606
|
+
this.resetPickupTimingCache();
|
|
1441
1607
|
this.core = core;
|
|
1442
1608
|
this.initializeOptions = options || {};
|
|
1443
1609
|
this.paymentNumberDevicePrefix = null;
|
|
@@ -1490,6 +1656,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1490
1656
|
this.core.effects.emit(`${this.name}:onInited`, {});
|
|
1491
1657
|
}
|
|
1492
1658
|
async destroy() {
|
|
1659
|
+
this.resetPickupTimingCache();
|
|
1660
|
+
this.fulfillmentItemRulesController?.invalidate();
|
|
1493
1661
|
this.serverOrderChangeUnsubscribe?.();
|
|
1494
1662
|
this.serverOrderChangeUnsubscribe = null;
|
|
1495
1663
|
this.paymentMethodsChangedUnsubscribe?.();
|
|
@@ -1589,9 +1757,12 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1589
1757
|
/** 获取根 booking(is_next === 0 / is_root === 1),多个时取第一个。 */
|
|
1590
1758
|
getRootBooking() {
|
|
1591
1759
|
if (!this.currentSalesDetail) return null;
|
|
1592
|
-
if (this.currentSalesDetail.rootBooking
|
|
1760
|
+
if (this.currentSalesDetail.rootBooking && !(0, _pickupTiming.isFulfillmentTimingBooking)(this.currentSalesDetail.rootBooking)) {
|
|
1761
|
+
return this.currentSalesDetail.rootBooking;
|
|
1762
|
+
}
|
|
1593
1763
|
const bookings = this.currentSalesDetail.bookings || [];
|
|
1594
1764
|
return bookings.find(booking => {
|
|
1765
|
+
if ((0, _pickupTiming.isFulfillmentTimingBooking)(booking)) return false;
|
|
1595
1766
|
const parentId = booking?.parent_id;
|
|
1596
1767
|
return parentId === 0 || parentId === null || parentId === undefined;
|
|
1597
1768
|
}) || null;
|
|
@@ -1704,14 +1875,54 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1704
1875
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1705
1876
|
return this.store.order.updateTempOrderPickupReferenceMode(mode);
|
|
1706
1877
|
}
|
|
1707
|
-
setServiceType(serviceType) {
|
|
1878
|
+
async setServiceType(serviceType) {
|
|
1708
1879
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1709
|
-
|
|
1880
|
+
const serviceData = this.store.order.updateTempOrderServiceType(serviceType);
|
|
1881
|
+
await this.getFulfillmentItemRulesController().apply(serviceType);
|
|
1882
|
+
// 费用规则可能增删商品;即使没有普通促销,也要同步页面的购物车和金额快照。
|
|
1883
|
+
const tempOrder = this.getTempOrder();
|
|
1884
|
+
if (tempOrder) await this.effectsEmit('onTempOrderReplaced', {
|
|
1885
|
+
tempOrder
|
|
1886
|
+
});
|
|
1887
|
+
return serviceData;
|
|
1888
|
+
}
|
|
1889
|
+
getPickupTimingBooking() {
|
|
1890
|
+
return this.store.order?.getPickupTimingBooking() || null;
|
|
1891
|
+
}
|
|
1892
|
+
setPickupTimingBooking(input) {
|
|
1893
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1894
|
+
return this.store.order.setPickupTimingBooking(input);
|
|
1895
|
+
}
|
|
1896
|
+
clearPickupTimingBooking() {
|
|
1897
|
+
this.store.order?.clearPickupTimingBooking();
|
|
1710
1898
|
}
|
|
1711
1899
|
updateTempOrderContactsInfo(contactsInfo) {
|
|
1712
1900
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1713
1901
|
return this.store.order.updateTempOrderContactsInfo(contactsInfo);
|
|
1714
1902
|
}
|
|
1903
|
+
async loadContactInfoOpenData() {
|
|
1904
|
+
return this.otherParams?.openData ?? null;
|
|
1905
|
+
}
|
|
1906
|
+
async getContactInfoConfig() {
|
|
1907
|
+
const scope = this.getPickupTimingScope();
|
|
1908
|
+
const data = await this.loadContactInfoOpenData();
|
|
1909
|
+
if (scope !== this.getPickupTimingScope()) throw new Error('Store settings changed. Please try again.');
|
|
1910
|
+
return (0, _contactInfo.resolveContactInfoConfig)(data);
|
|
1911
|
+
}
|
|
1912
|
+
async validateContactInfo() {
|
|
1913
|
+
const order = this.getTempOrder();
|
|
1914
|
+
const customerId = order?.customer_id;
|
|
1915
|
+
// Missing customer IDs and the reserved Walk-In IDs do not require contact info.
|
|
1916
|
+
if (!Number.isFinite(Number(customerId)) || Number(customerId) <= 1) return;
|
|
1917
|
+
const identity = order?._extend?.localId || order?.external_sale_number || order?.order_id || order;
|
|
1918
|
+
const config = await this.getContactInfoConfig();
|
|
1919
|
+
const current = this.getTempOrder();
|
|
1920
|
+
if (identity !== (current?._extend?.localId || current?.external_sale_number || current?.order_id || current) || customerId !== current?.customer_id) {
|
|
1921
|
+
throw new Error('The order changed. Please try again.');
|
|
1922
|
+
}
|
|
1923
|
+
const missing = (0, _contactInfo.getMissingContactInfoFields)(config, current?.contacts_info);
|
|
1924
|
+
if (missing.length) throw new _contactInfo.ContactInfoRequiredError(missing);
|
|
1925
|
+
}
|
|
1715
1926
|
|
|
1716
1927
|
/** @deprecated OrderModule 不再负责 tempOrder localStorage 持久化。 */
|
|
1717
1928
|
setEnableTempOrderPersist(enabled) {
|
|
@@ -1788,6 +1999,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1788
1999
|
async clearOrderCartLines() {
|
|
1789
2000
|
try {
|
|
1790
2001
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
2002
|
+
this.fulfillmentItemRulesController?.invalidate();
|
|
1791
2003
|
const tempOrder = await this.store.order.clearOrderCartLines();
|
|
1792
2004
|
if (this.currentSalesDetail) {
|
|
1793
2005
|
this.currentSalesDetail = {
|
|
@@ -1815,6 +2027,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1815
2027
|
/** 切换法币 / WalletPass 单位时清空商品、折扣与支付状态,保留客户。 */
|
|
1816
2028
|
async clearOrderForSettlementSwitch() {
|
|
1817
2029
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
2030
|
+
this.fulfillmentItemRulesController?.invalidate();
|
|
1818
2031
|
const tempOrder = await this.store.order.clearOrderForSettlementSwitch();
|
|
1819
2032
|
if (this.currentSalesDetail) {
|
|
1820
2033
|
this.currentSalesDetail = {
|
|
@@ -2402,7 +2615,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2402
2615
|
// Deprecated compatibility alias. New BaseSales callers should use submitSalesOrder.
|
|
2403
2616
|
return this.submitSalesOrder(params);
|
|
2404
2617
|
}
|
|
2405
|
-
|
|
2618
|
+
buildVirtualSettlementOrderData() {
|
|
2406
2619
|
if (!this.store.order) return null;
|
|
2407
2620
|
const tempOrder = this.store.order.getTempOrder();
|
|
2408
2621
|
if (!this.isActiveVirtualSettlementOrder(tempOrder)) return null;
|
|
@@ -2411,6 +2624,21 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2411
2624
|
if (!snapshot || !Number.isFinite(currencyProductId) || currencyProductId <= 0) {
|
|
2412
2625
|
throw new Error('Virtual currency settlement configuration is invalid.');
|
|
2413
2626
|
}
|
|
2627
|
+
return {
|
|
2628
|
+
snapshot,
|
|
2629
|
+
currencyProductId,
|
|
2630
|
+
currencyCode: String(tempOrder?.currency_code || ''),
|
|
2631
|
+
currencySymbol: String(tempOrder?.currency_symbol || ''),
|
|
2632
|
+
currencyFormat: String(tempOrder?.currency_format || 'symbol_first')
|
|
2633
|
+
};
|
|
2634
|
+
}
|
|
2635
|
+
async buildVirtualSettlementSubmitData() {
|
|
2636
|
+
const settlement = this.buildVirtualSettlementOrderData();
|
|
2637
|
+
if (!settlement || !this.store.order) return null;
|
|
2638
|
+
const tempOrder = this.store.order.getTempOrder();
|
|
2639
|
+
const {
|
|
2640
|
+
currencyProductId
|
|
2641
|
+
} = settlement;
|
|
2414
2642
|
const summary = await this.store.order.recalculateSummary({
|
|
2415
2643
|
createIfMissing: true
|
|
2416
2644
|
});
|
|
@@ -2425,17 +2653,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2425
2653
|
});
|
|
2426
2654
|
}
|
|
2427
2655
|
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
2656
|
if (amount.lte(0)) {
|
|
2432
2657
|
return {
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
currencyProductId,
|
|
2436
|
-
currencyCode,
|
|
2437
|
-
currencySymbol,
|
|
2438
|
-
currencyFormat
|
|
2658
|
+
...settlement,
|
|
2659
|
+
payments: []
|
|
2439
2660
|
};
|
|
2440
2661
|
}
|
|
2441
2662
|
if (!asset) {
|
|
@@ -2489,12 +2710,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2489
2710
|
};
|
|
2490
2711
|
}
|
|
2491
2712
|
return {
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
currencyProductId,
|
|
2495
|
-
currencyCode,
|
|
2496
|
-
currencySymbol,
|
|
2497
|
-
currencyFormat
|
|
2713
|
+
...settlement,
|
|
2714
|
+
payments: [payment]
|
|
2498
2715
|
};
|
|
2499
2716
|
}
|
|
2500
2717
|
|
|
@@ -2508,11 +2725,49 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2508
2725
|
if (!this.store.order) {
|
|
2509
2726
|
throw new Error('BaseSales 解决方案需要 order 模块支持');
|
|
2510
2727
|
}
|
|
2511
|
-
|
|
2728
|
+
await this.validateContactInfo();
|
|
2729
|
+
if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
|
|
2730
|
+
freeze: true
|
|
2731
|
+
});
|
|
2732
|
+
const isDeferredPayment = params?.paymentExecution === 'deferred';
|
|
2733
|
+
const virtualPaymentSettlement = isDeferredPayment ? null : await this.buildVirtualSettlementSubmitData();
|
|
2734
|
+
const virtualSettlement = isDeferredPayment ? this.buildVirtualSettlementOrderData() : virtualPaymentSettlement;
|
|
2512
2735
|
// this.store.order.persistTempOrder();
|
|
2513
|
-
const inferredPaymentStatus = this.getSubmitPaymentStatus(params?.paymentStatus);
|
|
2736
|
+
const inferredPaymentStatus = isDeferredPayment ? undefined : this.getSubmitPaymentStatus(params?.paymentStatus);
|
|
2514
2737
|
const smallTicketDataFlag = params?.smallTicketDataFlag ?? this.getDefaultCheckoutSmallTicketDataFlag();
|
|
2515
|
-
const
|
|
2738
|
+
const virtualSettlementEnhancePayload = virtualSettlement ? (payload, ctx) => {
|
|
2739
|
+
const callerPayload = params?.enhancePayload ? params.enhancePayload(payload, ctx) : payload;
|
|
2740
|
+
const currencySettlementConfig = callerPayload.metadata?.currency_settlement_config || {};
|
|
2741
|
+
return {
|
|
2742
|
+
...callerPayload,
|
|
2743
|
+
metadata: {
|
|
2744
|
+
...(callerPayload.metadata || {}),
|
|
2745
|
+
currency_settlement_config: {
|
|
2746
|
+
...currencySettlementConfig,
|
|
2747
|
+
settlement_type: 'virtual_currency',
|
|
2748
|
+
settlement_ids: [virtualSettlement.currencyProductId],
|
|
2749
|
+
currency_display_snapshot: (0, _lodashEs.cloneDeep)(currencySettlementConfig.currency_display_snapshot ?? (0, _virtualSettlement.buildCurrencyDisplaySnapshot)(virtualSettlement.snapshot))
|
|
2750
|
+
}
|
|
2751
|
+
},
|
|
2752
|
+
currency_code: virtualSettlement.currencyCode,
|
|
2753
|
+
currency_symbol: virtualSettlement.currencySymbol,
|
|
2754
|
+
currency_format: virtualSettlement.currencyFormat
|
|
2755
|
+
};
|
|
2756
|
+
} : params?.enhancePayload;
|
|
2757
|
+
const configuredEnhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(virtualSettlementEnhancePayload);
|
|
2758
|
+
// Apply this last so neither a stale draft status nor a caller enhancer can
|
|
2759
|
+
// turn deferred submission into payment. The live wallet selection is untouched.
|
|
2760
|
+
const enhancePayload = isDeferredPayment ? (payload, ctx) => {
|
|
2761
|
+
const enhancedPayload = configuredEnhancePayload ? configuredEnhancePayload(payload, ctx) : payload;
|
|
2762
|
+
const {
|
|
2763
|
+
payment_status: _paymentStatus,
|
|
2764
|
+
...orderPayload
|
|
2765
|
+
} = enhancedPayload;
|
|
2766
|
+
return {
|
|
2767
|
+
...orderPayload,
|
|
2768
|
+
payments: []
|
|
2769
|
+
};
|
|
2770
|
+
} : configuredEnhancePayload;
|
|
2516
2771
|
const submitParams = {
|
|
2517
2772
|
cacheId: this.cacheId,
|
|
2518
2773
|
platform: this.otherParams?.platform,
|
|
@@ -2520,8 +2775,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2520
2775
|
channel: this.getSubmitOrderSalesChannel(),
|
|
2521
2776
|
type: this.otherParams?.type,
|
|
2522
2777
|
request_unique_idempotency_token: this.store.order.generateIdempotencyToken(),
|
|
2523
|
-
...(
|
|
2524
|
-
payments:
|
|
2778
|
+
...(isDeferredPayment ? {
|
|
2779
|
+
payments: []
|
|
2780
|
+
} : virtualPaymentSettlement ? {
|
|
2781
|
+
payments: virtualPaymentSettlement.payments
|
|
2525
2782
|
} : params?.payments !== undefined ? {
|
|
2526
2783
|
payments: params.payments
|
|
2527
2784
|
} : {}),
|
|
@@ -2531,7 +2788,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2531
2788
|
...(smallTicketDataFlag !== undefined ? {
|
|
2532
2789
|
smallTicketDataFlag
|
|
2533
2790
|
} : {}),
|
|
2534
|
-
...(virtualSettlement ? {
|
|
2791
|
+
...(isDeferredPayment || virtualSettlement ? {
|
|
2535
2792
|
confirmPendingVoucherPayments: false
|
|
2536
2793
|
} : params?.confirmPendingVoucherPayments !== undefined ? {
|
|
2537
2794
|
confirmPendingVoucherPayments: params.confirmPendingVoucherPayments
|
|
@@ -2562,10 +2819,110 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2562
2819
|
};
|
|
2563
2820
|
return this.shouldUseCheckoutSyncTask() ? this.store.order.submitTempOrder(submitParams) : this.store.order.submitTempOrderAsync(submitParams);
|
|
2564
2821
|
}
|
|
2822
|
+
pendingLocalEftposFinalizations = new Map();
|
|
2823
|
+
async finalizeLocalEftposPayment(params) {
|
|
2824
|
+
const key = `${params.saleId}:${params.paymentNumber}`;
|
|
2825
|
+
// If SQLite rejects the write, retry this known result before another payment can start.
|
|
2826
|
+
this.pendingLocalEftposFinalizations.set(key, params);
|
|
2827
|
+
const response = await this.request.post('/local/finalizeLocalEftposPayment', {
|
|
2828
|
+
sale_id: params.saleId,
|
|
2829
|
+
payment_number: params.paymentNumber,
|
|
2830
|
+
result: params.result,
|
|
2831
|
+
failed_transaction_numbers: params.failedTransactionNumbers
|
|
2832
|
+
}, {
|
|
2833
|
+
osServer: true,
|
|
2834
|
+
customToast: () => {}
|
|
2835
|
+
});
|
|
2836
|
+
if (response?.code !== 200 || !response?.data?.order) {
|
|
2837
|
+
throw new Error(response?.message || '本地支付收尾失败,请刷新订单后重试');
|
|
2838
|
+
}
|
|
2839
|
+
this.pendingLocalEftposFinalizations.delete(key);
|
|
2840
|
+
const {
|
|
2841
|
+
order,
|
|
2842
|
+
payment
|
|
2843
|
+
} = response.data;
|
|
2844
|
+
const temp = this.getTempOrder();
|
|
2845
|
+
const isCurrentOrder = String(temp?.external_sale_number || temp?.order_id) === String(params.saleId) || temp?.order_id && String(temp.order_id) === String(order.order_id);
|
|
2846
|
+
if (isCurrentOrder) {
|
|
2847
|
+
// Persisted by the local route already. Saving a draft here would re-enable protection.
|
|
2848
|
+
if (temp?.payments?.some(item => String(item.payment_number) === params.paymentNumber)) {
|
|
2849
|
+
await this.updateOrderPayment(params.paymentNumber, payment, {
|
|
2850
|
+
persistDraft: false,
|
|
2851
|
+
submitWhenPaid: false
|
|
2852
|
+
});
|
|
2853
|
+
}
|
|
2854
|
+
if ((0, _localEftposState.requiresLocalPaymentRefresh)(order)) {
|
|
2855
|
+
// Set the in-memory gate before the GET so a failed refresh also blocks this page.
|
|
2856
|
+
const currentTemp = this.getTempOrder();
|
|
2857
|
+
if (currentTemp) currentTemp.metadata = {
|
|
2858
|
+
...currentTemp.metadata,
|
|
2859
|
+
...order.metadata
|
|
2860
|
+
};
|
|
2861
|
+
try {
|
|
2862
|
+
await this.loadSalesDetail({
|
|
2863
|
+
orderId: order.order_id,
|
|
2864
|
+
forceRemote: true,
|
|
2865
|
+
merge: false
|
|
2866
|
+
});
|
|
2867
|
+
} catch {
|
|
2868
|
+
throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
} else if ((0, _localEftposState.requiresLocalPaymentRefresh)(order)) {
|
|
2872
|
+
const refreshed = await this.store.order?.getSalesOrderByLookup({
|
|
2873
|
+
lookup: order.order_id,
|
|
2874
|
+
forceRemote: true
|
|
2875
|
+
});
|
|
2876
|
+
if (refreshed?.code !== 200) throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
|
|
2877
|
+
}
|
|
2878
|
+
return response.data;
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2881
|
+
/** Entry gate also reads SQLite state, so stale sessions/restarts cannot bypass it. */
|
|
2882
|
+
async ensureSalesOrderReadyForPayment() {
|
|
2883
|
+
const temp = this.getTempOrder();
|
|
2884
|
+
const unfinished = [...this.pendingLocalEftposFinalizations.values()].filter(params => String(params.saleId) === String(temp?.external_sale_number) || String(params.saleId) === String(temp?.order_id));
|
|
2885
|
+
if (unfinished.length > 0) {
|
|
2886
|
+
for (const params of unfinished) await this.finalizeLocalEftposPayment(params);
|
|
2887
|
+
throw new Error('订单已更新,请确认商品和金额后重新付款');
|
|
2888
|
+
}
|
|
2889
|
+
await this.validateContactInfo();
|
|
2890
|
+
const lookup = temp?.order_id || temp?.external_sale_number;
|
|
2891
|
+
let localOrder = null;
|
|
2892
|
+
if (lookup && this.core?.server?.hasRoute?.('post', '/shop/local/orderPaymentReadiness')) {
|
|
2893
|
+
const response = await this.request.post('/local/orderPaymentReadiness', {
|
|
2894
|
+
sale_id: lookup
|
|
2895
|
+
}, {
|
|
2896
|
+
osServer: true,
|
|
2897
|
+
customToast: () => {}
|
|
2898
|
+
});
|
|
2899
|
+
if (response?.code !== 200) throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
|
|
2900
|
+
localOrder = response.data;
|
|
2901
|
+
}
|
|
2902
|
+
if (!(0, _localEftposState.requiresLocalPaymentRefresh)(temp) && !(0, _localEftposState.requiresLocalPaymentRefresh)(localOrder)) return;
|
|
2903
|
+
const orderId = localOrder?.order_id || temp?.order_id;
|
|
2904
|
+
if (!orderId || String(orderId) === String(temp?.external_sale_number)) {
|
|
2905
|
+
throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
|
|
2906
|
+
}
|
|
2907
|
+
try {
|
|
2908
|
+
await this.loadSalesDetail({
|
|
2909
|
+
orderId,
|
|
2910
|
+
forceRemote: true,
|
|
2911
|
+
merge: false
|
|
2912
|
+
});
|
|
2913
|
+
} catch {
|
|
2914
|
+
throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
|
|
2915
|
+
}
|
|
2916
|
+
// The initiating UI may have captured the old amount before this await.
|
|
2917
|
+
throw new Error('订单已刷新,请确认商品和金额后重新付款');
|
|
2918
|
+
}
|
|
2565
2919
|
async saveSalesOrderDraft(params) {
|
|
2566
2920
|
if (!this.store.order) {
|
|
2567
2921
|
throw new Error('BaseSales 解决方案需要 order 模块支持');
|
|
2568
2922
|
}
|
|
2923
|
+
if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
|
|
2924
|
+
freeze: false
|
|
2925
|
+
});
|
|
2569
2926
|
return this.store.order.saveTempOrderAsDraft({
|
|
2570
2927
|
cacheId: this.cacheId,
|
|
2571
2928
|
platform: params?.platform ?? this.otherParams?.platform,
|
|
@@ -2581,6 +2938,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2581
2938
|
if (!this.store.order) {
|
|
2582
2939
|
throw new Error('BaseSales 解决方案需要 order 模块支持');
|
|
2583
2940
|
}
|
|
2941
|
+
await this.validateContactInfo();
|
|
2942
|
+
if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
|
|
2943
|
+
freeze: true
|
|
2944
|
+
});
|
|
2584
2945
|
const inferredPaymentStatus = this.getSubmitPaymentStatus(params?.paymentStatus);
|
|
2585
2946
|
const smallTicketDataFlag = params?.smallTicketDataFlag ?? this.getDefaultCheckoutSmallTicketDataFlag();
|
|
2586
2947
|
const enhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(params?.enhancePayload);
|
|
@@ -2996,7 +3357,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2996
3357
|
|
|
2997
3358
|
const walletProducts = tempOrder?.products.map(product => {
|
|
2998
3359
|
const metadata = product.metadata || {};
|
|
2999
|
-
const rawHolderId = product.holder_id ?? metadata.holder_id;
|
|
3360
|
+
const rawHolderId = (0, _holderRelations.hasProductBooking)(product) ? product.holder_id ?? metadata.holder_id : (0, _holderRelations.getProductHolderRelations)(tempOrder, product).filter(relation => relation.holder_type === 'form').map(relation => relation.holder_id);
|
|
3000
3361
|
const holderIdValue = Array.isArray(rawHolderId) ? rawHolderId[0] : rawHolderId;
|
|
3001
3362
|
const holder_id = Number.isInteger(Number(holderIdValue)) ? Number(holderIdValue) : undefined;
|
|
3002
3363
|
return {
|
|
@@ -3412,6 +3773,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
3412
3773
|
*/
|
|
3413
3774
|
async confirmWalletPayment() {
|
|
3414
3775
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
3776
|
+
await this.validateContactInfo();
|
|
3415
3777
|
const beforePayments = (0, _lodashEs.cloneDeep)(this.store.order.getOrderPayments());
|
|
3416
3778
|
const pendingWalletAmount = this.getPendingWalletPaymentAmount(beforePayments);
|
|
3417
3779
|
const amountSnapshot = this.store.order.getOrderAmountSnapshot?.();
|
|
@@ -3483,6 +3845,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
3483
3845
|
*/
|
|
3484
3846
|
async payCash(params) {
|
|
3485
3847
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
3848
|
+
await this.validateContactInfo();
|
|
3486
3849
|
const amount = Number(params.amount || 0);
|
|
3487
3850
|
if (!Number.isFinite(amount) || amount <= 0) {
|
|
3488
3851
|
throw new Error('现金支付金额必须大于 0');
|
|
@@ -3508,6 +3871,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
3508
3871
|
if (!Number.isFinite(actualPaidAmount) || actualPaidAmount + 0.01 < amount) {
|
|
3509
3872
|
throw new Error('顾客实收现金不能小于支付金额');
|
|
3510
3873
|
}
|
|
3874
|
+
if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
|
|
3875
|
+
freeze: true
|
|
3876
|
+
});
|
|
3511
3877
|
this.window?.interaction?.utils?.postMessageToApp?.({
|
|
3512
3878
|
module: 'till',
|
|
3513
3879
|
key: 'open_till',
|
|
@@ -3887,7 +4253,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
3887
4253
|
async addProductToOrder(product, booking, options) {
|
|
3888
4254
|
try {
|
|
3889
4255
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
3890
|
-
const products = await this.store.order.addProductToOrder(product, booking, options);
|
|
4256
|
+
const products = options === undefined ? await this.store.order.addProductToOrder(product, booking) : await this.store.order.addProductToOrder(product, booking, options);
|
|
3891
4257
|
// // 需要叠加
|
|
3892
4258
|
// if (this.hooks.onAddProductOverlay) {
|
|
3893
4259
|
// const res = this.hooks.onAddProductOverlay(是否叠加, product)
|
|
@@ -3976,7 +4342,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
3976
4342
|
async removeProductsFromOrder(identities, options) {
|
|
3977
4343
|
try {
|
|
3978
4344
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
3979
|
-
return await this.store.order.removeProductsFromOrder(identities, options);
|
|
4345
|
+
return options === undefined ? await this.store.order.removeProductsFromOrder(identities) : await this.store.order.removeProductsFromOrder(identities, options);
|
|
3980
4346
|
} catch (error) {
|
|
3981
4347
|
throw error;
|
|
3982
4348
|
}
|
|
@@ -4061,6 +4427,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
4061
4427
|
async setOtherParams(params, {
|
|
4062
4428
|
cover = false
|
|
4063
4429
|
} = {}) {
|
|
4430
|
+
const previousPickupTimingScope = this.getPickupTimingScope();
|
|
4064
4431
|
if (cover) {
|
|
4065
4432
|
this.otherParams = {
|
|
4066
4433
|
...params
|
|
@@ -4072,6 +4439,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
4072
4439
|
};
|
|
4073
4440
|
}
|
|
4074
4441
|
this.cacheId = this.otherParams?.cacheId;
|
|
4442
|
+
if (previousPickupTimingScope !== this.getPickupTimingScope()) this.resetPickupTimingCache();
|
|
4075
4443
|
await this.syncOtherParamsToSubModules(params, {
|
|
4076
4444
|
cover
|
|
4077
4445
|
});
|