@pisell/pisellos 2.2.264 → 2.2.265
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/model/strategy/adapter/dataVariant/adapter.d.ts +50 -0
- package/dist/model/strategy/adapter/dataVariant/adapter.js +167 -0
- package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +89 -0
- package/dist/model/strategy/adapter/dataVariant/evaluator.js +780 -0
- package/dist/model/strategy/adapter/dataVariant/examples.d.ts +39 -0
- package/dist/model/strategy/adapter/dataVariant/examples.js +277 -0
- package/dist/model/strategy/adapter/dataVariant/index.d.ts +4 -0
- package/dist/model/strategy/adapter/dataVariant/index.js +4 -0
- package/dist/model/strategy/adapter/dataVariant/type.d.ts +148 -0
- package/dist/model/strategy/adapter/dataVariant/type.js +54 -0
- package/dist/model/strategy/adapter/index.d.ts +4 -0
- package/dist/model/strategy/adapter/index.js +5 -1
- package/dist/model/strategy/adapter/promotion/adapter.d.ts +0 -4
- package/dist/model/strategy/adapter/promotion/adapter.js +0 -23
- package/dist/model/strategy/adapter/promotion/evaluator.d.ts +0 -17
- package/dist/model/strategy/adapter/promotion/evaluator.js +6 -279
- package/dist/model/strategy/adapter/promotion/examples.d.ts +0 -86
- package/dist/model/strategy/adapter/promotion/examples.js +0 -99
- package/dist/model/strategy/adapter/promotion/index.d.ts +1 -1
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/model/strategy/adapter/promotion/type.d.ts +2 -90
- package/dist/model/strategy/adapter/promotion/type.js +0 -45
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +16 -10
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +32 -1
- package/dist/modules/Discount/index.d.ts +5 -2
- package/dist/modules/Discount/index.js +30 -7
- package/dist/modules/Discount/types.d.ts +4 -0
- package/dist/modules/Order/index.d.ts +41 -10
- package/dist/modules/Order/index.js +1370 -808
- 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 +49 -1
- package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.js +410 -0
- package/dist/modules/Order/utils.d.ts +4 -3
- package/dist/modules/Order/utils.js +62 -66
- package/dist/modules/Payment/index.d.ts +2 -0
- package/dist/modules/Payment/index.js +78 -49
- package/dist/modules/Payment/types.d.ts +26 -24
- package/dist/modules/Payment/types.js +2 -0
- package/dist/modules/Product/types.d.ts +22 -0
- package/dist/modules/ProductList/index.d.ts +1 -1
- package/dist/modules/ProductList/index.js +4 -2
- package/dist/modules/ProductList/types.d.ts +2 -0
- package/dist/modules/Rules/index.d.ts +2 -9
- package/dist/modules/Rules/index.js +69 -43
- package/dist/modules/Rules/types.d.ts +10 -1
- package/dist/server/index.d.ts +71 -0
- package/dist/server/index.js +2504 -1187
- package/dist/server/modules/order/index.d.ts +56 -5
- package/dist/server/modules/order/index.js +1718 -834
- package/dist/server/modules/order/types.d.ts +15 -3
- package/dist/server/modules/order/types.js +1 -1
- package/dist/server/modules/products/index.d.ts +31 -8
- package/dist/server/modules/products/index.js +549 -390
- package/dist/server/modules/products/types.d.ts +18 -0
- package/dist/solution/BaseSales/index.d.ts +54 -4
- package/dist/solution/BaseSales/index.js +1448 -788
- package/dist/solution/BaseSales/types.d.ts +6 -1
- package/dist/solution/BaseSales/types.js +1 -1
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +1 -3
- package/dist/solution/BaseSales/utils/cartPromotion.js +50 -97
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +9 -4
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +6 -8
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +14 -1
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +61 -26
- package/dist/solution/BookingTicket/types.d.ts +2 -0
- package/dist/solution/Sales/index.d.ts +1 -0
- package/dist/solution/Sales/index.js +10 -2
- package/dist/solution/ScanOrder/index.js +20 -31
- package/dist/solution/ShopDiscount/index.js +15 -14
- package/dist/solution/VenueBooking/index.js +19 -30
- package/dist/utils/payment-number.d.ts +9 -0
- package/dist/utils/payment-number.js +69 -0
- package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +50 -0
- package/lib/model/strategy/adapter/dataVariant/adapter.js +149 -0
- package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +89 -0
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +583 -0
- package/lib/model/strategy/adapter/dataVariant/examples.d.ts +39 -0
- package/lib/model/strategy/adapter/dataVariant/examples.js +293 -0
- package/lib/model/strategy/adapter/dataVariant/index.d.ts +4 -0
- package/lib/model/strategy/adapter/dataVariant/index.js +38 -0
- package/lib/model/strategy/adapter/dataVariant/type.d.ts +148 -0
- package/lib/model/strategy/adapter/dataVariant/type.js +31 -0
- package/lib/model/strategy/adapter/index.d.ts +4 -0
- package/lib/model/strategy/adapter/index.js +13 -2
- package/lib/model/strategy/adapter/promotion/adapter.d.ts +0 -4
- package/lib/model/strategy/adapter/promotion/adapter.js +0 -20
- package/lib/model/strategy/adapter/promotion/evaluator.d.ts +0 -17
- package/lib/model/strategy/adapter/promotion/evaluator.js +0 -235
- package/lib/model/strategy/adapter/promotion/examples.d.ts +0 -86
- package/lib/model/strategy/adapter/promotion/examples.js +0 -91
- package/lib/model/strategy/adapter/promotion/index.d.ts +1 -1
- package/lib/model/strategy/adapter/promotion/index.js +0 -2
- package/lib/model/strategy/adapter/promotion/type.d.ts +2 -90
- package/lib/model/strategy/adapter/promotion/type.js +0 -2
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +5 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +1 -0
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +23 -2
- package/lib/modules/Discount/index.d.ts +5 -2
- package/lib/modules/Discount/index.js +23 -3
- package/lib/modules/Discount/types.d.ts +4 -0
- package/lib/modules/Order/index.d.ts +41 -10
- package/lib/modules/Order/index.js +505 -119
- 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 +49 -1
- package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.js +418 -0
- package/lib/modules/Order/utils.d.ts +4 -3
- package/lib/modules/Order/utils.js +27 -26
- package/lib/modules/Payment/index.d.ts +2 -0
- package/lib/modules/Payment/index.js +33 -12
- package/lib/modules/Payment/types.d.ts +26 -24
- package/lib/modules/Product/types.d.ts +22 -0
- package/lib/modules/ProductList/index.d.ts +1 -1
- package/lib/modules/ProductList/index.js +4 -2
- package/lib/modules/ProductList/types.d.ts +2 -0
- package/lib/modules/Rules/index.d.ts +2 -9
- package/lib/modules/Rules/index.js +61 -29
- package/lib/modules/Rules/types.d.ts +10 -1
- package/lib/server/index.d.ts +71 -0
- package/lib/server/index.js +1002 -52
- package/lib/server/modules/order/index.d.ts +56 -5
- package/lib/server/modules/order/index.js +798 -148
- package/lib/server/modules/order/types.d.ts +15 -3
- package/lib/server/modules/products/index.d.ts +31 -8
- package/lib/server/modules/products/index.js +134 -35
- package/lib/server/modules/products/types.d.ts +18 -0
- package/lib/solution/BaseSales/index.d.ts +54 -4
- package/lib/solution/BaseSales/index.js +475 -50
- package/lib/solution/BaseSales/types.d.ts +6 -1
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +1 -3
- package/lib/solution/BaseSales/utils/cartPromotion.js +25 -64
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +9 -4
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +4 -5
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +8 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +35 -9
- package/lib/solution/BookingTicket/types.d.ts +2 -0
- package/lib/solution/Sales/index.d.ts +1 -0
- package/lib/solution/Sales/index.js +5 -3
- package/lib/solution/ScanOrder/index.js +0 -8
- package/lib/solution/ShopDiscount/index.js +2 -1
- package/lib/solution/VenueBooking/index.js +0 -8
- package/lib/utils/payment-number.d.ts +9 -0
- package/lib/utils/payment-number.js +64 -0
- package/package.json +1 -1
|
@@ -35,7 +35,9 @@ module.exports = __toCommonJS(order_exports);
|
|
|
35
35
|
var import_lodash_es = require("lodash-es");
|
|
36
36
|
var import_dayjs = __toESM(require("dayjs"));
|
|
37
37
|
var import_BaseModule = require("../../../modules/BaseModule");
|
|
38
|
+
var import_orderCollectionIdentity = require("../../../modules/Order/utils/orderCollectionIdentity");
|
|
38
39
|
var import_types = require("./types");
|
|
40
|
+
var import_payment_utils = require("../../../modules/Order/payment-utils");
|
|
39
41
|
var INDEXDB_STORE_NAME = "orders";
|
|
40
42
|
var ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = "server_order_last_full_fetch_at";
|
|
41
43
|
var ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = "order_sync_throttle_ms";
|
|
@@ -45,10 +47,19 @@ var ORDER_SILENT_REFRESH_MIN_INTERVAL_MS = 3e4;
|
|
|
45
47
|
var ORDER_BUSINESS_WRITE_SOURCES = /* @__PURE__ */ new Set([
|
|
46
48
|
"upsertOrdersFromRemote",
|
|
47
49
|
"upsertPendingSyncOrders",
|
|
50
|
+
"upsertLocalDraftOrders",
|
|
48
51
|
"overwriteExistingOrder",
|
|
49
|
-
"markOrderSyncedByExternalSaleNumber"
|
|
52
|
+
"markOrderSyncedByExternalSaleNumber",
|
|
53
|
+
"updateLocalPayment"
|
|
50
54
|
]);
|
|
51
55
|
var ORDER_MERGE_SELF_CHECK = false;
|
|
56
|
+
var PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER = "__pisell_os_pending_payment_without_unique_number__";
|
|
57
|
+
var ORDER_AUTHORITATIVE_COLLECTION_FIELDS = ["products", "bookings", "payments"];
|
|
58
|
+
var ORDER_COLLECTION_KIND_BY_FIELD = {
|
|
59
|
+
products: "product",
|
|
60
|
+
bookings: "booking",
|
|
61
|
+
payments: "payment"
|
|
62
|
+
};
|
|
52
63
|
var OrderModule = class extends import_BaseModule.BaseModule {
|
|
53
64
|
constructor(name, version) {
|
|
54
65
|
super(name, version);
|
|
@@ -93,7 +104,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
93
104
|
this.updateCreateStore();
|
|
94
105
|
}
|
|
95
106
|
if (Array.isArray((_a = options == null ? void 0 : options.initialState) == null ? void 0 : _a.list)) {
|
|
96
|
-
this.store.list =
|
|
107
|
+
this.store.list = this.normalizeOrdersForMemoryList(
|
|
108
|
+
options.initialState.list,
|
|
109
|
+
"initialState"
|
|
110
|
+
);
|
|
97
111
|
this.syncOrdersMap();
|
|
98
112
|
this.emitOrdersChanged([], "initialState");
|
|
99
113
|
} else {
|
|
@@ -154,6 +168,131 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
154
168
|
} catch {
|
|
155
169
|
}
|
|
156
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* 在订单进入内存或 SQLite 前统一压缩子项强身份重复并补齐协议 UID。
|
|
173
|
+
* 仅记录计数与订单标识,不输出商品、预约、支付或客户明细。
|
|
174
|
+
*/
|
|
175
|
+
normalizeOrderCollectionsForIngress(order, source) {
|
|
176
|
+
const sourceOrder = (0, import_lodash_es.cloneDeep)(order);
|
|
177
|
+
const sourceOrderRecord = sourceOrder;
|
|
178
|
+
if (Array.isArray(sourceOrderRecord.payments)) {
|
|
179
|
+
sourceOrderRecord.payments = sourceOrderRecord.payments.map((payment) => {
|
|
180
|
+
if (!(0, import_payment_utils.isPendingOrderPayment)(payment) || (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment).some((key) => key.startsWith("unique_payment_number:"))) {
|
|
181
|
+
return payment;
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
...payment,
|
|
185
|
+
[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER]: true
|
|
186
|
+
};
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
const result = (0, import_orderCollectionIdentity.normalizeOrderCollections)(sourceOrder);
|
|
190
|
+
const normalizedOrderRecord = result.order;
|
|
191
|
+
if (Array.isArray(normalizedOrderRecord.payments)) {
|
|
192
|
+
normalizedOrderRecord.payments = normalizedOrderRecord.payments.map(
|
|
193
|
+
(payment) => {
|
|
194
|
+
if (!(payment == null ? void 0 : payment[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER]))
|
|
195
|
+
return payment;
|
|
196
|
+
const nextPayment = { ...payment };
|
|
197
|
+
const metadata = { ...nextPayment.metadata || {} };
|
|
198
|
+
delete metadata.unique_payment_number;
|
|
199
|
+
delete nextPayment[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER];
|
|
200
|
+
nextPayment.metadata = metadata;
|
|
201
|
+
return nextPayment;
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
const kinds = ["product", "booking", "payment"];
|
|
206
|
+
const hasChanges = kinds.some((kind) => {
|
|
207
|
+
const stats = result.stats[kind];
|
|
208
|
+
return stats.backfilledUidCount > 0 || stats.collapsedDuplicateCount > 0 || stats.uidConflictCount > 0 || stats.anonymousRowCount > 0;
|
|
209
|
+
});
|
|
210
|
+
if (hasChanges) {
|
|
211
|
+
const summarize = (stats) => ({
|
|
212
|
+
backfilled_uid_count: stats.backfilledUidCount,
|
|
213
|
+
collapsed_duplicate_count: stats.collapsedDuplicateCount,
|
|
214
|
+
uid_conflict_count: stats.uidConflictCount,
|
|
215
|
+
anonymous_row_count: stats.anonymousRowCount
|
|
216
|
+
});
|
|
217
|
+
const context = {
|
|
218
|
+
source,
|
|
219
|
+
order_id: (order == null ? void 0 : order.order_id) ?? null,
|
|
220
|
+
external_sale_number: (order == null ? void 0 : order.external_sale_number) ?? null,
|
|
221
|
+
products: summarize(result.stats.product),
|
|
222
|
+
bookings: summarize(result.stats.booking),
|
|
223
|
+
payments: summarize(result.stats.payment)
|
|
224
|
+
};
|
|
225
|
+
const hasUnsafeIdentity = kinds.some((kind) => {
|
|
226
|
+
const stats = result.stats[kind];
|
|
227
|
+
return stats.uidConflictCount > 0 || stats.anonymousRowCount > 0;
|
|
228
|
+
});
|
|
229
|
+
if (hasUnsafeIdentity) {
|
|
230
|
+
this.logWarning("订单子项身份存在冲突或匿名行", context);
|
|
231
|
+
} else {
|
|
232
|
+
this.logInfo("订单子项身份已规范化", context);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return result.order;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* incoming 决定权威成员集合;同一持久化行仍从 existing 补齐 incoming 省略的本地展示字段。
|
|
239
|
+
*/
|
|
240
|
+
mergeAuthoritativeOrderCollection(field, existing, incoming, uidRemaps = [], options = {}) {
|
|
241
|
+
const kind = ORDER_COLLECTION_KIND_BY_FIELD[field];
|
|
242
|
+
const existingItems = Array.isArray(existing) ? existing : [];
|
|
243
|
+
if (field === "payments" && options.preserveIdentifiedPendingPayments) {
|
|
244
|
+
return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(
|
|
245
|
+
existingItems,
|
|
246
|
+
incoming,
|
|
247
|
+
{ preserveUnmatchedExistingWhen: import_payment_utils.isIdentifiedPendingOrderPayment }
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
return incoming.map((incomingItem) => {
|
|
251
|
+
const existingItem = existingItems.find(
|
|
252
|
+
(item) => (0, import_orderCollectionIdentity.isSameOrderCollectionItem)(kind, item, incomingItem)
|
|
253
|
+
);
|
|
254
|
+
if (!existingItem)
|
|
255
|
+
return (0, import_lodash_es.cloneDeep)(incomingItem);
|
|
256
|
+
const mergedItem = (0, import_orderCollectionIdentity.mergeOrderCollectionItems)(kind, existingItem, incomingItem);
|
|
257
|
+
const mergedUid = (0, import_orderCollectionIdentity.getOrderCollectionUid)(kind, mergedItem);
|
|
258
|
+
if (mergedUid) {
|
|
259
|
+
for (const from of /* @__PURE__ */ new Set([
|
|
260
|
+
(0, import_orderCollectionIdentity.getOrderCollectionReferenceUid)(kind, existingItem),
|
|
261
|
+
(0, import_orderCollectionIdentity.getOrderCollectionReferenceUid)(kind, incomingItem)
|
|
262
|
+
])) {
|
|
263
|
+
if (!from || from === mergedUid)
|
|
264
|
+
continue;
|
|
265
|
+
uidRemaps.push({
|
|
266
|
+
kind,
|
|
267
|
+
from,
|
|
268
|
+
to: mergedUid,
|
|
269
|
+
persistentId: (0, import_orderCollectionIdentity.getOrderCollectionPersistentId)(kind, incomingItem) || (0, import_orderCollectionIdentity.getOrderCollectionPersistentId)(kind, existingItem)
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return mergedItem;
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
reconcileOverwriteOrderCollections(existing, incoming) {
|
|
277
|
+
const reconciled = (0, import_lodash_es.cloneDeep)(incoming);
|
|
278
|
+
const existingRecord = existing;
|
|
279
|
+
const incomingRecord = incoming;
|
|
280
|
+
const uidRemaps = [];
|
|
281
|
+
for (const field of ORDER_AUTHORITATIVE_COLLECTION_FIELDS) {
|
|
282
|
+
if (!Array.isArray(incomingRecord[field]))
|
|
283
|
+
continue;
|
|
284
|
+
reconciled[field] = this.mergeAuthoritativeOrderCollection(
|
|
285
|
+
field,
|
|
286
|
+
existingRecord[field],
|
|
287
|
+
incomingRecord[field],
|
|
288
|
+
uidRemaps
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
return this.normalizeOrderCollectionsForIngress(
|
|
292
|
+
(0, import_orderCollectionIdentity.applyOrderCollectionUidRemaps)(reconciled, uidRemaps),
|
|
293
|
+
"overwriteExistingOrder.reconciled"
|
|
294
|
+
);
|
|
295
|
+
}
|
|
157
296
|
/**
|
|
158
297
|
* 记录订单最近一次 SQLite 写入,供 pubsub 回声去重使用。
|
|
159
298
|
*
|
|
@@ -363,17 +502,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
363
502
|
return DEFAULT_ORDER_SYNC_THROTTLE_MS;
|
|
364
503
|
}
|
|
365
504
|
async preload() {
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
this.store.list = (0, import_lodash_es.cloneDeep)(orders);
|
|
372
|
-
this.syncOrdersMap();
|
|
373
|
-
this.emitOrdersChanged([], "preload");
|
|
374
|
-
this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
375
|
-
};
|
|
376
|
-
getData();
|
|
505
|
+
const orders = await this.loadOrdersByServer();
|
|
506
|
+
this.store.list = (0, import_lodash_es.cloneDeep)(orders);
|
|
507
|
+
this.syncOrdersMap();
|
|
508
|
+
await this.emitOrdersChanged([], "preload");
|
|
509
|
+
await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
377
510
|
}
|
|
378
511
|
getOrders() {
|
|
379
512
|
return this.store.list;
|
|
@@ -385,6 +518,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
385
518
|
getOrderByOrderId(orderId) {
|
|
386
519
|
return this.store.map.get(this.getIdKey(orderId));
|
|
387
520
|
}
|
|
521
|
+
buildLocalPaymentOrderLogContext(order) {
|
|
522
|
+
if (!order)
|
|
523
|
+
return {};
|
|
524
|
+
return {
|
|
525
|
+
order_id: order.order_id ?? null,
|
|
526
|
+
external_sale_number: order.external_sale_number ?? null,
|
|
527
|
+
order_number: order.order_number ?? null,
|
|
528
|
+
shop_order_number: order.shop_order_number ?? null,
|
|
529
|
+
shop_full_order_number: order.shop_full_order_number ?? null,
|
|
530
|
+
order_status: order.status ?? null,
|
|
531
|
+
payment_status: order.payment_status ?? null,
|
|
532
|
+
is_draft_order: Number(order.is_draft_order || 0),
|
|
533
|
+
need_sync: Number(order.need_sync || 0),
|
|
534
|
+
platform: order.platform ?? null,
|
|
535
|
+
business_code: order.business_code ?? null,
|
|
536
|
+
order_sales_channel: order.order_sales_channel ?? null,
|
|
537
|
+
sales_channel: order.sales_channel ?? null,
|
|
538
|
+
order_type: order.type ?? null,
|
|
539
|
+
payments_count: Array.isArray(order.payments) ? order.payments.length : 0
|
|
540
|
+
};
|
|
541
|
+
}
|
|
388
542
|
getLocalOrderFromMemoryByLookup(lookup) {
|
|
389
543
|
const key = this.getIdKey(lookup);
|
|
390
544
|
const memoryOrderById = this.store.map.get(key);
|
|
@@ -393,28 +547,200 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
393
547
|
const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
|
|
394
548
|
return memoryOrder || null;
|
|
395
549
|
}
|
|
396
|
-
async getLocalOrderByLookup(lookup) {
|
|
550
|
+
async getLocalOrderByLookup(lookup, options = {}) {
|
|
397
551
|
const key = this.getIdKey(lookup);
|
|
552
|
+
const logContext = {
|
|
553
|
+
operation_id: options.operationId,
|
|
554
|
+
lookup: key,
|
|
555
|
+
memory_order_count: this.store.list.length
|
|
556
|
+
};
|
|
557
|
+
if (options.operationId) {
|
|
558
|
+
this.logInfo("getLocalOrderByLookup-localPayment-开始", logContext);
|
|
559
|
+
}
|
|
398
560
|
const memoryOrderById = this.store.map.get(key);
|
|
399
|
-
if (memoryOrderById)
|
|
561
|
+
if (memoryOrderById) {
|
|
562
|
+
if (options.operationId) {
|
|
563
|
+
this.logInfo("getLocalOrderByLookup-localPayment-命中内存映射", {
|
|
564
|
+
...logContext,
|
|
565
|
+
...this.buildLocalPaymentOrderLogContext(memoryOrderById)
|
|
566
|
+
});
|
|
567
|
+
}
|
|
400
568
|
return memoryOrderById;
|
|
569
|
+
}
|
|
401
570
|
const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
|
|
402
|
-
if (memoryOrder)
|
|
571
|
+
if (memoryOrder) {
|
|
572
|
+
if (options.operationId) {
|
|
573
|
+
this.logInfo("getLocalOrderByLookup-localPayment-命中内存列表", {
|
|
574
|
+
...logContext,
|
|
575
|
+
...this.buildLocalPaymentOrderLogContext(memoryOrder)
|
|
576
|
+
});
|
|
577
|
+
}
|
|
403
578
|
return memoryOrder;
|
|
579
|
+
}
|
|
580
|
+
if (options.operationId) {
|
|
581
|
+
this.logInfo("getLocalOrderByLookup-localPayment-开始读取SQLite", logContext);
|
|
582
|
+
}
|
|
404
583
|
const orders = await this.loadOrdersFromSQLite();
|
|
405
584
|
const localOrder = orders.find((order) => this.isOrderLookupMatch(order, key));
|
|
406
|
-
if (!localOrder)
|
|
585
|
+
if (!localOrder) {
|
|
586
|
+
if (options.operationId) {
|
|
587
|
+
this.logWarning("getLocalOrderByLookup-localPayment-SQLite未命中", {
|
|
588
|
+
...logContext,
|
|
589
|
+
sqlite_order_count: orders.length
|
|
590
|
+
});
|
|
591
|
+
}
|
|
407
592
|
return null;
|
|
408
|
-
|
|
593
|
+
}
|
|
594
|
+
this.store.list = this.normalizeOrdersForMemoryList(
|
|
595
|
+
orders,
|
|
596
|
+
"getLocalOrderByLookup.sqliteMemory"
|
|
597
|
+
);
|
|
409
598
|
this.syncOrdersMap();
|
|
410
|
-
|
|
599
|
+
const normalizedOrder = this.normalizeOrderForMemoryList(localOrder);
|
|
600
|
+
if (options.operationId) {
|
|
601
|
+
this.logInfo("getLocalOrderByLookup-localPayment-SQLite命中", {
|
|
602
|
+
...logContext,
|
|
603
|
+
sqlite_order_count: orders.length,
|
|
604
|
+
...this.buildLocalPaymentOrderLogContext(normalizedOrder)
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
return normalizedOrder;
|
|
608
|
+
}
|
|
609
|
+
async getLocalPayment(params) {
|
|
610
|
+
const logContext = {
|
|
611
|
+
operation_id: params.operationId,
|
|
612
|
+
sale_id: params.saleId,
|
|
613
|
+
payment_number: params.paymentNumber
|
|
614
|
+
};
|
|
615
|
+
this.logInfo("getLocalPayment-开始", logContext);
|
|
616
|
+
try {
|
|
617
|
+
const order = await this.getLocalOrderByLookup(params.saleId, {
|
|
618
|
+
operationId: params.operationId
|
|
619
|
+
});
|
|
620
|
+
if (!order) {
|
|
621
|
+
this.logWarning("getLocalPayment-订单未命中", logContext);
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
const payments = order.payments || [];
|
|
625
|
+
const match = (0, import_payment_utils.resolveOrderPaymentIdentity)(
|
|
626
|
+
payments,
|
|
627
|
+
params.paymentNumber,
|
|
628
|
+
"compat"
|
|
629
|
+
);
|
|
630
|
+
if (!match) {
|
|
631
|
+
this.logWarning("getLocalPayment-支付项未命中", {
|
|
632
|
+
...logContext,
|
|
633
|
+
...this.buildLocalPaymentOrderLogContext(order),
|
|
634
|
+
payments
|
|
635
|
+
});
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
this.logInfo("getLocalPayment-支付项命中", {
|
|
639
|
+
...logContext,
|
|
640
|
+
...this.buildLocalPaymentOrderLogContext(order),
|
|
641
|
+
matched_by: match.matchedBy,
|
|
642
|
+
payment_index: match.index,
|
|
643
|
+
payment: match.payment
|
|
644
|
+
});
|
|
645
|
+
return {
|
|
646
|
+
order,
|
|
647
|
+
payment: match.payment,
|
|
648
|
+
paymentIndex: match.index,
|
|
649
|
+
matchedBy: match.matchedBy
|
|
650
|
+
};
|
|
651
|
+
} catch (error) {
|
|
652
|
+
this.logError("getLocalPayment-查询失败", {
|
|
653
|
+
...logContext,
|
|
654
|
+
error: error instanceof Error ? error.message : String(error)
|
|
655
|
+
});
|
|
656
|
+
throw error;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
async updateLocalPayment(params) {
|
|
660
|
+
const logContext = {
|
|
661
|
+
operation_id: params.operationId,
|
|
662
|
+
sale_id: params.saleId,
|
|
663
|
+
payment_number: params.paymentNumber,
|
|
664
|
+
incoming_payment_update: params.updates
|
|
665
|
+
};
|
|
666
|
+
this.logInfo("updateLocalPayment-开始", logContext);
|
|
667
|
+
const found = await this.getLocalPayment(params);
|
|
668
|
+
if (!found) {
|
|
669
|
+
this.logWarning("updateLocalPayment-支付项未命中", logContext);
|
|
670
|
+
return null;
|
|
671
|
+
}
|
|
672
|
+
const previousPayment = (0, import_lodash_es.cloneDeep)(found.payment);
|
|
673
|
+
const nextPayment = (0, import_payment_utils.mergeOrderPaymentRecord)(found.payment, {
|
|
674
|
+
...params.updates,
|
|
675
|
+
updated_at: params.updates.updated_at || (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
|
|
676
|
+
});
|
|
677
|
+
const nextOrder = {
|
|
678
|
+
...found.order,
|
|
679
|
+
payments: (found.order.payments || []).map((payment, index) => index === found.paymentIndex ? nextPayment : payment),
|
|
680
|
+
updated_at: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
|
|
681
|
+
};
|
|
682
|
+
const paymentContext = {
|
|
683
|
+
...logContext,
|
|
684
|
+
matched_by: found.matchedBy,
|
|
685
|
+
payment_index: found.paymentIndex,
|
|
686
|
+
...this.buildLocalPaymentOrderLogContext(nextOrder),
|
|
687
|
+
previous_payment: previousPayment,
|
|
688
|
+
payment: nextPayment
|
|
689
|
+
};
|
|
690
|
+
this.logInfo("updateLocalPayment-支付项合并完成", paymentContext);
|
|
691
|
+
const targetIndex = this.findOrderIndexByIdentity(this.store.list, found.order);
|
|
692
|
+
const shouldKeepInMemory = this.shouldKeepOrderInMemory(nextOrder);
|
|
693
|
+
if (targetIndex < 0 && shouldKeepInMemory) {
|
|
694
|
+
this.logError("updateLocalPayment-订单Store索引未命中", paymentContext);
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
const previousList = this.store.list;
|
|
698
|
+
this.store.list = shouldKeepInMemory ? this.store.list.map((order, index) => index === targetIndex ? nextOrder : order) : this.store.list.filter((_, index) => index !== targetIndex);
|
|
699
|
+
this.syncOrdersMap();
|
|
700
|
+
const storageOrder = this.withoutSyntheticDraftOrderId(nextOrder);
|
|
701
|
+
try {
|
|
702
|
+
this.logInfo("updateLocalPayment-SQLite写入开始", {
|
|
703
|
+
...paymentContext,
|
|
704
|
+
storage_order_id: storageOrder.order_id ?? null
|
|
705
|
+
});
|
|
706
|
+
await this.updateOrderInSQLite(storageOrder, "updateLocalPayment", { throwOnError: true });
|
|
707
|
+
this.logInfo("updateLocalPayment-SQLite写入完成", {
|
|
708
|
+
...paymentContext,
|
|
709
|
+
storage_order_id: storageOrder.order_id ?? null
|
|
710
|
+
});
|
|
711
|
+
} catch (error) {
|
|
712
|
+
this.store.list = previousList;
|
|
713
|
+
this.syncOrdersMap();
|
|
714
|
+
this.logError("updateLocalPayment-SQLite写入失败并回滚内存", {
|
|
715
|
+
...paymentContext,
|
|
716
|
+
storage_order_id: storageOrder.order_id ?? null,
|
|
717
|
+
error: error instanceof Error ? error.message : String(error)
|
|
718
|
+
});
|
|
719
|
+
throw error;
|
|
720
|
+
}
|
|
721
|
+
if (shouldKeepInMemory || targetIndex >= 0) {
|
|
722
|
+
await this.emitOrdersChanged(
|
|
723
|
+
shouldKeepInMemory ? [nextOrder] : [],
|
|
724
|
+
shouldKeepInMemory ? "updateLocalPayment" : "updateLocalPayment.sqliteOnlyDraft"
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
this.logInfo("updateLocalPayment-变更事件完成", paymentContext);
|
|
728
|
+
return { order: nextOrder, payment: nextPayment, previousPayment };
|
|
411
729
|
}
|
|
412
730
|
async loadOrdersByServer() {
|
|
413
731
|
var _a;
|
|
414
732
|
let orderList = [];
|
|
733
|
+
const protectedOrdersBeforeRemoteFetch = (await this.loadOrdersFromSQLite()).filter(
|
|
734
|
+
(order) => this.shouldProtectLocalOrderFromRemoteSnapshot(order)
|
|
735
|
+
);
|
|
415
736
|
this.logInfo("loadOrdersByServer-开始", {
|
|
416
737
|
hasOrderDataSource: !!this.orderDataSource,
|
|
417
|
-
query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null
|
|
738
|
+
query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null,
|
|
739
|
+
protectedLocalOrderCount: protectedOrdersBeforeRemoteFetch.length,
|
|
740
|
+
protectedPendingPaymentCount: protectedOrdersBeforeRemoteFetch.reduce(
|
|
741
|
+
(count, order) => count + this.getIdentifiedPendingPayments(order).length,
|
|
742
|
+
0
|
|
743
|
+
)
|
|
418
744
|
});
|
|
419
745
|
if (this.orderDataSource) {
|
|
420
746
|
try {
|
|
@@ -434,10 +760,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
434
760
|
return this.store.list;
|
|
435
761
|
}
|
|
436
762
|
}
|
|
437
|
-
const mergedOrders = await this.replaceOrdersSnapshotInSQLite(
|
|
438
|
-
|
|
763
|
+
const mergedOrders = await this.replaceOrdersSnapshotInSQLite(
|
|
764
|
+
orderList,
|
|
765
|
+
"loadOrdersByServer",
|
|
766
|
+
protectedOrdersBeforeRemoteFetch
|
|
767
|
+
);
|
|
768
|
+
const memoryOrders = this.normalizeOrdersForMemoryList(
|
|
769
|
+
mergedOrders,
|
|
770
|
+
"loadOrdersByServer.memory"
|
|
771
|
+
);
|
|
439
772
|
this.logInfo("loadOrdersByServer-结束", {
|
|
440
|
-
count: memoryOrders.length
|
|
773
|
+
count: memoryOrders.length,
|
|
774
|
+
persistedCount: mergedOrders.length,
|
|
775
|
+
sqliteOnlyDraftCount: mergedOrders.length - memoryOrders.length
|
|
441
776
|
});
|
|
442
777
|
await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded, memoryOrders);
|
|
443
778
|
return memoryOrders;
|
|
@@ -457,18 +792,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
457
792
|
try {
|
|
458
793
|
this.updateCreateStore();
|
|
459
794
|
const orders = await this.loadOrdersByServer();
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
});
|
|
469
|
-
} else {
|
|
470
|
-
this.logInfo("silentRefresh: 服务器未返回数据");
|
|
471
|
-
}
|
|
795
|
+
this.store.list = (0, import_lodash_es.cloneDeep)(orders);
|
|
796
|
+
this.syncOrdersMap();
|
|
797
|
+
await this.emitOrdersChanged([], "silentRefresh");
|
|
798
|
+
await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
799
|
+
this.logInfo("silentRefresh 完成", {
|
|
800
|
+
orderCount: orders.length,
|
|
801
|
+
duration: `${Date.now() - startTime}ms`
|
|
802
|
+
});
|
|
472
803
|
return this.store.list;
|
|
473
804
|
} catch (error) {
|
|
474
805
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -479,19 +810,44 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
479
810
|
return this.store.list;
|
|
480
811
|
}
|
|
481
812
|
}
|
|
482
|
-
normalizeOrderForMemoryList(order) {
|
|
483
|
-
const
|
|
484
|
-
|
|
485
|
-
|
|
813
|
+
normalizeOrderForMemoryList(order, source = "normalizeOrderForMemoryList") {
|
|
814
|
+
const normalizedOrder = this.normalizeOrderCollectionsForIngress(order, source);
|
|
815
|
+
const externalSaleNumber = normalizedOrder == null ? void 0 : normalizedOrder.external_sale_number;
|
|
816
|
+
if (this.isDraftOrder(normalizedOrder) && !this.hasRealOrderId(normalizedOrder)) {
|
|
817
|
+
return normalizedOrder;
|
|
818
|
+
}
|
|
819
|
+
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) !== "") {
|
|
820
|
+
return normalizedOrder;
|
|
486
821
|
}
|
|
487
822
|
if (externalSaleNumber === void 0 || externalSaleNumber === null || externalSaleNumber === "") {
|
|
488
|
-
return
|
|
823
|
+
return normalizedOrder;
|
|
489
824
|
}
|
|
490
825
|
return {
|
|
491
|
-
...
|
|
826
|
+
...normalizedOrder,
|
|
492
827
|
order_id: externalSaleNumber
|
|
493
828
|
};
|
|
494
829
|
}
|
|
830
|
+
normalizeOrdersForMemoryList(orders, source) {
|
|
831
|
+
return orders.map((order) => this.normalizeOrderForMemoryList(order, source)).filter((order) => this.shouldKeepOrderInMemory(order));
|
|
832
|
+
}
|
|
833
|
+
hasRealOrderId(order) {
|
|
834
|
+
if (!order || this.isBlankIdentityValue(order.order_id))
|
|
835
|
+
return false;
|
|
836
|
+
const externalSaleNumber = order.external_sale_number;
|
|
837
|
+
return !(this.isDraftOrder(order) && !this.isBlankIdentityValue(externalSaleNumber) && String(order.order_id) === String(externalSaleNumber));
|
|
838
|
+
}
|
|
839
|
+
shouldKeepOrderInMemory(order) {
|
|
840
|
+
return !this.isDraftOrder(order) || this.hasRealOrderId(order);
|
|
841
|
+
}
|
|
842
|
+
withoutSyntheticDraftOrderId(order) {
|
|
843
|
+
const externalSaleNumber = order.external_sale_number;
|
|
844
|
+
if (Number(order.is_draft_order || 0) !== 1 || order.order_id === void 0 || externalSaleNumber === void 0 || String(order.order_id) !== String(externalSaleNumber)) {
|
|
845
|
+
return order;
|
|
846
|
+
}
|
|
847
|
+
const next = { ...order };
|
|
848
|
+
delete next.order_id;
|
|
849
|
+
return next;
|
|
850
|
+
}
|
|
495
851
|
/**
|
|
496
852
|
* 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
|
|
497
853
|
* 适用于"按 order_id 主动刷新本地订单详情"的代理场景。
|
|
@@ -511,32 +867,42 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
511
867
|
orderId,
|
|
512
868
|
storeOrderCountBefore: this.store.list.length
|
|
513
869
|
});
|
|
870
|
+
const normalizedFresh = this.normalizeOrderForMemoryList(
|
|
871
|
+
fresh,
|
|
872
|
+
"overwriteExistingOrder.incoming"
|
|
873
|
+
);
|
|
874
|
+
const existingOrder = this.store.map.get(key);
|
|
875
|
+
const reconciledFresh = this.reconcileOverwriteOrderCollections(
|
|
876
|
+
existingOrder,
|
|
877
|
+
normalizedFresh
|
|
878
|
+
);
|
|
514
879
|
this.store.list = this.store.list.map((order) => {
|
|
515
880
|
const id = order == null ? void 0 : order.order_id;
|
|
516
|
-
if (id === void 0 || id === null)
|
|
517
|
-
return order;
|
|
518
|
-
|
|
881
|
+
if (id === void 0 || id === null) {
|
|
882
|
+
return this.normalizeOrderForMemoryList(order, "overwriteExistingOrder.existingMemory");
|
|
883
|
+
}
|
|
884
|
+
return this.getIdKey(id) === key ? reconciledFresh : this.normalizeOrderForMemoryList(order, "overwriteExistingOrder.existingMemory");
|
|
519
885
|
});
|
|
520
886
|
this.syncOrdersMap();
|
|
521
|
-
await this.updateOrderInSQLite(
|
|
887
|
+
await this.updateOrderInSQLite(reconciledFresh, "overwriteExistingOrder");
|
|
522
888
|
this.logInfo("overwriteExistingOrder-结束", {
|
|
523
889
|
orderId,
|
|
524
890
|
storeOrderCountAfter: this.store.list.length
|
|
525
891
|
});
|
|
526
|
-
await this.emitOrdersChanged([
|
|
892
|
+
await this.emitOrdersChanged([reconciledFresh], "overwriteExistingOrder");
|
|
527
893
|
return { overwritten: true };
|
|
528
894
|
}
|
|
529
895
|
/**
|
|
530
896
|
* 将远端拉取的订单合并进本地 store(已存在则更新,不存在则追加),落库并 emit onOrdersChanged。
|
|
531
897
|
* 供 /update/localOrder 等在「本地尚无该单」时写入新建单。
|
|
532
898
|
*/
|
|
533
|
-
async upsertOrdersFromRemote(freshOrders) {
|
|
899
|
+
async upsertOrdersFromRemote(freshOrders, source = "upsertOrdersFromRemote") {
|
|
534
900
|
if (!(freshOrders == null ? void 0 : freshOrders.length)) {
|
|
535
901
|
this.logInfo("upsertOrdersFromRemote-订单列表为空", {});
|
|
536
902
|
return;
|
|
537
903
|
}
|
|
538
|
-
this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length });
|
|
539
|
-
await this.mergeOrdersToStore(freshOrders,
|
|
904
|
+
this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length, source });
|
|
905
|
+
await this.mergeOrdersToStore(freshOrders, source);
|
|
540
906
|
}
|
|
541
907
|
async markOrderSyncedByExternalSaleNumber(params) {
|
|
542
908
|
const externalSaleNumber = params.externalSaleNumber;
|
|
@@ -562,7 +928,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
562
928
|
...existing,
|
|
563
929
|
...params.patch || {},
|
|
564
930
|
external_sale_number: existing.external_sale_number ?? externalSaleNumber,
|
|
565
|
-
need_sync: 0
|
|
931
|
+
need_sync: 0,
|
|
932
|
+
is_draft_order: 0
|
|
566
933
|
});
|
|
567
934
|
const storageKey = this.getOrderStorageKey(nextOrder) || key;
|
|
568
935
|
this.store.list = this.store.list.map((order, index) => {
|
|
@@ -587,7 +954,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
587
954
|
* 将本地待同步订单按 SQLite storage key 合并进 store 并落库。
|
|
588
955
|
* checkout 离线兜底可能没有 order_id,但通常会有 external_sale_number。
|
|
589
956
|
*/
|
|
590
|
-
async upsertPendingSyncOrders(pendingOrders) {
|
|
957
|
+
async upsertPendingSyncOrders(pendingOrders, options = {}) {
|
|
591
958
|
if (!(pendingOrders == null ? void 0 : pendingOrders.length)) {
|
|
592
959
|
this.logInfo("upsertPendingSyncOrders-订单列表为空", {});
|
|
593
960
|
return;
|
|
@@ -595,11 +962,26 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
595
962
|
const pendingMap = /* @__PURE__ */ new Map();
|
|
596
963
|
const memoryPendingMap = /* @__PURE__ */ new Map();
|
|
597
964
|
for (const order of pendingOrders) {
|
|
598
|
-
const
|
|
965
|
+
const normalizedOrder = this.normalizeOrderCollectionsForIngress(
|
|
966
|
+
order,
|
|
967
|
+
"upsertPendingSyncOrders.incoming"
|
|
968
|
+
);
|
|
969
|
+
const pendingOrder = {
|
|
970
|
+
...normalizedOrder,
|
|
971
|
+
need_sync: 1,
|
|
972
|
+
is_draft_order: 0
|
|
973
|
+
};
|
|
974
|
+
const storageKey = this.getOrderStorageKey(pendingOrder);
|
|
599
975
|
if (!storageKey)
|
|
600
976
|
continue;
|
|
601
|
-
pendingMap.set(storageKey,
|
|
602
|
-
memoryPendingMap.set(
|
|
977
|
+
pendingMap.set(storageKey, pendingOrder);
|
|
978
|
+
memoryPendingMap.set(
|
|
979
|
+
storageKey,
|
|
980
|
+
this.normalizeOrderForMemoryList(
|
|
981
|
+
pendingOrder,
|
|
982
|
+
"upsertPendingSyncOrders.memory"
|
|
983
|
+
)
|
|
984
|
+
);
|
|
603
985
|
}
|
|
604
986
|
if (pendingMap.size === 0) {
|
|
605
987
|
this.logError("upsertPendingSyncOrders-订单缺少可落库标识", {
|
|
@@ -608,9 +990,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
608
990
|
return;
|
|
609
991
|
}
|
|
610
992
|
this.logInfo("upsertPendingSyncOrders-开始", { count: pendingMap.size });
|
|
611
|
-
const patchedOrders = [...pendingMap.values()];
|
|
612
993
|
const mergeActions = {};
|
|
613
|
-
const updatedList =
|
|
994
|
+
const updatedList = this.store.list.map(
|
|
995
|
+
(order) => this.normalizeOrderForMemoryList(order, "upsertPendingSyncOrders.existingMemory")
|
|
996
|
+
);
|
|
614
997
|
const identityKeyToIndex = /* @__PURE__ */ new Map();
|
|
615
998
|
for (let index = 0; index < updatedList.length; index += 1) {
|
|
616
999
|
for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
|
|
@@ -624,11 +1007,22 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
624
1007
|
this.getOrderIdentityMatchKeys(pendingOrder)
|
|
625
1008
|
);
|
|
626
1009
|
if (matchIndex >= 0) {
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
1010
|
+
const existingOrder = updatedList[matchIndex];
|
|
1011
|
+
const mergedOrder = this.mergeOrderRecords(existingOrder, pendingOrder);
|
|
1012
|
+
const nextOrder = {
|
|
1013
|
+
...mergedOrder,
|
|
1014
|
+
need_sync: 1,
|
|
1015
|
+
is_draft_order: 0
|
|
1016
|
+
};
|
|
1017
|
+
updatedList[matchIndex] = nextOrder;
|
|
1018
|
+
const pendingSnapshot = pendingMap.get(storageKey);
|
|
1019
|
+
if (pendingSnapshot) {
|
|
1020
|
+
pendingMap.set(
|
|
1021
|
+
storageKey,
|
|
1022
|
+
this.reconcileOverwriteOrderCollections(existingOrder, pendingSnapshot)
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
this.registerOrderIdentityKeys(identityKeyToIndex, nextOrder, matchIndex);
|
|
632
1026
|
mergeActions[storageKey] = "update";
|
|
633
1027
|
continue;
|
|
634
1028
|
}
|
|
@@ -637,15 +1031,126 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
637
1031
|
this.registerOrderIdentityKeys(identityKeyToIndex, pendingOrder, insertIndex);
|
|
638
1032
|
mergeActions[storageKey] = "insert";
|
|
639
1033
|
}
|
|
1034
|
+
const patchedOrders = [...pendingMap.values()];
|
|
1035
|
+
const previousList = this.store.list;
|
|
640
1036
|
this.store.list = this.runOrderStoreSelfCheck(updatedList, "upsertPendingSyncOrders.store");
|
|
641
1037
|
this.syncOrdersMap();
|
|
642
|
-
|
|
1038
|
+
try {
|
|
1039
|
+
await this.patchOrdersInSQLite(
|
|
1040
|
+
patchedOrders,
|
|
1041
|
+
"upsertPendingSyncOrders",
|
|
1042
|
+
mergeActions,
|
|
1043
|
+
options
|
|
1044
|
+
);
|
|
1045
|
+
} catch (error) {
|
|
1046
|
+
this.store.list = previousList;
|
|
1047
|
+
this.syncOrdersMap();
|
|
1048
|
+
throw error;
|
|
1049
|
+
}
|
|
643
1050
|
this.logInfo("upsertPendingSyncOrders-结束", {
|
|
644
1051
|
count: patchedOrders.length,
|
|
645
1052
|
storeOrderCountAfter: this.store.list.length
|
|
646
1053
|
});
|
|
647
1054
|
await this.emitOrdersChanged(patchedOrders, "upsertPendingSyncOrders");
|
|
648
1055
|
}
|
|
1056
|
+
/**
|
|
1057
|
+
* 将 POS 草稿订单按 SQLite storage key 落库。
|
|
1058
|
+
* 只有具备真实 order_id 的草稿进入 store;其余草稿仅供本地恢复查询。
|
|
1059
|
+
*/
|
|
1060
|
+
async upsertLocalDraftOrders(draftOrders) {
|
|
1061
|
+
if (!(draftOrders == null ? void 0 : draftOrders.length)) {
|
|
1062
|
+
this.logInfo("upsertLocalDraftOrders-订单列表为空", {});
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
const draftMap = /* @__PURE__ */ new Map();
|
|
1066
|
+
const memoryDraftMap = /* @__PURE__ */ new Map();
|
|
1067
|
+
for (const order of draftOrders) {
|
|
1068
|
+
const draftOrder = {
|
|
1069
|
+
...order,
|
|
1070
|
+
need_sync: 0,
|
|
1071
|
+
is_draft_order: 1
|
|
1072
|
+
};
|
|
1073
|
+
const storageKey = this.getOrderStorageKey(draftOrder);
|
|
1074
|
+
if (!storageKey)
|
|
1075
|
+
continue;
|
|
1076
|
+
draftMap.set(storageKey, draftOrder);
|
|
1077
|
+
const memoryDraftOrder = this.normalizeOrderForMemoryList(draftOrder);
|
|
1078
|
+
if (this.shouldKeepOrderInMemory(memoryDraftOrder)) {
|
|
1079
|
+
memoryDraftMap.set(storageKey, memoryDraftOrder);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
if (draftMap.size === 0) {
|
|
1083
|
+
this.logError("upsertLocalDraftOrders-订单缺少可落库标识", {
|
|
1084
|
+
count: draftOrders.length
|
|
1085
|
+
});
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
this.logInfo("upsertLocalDraftOrders-开始", {
|
|
1089
|
+
count: draftMap.size,
|
|
1090
|
+
memoryDraftCount: memoryDraftMap.size,
|
|
1091
|
+
sqliteOnlyDraftCount: draftMap.size - memoryDraftMap.size
|
|
1092
|
+
});
|
|
1093
|
+
const patchedOrders = [...draftMap.values()];
|
|
1094
|
+
const mergeActions = {};
|
|
1095
|
+
const updatedList = this.store.list.filter((order) => this.shouldKeepOrderInMemory(order));
|
|
1096
|
+
const identityKeyToIndex = /* @__PURE__ */ new Map();
|
|
1097
|
+
for (let index = 0; index < updatedList.length; index += 1) {
|
|
1098
|
+
for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
|
|
1099
|
+
if (!identityKeyToIndex.has(key))
|
|
1100
|
+
identityKeyToIndex.set(key, index);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
for (const [storageKey, draftOrder] of memoryDraftMap.entries()) {
|
|
1104
|
+
const matchIndex = this.lookupOrderIndexByIdentityKeys(
|
|
1105
|
+
identityKeyToIndex,
|
|
1106
|
+
this.getOrderIdentityMatchKeys(draftOrder)
|
|
1107
|
+
);
|
|
1108
|
+
if (matchIndex >= 0) {
|
|
1109
|
+
const mergedOrder = this.mergeOrderRecords(updatedList[matchIndex], draftOrder);
|
|
1110
|
+
const nextOrder = {
|
|
1111
|
+
...mergedOrder,
|
|
1112
|
+
need_sync: 0,
|
|
1113
|
+
is_draft_order: 1
|
|
1114
|
+
};
|
|
1115
|
+
updatedList[matchIndex] = nextOrder;
|
|
1116
|
+
this.registerOrderIdentityKeys(identityKeyToIndex, nextOrder, matchIndex);
|
|
1117
|
+
mergeActions[storageKey] = "update";
|
|
1118
|
+
continue;
|
|
1119
|
+
}
|
|
1120
|
+
const insertIndex = updatedList.length;
|
|
1121
|
+
updatedList.push(draftOrder);
|
|
1122
|
+
this.registerOrderIdentityKeys(identityKeyToIndex, draftOrder, insertIndex);
|
|
1123
|
+
mergeActions[storageKey] = "insert";
|
|
1124
|
+
}
|
|
1125
|
+
const previousList = this.store.list;
|
|
1126
|
+
this.store.list = this.runOrderStoreSelfCheck(updatedList, "upsertLocalDraftOrders.store");
|
|
1127
|
+
this.syncOrdersMap();
|
|
1128
|
+
try {
|
|
1129
|
+
await this.patchOrdersInSQLite(
|
|
1130
|
+
patchedOrders,
|
|
1131
|
+
"upsertLocalDraftOrders",
|
|
1132
|
+
mergeActions,
|
|
1133
|
+
{ throwOnError: true }
|
|
1134
|
+
);
|
|
1135
|
+
} catch (error) {
|
|
1136
|
+
this.store.list = previousList;
|
|
1137
|
+
this.syncOrdersMap();
|
|
1138
|
+
throw error;
|
|
1139
|
+
}
|
|
1140
|
+
this.logInfo("upsertLocalDraftOrders-结束", {
|
|
1141
|
+
count: patchedOrders.length,
|
|
1142
|
+
storeOrderCountAfter: this.store.list.length
|
|
1143
|
+
});
|
|
1144
|
+
const removedLegacyMemoryDraft = previousList.some(
|
|
1145
|
+
(order) => !this.shouldKeepOrderInMemory(order)
|
|
1146
|
+
);
|
|
1147
|
+
if (memoryDraftMap.size > 0 || removedLegacyMemoryDraft) {
|
|
1148
|
+
await this.emitOrdersChanged(
|
|
1149
|
+
patchedOrders.filter((order) => this.shouldKeepOrderInMemory(order)),
|
|
1150
|
+
"upsertLocalDraftOrders"
|
|
1151
|
+
);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
649
1154
|
/**
|
|
650
1155
|
* 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
|
|
651
1156
|
*/
|
|
@@ -678,6 +1183,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
678
1183
|
super.destroy();
|
|
679
1184
|
}
|
|
680
1185
|
syncOrdersMap() {
|
|
1186
|
+
this.store.list = this.store.list.filter((order) => this.shouldKeepOrderInMemory(order));
|
|
681
1187
|
this.store.map.clear();
|
|
682
1188
|
for (const order of this.store.list) {
|
|
683
1189
|
const primaryIdentity = this.getOrderMapKey(order);
|
|
@@ -969,7 +1475,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
969
1475
|
const uniqueFreshCount = uniqueFreshOrders.length;
|
|
970
1476
|
const patchedOrders = [];
|
|
971
1477
|
const mergeActions = {};
|
|
972
|
-
const updatedList =
|
|
1478
|
+
const updatedList = this.store.list.map(
|
|
1479
|
+
(order) => this.normalizeOrderForMemoryList(order, `${source}.existingMemory`)
|
|
1480
|
+
);
|
|
973
1481
|
const identityKeyToIndex = /* @__PURE__ */ new Map();
|
|
974
1482
|
for (let index = 0; index < updatedList.length; index += 1) {
|
|
975
1483
|
const identityKeys = this.getOrderIdentityMatchKeys(updatedList[index]);
|
|
@@ -998,9 +1506,43 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
998
1506
|
});
|
|
999
1507
|
continue;
|
|
1000
1508
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1509
|
+
if (this.isDraftOrder(existingOrder) && this.shouldProtectDraftOrderFromIncoming(source)) {
|
|
1510
|
+
this.logInfo("mergeOrdersToStore-跳过 draft 订单远端覆盖", {
|
|
1511
|
+
source,
|
|
1512
|
+
order_id: existingOrder.order_id ?? fresh.order_id ?? null,
|
|
1513
|
+
external_sale_number: existingOrder.external_sale_number ?? fresh.external_sale_number ?? null,
|
|
1514
|
+
local_is_draft_order: existingOrder.is_draft_order ?? null,
|
|
1515
|
+
remote_is_draft_order: fresh.is_draft_order ?? null,
|
|
1516
|
+
reason: "protect_draft_order_from_remote_echo"
|
|
1517
|
+
});
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
let mergedOrder = this.mergeOrderRecords(existingOrder, fresh);
|
|
1521
|
+
let adjustedMatchIndex = matchIndex;
|
|
1522
|
+
const duplicateIndexes = /* @__PURE__ */ new Set();
|
|
1523
|
+
for (const key of freshIdentityKeys) {
|
|
1524
|
+
const duplicateIndex = identityKeyToIndex.get(key);
|
|
1525
|
+
if (duplicateIndex === void 0 || duplicateIndex === matchIndex)
|
|
1526
|
+
continue;
|
|
1527
|
+
duplicateIndexes.add(duplicateIndex);
|
|
1528
|
+
}
|
|
1529
|
+
if (duplicateIndexes.size > 0) {
|
|
1530
|
+
for (const duplicateIndex of [...duplicateIndexes].sort((left, right) => right - left)) {
|
|
1531
|
+
mergedOrder = this.mergeOrderRecords(mergedOrder, updatedList[duplicateIndex]);
|
|
1532
|
+
updatedList.splice(duplicateIndex, 1);
|
|
1533
|
+
if (duplicateIndex < adjustedMatchIndex)
|
|
1534
|
+
adjustedMatchIndex -= 1;
|
|
1535
|
+
}
|
|
1536
|
+
identityKeyToIndex.clear();
|
|
1537
|
+
for (let index = 0; index < updatedList.length; index += 1) {
|
|
1538
|
+
for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
|
|
1539
|
+
if (!identityKeyToIndex.has(key))
|
|
1540
|
+
identityKeyToIndex.set(key, index);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
updatedList[adjustedMatchIndex] = mergedOrder;
|
|
1545
|
+
this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, adjustedMatchIndex);
|
|
1004
1546
|
patchedOrders.push(mergedOrder);
|
|
1005
1547
|
if (mergeKey)
|
|
1006
1548
|
mergeActions[mergeKey] = "update";
|
|
@@ -1236,56 +1778,29 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1236
1778
|
}
|
|
1237
1779
|
return result;
|
|
1238
1780
|
}
|
|
1239
|
-
getPaymentMergeKey(payment) {
|
|
1240
|
-
var _a;
|
|
1241
|
-
const record = payment;
|
|
1242
|
-
if (!record)
|
|
1243
|
-
return "";
|
|
1244
|
-
const uniquePaymentNumber = (_a = record.metadata) == null ? void 0 : _a.unique_payment_number;
|
|
1245
|
-
if (!this.isBlankIdentityValue(uniquePaymentNumber)) {
|
|
1246
|
-
return `unique:${String(uniquePaymentNumber)}`;
|
|
1247
|
-
}
|
|
1248
|
-
const orderPaymentId = record.order_payment_id;
|
|
1249
|
-
if (!this.isBlankIdentityValue(orderPaymentId))
|
|
1250
|
-
return `order_payment:${String(orderPaymentId)}`;
|
|
1251
|
-
const code = record.code;
|
|
1252
|
-
const customPaymentId = record.custom_payment_id;
|
|
1253
|
-
if (!this.isBlankIdentityValue(code) && !this.isBlankIdentityValue(customPaymentId)) {
|
|
1254
|
-
return `custom:${String(code)}#${String(customPaymentId)}`;
|
|
1255
|
-
}
|
|
1256
|
-
return "";
|
|
1257
|
-
}
|
|
1258
1781
|
mergeOrderPaymentLists(existing, incoming) {
|
|
1259
1782
|
const existingList = Array.isArray(existing) ? existing : [];
|
|
1260
1783
|
const incomingList = Array.isArray(incoming) ? incoming : [];
|
|
1261
1784
|
if (incomingList.length === 0)
|
|
1262
1785
|
return (0, import_lodash_es.cloneDeep)(existingList);
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
if (!key)
|
|
1269
|
-
continue;
|
|
1270
|
-
existingByKey.set(key, payment);
|
|
1271
|
-
}
|
|
1272
|
-
return incomingList.map((payment) => {
|
|
1273
|
-
const incomingPayment = payment;
|
|
1274
|
-
const key = this.getPaymentMergeKey(incomingPayment);
|
|
1275
|
-
const existingPayment = key ? existingByKey.get(key) : void 0;
|
|
1276
|
-
if (!existingPayment)
|
|
1277
|
-
return (0, import_lodash_es.cloneDeep)(incomingPayment);
|
|
1278
|
-
return {
|
|
1279
|
-
...(0, import_lodash_es.cloneDeep)(existingPayment),
|
|
1280
|
-
...(0, import_lodash_es.cloneDeep)(incomingPayment),
|
|
1281
|
-
metadata: {
|
|
1282
|
-
...(0, import_lodash_es.cloneDeep)(existingPayment.metadata || {}),
|
|
1283
|
-
...(0, import_lodash_es.cloneDeep)(incomingPayment.metadata || {})
|
|
1284
|
-
}
|
|
1285
|
-
};
|
|
1286
|
-
});
|
|
1786
|
+
return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(existingList, incomingList);
|
|
1787
|
+
}
|
|
1788
|
+
getIdentifiedPendingPayments(order) {
|
|
1789
|
+
const payments = Array.isArray(order == null ? void 0 : order.payments) ? order.payments : [];
|
|
1790
|
+
return payments.filter((payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment));
|
|
1287
1791
|
}
|
|
1288
|
-
|
|
1792
|
+
shouldProtectLocalOrderFromRemoteSnapshot(order) {
|
|
1793
|
+
return this.isPendingSyncOrder(order) || this.isDraftOrder(order) || this.getIdentifiedPendingPayments(order).length > 0;
|
|
1794
|
+
}
|
|
1795
|
+
getUnmatchedIdentifiedPendingPayments(existing, incoming) {
|
|
1796
|
+
const existingPayments = Array.isArray(existing) ? existing : [];
|
|
1797
|
+
const incomingPayments = Array.isArray(incoming) ? incoming : [];
|
|
1798
|
+
const incomingIdentityKeys = new Set(
|
|
1799
|
+
incomingPayments.flatMap((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
|
|
1800
|
+
);
|
|
1801
|
+
return existingPayments.filter((payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment) && !(0, import_payment_utils.getOrderPaymentIdentityKeys)(payment).some((key) => incomingIdentityKeys.has(key)));
|
|
1802
|
+
}
|
|
1803
|
+
mergeOrderRecords(existing, incoming) {
|
|
1289
1804
|
const preferred = this.pickPreferredOrder(existing, incoming);
|
|
1290
1805
|
const secondary = preferred === existing ? incoming : existing;
|
|
1291
1806
|
const merged = {
|
|
@@ -1306,8 +1821,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1306
1821
|
"updated_at",
|
|
1307
1822
|
"shop_discount",
|
|
1308
1823
|
"summary",
|
|
1309
|
-
"products",
|
|
1310
|
-
"bookings",
|
|
1311
1824
|
"note",
|
|
1312
1825
|
"customer_id",
|
|
1313
1826
|
"customer_name",
|
|
@@ -1316,13 +1829,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1316
1829
|
"contacts_info",
|
|
1317
1830
|
"phone",
|
|
1318
1831
|
"email",
|
|
1319
|
-
"relation_forms"
|
|
1832
|
+
"relation_forms",
|
|
1833
|
+
"is_draft_order"
|
|
1320
1834
|
];
|
|
1321
1835
|
const mergedRecord = merged;
|
|
1322
1836
|
const preferredRecord = preferred;
|
|
1323
1837
|
const secondaryRecord = secondary;
|
|
1838
|
+
const existingRecord = existing;
|
|
1324
1839
|
const incomingRecord = incoming;
|
|
1325
|
-
const
|
|
1840
|
+
const childUidRemaps = [];
|
|
1326
1841
|
for (const field of fieldsToPreserve) {
|
|
1327
1842
|
if (!this.isBlankIdentityValue(preferredRecord[field])) {
|
|
1328
1843
|
mergedRecord[field] = preferredRecord[field];
|
|
@@ -1332,8 +1847,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1332
1847
|
mergedRecord[field] = secondaryRecord[field];
|
|
1333
1848
|
}
|
|
1334
1849
|
}
|
|
1335
|
-
const hasIncomingProducts = Object.prototype.hasOwnProperty.call(incomingRecord, "products");
|
|
1336
|
-
const shouldUseIncomingProductsSnapshot = (options == null ? void 0 : options.preferIncomingProducts) === true && hasIncomingProducts && incomingRecord.products !== void 0 && incomingRecord.products !== null;
|
|
1337
1850
|
for (const field of incomingPatchFields) {
|
|
1338
1851
|
if (!Object.prototype.hasOwnProperty.call(incomingRecord, field))
|
|
1339
1852
|
continue;
|
|
@@ -1343,21 +1856,44 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1343
1856
|
continue;
|
|
1344
1857
|
mergedRecord[field] = (0, import_lodash_es.cloneDeep)(incomingRecord[field]);
|
|
1345
1858
|
}
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1859
|
+
for (const field of ORDER_AUTHORITATIVE_COLLECTION_FIELDS) {
|
|
1860
|
+
if (Array.isArray(incomingRecord[field])) {
|
|
1861
|
+
if (field === "payments") {
|
|
1862
|
+
const preservedPending = this.getUnmatchedIdentifiedPendingPayments(
|
|
1863
|
+
existingRecord[field],
|
|
1864
|
+
incomingRecord[field]
|
|
1865
|
+
);
|
|
1866
|
+
if (preservedPending.length > 0) {
|
|
1867
|
+
this.logInfo("mergeOrderRecords-保留本地 pending 支付项", {
|
|
1868
|
+
order_id: existing.order_id ?? incoming.order_id ?? null,
|
|
1869
|
+
external_sale_number: existingRecord.external_sale_number ?? incomingRecord.external_sale_number ?? null,
|
|
1870
|
+
preserved_pending_count: preservedPending.length,
|
|
1871
|
+
preserved_payment_identities: preservedPending.map((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
mergedRecord[field] = this.mergeAuthoritativeOrderCollection(
|
|
1876
|
+
field,
|
|
1877
|
+
existingRecord[field],
|
|
1878
|
+
incomingRecord[field],
|
|
1879
|
+
childUidRemaps,
|
|
1880
|
+
{ preserveIdentifiedPendingPayments: field === "payments" }
|
|
1352
1881
|
);
|
|
1353
|
-
|
|
1354
|
-
|
|
1882
|
+
continue;
|
|
1883
|
+
}
|
|
1884
|
+
if (Object.prototype.hasOwnProperty.call(existingRecord, field)) {
|
|
1885
|
+
mergedRecord[field] = (0, import_lodash_es.cloneDeep)(existingRecord[field]);
|
|
1886
|
+
} else {
|
|
1887
|
+
delete mergedRecord[field];
|
|
1355
1888
|
}
|
|
1356
1889
|
}
|
|
1357
1890
|
if (!this.isPendingSyncOrder(preferred) || !this.isPendingSyncOrder(secondary)) {
|
|
1358
1891
|
merged.need_sync = 0;
|
|
1359
1892
|
}
|
|
1360
|
-
return
|
|
1893
|
+
return this.normalizeOrderCollectionsForIngress(
|
|
1894
|
+
(0, import_orderCollectionIdentity.applyOrderCollectionUidRemaps)(merged, childUidRemaps),
|
|
1895
|
+
"mergeOrderRecords"
|
|
1896
|
+
);
|
|
1361
1897
|
}
|
|
1362
1898
|
summarizeDuplicateOrders(orders) {
|
|
1363
1899
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -1376,7 +1912,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1376
1912
|
external_sale_number: order.external_sale_number ?? null,
|
|
1377
1913
|
shop_order_number: order.shop_order_number ?? null,
|
|
1378
1914
|
shop_full_order_number: order.shop_full_order_number ?? null,
|
|
1379
|
-
need_sync: order.need_sync ?? null
|
|
1915
|
+
need_sync: order.need_sync ?? null,
|
|
1916
|
+
is_draft_order: order.is_draft_order ?? null
|
|
1380
1917
|
}))
|
|
1381
1918
|
}));
|
|
1382
1919
|
}
|
|
@@ -1394,12 +1931,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1394
1931
|
const list = [];
|
|
1395
1932
|
let removedCount = 0;
|
|
1396
1933
|
for (const order of orders) {
|
|
1397
|
-
const
|
|
1934
|
+
const normalizedOrder = this.normalizeOrderCollectionsForIngress(
|
|
1935
|
+
order,
|
|
1936
|
+
`${source}.order`
|
|
1937
|
+
);
|
|
1938
|
+
const matchIndex = this.findOrderIndexByIdentity(list, normalizedOrder);
|
|
1398
1939
|
if (matchIndex < 0) {
|
|
1399
|
-
list.push(
|
|
1940
|
+
list.push(normalizedOrder);
|
|
1400
1941
|
continue;
|
|
1401
1942
|
}
|
|
1402
|
-
list[matchIndex] = this.mergeOrderRecords(list[matchIndex],
|
|
1943
|
+
list[matchIndex] = this.mergeOrderRecords(list[matchIndex], normalizedOrder);
|
|
1403
1944
|
removedCount += 1;
|
|
1404
1945
|
}
|
|
1405
1946
|
if (removedCount > 0) {
|
|
@@ -1479,7 +2020,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1479
2020
|
return [];
|
|
1480
2021
|
try {
|
|
1481
2022
|
const orders = await this.dbManager.getAll(INDEXDB_STORE_NAME);
|
|
1482
|
-
return orders || []
|
|
2023
|
+
return (orders || []).map(
|
|
2024
|
+
(order) => this.normalizeOrderCollectionsForIngress(order, "loadOrdersFromSQLite")
|
|
2025
|
+
);
|
|
1483
2026
|
} catch {
|
|
1484
2027
|
return [];
|
|
1485
2028
|
}
|
|
@@ -1487,22 +2030,67 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1487
2030
|
isPendingSyncOrder(order) {
|
|
1488
2031
|
return Number(order == null ? void 0 : order.need_sync) === 1;
|
|
1489
2032
|
}
|
|
2033
|
+
isDraftOrder(order) {
|
|
2034
|
+
return Number(order == null ? void 0 : order.is_draft_order) === 1;
|
|
2035
|
+
}
|
|
2036
|
+
shouldProtectDraftOrderFromIncoming(source) {
|
|
2037
|
+
return source !== "checkoutSync";
|
|
2038
|
+
}
|
|
1490
2039
|
normalizeRemoteSyncedOrder(order) {
|
|
1491
|
-
|
|
1492
|
-
|
|
2040
|
+
const normalizedOrder = this.normalizeOrderCollectionsForIngress(
|
|
2041
|
+
order,
|
|
2042
|
+
"normalizeRemoteSyncedOrder"
|
|
2043
|
+
);
|
|
2044
|
+
if (this.isPendingSyncOrder(normalizedOrder))
|
|
2045
|
+
return {
|
|
2046
|
+
...normalizedOrder,
|
|
2047
|
+
is_draft_order: 0
|
|
2048
|
+
};
|
|
1493
2049
|
return {
|
|
1494
|
-
...
|
|
1495
|
-
need_sync: 0
|
|
2050
|
+
...normalizedOrder,
|
|
2051
|
+
need_sync: 0,
|
|
2052
|
+
is_draft_order: 0
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
mergeRemoteIdentityIntoDraftOrder(draftOrder, remoteOrder) {
|
|
2056
|
+
const merged = {
|
|
2057
|
+
...this.withoutSyntheticDraftOrderId(draftOrder)
|
|
1496
2058
|
};
|
|
2059
|
+
const remote = remoteOrder;
|
|
2060
|
+
for (const field of [
|
|
2061
|
+
"order_id",
|
|
2062
|
+
"order_number",
|
|
2063
|
+
"shop_order_number",
|
|
2064
|
+
"shop_full_order_number"
|
|
2065
|
+
]) {
|
|
2066
|
+
if (this.isBlankIdentityValue(merged[field]) && !this.isBlankIdentityValue(remote[field])) {
|
|
2067
|
+
merged[field] = remote[field];
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
return this.normalizeOrderCollectionsForIngress(
|
|
2071
|
+
merged,
|
|
2072
|
+
"mergeRemoteIdentityIntoDraftOrder"
|
|
2073
|
+
);
|
|
1497
2074
|
}
|
|
1498
2075
|
mergeRemoteSnapshotWithPendingOrders(remoteOrders, existingOrders) {
|
|
1499
2076
|
const merged = remoteOrders.map((order) => this.normalizeRemoteSyncedOrder(order));
|
|
1500
|
-
for (const
|
|
1501
|
-
|
|
2077
|
+
for (const rawOrder of existingOrders) {
|
|
2078
|
+
const order = this.normalizeOrderCollectionsForIngress(
|
|
2079
|
+
rawOrder,
|
|
2080
|
+
"mergeRemoteSnapshotWithPendingOrders.existingSQLite"
|
|
2081
|
+
);
|
|
2082
|
+
if (!this.shouldProtectLocalOrderFromRemoteSnapshot(order))
|
|
1502
2083
|
continue;
|
|
1503
2084
|
const matchIndex = this.findOrderIndexByIdentity(merged, order);
|
|
1504
2085
|
if (matchIndex >= 0) {
|
|
1505
|
-
|
|
2086
|
+
if (this.isDraftOrder(order)) {
|
|
2087
|
+
merged[matchIndex] = this.mergeRemoteIdentityIntoDraftOrder(
|
|
2088
|
+
order,
|
|
2089
|
+
merged[matchIndex]
|
|
2090
|
+
);
|
|
2091
|
+
} else {
|
|
2092
|
+
merged[matchIndex] = this.mergeOrderRecords(order, merged[matchIndex]);
|
|
2093
|
+
}
|
|
1506
2094
|
continue;
|
|
1507
2095
|
}
|
|
1508
2096
|
if (!this.getOrderStorageKey(order))
|
|
@@ -1530,11 +2118,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1530
2118
|
* @example
|
|
1531
2119
|
* await this.patchOrdersInSQLite(freshOrders)
|
|
1532
2120
|
*/
|
|
1533
|
-
async patchOrdersInSQLite(orders, source, mergeActions = {}) {
|
|
1534
|
-
if (
|
|
2121
|
+
async patchOrdersInSQLite(orders, source, mergeActions = {}, options = {}) {
|
|
2122
|
+
if (orders.length === 0) {
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
if (!this.dbManager) {
|
|
2126
|
+
if (options.throwOnError)
|
|
2127
|
+
throw new Error("订单 SQLite 数据库未初始化");
|
|
1535
2128
|
return;
|
|
1536
2129
|
}
|
|
1537
|
-
const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).filter((order) => this.getOrderStorageKey(order));
|
|
2130
|
+
const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).map((order) => this.normalizeOrderCollectionsForIngress(order, `${source}.sqliteIngress`)).filter((order) => this.getOrderStorageKey(order));
|
|
1538
2131
|
if (ordersSnapshot.length === 0) {
|
|
1539
2132
|
return;
|
|
1540
2133
|
}
|
|
@@ -1569,6 +2162,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1569
2162
|
for (const order of compactedToWrite) {
|
|
1570
2163
|
await this.dbManager.update(INDEXDB_STORE_NAME, order);
|
|
1571
2164
|
}
|
|
2165
|
+
} else if (options.throwOnError) {
|
|
2166
|
+
throw new Error("订单 SQLite 数据库不支持写入");
|
|
1572
2167
|
}
|
|
1573
2168
|
this.recordRecentSqliteWrite(source, compactedToWrite);
|
|
1574
2169
|
this.logInfo("patchOrdersInSQLite-完成", {
|
|
@@ -1583,6 +2178,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1583
2178
|
error: error instanceof Error ? error.message : String(error),
|
|
1584
2179
|
orderCount: ordersSnapshot.length
|
|
1585
2180
|
});
|
|
2181
|
+
if (options.throwOnError)
|
|
2182
|
+
throw error;
|
|
1586
2183
|
}
|
|
1587
2184
|
}
|
|
1588
2185
|
/**
|
|
@@ -1591,11 +2188,21 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1591
2188
|
* @example
|
|
1592
2189
|
* await this.updateOrderInSQLite(freshOrder)
|
|
1593
2190
|
*/
|
|
1594
|
-
async updateOrderInSQLite(order, source) {
|
|
1595
|
-
if (!this.
|
|
2191
|
+
async updateOrderInSQLite(order, source, options = {}) {
|
|
2192
|
+
if (!this.getOrderStorageKey(order)) {
|
|
2193
|
+
if (options.throwOnError)
|
|
2194
|
+
throw new Error("订单缺少可用的 SQLite 存储主键");
|
|
1596
2195
|
return;
|
|
1597
2196
|
}
|
|
1598
|
-
|
|
2197
|
+
if (!this.dbManager) {
|
|
2198
|
+
if (options.throwOnError)
|
|
2199
|
+
throw new Error("订单 SQLite 数据库未初始化");
|
|
2200
|
+
return;
|
|
2201
|
+
}
|
|
2202
|
+
const orderSnapshot = this.normalizeOrderCollectionsForIngress(
|
|
2203
|
+
(0, import_lodash_es.cloneDeep)(order),
|
|
2204
|
+
`${source}.sqliteIngress`
|
|
2205
|
+
);
|
|
1599
2206
|
try {
|
|
1600
2207
|
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
1601
2208
|
let writeMethod = "none";
|
|
@@ -1613,6 +2220,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1613
2220
|
} else if (typeof this.dbManager.bulkAdd === "function") {
|
|
1614
2221
|
writeMethod = "bulkAdd";
|
|
1615
2222
|
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, [orderSnapshot]);
|
|
2223
|
+
} else if (options.throwOnError) {
|
|
2224
|
+
throw new Error("订单 SQLite 数据库不支持写入");
|
|
1616
2225
|
}
|
|
1617
2226
|
this.recordRecentSqliteWrite(source, [orderSnapshot]);
|
|
1618
2227
|
this.logInfo("updateOrderInSQLite-完成", {
|
|
@@ -1626,22 +2235,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1626
2235
|
error: error instanceof Error ? error.message : String(error),
|
|
1627
2236
|
orderId: orderSnapshot.order_id ?? null
|
|
1628
2237
|
});
|
|
2238
|
+
if (options.throwOnError)
|
|
2239
|
+
throw error;
|
|
1629
2240
|
}
|
|
1630
2241
|
}
|
|
1631
2242
|
/**
|
|
1632
|
-
* 全量快照替换 orders 表(clear + bulkAdd
|
|
2243
|
+
* 全量快照替换 orders 表(clear + bulkAdd),并保留本地 draft / need_sync / pending 支付订单。
|
|
2244
|
+
* 用于 SSE 全量拉取与营业日窗口裁剪。
|
|
1633
2245
|
*
|
|
1634
2246
|
* @example
|
|
1635
2247
|
* await this.replaceOrdersSnapshotInSQLite(orderList)
|
|
1636
2248
|
*/
|
|
1637
|
-
async replaceOrdersSnapshotInSQLite(orderList, source) {
|
|
2249
|
+
async replaceOrdersSnapshotInSQLite(orderList, source, protectedOrdersBeforeRemoteFetch = []) {
|
|
1638
2250
|
if (!this.dbManager) {
|
|
1639
2251
|
return this.compactOrderListByIdentity(
|
|
1640
2252
|
orderList.map((order) => this.normalizeRemoteSyncedOrder(order)),
|
|
1641
2253
|
`${source}.snapshotNoDb`
|
|
1642
2254
|
).list;
|
|
1643
2255
|
}
|
|
1644
|
-
const remoteSnapshot = (0, import_lodash_es.cloneDeep)(orderList)
|
|
2256
|
+
const remoteSnapshot = (0, import_lodash_es.cloneDeep)(orderList).map(
|
|
2257
|
+
(order) => this.normalizeOrderCollectionsForIngress(order, `${source}.remoteIngress`)
|
|
2258
|
+
);
|
|
1645
2259
|
let mergedSnapshot = this.compactOrderListByIdentity(
|
|
1646
2260
|
remoteSnapshot.map((order) => this.normalizeRemoteSyncedOrder(order)),
|
|
1647
2261
|
`${source}.remoteSnapshot`
|
|
@@ -1649,16 +2263,52 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1649
2263
|
try {
|
|
1650
2264
|
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
1651
2265
|
const existingOrders = typeof this.dbManager.getAll === "function" ? await this.dbManager.getAll(INDEXDB_STORE_NAME) : [];
|
|
2266
|
+
const protectedLocalOrders = protectedOrdersBeforeRemoteFetch.map((order) => this.normalizeOrderCollectionsForIngress(
|
|
2267
|
+
order,
|
|
2268
|
+
`${source}.protectedBeforeRemoteFetch`
|
|
2269
|
+
)).filter((order) => this.shouldProtectLocalOrderFromRemoteSnapshot(order));
|
|
2270
|
+
for (const rawCurrentOrder of existingOrders || []) {
|
|
2271
|
+
const currentOrder = this.normalizeOrderCollectionsForIngress(
|
|
2272
|
+
rawCurrentOrder,
|
|
2273
|
+
`${source}.currentSQLite`
|
|
2274
|
+
);
|
|
2275
|
+
const protectedIndex = this.findOrderIndexByIdentity(
|
|
2276
|
+
protectedLocalOrders,
|
|
2277
|
+
currentOrder
|
|
2278
|
+
);
|
|
2279
|
+
const currentNeedsProtection = this.shouldProtectLocalOrderFromRemoteSnapshot(currentOrder);
|
|
2280
|
+
if (protectedIndex >= 0) {
|
|
2281
|
+
if (currentNeedsProtection) {
|
|
2282
|
+
protectedLocalOrders[protectedIndex] = currentOrder;
|
|
2283
|
+
} else {
|
|
2284
|
+
protectedLocalOrders.splice(protectedIndex, 1);
|
|
2285
|
+
}
|
|
2286
|
+
continue;
|
|
2287
|
+
}
|
|
2288
|
+
if (currentNeedsProtection)
|
|
2289
|
+
protectedLocalOrders.push(currentOrder);
|
|
2290
|
+
}
|
|
1652
2291
|
const orderListSnapshot = this.mergeRemoteSnapshotWithPendingOrders(
|
|
1653
2292
|
remoteSnapshot,
|
|
1654
|
-
|
|
2293
|
+
protectedLocalOrders
|
|
1655
2294
|
);
|
|
1656
2295
|
mergedSnapshot = this.compactOrderListByIdentity(orderListSnapshot, `${source}.sqliteSnapshot`).list;
|
|
1657
2296
|
this.logInfo("replaceOrdersSnapshotInSQLite-开始", {
|
|
1658
2297
|
source,
|
|
1659
2298
|
count: mergedSnapshot.length,
|
|
1660
2299
|
remoteCount: remoteSnapshot.length,
|
|
1661
|
-
|
|
2300
|
+
protectedBeforeRemoteFetchCount: protectedOrdersBeforeRemoteFetch.length,
|
|
2301
|
+
protectedLocalOrderCount: protectedLocalOrders.length,
|
|
2302
|
+
preservedLocalUnsyncedCount: mergedSnapshot.length - remoteSnapshot.length,
|
|
2303
|
+
protectedPendingPaymentCount: protectedLocalOrders.reduce(
|
|
2304
|
+
(count, order) => count + this.getIdentifiedPendingPayments(order).length,
|
|
2305
|
+
0
|
|
2306
|
+
),
|
|
2307
|
+
protectedPendingPaymentIdentities: protectedLocalOrders.flatMap((order) => this.getIdentifiedPendingPayments(order).map((payment) => ({
|
|
2308
|
+
order_id: order.order_id ?? null,
|
|
2309
|
+
external_sale_number: order.external_sale_number ?? null,
|
|
2310
|
+
payment_identities: (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment)
|
|
2311
|
+
})))
|
|
1662
2312
|
});
|
|
1663
2313
|
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
1664
2314
|
this.logInfo("replaceOrdersSnapshotInSQLite-clear完成", {
|