@pisell/pisellos 2.2.274 → 2.2.276
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/core/index.d.ts +2 -0
- package/dist/core/index.js +7 -0
- package/dist/model/strategy/adapter/promotion/adapter.d.ts +4 -0
- package/dist/model/strategy/adapter/promotion/adapter.js +23 -0
- package/dist/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
- package/dist/model/strategy/adapter/promotion/evaluator.js +279 -6
- package/dist/model/strategy/adapter/promotion/examples.d.ts +86 -0
- package/dist/model/strategy/adapter/promotion/examples.js +99 -0
- package/dist/model/strategy/adapter/promotion/index.d.ts +1 -1
- package/dist/model/strategy/adapter/promotion/index.js +1 -1
- package/dist/model/strategy/adapter/promotion/type.d.ts +90 -2
- package/dist/model/strategy/adapter/promotion/type.js +45 -0
- package/dist/modules/OpenData/index.d.ts +2 -0
- package/dist/modules/OpenData/index.js +8 -0
- package/dist/modules/Order/index.d.ts +28 -8
- package/dist/modules/Order/index.js +907 -588
- package/dist/modules/Order/payment-utils.d.ts +26 -0
- package/dist/modules/Order/payment-utils.js +225 -0
- package/dist/modules/Order/types.d.ts +35 -1
- package/dist/modules/Order/utils/orderCollectionIdentity.js +7 -2
- package/dist/modules/Order/utils.js +10 -6
- package/dist/modules/Payment/index.d.ts +2 -0
- package/dist/modules/Payment/index.js +78 -49
- package/dist/modules/Payment/types.d.ts +104 -25
- package/dist/modules/Payment/types.js +17 -0
- package/dist/modules/Payment/walletpass.d.ts +38 -1
- package/dist/modules/Payment/walletpass.js +917 -114
- package/dist/modules/Rules/index.d.ts +3 -0
- package/dist/modules/Rules/index.js +100 -70
- package/dist/server/index.d.ts +25 -0
- package/dist/server/index.js +1993 -1061
- package/dist/server/modules/index.d.ts +1 -1
- package/dist/server/modules/order/index.d.ts +70 -4
- package/dist/server/modules/order/index.js +1816 -728
- package/dist/server/modules/order/types.d.ts +25 -3
- package/dist/server/modules/order/types.js +7 -1
- package/dist/solution/BaseSales/index.d.ts +104 -5
- package/dist/solution/BaseSales/index.js +1767 -436
- package/dist/solution/BaseSales/types.d.ts +55 -1
- package/dist/solution/BaseSales/types.js +2 -1
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
- package/dist/solution/BaseSales/utils/cartPromotion.js +94 -32
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +7 -4
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +21 -5
- package/dist/solution/BookingTicket/index.js +139 -56
- package/dist/solution/BookingTicket/types.d.ts +1 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +8 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +173 -83
- package/dist/solution/Sales/index.d.ts +2 -0
- package/dist/solution/Sales/index.js +26 -4
- package/dist/solution/ScanOrder/index.js +31 -20
- package/dist/solution/VenueBooking/index.d.ts +1 -0
- package/dist/solution/VenueBooking/index.js +30 -19
- package/dist/types/index.d.ts +1 -0
- package/dist/utils/payment-number.d.ts +9 -0
- package/dist/utils/payment-number.js +69 -0
- package/lib/core/index.d.ts +2 -0
- package/lib/core/index.js +4 -0
- package/lib/model/strategy/adapter/promotion/adapter.d.ts +4 -0
- package/lib/model/strategy/adapter/promotion/adapter.js +20 -0
- package/lib/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
- package/lib/model/strategy/adapter/promotion/evaluator.js +235 -0
- package/lib/model/strategy/adapter/promotion/examples.d.ts +86 -0
- package/lib/model/strategy/adapter/promotion/examples.js +91 -0
- package/lib/model/strategy/adapter/promotion/index.d.ts +1 -1
- package/lib/model/strategy/adapter/promotion/index.js +2 -0
- package/lib/model/strategy/adapter/promotion/type.d.ts +90 -2
- package/lib/model/strategy/adapter/promotion/type.js +2 -0
- package/lib/modules/OpenData/index.d.ts +2 -0
- package/lib/modules/OpenData/index.js +5 -0
- package/lib/modules/Order/index.d.ts +28 -8
- package/lib/modules/Order/index.js +252 -84
- package/lib/modules/Order/payment-utils.d.ts +26 -0
- package/lib/modules/Order/payment-utils.js +224 -0
- package/lib/modules/Order/types.d.ts +35 -1
- package/lib/modules/Order/utils/orderCollectionIdentity.js +3 -0
- package/lib/modules/Order/utils.js +11 -4
- package/lib/modules/Payment/index.d.ts +2 -0
- package/lib/modules/Payment/index.js +33 -12
- package/lib/modules/Payment/types.d.ts +104 -25
- package/lib/modules/Payment/types.js +1 -0
- package/lib/modules/Payment/walletpass.d.ts +38 -1
- package/lib/modules/Payment/walletpass.js +730 -21
- package/lib/modules/Rules/index.d.ts +3 -0
- package/lib/modules/Rules/index.js +38 -9
- package/lib/server/index.d.ts +25 -0
- package/lib/server/index.js +726 -31
- package/lib/server/modules/index.d.ts +1 -1
- package/lib/server/modules/order/index.d.ts +70 -4
- package/lib/server/modules/order/index.js +818 -69
- package/lib/server/modules/order/types.d.ts +25 -3
- package/lib/server/modules/order/types.js +1 -0
- package/lib/solution/BaseSales/index.d.ts +104 -5
- package/lib/solution/BaseSales/index.js +858 -27
- package/lib/solution/BaseSales/types.d.ts +55 -1
- package/lib/solution/BaseSales/types.js +2 -1
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
- package/lib/solution/BaseSales/utils/cartPromotion.js +66 -12
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +4 -3
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +21 -5
- package/lib/solution/BookingTicket/index.js +64 -13
- package/lib/solution/BookingTicket/types.d.ts +1 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +8 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +37 -5
- package/lib/solution/Sales/index.d.ts +2 -0
- package/lib/solution/Sales/index.js +20 -6
- package/lib/solution/ScanOrder/index.js +8 -0
- package/lib/solution/VenueBooking/index.d.ts +1 -0
- package/lib/solution/VenueBooking/index.js +8 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/utils/payment-number.d.ts +9 -0
- package/lib/utils/payment-number.js +64 -0
- package/package.json +1 -1
|
@@ -37,6 +37,7 @@ var import_dayjs = __toESM(require("dayjs"));
|
|
|
37
37
|
var import_BaseModule = require("../../../modules/BaseModule");
|
|
38
38
|
var import_orderCollectionIdentity = require("../../../modules/Order/utils/orderCollectionIdentity");
|
|
39
39
|
var import_types = require("./types");
|
|
40
|
+
var import_payment_utils = require("../../../modules/Order/payment-utils");
|
|
40
41
|
var INDEXDB_STORE_NAME = "orders";
|
|
41
42
|
var ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = "server_order_last_full_fetch_at";
|
|
42
43
|
var ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = "order_sync_throttle_ms";
|
|
@@ -46,10 +47,13 @@ var ORDER_SILENT_REFRESH_MIN_INTERVAL_MS = 3e4;
|
|
|
46
47
|
var ORDER_BUSINESS_WRITE_SOURCES = /* @__PURE__ */ new Set([
|
|
47
48
|
"upsertOrdersFromRemote",
|
|
48
49
|
"upsertPendingSyncOrders",
|
|
50
|
+
"upsertLocalDraftOrders",
|
|
49
51
|
"overwriteExistingOrder",
|
|
50
|
-
"markOrderSyncedByExternalSaleNumber"
|
|
52
|
+
"markOrderSyncedByExternalSaleNumber",
|
|
53
|
+
"updateLocalPayment"
|
|
51
54
|
]);
|
|
52
55
|
var ORDER_MERGE_SELF_CHECK = false;
|
|
56
|
+
var PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER = "__pisell_os_pending_payment_without_unique_number__";
|
|
53
57
|
var ORDER_AUTHORITATIVE_COLLECTION_FIELDS = ["products", "bookings", "payments"];
|
|
54
58
|
var ORDER_COLLECTION_KIND_BY_FIELD = {
|
|
55
59
|
products: "product",
|
|
@@ -85,6 +89,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
85
89
|
};
|
|
86
90
|
await this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, payload);
|
|
87
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* 广播远端商品成员增删。监听器异常必须与订单落库和原有订单广播隔离。
|
|
94
|
+
*/
|
|
95
|
+
async emitRemoteProductMembershipChanges(changes) {
|
|
96
|
+
for (const payload of changes) {
|
|
97
|
+
try {
|
|
98
|
+
await this.core.effects.emit(import_types.OrderHooks.onRemoteProductMembershipChanged, payload);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
this.logError("广播远端订单商品成员变更失败", {
|
|
101
|
+
order_id: payload.order_id,
|
|
102
|
+
source: payload.source,
|
|
103
|
+
added_product_count: payload.added_product_keys.length,
|
|
104
|
+
removed_product_count: payload.removed_product_keys.length,
|
|
105
|
+
error: error instanceof Error ? error.message : String(error)
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
88
110
|
async initialize(core, options) {
|
|
89
111
|
var _a;
|
|
90
112
|
this.core = core;
|
|
@@ -100,7 +122,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
100
122
|
this.updateCreateStore();
|
|
101
123
|
}
|
|
102
124
|
if (Array.isArray((_a = options == null ? void 0 : options.initialState) == null ? void 0 : _a.list)) {
|
|
103
|
-
this.store.list =
|
|
125
|
+
this.store.list = this.normalizeOrdersForMemoryList(
|
|
126
|
+
options.initialState.list,
|
|
127
|
+
"initialState"
|
|
128
|
+
);
|
|
104
129
|
this.syncOrdersMap();
|
|
105
130
|
this.emitOrdersChanged([], "initialState");
|
|
106
131
|
} else {
|
|
@@ -166,7 +191,35 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
166
191
|
* 仅记录计数与订单标识,不输出商品、预约、支付或客户明细。
|
|
167
192
|
*/
|
|
168
193
|
normalizeOrderCollectionsForIngress(order, source) {
|
|
169
|
-
const
|
|
194
|
+
const sourceOrder = (0, import_lodash_es.cloneDeep)(order);
|
|
195
|
+
const sourceOrderRecord = sourceOrder;
|
|
196
|
+
if (Array.isArray(sourceOrderRecord.payments)) {
|
|
197
|
+
sourceOrderRecord.payments = sourceOrderRecord.payments.map((payment) => {
|
|
198
|
+
if (!(0, import_payment_utils.isPendingOrderPayment)(payment) || (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment).some((key) => key.startsWith("unique_payment_number:"))) {
|
|
199
|
+
return payment;
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
...payment,
|
|
203
|
+
[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER]: true
|
|
204
|
+
};
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
const result = (0, import_orderCollectionIdentity.normalizeOrderCollections)(sourceOrder);
|
|
208
|
+
const normalizedOrderRecord = result.order;
|
|
209
|
+
if (Array.isArray(normalizedOrderRecord.payments)) {
|
|
210
|
+
normalizedOrderRecord.payments = normalizedOrderRecord.payments.map(
|
|
211
|
+
(payment) => {
|
|
212
|
+
if (!(payment == null ? void 0 : payment[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER]))
|
|
213
|
+
return payment;
|
|
214
|
+
const nextPayment = { ...payment };
|
|
215
|
+
const metadata = { ...nextPayment.metadata || {} };
|
|
216
|
+
delete metadata.unique_payment_number;
|
|
217
|
+
delete nextPayment[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER];
|
|
218
|
+
nextPayment.metadata = metadata;
|
|
219
|
+
return nextPayment;
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
}
|
|
170
223
|
const kinds = ["product", "booking", "payment"];
|
|
171
224
|
const hasChanges = kinds.some((kind) => {
|
|
172
225
|
const stats = result.stats[kind];
|
|
@@ -202,9 +255,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
202
255
|
/**
|
|
203
256
|
* incoming 决定权威成员集合;同一持久化行仍从 existing 补齐 incoming 省略的本地展示字段。
|
|
204
257
|
*/
|
|
205
|
-
mergeAuthoritativeOrderCollection(field, existing, incoming, uidRemaps = []) {
|
|
258
|
+
mergeAuthoritativeOrderCollection(field, existing, incoming, uidRemaps = [], options = {}) {
|
|
206
259
|
const kind = ORDER_COLLECTION_KIND_BY_FIELD[field];
|
|
207
260
|
const existingItems = Array.isArray(existing) ? existing : [];
|
|
261
|
+
if (field === "payments" && options.preserveIdentifiedPendingPayments) {
|
|
262
|
+
return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(
|
|
263
|
+
existingItems,
|
|
264
|
+
incoming,
|
|
265
|
+
{ preserveUnmatchedExistingWhen: import_payment_utils.isIdentifiedPendingOrderPayment }
|
|
266
|
+
);
|
|
267
|
+
}
|
|
208
268
|
return incoming.map((incomingItem) => {
|
|
209
269
|
const existingItem = existingItems.find(
|
|
210
270
|
(item) => (0, import_orderCollectionIdentity.isSameOrderCollectionItem)(kind, item, incomingItem)
|
|
@@ -272,7 +332,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
272
332
|
* @example
|
|
273
333
|
* const { toWrite, skipped } = this.filterRedundantPatchOrders('pubsub.bodyUpsert', orders, mergeActions)
|
|
274
334
|
*/
|
|
275
|
-
filterRedundantPatchOrders(source, orders, mergeActions) {
|
|
335
|
+
filterRedundantPatchOrders(source, orders, mergeActions, forceWriteStorageKeys = /* @__PURE__ */ new Set()) {
|
|
276
336
|
const eligibleSkipSources = /* @__PURE__ */ new Set(["pubsub.bodyUpsert", "pubsub.httpRefresh"]);
|
|
277
337
|
if (!eligibleSkipSources.has(source)) {
|
|
278
338
|
return { toWrite: orders, skipped: [] };
|
|
@@ -292,6 +352,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
292
352
|
toWrite.push(order);
|
|
293
353
|
continue;
|
|
294
354
|
}
|
|
355
|
+
if (forceWriteStorageKeys.has(storageKey)) {
|
|
356
|
+
toWrite.push(order);
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
295
359
|
const recent = this.recentSqliteWriteByStorageKey.get(storageKey);
|
|
296
360
|
if (recent && ORDER_BUSINESS_WRITE_SOURCES.has(recent.source) && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
|
|
297
361
|
skipped.push({
|
|
@@ -460,17 +524,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
460
524
|
return DEFAULT_ORDER_SYNC_THROTTLE_MS;
|
|
461
525
|
}
|
|
462
526
|
async preload() {
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
this.store.list = (0, import_lodash_es.cloneDeep)(orders);
|
|
469
|
-
this.syncOrdersMap();
|
|
470
|
-
this.emitOrdersChanged([], "preload");
|
|
471
|
-
this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
472
|
-
};
|
|
473
|
-
getData();
|
|
527
|
+
const orders = await this.loadOrdersByServer();
|
|
528
|
+
this.store.list = (0, import_lodash_es.cloneDeep)(orders);
|
|
529
|
+
this.syncOrdersMap();
|
|
530
|
+
await this.emitOrdersChanged([], "preload");
|
|
531
|
+
await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
474
532
|
}
|
|
475
533
|
getOrders() {
|
|
476
534
|
return this.store.list;
|
|
@@ -482,6 +540,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
482
540
|
getOrderByOrderId(orderId) {
|
|
483
541
|
return this.store.map.get(this.getIdKey(orderId));
|
|
484
542
|
}
|
|
543
|
+
buildLocalPaymentOrderLogContext(order) {
|
|
544
|
+
if (!order)
|
|
545
|
+
return {};
|
|
546
|
+
return {
|
|
547
|
+
order_id: order.order_id ?? null,
|
|
548
|
+
external_sale_number: order.external_sale_number ?? null,
|
|
549
|
+
order_number: order.order_number ?? null,
|
|
550
|
+
shop_order_number: order.shop_order_number ?? null,
|
|
551
|
+
shop_full_order_number: order.shop_full_order_number ?? null,
|
|
552
|
+
order_status: order.status ?? null,
|
|
553
|
+
payment_status: order.payment_status ?? null,
|
|
554
|
+
is_draft_order: Number(order.is_draft_order || 0),
|
|
555
|
+
need_sync: Number(order.need_sync || 0),
|
|
556
|
+
platform: order.platform ?? null,
|
|
557
|
+
business_code: order.business_code ?? null,
|
|
558
|
+
order_sales_channel: order.order_sales_channel ?? null,
|
|
559
|
+
sales_channel: order.sales_channel ?? null,
|
|
560
|
+
order_type: order.type ?? null,
|
|
561
|
+
payments_count: Array.isArray(order.payments) ? order.payments.length : 0
|
|
562
|
+
};
|
|
563
|
+
}
|
|
485
564
|
getLocalOrderFromMemoryByLookup(lookup) {
|
|
486
565
|
const key = this.getIdKey(lookup);
|
|
487
566
|
const memoryOrderById = this.store.map.get(key);
|
|
@@ -490,28 +569,200 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
490
569
|
const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
|
|
491
570
|
return memoryOrder || null;
|
|
492
571
|
}
|
|
493
|
-
async getLocalOrderByLookup(lookup) {
|
|
572
|
+
async getLocalOrderByLookup(lookup, options = {}) {
|
|
494
573
|
const key = this.getIdKey(lookup);
|
|
574
|
+
const logContext = {
|
|
575
|
+
operation_id: options.operationId,
|
|
576
|
+
lookup: key,
|
|
577
|
+
memory_order_count: this.store.list.length
|
|
578
|
+
};
|
|
579
|
+
if (options.operationId) {
|
|
580
|
+
this.logInfo("getLocalOrderByLookup-localPayment-开始", logContext);
|
|
581
|
+
}
|
|
495
582
|
const memoryOrderById = this.store.map.get(key);
|
|
496
|
-
if (memoryOrderById)
|
|
583
|
+
if (memoryOrderById) {
|
|
584
|
+
if (options.operationId) {
|
|
585
|
+
this.logInfo("getLocalOrderByLookup-localPayment-命中内存映射", {
|
|
586
|
+
...logContext,
|
|
587
|
+
...this.buildLocalPaymentOrderLogContext(memoryOrderById)
|
|
588
|
+
});
|
|
589
|
+
}
|
|
497
590
|
return memoryOrderById;
|
|
591
|
+
}
|
|
498
592
|
const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
|
|
499
|
-
if (memoryOrder)
|
|
593
|
+
if (memoryOrder) {
|
|
594
|
+
if (options.operationId) {
|
|
595
|
+
this.logInfo("getLocalOrderByLookup-localPayment-命中内存列表", {
|
|
596
|
+
...logContext,
|
|
597
|
+
...this.buildLocalPaymentOrderLogContext(memoryOrder)
|
|
598
|
+
});
|
|
599
|
+
}
|
|
500
600
|
return memoryOrder;
|
|
601
|
+
}
|
|
602
|
+
if (options.operationId) {
|
|
603
|
+
this.logInfo("getLocalOrderByLookup-localPayment-开始读取SQLite", logContext);
|
|
604
|
+
}
|
|
501
605
|
const orders = await this.loadOrdersFromSQLite();
|
|
502
606
|
const localOrder = orders.find((order) => this.isOrderLookupMatch(order, key));
|
|
503
|
-
if (!localOrder)
|
|
607
|
+
if (!localOrder) {
|
|
608
|
+
if (options.operationId) {
|
|
609
|
+
this.logWarning("getLocalOrderByLookup-localPayment-SQLite未命中", {
|
|
610
|
+
...logContext,
|
|
611
|
+
sqlite_order_count: orders.length
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
return null;
|
|
615
|
+
}
|
|
616
|
+
this.store.list = this.normalizeOrdersForMemoryList(
|
|
617
|
+
orders,
|
|
618
|
+
"getLocalOrderByLookup.sqliteMemory"
|
|
619
|
+
);
|
|
620
|
+
this.syncOrdersMap();
|
|
621
|
+
const normalizedOrder = this.normalizeOrderForMemoryList(localOrder);
|
|
622
|
+
if (options.operationId) {
|
|
623
|
+
this.logInfo("getLocalOrderByLookup-localPayment-SQLite命中", {
|
|
624
|
+
...logContext,
|
|
625
|
+
sqlite_order_count: orders.length,
|
|
626
|
+
...this.buildLocalPaymentOrderLogContext(normalizedOrder)
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
return normalizedOrder;
|
|
630
|
+
}
|
|
631
|
+
async getLocalPayment(params) {
|
|
632
|
+
const logContext = {
|
|
633
|
+
operation_id: params.operationId,
|
|
634
|
+
sale_id: params.saleId,
|
|
635
|
+
payment_number: params.paymentNumber
|
|
636
|
+
};
|
|
637
|
+
this.logInfo("getLocalPayment-开始", logContext);
|
|
638
|
+
try {
|
|
639
|
+
const order = await this.getLocalOrderByLookup(params.saleId, {
|
|
640
|
+
operationId: params.operationId
|
|
641
|
+
});
|
|
642
|
+
if (!order) {
|
|
643
|
+
this.logWarning("getLocalPayment-订单未命中", logContext);
|
|
644
|
+
return null;
|
|
645
|
+
}
|
|
646
|
+
const payments = order.payments || [];
|
|
647
|
+
const match = (0, import_payment_utils.resolveOrderPaymentIdentity)(
|
|
648
|
+
payments,
|
|
649
|
+
params.paymentNumber,
|
|
650
|
+
"compat"
|
|
651
|
+
);
|
|
652
|
+
if (!match) {
|
|
653
|
+
this.logWarning("getLocalPayment-支付项未命中", {
|
|
654
|
+
...logContext,
|
|
655
|
+
...this.buildLocalPaymentOrderLogContext(order),
|
|
656
|
+
payments
|
|
657
|
+
});
|
|
658
|
+
return null;
|
|
659
|
+
}
|
|
660
|
+
this.logInfo("getLocalPayment-支付项命中", {
|
|
661
|
+
...logContext,
|
|
662
|
+
...this.buildLocalPaymentOrderLogContext(order),
|
|
663
|
+
matched_by: match.matchedBy,
|
|
664
|
+
payment_index: match.index,
|
|
665
|
+
payment: match.payment
|
|
666
|
+
});
|
|
667
|
+
return {
|
|
668
|
+
order,
|
|
669
|
+
payment: match.payment,
|
|
670
|
+
paymentIndex: match.index,
|
|
671
|
+
matchedBy: match.matchedBy
|
|
672
|
+
};
|
|
673
|
+
} catch (error) {
|
|
674
|
+
this.logError("getLocalPayment-查询失败", {
|
|
675
|
+
...logContext,
|
|
676
|
+
error: error instanceof Error ? error.message : String(error)
|
|
677
|
+
});
|
|
678
|
+
throw error;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
async updateLocalPayment(params) {
|
|
682
|
+
const logContext = {
|
|
683
|
+
operation_id: params.operationId,
|
|
684
|
+
sale_id: params.saleId,
|
|
685
|
+
payment_number: params.paymentNumber,
|
|
686
|
+
incoming_payment_update: params.updates
|
|
687
|
+
};
|
|
688
|
+
this.logInfo("updateLocalPayment-开始", logContext);
|
|
689
|
+
const found = await this.getLocalPayment(params);
|
|
690
|
+
if (!found) {
|
|
691
|
+
this.logWarning("updateLocalPayment-支付项未命中", logContext);
|
|
692
|
+
return null;
|
|
693
|
+
}
|
|
694
|
+
const previousPayment = (0, import_lodash_es.cloneDeep)(found.payment);
|
|
695
|
+
const nextPayment = (0, import_payment_utils.mergeOrderPaymentRecord)(found.payment, {
|
|
696
|
+
...params.updates,
|
|
697
|
+
updated_at: params.updates.updated_at || (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
|
|
698
|
+
});
|
|
699
|
+
const nextOrder = {
|
|
700
|
+
...found.order,
|
|
701
|
+
payments: (found.order.payments || []).map((payment, index) => index === found.paymentIndex ? nextPayment : payment),
|
|
702
|
+
updated_at: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
|
|
703
|
+
};
|
|
704
|
+
const paymentContext = {
|
|
705
|
+
...logContext,
|
|
706
|
+
matched_by: found.matchedBy,
|
|
707
|
+
payment_index: found.paymentIndex,
|
|
708
|
+
...this.buildLocalPaymentOrderLogContext(nextOrder),
|
|
709
|
+
previous_payment: previousPayment,
|
|
710
|
+
payment: nextPayment
|
|
711
|
+
};
|
|
712
|
+
this.logInfo("updateLocalPayment-支付项合并完成", paymentContext);
|
|
713
|
+
const targetIndex = this.findOrderIndexByIdentity(this.store.list, found.order);
|
|
714
|
+
const shouldKeepInMemory = this.shouldKeepOrderInMemory(nextOrder);
|
|
715
|
+
if (targetIndex < 0 && shouldKeepInMemory) {
|
|
716
|
+
this.logError("updateLocalPayment-订单Store索引未命中", paymentContext);
|
|
504
717
|
return null;
|
|
505
|
-
|
|
718
|
+
}
|
|
719
|
+
const previousList = this.store.list;
|
|
720
|
+
this.store.list = shouldKeepInMemory ? this.store.list.map((order, index) => index === targetIndex ? nextOrder : order) : this.store.list.filter((_, index) => index !== targetIndex);
|
|
506
721
|
this.syncOrdersMap();
|
|
507
|
-
|
|
722
|
+
const storageOrder = this.withoutSyntheticDraftOrderId(nextOrder);
|
|
723
|
+
try {
|
|
724
|
+
this.logInfo("updateLocalPayment-SQLite写入开始", {
|
|
725
|
+
...paymentContext,
|
|
726
|
+
storage_order_id: storageOrder.order_id ?? null
|
|
727
|
+
});
|
|
728
|
+
await this.updateOrderInSQLite(storageOrder, "updateLocalPayment", { throwOnError: true });
|
|
729
|
+
this.logInfo("updateLocalPayment-SQLite写入完成", {
|
|
730
|
+
...paymentContext,
|
|
731
|
+
storage_order_id: storageOrder.order_id ?? null
|
|
732
|
+
});
|
|
733
|
+
} catch (error) {
|
|
734
|
+
this.store.list = previousList;
|
|
735
|
+
this.syncOrdersMap();
|
|
736
|
+
this.logError("updateLocalPayment-SQLite写入失败并回滚内存", {
|
|
737
|
+
...paymentContext,
|
|
738
|
+
storage_order_id: storageOrder.order_id ?? null,
|
|
739
|
+
error: error instanceof Error ? error.message : String(error)
|
|
740
|
+
});
|
|
741
|
+
throw error;
|
|
742
|
+
}
|
|
743
|
+
if (shouldKeepInMemory || targetIndex >= 0) {
|
|
744
|
+
await this.emitOrdersChanged(
|
|
745
|
+
shouldKeepInMemory ? [nextOrder] : [],
|
|
746
|
+
shouldKeepInMemory ? "updateLocalPayment" : "updateLocalPayment.sqliteOnlyDraft"
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
this.logInfo("updateLocalPayment-变更事件完成", paymentContext);
|
|
750
|
+
return { order: nextOrder, payment: nextPayment, previousPayment };
|
|
508
751
|
}
|
|
509
752
|
async loadOrdersByServer() {
|
|
510
753
|
var _a;
|
|
511
754
|
let orderList = [];
|
|
755
|
+
const protectedOrdersBeforeRemoteFetch = (await this.loadOrdersFromSQLite()).filter(
|
|
756
|
+
(order) => this.shouldProtectLocalOrderFromRemoteSnapshot(order)
|
|
757
|
+
);
|
|
512
758
|
this.logInfo("loadOrdersByServer-开始", {
|
|
513
759
|
hasOrderDataSource: !!this.orderDataSource,
|
|
514
|
-
query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null
|
|
760
|
+
query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null,
|
|
761
|
+
protectedLocalOrderCount: protectedOrdersBeforeRemoteFetch.length,
|
|
762
|
+
protectedPendingPaymentCount: protectedOrdersBeforeRemoteFetch.reduce(
|
|
763
|
+
(count, order) => count + this.getIdentifiedPendingPayments(order).length,
|
|
764
|
+
0
|
|
765
|
+
)
|
|
515
766
|
});
|
|
516
767
|
if (this.orderDataSource) {
|
|
517
768
|
try {
|
|
@@ -531,10 +782,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
531
782
|
return this.store.list;
|
|
532
783
|
}
|
|
533
784
|
}
|
|
534
|
-
const mergedOrders = await this.replaceOrdersSnapshotInSQLite(
|
|
535
|
-
|
|
785
|
+
const mergedOrders = await this.replaceOrdersSnapshotInSQLite(
|
|
786
|
+
orderList,
|
|
787
|
+
"loadOrdersByServer",
|
|
788
|
+
protectedOrdersBeforeRemoteFetch
|
|
789
|
+
);
|
|
790
|
+
const memoryOrders = this.normalizeOrdersForMemoryList(
|
|
791
|
+
mergedOrders,
|
|
792
|
+
"loadOrdersByServer.memory"
|
|
793
|
+
);
|
|
536
794
|
this.logInfo("loadOrdersByServer-结束", {
|
|
537
|
-
count: memoryOrders.length
|
|
795
|
+
count: memoryOrders.length,
|
|
796
|
+
persistedCount: mergedOrders.length,
|
|
797
|
+
sqliteOnlyDraftCount: mergedOrders.length - memoryOrders.length
|
|
538
798
|
});
|
|
539
799
|
await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded, memoryOrders);
|
|
540
800
|
return memoryOrders;
|
|
@@ -554,18 +814,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
554
814
|
try {
|
|
555
815
|
this.updateCreateStore();
|
|
556
816
|
const orders = await this.loadOrdersByServer();
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
});
|
|
566
|
-
} else {
|
|
567
|
-
this.logInfo("silentRefresh: 服务器未返回数据");
|
|
568
|
-
}
|
|
817
|
+
this.store.list = (0, import_lodash_es.cloneDeep)(orders);
|
|
818
|
+
this.syncOrdersMap();
|
|
819
|
+
await this.emitOrdersChanged([], "silentRefresh");
|
|
820
|
+
await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
821
|
+
this.logInfo("silentRefresh 完成", {
|
|
822
|
+
orderCount: orders.length,
|
|
823
|
+
duration: `${Date.now() - startTime}ms`
|
|
824
|
+
});
|
|
569
825
|
return this.store.list;
|
|
570
826
|
} catch (error) {
|
|
571
827
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -579,6 +835,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
579
835
|
normalizeOrderForMemoryList(order, source = "normalizeOrderForMemoryList") {
|
|
580
836
|
const normalizedOrder = this.normalizeOrderCollectionsForIngress(order, source);
|
|
581
837
|
const externalSaleNumber = normalizedOrder == null ? void 0 : normalizedOrder.external_sale_number;
|
|
838
|
+
if (this.isDraftOrder(normalizedOrder) && !this.hasRealOrderId(normalizedOrder)) {
|
|
839
|
+
return normalizedOrder;
|
|
840
|
+
}
|
|
582
841
|
if ((normalizedOrder == null ? void 0 : normalizedOrder.order_id) !== void 0 && (normalizedOrder == null ? void 0 : normalizedOrder.order_id) !== null && (normalizedOrder == null ? void 0 : normalizedOrder.order_id) !== "") {
|
|
583
842
|
return normalizedOrder;
|
|
584
843
|
}
|
|
@@ -590,6 +849,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
590
849
|
order_id: externalSaleNumber
|
|
591
850
|
};
|
|
592
851
|
}
|
|
852
|
+
normalizeOrdersForMemoryList(orders, source) {
|
|
853
|
+
return orders.map((order) => this.normalizeOrderForMemoryList(order, source)).filter((order) => this.shouldKeepOrderInMemory(order));
|
|
854
|
+
}
|
|
855
|
+
hasRealOrderId(order) {
|
|
856
|
+
if (!order || this.isBlankIdentityValue(order.order_id))
|
|
857
|
+
return false;
|
|
858
|
+
const externalSaleNumber = order.external_sale_number;
|
|
859
|
+
return !(this.isDraftOrder(order) && !this.isBlankIdentityValue(externalSaleNumber) && String(order.order_id) === String(externalSaleNumber));
|
|
860
|
+
}
|
|
861
|
+
shouldKeepOrderInMemory(order) {
|
|
862
|
+
return !this.isDraftOrder(order) || this.hasRealOrderId(order);
|
|
863
|
+
}
|
|
864
|
+
withoutSyntheticDraftOrderId(order) {
|
|
865
|
+
const externalSaleNumber = order.external_sale_number;
|
|
866
|
+
if (Number(order.is_draft_order || 0) !== 1 || order.order_id === void 0 || externalSaleNumber === void 0 || String(order.order_id) !== String(externalSaleNumber)) {
|
|
867
|
+
return order;
|
|
868
|
+
}
|
|
869
|
+
const next = { ...order };
|
|
870
|
+
delete next.order_id;
|
|
871
|
+
return next;
|
|
872
|
+
}
|
|
593
873
|
/**
|
|
594
874
|
* 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
|
|
595
875
|
* 适用于"按 order_id 主动刷新本地订单详情"的代理场景。
|
|
@@ -638,13 +918,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
638
918
|
* 将远端拉取的订单合并进本地 store(已存在则更新,不存在则追加),落库并 emit onOrdersChanged。
|
|
639
919
|
* 供 /update/localOrder 等在「本地尚无该单」时写入新建单。
|
|
640
920
|
*/
|
|
641
|
-
async upsertOrdersFromRemote(freshOrders) {
|
|
921
|
+
async upsertOrdersFromRemote(freshOrders, source = "upsertOrdersFromRemote") {
|
|
642
922
|
if (!(freshOrders == null ? void 0 : freshOrders.length)) {
|
|
643
923
|
this.logInfo("upsertOrdersFromRemote-订单列表为空", {});
|
|
644
924
|
return;
|
|
645
925
|
}
|
|
646
|
-
this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length });
|
|
647
|
-
await this.mergeOrdersToStore(freshOrders,
|
|
926
|
+
this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length, source });
|
|
927
|
+
await this.mergeOrdersToStore(freshOrders, source);
|
|
648
928
|
}
|
|
649
929
|
async markOrderSyncedByExternalSaleNumber(params) {
|
|
650
930
|
const externalSaleNumber = params.externalSaleNumber;
|
|
@@ -670,7 +950,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
670
950
|
...existing,
|
|
671
951
|
...params.patch || {},
|
|
672
952
|
external_sale_number: existing.external_sale_number ?? externalSaleNumber,
|
|
673
|
-
need_sync: 0
|
|
953
|
+
need_sync: 0,
|
|
954
|
+
is_draft_order: 0
|
|
674
955
|
});
|
|
675
956
|
const storageKey = this.getOrderStorageKey(nextOrder) || key;
|
|
676
957
|
this.store.list = this.store.list.map((order, index) => {
|
|
@@ -695,7 +976,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
695
976
|
* 将本地待同步订单按 SQLite storage key 合并进 store 并落库。
|
|
696
977
|
* checkout 离线兜底可能没有 order_id,但通常会有 external_sale_number。
|
|
697
978
|
*/
|
|
698
|
-
async upsertPendingSyncOrders(pendingOrders) {
|
|
979
|
+
async upsertPendingSyncOrders(pendingOrders, options = {}) {
|
|
699
980
|
if (!(pendingOrders == null ? void 0 : pendingOrders.length)) {
|
|
700
981
|
this.logInfo("upsertPendingSyncOrders-订单列表为空", {});
|
|
701
982
|
return;
|
|
@@ -707,14 +988,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
707
988
|
order,
|
|
708
989
|
"upsertPendingSyncOrders.incoming"
|
|
709
990
|
);
|
|
710
|
-
const
|
|
991
|
+
const pendingOrder = {
|
|
992
|
+
...normalizedOrder,
|
|
993
|
+
need_sync: 1,
|
|
994
|
+
is_draft_order: 0
|
|
995
|
+
};
|
|
996
|
+
const storageKey = this.getOrderStorageKey(pendingOrder);
|
|
711
997
|
if (!storageKey)
|
|
712
998
|
continue;
|
|
713
|
-
pendingMap.set(storageKey,
|
|
999
|
+
pendingMap.set(storageKey, pendingOrder);
|
|
714
1000
|
memoryPendingMap.set(
|
|
715
1001
|
storageKey,
|
|
716
1002
|
this.normalizeOrderForMemoryList(
|
|
717
|
-
|
|
1003
|
+
pendingOrder,
|
|
718
1004
|
"upsertPendingSyncOrders.memory"
|
|
719
1005
|
)
|
|
720
1006
|
);
|
|
@@ -745,7 +1031,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
745
1031
|
if (matchIndex >= 0) {
|
|
746
1032
|
const existingOrder = updatedList[matchIndex];
|
|
747
1033
|
const mergedOrder = this.mergeOrderRecords(existingOrder, pendingOrder);
|
|
748
|
-
|
|
1034
|
+
const nextOrder = {
|
|
1035
|
+
...mergedOrder,
|
|
1036
|
+
need_sync: 1,
|
|
1037
|
+
is_draft_order: 0
|
|
1038
|
+
};
|
|
1039
|
+
updatedList[matchIndex] = nextOrder;
|
|
749
1040
|
const pendingSnapshot = pendingMap.get(storageKey);
|
|
750
1041
|
if (pendingSnapshot) {
|
|
751
1042
|
pendingMap.set(
|
|
@@ -753,7 +1044,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
753
1044
|
this.reconcileOverwriteOrderCollections(existingOrder, pendingSnapshot)
|
|
754
1045
|
);
|
|
755
1046
|
}
|
|
756
|
-
this.registerOrderIdentityKeys(identityKeyToIndex,
|
|
1047
|
+
this.registerOrderIdentityKeys(identityKeyToIndex, nextOrder, matchIndex);
|
|
757
1048
|
mergeActions[storageKey] = "update";
|
|
758
1049
|
continue;
|
|
759
1050
|
}
|
|
@@ -763,15 +1054,131 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
763
1054
|
mergeActions[storageKey] = "insert";
|
|
764
1055
|
}
|
|
765
1056
|
const patchedOrders = [...pendingMap.values()];
|
|
1057
|
+
const previousList = this.store.list;
|
|
766
1058
|
this.store.list = this.runOrderStoreSelfCheck(updatedList, "upsertPendingSyncOrders.store");
|
|
767
1059
|
this.syncOrdersMap();
|
|
768
|
-
|
|
1060
|
+
try {
|
|
1061
|
+
await this.patchOrdersInSQLite(
|
|
1062
|
+
patchedOrders,
|
|
1063
|
+
"upsertPendingSyncOrders",
|
|
1064
|
+
mergeActions,
|
|
1065
|
+
options
|
|
1066
|
+
);
|
|
1067
|
+
} catch (error) {
|
|
1068
|
+
this.store.list = previousList;
|
|
1069
|
+
this.syncOrdersMap();
|
|
1070
|
+
throw error;
|
|
1071
|
+
}
|
|
769
1072
|
this.logInfo("upsertPendingSyncOrders-结束", {
|
|
770
1073
|
count: patchedOrders.length,
|
|
771
1074
|
storeOrderCountAfter: this.store.list.length
|
|
772
1075
|
});
|
|
773
1076
|
await this.emitOrdersChanged(patchedOrders, "upsertPendingSyncOrders");
|
|
774
1077
|
}
|
|
1078
|
+
/**
|
|
1079
|
+
* 将 POS 草稿订单按 SQLite storage key 落库。
|
|
1080
|
+
* 只有具备真实 order_id 的草稿进入 store;其余草稿仅供本地恢复查询。
|
|
1081
|
+
*/
|
|
1082
|
+
async upsertLocalDraftOrders(draftOrders) {
|
|
1083
|
+
if (!(draftOrders == null ? void 0 : draftOrders.length)) {
|
|
1084
|
+
this.logInfo("upsertLocalDraftOrders-订单列表为空", {});
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
const draftMap = /* @__PURE__ */ new Map();
|
|
1088
|
+
const memoryDraftMap = /* @__PURE__ */ new Map();
|
|
1089
|
+
for (const order of draftOrders) {
|
|
1090
|
+
const draftOrder = {
|
|
1091
|
+
...order,
|
|
1092
|
+
need_sync: 0,
|
|
1093
|
+
is_draft_order: 1
|
|
1094
|
+
};
|
|
1095
|
+
const storageKey = this.getOrderStorageKey(draftOrder);
|
|
1096
|
+
if (!storageKey)
|
|
1097
|
+
continue;
|
|
1098
|
+
draftMap.set(storageKey, draftOrder);
|
|
1099
|
+
const memoryDraftOrder = this.normalizeOrderForMemoryList(draftOrder);
|
|
1100
|
+
if (this.shouldKeepOrderInMemory(memoryDraftOrder)) {
|
|
1101
|
+
memoryDraftMap.set(storageKey, memoryDraftOrder);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
if (draftMap.size === 0) {
|
|
1105
|
+
this.logError("upsertLocalDraftOrders-订单缺少可落库标识", {
|
|
1106
|
+
count: draftOrders.length
|
|
1107
|
+
});
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
this.logInfo("upsertLocalDraftOrders-开始", {
|
|
1111
|
+
count: draftMap.size,
|
|
1112
|
+
memoryDraftCount: memoryDraftMap.size,
|
|
1113
|
+
sqliteOnlyDraftCount: draftMap.size - memoryDraftMap.size
|
|
1114
|
+
});
|
|
1115
|
+
const mergeActions = {};
|
|
1116
|
+
const updatedList = this.store.list.filter((order) => this.shouldKeepOrderInMemory(order));
|
|
1117
|
+
const identityKeyToIndex = /* @__PURE__ */ new Map();
|
|
1118
|
+
for (let index = 0; index < updatedList.length; index += 1) {
|
|
1119
|
+
for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
|
|
1120
|
+
if (!identityKeyToIndex.has(key))
|
|
1121
|
+
identityKeyToIndex.set(key, index);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
for (const [storageKey, draftOrder] of memoryDraftMap.entries()) {
|
|
1125
|
+
const matchIndex = this.lookupOrderIndexByIdentityKeys(
|
|
1126
|
+
identityKeyToIndex,
|
|
1127
|
+
this.getOrderIdentityMatchKeys(draftOrder)
|
|
1128
|
+
);
|
|
1129
|
+
if (matchIndex >= 0) {
|
|
1130
|
+
const existingOrder = updatedList[matchIndex];
|
|
1131
|
+
const reconciledDraftOrder = this.preserveExistingBusinessCodeForDraft(
|
|
1132
|
+
existingOrder,
|
|
1133
|
+
draftOrder
|
|
1134
|
+
);
|
|
1135
|
+
const mergedOrder = this.mergeOrderRecords(existingOrder, reconciledDraftOrder);
|
|
1136
|
+
const nextOrder = {
|
|
1137
|
+
...mergedOrder,
|
|
1138
|
+
need_sync: 0,
|
|
1139
|
+
is_draft_order: 1
|
|
1140
|
+
};
|
|
1141
|
+
updatedList[matchIndex] = nextOrder;
|
|
1142
|
+
draftMap.set(storageKey, reconciledDraftOrder);
|
|
1143
|
+
this.registerOrderIdentityKeys(identityKeyToIndex, nextOrder, matchIndex);
|
|
1144
|
+
mergeActions[storageKey] = "update";
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
const insertIndex = updatedList.length;
|
|
1148
|
+
updatedList.push(draftOrder);
|
|
1149
|
+
this.registerOrderIdentityKeys(identityKeyToIndex, draftOrder, insertIndex);
|
|
1150
|
+
mergeActions[storageKey] = "insert";
|
|
1151
|
+
}
|
|
1152
|
+
const patchedOrders = [...draftMap.values()];
|
|
1153
|
+
const previousList = this.store.list;
|
|
1154
|
+
this.store.list = this.runOrderStoreSelfCheck(updatedList, "upsertLocalDraftOrders.store");
|
|
1155
|
+
this.syncOrdersMap();
|
|
1156
|
+
try {
|
|
1157
|
+
await this.patchOrdersInSQLite(
|
|
1158
|
+
patchedOrders,
|
|
1159
|
+
"upsertLocalDraftOrders",
|
|
1160
|
+
mergeActions,
|
|
1161
|
+
{ throwOnError: true }
|
|
1162
|
+
);
|
|
1163
|
+
} catch (error) {
|
|
1164
|
+
this.store.list = previousList;
|
|
1165
|
+
this.syncOrdersMap();
|
|
1166
|
+
throw error;
|
|
1167
|
+
}
|
|
1168
|
+
this.logInfo("upsertLocalDraftOrders-结束", {
|
|
1169
|
+
count: patchedOrders.length,
|
|
1170
|
+
storeOrderCountAfter: this.store.list.length
|
|
1171
|
+
});
|
|
1172
|
+
const removedLegacyMemoryDraft = previousList.some(
|
|
1173
|
+
(order) => !this.shouldKeepOrderInMemory(order)
|
|
1174
|
+
);
|
|
1175
|
+
if (memoryDraftMap.size > 0 || removedLegacyMemoryDraft) {
|
|
1176
|
+
await this.emitOrdersChanged(
|
|
1177
|
+
patchedOrders.filter((order) => this.shouldKeepOrderInMemory(order)),
|
|
1178
|
+
"upsertLocalDraftOrders"
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
775
1182
|
/**
|
|
776
1183
|
* 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
|
|
777
1184
|
*/
|
|
@@ -804,6 +1211,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
804
1211
|
super.destroy();
|
|
805
1212
|
}
|
|
806
1213
|
syncOrdersMap() {
|
|
1214
|
+
this.store.list = this.store.list.filter((order) => this.shouldKeepOrderInMemory(order));
|
|
807
1215
|
this.store.map.clear();
|
|
808
1216
|
for (const order of this.store.list) {
|
|
809
1217
|
const primaryIdentity = this.getOrderMapKey(order);
|
|
@@ -827,6 +1235,22 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
827
1235
|
isBlankIdentityValue(value) {
|
|
828
1236
|
return value === void 0 || value === null || value === "";
|
|
829
1237
|
}
|
|
1238
|
+
/**
|
|
1239
|
+
* `/sales/draft` 的旧调用方可能把未设置的 business_code 传成空串。
|
|
1240
|
+
* 对同一真实订单,空值不能覆盖已有的分类,否则 booking 查询会把该订单从 Party 列表过滤掉。
|
|
1241
|
+
*/
|
|
1242
|
+
preserveExistingBusinessCodeForDraft(existingOrder, draftOrder) {
|
|
1243
|
+
const existingBusinessCode = existingOrder.business_code;
|
|
1244
|
+
const draftBusinessCode = draftOrder.business_code;
|
|
1245
|
+
const hasExistingBusinessCode = typeof existingBusinessCode === "string" && existingBusinessCode.trim() !== "";
|
|
1246
|
+
const hasDraftBusinessCode = typeof draftBusinessCode === "string" && draftBusinessCode.trim() !== "";
|
|
1247
|
+
if (!hasExistingBusinessCode || hasDraftBusinessCode)
|
|
1248
|
+
return draftOrder;
|
|
1249
|
+
return {
|
|
1250
|
+
...draftOrder,
|
|
1251
|
+
business_code: existingBusinessCode
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
830
1254
|
getOrderIdentityEntries(order) {
|
|
831
1255
|
if (!order)
|
|
832
1256
|
return [];
|
|
@@ -1082,10 +1506,20 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1082
1506
|
});
|
|
1083
1507
|
this.logDuplicateOrders(`${source}.beforeMerge`, this.store.list);
|
|
1084
1508
|
const normalizedFreshOrders = [];
|
|
1509
|
+
const incomingProductsHaveStableIdentity = /* @__PURE__ */ new Map();
|
|
1085
1510
|
for (const order of freshOrders) {
|
|
1086
1511
|
const id = order == null ? void 0 : order.order_id;
|
|
1087
1512
|
if (id === void 0 || id === null)
|
|
1088
1513
|
continue;
|
|
1514
|
+
const rawProducts = order.products;
|
|
1515
|
+
if (Array.isArray(rawProducts)) {
|
|
1516
|
+
const allProductsHaveStableIdentity = this.doProductsHaveStableMembershipIdentity(rawProducts);
|
|
1517
|
+
const orderIdKey = this.getIdKey(id);
|
|
1518
|
+
incomingProductsHaveStableIdentity.set(
|
|
1519
|
+
orderIdKey,
|
|
1520
|
+
(incomingProductsHaveStableIdentity.get(orderIdKey) ?? true) && allProductsHaveStableIdentity
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1089
1523
|
normalizedFreshOrders.push(this.normalizeRemoteSyncedOrder(order));
|
|
1090
1524
|
}
|
|
1091
1525
|
const uniqueFreshOrders = this.compactOrderListByIdentity(
|
|
@@ -1094,7 +1528,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1094
1528
|
).list;
|
|
1095
1529
|
const uniqueFreshCount = uniqueFreshOrders.length;
|
|
1096
1530
|
const patchedOrders = [];
|
|
1531
|
+
const remoteProductMembershipChanges = [];
|
|
1532
|
+
const forceWriteStorageKeys = /* @__PURE__ */ new Set();
|
|
1097
1533
|
const mergeActions = {};
|
|
1534
|
+
const existingProductsHaveStableIdentity = this.store.list.map(
|
|
1535
|
+
(order) => this.doProductsHaveStableMembershipIdentity(
|
|
1536
|
+
order.products
|
|
1537
|
+
)
|
|
1538
|
+
);
|
|
1098
1539
|
const updatedList = this.store.list.map(
|
|
1099
1540
|
(order) => this.normalizeOrderForMemoryList(order, `${source}.existingMemory`)
|
|
1100
1541
|
);
|
|
@@ -1126,9 +1567,63 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1126
1567
|
});
|
|
1127
1568
|
continue;
|
|
1128
1569
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1570
|
+
if (this.isDraftOrder(existingOrder) && this.shouldProtectDraftOrderFromIncoming(source)) {
|
|
1571
|
+
this.logInfo("mergeOrdersToStore-跳过 draft 订单远端覆盖", {
|
|
1572
|
+
source,
|
|
1573
|
+
order_id: existingOrder.order_id ?? fresh.order_id ?? null,
|
|
1574
|
+
external_sale_number: existingOrder.external_sale_number ?? fresh.external_sale_number ?? null,
|
|
1575
|
+
local_is_draft_order: existingOrder.is_draft_order ?? null,
|
|
1576
|
+
remote_is_draft_order: fresh.is_draft_order ?? null,
|
|
1577
|
+
reason: "protect_draft_order_from_remote_echo"
|
|
1578
|
+
});
|
|
1579
|
+
continue;
|
|
1580
|
+
}
|
|
1581
|
+
let mergedOrder = this.mergeOrderRecords(existingOrder, fresh);
|
|
1582
|
+
const freshOrderId = fresh.order_id;
|
|
1583
|
+
const incomingProductsAreStable = freshOrderId !== void 0 && freshOrderId !== null && incomingProductsHaveStableIdentity.get(this.getIdKey(freshOrderId)) !== false;
|
|
1584
|
+
let membershipChange = null;
|
|
1585
|
+
if (Array.isArray(fresh.products) && freshOrderId !== void 0 && freshOrderId !== null && existingProductsHaveStableIdentity[matchIndex] !== false && incomingProductsAreStable) {
|
|
1586
|
+
membershipChange = this.getRemoteProductMembershipChange(
|
|
1587
|
+
existingOrder,
|
|
1588
|
+
mergedOrder,
|
|
1589
|
+
source
|
|
1590
|
+
);
|
|
1591
|
+
}
|
|
1592
|
+
let mergedProductsHaveStableIdentity = existingProductsHaveStableIdentity[matchIndex] !== false && incomingProductsAreStable;
|
|
1593
|
+
let adjustedMatchIndex = matchIndex;
|
|
1594
|
+
const duplicateIndexes = /* @__PURE__ */ new Set();
|
|
1595
|
+
for (const key of freshIdentityKeys) {
|
|
1596
|
+
const duplicateIndex = identityKeyToIndex.get(key);
|
|
1597
|
+
if (duplicateIndex === void 0 || duplicateIndex === matchIndex)
|
|
1598
|
+
continue;
|
|
1599
|
+
duplicateIndexes.add(duplicateIndex);
|
|
1600
|
+
}
|
|
1601
|
+
if (duplicateIndexes.size > 0) {
|
|
1602
|
+
for (const duplicateIndex of [...duplicateIndexes].sort((left, right) => right - left)) {
|
|
1603
|
+
mergedOrder = this.mergeOrderRecords(mergedOrder, updatedList[duplicateIndex]);
|
|
1604
|
+
mergedProductsHaveStableIdentity = mergedProductsHaveStableIdentity && existingProductsHaveStableIdentity[duplicateIndex] !== false;
|
|
1605
|
+
updatedList.splice(duplicateIndex, 1);
|
|
1606
|
+
existingProductsHaveStableIdentity.splice(duplicateIndex, 1);
|
|
1607
|
+
if (duplicateIndex < adjustedMatchIndex)
|
|
1608
|
+
adjustedMatchIndex -= 1;
|
|
1609
|
+
}
|
|
1610
|
+
identityKeyToIndex.clear();
|
|
1611
|
+
for (let index = 0; index < updatedList.length; index += 1) {
|
|
1612
|
+
for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
|
|
1613
|
+
if (!identityKeyToIndex.has(key))
|
|
1614
|
+
identityKeyToIndex.set(key, index);
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
updatedList[adjustedMatchIndex] = mergedOrder;
|
|
1619
|
+
existingProductsHaveStableIdentity[adjustedMatchIndex] = mergedProductsHaveStableIdentity;
|
|
1620
|
+
if (membershipChange) {
|
|
1621
|
+
remoteProductMembershipChanges.push(membershipChange);
|
|
1622
|
+
const mergedStorageKey = this.getOrderStorageKey(mergedOrder);
|
|
1623
|
+
if (mergedStorageKey)
|
|
1624
|
+
forceWriteStorageKeys.add(mergedStorageKey);
|
|
1625
|
+
}
|
|
1626
|
+
this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, adjustedMatchIndex);
|
|
1132
1627
|
patchedOrders.push(mergedOrder);
|
|
1133
1628
|
if (mergeKey)
|
|
1134
1629
|
mergeActions[mergeKey] = "update";
|
|
@@ -1136,6 +1631,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1136
1631
|
}
|
|
1137
1632
|
const insertIndex = updatedList.length;
|
|
1138
1633
|
updatedList.push(fresh);
|
|
1634
|
+
existingProductsHaveStableIdentity.push(
|
|
1635
|
+
fresh.order_id !== void 0 && fresh.order_id !== null && incomingProductsHaveStableIdentity.get(this.getIdKey(fresh.order_id)) !== false
|
|
1636
|
+
);
|
|
1139
1637
|
this.registerOrderIdentityKeys(identityKeyToIndex, fresh, insertIndex);
|
|
1140
1638
|
patchedOrders.push(fresh);
|
|
1141
1639
|
if (mergeKey)
|
|
@@ -1150,13 +1648,20 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1150
1648
|
});
|
|
1151
1649
|
this.store.list = this.runOrderStoreSelfCheck(updatedList, `${source}.store`);
|
|
1152
1650
|
this.syncOrdersMap();
|
|
1153
|
-
await this.patchOrdersInSQLite(
|
|
1651
|
+
await this.patchOrdersInSQLite(
|
|
1652
|
+
patchedOrders,
|
|
1653
|
+
source,
|
|
1654
|
+
mergeActions,
|
|
1655
|
+
{},
|
|
1656
|
+
forceWriteStorageKeys
|
|
1657
|
+
);
|
|
1154
1658
|
this.logInfo("mergeOrdersToStore-结束", {
|
|
1155
1659
|
uniqueFreshCount,
|
|
1156
1660
|
storeOrderCountAfter: this.store.list.length,
|
|
1157
1661
|
insertCount,
|
|
1158
1662
|
updateCount
|
|
1159
1663
|
});
|
|
1664
|
+
await this.emitRemoteProductMembershipChanges(remoteProductMembershipChanges);
|
|
1160
1665
|
await this.emitOrdersChanged(patchedOrders, source);
|
|
1161
1666
|
}
|
|
1162
1667
|
/**
|
|
@@ -1180,6 +1685,72 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1180
1685
|
isRemoteEchoMergeSource(source) {
|
|
1181
1686
|
return source === "pubsub.bodyUpsert" || source === "pubsub.httpRefresh";
|
|
1182
1687
|
}
|
|
1688
|
+
getProductMembershipKey(product) {
|
|
1689
|
+
const persistentId = (0, import_orderCollectionIdentity.getOrderCollectionPersistentId)("product", product);
|
|
1690
|
+
if (persistentId)
|
|
1691
|
+
return `order_detail_id:${persistentId}`;
|
|
1692
|
+
const uid = (0, import_orderCollectionIdentity.getOrderCollectionUid)("product", product);
|
|
1693
|
+
return uid ? `unique_identification_number:${uid}` : "";
|
|
1694
|
+
}
|
|
1695
|
+
doProductsHaveStableMembershipIdentity(products) {
|
|
1696
|
+
if (!Array.isArray(products))
|
|
1697
|
+
return true;
|
|
1698
|
+
return products.every(
|
|
1699
|
+
(product) => Boolean(
|
|
1700
|
+
(0, import_orderCollectionIdentity.getOrderCollectionPersistentId)("product", product) || (0, import_orderCollectionIdentity.getOrderCollectionUid)("product", product)
|
|
1701
|
+
)
|
|
1702
|
+
);
|
|
1703
|
+
}
|
|
1704
|
+
/**
|
|
1705
|
+
* 冲突提示关注逻辑商品行,而不是服务端 checkout 过程中可能被重建的 detail 记录。
|
|
1706
|
+
* 通用集合合并仍以 order_detail_id 为事实主键;这里只允许相同稳定 UID 跨 detail id 对齐,
|
|
1707
|
+
* 避免本机 checkout 回声被误判成“一删一增”。
|
|
1708
|
+
*/
|
|
1709
|
+
isSameProductMembershipItem(left, right) {
|
|
1710
|
+
if ((0, import_orderCollectionIdentity.isSameOrderCollectionItem)("product", left, right))
|
|
1711
|
+
return true;
|
|
1712
|
+
const leftUid = (0, import_orderCollectionIdentity.getOrderCollectionUid)("product", left);
|
|
1713
|
+
const rightUid = (0, import_orderCollectionIdentity.getOrderCollectionUid)("product", right);
|
|
1714
|
+
return Boolean(leftUid && rightUid && leftUid === rightUid);
|
|
1715
|
+
}
|
|
1716
|
+
/**
|
|
1717
|
+
* 对比合并前后的商品成员集合。商品字段修改与数组重排不会产生 diff。
|
|
1718
|
+
*/
|
|
1719
|
+
getRemoteProductMembershipChange(existingOrder, mergedOrder, source) {
|
|
1720
|
+
if (!this.isRemoteEchoMergeSource(source))
|
|
1721
|
+
return null;
|
|
1722
|
+
const previousProducts = Array.isArray(existingOrder.products) ? existingOrder.products : [];
|
|
1723
|
+
const currentProducts = Array.isArray(mergedOrder.products) ? mergedOrder.products : [];
|
|
1724
|
+
const unmatchedCurrentIndexes = new Set(currentProducts.map((_, index) => index));
|
|
1725
|
+
const removedProductKeys = [];
|
|
1726
|
+
for (const previousProduct of previousProducts) {
|
|
1727
|
+
const matchedIndex = currentProducts.findIndex(
|
|
1728
|
+
(currentProduct, index) => unmatchedCurrentIndexes.has(index) && this.isSameProductMembershipItem(previousProduct, currentProduct)
|
|
1729
|
+
);
|
|
1730
|
+
if (matchedIndex >= 0) {
|
|
1731
|
+
unmatchedCurrentIndexes.delete(matchedIndex);
|
|
1732
|
+
continue;
|
|
1733
|
+
}
|
|
1734
|
+
const productKey = this.getProductMembershipKey(previousProduct);
|
|
1735
|
+
if (productKey)
|
|
1736
|
+
removedProductKeys.push(productKey);
|
|
1737
|
+
}
|
|
1738
|
+
const addedProductKeys = [...unmatchedCurrentIndexes].map((index) => this.getProductMembershipKey(currentProducts[index])).filter(Boolean);
|
|
1739
|
+
if (addedProductKeys.length === 0 && removedProductKeys.length === 0) {
|
|
1740
|
+
return null;
|
|
1741
|
+
}
|
|
1742
|
+
const orderId = mergedOrder.order_id ?? existingOrder.order_id;
|
|
1743
|
+
if (orderId === void 0 || orderId === null)
|
|
1744
|
+
return null;
|
|
1745
|
+
return {
|
|
1746
|
+
order_id: orderId,
|
|
1747
|
+
source,
|
|
1748
|
+
added_product_keys: addedProductKeys,
|
|
1749
|
+
removed_product_keys: removedProductKeys,
|
|
1750
|
+
previous_product_count: previousProducts.length,
|
|
1751
|
+
current_product_count: currentProducts.length
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1183
1754
|
/**
|
|
1184
1755
|
* 将订单的全部身份键登记到索引并指向其在列表中的下标。
|
|
1185
1756
|
* 合并后订单新增的身份字段(如挂单同步后拿到 order_id)也会被登记。
|
|
@@ -1320,6 +1891,72 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1320
1891
|
return right;
|
|
1321
1892
|
return left;
|
|
1322
1893
|
}
|
|
1894
|
+
getProductIdentityKeys(product) {
|
|
1895
|
+
var _a;
|
|
1896
|
+
const record = product;
|
|
1897
|
+
if (!record)
|
|
1898
|
+
return [];
|
|
1899
|
+
const keys = [];
|
|
1900
|
+
const metadataUid = (_a = record.metadata) == null ? void 0 : _a.unique_identification_number;
|
|
1901
|
+
if (!this.isBlankIdentityValue(metadataUid))
|
|
1902
|
+
keys.push(`uid:${String(metadataUid)}`);
|
|
1903
|
+
const topLevelUid = record.unique_identification_number;
|
|
1904
|
+
if (!this.isBlankIdentityValue(topLevelUid))
|
|
1905
|
+
keys.push(`uid:${String(topLevelUid)}`);
|
|
1906
|
+
const orderDetailId = record.order_detail_id;
|
|
1907
|
+
if (!this.isBlankIdentityValue(orderDetailId))
|
|
1908
|
+
keys.push(`detail:${String(orderDetailId)}`);
|
|
1909
|
+
const bookingUid = record.booking_uid;
|
|
1910
|
+
if (!this.isBlankIdentityValue(bookingUid))
|
|
1911
|
+
keys.push(`booking:${String(bookingUid)}`);
|
|
1912
|
+
return keys;
|
|
1913
|
+
}
|
|
1914
|
+
mergeOrderProductLists(preferred, secondary) {
|
|
1915
|
+
const preferredList = Array.isArray(preferred) ? preferred : [];
|
|
1916
|
+
const secondaryList = Array.isArray(secondary) ? secondary : [];
|
|
1917
|
+
if (secondaryList.length === 0)
|
|
1918
|
+
return preferredList;
|
|
1919
|
+
if (preferredList.length === 0)
|
|
1920
|
+
return secondaryList;
|
|
1921
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
1922
|
+
for (const item of preferredList) {
|
|
1923
|
+
const keys = this.getProductIdentityKeys(item);
|
|
1924
|
+
for (const key of keys)
|
|
1925
|
+
seenKeys.add(key);
|
|
1926
|
+
}
|
|
1927
|
+
const result = [...preferredList];
|
|
1928
|
+
for (const item of secondaryList) {
|
|
1929
|
+
const keys = this.getProductIdentityKeys(item);
|
|
1930
|
+
if (keys.length === 0 || keys.some((key) => seenKeys.has(key)))
|
|
1931
|
+
continue;
|
|
1932
|
+
for (const key of keys)
|
|
1933
|
+
seenKeys.add(key);
|
|
1934
|
+
result.push((0, import_lodash_es.cloneDeep)(item));
|
|
1935
|
+
}
|
|
1936
|
+
return result;
|
|
1937
|
+
}
|
|
1938
|
+
mergeOrderPaymentLists(existing, incoming) {
|
|
1939
|
+
const existingList = Array.isArray(existing) ? existing : [];
|
|
1940
|
+
const incomingList = Array.isArray(incoming) ? incoming : [];
|
|
1941
|
+
if (incomingList.length === 0)
|
|
1942
|
+
return (0, import_lodash_es.cloneDeep)(existingList);
|
|
1943
|
+
return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(existingList, incomingList);
|
|
1944
|
+
}
|
|
1945
|
+
getIdentifiedPendingPayments(order) {
|
|
1946
|
+
const payments = Array.isArray(order == null ? void 0 : order.payments) ? order.payments : [];
|
|
1947
|
+
return payments.filter((payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment));
|
|
1948
|
+
}
|
|
1949
|
+
shouldProtectLocalOrderFromRemoteSnapshot(order) {
|
|
1950
|
+
return this.isPendingSyncOrder(order) || this.isDraftOrder(order) || this.getIdentifiedPendingPayments(order).length > 0;
|
|
1951
|
+
}
|
|
1952
|
+
getUnmatchedIdentifiedPendingPayments(existing, incoming) {
|
|
1953
|
+
const existingPayments = Array.isArray(existing) ? existing : [];
|
|
1954
|
+
const incomingPayments = Array.isArray(incoming) ? incoming : [];
|
|
1955
|
+
const incomingIdentityKeys = new Set(
|
|
1956
|
+
incomingPayments.flatMap((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
|
|
1957
|
+
);
|
|
1958
|
+
return existingPayments.filter((payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment) && !(0, import_payment_utils.getOrderPaymentIdentityKeys)(payment).some((key) => incomingIdentityKeys.has(key)));
|
|
1959
|
+
}
|
|
1323
1960
|
mergeOrderRecords(existing, incoming) {
|
|
1324
1961
|
const preferred = this.pickPreferredOrder(existing, incoming);
|
|
1325
1962
|
const secondary = preferred === existing ? incoming : existing;
|
|
@@ -1349,7 +1986,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1349
1986
|
"contacts_info",
|
|
1350
1987
|
"phone",
|
|
1351
1988
|
"email",
|
|
1352
|
-
"relation_forms"
|
|
1989
|
+
"relation_forms",
|
|
1990
|
+
"is_draft_order"
|
|
1353
1991
|
];
|
|
1354
1992
|
const mergedRecord = merged;
|
|
1355
1993
|
const preferredRecord = preferred;
|
|
@@ -1377,11 +2015,26 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1377
2015
|
}
|
|
1378
2016
|
for (const field of ORDER_AUTHORITATIVE_COLLECTION_FIELDS) {
|
|
1379
2017
|
if (Array.isArray(incomingRecord[field])) {
|
|
2018
|
+
if (field === "payments") {
|
|
2019
|
+
const preservedPending = this.getUnmatchedIdentifiedPendingPayments(
|
|
2020
|
+
existingRecord[field],
|
|
2021
|
+
incomingRecord[field]
|
|
2022
|
+
);
|
|
2023
|
+
if (preservedPending.length > 0) {
|
|
2024
|
+
this.logInfo("mergeOrderRecords-保留本地 pending 支付项", {
|
|
2025
|
+
order_id: existing.order_id ?? incoming.order_id ?? null,
|
|
2026
|
+
external_sale_number: existingRecord.external_sale_number ?? incomingRecord.external_sale_number ?? null,
|
|
2027
|
+
preserved_pending_count: preservedPending.length,
|
|
2028
|
+
preserved_payment_identities: preservedPending.map((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
|
|
2029
|
+
});
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
1380
2032
|
mergedRecord[field] = this.mergeAuthoritativeOrderCollection(
|
|
1381
2033
|
field,
|
|
1382
2034
|
existingRecord[field],
|
|
1383
2035
|
incomingRecord[field],
|
|
1384
|
-
childUidRemaps
|
|
2036
|
+
childUidRemaps,
|
|
2037
|
+
{ preserveIdentifiedPendingPayments: field === "payments" }
|
|
1385
2038
|
);
|
|
1386
2039
|
continue;
|
|
1387
2040
|
}
|
|
@@ -1416,7 +2069,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1416
2069
|
external_sale_number: order.external_sale_number ?? null,
|
|
1417
2070
|
shop_order_number: order.shop_order_number ?? null,
|
|
1418
2071
|
shop_full_order_number: order.shop_full_order_number ?? null,
|
|
1419
|
-
need_sync: order.need_sync ?? null
|
|
2072
|
+
need_sync: order.need_sync ?? null,
|
|
2073
|
+
is_draft_order: order.is_draft_order ?? null
|
|
1420
2074
|
}))
|
|
1421
2075
|
}));
|
|
1422
2076
|
}
|
|
@@ -1533,18 +2187,48 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1533
2187
|
isPendingSyncOrder(order) {
|
|
1534
2188
|
return Number(order == null ? void 0 : order.need_sync) === 1;
|
|
1535
2189
|
}
|
|
2190
|
+
isDraftOrder(order) {
|
|
2191
|
+
return Number(order == null ? void 0 : order.is_draft_order) === 1;
|
|
2192
|
+
}
|
|
2193
|
+
shouldProtectDraftOrderFromIncoming(source) {
|
|
2194
|
+
return source !== "checkoutSync";
|
|
2195
|
+
}
|
|
1536
2196
|
normalizeRemoteSyncedOrder(order) {
|
|
1537
2197
|
const normalizedOrder = this.normalizeOrderCollectionsForIngress(
|
|
1538
2198
|
order,
|
|
1539
2199
|
"normalizeRemoteSyncedOrder"
|
|
1540
2200
|
);
|
|
1541
2201
|
if (this.isPendingSyncOrder(normalizedOrder))
|
|
1542
|
-
return
|
|
2202
|
+
return {
|
|
2203
|
+
...normalizedOrder,
|
|
2204
|
+
is_draft_order: 0
|
|
2205
|
+
};
|
|
1543
2206
|
return {
|
|
1544
2207
|
...normalizedOrder,
|
|
1545
|
-
need_sync: 0
|
|
2208
|
+
need_sync: 0,
|
|
2209
|
+
is_draft_order: 0
|
|
1546
2210
|
};
|
|
1547
2211
|
}
|
|
2212
|
+
mergeRemoteIdentityIntoDraftOrder(draftOrder, remoteOrder) {
|
|
2213
|
+
const merged = {
|
|
2214
|
+
...this.withoutSyntheticDraftOrderId(draftOrder)
|
|
2215
|
+
};
|
|
2216
|
+
const remote = remoteOrder;
|
|
2217
|
+
for (const field of [
|
|
2218
|
+
"order_id",
|
|
2219
|
+
"order_number",
|
|
2220
|
+
"shop_order_number",
|
|
2221
|
+
"shop_full_order_number"
|
|
2222
|
+
]) {
|
|
2223
|
+
if (this.isBlankIdentityValue(merged[field]) && !this.isBlankIdentityValue(remote[field])) {
|
|
2224
|
+
merged[field] = remote[field];
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
return this.normalizeOrderCollectionsForIngress(
|
|
2228
|
+
merged,
|
|
2229
|
+
"mergeRemoteIdentityIntoDraftOrder"
|
|
2230
|
+
);
|
|
2231
|
+
}
|
|
1548
2232
|
mergeRemoteSnapshotWithPendingOrders(remoteOrders, existingOrders) {
|
|
1549
2233
|
const merged = remoteOrders.map((order) => this.normalizeRemoteSyncedOrder(order));
|
|
1550
2234
|
for (const rawOrder of existingOrders) {
|
|
@@ -1552,11 +2236,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1552
2236
|
rawOrder,
|
|
1553
2237
|
"mergeRemoteSnapshotWithPendingOrders.existingSQLite"
|
|
1554
2238
|
);
|
|
1555
|
-
if (!this.
|
|
2239
|
+
if (!this.shouldProtectLocalOrderFromRemoteSnapshot(order))
|
|
1556
2240
|
continue;
|
|
1557
2241
|
const matchIndex = this.findOrderIndexByIdentity(merged, order);
|
|
1558
2242
|
if (matchIndex >= 0) {
|
|
1559
|
-
|
|
2243
|
+
if (this.isDraftOrder(order)) {
|
|
2244
|
+
merged[matchIndex] = this.mergeRemoteIdentityIntoDraftOrder(
|
|
2245
|
+
order,
|
|
2246
|
+
merged[matchIndex]
|
|
2247
|
+
);
|
|
2248
|
+
} else {
|
|
2249
|
+
merged[matchIndex] = this.mergeOrderRecords(order, merged[matchIndex]);
|
|
2250
|
+
}
|
|
1560
2251
|
continue;
|
|
1561
2252
|
}
|
|
1562
2253
|
if (!this.getOrderStorageKey(order))
|
|
@@ -1584,8 +2275,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1584
2275
|
* @example
|
|
1585
2276
|
* await this.patchOrdersInSQLite(freshOrders)
|
|
1586
2277
|
*/
|
|
1587
|
-
async patchOrdersInSQLite(orders, source, mergeActions = {}) {
|
|
1588
|
-
if (
|
|
2278
|
+
async patchOrdersInSQLite(orders, source, mergeActions = {}, options = {}, forceWriteStorageKeys = /* @__PURE__ */ new Set()) {
|
|
2279
|
+
if (orders.length === 0) {
|
|
2280
|
+
return;
|
|
2281
|
+
}
|
|
2282
|
+
if (!this.dbManager) {
|
|
2283
|
+
if (options.throwOnError)
|
|
2284
|
+
throw new Error("订单 SQLite 数据库未初始化");
|
|
1589
2285
|
return;
|
|
1590
2286
|
}
|
|
1591
2287
|
const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).map((order) => this.normalizeOrderCollectionsForIngress(order, `${source}.sqliteIngress`)).filter((order) => this.getOrderStorageKey(order));
|
|
@@ -1595,7 +2291,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1595
2291
|
const { toWrite, skipped } = this.filterRedundantPatchOrders(
|
|
1596
2292
|
source,
|
|
1597
2293
|
ordersSnapshot,
|
|
1598
|
-
mergeActions
|
|
2294
|
+
mergeActions,
|
|
2295
|
+
forceWriteStorageKeys
|
|
1599
2296
|
);
|
|
1600
2297
|
if (toWrite.length === 0) {
|
|
1601
2298
|
return;
|
|
@@ -1623,6 +2320,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1623
2320
|
for (const order of compactedToWrite) {
|
|
1624
2321
|
await this.dbManager.update(INDEXDB_STORE_NAME, order);
|
|
1625
2322
|
}
|
|
2323
|
+
} else if (options.throwOnError) {
|
|
2324
|
+
throw new Error("订单 SQLite 数据库不支持写入");
|
|
1626
2325
|
}
|
|
1627
2326
|
this.recordRecentSqliteWrite(source, compactedToWrite);
|
|
1628
2327
|
this.logInfo("patchOrdersInSQLite-完成", {
|
|
@@ -1637,6 +2336,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1637
2336
|
error: error instanceof Error ? error.message : String(error),
|
|
1638
2337
|
orderCount: ordersSnapshot.length
|
|
1639
2338
|
});
|
|
2339
|
+
if (options.throwOnError)
|
|
2340
|
+
throw error;
|
|
1640
2341
|
}
|
|
1641
2342
|
}
|
|
1642
2343
|
/**
|
|
@@ -1645,8 +2346,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1645
2346
|
* @example
|
|
1646
2347
|
* await this.updateOrderInSQLite(freshOrder)
|
|
1647
2348
|
*/
|
|
1648
|
-
async updateOrderInSQLite(order, source) {
|
|
1649
|
-
if (!this.
|
|
2349
|
+
async updateOrderInSQLite(order, source, options = {}) {
|
|
2350
|
+
if (!this.getOrderStorageKey(order)) {
|
|
2351
|
+
if (options.throwOnError)
|
|
2352
|
+
throw new Error("订单缺少可用的 SQLite 存储主键");
|
|
2353
|
+
return;
|
|
2354
|
+
}
|
|
2355
|
+
if (!this.dbManager) {
|
|
2356
|
+
if (options.throwOnError)
|
|
2357
|
+
throw new Error("订单 SQLite 数据库未初始化");
|
|
1650
2358
|
return;
|
|
1651
2359
|
}
|
|
1652
2360
|
const orderSnapshot = this.normalizeOrderCollectionsForIngress(
|
|
@@ -1670,6 +2378,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1670
2378
|
} else if (typeof this.dbManager.bulkAdd === "function") {
|
|
1671
2379
|
writeMethod = "bulkAdd";
|
|
1672
2380
|
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, [orderSnapshot]);
|
|
2381
|
+
} else if (options.throwOnError) {
|
|
2382
|
+
throw new Error("订单 SQLite 数据库不支持写入");
|
|
1673
2383
|
}
|
|
1674
2384
|
this.recordRecentSqliteWrite(source, [orderSnapshot]);
|
|
1675
2385
|
this.logInfo("updateOrderInSQLite-完成", {
|
|
@@ -1683,15 +2393,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1683
2393
|
error: error instanceof Error ? error.message : String(error),
|
|
1684
2394
|
orderId: orderSnapshot.order_id ?? null
|
|
1685
2395
|
});
|
|
2396
|
+
if (options.throwOnError)
|
|
2397
|
+
throw error;
|
|
1686
2398
|
}
|
|
1687
2399
|
}
|
|
1688
2400
|
/**
|
|
1689
|
-
* 全量快照替换 orders 表(clear + bulkAdd
|
|
2401
|
+
* 全量快照替换 orders 表(clear + bulkAdd),并保留本地 draft / need_sync / pending 支付订单。
|
|
2402
|
+
* 用于 SSE 全量拉取与营业日窗口裁剪。
|
|
1690
2403
|
*
|
|
1691
2404
|
* @example
|
|
1692
2405
|
* await this.replaceOrdersSnapshotInSQLite(orderList)
|
|
1693
2406
|
*/
|
|
1694
|
-
async replaceOrdersSnapshotInSQLite(orderList, source) {
|
|
2407
|
+
async replaceOrdersSnapshotInSQLite(orderList, source, protectedOrdersBeforeRemoteFetch = []) {
|
|
1695
2408
|
if (!this.dbManager) {
|
|
1696
2409
|
return this.compactOrderListByIdentity(
|
|
1697
2410
|
orderList.map((order) => this.normalizeRemoteSyncedOrder(order)),
|
|
@@ -1708,16 +2421,52 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1708
2421
|
try {
|
|
1709
2422
|
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
1710
2423
|
const existingOrders = typeof this.dbManager.getAll === "function" ? await this.dbManager.getAll(INDEXDB_STORE_NAME) : [];
|
|
2424
|
+
const protectedLocalOrders = protectedOrdersBeforeRemoteFetch.map((order) => this.normalizeOrderCollectionsForIngress(
|
|
2425
|
+
order,
|
|
2426
|
+
`${source}.protectedBeforeRemoteFetch`
|
|
2427
|
+
)).filter((order) => this.shouldProtectLocalOrderFromRemoteSnapshot(order));
|
|
2428
|
+
for (const rawCurrentOrder of existingOrders || []) {
|
|
2429
|
+
const currentOrder = this.normalizeOrderCollectionsForIngress(
|
|
2430
|
+
rawCurrentOrder,
|
|
2431
|
+
`${source}.currentSQLite`
|
|
2432
|
+
);
|
|
2433
|
+
const protectedIndex = this.findOrderIndexByIdentity(
|
|
2434
|
+
protectedLocalOrders,
|
|
2435
|
+
currentOrder
|
|
2436
|
+
);
|
|
2437
|
+
const currentNeedsProtection = this.shouldProtectLocalOrderFromRemoteSnapshot(currentOrder);
|
|
2438
|
+
if (protectedIndex >= 0) {
|
|
2439
|
+
if (currentNeedsProtection) {
|
|
2440
|
+
protectedLocalOrders[protectedIndex] = currentOrder;
|
|
2441
|
+
} else {
|
|
2442
|
+
protectedLocalOrders.splice(protectedIndex, 1);
|
|
2443
|
+
}
|
|
2444
|
+
continue;
|
|
2445
|
+
}
|
|
2446
|
+
if (currentNeedsProtection)
|
|
2447
|
+
protectedLocalOrders.push(currentOrder);
|
|
2448
|
+
}
|
|
1711
2449
|
const orderListSnapshot = this.mergeRemoteSnapshotWithPendingOrders(
|
|
1712
2450
|
remoteSnapshot,
|
|
1713
|
-
|
|
2451
|
+
protectedLocalOrders
|
|
1714
2452
|
);
|
|
1715
2453
|
mergedSnapshot = this.compactOrderListByIdentity(orderListSnapshot, `${source}.sqliteSnapshot`).list;
|
|
1716
2454
|
this.logInfo("replaceOrdersSnapshotInSQLite-开始", {
|
|
1717
2455
|
source,
|
|
1718
2456
|
count: mergedSnapshot.length,
|
|
1719
2457
|
remoteCount: remoteSnapshot.length,
|
|
1720
|
-
|
|
2458
|
+
protectedBeforeRemoteFetchCount: protectedOrdersBeforeRemoteFetch.length,
|
|
2459
|
+
protectedLocalOrderCount: protectedLocalOrders.length,
|
|
2460
|
+
preservedLocalUnsyncedCount: mergedSnapshot.length - remoteSnapshot.length,
|
|
2461
|
+
protectedPendingPaymentCount: protectedLocalOrders.reduce(
|
|
2462
|
+
(count, order) => count + this.getIdentifiedPendingPayments(order).length,
|
|
2463
|
+
0
|
|
2464
|
+
),
|
|
2465
|
+
protectedPendingPaymentIdentities: protectedLocalOrders.flatMap((order) => this.getIdentifiedPendingPayments(order).map((payment) => ({
|
|
2466
|
+
order_id: order.order_id ?? null,
|
|
2467
|
+
external_sale_number: order.external_sale_number ?? null,
|
|
2468
|
+
payment_identities: (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment)
|
|
2469
|
+
})))
|
|
1721
2470
|
});
|
|
1722
2471
|
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
1723
2472
|
this.logInfo("replaceOrdersSnapshotInSQLite-clear完成", {
|