@pisell/pisellos 2.2.244 → 2.2.246
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/promotion/evaluator.js +3 -2
- package/dist/model/strategy/adapter/walletPass/utils.js +7 -4
- package/dist/modules/BookingContext/index.d.ts +48 -0
- package/dist/modules/BookingContext/index.js +566 -0
- package/dist/modules/BookingContext/types.d.ts +102 -0
- package/dist/modules/BookingContext/types.js +51 -0
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +284 -0
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +148 -0
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +218 -0
- package/dist/modules/BookingContext/utils/flexible.d.ts +28 -0
- package/dist/modules/BookingContext/utils/flexible.js +56 -0
- package/dist/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
- package/dist/modules/BookingContext/utils/formatResourceList.js +38 -0
- package/dist/modules/BookingContext/utils/index.d.ts +11 -0
- package/dist/modules/BookingContext/utils/index.js +11 -0
- package/dist/modules/BookingContext/utils/noResource.d.ts +13 -0
- package/dist/modules/BookingContext/utils/noResource.js +77 -0
- package/dist/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
- package/dist/modules/BookingContext/utils/orderLineDisplay.js +36 -0
- package/dist/modules/BookingContext/utils/productExtend.d.ts +72 -0
- package/dist/modules/BookingContext/utils/productExtend.js +339 -0
- package/dist/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
- package/dist/modules/BookingContext/utils/resourceErrors.js +74 -0
- package/dist/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
- package/dist/modules/BookingContext/utils/resourceSelection.js +24 -0
- package/dist/modules/BookingContext/utils/resources.d.ts +80 -0
- package/dist/modules/BookingContext/utils/resources.js +486 -0
- package/dist/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
- package/dist/modules/BookingContext/utils/serviceTimes.js +151 -0
- package/dist/modules/BookingContext/utils/timeSlices.d.ts +42 -0
- package/dist/modules/BookingContext/utils/timeSlices.js +100 -0
- package/dist/modules/Cart/utils/cartProduct.js +24 -3
- package/dist/modules/Cart/utils/changePrice.js +11 -11
- package/dist/modules/Customer/index.d.ts +20 -0
- package/dist/modules/Customer/index.js +172 -83
- package/dist/modules/Customer/types.d.ts +2 -0
- package/dist/modules/Discount/index.d.ts +1 -1
- package/dist/modules/Discount/index.js +13 -6
- package/dist/modules/Discount/types.d.ts +1 -0
- package/dist/modules/OpenData/index.d.ts +8 -0
- package/dist/modules/OpenData/index.js +37 -17
- package/dist/modules/Order/index.d.ts +277 -18
- package/dist/modules/Order/index.js +3581 -779
- package/dist/modules/Order/types.d.ts +286 -31
- package/dist/modules/Order/types.js +38 -0
- package/dist/modules/Order/utils/manualProductDiscount.d.ts +106 -0
- package/dist/modules/Order/utils/manualProductDiscount.js +210 -0
- package/dist/modules/Order/utils.d.ts +147 -5
- package/dist/modules/Order/utils.js +750 -104
- package/dist/modules/Payment/index.d.ts +10 -13
- package/dist/modules/Payment/index.js +467 -837
- package/dist/modules/Payment/types.d.ts +2 -0
- package/dist/modules/Payment/utils.js +2 -1
- package/dist/modules/Payment/walletpass.js +41 -25
- package/dist/modules/ProductList/index.d.ts +16 -12
- package/dist/modules/ProductList/index.js +133 -59
- package/dist/modules/ProductList/types.d.ts +14 -0
- package/dist/modules/Quotation/index.d.ts +0 -1
- package/dist/modules/Quotation/index.js +25 -22
- package/dist/modules/Rules/index.d.ts +4 -0
- package/dist/modules/Rules/index.js +97 -70
- package/dist/modules/Rules/types.d.ts +1 -0
- package/dist/modules/SalesSummary/index.d.ts +8 -25
- package/dist/modules/SalesSummary/index.js +86 -35
- package/dist/modules/SalesSummary/types.d.ts +4 -1
- package/dist/modules/SalesSummary/utils.d.ts +2 -25
- package/dist/modules/SalesSummary/utils.js +794 -162
- package/dist/modules/Schedule/index.d.ts +7 -0
- package/dist/modules/Schedule/index.js +24 -2
- package/dist/modules/Summary/index.js +4 -3
- package/dist/modules/SurchargeList/index.d.ts +16 -0
- package/dist/modules/SurchargeList/index.js +162 -0
- package/dist/modules/SurchargeList/types.d.ts +11 -0
- package/dist/modules/SurchargeList/types.js +1 -0
- package/dist/modules/index.d.ts +2 -0
- package/dist/modules/index.js +3 -1
- package/dist/plugins/request.d.ts +1 -0
- package/dist/server/index.d.ts +204 -1
- package/dist/server/index.js +3654 -922
- package/dist/server/modules/index.d.ts +2 -0
- package/dist/server/modules/index.js +2 -0
- package/dist/server/modules/order/index.d.ts +120 -3
- package/dist/server/modules/order/index.js +1762 -448
- package/dist/server/modules/order/types.d.ts +32 -3
- package/dist/server/modules/order/types.js +8 -0
- package/dist/server/modules/order/utils/filterBookings.js +26 -3
- package/dist/server/modules/order/utils/filterOrders.js +23 -8
- package/dist/server/modules/payment/index.d.ts +28 -0
- package/dist/server/modules/payment/index.js +305 -0
- package/dist/server/modules/payment/types.d.ts +9 -0
- package/dist/server/modules/payment/types.js +1 -0
- package/dist/server/modules/products/index.d.ts +34 -7
- package/dist/server/modules/products/index.js +631 -317
- package/dist/server/modules/resource/index.d.ts +2 -0
- package/dist/server/modules/resource/index.js +29 -3
- package/dist/server/modules/schedule/index.d.ts +4 -4
- package/dist/server/modules/schedule/index.js +111 -88
- package/dist/server/test.json +713 -0
- package/dist/server/utils/small-ticket.d.ts +71 -0
- package/dist/server/utils/small-ticket.js +840 -0
- package/dist/solution/BaseSales/index.d.ts +133 -10
- package/dist/solution/BaseSales/index.js +1950 -447
- package/dist/solution/BaseSales/types.d.ts +82 -6
- package/dist/solution/BaseSales/types.js +5 -4
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
- package/dist/solution/BaseSales/utils/cartPromotion.js +1438 -0
- package/dist/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
- package/dist/solution/BaseSales/utils/quotationPrice.js +237 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +105 -24
- package/dist/solution/BaseSales/utils.d.ts +1 -1
- package/dist/solution/BaseSales/utils.js +62 -21
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +271 -11
- package/dist/solution/BookingTicket/index.js +1777 -242
- package/dist/solution/BookingTicket/types.d.ts +118 -1
- package/dist/solution/BookingTicket/types.js +41 -2
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
- package/dist/solution/BookingTicket/utils/addProductDecision.js +346 -0
- package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
- package/dist/solution/BookingTicket/utils/addTimeAvailability.js +95 -0
- package/dist/solution/BookingTicket/utils/bookingStatus.d.ts +40 -0
- package/dist/solution/BookingTicket/utils/bookingStatus.js +70 -0
- package/dist/solution/BookingTicket/utils/cartView.d.ts +9 -1
- package/dist/solution/BookingTicket/utils/cartView.js +94 -7
- package/dist/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/dist/solution/BookingTicket/utils/exampleData.js +183 -0
- package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
- package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.js +438 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +400 -0
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +56 -0
- package/dist/solution/BookingTicket/utils/scan/index.d.ts +5 -0
- package/dist/solution/BookingTicket/utils/scan/index.js +20 -8
- package/dist/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
- package/dist/solution/BookingTicket/utils/scan/scanProductValues.js +150 -0
- package/dist/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
- package/dist/solution/BookingTicket/utils/sessionCatalogStale.js +78 -0
- package/dist/solution/Checkout/index.d.ts +1 -0
- package/dist/solution/Checkout/index.js +10 -9
- package/dist/solution/RegisterAndLogin/config.js +2 -10
- package/dist/solution/ScanOrder/index.d.ts +9 -3
- package/dist/solution/ScanOrder/index.js +241 -134
- package/dist/solution/ScanOrder/types.d.ts +9 -5
- package/dist/solution/ScanOrder/types.js +2 -3
- package/dist/solution/ScanOrder/utils.d.ts +1 -1
- package/dist/solution/ScanOrder/utils.js +84 -22
- package/dist/solution/VenueBooking/index.d.ts +5 -2
- package/dist/solution/VenueBooking/index.js +110 -59
- package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
- package/dist/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
- package/dist/solution/VenueBooking/utils/slotMerge.js +10 -0
- package/dist/types/index.d.ts +10 -0
- package/lib/model/strategy/adapter/promotion/evaluator.js +2 -1
- package/lib/model/strategy/adapter/promotion/index.js +49 -0
- package/lib/model/strategy/adapter/walletPass/utils.js +3 -2
- package/lib/modules/BookingContext/index.d.ts +48 -0
- package/lib/modules/BookingContext/index.js +368 -0
- package/lib/modules/BookingContext/types.d.ts +102 -0
- package/lib/modules/BookingContext/types.js +34 -0
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +276 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +154 -0
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +201 -0
- package/lib/modules/BookingContext/utils/flexible.d.ts +28 -0
- package/lib/modules/BookingContext/utils/flexible.js +80 -0
- package/lib/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
- package/lib/modules/BookingContext/utils/formatResourceList.js +50 -0
- package/lib/modules/BookingContext/utils/index.d.ts +11 -0
- package/lib/modules/BookingContext/utils/index.js +43 -0
- package/lib/modules/BookingContext/utils/noResource.d.ts +13 -0
- package/lib/modules/BookingContext/utils/noResource.js +90 -0
- package/lib/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +56 -0
- package/lib/modules/BookingContext/utils/productExtend.d.ts +72 -0
- package/lib/modules/BookingContext/utils/productExtend.js +283 -0
- package/lib/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
- package/lib/modules/BookingContext/utils/resourceErrors.js +80 -0
- package/lib/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
- package/lib/modules/BookingContext/utils/resourceSelection.js +46 -0
- package/lib/modules/BookingContext/utils/resources.d.ts +80 -0
- package/lib/modules/BookingContext/utils/resources.js +377 -0
- package/lib/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
- package/lib/modules/BookingContext/utils/serviceTimes.js +162 -0
- package/lib/modules/BookingContext/utils/timeSlices.d.ts +42 -0
- package/lib/modules/BookingContext/utils/timeSlices.js +124 -0
- package/lib/modules/Cart/utils/cartProduct.js +20 -3
- package/lib/modules/Cart/utils/changePrice.js +12 -20
- package/lib/modules/Customer/index.d.ts +20 -0
- package/lib/modules/Customer/index.js +64 -11
- package/lib/modules/Customer/types.d.ts +2 -0
- package/lib/modules/Discount/index.d.ts +1 -1
- package/lib/modules/Discount/index.js +9 -1
- package/lib/modules/Discount/types.d.ts +1 -0
- package/lib/modules/OpenData/index.d.ts +8 -0
- package/lib/modules/OpenData/index.js +19 -5
- package/lib/modules/Order/index.d.ts +277 -18
- package/lib/modules/Order/index.js +2317 -337
- package/lib/modules/Order/types.d.ts +286 -31
- package/lib/modules/Order/types.js +1 -0
- package/lib/modules/Order/utils/manualProductDiscount.d.ts +106 -0
- package/lib/modules/Order/utils/manualProductDiscount.js +206 -0
- package/lib/modules/Order/utils.d.ts +147 -5
- package/lib/modules/Order/utils.js +615 -46
- package/lib/modules/Payment/index.d.ts +10 -13
- package/lib/modules/Payment/index.js +18 -150
- package/lib/modules/Payment/types.d.ts +2 -0
- package/lib/modules/Payment/utils.js +2 -1
- package/lib/modules/Payment/walletpass.js +16 -3
- package/lib/modules/ProductList/index.d.ts +16 -12
- package/lib/modules/ProductList/index.js +41 -4
- package/lib/modules/ProductList/types.d.ts +14 -0
- package/lib/modules/Quotation/index.d.ts +0 -1
- package/lib/modules/Quotation/index.js +19 -16
- package/lib/modules/Rules/index.d.ts +4 -0
- package/lib/modules/Rules/index.js +137 -120
- package/lib/modules/Rules/types.d.ts +1 -0
- package/lib/modules/SalesSummary/index.d.ts +8 -25
- package/lib/modules/SalesSummary/index.js +30 -4
- package/lib/modules/SalesSummary/types.d.ts +4 -1
- package/lib/modules/SalesSummary/utils.d.ts +2 -25
- package/lib/modules/SalesSummary/utils.js +645 -91
- package/lib/modules/Schedule/index.d.ts +7 -0
- package/lib/modules/Schedule/index.js +17 -1
- package/lib/modules/Summary/index.js +5 -4
- package/lib/modules/SurchargeList/index.d.ts +16 -0
- package/lib/modules/SurchargeList/index.js +89 -0
- package/lib/modules/SurchargeList/types.d.ts +11 -0
- package/lib/modules/SurchargeList/types.js +17 -0
- package/lib/modules/index.d.ts +2 -0
- package/lib/modules/index.js +5 -1
- package/lib/plugins/request.d.ts +1 -0
- package/lib/server/index.d.ts +204 -1
- package/lib/server/index.js +1891 -59
- package/lib/server/modules/index.d.ts +2 -0
- package/lib/server/modules/index.js +3 -0
- package/lib/server/modules/order/index.d.ts +120 -3
- package/lib/server/modules/order/index.js +887 -94
- package/lib/server/modules/order/types.d.ts +32 -3
- package/lib/server/modules/order/utils/filterBookings.js +24 -5
- package/lib/server/modules/order/utils/filterOrders.js +15 -6
- package/lib/server/modules/payment/index.d.ts +28 -0
- package/lib/server/modules/payment/index.js +192 -0
- package/lib/server/modules/payment/types.d.ts +9 -0
- package/lib/server/modules/payment/types.js +17 -0
- package/lib/server/modules/products/index.d.ts +34 -7
- package/lib/server/modules/products/index.js +189 -54
- package/lib/server/modules/resource/index.d.ts +2 -0
- package/lib/server/modules/resource/index.js +27 -3
- package/lib/server/modules/schedule/index.d.ts +4 -4
- package/lib/server/modules/schedule/index.js +47 -40
- package/lib/server/test.json +713 -0
- package/lib/server/utils/small-ticket.d.ts +71 -0
- package/lib/server/utils/small-ticket.js +800 -0
- package/lib/solution/BaseSales/index.d.ts +133 -10
- package/lib/solution/BaseSales/index.js +1111 -63
- package/lib/solution/BaseSales/types.d.ts +82 -6
- package/lib/solution/BaseSales/types.js +3 -1
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
- package/lib/solution/BaseSales/utils/cartPromotion.js +992 -0
- package/lib/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
- package/lib/solution/BaseSales/utils/quotationPrice.js +277 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +106 -18
- package/lib/solution/BaseSales/utils.d.ts +1 -1
- package/lib/solution/BaseSales/utils.js +54 -10
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +271 -11
- package/lib/solution/BookingTicket/index.js +922 -29
- package/lib/solution/BookingTicket/types.d.ts +118 -1
- package/lib/solution/BookingTicket/types.js +11 -0
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
- package/lib/solution/BookingTicket/utils/addProductDecision.js +318 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +125 -0
- package/lib/solution/BookingTicket/utils/bookingStatus.d.ts +40 -0
- package/lib/solution/BookingTicket/utils/bookingStatus.js +44 -2
- package/lib/solution/BookingTicket/utils/cartView.d.ts +9 -1
- package/lib/solution/BookingTicket/utils/cartView.js +61 -6
- package/lib/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/lib/solution/BookingTicket/utils/exampleData.js +0 -0
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +254 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +169 -0
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +51 -0
- package/lib/solution/BookingTicket/utils/scan/index.d.ts +5 -0
- package/lib/solution/BookingTicket/utils/scan/index.js +17 -3
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +127 -0
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +85 -0
- package/lib/solution/Checkout/index.d.ts +1 -0
- package/lib/solution/Checkout/index.js +1 -2
- package/lib/solution/RegisterAndLogin/config.js +2 -10
- package/lib/solution/ScanOrder/index.d.ts +9 -3
- package/lib/solution/ScanOrder/index.js +153 -70
- package/lib/solution/ScanOrder/types.d.ts +9 -5
- package/lib/solution/ScanOrder/utils.d.ts +1 -1
- package/lib/solution/ScanOrder/utils.js +83 -17
- package/lib/solution/VenueBooking/index.d.ts +5 -2
- package/lib/solution/VenueBooking/index.js +54 -17
- package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
- package/lib/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
- package/lib/solution/VenueBooking/utils/slotMerge.js +10 -0
- package/lib/types/index.d.ts +10 -0
- package/package.json +1 -1
- package/dist/solution/Checkout/appointmentDemo.json +0 -1
- package/lib/solution/Checkout/appointmentDemo.json +0 -1
|
@@ -40,6 +40,14 @@ var INDEXDB_STORE_NAME = "orders";
|
|
|
40
40
|
var ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = "server_order_last_full_fetch_at";
|
|
41
41
|
var ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = "order_sync_throttle_ms";
|
|
42
42
|
var DEFAULT_ORDER_SYNC_THROTTLE_MS = 2e3;
|
|
43
|
+
var ORDER_SQLITE_DEDUPE_MS = 15e3;
|
|
44
|
+
var ORDER_SILENT_REFRESH_MIN_INTERVAL_MS = 3e4;
|
|
45
|
+
var ORDER_BUSINESS_WRITE_SOURCES = /* @__PURE__ */ new Set([
|
|
46
|
+
"upsertOrdersFromRemote",
|
|
47
|
+
"upsertPendingSyncOrders",
|
|
48
|
+
"overwriteExistingOrder",
|
|
49
|
+
"markOrderSyncedByExternalSaleNumber"
|
|
50
|
+
]);
|
|
43
51
|
var OrderModule = class extends import_BaseModule.BaseModule {
|
|
44
52
|
constructor(name, version) {
|
|
45
53
|
super(name, version);
|
|
@@ -50,6 +58,26 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
50
58
|
this.isIdlePhase = true;
|
|
51
59
|
// Map<resource_id, OrderId[]> 资源到订单的倒排索引
|
|
52
60
|
this.resourceIdIndex = /* @__PURE__ */ new Map();
|
|
61
|
+
this.orderSQLiteSaveQueue = Promise.resolve();
|
|
62
|
+
/** 按 storageKey 记录最近一次 SQLite 写入来源与时间,用于去重 */
|
|
63
|
+
this.recentSqliteWriteByStorageKey = /* @__PURE__ */ new Map();
|
|
64
|
+
/** 最近一次 SSE 全量拉取完成时间 */
|
|
65
|
+
this.lastServerFullFetchAtMs = 0;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 广播订单变更事件,兼容全量列表订阅并额外携带本次变更订单。
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* await this.emitOrdersChanged([freshOrder], 'pubsub.bodyUpsert')
|
|
72
|
+
*/
|
|
73
|
+
async emitOrdersChanged(changedOrders = [], source) {
|
|
74
|
+
console.log("触发emitOrdersChanged");
|
|
75
|
+
const payload = {
|
|
76
|
+
list: this.store.list,
|
|
77
|
+
changedOrders: changedOrders.map((order) => this.normalizeOrderForMemoryList(order)),
|
|
78
|
+
source
|
|
79
|
+
};
|
|
80
|
+
await this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, payload);
|
|
53
81
|
}
|
|
54
82
|
async initialize(core, options) {
|
|
55
83
|
var _a;
|
|
@@ -66,9 +94,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
66
94
|
this.updateCreateStore();
|
|
67
95
|
}
|
|
68
96
|
if (Array.isArray((_a = options == null ? void 0 : options.initialState) == null ? void 0 : _a.list)) {
|
|
69
|
-
this.store.list = options.initialState.list;
|
|
97
|
+
this.store.list = options.initialState.list.map((order) => this.normalizeOrderForMemoryList(order));
|
|
70
98
|
this.syncOrdersMap();
|
|
71
|
-
this.
|
|
99
|
+
this.emitOrdersChanged([], "initialState");
|
|
72
100
|
} else {
|
|
73
101
|
this.store.list = [];
|
|
74
102
|
this.store.map = /* @__PURE__ */ new Map();
|
|
@@ -115,6 +143,171 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
115
143
|
} catch {
|
|
116
144
|
}
|
|
117
145
|
}
|
|
146
|
+
logWarning(title, metadata) {
|
|
147
|
+
try {
|
|
148
|
+
if (this.logger) {
|
|
149
|
+
this.logger.addLog({
|
|
150
|
+
type: "warning",
|
|
151
|
+
title: `[OrderServerModule] ${title}`,
|
|
152
|
+
metadata: metadata || {}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 记录订单最近一次 SQLite 写入,供 pubsub 回声去重使用。
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* this.recordRecentSqliteWrite('upsertOrdersFromRemote', orders)
|
|
163
|
+
*/
|
|
164
|
+
recordRecentSqliteWrite(source, orders) {
|
|
165
|
+
const now = Date.now();
|
|
166
|
+
for (const order of orders) {
|
|
167
|
+
const storageKey = this.getOrderStorageKey(order);
|
|
168
|
+
if (!storageKey)
|
|
169
|
+
continue;
|
|
170
|
+
this.recentSqliteWriteByStorageKey.set(storageKey, { source, ts: now });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* 过滤 pubsub 触发的冗余 SQLite patch(业务 API 刚写入过的 update 回声)。
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* const { toWrite, skipped } = this.filterRedundantPatchOrders('pubsub.bodyUpsert', orders, mergeActions)
|
|
178
|
+
*/
|
|
179
|
+
filterRedundantPatchOrders(source, orders, mergeActions) {
|
|
180
|
+
const eligibleSkipSources = /* @__PURE__ */ new Set(["pubsub.bodyUpsert", "pubsub.httpRefresh"]);
|
|
181
|
+
if (!eligibleSkipSources.has(source)) {
|
|
182
|
+
return { toWrite: orders, skipped: [] };
|
|
183
|
+
}
|
|
184
|
+
const now = Date.now();
|
|
185
|
+
const toWrite = [];
|
|
186
|
+
const skipped = [];
|
|
187
|
+
for (const order of orders) {
|
|
188
|
+
const storageKey = this.getOrderStorageKey(order);
|
|
189
|
+
if (!storageKey) {
|
|
190
|
+
toWrite.push(order);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const orderKey = order.order_id !== void 0 && order.order_id !== null ? this.getIdKey(order.order_id) : "";
|
|
194
|
+
const mergeAction = orderKey ? mergeActions[orderKey] : void 0;
|
|
195
|
+
if (mergeAction === "insert") {
|
|
196
|
+
toWrite.push(order);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
const recent = this.recentSqliteWriteByStorageKey.get(storageKey);
|
|
200
|
+
if (recent && ORDER_BUSINESS_WRITE_SOURCES.has(recent.source) && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
|
|
201
|
+
skipped.push({
|
|
202
|
+
orderId: order.order_id ?? null,
|
|
203
|
+
storageKey,
|
|
204
|
+
reason: "skip_pubsub_echo_after_business_write",
|
|
205
|
+
lastSource: recent.source,
|
|
206
|
+
elapsedMs: now - recent.ts
|
|
207
|
+
});
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
toWrite.push(order);
|
|
211
|
+
}
|
|
212
|
+
return { toWrite, skipped };
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* 过滤 pubsub HTTP 增量拉取 ids:本地刚由业务 API 写入的单可跳过 HTTP。
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* const ids = this.filterRedundantHttpRefreshIds([99331, 99332])
|
|
219
|
+
*/
|
|
220
|
+
filterRedundantHttpRefreshIds(ids) {
|
|
221
|
+
const now = Date.now();
|
|
222
|
+
const toFetch = [];
|
|
223
|
+
const skipped = [];
|
|
224
|
+
for (const id of ids) {
|
|
225
|
+
const existing = this.getOrderByOrderId(id);
|
|
226
|
+
if (!existing) {
|
|
227
|
+
toFetch.push(id);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const storageKey = this.getOrderStorageKey(existing);
|
|
231
|
+
const recent = storageKey ? this.recentSqliteWriteByStorageKey.get(storageKey) : void 0;
|
|
232
|
+
if (recent && recent.source === "upsertOrdersFromRemote" && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
|
|
233
|
+
skipped.push({
|
|
234
|
+
orderId: id,
|
|
235
|
+
lastSource: recent.source,
|
|
236
|
+
elapsedMs: now - recent.ts
|
|
237
|
+
});
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
toFetch.push(id);
|
|
241
|
+
}
|
|
242
|
+
return { toFetch, skipped };
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* 解析 pubsub 消息会走哪条同步分支,便于对照为何触发 HTTP 重拉或 body 直写。
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* this.resolveSyncMessageRoute(msg)
|
|
249
|
+
* // => { route: 'httpRefresh.batchIds', ... }
|
|
250
|
+
*/
|
|
251
|
+
resolveSyncMessageRoute(msg) {
|
|
252
|
+
var _a;
|
|
253
|
+
const hasBatchIds = Array.isArray(msg.ids) && msg.ids.length > 0;
|
|
254
|
+
const singleIdRaw = msg.id ?? msg.order_id;
|
|
255
|
+
const hasSingleId = !hasBatchIds && singleIdRaw !== void 0 && singleIdRaw !== null;
|
|
256
|
+
const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
|
|
257
|
+
if (hasBatchIds) {
|
|
258
|
+
return {
|
|
259
|
+
route: "httpRefresh.batchIds",
|
|
260
|
+
hasBatchIds: true,
|
|
261
|
+
hasSingleId: false,
|
|
262
|
+
hasNormalizedBody: !!normalizedBody,
|
|
263
|
+
singleId: null,
|
|
264
|
+
batchIds: msg.ids || [],
|
|
265
|
+
bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (hasSingleId && normalizedBody) {
|
|
269
|
+
return {
|
|
270
|
+
route: "bodyUpsert",
|
|
271
|
+
hasBatchIds: false,
|
|
272
|
+
hasSingleId: true,
|
|
273
|
+
hasNormalizedBody: true,
|
|
274
|
+
singleId: singleIdRaw,
|
|
275
|
+
batchIds: [],
|
|
276
|
+
bodyOrderId: normalizedBody.order_id ?? null
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
if (hasSingleId) {
|
|
280
|
+
return {
|
|
281
|
+
route: "httpRefresh.singleId",
|
|
282
|
+
hasBatchIds: false,
|
|
283
|
+
hasSingleId: true,
|
|
284
|
+
hasNormalizedBody: !!normalizedBody,
|
|
285
|
+
singleId: singleIdRaw,
|
|
286
|
+
batchIds: [],
|
|
287
|
+
bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
if ((_a = msg.relation_order_ids) == null ? void 0 : _a.length) {
|
|
291
|
+
return {
|
|
292
|
+
route: "httpRefresh.relationIds",
|
|
293
|
+
hasBatchIds: false,
|
|
294
|
+
hasSingleId: false,
|
|
295
|
+
hasNormalizedBody: !!normalizedBody,
|
|
296
|
+
singleId: null,
|
|
297
|
+
batchIds: msg.relation_order_ids,
|
|
298
|
+
bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
route: "noop",
|
|
303
|
+
hasBatchIds: false,
|
|
304
|
+
hasSingleId: false,
|
|
305
|
+
hasNormalizedBody: !!normalizedBody,
|
|
306
|
+
singleId: null,
|
|
307
|
+
batchIds: [],
|
|
308
|
+
bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
|
|
309
|
+
};
|
|
310
|
+
}
|
|
118
311
|
updateCreateStore() {
|
|
119
312
|
var _a;
|
|
120
313
|
const appPlugin = this.core.getPlugin("app");
|
|
@@ -174,11 +367,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
174
367
|
async preload() {
|
|
175
368
|
const getData = async () => {
|
|
176
369
|
const orders = await this.loadOrdersByServer();
|
|
177
|
-
if (orders.length === 0)
|
|
370
|
+
if (orders.length === 0) {
|
|
178
371
|
return;
|
|
372
|
+
}
|
|
179
373
|
this.store.list = (0, import_lodash_es.cloneDeep)(orders);
|
|
180
374
|
this.syncOrdersMap();
|
|
181
|
-
this.
|
|
375
|
+
this.emitOrdersChanged([], "preload");
|
|
182
376
|
this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
183
377
|
};
|
|
184
378
|
getData();
|
|
@@ -189,30 +383,33 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
189
383
|
getOrderById(id) {
|
|
190
384
|
return this.store.map.get(this.getIdKey(id));
|
|
191
385
|
}
|
|
192
|
-
/** 按 order_id
|
|
386
|
+
/** 按 order_id 查询内存订单。 */
|
|
193
387
|
getOrderByOrderId(orderId) {
|
|
194
388
|
return this.store.map.get(this.getIdKey(orderId));
|
|
195
389
|
}
|
|
196
|
-
|
|
197
|
-
const key = this.getIdKey(
|
|
198
|
-
const
|
|
390
|
+
getLocalOrderFromMemoryByLookup(lookup) {
|
|
391
|
+
const key = this.getIdKey(lookup);
|
|
392
|
+
const memoryOrderById = this.store.map.get(key);
|
|
393
|
+
if (memoryOrderById)
|
|
394
|
+
return memoryOrderById;
|
|
395
|
+
const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
|
|
396
|
+
return memoryOrder || null;
|
|
397
|
+
}
|
|
398
|
+
async getLocalOrderByLookup(lookup) {
|
|
399
|
+
const key = this.getIdKey(lookup);
|
|
400
|
+
const memoryOrderById = this.store.map.get(key);
|
|
401
|
+
if (memoryOrderById)
|
|
402
|
+
return memoryOrderById;
|
|
403
|
+
const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
|
|
199
404
|
if (memoryOrder)
|
|
200
405
|
return memoryOrder;
|
|
201
406
|
const orders = await this.loadOrdersFromSQLite();
|
|
202
|
-
const localOrder = orders.find((order) =>
|
|
203
|
-
const shopOrderNumber = order == null ? void 0 : order.shop_order_number;
|
|
204
|
-
if (shopOrderNumber && this.getIdKey(shopOrderNumber) === key)
|
|
205
|
-
return true;
|
|
206
|
-
const id = order == null ? void 0 : order.order_id;
|
|
207
|
-
if (id === void 0 || id === null)
|
|
208
|
-
return false;
|
|
209
|
-
return this.getIdKey(id) === key;
|
|
210
|
-
});
|
|
407
|
+
const localOrder = orders.find((order) => this.isOrderLookupMatch(order, key));
|
|
211
408
|
if (!localOrder)
|
|
212
409
|
return null;
|
|
213
|
-
this.store.list = orders;
|
|
410
|
+
this.store.list = orders.map((order) => this.normalizeOrderForMemoryList(order));
|
|
214
411
|
this.syncOrdersMap();
|
|
215
|
-
return localOrder;
|
|
412
|
+
return this.normalizeOrderForMemoryList(localOrder);
|
|
216
413
|
}
|
|
217
414
|
async loadOrdersByServer() {
|
|
218
415
|
var _a;
|
|
@@ -233,17 +430,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
233
430
|
count: orderList.length
|
|
234
431
|
});
|
|
235
432
|
this.markOrderPulledAtNow();
|
|
433
|
+
this.lastServerFullFetchAtMs = Date.now();
|
|
236
434
|
} catch {
|
|
237
|
-
|
|
238
|
-
this.
|
|
435
|
+
this.logInfo("loadOrdersByServer-SSE拉取失败,保持当前内存订单");
|
|
436
|
+
return this.store.list;
|
|
239
437
|
}
|
|
240
438
|
}
|
|
241
|
-
await this.
|
|
439
|
+
const mergedOrders = await this.replaceOrdersSnapshotInSQLite(orderList, "loadOrdersByServer");
|
|
440
|
+
const memoryOrders = mergedOrders.map((order) => this.normalizeOrderForMemoryList(order));
|
|
242
441
|
this.logInfo("loadOrdersByServer-结束", {
|
|
243
|
-
count:
|
|
442
|
+
count: memoryOrders.length
|
|
244
443
|
});
|
|
245
|
-
await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded,
|
|
246
|
-
return
|
|
444
|
+
await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded, memoryOrders);
|
|
445
|
+
return memoryOrders;
|
|
247
446
|
}
|
|
248
447
|
/**
|
|
249
448
|
* 静默全量刷新:后台重新拉取全量 SSE 订单数据并更新本地
|
|
@@ -252,6 +451,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
252
451
|
*/
|
|
253
452
|
async silentRefresh() {
|
|
254
453
|
const startTime = Date.now();
|
|
454
|
+
const elapsedSinceFullFetch = Date.now() - this.lastServerFullFetchAtMs;
|
|
455
|
+
if (this.lastServerFullFetchAtMs > 0 && elapsedSinceFullFetch < ORDER_SILENT_REFRESH_MIN_INTERVAL_MS) {
|
|
456
|
+
return this.store.list;
|
|
457
|
+
}
|
|
255
458
|
this.logInfo("silentRefresh 开始");
|
|
256
459
|
try {
|
|
257
460
|
this.updateCreateStore();
|
|
@@ -259,7 +462,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
259
462
|
if (orders.length > 0) {
|
|
260
463
|
this.store.list = (0, import_lodash_es.cloneDeep)(orders);
|
|
261
464
|
this.syncOrdersMap();
|
|
262
|
-
this.
|
|
465
|
+
this.emitOrdersChanged([], "silentRefresh");
|
|
263
466
|
await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
264
467
|
this.logInfo("silentRefresh 完成", {
|
|
265
468
|
orderCount: orders.length,
|
|
@@ -282,6 +485,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
282
485
|
const ids = this.resourceIdIndex.get(String(resourceId)) || [];
|
|
283
486
|
return ids.map((id) => this.store.map.get(id)).filter((order) => !!order);
|
|
284
487
|
}
|
|
488
|
+
normalizeOrderForMemoryList(order) {
|
|
489
|
+
const externalSaleNumber = order == null ? void 0 : order.external_sale_number;
|
|
490
|
+
if ((order == null ? void 0 : order.order_id) !== void 0 && (order == null ? void 0 : order.order_id) !== null && (order == null ? void 0 : order.order_id) !== "") {
|
|
491
|
+
return order;
|
|
492
|
+
}
|
|
493
|
+
if (externalSaleNumber === void 0 || externalSaleNumber === null || externalSaleNumber === "") {
|
|
494
|
+
return order;
|
|
495
|
+
}
|
|
496
|
+
return {
|
|
497
|
+
...order,
|
|
498
|
+
order_id: externalSaleNumber
|
|
499
|
+
};
|
|
500
|
+
}
|
|
285
501
|
/**
|
|
286
502
|
* 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
|
|
287
503
|
* 适用于"按 order_id 主动刷新本地订单详情"的代理场景。
|
|
@@ -308,12 +524,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
308
524
|
return this.getIdKey(id) === key ? fresh : order;
|
|
309
525
|
});
|
|
310
526
|
this.syncOrdersMap();
|
|
311
|
-
await this.
|
|
527
|
+
await this.updateOrderInSQLite(fresh, "overwriteExistingOrder");
|
|
312
528
|
this.logInfo("overwriteExistingOrder-结束", {
|
|
313
529
|
orderId,
|
|
314
530
|
storeOrderCountAfter: this.store.list.length
|
|
315
531
|
});
|
|
316
|
-
await this.
|
|
532
|
+
await this.emitOrdersChanged([fresh], "overwriteExistingOrder");
|
|
317
533
|
return { overwritten: true };
|
|
318
534
|
}
|
|
319
535
|
/**
|
|
@@ -326,7 +542,104 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
326
542
|
return;
|
|
327
543
|
}
|
|
328
544
|
this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length });
|
|
329
|
-
await this.mergeOrdersToStore(freshOrders);
|
|
545
|
+
await this.mergeOrdersToStore(freshOrders, "upsertOrdersFromRemote");
|
|
546
|
+
}
|
|
547
|
+
async markOrderSyncedByExternalSaleNumber(params) {
|
|
548
|
+
const externalSaleNumber = params.externalSaleNumber;
|
|
549
|
+
if (externalSaleNumber === void 0 || externalSaleNumber === null || externalSaleNumber === "") {
|
|
550
|
+
this.logError("markOrderSyncedByExternalSaleNumber-缺少 external_sale_number");
|
|
551
|
+
return { updated: false };
|
|
552
|
+
}
|
|
553
|
+
const key = this.getIdKey(externalSaleNumber);
|
|
554
|
+
const targetIndex = this.store.list.findIndex((order) => {
|
|
555
|
+
const value = order == null ? void 0 : order.external_sale_number;
|
|
556
|
+
if (value === void 0 || value === null || value === "")
|
|
557
|
+
return false;
|
|
558
|
+
return this.getIdKey(value) === key;
|
|
559
|
+
});
|
|
560
|
+
if (targetIndex < 0) {
|
|
561
|
+
this.logInfo("markOrderSyncedByExternalSaleNumber-本地订单不存在,跳过", {
|
|
562
|
+
external_sale_number: externalSaleNumber
|
|
563
|
+
});
|
|
564
|
+
return { updated: false };
|
|
565
|
+
}
|
|
566
|
+
const existing = this.store.list[targetIndex];
|
|
567
|
+
const nextOrder = this.normalizeRemoteSyncedOrder({
|
|
568
|
+
...existing,
|
|
569
|
+
...params.patch || {},
|
|
570
|
+
external_sale_number: existing.external_sale_number ?? externalSaleNumber,
|
|
571
|
+
need_sync: 0
|
|
572
|
+
});
|
|
573
|
+
const storageKey = this.getOrderStorageKey(nextOrder) || key;
|
|
574
|
+
this.store.list = this.store.list.map((order, index) => {
|
|
575
|
+
if (index !== targetIndex)
|
|
576
|
+
return order;
|
|
577
|
+
return nextOrder;
|
|
578
|
+
});
|
|
579
|
+
this.syncOrdersMap();
|
|
580
|
+
await this.patchOrdersInSQLite(
|
|
581
|
+
[nextOrder],
|
|
582
|
+
"markOrderSyncedByExternalSaleNumber",
|
|
583
|
+
{ [storageKey]: "update" }
|
|
584
|
+
);
|
|
585
|
+
this.logInfo("markOrderSyncedByExternalSaleNumber-完成", {
|
|
586
|
+
external_sale_number: externalSaleNumber,
|
|
587
|
+
order_id: nextOrder.order_id ?? null
|
|
588
|
+
});
|
|
589
|
+
await this.emitOrdersChanged([nextOrder], "markOrderSyncedByExternalSaleNumber");
|
|
590
|
+
return { updated: true, order: nextOrder };
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* 将本地待同步订单按 SQLite storage key 合并进 store 并落库。
|
|
594
|
+
* checkout 离线兜底可能没有 order_id,但通常会有 external_sale_number。
|
|
595
|
+
*/
|
|
596
|
+
async upsertPendingSyncOrders(pendingOrders) {
|
|
597
|
+
if (!(pendingOrders == null ? void 0 : pendingOrders.length)) {
|
|
598
|
+
this.logInfo("upsertPendingSyncOrders-订单列表为空", {});
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
const pendingMap = /* @__PURE__ */ new Map();
|
|
602
|
+
const memoryPendingMap = /* @__PURE__ */ new Map();
|
|
603
|
+
for (const order of pendingOrders) {
|
|
604
|
+
const storageKey = this.getOrderStorageKey(order);
|
|
605
|
+
if (!storageKey)
|
|
606
|
+
continue;
|
|
607
|
+
pendingMap.set(storageKey, order);
|
|
608
|
+
memoryPendingMap.set(storageKey, this.normalizeOrderForMemoryList(order));
|
|
609
|
+
}
|
|
610
|
+
if (pendingMap.size === 0) {
|
|
611
|
+
this.logError("upsertPendingSyncOrders-订单缺少可落库标识", {
|
|
612
|
+
count: pendingOrders.length
|
|
613
|
+
});
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
this.logInfo("upsertPendingSyncOrders-开始", { count: pendingMap.size });
|
|
617
|
+
const patchedOrders = [...pendingMap.values()];
|
|
618
|
+
const mergeActions = {};
|
|
619
|
+
const updatedList = [...this.store.list];
|
|
620
|
+
for (const [storageKey, pendingOrder] of memoryPendingMap.entries()) {
|
|
621
|
+
const matchIndex = this.findOrderIndexByIdentity(updatedList, pendingOrder);
|
|
622
|
+
if (matchIndex < 0)
|
|
623
|
+
continue;
|
|
624
|
+
updatedList[matchIndex] = this.mergeOrderRecords(updatedList[matchIndex], pendingOrder, {
|
|
625
|
+
preferIncomingProducts: true
|
|
626
|
+
});
|
|
627
|
+
pendingMap.delete(storageKey);
|
|
628
|
+
memoryPendingMap.delete(storageKey);
|
|
629
|
+
mergeActions[storageKey] = "update";
|
|
630
|
+
}
|
|
631
|
+
for (const [storageKey, order] of memoryPendingMap.entries()) {
|
|
632
|
+
mergeActions[storageKey] = "insert";
|
|
633
|
+
updatedList.push(order);
|
|
634
|
+
}
|
|
635
|
+
this.store.list = this.compactOrderListByIdentity(updatedList, "upsertPendingSyncOrders.store").list;
|
|
636
|
+
this.syncOrdersMap();
|
|
637
|
+
await this.patchOrdersInSQLite(patchedOrders, "upsertPendingSyncOrders", mergeActions);
|
|
638
|
+
this.logInfo("upsertPendingSyncOrders-结束", {
|
|
639
|
+
count: patchedOrders.length,
|
|
640
|
+
storeOrderCountAfter: this.store.list.length
|
|
641
|
+
});
|
|
642
|
+
await this.emitOrdersChanged(patchedOrders, "upsertPendingSyncOrders");
|
|
330
643
|
}
|
|
331
644
|
/**
|
|
332
645
|
* 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
|
|
@@ -363,21 +676,65 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
363
676
|
this.store.map.clear();
|
|
364
677
|
this.resourceIdIndex.clear();
|
|
365
678
|
for (const order of this.store.list) {
|
|
366
|
-
const
|
|
367
|
-
if (
|
|
679
|
+
const primaryIdentity = this.getOrderMapKey(order);
|
|
680
|
+
if (!primaryIdentity)
|
|
368
681
|
continue;
|
|
369
|
-
this.store.map.set(
|
|
682
|
+
this.store.map.set(primaryIdentity, order);
|
|
370
683
|
const resourceIds = this.extractResourceIds(order);
|
|
371
684
|
for (const resourceId of resourceIds) {
|
|
372
685
|
const key = String(resourceId);
|
|
373
686
|
const existing = this.resourceIdIndex.get(key) || [];
|
|
374
|
-
if (existing.some((eid) => this.getIdKey(eid) ===
|
|
687
|
+
if (existing.some((eid) => this.getIdKey(eid) === primaryIdentity))
|
|
375
688
|
continue;
|
|
376
|
-
existing.push(
|
|
689
|
+
existing.push(primaryIdentity);
|
|
377
690
|
this.resourceIdIndex.set(key, existing);
|
|
378
691
|
}
|
|
379
692
|
}
|
|
380
693
|
}
|
|
694
|
+
getOrderMapKey(order) {
|
|
695
|
+
if (!order)
|
|
696
|
+
return "";
|
|
697
|
+
if (!this.isBlankIdentityValue(order.order_id)) {
|
|
698
|
+
return this.getIdKey(order.order_id);
|
|
699
|
+
}
|
|
700
|
+
const externalSaleNumber = order.external_sale_number;
|
|
701
|
+
if (!this.isBlankIdentityValue(externalSaleNumber)) {
|
|
702
|
+
return this.getIdKey(externalSaleNumber);
|
|
703
|
+
}
|
|
704
|
+
return "";
|
|
705
|
+
}
|
|
706
|
+
isBlankIdentityValue(value) {
|
|
707
|
+
return value === void 0 || value === null || value === "";
|
|
708
|
+
}
|
|
709
|
+
getOrderIdentityEntries(order) {
|
|
710
|
+
if (!order)
|
|
711
|
+
return [];
|
|
712
|
+
const record = order;
|
|
713
|
+
const candidates = [
|
|
714
|
+
{ field: "order_id", value: order.order_id },
|
|
715
|
+
{ field: "external_sale_number", value: record.external_sale_number },
|
|
716
|
+
{ field: "order_number", value: record.order_number },
|
|
717
|
+
{ field: "shop_order_number", value: record.shop_order_number }
|
|
718
|
+
];
|
|
719
|
+
const entries = [];
|
|
720
|
+
for (const candidate of candidates) {
|
|
721
|
+
if (this.isBlankIdentityValue(candidate.value))
|
|
722
|
+
continue;
|
|
723
|
+
const key = this.getIdKey(candidate.value);
|
|
724
|
+
if (entries.some((entry) => entry.field === candidate.field && entry.key === key))
|
|
725
|
+
continue;
|
|
726
|
+
entries.push({ field: candidate.field, key });
|
|
727
|
+
}
|
|
728
|
+
return entries;
|
|
729
|
+
}
|
|
730
|
+
getOrderIdentityKeys(order) {
|
|
731
|
+
const keys = [];
|
|
732
|
+
for (const entry of this.getOrderIdentityEntries(order)) {
|
|
733
|
+
if (!keys.includes(entry.key))
|
|
734
|
+
keys.push(entry.key);
|
|
735
|
+
}
|
|
736
|
+
return keys;
|
|
737
|
+
}
|
|
381
738
|
extractResourceIds(order) {
|
|
382
739
|
const ids = /* @__PURE__ */ new Set();
|
|
383
740
|
const visitResources = (resources) => {
|
|
@@ -434,7 +791,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
434
791
|
this.orderDataSource.run({
|
|
435
792
|
pubsub: {
|
|
436
793
|
callback: (res) => {
|
|
437
|
-
console.log("orderDataSource");
|
|
794
|
+
console.log("orderDataSource", res);
|
|
438
795
|
const pubsubReceivedAt = Date.now();
|
|
439
796
|
const message = this.normalizeOrderSyncMessage(res);
|
|
440
797
|
if (!message)
|
|
@@ -442,13 +799,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
442
799
|
message._pubsubReceivedAt = pubsubReceivedAt;
|
|
443
800
|
this.pendingSyncMessages.push(message);
|
|
444
801
|
const throttleMs = this.getOrderSyncThrottleMs();
|
|
802
|
+
const routeInfo = this.resolveSyncMessageRoute(message);
|
|
445
803
|
this.logInfo("orderSync-收到消息并入队", {
|
|
446
804
|
id: message.id ?? null,
|
|
447
805
|
order_id: message.order_id ?? null,
|
|
448
806
|
type: message.type ?? null,
|
|
449
807
|
pendingCount: this.pendingSyncMessages.length,
|
|
450
808
|
throttleMs,
|
|
451
|
-
pubsubReceivedAt: new Date(pubsubReceivedAt).toISOString()
|
|
809
|
+
pubsubReceivedAt: new Date(pubsubReceivedAt).toISOString(),
|
|
810
|
+
fullMessage: JSON.stringify(message)
|
|
452
811
|
});
|
|
453
812
|
this.scheduleOrderSyncThrottle();
|
|
454
813
|
}
|
|
@@ -514,7 +873,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
514
873
|
* await this.processOrderSyncMessages()
|
|
515
874
|
*/
|
|
516
875
|
async processOrderSyncMessages() {
|
|
517
|
-
var _a;
|
|
518
876
|
const messages = [...this.pendingSyncMessages];
|
|
519
877
|
this.pendingSyncMessages = [];
|
|
520
878
|
if (messages.length === 0)
|
|
@@ -531,38 +889,47 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
531
889
|
});
|
|
532
890
|
const upsertOrders = /* @__PURE__ */ new Map();
|
|
533
891
|
const refreshIds = [];
|
|
534
|
-
|
|
535
|
-
const
|
|
536
|
-
const
|
|
537
|
-
const
|
|
538
|
-
const
|
|
539
|
-
const normalizedBody = this.normalizeOrderSyncPayload(
|
|
540
|
-
if (
|
|
892
|
+
messages.forEach((msg, msgIndex) => {
|
|
893
|
+
const routeInfo = this.resolveSyncMessageRoute(msg);
|
|
894
|
+
const hasBatchIds = routeInfo.hasBatchIds;
|
|
895
|
+
const singleId = routeInfo.singleId;
|
|
896
|
+
const hasSingleId = routeInfo.hasSingleId;
|
|
897
|
+
const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
|
|
898
|
+
if (routeInfo.route === "bodyUpsert" && normalizedBody) {
|
|
541
899
|
upsertOrders.set(this.getIdKey(normalizedBody.order_id), normalizedBody);
|
|
542
|
-
|
|
900
|
+
return;
|
|
543
901
|
}
|
|
544
902
|
if (hasBatchIds)
|
|
545
|
-
refreshIds.push(...
|
|
546
|
-
else if (
|
|
903
|
+
refreshIds.push(...routeInfo.batchIds);
|
|
904
|
+
else if (routeInfo.route === "httpRefresh.singleId" && singleId !== null)
|
|
547
905
|
refreshIds.push(singleId);
|
|
548
|
-
else if (
|
|
549
|
-
refreshIds.push(...
|
|
550
|
-
}
|
|
906
|
+
else if (routeInfo.route === "httpRefresh.relationIds")
|
|
907
|
+
refreshIds.push(...routeInfo.batchIds);
|
|
908
|
+
});
|
|
551
909
|
const uniqueRefreshIds = this.uniqueOrderIds(refreshIds);
|
|
552
910
|
const upsertList = [...upsertOrders.values()];
|
|
553
911
|
this.logInfo("processOrderSyncMessages-去重完成", {
|
|
554
912
|
upsertCount: upsertList.length,
|
|
555
913
|
refreshIdCount: uniqueRefreshIds.length
|
|
556
914
|
});
|
|
557
|
-
if (upsertList.length > 0)
|
|
558
|
-
await this.mergeOrdersToStore(upsertList);
|
|
915
|
+
if (upsertList.length > 0) {
|
|
916
|
+
await this.mergeOrdersToStore(upsertList, "pubsub.bodyUpsert");
|
|
917
|
+
}
|
|
559
918
|
if (uniqueRefreshIds.length > 0) {
|
|
560
|
-
const
|
|
561
|
-
if (
|
|
562
|
-
|
|
919
|
+
const { toFetch, skipped } = this.filterRedundantHttpRefreshIds(uniqueRefreshIds);
|
|
920
|
+
if (skipped.length > 0) {
|
|
921
|
+
}
|
|
922
|
+
if (toFetch.length > 0) {
|
|
923
|
+
const freshOrders = await this.fetchOrdersByHttp(toFetch);
|
|
924
|
+
if (freshOrders.length > 0) {
|
|
925
|
+
await this.mergeOrdersToStore(freshOrders, "pubsub.httpRefresh");
|
|
926
|
+
} else {
|
|
927
|
+
}
|
|
928
|
+
}
|
|
563
929
|
}
|
|
564
|
-
if (upsertList.length === 0 && uniqueRefreshIds.length === 0)
|
|
930
|
+
if (upsertList.length === 0 && uniqueRefreshIds.length === 0) {
|
|
565
931
|
return;
|
|
932
|
+
}
|
|
566
933
|
const batchProcessEndAt = Date.now();
|
|
567
934
|
this.logInfo("processOrderSyncMessages-结束", {
|
|
568
935
|
upsertCount: upsertList.length,
|
|
@@ -603,41 +970,62 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
603
970
|
/**
|
|
604
971
|
* 将增量订单合并到 store
|
|
605
972
|
*/
|
|
606
|
-
async mergeOrdersToStore(freshOrders) {
|
|
973
|
+
async mergeOrdersToStore(freshOrders, source) {
|
|
607
974
|
this.logInfo("mergeOrdersToStore-开始", {
|
|
608
975
|
freshOrderCount: freshOrders.length,
|
|
609
|
-
storeOrderCountBefore: this.store.list.length
|
|
976
|
+
storeOrderCountBefore: this.store.list.length,
|
|
977
|
+
source
|
|
610
978
|
});
|
|
611
|
-
|
|
979
|
+
this.logDuplicateOrders(`${source}.beforeMerge`, this.store.list);
|
|
980
|
+
const normalizedFreshOrders = [];
|
|
612
981
|
for (const order of freshOrders) {
|
|
613
982
|
const id = order == null ? void 0 : order.order_id;
|
|
614
983
|
if (id === void 0 || id === null)
|
|
615
984
|
continue;
|
|
616
|
-
|
|
985
|
+
normalizedFreshOrders.push(this.normalizeRemoteSyncedOrder(order));
|
|
617
986
|
}
|
|
618
|
-
const
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
987
|
+
const uniqueFreshOrders = this.compactOrderListByIdentity(
|
|
988
|
+
normalizedFreshOrders,
|
|
989
|
+
`${source}.incoming`
|
|
990
|
+
).list;
|
|
991
|
+
const uniqueFreshCount = uniqueFreshOrders.length;
|
|
992
|
+
const patchedOrders = [];
|
|
993
|
+
const mergeActions = {};
|
|
994
|
+
const updatedList = [...this.store.list];
|
|
995
|
+
for (const fresh of uniqueFreshOrders) {
|
|
996
|
+
const matchIndex = this.findOrderIndexByIdentity(updatedList, fresh);
|
|
997
|
+
const storageKey = this.getOrderStorageKey(fresh);
|
|
998
|
+
const mergeKey = storageKey || (fresh.order_id !== void 0 && fresh.order_id !== null ? this.getIdKey(fresh.order_id) : "");
|
|
999
|
+
if (matchIndex >= 0) {
|
|
1000
|
+
const mergedOrder = this.mergeOrderRecords(updatedList[matchIndex], fresh);
|
|
1001
|
+
updatedList[matchIndex] = mergedOrder;
|
|
1002
|
+
patchedOrders.push(mergedOrder);
|
|
1003
|
+
if (mergeKey)
|
|
1004
|
+
mergeActions[mergeKey] = "update";
|
|
1005
|
+
continue;
|
|
1006
|
+
}
|
|
1007
|
+
updatedList.push(fresh);
|
|
1008
|
+
patchedOrders.push(fresh);
|
|
1009
|
+
if (mergeKey)
|
|
1010
|
+
mergeActions[mergeKey] = "insert";
|
|
632
1011
|
}
|
|
633
|
-
|
|
1012
|
+
const insertCount = Object.values(mergeActions).filter((v) => v === "insert").length;
|
|
1013
|
+
const updateCount = Object.values(mergeActions).filter((v) => v === "update").length;
|
|
1014
|
+
this.logInfo("mergeOrdersToStore-合并完成", {
|
|
1015
|
+
insertCount,
|
|
1016
|
+
updateCount,
|
|
1017
|
+
storeOrderCountAfter: this.store.list.length
|
|
1018
|
+
});
|
|
1019
|
+
this.store.list = this.compactOrderListByIdentity(updatedList, `${source}.store`).list;
|
|
634
1020
|
this.syncOrdersMap();
|
|
635
|
-
await this.
|
|
1021
|
+
await this.patchOrdersInSQLite(patchedOrders, source, mergeActions);
|
|
636
1022
|
this.logInfo("mergeOrdersToStore-结束", {
|
|
637
1023
|
uniqueFreshCount,
|
|
638
|
-
storeOrderCountAfter: this.store.list.length
|
|
1024
|
+
storeOrderCountAfter: this.store.list.length,
|
|
1025
|
+
insertCount,
|
|
1026
|
+
updateCount
|
|
639
1027
|
});
|
|
640
|
-
this.
|
|
1028
|
+
await this.emitOrdersChanged(patchedOrders, source);
|
|
641
1029
|
}
|
|
642
1030
|
normalizeOrderSyncMessage(res) {
|
|
643
1031
|
const data = (res == null ? void 0 : res.data) || res;
|
|
@@ -682,6 +1070,229 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
682
1070
|
getIdKey(id) {
|
|
683
1071
|
return String(id);
|
|
684
1072
|
}
|
|
1073
|
+
isOrderLookupMatch(order, lookupKey) {
|
|
1074
|
+
if (!order || !lookupKey)
|
|
1075
|
+
return false;
|
|
1076
|
+
const candidates = [
|
|
1077
|
+
order.order_id,
|
|
1078
|
+
order.external_sale_number,
|
|
1079
|
+
order.order_number,
|
|
1080
|
+
order.shop_order_number,
|
|
1081
|
+
order.shop_full_order_number
|
|
1082
|
+
];
|
|
1083
|
+
return candidates.some((value) => {
|
|
1084
|
+
if (value === void 0 || value === null || value === "")
|
|
1085
|
+
return false;
|
|
1086
|
+
return this.getIdKey(value) === lookupKey;
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* 解析订单 SQLite 主键,规则与宿主 OrderDataSource.getOrderStorageKey 一致。
|
|
1091
|
+
*
|
|
1092
|
+
* @example
|
|
1093
|
+
* const key = this.getOrderStorageKey({ order_id: 1001, external_sale_number: 'S-1001' })
|
|
1094
|
+
* // => 'S-1001'
|
|
1095
|
+
*/
|
|
1096
|
+
getOrderStorageKey(order) {
|
|
1097
|
+
const externalSaleNumber = order == null ? void 0 : order.external_sale_number;
|
|
1098
|
+
if (externalSaleNumber !== void 0 && externalSaleNumber !== null && externalSaleNumber !== "") {
|
|
1099
|
+
return String(externalSaleNumber);
|
|
1100
|
+
}
|
|
1101
|
+
const orderId = order == null ? void 0 : order.order_id;
|
|
1102
|
+
if (orderId !== void 0 && orderId !== null && orderId !== "") {
|
|
1103
|
+
return String(orderId);
|
|
1104
|
+
}
|
|
1105
|
+
return "";
|
|
1106
|
+
}
|
|
1107
|
+
getOrderIdentityMatchKeys(order) {
|
|
1108
|
+
return this.getOrderIdentityEntries(order).map((entry) => `${entry.field}:${entry.key}`);
|
|
1109
|
+
}
|
|
1110
|
+
doOrdersShareIdentity(left, right) {
|
|
1111
|
+
const leftKeys = new Set(this.getOrderIdentityMatchKeys(left));
|
|
1112
|
+
if (leftKeys.size === 0)
|
|
1113
|
+
return false;
|
|
1114
|
+
return this.getOrderIdentityMatchKeys(right).some((key) => leftKeys.has(key));
|
|
1115
|
+
}
|
|
1116
|
+
findOrderIndexByIdentity(orders, target) {
|
|
1117
|
+
if (this.getOrderIdentityMatchKeys(target).length === 0)
|
|
1118
|
+
return -1;
|
|
1119
|
+
return orders.findIndex((order) => this.doOrdersShareIdentity(order, target));
|
|
1120
|
+
}
|
|
1121
|
+
getOrderCompletenessScore(order) {
|
|
1122
|
+
const record = order;
|
|
1123
|
+
let score = this.isPendingSyncOrder(order) ? 0 : 100;
|
|
1124
|
+
if (!this.isBlankIdentityValue(order.order_id) && order.order_id !== record.external_sale_number)
|
|
1125
|
+
score += 30;
|
|
1126
|
+
score += this.getOrderIdentityMatchKeys(order).length * 5;
|
|
1127
|
+
if (Array.isArray(order.products))
|
|
1128
|
+
score += Math.min(order.products.length, 10);
|
|
1129
|
+
if (Array.isArray(order.bookings))
|
|
1130
|
+
score += Math.min(order.bookings.length, 10);
|
|
1131
|
+
if (Array.isArray(order.payments))
|
|
1132
|
+
score += Math.min(order.payments.length, 10);
|
|
1133
|
+
if (record.updated_at)
|
|
1134
|
+
score += 1;
|
|
1135
|
+
return score;
|
|
1136
|
+
}
|
|
1137
|
+
pickPreferredOrder(left, right) {
|
|
1138
|
+
const leftScore = this.getOrderCompletenessScore(left);
|
|
1139
|
+
const rightScore = this.getOrderCompletenessScore(right);
|
|
1140
|
+
if (rightScore >= leftScore)
|
|
1141
|
+
return right;
|
|
1142
|
+
return left;
|
|
1143
|
+
}
|
|
1144
|
+
getProductMergeKey(product) {
|
|
1145
|
+
var _a;
|
|
1146
|
+
const record = product;
|
|
1147
|
+
if (!record)
|
|
1148
|
+
return "";
|
|
1149
|
+
const metadataUid = (_a = record.metadata) == null ? void 0 : _a.unique_identification_number;
|
|
1150
|
+
if (!this.isBlankIdentityValue(metadataUid))
|
|
1151
|
+
return `uid:${String(metadataUid)}`;
|
|
1152
|
+
const topLevelUid = record.unique_identification_number;
|
|
1153
|
+
if (!this.isBlankIdentityValue(topLevelUid))
|
|
1154
|
+
return `uid:${String(topLevelUid)}`;
|
|
1155
|
+
const orderDetailId = record.order_detail_id;
|
|
1156
|
+
if (!this.isBlankIdentityValue(orderDetailId))
|
|
1157
|
+
return `detail:${String(orderDetailId)}`;
|
|
1158
|
+
const bookingUid = record.booking_uid;
|
|
1159
|
+
if (!this.isBlankIdentityValue(bookingUid))
|
|
1160
|
+
return `booking:${String(bookingUid)}`;
|
|
1161
|
+
return "";
|
|
1162
|
+
}
|
|
1163
|
+
mergeOrderProductLists(preferred, secondary) {
|
|
1164
|
+
const preferredList = Array.isArray(preferred) ? preferred : [];
|
|
1165
|
+
const secondaryList = Array.isArray(secondary) ? secondary : [];
|
|
1166
|
+
if (secondaryList.length === 0)
|
|
1167
|
+
return preferredList;
|
|
1168
|
+
if (preferredList.length === 0)
|
|
1169
|
+
return secondaryList;
|
|
1170
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
1171
|
+
for (const item of preferredList) {
|
|
1172
|
+
const key = this.getProductMergeKey(item);
|
|
1173
|
+
if (key)
|
|
1174
|
+
seenKeys.add(key);
|
|
1175
|
+
}
|
|
1176
|
+
const result = [...preferredList];
|
|
1177
|
+
for (const item of secondaryList) {
|
|
1178
|
+
const key = this.getProductMergeKey(item);
|
|
1179
|
+
if (!key || seenKeys.has(key))
|
|
1180
|
+
continue;
|
|
1181
|
+
seenKeys.add(key);
|
|
1182
|
+
result.push((0, import_lodash_es.cloneDeep)(item));
|
|
1183
|
+
}
|
|
1184
|
+
return result;
|
|
1185
|
+
}
|
|
1186
|
+
mergeOrderRecords(existing, incoming, options) {
|
|
1187
|
+
const preferred = this.pickPreferredOrder(existing, incoming);
|
|
1188
|
+
const secondary = preferred === existing ? incoming : existing;
|
|
1189
|
+
const merged = {
|
|
1190
|
+
...secondary,
|
|
1191
|
+
...preferred
|
|
1192
|
+
};
|
|
1193
|
+
const fieldsToPreserve = [
|
|
1194
|
+
"order_id",
|
|
1195
|
+
"external_sale_number",
|
|
1196
|
+
"order_number",
|
|
1197
|
+
"shop_order_number",
|
|
1198
|
+
"shop_full_order_number"
|
|
1199
|
+
];
|
|
1200
|
+
const incomingPatchFields = [
|
|
1201
|
+
"payment_status",
|
|
1202
|
+
"status",
|
|
1203
|
+
"shipping_status",
|
|
1204
|
+
"updated_at",
|
|
1205
|
+
"shop_discount",
|
|
1206
|
+
"summary",
|
|
1207
|
+
"payments",
|
|
1208
|
+
"products",
|
|
1209
|
+
"bookings"
|
|
1210
|
+
];
|
|
1211
|
+
const mergedRecord = merged;
|
|
1212
|
+
const preferredRecord = preferred;
|
|
1213
|
+
const secondaryRecord = secondary;
|
|
1214
|
+
const incomingRecord = incoming;
|
|
1215
|
+
for (const field of fieldsToPreserve) {
|
|
1216
|
+
if (!this.isBlankIdentityValue(preferredRecord[field])) {
|
|
1217
|
+
mergedRecord[field] = preferredRecord[field];
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1220
|
+
if (!this.isBlankIdentityValue(secondaryRecord[field])) {
|
|
1221
|
+
mergedRecord[field] = secondaryRecord[field];
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
const hasIncomingProducts = Object.prototype.hasOwnProperty.call(incomingRecord, "products");
|
|
1225
|
+
const shouldUseIncomingProductsSnapshot = (options == null ? void 0 : options.preferIncomingProducts) === true && hasIncomingProducts && incomingRecord.products !== void 0 && incomingRecord.products !== null;
|
|
1226
|
+
for (const field of incomingPatchFields) {
|
|
1227
|
+
if (!Object.prototype.hasOwnProperty.call(incomingRecord, field))
|
|
1228
|
+
continue;
|
|
1229
|
+
if (incomingRecord[field] === void 0 || incomingRecord[field] === null)
|
|
1230
|
+
continue;
|
|
1231
|
+
if (typeof incomingRecord[field] === "string" && incomingRecord[field] === "")
|
|
1232
|
+
continue;
|
|
1233
|
+
mergedRecord[field] = (0, import_lodash_es.cloneDeep)(incomingRecord[field]);
|
|
1234
|
+
}
|
|
1235
|
+
mergedRecord.products = shouldUseIncomingProductsSnapshot ? (0, import_lodash_es.cloneDeep)(incomingRecord.products) : this.mergeOrderProductLists(preferredRecord.products, secondaryRecord.products);
|
|
1236
|
+
if (!this.isPendingSyncOrder(preferred) || !this.isPendingSyncOrder(secondary)) {
|
|
1237
|
+
merged.need_sync = 0;
|
|
1238
|
+
}
|
|
1239
|
+
return merged;
|
|
1240
|
+
}
|
|
1241
|
+
summarizeDuplicateOrders(orders) {
|
|
1242
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1243
|
+
for (const order of orders) {
|
|
1244
|
+
for (const key of this.getOrderIdentityMatchKeys(order)) {
|
|
1245
|
+
const group = groups.get(key) || [];
|
|
1246
|
+
group.push(order);
|
|
1247
|
+
groups.set(key, group);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
return [...groups.entries()].filter(([, group]) => group.length > 1).slice(0, 20).map(([key, group]) => ({
|
|
1251
|
+
key,
|
|
1252
|
+
count: group.length,
|
|
1253
|
+
orders: group.map((order) => ({
|
|
1254
|
+
order_id: order.order_id ?? null,
|
|
1255
|
+
external_sale_number: order.external_sale_number ?? null,
|
|
1256
|
+
shop_order_number: order.shop_order_number ?? null,
|
|
1257
|
+
shop_full_order_number: order.shop_full_order_number ?? null,
|
|
1258
|
+
need_sync: order.need_sync ?? null
|
|
1259
|
+
}))
|
|
1260
|
+
}));
|
|
1261
|
+
}
|
|
1262
|
+
logDuplicateOrders(source, orders) {
|
|
1263
|
+
const duplicateGroups = this.summarizeDuplicateOrders(orders);
|
|
1264
|
+
if (duplicateGroups.length === 0)
|
|
1265
|
+
return;
|
|
1266
|
+
this.logWarning("检测到重复订单身份键", {
|
|
1267
|
+
source,
|
|
1268
|
+
duplicateGroupCount: duplicateGroups.length,
|
|
1269
|
+
duplicateGroups
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
compactOrderListByIdentity(orders, source) {
|
|
1273
|
+
const list = [];
|
|
1274
|
+
let removedCount = 0;
|
|
1275
|
+
for (const order of orders) {
|
|
1276
|
+
const matchIndex = this.findOrderIndexByIdentity(list, order);
|
|
1277
|
+
if (matchIndex < 0) {
|
|
1278
|
+
list.push(order);
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
list[matchIndex] = this.mergeOrderRecords(list[matchIndex], order);
|
|
1282
|
+
removedCount += 1;
|
|
1283
|
+
}
|
|
1284
|
+
if (removedCount > 0) {
|
|
1285
|
+
this.logWarning("订单列表重复项已压缩", {
|
|
1286
|
+
source,
|
|
1287
|
+
beforeCount: orders.length,
|
|
1288
|
+
afterCount: list.length,
|
|
1289
|
+
removedCount
|
|
1290
|
+
});
|
|
1291
|
+
} else {
|
|
1292
|
+
this.logDuplicateOrders(source, orders);
|
|
1293
|
+
}
|
|
1294
|
+
return { list, removedCount };
|
|
1295
|
+
}
|
|
685
1296
|
/**
|
|
686
1297
|
* 当前订单拉取窗口:
|
|
687
1298
|
* - 优先使用 createdAtQuery.sales_time_between(已按营业日边界初始化)
|
|
@@ -752,39 +1363,221 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
752
1363
|
return [];
|
|
753
1364
|
}
|
|
754
1365
|
}
|
|
755
|
-
|
|
756
|
-
|
|
1366
|
+
isPendingSyncOrder(order) {
|
|
1367
|
+
return Number(order == null ? void 0 : order.need_sync) === 1;
|
|
1368
|
+
}
|
|
1369
|
+
normalizeRemoteSyncedOrder(order) {
|
|
1370
|
+
if (this.isPendingSyncOrder(order))
|
|
1371
|
+
return order;
|
|
1372
|
+
return {
|
|
1373
|
+
...order,
|
|
1374
|
+
need_sync: 0
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
mergeRemoteSnapshotWithPendingOrders(remoteOrders, existingOrders) {
|
|
1378
|
+
const merged = remoteOrders.map((order) => this.normalizeRemoteSyncedOrder(order));
|
|
1379
|
+
for (const order of existingOrders) {
|
|
1380
|
+
if (!this.isPendingSyncOrder(order))
|
|
1381
|
+
continue;
|
|
1382
|
+
const matchIndex = this.findOrderIndexByIdentity(merged, order);
|
|
1383
|
+
if (matchIndex >= 0) {
|
|
1384
|
+
merged[matchIndex] = this.mergeOrderRecords(order, merged[matchIndex]);
|
|
1385
|
+
continue;
|
|
1386
|
+
}
|
|
1387
|
+
if (!this.getOrderStorageKey(order))
|
|
1388
|
+
continue;
|
|
1389
|
+
merged.push(order);
|
|
1390
|
+
}
|
|
1391
|
+
return this.compactOrderListByIdentity(merged, "mergeRemoteSnapshotWithPendingOrders").list;
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* 串行执行订单 SQLite 写入任务,避免快照替换与增量 upsert 并发交错。
|
|
1395
|
+
*
|
|
1396
|
+
* @example
|
|
1397
|
+
* await this.runInOrderSQLiteSaveQueue(async () => {
|
|
1398
|
+
* await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, orders)
|
|
1399
|
+
* })
|
|
1400
|
+
*/
|
|
1401
|
+
async runInOrderSQLiteSaveQueue(task) {
|
|
1402
|
+
const queuedTask = this.orderSQLiteSaveQueue.then(task, task);
|
|
1403
|
+
this.orderSQLiteSaveQueue = queuedTask.then(() => void 0, () => void 0);
|
|
1404
|
+
return queuedTask;
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* 批量增量 upsert 订单到 SQLite,不清空表;用于 pubsub / HTTP 增量合并。
|
|
1408
|
+
*
|
|
1409
|
+
* @example
|
|
1410
|
+
* await this.patchOrdersInSQLite(freshOrders)
|
|
1411
|
+
*/
|
|
1412
|
+
async patchOrdersInSQLite(orders, source, mergeActions = {}) {
|
|
1413
|
+
if (!this.dbManager || orders.length === 0) {
|
|
757
1414
|
return;
|
|
1415
|
+
}
|
|
1416
|
+
const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).filter((order) => this.getOrderStorageKey(order));
|
|
1417
|
+
if (ordersSnapshot.length === 0) {
|
|
1418
|
+
return;
|
|
1419
|
+
}
|
|
1420
|
+
const { toWrite, skipped } = this.filterRedundantPatchOrders(
|
|
1421
|
+
source,
|
|
1422
|
+
ordersSnapshot,
|
|
1423
|
+
mergeActions
|
|
1424
|
+
);
|
|
1425
|
+
if (toWrite.length === 0) {
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
const compactedToWrite = this.compactOrderListByIdentity(toWrite, `${source}.sqlitePatch`).list;
|
|
1429
|
+
if (compactedToWrite.length === 0) {
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
758
1432
|
try {
|
|
759
|
-
this.
|
|
760
|
-
|
|
1433
|
+
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
1434
|
+
let writeMethod = "none";
|
|
1435
|
+
this.logInfo("patchOrdersInSQLite-开始", {
|
|
1436
|
+
source,
|
|
1437
|
+
count: compactedToWrite.length,
|
|
1438
|
+
dedupedCount: skipped.length
|
|
1439
|
+
});
|
|
1440
|
+
if (typeof this.dbManager.bulkUpdate === "function") {
|
|
1441
|
+
writeMethod = "bulkUpdate";
|
|
1442
|
+
await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, compactedToWrite);
|
|
1443
|
+
} else if (typeof this.dbManager.bulkAdd === "function") {
|
|
1444
|
+
writeMethod = "bulkAdd";
|
|
1445
|
+
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, compactedToWrite);
|
|
1446
|
+
} else if (typeof this.dbManager.update === "function") {
|
|
1447
|
+
writeMethod = "update";
|
|
1448
|
+
for (const order of compactedToWrite) {
|
|
1449
|
+
await this.dbManager.update(INDEXDB_STORE_NAME, order);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
this.recordRecentSqliteWrite(source, compactedToWrite);
|
|
1453
|
+
this.logInfo("patchOrdersInSQLite-完成", {
|
|
1454
|
+
source,
|
|
1455
|
+
count: compactedToWrite.length,
|
|
1456
|
+
writeMethod,
|
|
1457
|
+
dedupedCount: skipped.length
|
|
1458
|
+
});
|
|
761
1459
|
});
|
|
762
|
-
|
|
763
|
-
this.
|
|
764
|
-
|
|
1460
|
+
} catch (error) {
|
|
1461
|
+
this.logError("增量保存订单到 SQLite 失败", {
|
|
1462
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1463
|
+
orderCount: ordersSnapshot.length
|
|
765
1464
|
});
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* 单条 upsert 订单到 SQLite;用于 overwriteExistingOrder 等单条覆盖场景。
|
|
1469
|
+
*
|
|
1470
|
+
* @example
|
|
1471
|
+
* await this.updateOrderInSQLite(freshOrder)
|
|
1472
|
+
*/
|
|
1473
|
+
async updateOrderInSQLite(order, source) {
|
|
1474
|
+
if (!this.dbManager || !this.getOrderStorageKey(order)) {
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
const orderSnapshot = (0, import_lodash_es.cloneDeep)(order);
|
|
1478
|
+
try {
|
|
1479
|
+
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
1480
|
+
let writeMethod = "none";
|
|
1481
|
+
this.logInfo("updateOrderInSQLite-开始", {
|
|
1482
|
+
source,
|
|
1483
|
+
orderId: orderSnapshot.order_id ?? null,
|
|
1484
|
+
storageKey: this.getOrderStorageKey(orderSnapshot)
|
|
1485
|
+
});
|
|
1486
|
+
if (typeof this.dbManager.update === "function") {
|
|
1487
|
+
writeMethod = "update";
|
|
1488
|
+
await this.dbManager.update(INDEXDB_STORE_NAME, orderSnapshot);
|
|
1489
|
+
} else if (typeof this.dbManager.bulkUpdate === "function") {
|
|
1490
|
+
writeMethod = "bulkUpdate";
|
|
1491
|
+
await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, [orderSnapshot]);
|
|
1492
|
+
} else if (typeof this.dbManager.bulkAdd === "function") {
|
|
1493
|
+
writeMethod = "bulkAdd";
|
|
1494
|
+
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, [orderSnapshot]);
|
|
1495
|
+
}
|
|
1496
|
+
this.recordRecentSqliteWrite(source, [orderSnapshot]);
|
|
1497
|
+
this.logInfo("updateOrderInSQLite-完成", {
|
|
1498
|
+
source,
|
|
1499
|
+
orderId: orderSnapshot.order_id ?? null,
|
|
1500
|
+
writeMethod
|
|
1501
|
+
});
|
|
1502
|
+
});
|
|
1503
|
+
} catch (error) {
|
|
1504
|
+
this.logError("单条保存订单到 SQLite 失败", {
|
|
1505
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1506
|
+
orderId: orderSnapshot.order_id ?? null
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* 全量快照替换 orders 表(clear + bulkAdd),用于 SSE 全量拉取与营业日窗口裁剪。
|
|
1512
|
+
*
|
|
1513
|
+
* @example
|
|
1514
|
+
* await this.replaceOrdersSnapshotInSQLite(orderList)
|
|
1515
|
+
*/
|
|
1516
|
+
async replaceOrdersSnapshotInSQLite(orderList, source) {
|
|
1517
|
+
if (!this.dbManager) {
|
|
1518
|
+
return this.compactOrderListByIdentity(
|
|
1519
|
+
orderList.map((order) => this.normalizeRemoteSyncedOrder(order)),
|
|
1520
|
+
`${source}.snapshotNoDb`
|
|
1521
|
+
).list;
|
|
1522
|
+
}
|
|
1523
|
+
const remoteSnapshot = (0, import_lodash_es.cloneDeep)(orderList);
|
|
1524
|
+
let mergedSnapshot = this.compactOrderListByIdentity(
|
|
1525
|
+
remoteSnapshot.map((order) => this.normalizeRemoteSyncedOrder(order)),
|
|
1526
|
+
`${source}.remoteSnapshot`
|
|
1527
|
+
).list;
|
|
1528
|
+
try {
|
|
1529
|
+
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
1530
|
+
const existingOrders = typeof this.dbManager.getAll === "function" ? await this.dbManager.getAll(INDEXDB_STORE_NAME) : [];
|
|
1531
|
+
const orderListSnapshot = this.mergeRemoteSnapshotWithPendingOrders(
|
|
1532
|
+
remoteSnapshot,
|
|
1533
|
+
existingOrders || []
|
|
1534
|
+
);
|
|
1535
|
+
mergedSnapshot = this.compactOrderListByIdentity(orderListSnapshot, `${source}.sqliteSnapshot`).list;
|
|
1536
|
+
this.logInfo("replaceOrdersSnapshotInSQLite-开始", {
|
|
1537
|
+
source,
|
|
1538
|
+
count: mergedSnapshot.length,
|
|
1539
|
+
remoteCount: remoteSnapshot.length,
|
|
1540
|
+
preservedPendingCount: mergedSnapshot.length - remoteSnapshot.length
|
|
1541
|
+
});
|
|
1542
|
+
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
1543
|
+
this.logInfo("replaceOrdersSnapshotInSQLite-clear完成", {
|
|
1544
|
+
count: mergedSnapshot.length
|
|
1545
|
+
});
|
|
1546
|
+
if (mergedSnapshot.length === 0) {
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, mergedSnapshot);
|
|
1550
|
+
this.recordRecentSqliteWrite(source, mergedSnapshot);
|
|
1551
|
+
this.logInfo("replaceOrdersSnapshotInSQLite-bulkAdd完成", {
|
|
1552
|
+
source,
|
|
1553
|
+
count: mergedSnapshot.length
|
|
1554
|
+
});
|
|
771
1555
|
});
|
|
772
1556
|
} catch (error) {
|
|
773
|
-
this.logError("
|
|
1557
|
+
this.logError("全量保存订单到 SQLite 失败", {
|
|
774
1558
|
error: error instanceof Error ? error.message : String(error),
|
|
775
|
-
orderList:
|
|
1559
|
+
orderList: remoteSnapshot.length
|
|
776
1560
|
});
|
|
777
1561
|
}
|
|
1562
|
+
return mergedSnapshot;
|
|
778
1563
|
}
|
|
1564
|
+
/**
|
|
1565
|
+
* 清空订单模块的内存数据和本地 SQLite 订单表。
|
|
1566
|
+
*
|
|
1567
|
+
* @example
|
|
1568
|
+
* await orderModule.clear()
|
|
1569
|
+
*/
|
|
779
1570
|
async clear() {
|
|
780
1571
|
this.store.list = [];
|
|
781
1572
|
this.store.map = /* @__PURE__ */ new Map();
|
|
782
1573
|
this.resourceIdIndex.clear();
|
|
783
1574
|
if (this.dbManager) {
|
|
784
|
-
await this.
|
|
1575
|
+
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
1576
|
+
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
1577
|
+
});
|
|
785
1578
|
}
|
|
786
1579
|
this.setStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY, "");
|
|
787
|
-
this.
|
|
1580
|
+
this.emitOrdersChanged([], "clear");
|
|
788
1581
|
}
|
|
789
1582
|
};
|
|
790
1583
|
// Annotate the CommonJS export names for ESM import in node:
|