@pisell/pisellos 0.10.15 → 0.10.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.js +6 -9
- package/dist/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/model/strategy/adapter/walletPass/example.js +3 -26
- package/dist/model/strategy/strategy-example.js +5 -19
- package/dist/modules/Cart/index.js +0 -3
- package/dist/modules/Cart/utils/cartProduct.js +0 -1
- package/dist/modules/Date/index.js +1 -5
- package/dist/modules/Discount/index.js +2 -4
- package/dist/modules/OpenData/index.d.ts +5 -2
- package/dist/modules/OpenData/index.js +27 -14
- package/dist/modules/OpenData/types.d.ts +42 -0
- package/dist/modules/OpenData/types.js +7 -1
- package/dist/modules/OpenData/utils.d.ts +15 -1
- package/dist/modules/OpenData/utils.js +85 -0
- package/dist/modules/Order/index.d.ts +4 -2
- package/dist/modules/Order/index.js +131 -123
- package/dist/modules/Order/types.d.ts +8 -1
- package/dist/modules/Order/types.js +1 -0
- package/dist/modules/Order/utils.js +7 -1
- package/dist/modules/Payment/index.js +97 -162
- package/dist/modules/Product/types.d.ts +2 -0
- package/dist/modules/ProductList/index.js +96 -74
- package/dist/modules/Rules/index.js +12 -12
- package/dist/modules/SalesSummary/index.js +6 -4
- package/dist/modules/Schedule/index.js +0 -1
- package/dist/modules/Schedule/utils.js +0 -1
- package/dist/modules/Step/index.js +0 -1
- package/dist/plugins/request.js +1 -4
- package/dist/plugins/window.js +2 -6
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.js +977 -641
- package/dist/server/modules/menu/index.js +32 -41
- package/dist/server/modules/order/index.d.ts +8 -0
- package/dist/server/modules/order/index.js +253 -219
- package/dist/server/modules/products/index.js +24 -42
- package/dist/server/modules/quotation/index.js +29 -38
- package/dist/server/modules/resource/index.js +3 -4
- package/dist/server/modules/schedule/index.js +27 -35
- package/dist/server/utils/product.js +0 -1
- package/dist/server/utils/small-ticket.d.ts +9 -1
- package/dist/server/utils/small-ticket.js +117 -43
- package/dist/solution/BaseSales/index.d.ts +7 -0
- package/dist/solution/BaseSales/index.js +350 -215
- package/dist/solution/BaseSales/types.d.ts +2 -0
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +5 -0
- package/dist/solution/BaseSales/utils/cartPromotion.js +15 -6
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +3 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +7 -1
- package/dist/solution/BaseSales/utils.js +6 -3
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/BookingByStep/index.js +7 -59
- package/dist/solution/BookingByStep/utils/capacity.js +1 -11
- package/dist/solution/BookingByStep/utils/resources.js +1 -3
- package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
- package/dist/solution/BookingTicket/index.d.ts +14 -19
- package/dist/solution/BookingTicket/index.js +553 -433
- package/dist/solution/BookingTicket/utils/addProductDecision.js +3 -1
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +6 -7
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
- package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
- package/dist/solution/BuyTickets/index.js +9 -12
- package/dist/solution/Checkout/index.js +177 -252
- package/dist/solution/Checkout/utils/index.js +4 -16
- package/dist/solution/RegisterAndLogin/index.js +30 -76
- package/dist/solution/Sales/index.d.ts +20 -4
- package/dist/solution/Sales/index.js +348 -75
- package/dist/solution/Sales/types.d.ts +10 -0
- package/dist/solution/ScanOrder/index.js +50 -60
- package/dist/solution/ScanOrder/types.d.ts +2 -0
- package/dist/solution/ScanOrder/utils.js +6 -3
- package/dist/solution/ShopDiscount/index.js +2 -7
- package/dist/solution/UnifiedBookingSales/index.d.ts +5 -4
- package/dist/solution/UnifiedBookingSales/index.js +495 -422
- package/dist/solution/UnifiedBookingSales/types.d.ts +7 -1
- package/dist/solution/VenueBooking/index.js +45 -55
- package/dist/utils/task.js +15 -18
- package/dist/utils/watch.js +0 -1
- package/lib/apis/picoding.js +2 -0
- package/lib/core/index.js +131 -131
- package/lib/effects/index.js +46 -57
- package/lib/index.js +82 -49
- package/lib/model/index.js +14 -21
- package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +209 -315
- package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
- package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
- package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
- package/lib/model/strategy/adapter/index.js +100 -64
- package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
- package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
- package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
- package/lib/model/strategy/adapter/itemRule/index.js +83 -57
- package/lib/model/strategy/adapter/itemRule/type.js +97 -36
- package/lib/model/strategy/adapter/promotion/adapter.js +91 -69
- package/lib/model/strategy/adapter/promotion/evaluator.js +444 -310
- package/lib/model/strategy/adapter/promotion/examples.js +222 -234
- package/lib/model/strategy/adapter/promotion/index.js +1 -51
- package/lib/model/strategy/adapter/promotion/type.js +243 -36
- package/lib/model/strategy/adapter/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -150
- package/lib/model/strategy/adapter/walletPass/example.js +217 -190
- package/lib/model/strategy/adapter/walletPass/index.js +75 -51
- package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
- package/lib/model/strategy/adapter/walletPass/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/utils.js +588 -378
- package/lib/model/strategy/engine.js +270 -168
- package/lib/model/strategy/index.js +49 -34
- package/lib/model/strategy/strategy-example.js +243 -239
- package/lib/model/strategy/type.js +100 -40
- package/lib/modules/Account/index.js +39 -53
- package/lib/modules/Account/types.js +20 -33
- package/lib/modules/AccountList/index.js +116 -154
- package/lib/modules/AccountList/types.js +30 -31
- package/lib/modules/AccountList/utils.js +18 -30
- package/lib/modules/BaseModule.js +23 -42
- package/lib/modules/BookingContext/index.js +158 -136
- package/lib/modules/BookingContext/types.js +46 -32
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +138 -146
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +78 -83
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +170 -150
- package/lib/modules/BookingContext/utils/flexible.js +38 -55
- package/lib/modules/BookingContext/utils/formatResourceList.js +19 -34
- package/lib/modules/BookingContext/utils/index.js +124 -41
- package/lib/modules/BookingContext/utils/noResource.js +58 -70
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +14 -41
- package/lib/modules/BookingContext/utils/productExtend.js +202 -155
- package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
- package/lib/modules/BookingContext/utils/resourceSelection.js +19 -41
- package/lib/modules/BookingContext/utils/resources.js +209 -167
- package/lib/modules/BookingContext/utils/serviceTimes.js +115 -116
- package/lib/modules/BookingContext/utils/timeSlices.js +76 -86
- package/lib/modules/Cart/index.js +170 -124
- package/lib/modules/Cart/types.js +46 -51
- package/lib/modules/Cart/utils/cartAccount.js +40 -39
- package/lib/modules/Cart/utils/cartDate.js +56 -61
- package/lib/modules/Cart/utils/cartDiscount.js +28 -33
- package/lib/modules/Cart/utils/cartNote.js +27 -32
- package/lib/modules/Cart/utils/cartProduct.js +321 -251
- package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
- package/lib/modules/Cart/utils/cartResource.js +70 -78
- package/lib/modules/Cart/utils/changePrice.js +22 -50
- package/lib/modules/Cart/utils/index.js +106 -48
- package/lib/modules/Customer/constants.js +13 -34
- package/lib/modules/Customer/index.js +235 -172
- package/lib/modules/Customer/types.js +38 -35
- package/lib/modules/Date/index.js +116 -115
- package/lib/modules/Date/types.js +16 -28
- package/lib/modules/Date/utils.js +174 -123
- package/lib/modules/Discount/index.js +133 -143
- package/lib/modules/Discount/types.js +9 -31
- package/lib/modules/Guests/index.js +30 -56
- package/lib/modules/Guests/types.js +23 -33
- package/lib/modules/Holder/index.js +209 -189
- package/lib/modules/Holder/types.js +4 -16
- package/lib/modules/Holder/utils.js +20 -49
- package/lib/modules/OpenData/index.d.ts +5 -2
- package/lib/modules/OpenData/index.js +119 -78
- package/lib/modules/OpenData/types.d.ts +42 -0
- package/lib/modules/OpenData/types.js +12 -16
- package/lib/modules/OpenData/utils.d.ts +15 -1
- package/lib/modules/OpenData/utils.js +129 -78
- package/lib/modules/Order/index.d.ts +4 -2
- package/lib/modules/Order/index.js +1843 -2251
- package/lib/modules/Order/payment-utils.js +77 -120
- package/lib/modules/Order/types.d.ts +8 -1
- package/lib/modules/Order/types.js +88 -35
- package/lib/modules/Order/utils/bundleDiscountHydration.js +41 -74
- package/lib/modules/Order/utils/discountProductLineIdentity.js +142 -100
- package/lib/modules/Order/utils/manualProductDiscount.js +124 -123
- package/lib/modules/Order/utils/orderCollectionIdentity.js +184 -244
- package/lib/modules/Order/utils/virtualSettlement.js +120 -171
- package/lib/modules/Order/utils.js +834 -668
- package/lib/modules/Payment/cash.js +20 -33
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
- package/lib/modules/Payment/eftpos.js +16 -30
- package/lib/modules/Payment/index.js +532 -399
- package/lib/modules/Payment/mx51.js +1 -0
- package/lib/modules/Payment/types.js +230 -108
- package/lib/modules/Payment/utils.js +52 -51
- package/lib/modules/Payment/walletpass.js +485 -660
- package/lib/modules/Product/index.js +51 -46
- package/lib/modules/Product/types.d.ts +2 -0
- package/lib/modules/Product/types.js +4 -16
- package/lib/modules/Product/utils.js +32 -33
- package/lib/modules/ProductList/index.js +141 -161
- package/lib/modules/ProductList/types.js +9 -31
- package/lib/modules/Quotation/index.js +66 -100
- package/lib/modules/Quotation/types.js +4 -16
- package/lib/modules/Resource/index.js +27 -59
- package/lib/modules/Resource/types.js +22 -32
- package/lib/modules/Resource/utils.js +30 -38
- package/lib/modules/ResourcePlanner/index.js +25 -23
- package/lib/modules/ResourcePlanner/localClock.js +54 -119
- package/lib/modules/ResourcePlanner/planner.js +591 -772
- package/lib/modules/ResourcePlanner/types.js +10 -29
- package/lib/modules/Rules/index.js +1224 -963
- package/lib/modules/Rules/types.js +17 -40
- package/lib/modules/SalesSummary/index.js +80 -89
- package/lib/modules/SalesSummary/types.js +4 -16
- package/lib/modules/SalesSummary/utils.js +359 -442
- package/lib/modules/ScanOrderLogger/index.js +59 -79
- package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
- package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
- package/lib/modules/ScanOrderLogger/types.js +4 -16
- package/lib/modules/Schedule/getDateIsInSchedule.js +334 -163
- package/lib/modules/Schedule/index.js +100 -114
- package/lib/modules/Schedule/type.js +4 -16
- package/lib/modules/Schedule/types.js +4 -16
- package/lib/modules/Schedule/utils.js +433 -291
- package/lib/modules/Step/index.js +40 -52
- package/lib/modules/Step/tyeps.js +4 -16
- package/lib/modules/Summary/index.js +66 -71
- package/lib/modules/Summary/types.js +4 -16
- package/lib/modules/Summary/utils.js +773 -418
- package/lib/modules/SurchargeList/index.js +46 -60
- package/lib/modules/SurchargeList/types.js +4 -16
- package/lib/modules/index.js +245 -63
- package/lib/plugins/app.js +4 -16
- package/lib/plugins/index.js +36 -25
- package/lib/plugins/request.js +137 -126
- package/lib/plugins/shopStore.js +4 -16
- package/lib/plugins/user.js +4 -16
- package/lib/plugins/window.js +171 -179
- package/lib/server/index.d.ts +11 -0
- package/lib/server/index.js +3432 -2757
- package/lib/server/modules/floor-plan/index.js +102 -123
- package/lib/server/modules/floor-plan/types.js +15 -30
- package/lib/server/modules/index.js +106 -68
- package/lib/server/modules/menu/index.js +146 -122
- package/lib/server/modules/menu/types.js +18 -31
- package/lib/server/modules/order/index.d.ts +8 -0
- package/lib/server/modules/order/index.js +781 -956
- package/lib/server/modules/order/types.js +122 -33
- package/lib/server/modules/order/utils/filterBookings.js +219 -194
- package/lib/server/modules/order/utils/filterOrders.js +118 -92
- package/lib/server/modules/payment/index.js +59 -83
- package/lib/server/modules/payment/types.js +4 -16
- package/lib/server/modules/products/index.js +575 -459
- package/lib/server/modules/products/types.js +44 -34
- package/lib/server/modules/quotation/index.js +137 -172
- package/lib/server/modules/quotation/types.js +21 -31
- package/lib/server/modules/resource/index.js +213 -184
- package/lib/server/modules/resource/types.js +42 -33
- package/lib/server/modules/schedule/index.js +135 -123
- package/lib/server/modules/schedule/types.js +14 -21
- package/lib/server/modules/schedule/utils.js +334 -163
- package/lib/server/types.js +4 -16
- package/lib/server/utils/index.js +25 -23
- package/lib/server/utils/product.js +196 -139
- package/lib/server/utils/schedule.js +34 -41
- package/lib/server/utils/small-ticket.d.ts +9 -1
- package/lib/server/utils/small-ticket.js +565 -470
- package/lib/server/utils/time.js +40 -49
- package/lib/solution/BaseSales/index.d.ts +7 -0
- package/lib/solution/BaseSales/index.js +1385 -1503
- package/lib/solution/BaseSales/types.d.ts +2 -0
- package/lib/solution/BaseSales/types.js +42 -38
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +5 -0
- package/lib/solution/BaseSales/utils/cartPromotion.js +652 -498
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +85 -105
- package/lib/solution/BaseSales/utils/quotationPrice.js +56 -114
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +3 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +138 -180
- package/lib/solution/BaseSales/utils.js +161 -143
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/BookingByStep/index.js +1527 -1340
- package/lib/solution/BookingByStep/types.js +40 -99
- package/lib/solution/BookingByStep/utils/capacity.js +192 -160
- package/lib/solution/BookingByStep/utils/products.js +42 -52
- package/lib/solution/BookingByStep/utils/resources.js +527 -330
- package/lib/solution/BookingByStep/utils/stock.js +65 -44
- package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
- package/lib/solution/BookingTicket/index.d.ts +14 -19
- package/lib/solution/BookingTicket/index.js +663 -526
- package/lib/solution/BookingTicket/types.js +99 -77
- package/lib/solution/BookingTicket/utils/addProductDecision.js +229 -190
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +58 -89
- package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -78
- package/lib/solution/BookingTicket/utils/cartView.js +114 -99
- package/lib/solution/BookingTicket/utils/exampleData.js +185 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.js +18 -41
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +219 -86
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +168 -116
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +79 -91
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +54 -41
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +84 -81
- package/lib/solution/BookingTicket/utils/scan/index.js +98 -104
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +52 -64
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +56 -58
- package/lib/solution/BookingTicket/utils/weighingProductSku.js +34 -48
- package/lib/solution/BuyTickets/index.js +67 -70
- package/lib/solution/BuyTickets/types.js +22 -38
- package/lib/solution/Checkout/index.js +1451 -1158
- package/lib/solution/Checkout/types.js +91 -61
- package/lib/solution/Checkout/utils/index.js +228 -156
- package/lib/solution/PlaceOrder/index.js +55 -0
- package/lib/solution/RegisterAndLogin/config.js +493 -460
- package/lib/solution/RegisterAndLogin/index.js +633 -630
- package/lib/solution/RegisterAndLogin/types.js +189 -76
- package/lib/solution/RegisterAndLogin/utils.js +183 -125
- package/lib/solution/Sales/index.d.ts +20 -4
- package/lib/solution/Sales/index.js +502 -330
- package/lib/solution/Sales/types.d.ts +10 -0
- package/lib/solution/Sales/types.js +27 -33
- package/lib/solution/ScanOrder/index.js +822 -852
- package/lib/solution/ScanOrder/types.d.ts +2 -0
- package/lib/solution/ScanOrder/types.js +33 -34
- package/lib/solution/ScanOrder/utils.js +412 -374
- package/lib/solution/ShopDiscount/index.js +226 -232
- package/lib/solution/ShopDiscount/types.js +15 -37
- package/lib/solution/ShopDiscount/utils.js +300 -172
- package/lib/solution/UnifiedBookingSales/index.d.ts +5 -4
- package/lib/solution/UnifiedBookingSales/index.js +1087 -1222
- package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.js +99 -159
- package/lib/solution/UnifiedBookingSales/types.d.ts +7 -1
- package/lib/solution/UnifiedBookingSales/types.js +10 -32
- package/lib/solution/VenueBooking/index.js +811 -879
- package/lib/solution/VenueBooking/types.js +19 -39
- package/lib/solution/VenueBooking/utils/dateSummary.js +27 -56
- package/lib/solution/VenueBooking/utils/resource.js +31 -54
- package/lib/solution/VenueBooking/utils/slotMerge.js +94 -107
- package/lib/solution/VenueBooking/utils/timeSlot.js +132 -132
- package/lib/solution/VenueBooking/utils.js +130 -67
- package/lib/solution/index.js +124 -41
- package/lib/store/createStore.js +32 -29
- package/lib/types/index.js +4 -16
- package/lib/utils/payment-number.js +26 -46
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +81 -47
- package/package.json +2 -1
|
@@ -1,80 +1,69 @@
|
|
|
1
|
-
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
1
|
+
"use strict";
|
|
28
2
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
__export(order_exports, {
|
|
32
|
-
OrderModule: () => OrderModule
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
33
5
|
});
|
|
34
|
-
|
|
35
|
-
var
|
|
36
|
-
var
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
var
|
|
40
|
-
var
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
]);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
6
|
+
exports.OrderModule = void 0;
|
|
7
|
+
var _lodashEs = require("lodash-es");
|
|
8
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
9
|
+
var _BaseModule = require("../../../modules/BaseModule");
|
|
10
|
+
var _orderCollectionIdentity = require("../../../modules/Order/utils/orderCollectionIdentity");
|
|
11
|
+
var _types = require("./types");
|
|
12
|
+
var _paymentUtils = require("../../../modules/Order/payment-utils");
|
|
13
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
|
+
/**
|
|
15
|
+
* SQLite 存储名称
|
|
16
|
+
*/
|
|
17
|
+
const INDEXDB_STORE_NAME = 'orders';
|
|
18
|
+
const ORDER_STORAGE_KEY_FIELD = '__order_storage_key';
|
|
19
|
+
const ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = 'server_order_last_full_fetch_at';
|
|
20
|
+
const ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = 'order_sync_throttle_ms';
|
|
21
|
+
const DEFAULT_ORDER_SYNC_THROTTLE_MS = 2_000;
|
|
22
|
+
/** pubsub 回声写入去重窗口:业务 API 刚写入后,跳过同单 SQLite patch */
|
|
23
|
+
const ORDER_SQLITE_DEDUPE_MS = 15_000;
|
|
24
|
+
/** silentRefresh 最小间隔,避免 preload 后立即全量重拉 */
|
|
25
|
+
const ORDER_SILENT_REFRESH_MIN_INTERVAL_MS = 30_000;
|
|
26
|
+
/** 视为「业务侧刚写入」的来源,pubsub 回声可跳过 SQLite */
|
|
27
|
+
const ORDER_BUSINESS_WRITE_SOURCES = new Set(['upsertOrdersFromRemote', 'upsertPendingSyncOrders', 'upsertLocalDraftOrders', 'overwriteExistingOrder', 'markOrderSyncedByExternalSaleNumber', 'updateLocalPayment']);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 合并热路径全表去重自检开关:默认关闭。
|
|
31
|
+
* 开启后每次合并会额外对整张 store 做一次 O(n^2) 重复检测并告警,
|
|
32
|
+
* 仅用于排查增量身份索引是否遗漏了重复订单,不应在生产常开。
|
|
33
|
+
*/
|
|
34
|
+
const ORDER_MERGE_SELF_CHECK = false;
|
|
35
|
+
const PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER = '__pisell_os_pending_payment_without_unique_number__';
|
|
36
|
+
const ORDER_AUTHORITATIVE_COLLECTION_FIELDS = ['products', 'bookings', 'payments'];
|
|
37
|
+
const ORDER_COLLECTION_KIND_BY_FIELD = {
|
|
38
|
+
products: 'product',
|
|
39
|
+
bookings: 'booking',
|
|
40
|
+
payments: 'payment'
|
|
63
41
|
};
|
|
64
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Order 模块 - 基础框架
|
|
44
|
+
*/
|
|
45
|
+
class OrderModule extends _BaseModule.BaseModule {
|
|
46
|
+
defaultName = 'order';
|
|
47
|
+
defaultVersion = '1.0.0';
|
|
48
|
+
store;
|
|
49
|
+
dbManager;
|
|
50
|
+
orderDataSource;
|
|
51
|
+
pendingSyncMessages = [];
|
|
52
|
+
syncTimer;
|
|
53
|
+
isProcessingSyncBatch = false;
|
|
54
|
+
isIdlePhase = true;
|
|
55
|
+
logger; // LoggerManager 实例
|
|
56
|
+
storage;
|
|
57
|
+
orderSQLiteSaveQueue = Promise.resolve(); /** 按 storageKey 记录最近一次 SQLite 写入来源与时间,用于去重 */
|
|
58
|
+
recentSqliteWriteByStorageKey = new Map();
|
|
59
|
+
/** 最近一次清理过期 SQLite 去重记录的时间,避免每次写入都遍历 Map */
|
|
60
|
+
lastRecentSqliteWriteCleanupAtMs = 0;
|
|
61
|
+
/** 最近一次 SSE 全量拉取完成时间 */
|
|
62
|
+
lastServerFullFetchAtMs = 0;
|
|
65
63
|
constructor(name, version) {
|
|
66
64
|
super(name, version);
|
|
67
|
-
this.defaultName = "order";
|
|
68
|
-
this.defaultVersion = "1.0.0";
|
|
69
|
-
this.pendingSyncMessages = [];
|
|
70
|
-
this.isProcessingSyncBatch = false;
|
|
71
|
-
this.isIdlePhase = true;
|
|
72
|
-
this.orderSQLiteSaveQueue = Promise.resolve();
|
|
73
|
-
/** 按 storageKey 记录最近一次 SQLite 写入来源与时间,用于去重 */
|
|
74
|
-
this.recentSqliteWriteByStorageKey = /* @__PURE__ */ new Map();
|
|
75
|
-
/** 最近一次 SSE 全量拉取完成时间 */
|
|
76
|
-
this.lastServerFullFetchAtMs = 0;
|
|
77
65
|
}
|
|
66
|
+
|
|
78
67
|
/**
|
|
79
68
|
* 广播订单变更事件,兼容全量列表订阅并额外携带本次变更订单。
|
|
80
69
|
*
|
|
@@ -82,23 +71,23 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
82
71
|
* await this.emitOrdersChanged([freshOrder], 'pubsub.bodyUpsert')
|
|
83
72
|
*/
|
|
84
73
|
async emitOrdersChanged(changedOrders = [], source) {
|
|
85
|
-
console.log("触发emitOrdersChanged");
|
|
86
74
|
const payload = {
|
|
87
75
|
list: this.store.list,
|
|
88
|
-
changedOrders: changedOrders.map(
|
|
76
|
+
changedOrders: changedOrders.map(order => this.normalizeOrderForMemoryList(order)),
|
|
89
77
|
source
|
|
90
78
|
};
|
|
91
|
-
await this.core.effects.emit(
|
|
79
|
+
await this.core.effects.emit(_types.OrderHooks.onOrdersChanged, payload);
|
|
92
80
|
}
|
|
81
|
+
|
|
93
82
|
/**
|
|
94
83
|
* 广播远端商品成员增删。监听器异常必须与订单落库和原有订单广播隔离。
|
|
95
84
|
*/
|
|
96
85
|
async emitRemoteProductMembershipChanges(changes) {
|
|
97
86
|
for (const payload of changes) {
|
|
98
87
|
try {
|
|
99
|
-
await this.core.effects.emit(
|
|
88
|
+
await this.core.effects.emit(_types.OrderHooks.onRemoteProductMembershipChanged, payload);
|
|
100
89
|
} catch (error) {
|
|
101
|
-
this.logError(
|
|
90
|
+
this.logError('广播远端订单商品成员变更失败', {
|
|
102
91
|
order_id: payload.order_id,
|
|
103
92
|
source: payload.source,
|
|
104
93
|
added_product_count: payload.added_product_keys.length,
|
|
@@ -109,38 +98,34 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
109
98
|
}
|
|
110
99
|
}
|
|
111
100
|
async initialize(core, options) {
|
|
112
|
-
var _a;
|
|
113
101
|
this.core = core;
|
|
114
|
-
this.store = options
|
|
115
|
-
if (!this.store.map)
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
const app = appPlugin == null ? void 0 : appPlugin.getApp();
|
|
102
|
+
this.store = options?.store;
|
|
103
|
+
if (!this.store.map) this.store.map = new Map();
|
|
104
|
+
const appPlugin = core.getPlugin('app');
|
|
105
|
+
const app = appPlugin?.getApp();
|
|
119
106
|
if (app) {
|
|
120
107
|
this.dbManager = app.sqlite;
|
|
121
108
|
this.logger = app.logger;
|
|
122
109
|
this.storage = app.storage;
|
|
123
110
|
this.updateCreateStore();
|
|
124
111
|
}
|
|
125
|
-
if (Array.isArray(
|
|
126
|
-
this.store.list = this.normalizeOrdersForMemoryList(
|
|
127
|
-
options.initialState.list,
|
|
128
|
-
"initialState"
|
|
129
|
-
);
|
|
112
|
+
if (Array.isArray(options?.initialState?.list)) {
|
|
113
|
+
this.store.list = this.normalizeOrdersForMemoryList(options.initialState.list, 'initialState');
|
|
130
114
|
this.syncOrdersMap();
|
|
131
|
-
this.emitOrdersChanged([],
|
|
115
|
+
this.emitOrdersChanged([], 'initialState');
|
|
132
116
|
} else {
|
|
133
117
|
this.store.list = [];
|
|
134
|
-
this.store.map =
|
|
118
|
+
this.store.map = new Map();
|
|
135
119
|
}
|
|
136
120
|
this.initOrderDataSource();
|
|
137
121
|
this.setupOrderSync();
|
|
138
|
-
this.logInfo(
|
|
122
|
+
this.logInfo('OrderServer模块初始化完成', {
|
|
139
123
|
hasDbManager: !!this.dbManager,
|
|
140
124
|
hasLogger: !!this.logger,
|
|
141
125
|
initialOrderCount: this.store.list.length
|
|
142
126
|
});
|
|
143
127
|
}
|
|
128
|
+
|
|
144
129
|
/**
|
|
145
130
|
* 记录信息日志
|
|
146
131
|
* @param title 日志标题
|
|
@@ -150,14 +135,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
150
135
|
try {
|
|
151
136
|
if (this.logger) {
|
|
152
137
|
this.logger.addLog({
|
|
153
|
-
type:
|
|
138
|
+
type: 'info',
|
|
154
139
|
title: `[OrderServerModule] ${title}`,
|
|
155
140
|
metadata: metadata || {}
|
|
156
141
|
});
|
|
157
142
|
}
|
|
158
143
|
} catch {
|
|
144
|
+
// 日志记录失败不影响主流程
|
|
159
145
|
}
|
|
160
146
|
}
|
|
147
|
+
|
|
161
148
|
/**
|
|
162
149
|
* 记录错误日志
|
|
163
150
|
* @param title 日志标题
|
|
@@ -167,36 +154,39 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
167
154
|
try {
|
|
168
155
|
if (this.logger) {
|
|
169
156
|
this.logger.addLog({
|
|
170
|
-
type:
|
|
157
|
+
type: 'error',
|
|
171
158
|
title: `[OrderServerModule] ${title}`,
|
|
172
159
|
metadata: metadata || {}
|
|
173
160
|
});
|
|
174
161
|
}
|
|
175
162
|
} catch {
|
|
163
|
+
// 日志记录失败不影响主流程
|
|
176
164
|
}
|
|
177
165
|
}
|
|
178
166
|
logWarning(title, metadata) {
|
|
179
167
|
try {
|
|
180
168
|
if (this.logger) {
|
|
181
169
|
this.logger.addLog({
|
|
182
|
-
type:
|
|
170
|
+
type: 'warning',
|
|
183
171
|
title: `[OrderServerModule] ${title}`,
|
|
184
172
|
metadata: metadata || {}
|
|
185
173
|
});
|
|
186
174
|
}
|
|
187
175
|
} catch {
|
|
176
|
+
// 日志记录失败不影响主流程
|
|
188
177
|
}
|
|
189
178
|
}
|
|
179
|
+
|
|
190
180
|
/**
|
|
191
181
|
* 在订单进入内存或 SQLite 前统一压缩子项强身份重复并补齐协议 UID。
|
|
192
182
|
* 仅记录计数与订单标识,不输出商品、预约、支付或客户明细。
|
|
193
183
|
*/
|
|
194
184
|
normalizeOrderCollectionsForIngress(order, source) {
|
|
195
|
-
const sourceOrder = (0,
|
|
185
|
+
const sourceOrder = (0, _lodashEs.cloneDeep)(order);
|
|
196
186
|
const sourceOrderRecord = sourceOrder;
|
|
197
187
|
if (Array.isArray(sourceOrderRecord.payments)) {
|
|
198
|
-
sourceOrderRecord.payments = sourceOrderRecord.payments.map(
|
|
199
|
-
if (!(0,
|
|
188
|
+
sourceOrderRecord.payments = sourceOrderRecord.payments.map(payment => {
|
|
189
|
+
if (!(0, _paymentUtils.isPendingOrderPayment)(payment) || (0, _paymentUtils.getOrderPaymentIdentityKeys)(payment).some(key => key.startsWith('unique_payment_number:'))) {
|
|
200
190
|
return payment;
|
|
201
191
|
}
|
|
202
192
|
return {
|
|
@@ -205,29 +195,30 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
205
195
|
};
|
|
206
196
|
});
|
|
207
197
|
}
|
|
208
|
-
const result = (0,
|
|
198
|
+
const result = (0, _orderCollectionIdentity.normalizeOrderCollections)(sourceOrder);
|
|
209
199
|
const normalizedOrderRecord = result.order;
|
|
210
200
|
if (Array.isArray(normalizedOrderRecord.payments)) {
|
|
211
|
-
normalizedOrderRecord.payments = normalizedOrderRecord.payments.map(
|
|
212
|
-
(payment)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
201
|
+
normalizedOrderRecord.payments = normalizedOrderRecord.payments.map(payment => {
|
|
202
|
+
if (!payment?.[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER]) return payment;
|
|
203
|
+
const nextPayment = {
|
|
204
|
+
...payment
|
|
205
|
+
};
|
|
206
|
+
const metadata = {
|
|
207
|
+
...(nextPayment.metadata || {})
|
|
208
|
+
};
|
|
209
|
+
delete metadata.unique_payment_number;
|
|
210
|
+
delete nextPayment[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER];
|
|
211
|
+
nextPayment.metadata = metadata;
|
|
212
|
+
return nextPayment;
|
|
213
|
+
});
|
|
223
214
|
}
|
|
224
|
-
const kinds = [
|
|
225
|
-
const hasChanges = kinds.some(
|
|
215
|
+
const kinds = ['product', 'booking', 'payment'];
|
|
216
|
+
const hasChanges = kinds.some(kind => {
|
|
226
217
|
const stats = result.stats[kind];
|
|
227
218
|
return stats.backfilledUidCount > 0 || stats.collapsedDuplicateCount > 0 || stats.uidConflictCount > 0 || stats.anonymousRowCount > 0;
|
|
228
219
|
});
|
|
229
220
|
if (hasChanges) {
|
|
230
|
-
const summarize =
|
|
221
|
+
const summarize = stats => ({
|
|
231
222
|
backfilled_uid_count: stats.backfilledUidCount,
|
|
232
223
|
collapsed_duplicate_count: stats.collapsedDuplicateCount,
|
|
233
224
|
uid_conflict_count: stats.uidConflictCount,
|
|
@@ -235,57 +226,49 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
235
226
|
});
|
|
236
227
|
const context = {
|
|
237
228
|
source,
|
|
238
|
-
order_id:
|
|
239
|
-
external_sale_number:
|
|
229
|
+
order_id: order?.order_id ?? null,
|
|
230
|
+
external_sale_number: order?.external_sale_number ?? null,
|
|
240
231
|
products: summarize(result.stats.product),
|
|
241
232
|
bookings: summarize(result.stats.booking),
|
|
242
233
|
payments: summarize(result.stats.payment)
|
|
243
234
|
};
|
|
244
|
-
const hasUnsafeIdentity = kinds.some(
|
|
235
|
+
const hasUnsafeIdentity = kinds.some(kind => {
|
|
245
236
|
const stats = result.stats[kind];
|
|
246
237
|
return stats.uidConflictCount > 0 || stats.anonymousRowCount > 0;
|
|
247
238
|
});
|
|
248
239
|
if (hasUnsafeIdentity) {
|
|
249
|
-
this.logWarning(
|
|
240
|
+
this.logWarning('订单子项身份存在冲突或匿名行', context);
|
|
250
241
|
} else {
|
|
251
|
-
this.logInfo(
|
|
242
|
+
this.logInfo('订单子项身份已规范化', context);
|
|
252
243
|
}
|
|
253
244
|
}
|
|
254
245
|
return result.order;
|
|
255
246
|
}
|
|
247
|
+
|
|
256
248
|
/**
|
|
257
249
|
* incoming 决定权威成员集合;同一持久化行仍从 existing 补齐 incoming 省略的本地展示字段。
|
|
258
250
|
*/
|
|
259
251
|
mergeAuthoritativeOrderCollection(field, existing, incoming, uidRemaps = [], options = {}) {
|
|
260
252
|
const kind = ORDER_COLLECTION_KIND_BY_FIELD[field];
|
|
261
253
|
const existingItems = Array.isArray(existing) ? existing : [];
|
|
262
|
-
if (field ===
|
|
263
|
-
return (0,
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
);
|
|
273
|
-
if (!existingItem)
|
|
274
|
-
return (0, import_lodash_es.cloneDeep)(incomingItem);
|
|
275
|
-
const mergedItem = (0, import_orderCollectionIdentity.mergeOrderCollectionItems)(kind, existingItem, incomingItem);
|
|
276
|
-
const mergedUid = (0, import_orderCollectionIdentity.getOrderCollectionUid)(kind, mergedItem);
|
|
254
|
+
if (field === 'payments' && options.preserveIdentifiedPendingPayments) {
|
|
255
|
+
return (0, _paymentUtils.mergeOrderPaymentListsByIdentity)(existingItems, incoming, {
|
|
256
|
+
preserveUnmatchedExistingWhen: _paymentUtils.isIdentifiedPendingOrderPayment
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
return incoming.map(incomingItem => {
|
|
260
|
+
const existingItem = existingItems.find(item => (0, _orderCollectionIdentity.isSameOrderCollectionItem)(kind, item, incomingItem));
|
|
261
|
+
if (!existingItem) return (0, _lodashEs.cloneDeep)(incomingItem);
|
|
262
|
+
const mergedItem = (0, _orderCollectionIdentity.mergeOrderCollectionItems)(kind, existingItem, incomingItem);
|
|
263
|
+
const mergedUid = (0, _orderCollectionIdentity.getOrderCollectionUid)(kind, mergedItem);
|
|
277
264
|
if (mergedUid) {
|
|
278
|
-
for (const from of
|
|
279
|
-
(
|
|
280
|
-
(0, import_orderCollectionIdentity.getOrderCollectionReferenceUid)(kind, incomingItem)
|
|
281
|
-
])) {
|
|
282
|
-
if (!from || from === mergedUid)
|
|
283
|
-
continue;
|
|
265
|
+
for (const from of new Set([(0, _orderCollectionIdentity.getOrderCollectionReferenceUid)(kind, existingItem), (0, _orderCollectionIdentity.getOrderCollectionReferenceUid)(kind, incomingItem)])) {
|
|
266
|
+
if (!from || from === mergedUid) continue;
|
|
284
267
|
uidRemaps.push({
|
|
285
268
|
kind,
|
|
286
269
|
from,
|
|
287
270
|
to: mergedUid,
|
|
288
|
-
persistentId: (0,
|
|
271
|
+
persistentId: (0, _orderCollectionIdentity.getOrderCollectionPersistentId)(kind, incomingItem) || (0, _orderCollectionIdentity.getOrderCollectionPersistentId)(kind, existingItem)
|
|
289
272
|
});
|
|
290
273
|
}
|
|
291
274
|
}
|
|
@@ -293,25 +276,35 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
293
276
|
});
|
|
294
277
|
}
|
|
295
278
|
reconcileOverwriteOrderCollections(existing, incoming) {
|
|
296
|
-
const reconciled = (0,
|
|
279
|
+
const reconciled = (0, _lodashEs.cloneDeep)(incoming);
|
|
297
280
|
const existingRecord = existing;
|
|
298
281
|
const incomingRecord = incoming;
|
|
299
282
|
const uidRemaps = [];
|
|
300
283
|
for (const field of ORDER_AUTHORITATIVE_COLLECTION_FIELDS) {
|
|
301
|
-
if (!Array.isArray(incomingRecord[field]))
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
existingRecord[field],
|
|
306
|
-
incomingRecord[field],
|
|
307
|
-
uidRemaps
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
return this.normalizeOrderCollectionsForIngress(
|
|
311
|
-
(0, import_orderCollectionIdentity.applyOrderCollectionUidRemaps)(reconciled, uidRemaps),
|
|
312
|
-
"overwriteExistingOrder.reconciled"
|
|
313
|
-
);
|
|
284
|
+
if (!Array.isArray(incomingRecord[field])) continue;
|
|
285
|
+
reconciled[field] = this.mergeAuthoritativeOrderCollection(field, existingRecord[field], incomingRecord[field], uidRemaps);
|
|
286
|
+
}
|
|
287
|
+
return this.normalizeOrderCollectionsForIngress((0, _orderCollectionIdentity.applyOrderCollectionUidRemaps)(reconciled, uidRemaps), 'overwriteExistingOrder.reconciled');
|
|
314
288
|
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* 惰性清理已经超过去重窗口的 SQLite 写入记录。
|
|
292
|
+
*
|
|
293
|
+
* 清理频率与去重窗口一致,既限制 Map 长期增长,也不会移除仍参与去重的记录。
|
|
294
|
+
*/
|
|
295
|
+
cleanupExpiredRecentSqliteWrites(now) {
|
|
296
|
+
const elapsedSinceCleanup = now - this.lastRecentSqliteWriteCleanupAtMs;
|
|
297
|
+
if (this.lastRecentSqliteWriteCleanupAtMs > 0 && elapsedSinceCleanup >= 0 && elapsedSinceCleanup < ORDER_SQLITE_DEDUPE_MS) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
for (const [storageKey, recentWrite] of this.recentSqliteWriteByStorageKey) {
|
|
301
|
+
if (now - recentWrite.ts >= ORDER_SQLITE_DEDUPE_MS) {
|
|
302
|
+
this.recentSqliteWriteByStorageKey.delete(storageKey);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
this.lastRecentSqliteWriteCleanupAtMs = now;
|
|
306
|
+
}
|
|
307
|
+
|
|
315
308
|
/**
|
|
316
309
|
* 记录订单最近一次 SQLite 写入,供 pubsub 回声去重使用。
|
|
317
310
|
*
|
|
@@ -320,23 +313,30 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
320
313
|
*/
|
|
321
314
|
recordRecentSqliteWrite(source, orders) {
|
|
322
315
|
const now = Date.now();
|
|
316
|
+
this.cleanupExpiredRecentSqliteWrites(now);
|
|
323
317
|
for (const order of orders) {
|
|
324
318
|
const storageKey = this.getOrderStorageKey(order);
|
|
325
|
-
if (!storageKey)
|
|
326
|
-
|
|
327
|
-
|
|
319
|
+
if (!storageKey) continue;
|
|
320
|
+
this.recentSqliteWriteByStorageKey.set(storageKey, {
|
|
321
|
+
source,
|
|
322
|
+
ts: now
|
|
323
|
+
});
|
|
328
324
|
}
|
|
329
325
|
}
|
|
326
|
+
|
|
330
327
|
/**
|
|
331
328
|
* 过滤 pubsub 触发的冗余 SQLite patch(业务 API 刚写入过的 update 回声)。
|
|
332
329
|
*
|
|
333
330
|
* @example
|
|
334
331
|
* const { toWrite, skipped } = this.filterRedundantPatchOrders('pubsub.bodyUpsert', orders, mergeActions)
|
|
335
332
|
*/
|
|
336
|
-
filterRedundantPatchOrders(source, orders, mergeActions, forceWriteStorageKeys =
|
|
337
|
-
const eligibleSkipSources =
|
|
333
|
+
filterRedundantPatchOrders(source, orders, mergeActions, forceWriteStorageKeys = new Set()) {
|
|
334
|
+
const eligibleSkipSources = new Set(['pubsub.bodyUpsert', 'pubsub.httpRefresh']);
|
|
338
335
|
if (!eligibleSkipSources.has(source)) {
|
|
339
|
-
return {
|
|
336
|
+
return {
|
|
337
|
+
toWrite: orders,
|
|
338
|
+
skipped: []
|
|
339
|
+
};
|
|
340
340
|
}
|
|
341
341
|
const now = Date.now();
|
|
342
342
|
const toWrite = [];
|
|
@@ -347,12 +347,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
347
347
|
toWrite.push(order);
|
|
348
348
|
continue;
|
|
349
349
|
}
|
|
350
|
-
const orderKey = order.order_id !==
|
|
351
|
-
const mergeAction = orderKey ? mergeActions[orderKey] :
|
|
352
|
-
|
|
350
|
+
const orderKey = order.order_id !== undefined && order.order_id !== null ? this.getIdKey(order.order_id) : '';
|
|
351
|
+
const mergeAction = orderKey ? mergeActions[orderKey] : undefined;
|
|
352
|
+
|
|
353
|
+
// 新增单必须落库,不参与去重
|
|
354
|
+
if (mergeAction === 'insert') {
|
|
353
355
|
toWrite.push(order);
|
|
354
356
|
continue;
|
|
355
357
|
}
|
|
358
|
+
|
|
359
|
+
// 远端商品成员确实发生增删时必须落库,避免内存已更新但 SQLite 仍被回声窗口跳过。
|
|
356
360
|
if (forceWriteStorageKeys.has(storageKey)) {
|
|
357
361
|
toWrite.push(order);
|
|
358
362
|
continue;
|
|
@@ -362,7 +366,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
362
366
|
skipped.push({
|
|
363
367
|
orderId: order.order_id ?? null,
|
|
364
368
|
storageKey,
|
|
365
|
-
reason:
|
|
369
|
+
reason: 'skip_pubsub_echo_after_business_write',
|
|
366
370
|
lastSource: recent.source,
|
|
367
371
|
elapsedMs: now - recent.ts
|
|
368
372
|
});
|
|
@@ -370,8 +374,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
370
374
|
}
|
|
371
375
|
toWrite.push(order);
|
|
372
376
|
}
|
|
373
|
-
return {
|
|
377
|
+
return {
|
|
378
|
+
toWrite,
|
|
379
|
+
skipped
|
|
380
|
+
};
|
|
374
381
|
}
|
|
382
|
+
|
|
375
383
|
/**
|
|
376
384
|
* 过滤 pubsub HTTP 增量拉取 ids:本地刚由业务 API 写入的单可跳过 HTTP。
|
|
377
385
|
*
|
|
@@ -389,8 +397,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
389
397
|
continue;
|
|
390
398
|
}
|
|
391
399
|
const storageKey = this.getOrderStorageKey(existing);
|
|
392
|
-
const recent = storageKey ? this.recentSqliteWriteByStorageKey.get(storageKey) :
|
|
393
|
-
if (recent && recent.source ===
|
|
400
|
+
const recent = storageKey ? this.recentSqliteWriteByStorageKey.get(storageKey) : undefined;
|
|
401
|
+
if (recent && recent.source === 'upsertOrdersFromRemote' && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
|
|
394
402
|
skipped.push({
|
|
395
403
|
orderId: id,
|
|
396
404
|
lastSource: recent.source,
|
|
@@ -400,8 +408,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
400
408
|
}
|
|
401
409
|
toFetch.push(id);
|
|
402
410
|
}
|
|
403
|
-
return {
|
|
411
|
+
return {
|
|
412
|
+
toFetch,
|
|
413
|
+
skipped
|
|
414
|
+
};
|
|
404
415
|
}
|
|
416
|
+
|
|
405
417
|
/**
|
|
406
418
|
* 解析 pubsub 消息会走哪条同步分支,便于对照为何触发 HTTP 重拉或 body 直写。
|
|
407
419
|
*
|
|
@@ -410,25 +422,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
410
422
|
* // => { route: 'httpRefresh.batchIds', ... }
|
|
411
423
|
*/
|
|
412
424
|
resolveSyncMessageRoute(msg) {
|
|
413
|
-
var _a;
|
|
414
425
|
const hasBatchIds = Array.isArray(msg.ids) && msg.ids.length > 0;
|
|
415
426
|
const singleIdRaw = msg.id ?? msg.order_id;
|
|
416
|
-
const hasSingleId = !hasBatchIds && singleIdRaw !==
|
|
427
|
+
const hasSingleId = !hasBatchIds && singleIdRaw !== undefined && singleIdRaw !== null;
|
|
417
428
|
const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
|
|
418
429
|
if (hasBatchIds) {
|
|
419
430
|
return {
|
|
420
|
-
route:
|
|
431
|
+
route: 'httpRefresh.batchIds',
|
|
421
432
|
hasBatchIds: true,
|
|
422
433
|
hasSingleId: false,
|
|
423
434
|
hasNormalizedBody: !!normalizedBody,
|
|
424
435
|
singleId: null,
|
|
425
436
|
batchIds: msg.ids || [],
|
|
426
|
-
bodyOrderId:
|
|
437
|
+
bodyOrderId: normalizedBody?.order_id ?? null
|
|
427
438
|
};
|
|
428
439
|
}
|
|
429
440
|
if (hasSingleId && normalizedBody) {
|
|
430
441
|
return {
|
|
431
|
-
route:
|
|
442
|
+
route: 'bodyUpsert',
|
|
432
443
|
hasBatchIds: false,
|
|
433
444
|
hasSingleId: true,
|
|
434
445
|
hasNormalizedBody: true,
|
|
@@ -439,77 +450,70 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
439
450
|
}
|
|
440
451
|
if (hasSingleId) {
|
|
441
452
|
return {
|
|
442
|
-
route:
|
|
453
|
+
route: 'httpRefresh.singleId',
|
|
443
454
|
hasBatchIds: false,
|
|
444
455
|
hasSingleId: true,
|
|
445
456
|
hasNormalizedBody: !!normalizedBody,
|
|
446
457
|
singleId: singleIdRaw,
|
|
447
458
|
batchIds: [],
|
|
448
|
-
bodyOrderId:
|
|
459
|
+
bodyOrderId: normalizedBody?.order_id ?? null
|
|
449
460
|
};
|
|
450
461
|
}
|
|
451
|
-
if (
|
|
462
|
+
if (msg.relation_order_ids?.length) {
|
|
452
463
|
return {
|
|
453
|
-
route:
|
|
464
|
+
route: 'httpRefresh.relationIds',
|
|
454
465
|
hasBatchIds: false,
|
|
455
466
|
hasSingleId: false,
|
|
456
467
|
hasNormalizedBody: !!normalizedBody,
|
|
457
468
|
singleId: null,
|
|
458
469
|
batchIds: msg.relation_order_ids,
|
|
459
|
-
bodyOrderId:
|
|
470
|
+
bodyOrderId: normalizedBody?.order_id ?? null
|
|
460
471
|
};
|
|
461
472
|
}
|
|
462
473
|
return {
|
|
463
|
-
route:
|
|
474
|
+
route: 'noop',
|
|
464
475
|
hasBatchIds: false,
|
|
465
476
|
hasSingleId: false,
|
|
466
477
|
hasNormalizedBody: !!normalizedBody,
|
|
467
478
|
singleId: null,
|
|
468
479
|
batchIds: [],
|
|
469
|
-
bodyOrderId:
|
|
480
|
+
bodyOrderId: normalizedBody?.order_id ?? null
|
|
470
481
|
};
|
|
471
482
|
}
|
|
472
483
|
updateCreateStore() {
|
|
473
|
-
const appPlugin = this.core.getPlugin(
|
|
474
|
-
const app = appPlugin
|
|
484
|
+
const appPlugin = this.core.getPlugin('app');
|
|
485
|
+
const app = appPlugin?.getApp();
|
|
475
486
|
if (app) {
|
|
476
|
-
const coreData = app.data.store.getStore().getDataByModel(
|
|
477
|
-
if (coreData
|
|
478
|
-
const today = (0,
|
|
479
|
-
if (coreData
|
|
487
|
+
const coreData = app.data.store.getStore().getDataByModel('core');
|
|
488
|
+
if (coreData?.core) {
|
|
489
|
+
const today = (0, _dayjs.default)();
|
|
490
|
+
if (coreData?.core.operating_day_boundary) {
|
|
480
491
|
const operatingDayBoundary = coreData.core.operating_day_boundary;
|
|
481
|
-
if (operatingDayBoundary.type ===
|
|
482
|
-
const boundaryTime = String(operatingDayBoundary.time ||
|
|
483
|
-
const boundaryStart = (0,
|
|
492
|
+
if (operatingDayBoundary.type === 'start_time') {
|
|
493
|
+
const boundaryTime = String(operatingDayBoundary.time || '').trim();
|
|
494
|
+
const boundaryStart = (0, _dayjs.default)(`${today.format('YYYY-MM-DD')} ${boundaryTime}`);
|
|
484
495
|
if (boundaryStart.isValid()) {
|
|
485
496
|
const isAfterBoundary = today.isAfter(boundaryStart);
|
|
486
|
-
const queryStart = isAfterBoundary ? today.startOf(
|
|
487
|
-
const queryEnd = isAfterBoundary ? today.add(1,
|
|
497
|
+
const queryStart = isAfterBoundary ? today.startOf('day') : today.subtract(1, 'day').startOf('day');
|
|
498
|
+
const queryEnd = isAfterBoundary ? today.add(1, 'day').endOf('day') : today.endOf('day');
|
|
488
499
|
this.store.createdAtQuery = {
|
|
489
|
-
sales_time_between: [
|
|
490
|
-
queryStart.format("YYYY-MM-DD HH:mm:ss"),
|
|
491
|
-
queryEnd.format("YYYY-MM-DD HH:mm:ss")
|
|
492
|
-
]
|
|
500
|
+
sales_time_between: [queryStart.format('YYYY-MM-DD HH:mm:ss'), queryEnd.format('YYYY-MM-DD HH:mm:ss')]
|
|
493
501
|
};
|
|
494
502
|
} else {
|
|
503
|
+
// 边界时间异常时回退到自然日,避免 createdAtQuery 为空导致后续查询异常
|
|
495
504
|
this.store.createdAtQuery = {
|
|
496
|
-
sales_time_between: [
|
|
497
|
-
today.startOf("day").format("YYYY-MM-DD HH:mm:ss"),
|
|
498
|
-
today.endOf("day").format("YYYY-MM-DD HH:mm:ss")
|
|
499
|
-
]
|
|
505
|
+
sales_time_between: [today.startOf('day').format('YYYY-MM-DD HH:mm:ss'), today.endOf('day').format('YYYY-MM-DD HH:mm:ss')]
|
|
500
506
|
};
|
|
501
507
|
}
|
|
502
508
|
} else {
|
|
503
509
|
this.store.createdAtQuery = {
|
|
504
|
-
sales_time_between: [
|
|
505
|
-
today.startOf("day").format("YYYY-MM-DD HH:mm:ss"),
|
|
506
|
-
today.endOf("day").format("YYYY-MM-DD HH:mm:ss")
|
|
507
|
-
]
|
|
510
|
+
sales_time_between: [today.startOf('day').format('YYYY-MM-DD HH:mm:ss'), today.endOf('day').format('YYYY-MM-DD HH:mm:ss')]
|
|
508
511
|
};
|
|
509
512
|
}
|
|
510
513
|
} else {
|
|
514
|
+
// TODO: 这里后续可能需要使用店铺营业时间查询
|
|
511
515
|
this.store.createdAtQuery = {
|
|
512
|
-
sales_time_between: [today.startOf(
|
|
516
|
+
sales_time_between: [today.startOf('day').format('YYYY-MM-DD HH:mm:ss'), today.endOf('day').format('YYYY-MM-DD HH:mm:ss')]
|
|
513
517
|
};
|
|
514
518
|
}
|
|
515
519
|
}
|
|
@@ -519,17 +523,32 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
519
523
|
const raw = localStorage.getItem(ORDER_SYNC_THROTTLE_MS_STORAGE_KEY);
|
|
520
524
|
if (raw !== null) {
|
|
521
525
|
const parsed = Number(raw);
|
|
522
|
-
if (Number.isFinite(parsed) && parsed >= 0)
|
|
523
|
-
return parsed;
|
|
526
|
+
if (Number.isFinite(parsed) && parsed >= 0) return parsed;
|
|
524
527
|
}
|
|
525
528
|
return DEFAULT_ORDER_SYNC_THROTTLE_MS;
|
|
526
529
|
}
|
|
527
530
|
async preload() {
|
|
531
|
+
// const hasPulledInCurrentWindow = this.hasPulledOrdersToday()
|
|
532
|
+
// // 仅当缓存属于当前统计窗口时才直接复用,避免跨天/跨营业日窗口继续使用旧数据
|
|
533
|
+
// if (cachedOrders.length > 0 && hasPulledInCurrentWindow) {
|
|
534
|
+
// this.store.list = cloneDeep(cachedOrders)
|
|
535
|
+
// this.syncOrdersMap()
|
|
536
|
+
// this.core.effects.emit(OrderHooks.onOrdersChanged, this.store.list)
|
|
537
|
+
// return
|
|
538
|
+
// }
|
|
539
|
+
|
|
540
|
+
// if (hasPulledInCurrentWindow) {
|
|
541
|
+
// this.logInfo('当天已完成全量订单拉取,跳过本次全量拉取', {
|
|
542
|
+
// lastFullFetchAt: this.getStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY),
|
|
543
|
+
// })
|
|
544
|
+
// return
|
|
545
|
+
// }
|
|
546
|
+
|
|
528
547
|
const orders = await this.loadOrdersByServer();
|
|
529
|
-
this.store.list = (0,
|
|
548
|
+
this.store.list = (0, _lodashEs.cloneDeep)(orders);
|
|
530
549
|
this.syncOrdersMap();
|
|
531
|
-
await this.emitOrdersChanged([],
|
|
532
|
-
await this.core.effects.emit(
|
|
550
|
+
await this.emitOrdersChanged([], 'preload');
|
|
551
|
+
await this.core.effects.emit(_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
533
552
|
}
|
|
534
553
|
getOrders() {
|
|
535
554
|
return this.store.list;
|
|
@@ -537,13 +556,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
537
556
|
getOrderById(id) {
|
|
538
557
|
return this.store.map.get(this.getIdKey(id));
|
|
539
558
|
}
|
|
559
|
+
|
|
540
560
|
/** 按 order_id 查询内存订单。 */
|
|
541
561
|
getOrderByOrderId(orderId) {
|
|
542
562
|
return this.store.map.get(this.getIdKey(orderId));
|
|
543
563
|
}
|
|
544
564
|
buildLocalPaymentOrderLogContext(order) {
|
|
545
|
-
if (!order)
|
|
546
|
-
return {};
|
|
565
|
+
if (!order) return {};
|
|
547
566
|
return {
|
|
548
567
|
order_id: order.order_id ?? null,
|
|
549
568
|
external_sale_number: order.external_sale_number ?? null,
|
|
@@ -565,9 +584,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
565
584
|
getLocalOrderFromMemoryByLookup(lookup) {
|
|
566
585
|
const key = this.getIdKey(lookup);
|
|
567
586
|
const memoryOrderById = this.store.map.get(key);
|
|
568
|
-
if (memoryOrderById)
|
|
569
|
-
|
|
570
|
-
const memoryOrder = this.store.list.find((order) => this.isOrderLookupMatch(order, key));
|
|
587
|
+
if (memoryOrderById) return memoryOrderById;
|
|
588
|
+
const memoryOrder = this.store.list.find(order => this.isOrderLookupMatch(order, key));
|
|
571
589
|
return memoryOrder || null;
|
|
572
590
|
}
|
|
573
591
|
async getLocalOrderByLookup(lookup, options = {}) {
|
|
@@ -578,22 +596,22 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
578
596
|
memory_order_count: this.store.list.length
|
|
579
597
|
};
|
|
580
598
|
if (options.operationId) {
|
|
581
|
-
this.logInfo(
|
|
599
|
+
this.logInfo('getLocalOrderByLookup-localPayment-开始', logContext);
|
|
582
600
|
}
|
|
583
601
|
const memoryOrderById = this.store.map.get(key);
|
|
584
602
|
if (memoryOrderById) {
|
|
585
603
|
if (options.operationId) {
|
|
586
|
-
this.logInfo(
|
|
604
|
+
this.logInfo('getLocalOrderByLookup-localPayment-命中内存映射', {
|
|
587
605
|
...logContext,
|
|
588
606
|
...this.buildLocalPaymentOrderLogContext(memoryOrderById)
|
|
589
607
|
});
|
|
590
608
|
}
|
|
591
609
|
return memoryOrderById;
|
|
592
610
|
}
|
|
593
|
-
const memoryOrder = this.store.list.find(
|
|
611
|
+
const memoryOrder = this.store.list.find(order => this.isOrderLookupMatch(order, key));
|
|
594
612
|
if (memoryOrder) {
|
|
595
613
|
if (options.operationId) {
|
|
596
|
-
this.logInfo(
|
|
614
|
+
this.logInfo('getLocalOrderByLookup-localPayment-命中内存列表', {
|
|
597
615
|
...logContext,
|
|
598
616
|
...this.buildLocalPaymentOrderLogContext(memoryOrder)
|
|
599
617
|
});
|
|
@@ -601,27 +619,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
601
619
|
return memoryOrder;
|
|
602
620
|
}
|
|
603
621
|
if (options.operationId) {
|
|
604
|
-
this.logInfo(
|
|
622
|
+
this.logInfo('getLocalOrderByLookup-localPayment-开始读取SQLite', logContext);
|
|
605
623
|
}
|
|
606
624
|
const orders = await this.loadOrdersFromSQLite();
|
|
607
|
-
const localOrder = orders.find(
|
|
625
|
+
const localOrder = orders.find(order => this.isOrderLookupMatch(order, key));
|
|
608
626
|
if (!localOrder) {
|
|
609
627
|
if (options.operationId) {
|
|
610
|
-
this.logWarning(
|
|
628
|
+
this.logWarning('getLocalOrderByLookup-localPayment-SQLite未命中', {
|
|
611
629
|
...logContext,
|
|
612
630
|
sqlite_order_count: orders.length
|
|
613
631
|
});
|
|
614
632
|
}
|
|
615
633
|
return null;
|
|
616
634
|
}
|
|
617
|
-
this.store.list = this.normalizeOrdersForMemoryList(
|
|
618
|
-
orders,
|
|
619
|
-
"getLocalOrderByLookup.sqliteMemory"
|
|
620
|
-
);
|
|
635
|
+
this.store.list = this.normalizeOrdersForMemoryList(orders, 'getLocalOrderByLookup.sqliteMemory');
|
|
621
636
|
this.syncOrdersMap();
|
|
622
637
|
const normalizedOrder = this.normalizeOrderForMemoryList(localOrder);
|
|
623
638
|
if (options.operationId) {
|
|
624
|
-
this.logInfo(
|
|
639
|
+
this.logInfo('getLocalOrderByLookup-localPayment-SQLite命中', {
|
|
625
640
|
...logContext,
|
|
626
641
|
sqlite_order_count: orders.length,
|
|
627
642
|
...this.buildLocalPaymentOrderLogContext(normalizedOrder)
|
|
@@ -635,30 +650,26 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
635
650
|
sale_id: params.saleId,
|
|
636
651
|
payment_number: params.paymentNumber
|
|
637
652
|
};
|
|
638
|
-
this.logInfo(
|
|
653
|
+
this.logInfo('getLocalPayment-开始', logContext);
|
|
639
654
|
try {
|
|
640
655
|
const order = await this.getLocalOrderByLookup(params.saleId, {
|
|
641
656
|
operationId: params.operationId
|
|
642
657
|
});
|
|
643
658
|
if (!order) {
|
|
644
|
-
this.logWarning(
|
|
659
|
+
this.logWarning('getLocalPayment-订单未命中', logContext);
|
|
645
660
|
return null;
|
|
646
661
|
}
|
|
647
662
|
const payments = order.payments || [];
|
|
648
|
-
const match = (0,
|
|
649
|
-
payments,
|
|
650
|
-
params.paymentNumber,
|
|
651
|
-
"compat"
|
|
652
|
-
);
|
|
663
|
+
const match = (0, _paymentUtils.resolveOrderPaymentIdentity)(payments, params.paymentNumber, 'compat');
|
|
653
664
|
if (!match) {
|
|
654
|
-
this.logWarning(
|
|
665
|
+
this.logWarning('getLocalPayment-支付项未命中', {
|
|
655
666
|
...logContext,
|
|
656
667
|
...this.buildLocalPaymentOrderLogContext(order),
|
|
657
668
|
payments
|
|
658
669
|
});
|
|
659
670
|
return null;
|
|
660
671
|
}
|
|
661
|
-
this.logInfo(
|
|
672
|
+
this.logInfo('getLocalPayment-支付项命中', {
|
|
662
673
|
...logContext,
|
|
663
674
|
...this.buildLocalPaymentOrderLogContext(order),
|
|
664
675
|
matched_by: match.matchedBy,
|
|
@@ -672,7 +683,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
672
683
|
matchedBy: match.matchedBy
|
|
673
684
|
};
|
|
674
685
|
} catch (error) {
|
|
675
|
-
this.logError(
|
|
686
|
+
this.logError('getLocalPayment-查询失败', {
|
|
676
687
|
...logContext,
|
|
677
688
|
error: error instanceof Error ? error.message : String(error)
|
|
678
689
|
});
|
|
@@ -686,21 +697,21 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
686
697
|
payment_number: params.paymentNumber,
|
|
687
698
|
incoming_payment_update: params.updates
|
|
688
699
|
};
|
|
689
|
-
this.logInfo(
|
|
700
|
+
this.logInfo('updateLocalPayment-开始', logContext);
|
|
690
701
|
const found = await this.getLocalPayment(params);
|
|
691
702
|
if (!found) {
|
|
692
|
-
this.logWarning(
|
|
703
|
+
this.logWarning('updateLocalPayment-支付项未命中', logContext);
|
|
693
704
|
return null;
|
|
694
705
|
}
|
|
695
|
-
const previousPayment = (0,
|
|
696
|
-
const nextPayment = (0,
|
|
706
|
+
const previousPayment = (0, _lodashEs.cloneDeep)(found.payment);
|
|
707
|
+
const nextPayment = (0, _paymentUtils.mergeOrderPaymentRecord)(found.payment, {
|
|
697
708
|
...params.updates,
|
|
698
|
-
updated_at: params.updates.updated_at || (0,
|
|
709
|
+
updated_at: params.updates.updated_at || (0, _dayjs.default)().format('YYYY-MM-DD HH:mm:ss')
|
|
699
710
|
});
|
|
700
711
|
const nextOrder = {
|
|
701
712
|
...found.order,
|
|
702
713
|
payments: (found.order.payments || []).map((payment, index) => index === found.paymentIndex ? nextPayment : payment),
|
|
703
|
-
updated_at: (0,
|
|
714
|
+
updated_at: (0, _dayjs.default)().format('YYYY-MM-DD HH:mm:ss')
|
|
704
715
|
};
|
|
705
716
|
const paymentContext = {
|
|
706
717
|
...logContext,
|
|
@@ -710,11 +721,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
710
721
|
previous_payment: previousPayment,
|
|
711
722
|
payment: nextPayment
|
|
712
723
|
};
|
|
713
|
-
this.logInfo(
|
|
724
|
+
this.logInfo('updateLocalPayment-支付项合并完成', paymentContext);
|
|
714
725
|
const targetIndex = this.findOrderIndexByIdentity(this.store.list, found.order);
|
|
715
726
|
const shouldKeepInMemory = this.shouldKeepOrderInMemory(nextOrder);
|
|
716
727
|
if (targetIndex < 0 && shouldKeepInMemory) {
|
|
717
|
-
this.logError(
|
|
728
|
+
this.logError('updateLocalPayment-订单Store索引未命中', paymentContext);
|
|
718
729
|
return null;
|
|
719
730
|
}
|
|
720
731
|
const previousList = this.store.list;
|
|
@@ -722,19 +733,21 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
722
733
|
this.syncOrdersMap();
|
|
723
734
|
const storageOrder = this.withoutSyntheticDraftOrderId(nextOrder);
|
|
724
735
|
try {
|
|
725
|
-
this.logInfo(
|
|
736
|
+
this.logInfo('updateLocalPayment-SQLite写入开始', {
|
|
726
737
|
...paymentContext,
|
|
727
738
|
storage_order_id: storageOrder.order_id ?? null
|
|
728
739
|
});
|
|
729
|
-
await this.updateOrderInSQLite(storageOrder,
|
|
730
|
-
|
|
740
|
+
await this.updateOrderInSQLite(storageOrder, 'updateLocalPayment', {
|
|
741
|
+
throwOnError: true
|
|
742
|
+
});
|
|
743
|
+
this.logInfo('updateLocalPayment-SQLite写入完成', {
|
|
731
744
|
...paymentContext,
|
|
732
745
|
storage_order_id: storageOrder.order_id ?? null
|
|
733
746
|
});
|
|
734
747
|
} catch (error) {
|
|
735
748
|
this.store.list = previousList;
|
|
736
749
|
this.syncOrdersMap();
|
|
737
|
-
this.logError(
|
|
750
|
+
this.logError('updateLocalPayment-SQLite写入失败并回滚内存', {
|
|
738
751
|
...paymentContext,
|
|
739
752
|
storage_order_id: storageOrder.order_id ?? null,
|
|
740
753
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -742,28 +755,23 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
742
755
|
throw error;
|
|
743
756
|
}
|
|
744
757
|
if (shouldKeepInMemory || targetIndex >= 0) {
|
|
745
|
-
await this.emitOrdersChanged(
|
|
746
|
-
shouldKeepInMemory ? [nextOrder] : [],
|
|
747
|
-
shouldKeepInMemory ? "updateLocalPayment" : "updateLocalPayment.sqliteOnlyDraft"
|
|
748
|
-
);
|
|
758
|
+
await this.emitOrdersChanged(shouldKeepInMemory ? [nextOrder] : [], shouldKeepInMemory ? 'updateLocalPayment' : 'updateLocalPayment.sqliteOnlyDraft');
|
|
749
759
|
}
|
|
750
|
-
this.logInfo(
|
|
751
|
-
return {
|
|
760
|
+
this.logInfo('updateLocalPayment-变更事件完成', paymentContext);
|
|
761
|
+
return {
|
|
762
|
+
order: nextOrder,
|
|
763
|
+
payment: nextPayment,
|
|
764
|
+
previousPayment
|
|
765
|
+
};
|
|
752
766
|
}
|
|
753
767
|
async loadOrdersByServer() {
|
|
754
|
-
var _a;
|
|
755
768
|
let orderList = [];
|
|
756
|
-
const protectedOrdersBeforeRemoteFetch = (await this.loadOrdersFromSQLite()).filter(
|
|
757
|
-
|
|
758
|
-
);
|
|
759
|
-
this.logInfo("loadOrdersByServer-开始", {
|
|
769
|
+
const protectedOrdersBeforeRemoteFetch = (await this.loadOrdersFromSQLite()).filter(order => this.shouldProtectLocalOrderFromRemoteSnapshot(order));
|
|
770
|
+
this.logInfo('loadOrdersByServer-开始', {
|
|
760
771
|
hasOrderDataSource: !!this.orderDataSource,
|
|
761
|
-
query:
|
|
772
|
+
query: this.store?.createdAtQuery || null,
|
|
762
773
|
protectedLocalOrderCount: protectedOrdersBeforeRemoteFetch.length,
|
|
763
|
-
protectedPendingPaymentCount: protectedOrdersBeforeRemoteFetch.reduce(
|
|
764
|
-
(count, order) => count + this.getIdentifiedPendingPayments(order).length,
|
|
765
|
-
0
|
|
766
|
-
)
|
|
774
|
+
protectedPendingPaymentCount: protectedOrdersBeforeRemoteFetch.reduce((count, order) => count + this.getIdentifiedPendingPayments(order).length, 0)
|
|
767
775
|
});
|
|
768
776
|
if (this.orderDataSource) {
|
|
769
777
|
try {
|
|
@@ -773,33 +781,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
773
781
|
}
|
|
774
782
|
});
|
|
775
783
|
orderList = data || [];
|
|
776
|
-
this.logInfo(
|
|
784
|
+
this.logInfo('loadOrdersByServer-SSE拉取成功', {
|
|
777
785
|
count: orderList.length
|
|
778
786
|
});
|
|
779
787
|
this.markOrderPulledAtNow();
|
|
780
788
|
this.lastServerFullFetchAtMs = Date.now();
|
|
781
789
|
} catch {
|
|
782
|
-
this.logInfo(
|
|
790
|
+
this.logInfo('loadOrdersByServer-SSE拉取失败,保持当前内存订单');
|
|
783
791
|
return this.store.list;
|
|
784
792
|
}
|
|
785
793
|
}
|
|
786
|
-
const mergedOrders = await this.replaceOrdersSnapshotInSQLite(
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
protectedOrdersBeforeRemoteFetch
|
|
790
|
-
);
|
|
791
|
-
const memoryOrders = this.normalizeOrdersForMemoryList(
|
|
792
|
-
mergedOrders,
|
|
793
|
-
"loadOrdersByServer.memory"
|
|
794
|
-
);
|
|
795
|
-
this.logInfo("loadOrdersByServer-结束", {
|
|
794
|
+
const mergedOrders = await this.replaceOrdersSnapshotInSQLite(orderList, 'loadOrdersByServer', protectedOrdersBeforeRemoteFetch);
|
|
795
|
+
const memoryOrders = this.normalizeOrdersForMemoryList(mergedOrders, 'loadOrdersByServer.memory');
|
|
796
|
+
this.logInfo('loadOrdersByServer-结束', {
|
|
796
797
|
count: memoryOrders.length,
|
|
797
798
|
persistedCount: mergedOrders.length,
|
|
798
799
|
sqliteOnlyDraftCount: mergedOrders.length - memoryOrders.length
|
|
799
800
|
});
|
|
800
|
-
await this.core.effects.emit(
|
|
801
|
+
await this.core.effects.emit(_types.OrderHooks.onOrdersLoaded, memoryOrders);
|
|
801
802
|
return memoryOrders;
|
|
802
803
|
}
|
|
804
|
+
|
|
803
805
|
/**
|
|
804
806
|
* 静默全量刷新:后台重新拉取全量 SSE 订单数据并更新本地
|
|
805
807
|
* 拿到完整数据后一次性替换 store,触发订单变更与同步完成事件
|
|
@@ -811,38 +813,39 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
811
813
|
if (this.lastServerFullFetchAtMs > 0 && elapsedSinceFullFetch < ORDER_SILENT_REFRESH_MIN_INTERVAL_MS) {
|
|
812
814
|
return this.store.list;
|
|
813
815
|
}
|
|
814
|
-
this.logInfo(
|
|
816
|
+
this.logInfo('silentRefresh 开始');
|
|
815
817
|
try {
|
|
818
|
+
// 刷新前,需要更新当前营业日边界(store.createdAtQuery)
|
|
816
819
|
this.updateCreateStore();
|
|
817
820
|
const orders = await this.loadOrdersByServer();
|
|
818
|
-
this.store.list = (0,
|
|
821
|
+
this.store.list = (0, _lodashEs.cloneDeep)(orders);
|
|
819
822
|
this.syncOrdersMap();
|
|
820
|
-
await this.emitOrdersChanged([],
|
|
821
|
-
await this.core.effects.emit(
|
|
822
|
-
this.logInfo(
|
|
823
|
+
await this.emitOrdersChanged([], 'silentRefresh');
|
|
824
|
+
await this.core.effects.emit(_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
825
|
+
this.logInfo('silentRefresh 完成', {
|
|
823
826
|
orderCount: orders.length,
|
|
824
827
|
duration: `${Date.now() - startTime}ms`
|
|
825
828
|
});
|
|
826
829
|
return this.store.list;
|
|
827
830
|
} catch (error) {
|
|
828
831
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
829
|
-
this.logError(
|
|
832
|
+
this.logError('silentRefresh 失败', {
|
|
830
833
|
duration: `${Date.now() - startTime}ms`,
|
|
831
834
|
error: errorMessage
|
|
832
835
|
});
|
|
833
836
|
return this.store.list;
|
|
834
837
|
}
|
|
835
838
|
}
|
|
836
|
-
normalizeOrderForMemoryList(order, source =
|
|
839
|
+
normalizeOrderForMemoryList(order, source = 'normalizeOrderForMemoryList') {
|
|
837
840
|
const normalizedOrder = this.normalizeOrderCollectionsForIngress(order, source);
|
|
838
|
-
const externalSaleNumber = normalizedOrder
|
|
841
|
+
const externalSaleNumber = normalizedOrder?.external_sale_number;
|
|
839
842
|
if (this.isDraftOrder(normalizedOrder) && !this.hasRealOrderId(normalizedOrder)) {
|
|
840
843
|
return normalizedOrder;
|
|
841
844
|
}
|
|
842
|
-
if (
|
|
845
|
+
if (normalizedOrder?.order_id !== undefined && normalizedOrder?.order_id !== null && normalizedOrder?.order_id !== '') {
|
|
843
846
|
return normalizedOrder;
|
|
844
847
|
}
|
|
845
|
-
if (externalSaleNumber ===
|
|
848
|
+
if (externalSaleNumber === undefined || externalSaleNumber === null || externalSaleNumber === '') {
|
|
846
849
|
return normalizedOrder;
|
|
847
850
|
}
|
|
848
851
|
return {
|
|
@@ -851,11 +854,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
851
854
|
};
|
|
852
855
|
}
|
|
853
856
|
normalizeOrdersForMemoryList(orders, source) {
|
|
854
|
-
return orders.map(
|
|
857
|
+
return orders.map(order => this.normalizeOrderForMemoryList(order, source)).filter(order => this.shouldKeepOrderInMemory(order));
|
|
855
858
|
}
|
|
856
859
|
hasRealOrderId(order) {
|
|
857
|
-
if (!order || this.isBlankIdentityValue(order.order_id))
|
|
858
|
-
return false;
|
|
860
|
+
if (!order || this.isBlankIdentityValue(order.order_id)) return false;
|
|
859
861
|
const externalSaleNumber = order.external_sale_number;
|
|
860
862
|
return !(this.isDraftOrder(order) && !this.isBlankIdentityValue(externalSaleNumber) && String(order.order_id) === String(externalSaleNumber));
|
|
861
863
|
}
|
|
@@ -864,67 +866,75 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
864
866
|
}
|
|
865
867
|
withoutSyntheticDraftOrderId(order) {
|
|
866
868
|
const externalSaleNumber = order.external_sale_number;
|
|
867
|
-
if (Number(order.is_draft_order || 0) !== 1 || order.order_id ===
|
|
869
|
+
if (Number(order.is_draft_order || 0) !== 1 || order.order_id === undefined || externalSaleNumber === undefined || String(order.order_id) !== String(externalSaleNumber)) {
|
|
868
870
|
return order;
|
|
869
871
|
}
|
|
870
|
-
const next = {
|
|
872
|
+
const next = {
|
|
873
|
+
...order
|
|
874
|
+
};
|
|
871
875
|
delete next.order_id;
|
|
872
876
|
return next;
|
|
873
877
|
}
|
|
878
|
+
|
|
874
879
|
/**
|
|
875
880
|
* 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
|
|
876
881
|
* 适用于"按 order_id 主动刷新本地订单详情"的代理场景。
|
|
877
882
|
*/
|
|
878
883
|
async overwriteExistingOrder(fresh) {
|
|
879
|
-
const orderId = fresh
|
|
880
|
-
if (orderId ===
|
|
881
|
-
this.logError(
|
|
882
|
-
return {
|
|
884
|
+
const orderId = fresh?.order_id;
|
|
885
|
+
if (orderId === undefined || orderId === null) {
|
|
886
|
+
this.logError('overwriteExistingOrder-入参缺少 order_id');
|
|
887
|
+
return {
|
|
888
|
+
overwritten: false
|
|
889
|
+
};
|
|
883
890
|
}
|
|
884
891
|
const key = this.getIdKey(orderId);
|
|
885
892
|
if (!this.store.map.has(key)) {
|
|
886
|
-
this.logInfo(
|
|
887
|
-
|
|
893
|
+
this.logInfo('overwriteExistingOrder-本地不存在该订单,跳过', {
|
|
894
|
+
orderId
|
|
895
|
+
});
|
|
896
|
+
return {
|
|
897
|
+
overwritten: false
|
|
898
|
+
};
|
|
888
899
|
}
|
|
889
|
-
this.logInfo(
|
|
900
|
+
this.logInfo('overwriteExistingOrder-开始覆盖', {
|
|
890
901
|
orderId,
|
|
891
902
|
storeOrderCountBefore: this.store.list.length
|
|
892
903
|
});
|
|
893
|
-
const normalizedFresh = this.normalizeOrderForMemoryList(
|
|
894
|
-
fresh,
|
|
895
|
-
"overwriteExistingOrder.incoming"
|
|
896
|
-
);
|
|
904
|
+
const normalizedFresh = this.normalizeOrderForMemoryList(fresh, 'overwriteExistingOrder.incoming');
|
|
897
905
|
const existingOrder = this.store.map.get(key);
|
|
898
|
-
const reconciledFresh = this.reconcileOverwriteOrderCollections(
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
const id = order == null ? void 0 : order.order_id;
|
|
904
|
-
if (id === void 0 || id === null) {
|
|
905
|
-
return this.normalizeOrderForMemoryList(order, "overwriteExistingOrder.existingMemory");
|
|
906
|
+
const reconciledFresh = this.reconcileOverwriteOrderCollections(existingOrder, normalizedFresh);
|
|
907
|
+
this.store.list = this.store.list.map(order => {
|
|
908
|
+
const id = order?.order_id;
|
|
909
|
+
if (id === undefined || id === null) {
|
|
910
|
+
return this.normalizeOrderForMemoryList(order, 'overwriteExistingOrder.existingMemory');
|
|
906
911
|
}
|
|
907
|
-
return this.getIdKey(id) === key ? reconciledFresh : this.normalizeOrderForMemoryList(order,
|
|
912
|
+
return this.getIdKey(id) === key ? reconciledFresh : this.normalizeOrderForMemoryList(order, 'overwriteExistingOrder.existingMemory');
|
|
908
913
|
});
|
|
909
914
|
this.syncOrdersMap();
|
|
910
|
-
await this.updateOrderInSQLite(reconciledFresh,
|
|
911
|
-
this.logInfo(
|
|
915
|
+
await this.updateOrderInSQLite(reconciledFresh, 'overwriteExistingOrder');
|
|
916
|
+
this.logInfo('overwriteExistingOrder-结束', {
|
|
912
917
|
orderId,
|
|
913
918
|
storeOrderCountAfter: this.store.list.length
|
|
914
919
|
});
|
|
915
|
-
await this.emitOrdersChanged([reconciledFresh],
|
|
916
|
-
return {
|
|
920
|
+
await this.emitOrdersChanged([reconciledFresh], 'overwriteExistingOrder');
|
|
921
|
+
return {
|
|
922
|
+
overwritten: true
|
|
923
|
+
};
|
|
917
924
|
}
|
|
925
|
+
|
|
918
926
|
/**
|
|
919
927
|
* 将远端拉取的订单合并进本地 store(已存在则更新,不存在则追加),落库并 emit onOrdersChanged。
|
|
920
928
|
* 供 /update/localOrder 等在「本地尚无该单」时写入新建单。
|
|
921
929
|
*/
|
|
922
|
-
async upsertOrdersFromRemote(freshOrders, source =
|
|
923
|
-
if (!
|
|
924
|
-
this.logInfo(
|
|
930
|
+
async upsertOrdersFromRemote(freshOrders, source = 'upsertOrdersFromRemote') {
|
|
931
|
+
if (!freshOrders?.length) {
|
|
932
|
+
this.logInfo('upsertOrdersFromRemote-订单列表为空', {
|
|
933
|
+
source
|
|
934
|
+
});
|
|
925
935
|
return;
|
|
926
936
|
}
|
|
927
|
-
this.logInfo(
|
|
937
|
+
this.logInfo('upsertOrdersFromRemote-开始', {
|
|
928
938
|
count: freshOrders.length,
|
|
929
939
|
source
|
|
930
940
|
});
|
|
@@ -932,106 +942,100 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
932
942
|
}
|
|
933
943
|
async markOrderSyncedByExternalSaleNumber(params) {
|
|
934
944
|
const externalSaleNumber = params.externalSaleNumber;
|
|
935
|
-
if (externalSaleNumber ===
|
|
936
|
-
this.logError(
|
|
937
|
-
return {
|
|
945
|
+
if (externalSaleNumber === undefined || externalSaleNumber === null || externalSaleNumber === '') {
|
|
946
|
+
this.logError('markOrderSyncedByExternalSaleNumber-缺少 external_sale_number');
|
|
947
|
+
return {
|
|
948
|
+
updated: false
|
|
949
|
+
};
|
|
938
950
|
}
|
|
939
951
|
const key = this.getIdKey(externalSaleNumber);
|
|
940
|
-
const targetIndex = this.store.list.findIndex(
|
|
941
|
-
const value = order
|
|
942
|
-
if (value ===
|
|
943
|
-
return false;
|
|
952
|
+
const targetIndex = this.store.list.findIndex(order => {
|
|
953
|
+
const value = order?.external_sale_number;
|
|
954
|
+
if (value === undefined || value === null || value === '') return false;
|
|
944
955
|
return this.getIdKey(value) === key;
|
|
945
956
|
});
|
|
946
957
|
if (targetIndex < 0) {
|
|
947
|
-
this.logInfo(
|
|
958
|
+
this.logInfo('markOrderSyncedByExternalSaleNumber-本地订单不存在,跳过', {
|
|
948
959
|
external_sale_number: externalSaleNumber
|
|
949
960
|
});
|
|
950
|
-
return {
|
|
961
|
+
return {
|
|
962
|
+
updated: false
|
|
963
|
+
};
|
|
951
964
|
}
|
|
952
965
|
const existing = this.store.list[targetIndex];
|
|
953
966
|
const nextOrder = this.normalizeRemoteSyncedOrder({
|
|
954
967
|
...existing,
|
|
955
|
-
...params.patch || {},
|
|
968
|
+
...(params.patch || {}),
|
|
956
969
|
external_sale_number: existing.external_sale_number ?? externalSaleNumber,
|
|
957
970
|
need_sync: 0,
|
|
958
971
|
is_draft_order: 0
|
|
959
972
|
});
|
|
960
973
|
const storageKey = this.getOrderStorageKey(nextOrder) || key;
|
|
961
974
|
this.store.list = this.store.list.map((order, index) => {
|
|
962
|
-
if (index !== targetIndex)
|
|
963
|
-
return order;
|
|
975
|
+
if (index !== targetIndex) return order;
|
|
964
976
|
return nextOrder;
|
|
965
977
|
});
|
|
966
978
|
this.syncOrdersMap();
|
|
967
|
-
await this.patchOrdersInSQLite(
|
|
968
|
-
[
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
);
|
|
972
|
-
this.logInfo("markOrderSyncedByExternalSaleNumber-完成", {
|
|
979
|
+
await this.patchOrdersInSQLite([nextOrder], 'markOrderSyncedByExternalSaleNumber', {
|
|
980
|
+
[storageKey]: 'update'
|
|
981
|
+
});
|
|
982
|
+
this.logInfo('markOrderSyncedByExternalSaleNumber-完成', {
|
|
973
983
|
external_sale_number: externalSaleNumber,
|
|
974
984
|
order_id: nextOrder.order_id ?? null
|
|
975
985
|
});
|
|
976
|
-
await this.emitOrdersChanged([nextOrder],
|
|
977
|
-
return {
|
|
986
|
+
await this.emitOrdersChanged([nextOrder], 'markOrderSyncedByExternalSaleNumber');
|
|
987
|
+
return {
|
|
988
|
+
updated: true,
|
|
989
|
+
order: nextOrder
|
|
990
|
+
};
|
|
978
991
|
}
|
|
992
|
+
|
|
979
993
|
/**
|
|
980
994
|
* 将本地待同步订单按 SQLite storage key 合并进 store 并落库。
|
|
981
995
|
* checkout 离线兜底可能没有 order_id,但通常会有 external_sale_number。
|
|
982
996
|
*/
|
|
983
997
|
async upsertPendingSyncOrders(pendingOrders, options = {}) {
|
|
984
|
-
if (!
|
|
985
|
-
this.logInfo(
|
|
998
|
+
if (!pendingOrders?.length) {
|
|
999
|
+
this.logInfo('upsertPendingSyncOrders-订单列表为空', {});
|
|
986
1000
|
return;
|
|
987
1001
|
}
|
|
988
|
-
const pendingMap =
|
|
989
|
-
const memoryPendingMap =
|
|
1002
|
+
const pendingMap = new Map();
|
|
1003
|
+
const memoryPendingMap = new Map();
|
|
990
1004
|
for (const order of pendingOrders) {
|
|
991
|
-
const normalizedOrder = this.normalizeOrderCollectionsForIngress(
|
|
992
|
-
order,
|
|
993
|
-
"upsertPendingSyncOrders.incoming"
|
|
994
|
-
);
|
|
1005
|
+
const normalizedOrder = this.normalizeOrderCollectionsForIngress(order, 'upsertPendingSyncOrders.incoming');
|
|
995
1006
|
const pendingOrder = {
|
|
996
1007
|
...normalizedOrder,
|
|
997
1008
|
need_sync: 1,
|
|
998
1009
|
is_draft_order: 0
|
|
999
1010
|
};
|
|
1000
1011
|
const storageKey = this.getOrderStorageKey(pendingOrder);
|
|
1001
|
-
if (!storageKey)
|
|
1002
|
-
continue;
|
|
1012
|
+
if (!storageKey) continue;
|
|
1003
1013
|
pendingMap.set(storageKey, pendingOrder);
|
|
1004
|
-
memoryPendingMap.set(
|
|
1005
|
-
storageKey,
|
|
1006
|
-
this.normalizeOrderForMemoryList(
|
|
1007
|
-
pendingOrder,
|
|
1008
|
-
"upsertPendingSyncOrders.memory"
|
|
1009
|
-
)
|
|
1010
|
-
);
|
|
1014
|
+
memoryPendingMap.set(storageKey, this.normalizeOrderForMemoryList(pendingOrder, 'upsertPendingSyncOrders.memory'));
|
|
1011
1015
|
}
|
|
1012
1016
|
if (pendingMap.size === 0) {
|
|
1013
|
-
this.logError(
|
|
1017
|
+
this.logError('upsertPendingSyncOrders-订单缺少可落库标识', {
|
|
1014
1018
|
count: pendingOrders.length
|
|
1015
1019
|
});
|
|
1016
1020
|
return;
|
|
1017
1021
|
}
|
|
1018
|
-
this.logInfo(
|
|
1022
|
+
this.logInfo('upsertPendingSyncOrders-开始', {
|
|
1023
|
+
count: pendingMap.size
|
|
1024
|
+
});
|
|
1019
1025
|
const mergeActions = {};
|
|
1020
|
-
const updatedList = this.store.list.map(
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1026
|
+
const updatedList = this.store.list.map(order => this.normalizeOrderForMemoryList(order, 'upsertPendingSyncOrders.existingMemory'));
|
|
1027
|
+
|
|
1028
|
+
// 与 mergeOrdersToStore 一致:基于身份键(field:value)建立索引,把「查找已存在订单」
|
|
1029
|
+
// 从 O(n) 线性扫描降为 O(1),整体复杂度由 O(n^2) 降为 O(n + m)。
|
|
1030
|
+
const identityKeyToIndex = new Map();
|
|
1024
1031
|
for (let index = 0; index < updatedList.length; index += 1) {
|
|
1025
1032
|
for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
|
|
1026
|
-
|
|
1027
|
-
|
|
1033
|
+
// 同一 key 命中多张时保留最靠前的下标,与原 findIndex「取首个匹配」一致
|
|
1034
|
+
if (!identityKeyToIndex.has(key)) identityKeyToIndex.set(key, index);
|
|
1028
1035
|
}
|
|
1029
1036
|
}
|
|
1030
1037
|
for (const [storageKey, pendingOrder] of memoryPendingMap.entries()) {
|
|
1031
|
-
const matchIndex = this.lookupOrderIndexByIdentityKeys(
|
|
1032
|
-
identityKeyToIndex,
|
|
1033
|
-
this.getOrderIdentityMatchKeys(pendingOrder)
|
|
1034
|
-
);
|
|
1038
|
+
const matchIndex = this.lookupOrderIndexByIdentityKeys(identityKeyToIndex, this.getOrderIdentityMatchKeys(pendingOrder));
|
|
1035
1039
|
if (matchIndex >= 0) {
|
|
1036
1040
|
const existingOrder = updatedList[matchIndex];
|
|
1037
1041
|
const mergedOrder = this.mergeOrderRecords(existingOrder, pendingOrder);
|
|
@@ -1043,53 +1047,48 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1043
1047
|
updatedList[matchIndex] = nextOrder;
|
|
1044
1048
|
const pendingSnapshot = pendingMap.get(storageKey);
|
|
1045
1049
|
if (pendingSnapshot) {
|
|
1046
|
-
pendingMap.set(
|
|
1047
|
-
storageKey,
|
|
1048
|
-
this.reconcileOverwriteOrderCollections(existingOrder, pendingSnapshot)
|
|
1049
|
-
);
|
|
1050
|
+
pendingMap.set(storageKey, this.reconcileOverwriteOrderCollections(existingOrder, pendingSnapshot));
|
|
1050
1051
|
}
|
|
1052
|
+
// 合并后身份字段可能新增(如挂单拿到 order_id),同步登记,供同批后续 pending 命中同一槽位
|
|
1051
1053
|
this.registerOrderIdentityKeys(identityKeyToIndex, nextOrder, matchIndex);
|
|
1052
|
-
mergeActions[storageKey] =
|
|
1054
|
+
mergeActions[storageKey] = 'update';
|
|
1053
1055
|
continue;
|
|
1054
1056
|
}
|
|
1055
1057
|
const insertIndex = updatedList.length;
|
|
1056
1058
|
updatedList.push(pendingOrder);
|
|
1057
1059
|
this.registerOrderIdentityKeys(identityKeyToIndex, pendingOrder, insertIndex);
|
|
1058
|
-
mergeActions[storageKey] =
|
|
1060
|
+
mergeActions[storageKey] = 'insert';
|
|
1059
1061
|
}
|
|
1060
1062
|
const patchedOrders = [...pendingMap.values()];
|
|
1063
|
+
// 增量索引已保证 store 去重不变量,无需再对全表做 O(n^2) 压缩;仅自检开关开启时兜底。
|
|
1061
1064
|
const previousList = this.store.list;
|
|
1062
|
-
this.store.list = this.runOrderStoreSelfCheck(updatedList,
|
|
1065
|
+
this.store.list = this.runOrderStoreSelfCheck(updatedList, 'upsertPendingSyncOrders.store');
|
|
1063
1066
|
this.syncOrdersMap();
|
|
1064
1067
|
try {
|
|
1065
|
-
await this.patchOrdersInSQLite(
|
|
1066
|
-
patchedOrders,
|
|
1067
|
-
"upsertPendingSyncOrders",
|
|
1068
|
-
mergeActions,
|
|
1069
|
-
options
|
|
1070
|
-
);
|
|
1068
|
+
await this.patchOrdersInSQLite(patchedOrders, 'upsertPendingSyncOrders', mergeActions, options);
|
|
1071
1069
|
} catch (error) {
|
|
1072
1070
|
this.store.list = previousList;
|
|
1073
1071
|
this.syncOrdersMap();
|
|
1074
1072
|
throw error;
|
|
1075
1073
|
}
|
|
1076
|
-
this.logInfo(
|
|
1074
|
+
this.logInfo('upsertPendingSyncOrders-结束', {
|
|
1077
1075
|
count: patchedOrders.length,
|
|
1078
1076
|
storeOrderCountAfter: this.store.list.length
|
|
1079
1077
|
});
|
|
1080
|
-
await this.emitOrdersChanged(patchedOrders,
|
|
1078
|
+
await this.emitOrdersChanged(patchedOrders, 'upsertPendingSyncOrders');
|
|
1081
1079
|
}
|
|
1080
|
+
|
|
1082
1081
|
/**
|
|
1083
1082
|
* 将 POS 草稿订单按 SQLite storage key 落库。
|
|
1084
1083
|
* 只有具备真实 order_id 的草稿进入 store;其余草稿仅供本地恢复查询。
|
|
1085
1084
|
*/
|
|
1086
1085
|
async upsertLocalDraftOrders(draftOrders) {
|
|
1087
|
-
if (!
|
|
1088
|
-
this.logInfo(
|
|
1086
|
+
if (!draftOrders?.length) {
|
|
1087
|
+
this.logInfo('upsertLocalDraftOrders-订单列表为空', {});
|
|
1089
1088
|
return;
|
|
1090
1089
|
}
|
|
1091
|
-
const draftMap =
|
|
1092
|
-
const memoryDraftMap =
|
|
1090
|
+
const draftMap = new Map();
|
|
1091
|
+
const memoryDraftMap = new Map();
|
|
1093
1092
|
for (const order of draftOrders) {
|
|
1094
1093
|
const draftOrder = {
|
|
1095
1094
|
...order,
|
|
@@ -1097,8 +1096,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1097
1096
|
is_draft_order: 1
|
|
1098
1097
|
};
|
|
1099
1098
|
const storageKey = this.getOrderStorageKey(draftOrder);
|
|
1100
|
-
if (!storageKey)
|
|
1101
|
-
continue;
|
|
1099
|
+
if (!storageKey) continue;
|
|
1102
1100
|
draftMap.set(storageKey, draftOrder);
|
|
1103
1101
|
const memoryDraftOrder = this.normalizeOrderForMemoryList(draftOrder);
|
|
1104
1102
|
if (this.shouldKeepOrderInMemory(memoryDraftOrder)) {
|
|
@@ -1106,36 +1104,29 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1106
1104
|
}
|
|
1107
1105
|
}
|
|
1108
1106
|
if (draftMap.size === 0) {
|
|
1109
|
-
this.logError(
|
|
1107
|
+
this.logError('upsertLocalDraftOrders-订单缺少可落库标识', {
|
|
1110
1108
|
count: draftOrders.length
|
|
1111
1109
|
});
|
|
1112
1110
|
return;
|
|
1113
1111
|
}
|
|
1114
|
-
this.logInfo(
|
|
1112
|
+
this.logInfo('upsertLocalDraftOrders-开始', {
|
|
1115
1113
|
count: draftMap.size,
|
|
1116
1114
|
memoryDraftCount: memoryDraftMap.size,
|
|
1117
1115
|
sqliteOnlyDraftCount: draftMap.size - memoryDraftMap.size
|
|
1118
1116
|
});
|
|
1119
1117
|
const mergeActions = {};
|
|
1120
|
-
const updatedList = this.store.list.filter(
|
|
1121
|
-
const identityKeyToIndex =
|
|
1118
|
+
const updatedList = this.store.list.filter(order => this.shouldKeepOrderInMemory(order));
|
|
1119
|
+
const identityKeyToIndex = new Map();
|
|
1122
1120
|
for (let index = 0; index < updatedList.length; index += 1) {
|
|
1123
1121
|
for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
|
|
1124
|
-
if (!identityKeyToIndex.has(key))
|
|
1125
|
-
identityKeyToIndex.set(key, index);
|
|
1122
|
+
if (!identityKeyToIndex.has(key)) identityKeyToIndex.set(key, index);
|
|
1126
1123
|
}
|
|
1127
1124
|
}
|
|
1128
1125
|
for (const [storageKey, draftOrder] of memoryDraftMap.entries()) {
|
|
1129
|
-
const matchIndex = this.lookupOrderIndexByIdentityKeys(
|
|
1130
|
-
identityKeyToIndex,
|
|
1131
|
-
this.getOrderIdentityMatchKeys(draftOrder)
|
|
1132
|
-
);
|
|
1126
|
+
const matchIndex = this.lookupOrderIndexByIdentityKeys(identityKeyToIndex, this.getOrderIdentityMatchKeys(draftOrder));
|
|
1133
1127
|
if (matchIndex >= 0) {
|
|
1134
1128
|
const existingOrder = updatedList[matchIndex];
|
|
1135
|
-
const reconciledDraftOrder = this.preserveExistingBusinessCodeForDraft(
|
|
1136
|
-
existingOrder,
|
|
1137
|
-
draftOrder
|
|
1138
|
-
);
|
|
1129
|
+
const reconciledDraftOrder = this.preserveExistingBusinessCodeForDraft(existingOrder, draftOrder);
|
|
1139
1130
|
const mergedOrder = this.mergeOrderRecords(existingOrder, reconciledDraftOrder);
|
|
1140
1131
|
const nextOrder = {
|
|
1141
1132
|
...mergedOrder,
|
|
@@ -1143,57 +1134,54 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1143
1134
|
is_draft_order: 1
|
|
1144
1135
|
};
|
|
1145
1136
|
updatedList[matchIndex] = nextOrder;
|
|
1137
|
+
// SQLite 必须与内存中的草稿保持同一份 business_code,避免下次 hydrate 再次丢失分类。
|
|
1146
1138
|
draftMap.set(storageKey, reconciledDraftOrder);
|
|
1147
1139
|
this.registerOrderIdentityKeys(identityKeyToIndex, nextOrder, matchIndex);
|
|
1148
|
-
mergeActions[storageKey] =
|
|
1140
|
+
mergeActions[storageKey] = 'update';
|
|
1149
1141
|
continue;
|
|
1150
1142
|
}
|
|
1151
1143
|
const insertIndex = updatedList.length;
|
|
1152
1144
|
updatedList.push(draftOrder);
|
|
1153
1145
|
this.registerOrderIdentityKeys(identityKeyToIndex, draftOrder, insertIndex);
|
|
1154
|
-
mergeActions[storageKey] =
|
|
1146
|
+
mergeActions[storageKey] = 'insert';
|
|
1155
1147
|
}
|
|
1156
1148
|
const patchedOrders = [...draftMap.values()];
|
|
1157
1149
|
const previousList = this.store.list;
|
|
1158
|
-
this.store.list = this.runOrderStoreSelfCheck(updatedList,
|
|
1150
|
+
this.store.list = this.runOrderStoreSelfCheck(updatedList, 'upsertLocalDraftOrders.store');
|
|
1159
1151
|
this.syncOrdersMap();
|
|
1160
1152
|
try {
|
|
1161
|
-
await this.patchOrdersInSQLite(
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
mergeActions,
|
|
1165
|
-
{ throwOnError: true }
|
|
1166
|
-
);
|
|
1153
|
+
await this.patchOrdersInSQLite(patchedOrders, 'upsertLocalDraftOrders', mergeActions, {
|
|
1154
|
+
throwOnError: true
|
|
1155
|
+
});
|
|
1167
1156
|
} catch (error) {
|
|
1168
1157
|
this.store.list = previousList;
|
|
1169
1158
|
this.syncOrdersMap();
|
|
1170
1159
|
throw error;
|
|
1171
1160
|
}
|
|
1172
|
-
this.logInfo(
|
|
1161
|
+
this.logInfo('upsertLocalDraftOrders-结束', {
|
|
1173
1162
|
count: patchedOrders.length,
|
|
1174
1163
|
storeOrderCountAfter: this.store.list.length
|
|
1175
1164
|
});
|
|
1176
|
-
const removedLegacyMemoryDraft = previousList.some(
|
|
1177
|
-
(order) => !this.shouldKeepOrderInMemory(order)
|
|
1178
|
-
);
|
|
1165
|
+
const removedLegacyMemoryDraft = previousList.some(order => !this.shouldKeepOrderInMemory(order));
|
|
1179
1166
|
if (memoryDraftMap.size > 0 || removedLegacyMemoryDraft) {
|
|
1180
|
-
await this.emitOrdersChanged(
|
|
1181
|
-
patchedOrders.filter((order) => this.shouldKeepOrderInMemory(order)),
|
|
1182
|
-
"upsertLocalDraftOrders"
|
|
1183
|
-
);
|
|
1167
|
+
await this.emitOrdersChanged(patchedOrders.filter(order => this.shouldKeepOrderInMemory(order)), 'upsertLocalDraftOrders');
|
|
1184
1168
|
}
|
|
1185
1169
|
}
|
|
1170
|
+
|
|
1186
1171
|
/**
|
|
1187
1172
|
* 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
|
|
1188
1173
|
*/
|
|
1189
1174
|
async fetchOrdersBySSE(query = {}) {
|
|
1190
|
-
if (!this.orderDataSource)
|
|
1191
|
-
return [];
|
|
1175
|
+
if (!this.orderDataSource) return [];
|
|
1192
1176
|
try {
|
|
1193
|
-
const data = await this.orderDataSource.run({
|
|
1177
|
+
const data = await this.orderDataSource.run({
|
|
1178
|
+
sse: {
|
|
1179
|
+
query
|
|
1180
|
+
}
|
|
1181
|
+
});
|
|
1194
1182
|
return data || [];
|
|
1195
1183
|
} catch (error) {
|
|
1196
|
-
this.logError(
|
|
1184
|
+
this.logError('fetchOrdersBySSE-失败', {
|
|
1197
1185
|
error: error instanceof Error ? error.message : String(error)
|
|
1198
1186
|
});
|
|
1199
1187
|
return [];
|
|
@@ -1203,30 +1191,28 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1203
1191
|
return [];
|
|
1204
1192
|
}
|
|
1205
1193
|
destroy() {
|
|
1206
|
-
var _a;
|
|
1207
1194
|
if (this.syncTimer) {
|
|
1208
1195
|
clearTimeout(this.syncTimer);
|
|
1209
|
-
this.syncTimer =
|
|
1196
|
+
this.syncTimer = undefined;
|
|
1210
1197
|
}
|
|
1211
1198
|
this.isProcessingSyncBatch = false;
|
|
1212
1199
|
this.pendingSyncMessages = [];
|
|
1213
|
-
|
|
1214
|
-
|
|
1200
|
+
this.recentSqliteWriteByStorageKey.clear();
|
|
1201
|
+
this.lastRecentSqliteWriteCleanupAtMs = 0;
|
|
1202
|
+
if (this.orderDataSource?.destroy) this.orderDataSource.destroy();
|
|
1215
1203
|
super.destroy();
|
|
1216
1204
|
}
|
|
1217
1205
|
syncOrdersMap() {
|
|
1218
|
-
this.store.list = this.store.list.filter(
|
|
1206
|
+
this.store.list = this.store.list.filter(order => this.shouldKeepOrderInMemory(order));
|
|
1219
1207
|
this.store.map.clear();
|
|
1220
1208
|
for (const order of this.store.list) {
|
|
1221
1209
|
const primaryIdentity = this.getOrderMapKey(order);
|
|
1222
|
-
if (!primaryIdentity)
|
|
1223
|
-
continue;
|
|
1210
|
+
if (!primaryIdentity) continue;
|
|
1224
1211
|
this.store.map.set(primaryIdentity, order);
|
|
1225
1212
|
}
|
|
1226
1213
|
}
|
|
1227
1214
|
getOrderMapKey(order) {
|
|
1228
|
-
if (!order)
|
|
1229
|
-
return "";
|
|
1215
|
+
if (!order) return '';
|
|
1230
1216
|
if (!this.isBlankIdentityValue(order.order_id)) {
|
|
1231
1217
|
return this.getIdKey(order.order_id);
|
|
1232
1218
|
}
|
|
@@ -1234,11 +1220,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1234
1220
|
if (!this.isBlankIdentityValue(externalSaleNumber)) {
|
|
1235
1221
|
return this.getIdKey(externalSaleNumber);
|
|
1236
1222
|
}
|
|
1237
|
-
return
|
|
1223
|
+
return '';
|
|
1238
1224
|
}
|
|
1239
1225
|
isBlankIdentityValue(value) {
|
|
1240
|
-
return value ===
|
|
1226
|
+
return value === undefined || value === null || value === '';
|
|
1241
1227
|
}
|
|
1228
|
+
|
|
1242
1229
|
/**
|
|
1243
1230
|
* `/sales/draft` 的旧调用方可能把未设置的 business_code 传成空串。
|
|
1244
1231
|
* 对同一真实订单,空值不能覆盖已有的分类,否则 booking 查询会把该订单从 Party 列表过滤掉。
|
|
@@ -1246,92 +1233,85 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1246
1233
|
preserveExistingBusinessCodeForDraft(existingOrder, draftOrder) {
|
|
1247
1234
|
const existingBusinessCode = existingOrder.business_code;
|
|
1248
1235
|
const draftBusinessCode = draftOrder.business_code;
|
|
1249
|
-
const hasExistingBusinessCode = typeof existingBusinessCode ===
|
|
1250
|
-
const hasDraftBusinessCode = typeof draftBusinessCode ===
|
|
1251
|
-
if (!hasExistingBusinessCode || hasDraftBusinessCode)
|
|
1252
|
-
return draftOrder;
|
|
1236
|
+
const hasExistingBusinessCode = typeof existingBusinessCode === 'string' && existingBusinessCode.trim() !== '';
|
|
1237
|
+
const hasDraftBusinessCode = typeof draftBusinessCode === 'string' && draftBusinessCode.trim() !== '';
|
|
1238
|
+
if (!hasExistingBusinessCode || hasDraftBusinessCode) return draftOrder;
|
|
1253
1239
|
return {
|
|
1254
1240
|
...draftOrder,
|
|
1255
1241
|
business_code: existingBusinessCode
|
|
1256
1242
|
};
|
|
1257
1243
|
}
|
|
1258
1244
|
getOrderIdentityEntries(order) {
|
|
1259
|
-
if (!order)
|
|
1260
|
-
return [];
|
|
1245
|
+
if (!order) return [];
|
|
1261
1246
|
const record = order;
|
|
1262
|
-
const candidates = [
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1247
|
+
const candidates = [{
|
|
1248
|
+
field: 'order_id',
|
|
1249
|
+
value: order.order_id
|
|
1250
|
+
}, {
|
|
1251
|
+
field: 'external_sale_number',
|
|
1252
|
+
value: record.external_sale_number
|
|
1253
|
+
}, {
|
|
1254
|
+
field: 'order_number',
|
|
1255
|
+
value: record.order_number
|
|
1256
|
+
}, {
|
|
1257
|
+
field: 'shop_order_number',
|
|
1258
|
+
value: record.shop_order_number
|
|
1259
|
+
}];
|
|
1268
1260
|
const entries = [];
|
|
1269
1261
|
for (const candidate of candidates) {
|
|
1270
|
-
if (this.isBlankIdentityValue(candidate.value))
|
|
1271
|
-
continue;
|
|
1262
|
+
if (this.isBlankIdentityValue(candidate.value)) continue;
|
|
1272
1263
|
const key = this.getIdKey(candidate.value);
|
|
1273
|
-
if (entries.some(
|
|
1274
|
-
|
|
1275
|
-
|
|
1264
|
+
if (entries.some(entry => entry.field === candidate.field && entry.key === key)) continue;
|
|
1265
|
+
entries.push({
|
|
1266
|
+
field: candidate.field,
|
|
1267
|
+
key
|
|
1268
|
+
});
|
|
1276
1269
|
}
|
|
1277
1270
|
return entries;
|
|
1278
1271
|
}
|
|
1279
1272
|
getOrderIdentityKeys(order) {
|
|
1280
1273
|
const keys = [];
|
|
1281
1274
|
for (const entry of this.getOrderIdentityEntries(order)) {
|
|
1282
|
-
if (!keys.includes(entry.key))
|
|
1283
|
-
keys.push(entry.key);
|
|
1275
|
+
if (!keys.includes(entry.key)) keys.push(entry.key);
|
|
1284
1276
|
}
|
|
1285
1277
|
return keys;
|
|
1286
1278
|
}
|
|
1287
1279
|
getOrderDateKey(order) {
|
|
1288
|
-
|
|
1289
|
-
const candidates = [
|
|
1290
|
-
order == null ? void 0 : order.schedule_date,
|
|
1291
|
-
order == null ? void 0 : order.create_date,
|
|
1292
|
-
order == null ? void 0 : order.created_at,
|
|
1293
|
-
(_b = (_a = order == null ? void 0 : order.bookings) == null ? void 0 : _a[0]) == null ? void 0 : _b.start_date,
|
|
1294
|
-
(_d = (_c = order == null ? void 0 : order.bookings) == null ? void 0 : _c[0]) == null ? void 0 : _d.select_date
|
|
1295
|
-
];
|
|
1280
|
+
const candidates = [order?.schedule_date, order?.create_date, order?.created_at, order?.bookings?.[0]?.start_date, order?.bookings?.[0]?.select_date];
|
|
1296
1281
|
for (const v of candidates) {
|
|
1297
|
-
if (!v)
|
|
1298
|
-
continue;
|
|
1282
|
+
if (!v) continue;
|
|
1299
1283
|
const text = String(v);
|
|
1300
|
-
if (!text)
|
|
1301
|
-
|
|
1302
|
-
return text.split("T")[0].split(" ")[0];
|
|
1284
|
+
if (!text) continue;
|
|
1285
|
+
return text.split('T')[0].split(' ')[0];
|
|
1303
1286
|
}
|
|
1304
|
-
return
|
|
1287
|
+
return undefined;
|
|
1305
1288
|
}
|
|
1289
|
+
|
|
1306
1290
|
/**
|
|
1307
1291
|
* 初始化 OrderDataSource 实例
|
|
1308
1292
|
*/
|
|
1309
1293
|
initOrderDataSource() {
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
if (!OrderDataSourceClass)
|
|
1313
|
-
return;
|
|
1294
|
+
const OrderDataSourceClass = this.core.serverOptions?.All_DATA_SOURCES?.OrderDataSource;
|
|
1295
|
+
if (!OrderDataSourceClass) return;
|
|
1314
1296
|
this.orderDataSource = new OrderDataSourceClass();
|
|
1315
1297
|
}
|
|
1298
|
+
|
|
1316
1299
|
/**
|
|
1317
1300
|
* 初始化 pubsub 订阅,监听订单变更(纯订阅,不拉数据;全量 SSE 由 loadOrdersByServer 负责)
|
|
1318
1301
|
*/
|
|
1319
1302
|
setupOrderSync() {
|
|
1320
|
-
if (!this.orderDataSource)
|
|
1321
|
-
return;
|
|
1303
|
+
if (!this.orderDataSource) return;
|
|
1322
1304
|
this.orderDataSource.run({
|
|
1323
1305
|
pubsub: {
|
|
1324
|
-
callback:
|
|
1325
|
-
console.log("orderDataSource", res);
|
|
1306
|
+
callback: res => {
|
|
1326
1307
|
const pubsubReceivedAt = Date.now();
|
|
1327
1308
|
const message = this.normalizeOrderSyncMessage(res);
|
|
1328
|
-
if (!message)
|
|
1329
|
-
return;
|
|
1309
|
+
if (!message) return;
|
|
1330
1310
|
message._pubsubReceivedAt = pubsubReceivedAt;
|
|
1331
1311
|
this.pendingSyncMessages.push(message);
|
|
1332
1312
|
const throttleMs = this.getOrderSyncThrottleMs();
|
|
1333
1313
|
const routeInfo = this.resolveSyncMessageRoute(message);
|
|
1334
|
-
this.logInfo(
|
|
1314
|
+
this.logInfo('orderSync-收到消息并入队', {
|
|
1335
1315
|
id: message.id ?? null,
|
|
1336
1316
|
order_id: message.order_id ?? null,
|
|
1337
1317
|
type: message.type ?? null,
|
|
@@ -1344,8 +1324,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1344
1324
|
}
|
|
1345
1325
|
}
|
|
1346
1326
|
}).catch(() => {
|
|
1327
|
+
// 忽略同步初始化异常,避免影响主流程
|
|
1347
1328
|
});
|
|
1348
1329
|
}
|
|
1330
|
+
|
|
1349
1331
|
/**
|
|
1350
1332
|
* 调度订单同步节流窗口(leading-edge throttle):
|
|
1351
1333
|
* - 空闲状态下收到的第一条消息立即触发批处理,无需等待;
|
|
@@ -1353,29 +1335,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1353
1335
|
* - 若当前批处理执行中,则由批处理结束后决定是否开启下一轮窗口。
|
|
1354
1336
|
*/
|
|
1355
1337
|
scheduleOrderSyncThrottle() {
|
|
1356
|
-
if (this.isProcessingSyncBatch)
|
|
1357
|
-
return;
|
|
1338
|
+
if (this.isProcessingSyncBatch) return;
|
|
1358
1339
|
if (this.isIdlePhase) {
|
|
1359
1340
|
this.isIdlePhase = false;
|
|
1360
|
-
this.logInfo(
|
|
1341
|
+
this.logInfo('orderSync-首条消息立即触发处理');
|
|
1361
1342
|
void this.flushOrderSyncMessagesByThrottle();
|
|
1362
1343
|
return;
|
|
1363
1344
|
}
|
|
1364
|
-
if (this.syncTimer)
|
|
1365
|
-
return;
|
|
1345
|
+
if (this.syncTimer) return;
|
|
1366
1346
|
const throttleMs = this.getOrderSyncThrottleMs();
|
|
1367
1347
|
this.syncTimer = setTimeout(() => {
|
|
1368
|
-
this.syncTimer =
|
|
1348
|
+
this.syncTimer = undefined;
|
|
1369
1349
|
void this.flushOrderSyncMessagesByThrottle();
|
|
1370
1350
|
}, throttleMs);
|
|
1371
1351
|
}
|
|
1352
|
+
|
|
1372
1353
|
/**
|
|
1373
1354
|
* 执行一次节流批处理并在需要时续约下一轮窗口。
|
|
1374
1355
|
* 批处理完成且无后续消息时恢复空闲状态,下一条消息将立即触发。
|
|
1375
1356
|
*/
|
|
1376
1357
|
async flushOrderSyncMessagesByThrottle() {
|
|
1377
|
-
if (this.isProcessingSyncBatch)
|
|
1378
|
-
return;
|
|
1358
|
+
if (this.isProcessingSyncBatch) return;
|
|
1379
1359
|
if (this.pendingSyncMessages.length === 0) {
|
|
1380
1360
|
this.isIdlePhase = true;
|
|
1381
1361
|
return;
|
|
@@ -1392,6 +1372,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1392
1372
|
}
|
|
1393
1373
|
}
|
|
1394
1374
|
}
|
|
1375
|
+
|
|
1395
1376
|
/**
|
|
1396
1377
|
* 处理节流窗口内聚合后的同步消息批次
|
|
1397
1378
|
*
|
|
@@ -1406,19 +1387,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1406
1387
|
async processOrderSyncMessages() {
|
|
1407
1388
|
const messages = [...this.pendingSyncMessages];
|
|
1408
1389
|
this.pendingSyncMessages = [];
|
|
1409
|
-
if (messages.length === 0)
|
|
1410
|
-
return;
|
|
1390
|
+
if (messages.length === 0) return;
|
|
1411
1391
|
const batchProcessStartAt = Date.now();
|
|
1412
|
-
const earliestReceivedAt = Math.min(
|
|
1413
|
-
|
|
1414
|
-
);
|
|
1415
|
-
this.logInfo("processOrderSyncMessages-开始", {
|
|
1392
|
+
const earliestReceivedAt = Math.min(...messages.map(m => m._pubsubReceivedAt ?? batchProcessStartAt));
|
|
1393
|
+
this.logInfo('processOrderSyncMessages-开始', {
|
|
1416
1394
|
messageCount: messages.length,
|
|
1417
1395
|
earliestReceivedAt: new Date(earliestReceivedAt).toISOString(),
|
|
1418
1396
|
batchProcessStartAt: new Date(batchProcessStartAt).toISOString(),
|
|
1419
1397
|
waitDurationMs: batchProcessStartAt - earliestReceivedAt
|
|
1420
1398
|
});
|
|
1421
|
-
const upsertOrders =
|
|
1399
|
+
const upsertOrders = new Map();
|
|
1422
1400
|
const refreshIds = [];
|
|
1423
1401
|
messages.forEach((msg, msgIndex) => {
|
|
1424
1402
|
const routeInfo = this.resolveSyncMessageRoute(msg);
|
|
@@ -1426,50 +1404,47 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1426
1404
|
const singleId = routeInfo.singleId;
|
|
1427
1405
|
const hasSingleId = routeInfo.hasSingleId;
|
|
1428
1406
|
const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
|
|
1429
|
-
if (routeInfo.route ===
|
|
1407
|
+
if (routeInfo.route === 'bodyUpsert' && normalizedBody) {
|
|
1430
1408
|
upsertOrders.set(this.getIdKey(normalizedBody.order_id), normalizedBody);
|
|
1431
1409
|
return;
|
|
1432
1410
|
}
|
|
1433
|
-
if (hasBatchIds)
|
|
1434
|
-
refreshIds.push(...routeInfo.batchIds);
|
|
1435
|
-
else if (routeInfo.route === "httpRefresh.singleId" && singleId !== null)
|
|
1436
|
-
refreshIds.push(singleId);
|
|
1437
|
-
else if (routeInfo.route === "httpRefresh.relationIds")
|
|
1438
|
-
refreshIds.push(...routeInfo.batchIds);
|
|
1411
|
+
if (hasBatchIds) refreshIds.push(...routeInfo.batchIds);else if (routeInfo.route === 'httpRefresh.singleId' && singleId !== null) refreshIds.push(singleId);else if (routeInfo.route === 'httpRefresh.relationIds') refreshIds.push(...routeInfo.batchIds);
|
|
1439
1412
|
});
|
|
1440
1413
|
const uniqueRefreshIds = this.uniqueOrderIds(refreshIds);
|
|
1441
1414
|
const upsertList = [...upsertOrders.values()];
|
|
1442
|
-
this.logInfo(
|
|
1415
|
+
this.logInfo('processOrderSyncMessages-去重完成', {
|
|
1443
1416
|
upsertCount: upsertList.length,
|
|
1444
1417
|
refreshIdCount: uniqueRefreshIds.length
|
|
1445
1418
|
});
|
|
1446
1419
|
if (upsertList.length > 0) {
|
|
1447
|
-
await this.mergeOrdersToStore(upsertList,
|
|
1420
|
+
await this.mergeOrdersToStore(upsertList, 'pubsub.bodyUpsert');
|
|
1448
1421
|
}
|
|
1449
1422
|
if (uniqueRefreshIds.length > 0) {
|
|
1450
|
-
const {
|
|
1451
|
-
|
|
1452
|
-
|
|
1423
|
+
const {
|
|
1424
|
+
toFetch,
|
|
1425
|
+
skipped
|
|
1426
|
+
} = this.filterRedundantHttpRefreshIds(uniqueRefreshIds);
|
|
1427
|
+
if (skipped.length > 0) {}
|
|
1453
1428
|
if (toFetch.length > 0) {
|
|
1454
1429
|
const freshOrders = await this.fetchOrdersByHttp(toFetch);
|
|
1455
1430
|
if (freshOrders.length > 0) {
|
|
1456
|
-
await this.mergeOrdersToStore(freshOrders,
|
|
1457
|
-
} else {
|
|
1458
|
-
}
|
|
1431
|
+
await this.mergeOrdersToStore(freshOrders, 'pubsub.httpRefresh');
|
|
1432
|
+
} else {}
|
|
1459
1433
|
}
|
|
1460
1434
|
}
|
|
1461
1435
|
if (upsertList.length === 0 && uniqueRefreshIds.length === 0) {
|
|
1462
1436
|
return;
|
|
1463
1437
|
}
|
|
1464
1438
|
const batchProcessEndAt = Date.now();
|
|
1465
|
-
this.logInfo(
|
|
1439
|
+
this.logInfo('processOrderSyncMessages-结束', {
|
|
1466
1440
|
upsertCount: upsertList.length,
|
|
1467
1441
|
refreshIdCount: uniqueRefreshIds.length,
|
|
1468
1442
|
batchProcessDurationMs: batchProcessEndAt - batchProcessStartAt,
|
|
1469
1443
|
totalFromPubsubToProcessedMs: batchProcessEndAt - earliestReceivedAt
|
|
1470
1444
|
});
|
|
1471
|
-
await this.core.effects.emit(
|
|
1445
|
+
await this.core.effects.emit(_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
1472
1446
|
}
|
|
1447
|
+
|
|
1473
1448
|
/**
|
|
1474
1449
|
* 通过 HTTP 按 ids 批量拉取订单详情(走 orderDataSource)。
|
|
1475
1450
|
*
|
|
@@ -1481,16 +1456,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1481
1456
|
* const fresh = await orderModule.fetchOrdersByHttp(['96971', '96972'])
|
|
1482
1457
|
*/
|
|
1483
1458
|
async fetchOrdersByHttp(ids) {
|
|
1484
|
-
if (!this.orderDataSource || ids.length === 0)
|
|
1485
|
-
return [];
|
|
1459
|
+
if (!this.orderDataSource || ids.length === 0) return [];
|
|
1486
1460
|
try {
|
|
1487
|
-
if (typeof this.orderDataSource.fetchOrdersByIds ===
|
|
1488
|
-
const
|
|
1489
|
-
return
|
|
1461
|
+
if (typeof this.orderDataSource.fetchOrdersByIds === 'function') {
|
|
1462
|
+
const orderList = await this.orderDataSource.fetchOrdersByIds(ids);
|
|
1463
|
+
return orderList || [];
|
|
1490
1464
|
}
|
|
1491
1465
|
const orderList = await this.orderDataSource.run({
|
|
1492
1466
|
http: {
|
|
1493
|
-
query: {
|
|
1467
|
+
query: {
|
|
1468
|
+
ids
|
|
1469
|
+
}
|
|
1494
1470
|
}
|
|
1495
1471
|
});
|
|
1496
1472
|
return orderList || [];
|
|
@@ -1498,70 +1474,63 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1498
1474
|
return [];
|
|
1499
1475
|
}
|
|
1500
1476
|
}
|
|
1477
|
+
|
|
1501
1478
|
/**
|
|
1502
1479
|
* 将增量订单合并到 store
|
|
1503
1480
|
*/
|
|
1504
1481
|
async mergeOrdersToStore(freshOrders, source) {
|
|
1505
1482
|
const storeOrderCountBefore = this.store.list.length;
|
|
1506
|
-
this.logInfo(
|
|
1483
|
+
this.logInfo('mergeOrdersToStore-开始', {
|
|
1507
1484
|
freshOrderCount: freshOrders.length,
|
|
1508
1485
|
storeOrderCountBefore,
|
|
1509
1486
|
source
|
|
1510
1487
|
});
|
|
1511
1488
|
this.logDuplicateOrders(`${source}.beforeMerge`, this.store.list);
|
|
1512
1489
|
const normalizedFreshOrders = [];
|
|
1513
|
-
const incomingProductsHaveStableIdentity =
|
|
1490
|
+
const incomingProductsHaveStableIdentity = new Map();
|
|
1514
1491
|
for (const order of freshOrders) {
|
|
1515
|
-
const id = order
|
|
1516
|
-
if (id ===
|
|
1517
|
-
continue;
|
|
1492
|
+
const id = order?.order_id;
|
|
1493
|
+
if (id === undefined || id === null) continue;
|
|
1518
1494
|
const rawProducts = order.products;
|
|
1519
1495
|
if (Array.isArray(rawProducts)) {
|
|
1520
1496
|
const allProductsHaveStableIdentity = this.doProductsHaveStableMembershipIdentity(rawProducts);
|
|
1521
1497
|
const orderIdKey = this.getIdKey(id);
|
|
1522
|
-
incomingProductsHaveStableIdentity.set(
|
|
1523
|
-
orderIdKey,
|
|
1524
|
-
(incomingProductsHaveStableIdentity.get(orderIdKey) ?? true) && allProductsHaveStableIdentity
|
|
1525
|
-
);
|
|
1498
|
+
incomingProductsHaveStableIdentity.set(orderIdKey, (incomingProductsHaveStableIdentity.get(orderIdKey) ?? true) && allProductsHaveStableIdentity);
|
|
1526
1499
|
}
|
|
1527
1500
|
normalizedFreshOrders.push(this.normalizeRemoteSyncedOrder(order));
|
|
1528
1501
|
}
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
`${source}.incoming`
|
|
1532
|
-
).list;
|
|
1502
|
+
// 先对本批新单做去重(批内规模 m 很小),保证每条 fresh 身份唯一
|
|
1503
|
+
const uniqueFreshOrders = this.compactOrderListByIdentity(normalizedFreshOrders, `${source}.incoming`).list;
|
|
1533
1504
|
const uniqueFreshCount = uniqueFreshOrders.length;
|
|
1534
1505
|
const patchedOrders = [];
|
|
1535
1506
|
const remoteProductMembershipChanges = [];
|
|
1536
|
-
const forceWriteStorageKeys =
|
|
1507
|
+
const forceWriteStorageKeys = new Set();
|
|
1537
1508
|
const storageKeyMigrations = [];
|
|
1538
1509
|
const mergeActions = {};
|
|
1539
|
-
const existingProductsHaveStableIdentity = this.store.list.map(
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
)
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
);
|
|
1547
|
-
const identityKeyToIndex = /* @__PURE__ */ new Map();
|
|
1510
|
+
const existingProductsHaveStableIdentity = this.store.list.map(order => this.doProductsHaveStableMembershipIdentity(order.products));
|
|
1511
|
+
const updatedList = this.store.list.map(order => this.normalizeOrderForMemoryList(order, `${source}.existingMemory`));
|
|
1512
|
+
|
|
1513
|
+
// 基于身份键(field:value)建立索引,把「查找已存在订单」从 O(n) 线性扫描降为 O(1),
|
|
1514
|
+
// 整体合并复杂度由 O(n^2) 降为 O(n + m)。索引语义与 doOrdersShareIdentity 完全一致:
|
|
1515
|
+
// 任一身份字段(order_id/external_sale_number/order_number/shop_order_number)同值即同一单。
|
|
1516
|
+
const identityKeyToIndex = new Map();
|
|
1548
1517
|
for (let index = 0; index < updatedList.length; index += 1) {
|
|
1549
1518
|
const identityKeys = this.getOrderIdentityMatchKeys(updatedList[index]);
|
|
1550
1519
|
for (const key of identityKeys) {
|
|
1551
|
-
|
|
1552
|
-
|
|
1520
|
+
// 同一 key 命中多张时保留最靠前的下标,与原 findIndex「取首个匹配」一致
|
|
1521
|
+
if (!identityKeyToIndex.has(key)) identityKeyToIndex.set(key, index);
|
|
1553
1522
|
}
|
|
1554
1523
|
}
|
|
1555
1524
|
for (const fresh of uniqueFreshOrders) {
|
|
1556
1525
|
const freshIdentityKeys = this.getOrderIdentityMatchKeys(fresh);
|
|
1557
1526
|
const matchIndex = this.lookupOrderIndexByIdentityKeys(identityKeyToIndex, freshIdentityKeys);
|
|
1558
1527
|
const storageKey = this.getOrderStorageKey(fresh);
|
|
1559
|
-
const mergeKey = storageKey || (fresh.order_id !==
|
|
1528
|
+
const mergeKey = storageKey || (fresh.order_id !== undefined && fresh.order_id !== null ? this.getIdKey(fresh.order_id) : '');
|
|
1560
1529
|
if (matchIndex >= 0) {
|
|
1561
1530
|
const existingOrder = updatedList[matchIndex];
|
|
1562
1531
|
const previousStorageKey = this.getPersistedOrderStorageKey(existingOrder);
|
|
1563
1532
|
if (this.isPendingSyncOrder(existingOrder) && this.isRemoteEchoMergeSource(source)) {
|
|
1564
|
-
this.logInfo(
|
|
1533
|
+
this.logInfo('mergeOrdersToStore-跳过 pending 订单远端覆盖', {
|
|
1565
1534
|
source,
|
|
1566
1535
|
order_id: existingOrder.order_id ?? fresh.order_id ?? null,
|
|
1567
1536
|
external_sale_number: existingOrder.external_sale_number ?? fresh.external_sale_number ?? null,
|
|
@@ -1569,39 +1538,34 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1569
1538
|
remote_payment_status: fresh.payment_status ?? null,
|
|
1570
1539
|
local_need_sync: existingOrder.need_sync ?? null,
|
|
1571
1540
|
remote_need_sync: fresh.need_sync ?? null,
|
|
1572
|
-
reason:
|
|
1541
|
+
reason: 'protect_pending_sync_order_from_remote_echo'
|
|
1573
1542
|
});
|
|
1574
1543
|
continue;
|
|
1575
1544
|
}
|
|
1576
1545
|
if (this.isDraftOrder(existingOrder) && this.shouldProtectDraftOrderFromIncoming(source)) {
|
|
1577
|
-
this.logInfo(
|
|
1546
|
+
this.logInfo('mergeOrdersToStore-跳过 draft 订单远端覆盖', {
|
|
1578
1547
|
source,
|
|
1579
1548
|
order_id: existingOrder.order_id ?? fresh.order_id ?? null,
|
|
1580
1549
|
external_sale_number: existingOrder.external_sale_number ?? fresh.external_sale_number ?? null,
|
|
1581
1550
|
local_is_draft_order: existingOrder.is_draft_order ?? null,
|
|
1582
1551
|
remote_is_draft_order: fresh.is_draft_order ?? null,
|
|
1583
|
-
reason:
|
|
1552
|
+
reason: 'protect_draft_order_from_remote_echo'
|
|
1584
1553
|
});
|
|
1585
1554
|
continue;
|
|
1586
1555
|
}
|
|
1587
1556
|
let mergedOrder = this.mergeOrderRecords(existingOrder, fresh);
|
|
1588
1557
|
const freshOrderId = fresh.order_id;
|
|
1589
|
-
const incomingProductsAreStable = freshOrderId !==
|
|
1558
|
+
const incomingProductsAreStable = freshOrderId !== undefined && freshOrderId !== null && incomingProductsHaveStableIdentity.get(this.getIdKey(freshOrderId)) !== false;
|
|
1590
1559
|
let membershipChange = null;
|
|
1591
|
-
if (Array.isArray(fresh.products) && freshOrderId !==
|
|
1592
|
-
membershipChange = this.getRemoteProductMembershipChange(
|
|
1593
|
-
existingOrder,
|
|
1594
|
-
mergedOrder,
|
|
1595
|
-
source
|
|
1596
|
-
);
|
|
1560
|
+
if (Array.isArray(fresh.products) && freshOrderId !== undefined && freshOrderId !== null && existingProductsHaveStableIdentity[matchIndex] !== false && incomingProductsAreStable) {
|
|
1561
|
+
membershipChange = this.getRemoteProductMembershipChange(existingOrder, mergedOrder, source);
|
|
1597
1562
|
}
|
|
1598
1563
|
let mergedProductsHaveStableIdentity = existingProductsHaveStableIdentity[matchIndex] !== false && incomingProductsAreStable;
|
|
1599
1564
|
let adjustedMatchIndex = matchIndex;
|
|
1600
|
-
const duplicateIndexes =
|
|
1565
|
+
const duplicateIndexes = new Set();
|
|
1601
1566
|
for (const key of freshIdentityKeys) {
|
|
1602
1567
|
const duplicateIndex = identityKeyToIndex.get(key);
|
|
1603
|
-
if (duplicateIndex ===
|
|
1604
|
-
continue;
|
|
1568
|
+
if (duplicateIndex === undefined || duplicateIndex === matchIndex) continue;
|
|
1605
1569
|
duplicateIndexes.add(duplicateIndex);
|
|
1606
1570
|
}
|
|
1607
1571
|
if (duplicateIndexes.size > 0) {
|
|
@@ -1610,14 +1574,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1610
1574
|
mergedProductsHaveStableIdentity = mergedProductsHaveStableIdentity && existingProductsHaveStableIdentity[duplicateIndex] !== false;
|
|
1611
1575
|
updatedList.splice(duplicateIndex, 1);
|
|
1612
1576
|
existingProductsHaveStableIdentity.splice(duplicateIndex, 1);
|
|
1613
|
-
if (duplicateIndex < adjustedMatchIndex)
|
|
1614
|
-
adjustedMatchIndex -= 1;
|
|
1577
|
+
if (duplicateIndex < adjustedMatchIndex) adjustedMatchIndex -= 1;
|
|
1615
1578
|
}
|
|
1616
1579
|
identityKeyToIndex.clear();
|
|
1617
1580
|
for (let index = 0; index < updatedList.length; index += 1) {
|
|
1618
1581
|
for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
|
|
1619
|
-
if (!identityKeyToIndex.has(key))
|
|
1620
|
-
identityKeyToIndex.set(key, index);
|
|
1582
|
+
if (!identityKeyToIndex.has(key)) identityKeyToIndex.set(key, index);
|
|
1621
1583
|
}
|
|
1622
1584
|
}
|
|
1623
1585
|
}
|
|
@@ -1634,42 +1596,37 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1634
1596
|
if (membershipChange) {
|
|
1635
1597
|
remoteProductMembershipChanges.push(membershipChange);
|
|
1636
1598
|
const mergedStorageKey = this.getOrderStorageKey(mergedOrder);
|
|
1637
|
-
if (mergedStorageKey)
|
|
1638
|
-
forceWriteStorageKeys.add(mergedStorageKey);
|
|
1599
|
+
if (mergedStorageKey) forceWriteStorageKeys.add(mergedStorageKey);
|
|
1639
1600
|
}
|
|
1601
|
+
// 合并后身份字段可能新增(如挂单拿到 order_id),同步登记到索引,
|
|
1602
|
+
// 供同批后续 fresh 命中同一槽位,避免重复插入
|
|
1640
1603
|
this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, adjustedMatchIndex);
|
|
1641
1604
|
patchedOrders.push(mergedOrder);
|
|
1642
|
-
if (mergeKey)
|
|
1643
|
-
mergeActions[mergeKey] = "update";
|
|
1605
|
+
if (mergeKey) mergeActions[mergeKey] = 'update';
|
|
1644
1606
|
continue;
|
|
1645
1607
|
}
|
|
1646
1608
|
const insertIndex = updatedList.length;
|
|
1647
1609
|
updatedList.push(fresh);
|
|
1648
|
-
existingProductsHaveStableIdentity.push(
|
|
1649
|
-
fresh.order_id !== void 0 && fresh.order_id !== null && incomingProductsHaveStableIdentity.get(this.getIdKey(fresh.order_id)) !== false
|
|
1650
|
-
);
|
|
1610
|
+
existingProductsHaveStableIdentity.push(fresh.order_id !== undefined && fresh.order_id !== null && incomingProductsHaveStableIdentity.get(this.getIdKey(fresh.order_id)) !== false);
|
|
1651
1611
|
this.registerOrderIdentityKeys(identityKeyToIndex, fresh, insertIndex);
|
|
1652
1612
|
patchedOrders.push(fresh);
|
|
1653
|
-
if (mergeKey)
|
|
1654
|
-
mergeActions[mergeKey] = "insert";
|
|
1613
|
+
if (mergeKey) mergeActions[mergeKey] = 'insert';
|
|
1655
1614
|
}
|
|
1656
|
-
const insertCount = Object.values(mergeActions).filter(
|
|
1657
|
-
const updateCount = Object.values(mergeActions).filter(
|
|
1658
|
-
this.logInfo(
|
|
1615
|
+
const insertCount = Object.values(mergeActions).filter(v => v === 'insert').length;
|
|
1616
|
+
const updateCount = Object.values(mergeActions).filter(v => v === 'update').length;
|
|
1617
|
+
this.logInfo('mergeOrdersToStore-合并完成', {
|
|
1659
1618
|
insertCount,
|
|
1660
1619
|
updateCount,
|
|
1661
1620
|
storeOrderCountAfter: this.store.list.length
|
|
1662
1621
|
});
|
|
1622
|
+
// 增量索引已保证 store 去重不变量,无需再对全表做 O(n^2) 压缩;
|
|
1623
|
+
// 仅在自检开关开启时做一次兜底校验。
|
|
1663
1624
|
this.store.list = this.runOrderStoreSelfCheck(updatedList, `${source}.store`);
|
|
1664
1625
|
this.syncOrdersMap();
|
|
1665
|
-
await this.patchOrdersInSQLite(
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
{ storageKeyMigrations },
|
|
1670
|
-
forceWriteStorageKeys
|
|
1671
|
-
);
|
|
1672
|
-
this.logInfo("mergeOrdersToStore-结束", {
|
|
1626
|
+
await this.patchOrdersInSQLite(patchedOrders, source, mergeActions, {
|
|
1627
|
+
storageKeyMigrations
|
|
1628
|
+
}, forceWriteStorageKeys);
|
|
1629
|
+
this.logInfo('mergeOrdersToStore-结束', {
|
|
1673
1630
|
uniqueFreshCount,
|
|
1674
1631
|
storeOrderCountAfter: this.store.list.length,
|
|
1675
1632
|
insertCount,
|
|
@@ -1678,6 +1635,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1678
1635
|
await this.emitRemoteProductMembershipChanges(remoteProductMembershipChanges);
|
|
1679
1636
|
await this.emitOrdersChanged(patchedOrders, source);
|
|
1680
1637
|
}
|
|
1638
|
+
|
|
1681
1639
|
/**
|
|
1682
1640
|
* 在身份索引中查找与目标订单共享任一身份键的已存在订单下标。
|
|
1683
1641
|
* 返回所有命中键里最小的下标,等价于原 findOrderIndexByIdentity 的「取首个匹配」语义。
|
|
@@ -1689,76 +1647,64 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1689
1647
|
let matchIndex = -1;
|
|
1690
1648
|
for (const key of identityKeys) {
|
|
1691
1649
|
const index = identityKeyToIndex.get(key);
|
|
1692
|
-
if (index ===
|
|
1693
|
-
|
|
1694
|
-
if (matchIndex < 0 || index < matchIndex)
|
|
1695
|
-
matchIndex = index;
|
|
1650
|
+
if (index === undefined) continue;
|
|
1651
|
+
if (matchIndex < 0 || index < matchIndex) matchIndex = index;
|
|
1696
1652
|
}
|
|
1697
1653
|
return matchIndex;
|
|
1698
1654
|
}
|
|
1699
1655
|
isRemoteEchoMergeSource(source) {
|
|
1700
|
-
return source ===
|
|
1656
|
+
return source === 'pubsub.bodyUpsert' || source === 'pubsub.httpRefresh';
|
|
1701
1657
|
}
|
|
1702
1658
|
isRemoteProductMembershipChangeSource(source) {
|
|
1703
|
-
return this.isRemoteEchoMergeSource(source) || source ===
|
|
1659
|
+
return this.isRemoteEchoMergeSource(source) || source === 'manual.editOpenRemoteCheck';
|
|
1704
1660
|
}
|
|
1705
1661
|
getProductMembershipKey(product) {
|
|
1706
|
-
const persistentId = (0,
|
|
1707
|
-
if (persistentId)
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
return uid ? `unique_identification_number:${uid}` : "";
|
|
1662
|
+
const persistentId = (0, _orderCollectionIdentity.getOrderCollectionPersistentId)('product', product);
|
|
1663
|
+
if (persistentId) return `order_detail_id:${persistentId}`;
|
|
1664
|
+
const uid = (0, _orderCollectionIdentity.getOrderCollectionUid)('product', product);
|
|
1665
|
+
return uid ? `unique_identification_number:${uid}` : '';
|
|
1711
1666
|
}
|
|
1712
1667
|
doProductsHaveStableMembershipIdentity(products) {
|
|
1713
|
-
if (!Array.isArray(products))
|
|
1714
|
-
|
|
1715
|
-
return products.every(
|
|
1716
|
-
(product) => Boolean(
|
|
1717
|
-
(0, import_orderCollectionIdentity.getOrderCollectionPersistentId)("product", product) || (0, import_orderCollectionIdentity.getOrderCollectionUid)("product", product)
|
|
1718
|
-
)
|
|
1719
|
-
);
|
|
1668
|
+
if (!Array.isArray(products)) return true;
|
|
1669
|
+
return products.every(product => Boolean((0, _orderCollectionIdentity.getOrderCollectionPersistentId)('product', product) || (0, _orderCollectionIdentity.getOrderCollectionUid)('product', product)));
|
|
1720
1670
|
}
|
|
1671
|
+
|
|
1721
1672
|
/**
|
|
1722
1673
|
* 冲突提示关注逻辑商品行,而不是服务端 checkout 过程中可能被重建的 detail 记录。
|
|
1723
1674
|
* 通用集合合并仍以 order_detail_id 为事实主键;这里只允许相同稳定 UID 跨 detail id 对齐,
|
|
1724
1675
|
* 避免本机 checkout 回声被误判成“一删一增”。
|
|
1725
1676
|
*/
|
|
1726
1677
|
isSameProductMembershipItem(left, right) {
|
|
1727
|
-
if ((0,
|
|
1728
|
-
|
|
1729
|
-
const
|
|
1730
|
-
const rightUid = (0, import_orderCollectionIdentity.getOrderCollectionUid)("product", right);
|
|
1678
|
+
if ((0, _orderCollectionIdentity.isSameOrderCollectionItem)('product', left, right)) return true;
|
|
1679
|
+
const leftUid = (0, _orderCollectionIdentity.getOrderCollectionUid)('product', left);
|
|
1680
|
+
const rightUid = (0, _orderCollectionIdentity.getOrderCollectionUid)('product', right);
|
|
1731
1681
|
return Boolean(leftUid && rightUid && leftUid === rightUid);
|
|
1732
1682
|
}
|
|
1683
|
+
|
|
1733
1684
|
/**
|
|
1734
1685
|
* 对比合并前后的商品成员集合。商品字段修改与数组重排不会产生 diff。
|
|
1735
1686
|
*/
|
|
1736
1687
|
getRemoteProductMembershipChange(existingOrder, mergedOrder, source) {
|
|
1737
|
-
if (!this.isRemoteProductMembershipChangeSource(source))
|
|
1738
|
-
return null;
|
|
1688
|
+
if (!this.isRemoteProductMembershipChangeSource(source)) return null;
|
|
1739
1689
|
const previousProducts = Array.isArray(existingOrder.products) ? existingOrder.products : [];
|
|
1740
1690
|
const currentProducts = Array.isArray(mergedOrder.products) ? mergedOrder.products : [];
|
|
1741
1691
|
const unmatchedCurrentIndexes = new Set(currentProducts.map((_, index) => index));
|
|
1742
1692
|
const removedProductKeys = [];
|
|
1743
1693
|
for (const previousProduct of previousProducts) {
|
|
1744
|
-
const matchedIndex = currentProducts.findIndex(
|
|
1745
|
-
(currentProduct, index) => unmatchedCurrentIndexes.has(index) && this.isSameProductMembershipItem(previousProduct, currentProduct)
|
|
1746
|
-
);
|
|
1694
|
+
const matchedIndex = currentProducts.findIndex((currentProduct, index) => unmatchedCurrentIndexes.has(index) && this.isSameProductMembershipItem(previousProduct, currentProduct));
|
|
1747
1695
|
if (matchedIndex >= 0) {
|
|
1748
1696
|
unmatchedCurrentIndexes.delete(matchedIndex);
|
|
1749
1697
|
continue;
|
|
1750
1698
|
}
|
|
1751
1699
|
const productKey = this.getProductMembershipKey(previousProduct);
|
|
1752
|
-
if (productKey)
|
|
1753
|
-
removedProductKeys.push(productKey);
|
|
1700
|
+
if (productKey) removedProductKeys.push(productKey);
|
|
1754
1701
|
}
|
|
1755
|
-
const addedProductKeys = [...unmatchedCurrentIndexes].map(
|
|
1702
|
+
const addedProductKeys = [...unmatchedCurrentIndexes].map(index => this.getProductMembershipKey(currentProducts[index])).filter(Boolean);
|
|
1756
1703
|
if (addedProductKeys.length === 0 && removedProductKeys.length === 0) {
|
|
1757
1704
|
return null;
|
|
1758
1705
|
}
|
|
1759
1706
|
const orderId = mergedOrder.order_id ?? existingOrder.order_id;
|
|
1760
|
-
if (orderId ===
|
|
1761
|
-
return null;
|
|
1707
|
+
if (orderId === undefined || orderId === null) return null;
|
|
1762
1708
|
return {
|
|
1763
1709
|
order_id: orderId,
|
|
1764
1710
|
source,
|
|
@@ -1768,6 +1714,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1768
1714
|
current_product_count: currentProducts.length
|
|
1769
1715
|
};
|
|
1770
1716
|
}
|
|
1717
|
+
|
|
1771
1718
|
/**
|
|
1772
1719
|
* 将订单的全部身份键登记到索引并指向其在列表中的下标。
|
|
1773
1720
|
* 合并后订单新增的身份字段(如挂单同步后拿到 order_id)也会被登记。
|
|
@@ -1781,54 +1728,53 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1781
1728
|
identityKeyToIndex.set(key, index);
|
|
1782
1729
|
}
|
|
1783
1730
|
}
|
|
1731
|
+
|
|
1784
1732
|
/**
|
|
1785
1733
|
* 合并热路径去重兜底:默认直接返回原列表(增量索引已保证无重复)。
|
|
1786
1734
|
* 仅当 ORDER_MERGE_SELF_CHECK 开启时,额外做一次全表压缩并在发现残留重复时告警。
|
|
1787
1735
|
*/
|
|
1788
1736
|
runOrderStoreSelfCheck(orders, source) {
|
|
1789
|
-
if (!ORDER_MERGE_SELF_CHECK)
|
|
1790
|
-
|
|
1791
|
-
|
|
1737
|
+
if (!ORDER_MERGE_SELF_CHECK) return orders;
|
|
1738
|
+
const {
|
|
1739
|
+
list,
|
|
1740
|
+
removedCount
|
|
1741
|
+
} = this.compactOrderListByIdentity(orders, source);
|
|
1792
1742
|
if (removedCount > 0) {
|
|
1793
|
-
this.logWarning(
|
|
1743
|
+
this.logWarning('合并自检发现残留重复订单,已压缩', {
|
|
1744
|
+
source,
|
|
1745
|
+
removedCount
|
|
1746
|
+
});
|
|
1794
1747
|
}
|
|
1795
1748
|
return list;
|
|
1796
1749
|
}
|
|
1797
1750
|
normalizeOrderSyncMessage(res) {
|
|
1798
|
-
const data =
|
|
1799
|
-
if (!data)
|
|
1800
|
-
|
|
1801
|
-
const payload = (data == null ? void 0 : data.data) && typeof data.data === "object" ? data.data : void 0;
|
|
1751
|
+
const data = res?.data || res;
|
|
1752
|
+
if (!data) return null;
|
|
1753
|
+
const payload = data?.data && typeof data.data === 'object' ? data.data : undefined;
|
|
1802
1754
|
const normalized = {
|
|
1803
1755
|
...data,
|
|
1804
|
-
_channelKey: data.module ||
|
|
1756
|
+
_channelKey: data.module || 'sales_sync'
|
|
1805
1757
|
};
|
|
1806
|
-
if (!normalized.type && typeof data.event ===
|
|
1807
|
-
|
|
1808
|
-
if (!normalized.id && data.
|
|
1809
|
-
|
|
1810
|
-
if (!normalized.
|
|
1811
|
-
|
|
1812
|
-
if (!normalized.
|
|
1813
|
-
normalized.order_id = data.order_id;
|
|
1814
|
-
if (!normalized.order_id && (payload == null ? void 0 : payload.order_id) !== void 0)
|
|
1815
|
-
normalized.order_id = payload.order_id;
|
|
1816
|
-
if (!normalized.body && (payload == null ? void 0 : payload.order_id) !== void 0)
|
|
1817
|
-
normalized.body = payload;
|
|
1818
|
-
if (!normalized.data && (payload == null ? void 0 : payload.order_id) !== void 0)
|
|
1819
|
-
normalized.data = payload;
|
|
1758
|
+
if (!normalized.type && typeof data.event === 'string') normalized.type = data.event;
|
|
1759
|
+
if (!normalized.id && data.id !== undefined) normalized.id = data.id;
|
|
1760
|
+
if (!normalized.id && data.order_id !== undefined) normalized.id = data.order_id;
|
|
1761
|
+
if (!normalized.order_id && data.order_id !== undefined) normalized.order_id = data.order_id;
|
|
1762
|
+
if (!normalized.order_id && payload?.order_id !== undefined) normalized.order_id = payload.order_id;
|
|
1763
|
+
if (!normalized.body && payload?.order_id !== undefined) normalized.body = payload;
|
|
1764
|
+
if (!normalized.data && payload?.order_id !== undefined) normalized.data = payload;
|
|
1820
1765
|
return normalized;
|
|
1821
1766
|
}
|
|
1822
1767
|
normalizeOrderSyncPayload(payload) {
|
|
1823
|
-
if (!payload)
|
|
1824
|
-
return null;
|
|
1768
|
+
if (!payload) return null;
|
|
1825
1769
|
const orderId = payload.order_id;
|
|
1826
|
-
if (orderId ===
|
|
1827
|
-
|
|
1828
|
-
|
|
1770
|
+
if (orderId === undefined || orderId === null) return null;
|
|
1771
|
+
return {
|
|
1772
|
+
...payload,
|
|
1773
|
+
order_id: orderId
|
|
1774
|
+
};
|
|
1829
1775
|
}
|
|
1830
1776
|
uniqueOrderIds(ids) {
|
|
1831
|
-
const idMap =
|
|
1777
|
+
const idMap = new Map();
|
|
1832
1778
|
for (const id of ids) {
|
|
1833
1779
|
idMap.set(this.getIdKey(id), id);
|
|
1834
1780
|
}
|
|
@@ -1838,21 +1784,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1838
1784
|
return String(id);
|
|
1839
1785
|
}
|
|
1840
1786
|
isOrderLookupMatch(order, lookupKey) {
|
|
1841
|
-
if (!order || !lookupKey)
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
order.external_sale_number,
|
|
1846
|
-
order.order_number,
|
|
1847
|
-
order.shop_order_number,
|
|
1848
|
-
order.shop_full_order_number
|
|
1849
|
-
];
|
|
1850
|
-
return candidates.some((value) => {
|
|
1851
|
-
if (value === void 0 || value === null || value === "")
|
|
1852
|
-
return false;
|
|
1787
|
+
if (!order || !lookupKey) return false;
|
|
1788
|
+
const candidates = [order.order_id, order.external_sale_number, order.order_number, order.shop_order_number, order.shop_full_order_number];
|
|
1789
|
+
return candidates.some(value => {
|
|
1790
|
+
if (value === undefined || value === null || value === '') return false;
|
|
1853
1791
|
return this.getIdKey(value) === lookupKey;
|
|
1854
1792
|
});
|
|
1855
1793
|
}
|
|
1794
|
+
|
|
1856
1795
|
/**
|
|
1857
1796
|
* 解析订单 SQLite 主键,规则与宿主 OrderDataSource.getOrderStorageKey 一致。
|
|
1858
1797
|
*
|
|
@@ -1861,114 +1800,94 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1861
1800
|
* // => 'S-1001'
|
|
1862
1801
|
*/
|
|
1863
1802
|
getOrderStorageKey(order) {
|
|
1864
|
-
const externalSaleNumber = order
|
|
1865
|
-
if (externalSaleNumber !==
|
|
1803
|
+
const externalSaleNumber = order?.external_sale_number;
|
|
1804
|
+
if (externalSaleNumber !== undefined && externalSaleNumber !== null && externalSaleNumber !== '') {
|
|
1866
1805
|
return String(externalSaleNumber);
|
|
1867
1806
|
}
|
|
1868
|
-
const orderId = order
|
|
1869
|
-
if (orderId !==
|
|
1807
|
+
const orderId = order?.order_id;
|
|
1808
|
+
if (orderId !== undefined && orderId !== null && orderId !== '') {
|
|
1870
1809
|
return String(orderId);
|
|
1871
1810
|
}
|
|
1872
|
-
return
|
|
1811
|
+
return '';
|
|
1873
1812
|
}
|
|
1874
1813
|
getPersistedOrderStorageKey(order) {
|
|
1875
|
-
const persistedStorageKey = order
|
|
1876
|
-
if (persistedStorageKey !==
|
|
1814
|
+
const persistedStorageKey = order?.[ORDER_STORAGE_KEY_FIELD];
|
|
1815
|
+
if (persistedStorageKey !== undefined && persistedStorageKey !== null && persistedStorageKey !== '') {
|
|
1877
1816
|
return String(persistedStorageKey);
|
|
1878
1817
|
}
|
|
1879
1818
|
return this.getOrderStorageKey(order);
|
|
1880
1819
|
}
|
|
1881
1820
|
getOrderIdentityMatchKeys(order) {
|
|
1882
|
-
return this.getOrderIdentityEntries(order).map(
|
|
1821
|
+
return this.getOrderIdentityEntries(order).map(entry => `${entry.field}:${entry.key}`);
|
|
1883
1822
|
}
|
|
1884
1823
|
doOrdersShareIdentity(left, right) {
|
|
1885
1824
|
const leftKeys = new Set(this.getOrderIdentityMatchKeys(left));
|
|
1886
|
-
if (leftKeys.size === 0)
|
|
1887
|
-
|
|
1888
|
-
return this.getOrderIdentityMatchKeys(right).some((key) => leftKeys.has(key));
|
|
1825
|
+
if (leftKeys.size === 0) return false;
|
|
1826
|
+
return this.getOrderIdentityMatchKeys(right).some(key => leftKeys.has(key));
|
|
1889
1827
|
}
|
|
1890
1828
|
findOrderIndexByIdentity(orders, target) {
|
|
1891
|
-
if (this.getOrderIdentityMatchKeys(target).length === 0)
|
|
1892
|
-
|
|
1893
|
-
return orders.findIndex((order) => this.doOrdersShareIdentity(order, target));
|
|
1829
|
+
if (this.getOrderIdentityMatchKeys(target).length === 0) return -1;
|
|
1830
|
+
return orders.findIndex(order => this.doOrdersShareIdentity(order, target));
|
|
1894
1831
|
}
|
|
1895
1832
|
getOrderCompletenessScore(order) {
|
|
1896
1833
|
const record = order;
|
|
1897
1834
|
let score = this.isPendingSyncOrder(order) ? 0 : 100;
|
|
1898
|
-
if (!this.isBlankIdentityValue(order.order_id) && order.order_id !== record.external_sale_number)
|
|
1899
|
-
score += 30;
|
|
1835
|
+
if (!this.isBlankIdentityValue(order.order_id) && order.order_id !== record.external_sale_number) score += 30;
|
|
1900
1836
|
score += this.getOrderIdentityMatchKeys(order).length * 5;
|
|
1901
|
-
if (Array.isArray(order.products))
|
|
1902
|
-
|
|
1903
|
-
if (Array.isArray(order.
|
|
1904
|
-
|
|
1905
|
-
if (Array.isArray(order.payments))
|
|
1906
|
-
score += Math.min(order.payments.length, 10);
|
|
1907
|
-
if (record.updated_at)
|
|
1908
|
-
score += 1;
|
|
1837
|
+
if (Array.isArray(order.products)) score += Math.min(order.products.length, 10);
|
|
1838
|
+
if (Array.isArray(order.bookings)) score += Math.min(order.bookings.length, 10);
|
|
1839
|
+
if (Array.isArray(order.payments)) score += Math.min(order.payments.length, 10);
|
|
1840
|
+
if (record.updated_at) score += 1;
|
|
1909
1841
|
return score;
|
|
1910
1842
|
}
|
|
1911
1843
|
pickPreferredOrder(left, right) {
|
|
1912
1844
|
const leftScore = this.getOrderCompletenessScore(left);
|
|
1913
1845
|
const rightScore = this.getOrderCompletenessScore(right);
|
|
1914
|
-
if (rightScore >= leftScore)
|
|
1915
|
-
return right;
|
|
1846
|
+
if (rightScore >= leftScore) return right;
|
|
1916
1847
|
return left;
|
|
1917
1848
|
}
|
|
1918
1849
|
getProductIdentityKeys(product) {
|
|
1919
|
-
var _a;
|
|
1920
1850
|
const record = product;
|
|
1921
|
-
if (!record)
|
|
1922
|
-
return [];
|
|
1851
|
+
if (!record) return [];
|
|
1923
1852
|
const keys = [];
|
|
1924
|
-
const metadataUid =
|
|
1925
|
-
if (!this.isBlankIdentityValue(metadataUid))
|
|
1926
|
-
keys.push(`uid:${String(metadataUid)}`);
|
|
1853
|
+
const metadataUid = record.metadata?.unique_identification_number;
|
|
1854
|
+
if (!this.isBlankIdentityValue(metadataUid)) keys.push(`uid:${String(metadataUid)}`);
|
|
1927
1855
|
const topLevelUid = record.unique_identification_number;
|
|
1928
|
-
if (!this.isBlankIdentityValue(topLevelUid))
|
|
1929
|
-
keys.push(`uid:${String(topLevelUid)}`);
|
|
1856
|
+
if (!this.isBlankIdentityValue(topLevelUid)) keys.push(`uid:${String(topLevelUid)}`);
|
|
1930
1857
|
const orderDetailId = record.order_detail_id;
|
|
1931
|
-
if (!this.isBlankIdentityValue(orderDetailId))
|
|
1932
|
-
keys.push(`detail:${String(orderDetailId)}`);
|
|
1858
|
+
if (!this.isBlankIdentityValue(orderDetailId)) keys.push(`detail:${String(orderDetailId)}`);
|
|
1933
1859
|
const bookingUid = record.booking_uid;
|
|
1934
|
-
if (!this.isBlankIdentityValue(bookingUid))
|
|
1935
|
-
keys.push(`booking:${String(bookingUid)}`);
|
|
1860
|
+
if (!this.isBlankIdentityValue(bookingUid)) keys.push(`booking:${String(bookingUid)}`);
|
|
1936
1861
|
return keys;
|
|
1937
1862
|
}
|
|
1938
1863
|
mergeOrderProductLists(preferred, secondary) {
|
|
1939
1864
|
const preferredList = Array.isArray(preferred) ? preferred : [];
|
|
1940
1865
|
const secondaryList = Array.isArray(secondary) ? secondary : [];
|
|
1941
|
-
if (secondaryList.length === 0)
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
return secondaryList;
|
|
1945
|
-
const seenKeys = /* @__PURE__ */ new Set();
|
|
1866
|
+
if (secondaryList.length === 0) return preferredList;
|
|
1867
|
+
if (preferredList.length === 0) return secondaryList;
|
|
1868
|
+
const seenKeys = new Set();
|
|
1946
1869
|
for (const item of preferredList) {
|
|
1947
1870
|
const keys = this.getProductIdentityKeys(item);
|
|
1948
|
-
for (const key of keys)
|
|
1949
|
-
seenKeys.add(key);
|
|
1871
|
+
for (const key of keys) seenKeys.add(key);
|
|
1950
1872
|
}
|
|
1951
1873
|
const result = [...preferredList];
|
|
1952
1874
|
for (const item of secondaryList) {
|
|
1953
1875
|
const keys = this.getProductIdentityKeys(item);
|
|
1954
|
-
if (keys.length === 0 || keys.some(
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
seenKeys.add(key);
|
|
1958
|
-
result.push((0, import_lodash_es.cloneDeep)(item));
|
|
1876
|
+
if (keys.length === 0 || keys.some(key => seenKeys.has(key))) continue;
|
|
1877
|
+
for (const key of keys) seenKeys.add(key);
|
|
1878
|
+
result.push((0, _lodashEs.cloneDeep)(item));
|
|
1959
1879
|
}
|
|
1960
1880
|
return result;
|
|
1961
1881
|
}
|
|
1962
1882
|
mergeOrderPaymentLists(existing, incoming) {
|
|
1963
1883
|
const existingList = Array.isArray(existing) ? existing : [];
|
|
1964
1884
|
const incomingList = Array.isArray(incoming) ? incoming : [];
|
|
1965
|
-
if (incomingList.length === 0)
|
|
1966
|
-
|
|
1967
|
-
return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(existingList, incomingList);
|
|
1885
|
+
if (incomingList.length === 0) return (0, _lodashEs.cloneDeep)(existingList);
|
|
1886
|
+
return (0, _paymentUtils.mergeOrderPaymentListsByIdentity)(existingList, incomingList);
|
|
1968
1887
|
}
|
|
1969
1888
|
getIdentifiedPendingPayments(order) {
|
|
1970
|
-
const payments = Array.isArray(order
|
|
1971
|
-
return payments.filter(
|
|
1889
|
+
const payments = Array.isArray(order?.payments) ? order.payments : [];
|
|
1890
|
+
return payments.filter(payment => (0, _paymentUtils.isIdentifiedPendingOrderPayment)(payment));
|
|
1972
1891
|
}
|
|
1973
1892
|
shouldProtectLocalOrderFromRemoteSnapshot(order) {
|
|
1974
1893
|
return this.isPendingSyncOrder(order) || this.isDraftOrder(order) || this.getIdentifiedPendingPayments(order).length > 0;
|
|
@@ -1976,10 +1895,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1976
1895
|
getUnmatchedIdentifiedPendingPayments(existing, incoming) {
|
|
1977
1896
|
const existingPayments = Array.isArray(existing) ? existing : [];
|
|
1978
1897
|
const incomingPayments = Array.isArray(incoming) ? incoming : [];
|
|
1979
|
-
const incomingIdentityKeys = new Set(
|
|
1980
|
-
|
|
1981
|
-
);
|
|
1982
|
-
return existingPayments.filter((payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment) && !(0, import_payment_utils.getOrderPaymentIdentityKeys)(payment).some((key) => incomingIdentityKeys.has(key)));
|
|
1898
|
+
const incomingIdentityKeys = new Set(incomingPayments.flatMap(payment => (0, _paymentUtils.getOrderPaymentIdentityKeys)(payment)));
|
|
1899
|
+
return existingPayments.filter(payment => (0, _paymentUtils.isIdentifiedPendingOrderPayment)(payment) && !(0, _paymentUtils.getOrderPaymentIdentityKeys)(payment).some(key => incomingIdentityKeys.has(key)));
|
|
1983
1900
|
}
|
|
1984
1901
|
mergeOrderRecords(existing, incoming) {
|
|
1985
1902
|
const preferred = this.pickPreferredOrder(existing, incoming);
|
|
@@ -1988,31 +1905,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1988
1905
|
...secondary,
|
|
1989
1906
|
...preferred
|
|
1990
1907
|
};
|
|
1991
|
-
const fieldsToPreserve = [
|
|
1992
|
-
|
|
1993
|
-
"external_sale_number",
|
|
1994
|
-
"order_number",
|
|
1995
|
-
"shop_order_number",
|
|
1996
|
-
"shop_full_order_number"
|
|
1997
|
-
];
|
|
1998
|
-
const incomingPatchFields = [
|
|
1999
|
-
"payment_status",
|
|
2000
|
-
"status",
|
|
2001
|
-
"shipping_status",
|
|
2002
|
-
"updated_at",
|
|
2003
|
-
"shop_discount",
|
|
2004
|
-
"summary",
|
|
2005
|
-
"note",
|
|
2006
|
-
"customer_id",
|
|
2007
|
-
"customer_name",
|
|
2008
|
-
"customer",
|
|
2009
|
-
"holder",
|
|
2010
|
-
"contacts_info",
|
|
2011
|
-
"phone",
|
|
2012
|
-
"email",
|
|
2013
|
-
"relation_forms",
|
|
2014
|
-
"is_draft_order"
|
|
2015
|
-
];
|
|
1908
|
+
const fieldsToPreserve = ['order_id', 'external_sale_number', 'order_number', 'shop_order_number', 'shop_full_order_number'];
|
|
1909
|
+
const incomingPatchFields = ['payment_status', 'status', 'shipping_status', 'updated_at', 'shop_discount', 'summary', 'note', 'customer_id', 'customer_name', 'customer', 'holder', 'contacts_info', 'phone', 'email', 'relation_forms', 'is_draft_order'];
|
|
2016
1910
|
const mergedRecord = merged;
|
|
2017
1911
|
const preferredRecord = preferred;
|
|
2018
1912
|
const secondaryRecord = secondary;
|
|
@@ -2029,41 +1923,34 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2029
1923
|
}
|
|
2030
1924
|
}
|
|
2031
1925
|
for (const field of incomingPatchFields) {
|
|
2032
|
-
if (!Object.prototype.hasOwnProperty.call(incomingRecord, field))
|
|
2033
|
-
|
|
2034
|
-
if (incomingRecord[field] ===
|
|
2035
|
-
|
|
2036
|
-
if (typeof incomingRecord[field] === "string" && incomingRecord[field] === "")
|
|
2037
|
-
continue;
|
|
2038
|
-
mergedRecord[field] = (0, import_lodash_es.cloneDeep)(incomingRecord[field]);
|
|
1926
|
+
if (!Object.prototype.hasOwnProperty.call(incomingRecord, field)) continue;
|
|
1927
|
+
if (incomingRecord[field] === undefined || incomingRecord[field] === null) continue;
|
|
1928
|
+
if (typeof incomingRecord[field] === 'string' && incomingRecord[field] === '') continue;
|
|
1929
|
+
mergedRecord[field] = (0, _lodashEs.cloneDeep)(incomingRecord[field]);
|
|
2039
1930
|
}
|
|
1931
|
+
|
|
1932
|
+
// 子项数组遵循完整快照语义:incoming 自有且为数组(包括 [])时权威替换;
|
|
1933
|
+
// 字段缺席或不是数组时视为稀疏 patch,继续保留 existing。
|
|
2040
1934
|
for (const field of ORDER_AUTHORITATIVE_COLLECTION_FIELDS) {
|
|
2041
1935
|
if (Array.isArray(incomingRecord[field])) {
|
|
2042
|
-
if (field ===
|
|
2043
|
-
const preservedPending = this.getUnmatchedIdentifiedPendingPayments(
|
|
2044
|
-
existingRecord[field],
|
|
2045
|
-
incomingRecord[field]
|
|
2046
|
-
);
|
|
1936
|
+
if (field === 'payments') {
|
|
1937
|
+
const preservedPending = this.getUnmatchedIdentifiedPendingPayments(existingRecord[field], incomingRecord[field]);
|
|
2047
1938
|
if (preservedPending.length > 0) {
|
|
2048
|
-
this.logInfo(
|
|
1939
|
+
this.logInfo('mergeOrderRecords-保留本地 pending 支付项', {
|
|
2049
1940
|
order_id: existing.order_id ?? incoming.order_id ?? null,
|
|
2050
1941
|
external_sale_number: existingRecord.external_sale_number ?? incomingRecord.external_sale_number ?? null,
|
|
2051
1942
|
preserved_pending_count: preservedPending.length,
|
|
2052
|
-
preserved_payment_identities: preservedPending.map(
|
|
1943
|
+
preserved_payment_identities: preservedPending.map(payment => (0, _paymentUtils.getOrderPaymentIdentityKeys)(payment))
|
|
2053
1944
|
});
|
|
2054
1945
|
}
|
|
2055
1946
|
}
|
|
2056
|
-
mergedRecord[field] = this.mergeAuthoritativeOrderCollection(
|
|
2057
|
-
field
|
|
2058
|
-
|
|
2059
|
-
incomingRecord[field],
|
|
2060
|
-
childUidRemaps,
|
|
2061
|
-
{ preserveIdentifiedPendingPayments: field === "payments" }
|
|
2062
|
-
);
|
|
1947
|
+
mergedRecord[field] = this.mergeAuthoritativeOrderCollection(field, existingRecord[field], incomingRecord[field], childUidRemaps, {
|
|
1948
|
+
preserveIdentifiedPendingPayments: field === 'payments'
|
|
1949
|
+
});
|
|
2063
1950
|
continue;
|
|
2064
1951
|
}
|
|
2065
1952
|
if (Object.prototype.hasOwnProperty.call(existingRecord, field)) {
|
|
2066
|
-
mergedRecord[field] = (0,
|
|
1953
|
+
mergedRecord[field] = (0, _lodashEs.cloneDeep)(existingRecord[field]);
|
|
2067
1954
|
} else {
|
|
2068
1955
|
delete mergedRecord[field];
|
|
2069
1956
|
}
|
|
@@ -2071,13 +1958,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2071
1958
|
if (!this.isPendingSyncOrder(preferred) || !this.isPendingSyncOrder(secondary)) {
|
|
2072
1959
|
merged.need_sync = 0;
|
|
2073
1960
|
}
|
|
2074
|
-
return this.normalizeOrderCollectionsForIngress(
|
|
2075
|
-
(0, import_orderCollectionIdentity.applyOrderCollectionUidRemaps)(merged, childUidRemaps),
|
|
2076
|
-
"mergeOrderRecords"
|
|
2077
|
-
);
|
|
1961
|
+
return this.normalizeOrderCollectionsForIngress((0, _orderCollectionIdentity.applyOrderCollectionUidRemaps)(merged, childUidRemaps), 'mergeOrderRecords');
|
|
2078
1962
|
}
|
|
2079
1963
|
summarizeDuplicateOrders(orders) {
|
|
2080
|
-
const groups =
|
|
1964
|
+
const groups = new Map();
|
|
2081
1965
|
for (const order of orders) {
|
|
2082
1966
|
for (const key of this.getOrderIdentityMatchKeys(order)) {
|
|
2083
1967
|
const group = groups.get(key) || [];
|
|
@@ -2088,7 +1972,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2088
1972
|
return [...groups.entries()].filter(([, group]) => group.length > 1).slice(0, 20).map(([key, group]) => ({
|
|
2089
1973
|
key,
|
|
2090
1974
|
count: group.length,
|
|
2091
|
-
orders: group.map(
|
|
1975
|
+
orders: group.map(order => ({
|
|
2092
1976
|
order_id: order.order_id ?? null,
|
|
2093
1977
|
external_sale_number: order.external_sale_number ?? null,
|
|
2094
1978
|
shop_order_number: order.shop_order_number ?? null,
|
|
@@ -2100,9 +1984,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2100
1984
|
}
|
|
2101
1985
|
logDuplicateOrders(source, orders) {
|
|
2102
1986
|
const duplicateGroups = this.summarizeDuplicateOrders(orders);
|
|
2103
|
-
if (duplicateGroups.length === 0)
|
|
2104
|
-
|
|
2105
|
-
this.logWarning("检测到重复订单身份键", {
|
|
1987
|
+
if (duplicateGroups.length === 0) return;
|
|
1988
|
+
this.logWarning('检测到重复订单身份键', {
|
|
2106
1989
|
source,
|
|
2107
1990
|
duplicateGroupCount: duplicateGroups.length,
|
|
2108
1991
|
duplicateGroups
|
|
@@ -2112,10 +1995,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2112
1995
|
const list = [];
|
|
2113
1996
|
let removedCount = 0;
|
|
2114
1997
|
for (const order of orders) {
|
|
2115
|
-
const normalizedOrder = this.normalizeOrderCollectionsForIngress(
|
|
2116
|
-
order,
|
|
2117
|
-
`${source}.order`
|
|
2118
|
-
);
|
|
1998
|
+
const normalizedOrder = this.normalizeOrderCollectionsForIngress(order, `${source}.order`);
|
|
2119
1999
|
const matchIndex = this.findOrderIndexByIdentity(list, normalizedOrder);
|
|
2120
2000
|
if (matchIndex < 0) {
|
|
2121
2001
|
list.push(normalizedOrder);
|
|
@@ -2125,7 +2005,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2125
2005
|
removedCount += 1;
|
|
2126
2006
|
}
|
|
2127
2007
|
if (removedCount > 0) {
|
|
2128
|
-
this.logWarning(
|
|
2008
|
+
this.logWarning('订单列表重复项已压缩', {
|
|
2129
2009
|
source,
|
|
2130
2010
|
beforeCount: orders.length,
|
|
2131
2011
|
afterCount: list.length,
|
|
@@ -2134,99 +2014,101 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2134
2014
|
} else {
|
|
2135
2015
|
this.logDuplicateOrders(source, orders);
|
|
2136
2016
|
}
|
|
2137
|
-
return {
|
|
2017
|
+
return {
|
|
2018
|
+
list,
|
|
2019
|
+
removedCount
|
|
2020
|
+
};
|
|
2138
2021
|
}
|
|
2022
|
+
|
|
2139
2023
|
/**
|
|
2140
2024
|
* 当前订单拉取窗口:
|
|
2141
2025
|
* - 优先使用 createdAtQuery.sales_time_between(已按营业日边界初始化)
|
|
2142
2026
|
* - 无法解析时退化为自然日窗口
|
|
2143
2027
|
*/
|
|
2144
2028
|
getCurrentPullWindow() {
|
|
2145
|
-
|
|
2146
|
-
const
|
|
2147
|
-
const range = (_b = (_a = this.store) == null ? void 0 : _a.createdAtQuery) == null ? void 0 : _b.sales_time_between;
|
|
2029
|
+
const now = (0, _dayjs.default)();
|
|
2030
|
+
const range = this.store?.createdAtQuery?.sales_time_between;
|
|
2148
2031
|
if (Array.isArray(range) && range.length >= 2) {
|
|
2149
|
-
const
|
|
2150
|
-
const endExclusiveAt = (0,
|
|
2151
|
-
if (
|
|
2152
|
-
return {
|
|
2032
|
+
const startAt = (0, _dayjs.default)(range[0]);
|
|
2033
|
+
const endExclusiveAt = (0, _dayjs.default)(range[1]);
|
|
2034
|
+
if (startAt.isValid() && endExclusiveAt.isValid() && endExclusiveAt.isAfter(startAt)) {
|
|
2035
|
+
return {
|
|
2036
|
+
startAt,
|
|
2037
|
+
endExclusiveAt
|
|
2038
|
+
};
|
|
2153
2039
|
}
|
|
2154
2040
|
}
|
|
2155
|
-
const startAt = now.startOf(
|
|
2156
|
-
return {
|
|
2041
|
+
const startAt = now.startOf('day');
|
|
2042
|
+
return {
|
|
2043
|
+
startAt,
|
|
2044
|
+
endExclusiveAt: startAt.add(1, 'day')
|
|
2045
|
+
};
|
|
2157
2046
|
}
|
|
2158
2047
|
hasPulledOrdersToday() {
|
|
2159
2048
|
const lastFullFetchAt = this.getStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY);
|
|
2160
|
-
if (!lastFullFetchAt)
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2049
|
+
if (!lastFullFetchAt) return false;
|
|
2050
|
+
const parsed = (0, _dayjs.default)(lastFullFetchAt);
|
|
2051
|
+
if (!parsed.isValid()) return false;
|
|
2052
|
+
|
|
2053
|
+
// 按当前拉取窗口判断,而不是自然日判断。
|
|
2054
|
+
// 这样在营业日跨日边界(start_time)场景下也能正确判定是否需要重新拉取。
|
|
2055
|
+
const {
|
|
2056
|
+
startAt,
|
|
2057
|
+
endExclusiveAt
|
|
2058
|
+
} = this.getCurrentPullWindow();
|
|
2166
2059
|
return (parsed.isAfter(startAt) || parsed.isSame(startAt)) && parsed.isBefore(endExclusiveAt);
|
|
2167
2060
|
}
|
|
2168
2061
|
markOrderPulledAtNow() {
|
|
2169
|
-
this.setStorageItem(
|
|
2170
|
-
ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY,
|
|
2171
|
-
(0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
|
|
2172
|
-
);
|
|
2062
|
+
this.setStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY, (0, _dayjs.default)().format('YYYY-MM-DD HH:mm:ss'));
|
|
2173
2063
|
}
|
|
2174
2064
|
getStorageItem(key) {
|
|
2175
|
-
var _a;
|
|
2176
2065
|
try {
|
|
2177
|
-
if (
|
|
2178
|
-
|
|
2179
|
-
if (typeof globalThis !== "undefined" && (globalThis == null ? void 0 : globalThis.localStorage)) {
|
|
2066
|
+
if (this.storage?.getStorage) return this.storage.getStorage(key);
|
|
2067
|
+
if (typeof globalThis !== 'undefined' && globalThis?.localStorage) {
|
|
2180
2068
|
return globalThis.localStorage.getItem(key);
|
|
2181
2069
|
}
|
|
2182
2070
|
} catch {
|
|
2071
|
+
// 忽略存储异常,避免影响主流程
|
|
2183
2072
|
}
|
|
2184
2073
|
return null;
|
|
2185
2074
|
}
|
|
2186
2075
|
setStorageItem(key, value) {
|
|
2187
|
-
var _a;
|
|
2188
2076
|
try {
|
|
2189
|
-
if (
|
|
2077
|
+
if (this.storage?.setStorage) {
|
|
2190
2078
|
this.storage.setStorage(key, value);
|
|
2191
2079
|
return;
|
|
2192
2080
|
}
|
|
2193
|
-
if (typeof globalThis !==
|
|
2081
|
+
if (typeof globalThis !== 'undefined' && globalThis?.localStorage) {
|
|
2194
2082
|
globalThis.localStorage.setItem(key, value);
|
|
2195
2083
|
}
|
|
2196
2084
|
} catch {
|
|
2085
|
+
// 忽略存储异常,避免影响主流程
|
|
2197
2086
|
}
|
|
2198
2087
|
}
|
|
2199
2088
|
async loadOrdersFromSQLite() {
|
|
2200
|
-
if (!this.dbManager)
|
|
2201
|
-
return [];
|
|
2089
|
+
if (!this.dbManager) return [];
|
|
2202
2090
|
try {
|
|
2203
2091
|
const orders = await this.dbManager.getAll(INDEXDB_STORE_NAME);
|
|
2204
|
-
return (orders || []).map(
|
|
2205
|
-
(order) => this.normalizeOrderCollectionsForIngress(order, "loadOrdersFromSQLite")
|
|
2206
|
-
);
|
|
2092
|
+
return (orders || []).map(order => this.normalizeOrderCollectionsForIngress(order, 'loadOrdersFromSQLite'));
|
|
2207
2093
|
} catch {
|
|
2208
2094
|
return [];
|
|
2209
2095
|
}
|
|
2210
2096
|
}
|
|
2211
2097
|
isPendingSyncOrder(order) {
|
|
2212
|
-
return Number(order
|
|
2098
|
+
return Number(order?.need_sync) === 1;
|
|
2213
2099
|
}
|
|
2214
2100
|
isDraftOrder(order) {
|
|
2215
|
-
return Number(order
|
|
2101
|
+
return Number(order?.is_draft_order) === 1;
|
|
2216
2102
|
}
|
|
2217
2103
|
shouldProtectDraftOrderFromIncoming(source) {
|
|
2218
|
-
return source !==
|
|
2104
|
+
return source !== 'checkoutSync';
|
|
2219
2105
|
}
|
|
2220
2106
|
normalizeRemoteSyncedOrder(order) {
|
|
2221
|
-
const normalizedOrder = this.normalizeOrderCollectionsForIngress(
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
return {
|
|
2227
|
-
...normalizedOrder,
|
|
2228
|
-
is_draft_order: 0
|
|
2229
|
-
};
|
|
2107
|
+
const normalizedOrder = this.normalizeOrderCollectionsForIngress(order, 'normalizeRemoteSyncedOrder');
|
|
2108
|
+
if (this.isPendingSyncOrder(normalizedOrder)) return {
|
|
2109
|
+
...normalizedOrder,
|
|
2110
|
+
is_draft_order: 0
|
|
2111
|
+
};
|
|
2230
2112
|
return {
|
|
2231
2113
|
...normalizedOrder,
|
|
2232
2114
|
need_sync: 0,
|
|
@@ -2238,48 +2120,33 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2238
2120
|
...this.withoutSyntheticDraftOrderId(draftOrder)
|
|
2239
2121
|
};
|
|
2240
2122
|
const remote = remoteOrder;
|
|
2241
|
-
for (const field of [
|
|
2242
|
-
"order_id",
|
|
2243
|
-
"order_number",
|
|
2244
|
-
"shop_order_number",
|
|
2245
|
-
"shop_full_order_number"
|
|
2246
|
-
]) {
|
|
2123
|
+
for (const field of ['order_id', 'order_number', 'shop_order_number', 'shop_full_order_number']) {
|
|
2247
2124
|
if (this.isBlankIdentityValue(merged[field]) && !this.isBlankIdentityValue(remote[field])) {
|
|
2248
2125
|
merged[field] = remote[field];
|
|
2249
2126
|
}
|
|
2250
2127
|
}
|
|
2251
|
-
return this.normalizeOrderCollectionsForIngress(
|
|
2252
|
-
merged,
|
|
2253
|
-
"mergeRemoteIdentityIntoDraftOrder"
|
|
2254
|
-
);
|
|
2128
|
+
return this.normalizeOrderCollectionsForIngress(merged, 'mergeRemoteIdentityIntoDraftOrder');
|
|
2255
2129
|
}
|
|
2256
2130
|
mergeRemoteSnapshotWithPendingOrders(remoteOrders, existingOrders) {
|
|
2257
|
-
const merged = remoteOrders.map(
|
|
2131
|
+
const merged = remoteOrders.map(order => this.normalizeRemoteSyncedOrder(order));
|
|
2258
2132
|
for (const rawOrder of existingOrders) {
|
|
2259
|
-
const order = this.normalizeOrderCollectionsForIngress(
|
|
2260
|
-
|
|
2261
|
-
"mergeRemoteSnapshotWithPendingOrders.existingSQLite"
|
|
2262
|
-
);
|
|
2263
|
-
if (!this.shouldProtectLocalOrderFromRemoteSnapshot(order))
|
|
2264
|
-
continue;
|
|
2133
|
+
const order = this.normalizeOrderCollectionsForIngress(rawOrder, 'mergeRemoteSnapshotWithPendingOrders.existingSQLite');
|
|
2134
|
+
if (!this.shouldProtectLocalOrderFromRemoteSnapshot(order)) continue;
|
|
2265
2135
|
const matchIndex = this.findOrderIndexByIdentity(merged, order);
|
|
2266
2136
|
if (matchIndex >= 0) {
|
|
2267
2137
|
if (this.isDraftOrder(order)) {
|
|
2268
|
-
merged[matchIndex] = this.mergeRemoteIdentityIntoDraftOrder(
|
|
2269
|
-
order,
|
|
2270
|
-
merged[matchIndex]
|
|
2271
|
-
);
|
|
2138
|
+
merged[matchIndex] = this.mergeRemoteIdentityIntoDraftOrder(order, merged[matchIndex]);
|
|
2272
2139
|
} else {
|
|
2273
2140
|
merged[matchIndex] = this.mergeOrderRecords(order, merged[matchIndex]);
|
|
2274
2141
|
}
|
|
2275
2142
|
continue;
|
|
2276
2143
|
}
|
|
2277
|
-
if (!this.getOrderStorageKey(order))
|
|
2278
|
-
continue;
|
|
2144
|
+
if (!this.getOrderStorageKey(order)) continue;
|
|
2279
2145
|
merged.push(order);
|
|
2280
2146
|
}
|
|
2281
|
-
return this.compactOrderListByIdentity(merged,
|
|
2147
|
+
return this.compactOrderListByIdentity(merged, 'mergeRemoteSnapshotWithPendingOrders').list;
|
|
2282
2148
|
}
|
|
2149
|
+
|
|
2283
2150
|
/**
|
|
2284
2151
|
* 串行执行订单 SQLite 写入任务,避免快照替换与增量 upsert 并发交错。
|
|
2285
2152
|
*
|
|
@@ -2290,45 +2157,40 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2290
2157
|
*/
|
|
2291
2158
|
async runInOrderSQLiteSaveQueue(task) {
|
|
2292
2159
|
const queuedTask = this.orderSQLiteSaveQueue.then(task, task);
|
|
2293
|
-
this.orderSQLiteSaveQueue = queuedTask.then(() =>
|
|
2160
|
+
this.orderSQLiteSaveQueue = queuedTask.then(() => undefined, () => undefined);
|
|
2294
2161
|
return queuedTask;
|
|
2295
2162
|
}
|
|
2163
|
+
|
|
2296
2164
|
/**
|
|
2297
2165
|
* 批量增量 upsert 订单到 SQLite,不清空表;用于 pubsub / HTTP 增量合并。
|
|
2298
2166
|
*
|
|
2299
2167
|
* @example
|
|
2300
2168
|
* await this.patchOrdersInSQLite(freshOrders)
|
|
2301
2169
|
*/
|
|
2302
|
-
async patchOrdersInSQLite(orders, source, mergeActions = {}, options = {}, forceWriteStorageKeys =
|
|
2170
|
+
async patchOrdersInSQLite(orders, source, mergeActions = {}, options = {}, forceWriteStorageKeys = new Set()) {
|
|
2303
2171
|
if (orders.length === 0) {
|
|
2304
2172
|
return;
|
|
2305
2173
|
}
|
|
2306
2174
|
if (!this.dbManager) {
|
|
2307
|
-
if (options.throwOnError)
|
|
2308
|
-
throw new Error("订单 SQLite 数据库未初始化");
|
|
2175
|
+
if (options.throwOnError) throw new Error('订单 SQLite 数据库未初始化');
|
|
2309
2176
|
return;
|
|
2310
2177
|
}
|
|
2311
|
-
const migrationTargetStorageKeys = new Set(
|
|
2312
|
-
|
|
2313
|
-
);
|
|
2314
|
-
const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).map((order) => this.normalizeOrderCollectionsForIngress(order, `${source}.sqliteIngress`)).map((order) => {
|
|
2178
|
+
const migrationTargetStorageKeys = new Set((options.storageKeyMigrations || []).map(migration => migration.to));
|
|
2179
|
+
const ordersSnapshot = (0, _lodashEs.cloneDeep)(orders).map(order => this.normalizeOrderCollectionsForIngress(order, `${source}.sqliteIngress`)).map(order => {
|
|
2315
2180
|
const storageKey = this.getOrderStorageKey(order);
|
|
2316
|
-
if (!storageKey || !migrationTargetStorageKeys.has(storageKey))
|
|
2317
|
-
return order;
|
|
2181
|
+
if (!storageKey || !migrationTargetStorageKeys.has(storageKey)) return order;
|
|
2318
2182
|
return {
|
|
2319
2183
|
...order,
|
|
2320
2184
|
[ORDER_STORAGE_KEY_FIELD]: storageKey
|
|
2321
2185
|
};
|
|
2322
|
-
}).filter(
|
|
2186
|
+
}).filter(order => this.getOrderStorageKey(order));
|
|
2323
2187
|
if (ordersSnapshot.length === 0) {
|
|
2324
2188
|
return;
|
|
2325
2189
|
}
|
|
2326
|
-
const {
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
forceWriteStorageKeys
|
|
2331
|
-
);
|
|
2190
|
+
const {
|
|
2191
|
+
toWrite,
|
|
2192
|
+
skipped
|
|
2193
|
+
} = this.filterRedundantPatchOrders(source, ordersSnapshot, mergeActions, forceWriteStorageKeys);
|
|
2332
2194
|
if (toWrite.length === 0) {
|
|
2333
2195
|
return;
|
|
2334
2196
|
}
|
|
@@ -2336,55 +2198,49 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2336
2198
|
if (compactedToWrite.length === 0) {
|
|
2337
2199
|
return;
|
|
2338
2200
|
}
|
|
2339
|
-
const writtenStorageKeys = new Set(
|
|
2340
|
-
|
|
2341
|
-
);
|
|
2342
|
-
const storageKeyMigrations = /* @__PURE__ */ new Map();
|
|
2201
|
+
const writtenStorageKeys = new Set(compactedToWrite.map(order => this.getOrderStorageKey(order)).filter(Boolean));
|
|
2202
|
+
const storageKeyMigrations = new Map();
|
|
2343
2203
|
for (const migration of options.storageKeyMigrations || []) {
|
|
2344
|
-
if (!writtenStorageKeys.has(migration.to))
|
|
2345
|
-
|
|
2346
|
-
if (writtenStorageKeys.has(migration.from))
|
|
2347
|
-
continue;
|
|
2204
|
+
if (!writtenStorageKeys.has(migration.to)) continue;
|
|
2205
|
+
if (writtenStorageKeys.has(migration.from)) continue;
|
|
2348
2206
|
storageKeyMigrations.set(migration.from, migration);
|
|
2349
2207
|
}
|
|
2350
2208
|
try {
|
|
2351
2209
|
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
2352
|
-
let writeMethod =
|
|
2353
|
-
this.logInfo(
|
|
2210
|
+
let writeMethod = 'none';
|
|
2211
|
+
this.logInfo('patchOrdersInSQLite-开始', {
|
|
2354
2212
|
source,
|
|
2355
2213
|
count: compactedToWrite.length,
|
|
2356
2214
|
dedupedCount: skipped.length
|
|
2357
2215
|
});
|
|
2358
|
-
if (typeof this.dbManager.bulkUpdate ===
|
|
2359
|
-
writeMethod =
|
|
2216
|
+
if (typeof this.dbManager.bulkUpdate === 'function') {
|
|
2217
|
+
writeMethod = 'bulkUpdate';
|
|
2360
2218
|
await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, compactedToWrite);
|
|
2361
|
-
} else if (typeof this.dbManager.bulkAdd ===
|
|
2362
|
-
writeMethod =
|
|
2219
|
+
} else if (typeof this.dbManager.bulkAdd === 'function') {
|
|
2220
|
+
writeMethod = 'bulkAdd';
|
|
2363
2221
|
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, compactedToWrite);
|
|
2364
|
-
} else if (typeof this.dbManager.update ===
|
|
2365
|
-
writeMethod =
|
|
2222
|
+
} else if (typeof this.dbManager.update === 'function') {
|
|
2223
|
+
writeMethod = 'update';
|
|
2366
2224
|
for (const order of compactedToWrite) {
|
|
2367
2225
|
await this.dbManager.update(INDEXDB_STORE_NAME, order);
|
|
2368
2226
|
}
|
|
2369
2227
|
} else if (options.throwOnError) {
|
|
2370
|
-
throw new Error(
|
|
2228
|
+
throw new Error('订单 SQLite 数据库不支持写入');
|
|
2371
2229
|
}
|
|
2372
2230
|
this.recordRecentSqliteWrite(source, compactedToWrite);
|
|
2373
|
-
if (writeMethod !==
|
|
2231
|
+
if (writeMethod !== 'none') {
|
|
2374
2232
|
for (const migration of storageKeyMigrations.values()) {
|
|
2375
2233
|
try {
|
|
2376
2234
|
await this.dbManager.delete(INDEXDB_STORE_NAME, migration.from);
|
|
2377
2235
|
this.recentSqliteWriteByStorageKey.delete(migration.from);
|
|
2378
2236
|
for (const order of orders) {
|
|
2379
|
-
if (this.getOrderStorageKey(order) !== migration.to)
|
|
2380
|
-
continue;
|
|
2237
|
+
if (this.getOrderStorageKey(order) !== migration.to) continue;
|
|
2381
2238
|
const orderRecord = order;
|
|
2382
|
-
if (String(orderRecord[ORDER_STORAGE_KEY_FIELD] ??
|
|
2383
|
-
continue;
|
|
2239
|
+
if (String(orderRecord[ORDER_STORAGE_KEY_FIELD] ?? '') !== migration.from) continue;
|
|
2384
2240
|
orderRecord[ORDER_STORAGE_KEY_FIELD] = migration.to;
|
|
2385
2241
|
}
|
|
2386
2242
|
} catch (error) {
|
|
2387
|
-
this.logError(
|
|
2243
|
+
this.logError('删除订单旧 SQLite storage key 失败', {
|
|
2388
2244
|
source,
|
|
2389
2245
|
order_id: migration.orderId,
|
|
2390
2246
|
oldStorageKey: migration.from,
|
|
@@ -2394,7 +2250,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2394
2250
|
}
|
|
2395
2251
|
}
|
|
2396
2252
|
}
|
|
2397
|
-
this.logInfo(
|
|
2253
|
+
this.logInfo('patchOrdersInSQLite-完成', {
|
|
2398
2254
|
source,
|
|
2399
2255
|
count: compactedToWrite.length,
|
|
2400
2256
|
writeMethod,
|
|
@@ -2402,14 +2258,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2402
2258
|
});
|
|
2403
2259
|
});
|
|
2404
2260
|
} catch (error) {
|
|
2405
|
-
this.logError(
|
|
2261
|
+
this.logError('增量保存订单到 SQLite 失败', {
|
|
2406
2262
|
error: error instanceof Error ? error.message : String(error),
|
|
2407
2263
|
orderCount: ordersSnapshot.length
|
|
2408
2264
|
});
|
|
2409
|
-
if (options.throwOnError)
|
|
2410
|
-
throw error;
|
|
2265
|
+
if (options.throwOnError) throw error;
|
|
2411
2266
|
}
|
|
2412
2267
|
}
|
|
2268
|
+
|
|
2413
2269
|
/**
|
|
2414
2270
|
* 单条 upsert 订单到 SQLite;用于 overwriteExistingOrder 等单条覆盖场景。
|
|
2415
2271
|
*
|
|
@@ -2418,55 +2274,50 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2418
2274
|
*/
|
|
2419
2275
|
async updateOrderInSQLite(order, source, options = {}) {
|
|
2420
2276
|
if (!this.getOrderStorageKey(order)) {
|
|
2421
|
-
if (options.throwOnError)
|
|
2422
|
-
throw new Error("订单缺少可用的 SQLite 存储主键");
|
|
2277
|
+
if (options.throwOnError) throw new Error('订单缺少可用的 SQLite 存储主键');
|
|
2423
2278
|
return;
|
|
2424
2279
|
}
|
|
2425
2280
|
if (!this.dbManager) {
|
|
2426
|
-
if (options.throwOnError)
|
|
2427
|
-
throw new Error("订单 SQLite 数据库未初始化");
|
|
2281
|
+
if (options.throwOnError) throw new Error('订单 SQLite 数据库未初始化');
|
|
2428
2282
|
return;
|
|
2429
2283
|
}
|
|
2430
|
-
const orderSnapshot = this.normalizeOrderCollectionsForIngress(
|
|
2431
|
-
(0, import_lodash_es.cloneDeep)(order),
|
|
2432
|
-
`${source}.sqliteIngress`
|
|
2433
|
-
);
|
|
2284
|
+
const orderSnapshot = this.normalizeOrderCollectionsForIngress((0, _lodashEs.cloneDeep)(order), `${source}.sqliteIngress`);
|
|
2434
2285
|
try {
|
|
2435
2286
|
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
2436
|
-
let writeMethod =
|
|
2437
|
-
this.logInfo(
|
|
2287
|
+
let writeMethod = 'none';
|
|
2288
|
+
this.logInfo('updateOrderInSQLite-开始', {
|
|
2438
2289
|
source,
|
|
2439
2290
|
orderId: orderSnapshot.order_id ?? null,
|
|
2440
2291
|
storageKey: this.getOrderStorageKey(orderSnapshot)
|
|
2441
2292
|
});
|
|
2442
|
-
if (typeof this.dbManager.update ===
|
|
2443
|
-
writeMethod =
|
|
2293
|
+
if (typeof this.dbManager.update === 'function') {
|
|
2294
|
+
writeMethod = 'update';
|
|
2444
2295
|
await this.dbManager.update(INDEXDB_STORE_NAME, orderSnapshot);
|
|
2445
|
-
} else if (typeof this.dbManager.bulkUpdate ===
|
|
2446
|
-
writeMethod =
|
|
2296
|
+
} else if (typeof this.dbManager.bulkUpdate === 'function') {
|
|
2297
|
+
writeMethod = 'bulkUpdate';
|
|
2447
2298
|
await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, [orderSnapshot]);
|
|
2448
|
-
} else if (typeof this.dbManager.bulkAdd ===
|
|
2449
|
-
writeMethod =
|
|
2299
|
+
} else if (typeof this.dbManager.bulkAdd === 'function') {
|
|
2300
|
+
writeMethod = 'bulkAdd';
|
|
2450
2301
|
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, [orderSnapshot]);
|
|
2451
2302
|
} else if (options.throwOnError) {
|
|
2452
|
-
throw new Error(
|
|
2303
|
+
throw new Error('订单 SQLite 数据库不支持写入');
|
|
2453
2304
|
}
|
|
2454
2305
|
this.recordRecentSqliteWrite(source, [orderSnapshot]);
|
|
2455
|
-
this.logInfo(
|
|
2306
|
+
this.logInfo('updateOrderInSQLite-完成', {
|
|
2456
2307
|
source,
|
|
2457
2308
|
orderId: orderSnapshot.order_id ?? null,
|
|
2458
2309
|
writeMethod
|
|
2459
2310
|
});
|
|
2460
2311
|
});
|
|
2461
2312
|
} catch (error) {
|
|
2462
|
-
this.logError(
|
|
2313
|
+
this.logError('单条保存订单到 SQLite 失败', {
|
|
2463
2314
|
error: error instanceof Error ? error.message : String(error),
|
|
2464
2315
|
orderId: orderSnapshot.order_id ?? null
|
|
2465
2316
|
});
|
|
2466
|
-
if (options.throwOnError)
|
|
2467
|
-
throw error;
|
|
2317
|
+
if (options.throwOnError) throw error;
|
|
2468
2318
|
}
|
|
2469
2319
|
}
|
|
2320
|
+
|
|
2470
2321
|
/**
|
|
2471
2322
|
* 全量快照替换 orders 表(clear + bulkAdd),并保留本地 draft / need_sync / pending 支付订单。
|
|
2472
2323
|
* 用于 SSE 全量拉取与营业日窗口裁剪。
|
|
@@ -2476,34 +2327,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2476
2327
|
*/
|
|
2477
2328
|
async replaceOrdersSnapshotInSQLite(orderList, source, protectedOrdersBeforeRemoteFetch = []) {
|
|
2478
2329
|
if (!this.dbManager) {
|
|
2479
|
-
return this.compactOrderListByIdentity(
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
}
|
|
2484
|
-
const remoteSnapshot = (0, import_lodash_es.cloneDeep)(orderList).map(
|
|
2485
|
-
(order) => this.normalizeOrderCollectionsForIngress(order, `${source}.remoteIngress`)
|
|
2486
|
-
);
|
|
2487
|
-
let mergedSnapshot = this.compactOrderListByIdentity(
|
|
2488
|
-
remoteSnapshot.map((order) => this.normalizeRemoteSyncedOrder(order)),
|
|
2489
|
-
`${source}.remoteSnapshot`
|
|
2490
|
-
).list;
|
|
2330
|
+
return this.compactOrderListByIdentity(orderList.map(order => this.normalizeRemoteSyncedOrder(order)), `${source}.snapshotNoDb`).list;
|
|
2331
|
+
}
|
|
2332
|
+
const remoteSnapshot = (0, _lodashEs.cloneDeep)(orderList).map(order => this.normalizeOrderCollectionsForIngress(order, `${source}.remoteIngress`));
|
|
2333
|
+
let mergedSnapshot = this.compactOrderListByIdentity(remoteSnapshot.map(order => this.normalizeRemoteSyncedOrder(order)), `${source}.remoteSnapshot`).list;
|
|
2491
2334
|
try {
|
|
2492
2335
|
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
2493
|
-
const existingOrders = typeof this.dbManager.getAll ===
|
|
2494
|
-
const protectedLocalOrders = protectedOrdersBeforeRemoteFetch.map((order) => this.
|
|
2495
|
-
order,
|
|
2496
|
-
`${source}.protectedBeforeRemoteFetch`
|
|
2497
|
-
)).filter((order) => this.shouldProtectLocalOrderFromRemoteSnapshot(order));
|
|
2336
|
+
const existingOrders = typeof this.dbManager.getAll === 'function' ? await this.dbManager.getAll(INDEXDB_STORE_NAME) : [];
|
|
2337
|
+
const protectedLocalOrders = protectedOrdersBeforeRemoteFetch.map(order => this.normalizeOrderCollectionsForIngress(order, `${source}.protectedBeforeRemoteFetch`)).filter(order => this.shouldProtectLocalOrderFromRemoteSnapshot(order));
|
|
2498
2338
|
for (const rawCurrentOrder of existingOrders || []) {
|
|
2499
|
-
const currentOrder = this.normalizeOrderCollectionsForIngress(
|
|
2500
|
-
|
|
2501
|
-
`${source}.currentSQLite`
|
|
2502
|
-
);
|
|
2503
|
-
const protectedIndex = this.findOrderIndexByIdentity(
|
|
2504
|
-
protectedLocalOrders,
|
|
2505
|
-
currentOrder
|
|
2506
|
-
);
|
|
2339
|
+
const currentOrder = this.normalizeOrderCollectionsForIngress(rawCurrentOrder, `${source}.currentSQLite`);
|
|
2340
|
+
const protectedIndex = this.findOrderIndexByIdentity(protectedLocalOrders, currentOrder);
|
|
2507
2341
|
const currentNeedsProtection = this.shouldProtectLocalOrderFromRemoteSnapshot(currentOrder);
|
|
2508
2342
|
if (protectedIndex >= 0) {
|
|
2509
2343
|
if (currentNeedsProtection) {
|
|
@@ -2513,33 +2347,26 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2513
2347
|
}
|
|
2514
2348
|
continue;
|
|
2515
2349
|
}
|
|
2516
|
-
if (currentNeedsProtection)
|
|
2517
|
-
protectedLocalOrders.push(currentOrder);
|
|
2350
|
+
if (currentNeedsProtection) protectedLocalOrders.push(currentOrder);
|
|
2518
2351
|
}
|
|
2519
|
-
const orderListSnapshot = this.mergeRemoteSnapshotWithPendingOrders(
|
|
2520
|
-
remoteSnapshot,
|
|
2521
|
-
protectedLocalOrders
|
|
2522
|
-
);
|
|
2352
|
+
const orderListSnapshot = this.mergeRemoteSnapshotWithPendingOrders(remoteSnapshot, protectedLocalOrders);
|
|
2523
2353
|
mergedSnapshot = this.compactOrderListByIdentity(orderListSnapshot, `${source}.sqliteSnapshot`).list;
|
|
2524
|
-
this.logInfo(
|
|
2354
|
+
this.logInfo('replaceOrdersSnapshotInSQLite-开始', {
|
|
2525
2355
|
source,
|
|
2526
2356
|
count: mergedSnapshot.length,
|
|
2527
2357
|
remoteCount: remoteSnapshot.length,
|
|
2528
2358
|
protectedBeforeRemoteFetchCount: protectedOrdersBeforeRemoteFetch.length,
|
|
2529
2359
|
protectedLocalOrderCount: protectedLocalOrders.length,
|
|
2530
2360
|
preservedLocalUnsyncedCount: mergedSnapshot.length - remoteSnapshot.length,
|
|
2531
|
-
protectedPendingPaymentCount: protectedLocalOrders.reduce(
|
|
2532
|
-
|
|
2533
|
-
0
|
|
2534
|
-
),
|
|
2535
|
-
protectedPendingPaymentIdentities: protectedLocalOrders.flatMap((order) => this.getIdentifiedPendingPayments(order).map((payment) => ({
|
|
2361
|
+
protectedPendingPaymentCount: protectedLocalOrders.reduce((count, order) => count + this.getIdentifiedPendingPayments(order).length, 0),
|
|
2362
|
+
protectedPendingPaymentIdentities: protectedLocalOrders.flatMap(order => this.getIdentifiedPendingPayments(order).map(payment => ({
|
|
2536
2363
|
order_id: order.order_id ?? null,
|
|
2537
2364
|
external_sale_number: order.external_sale_number ?? null,
|
|
2538
|
-
payment_identities: (0,
|
|
2365
|
+
payment_identities: (0, _paymentUtils.getOrderPaymentIdentityKeys)(payment)
|
|
2539
2366
|
})))
|
|
2540
2367
|
});
|
|
2541
2368
|
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
2542
|
-
this.logInfo(
|
|
2369
|
+
this.logInfo('replaceOrdersSnapshotInSQLite-clear完成', {
|
|
2543
2370
|
count: mergedSnapshot.length
|
|
2544
2371
|
});
|
|
2545
2372
|
if (mergedSnapshot.length === 0) {
|
|
@@ -2547,19 +2374,20 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2547
2374
|
}
|
|
2548
2375
|
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, mergedSnapshot);
|
|
2549
2376
|
this.recordRecentSqliteWrite(source, mergedSnapshot);
|
|
2550
|
-
this.logInfo(
|
|
2377
|
+
this.logInfo('replaceOrdersSnapshotInSQLite-bulkAdd完成', {
|
|
2551
2378
|
source,
|
|
2552
2379
|
count: mergedSnapshot.length
|
|
2553
2380
|
});
|
|
2554
2381
|
});
|
|
2555
2382
|
} catch (error) {
|
|
2556
|
-
this.logError(
|
|
2383
|
+
this.logError('全量保存订单到 SQLite 失败', {
|
|
2557
2384
|
error: error instanceof Error ? error.message : String(error),
|
|
2558
2385
|
orderList: remoteSnapshot.length
|
|
2559
2386
|
});
|
|
2560
2387
|
}
|
|
2561
2388
|
return mergedSnapshot;
|
|
2562
2389
|
}
|
|
2390
|
+
|
|
2563
2391
|
/**
|
|
2564
2392
|
* 清空订单模块的内存数据和本地 SQLite 订单表。
|
|
2565
2393
|
*
|
|
@@ -2568,17 +2396,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2568
2396
|
*/
|
|
2569
2397
|
async clear() {
|
|
2570
2398
|
this.store.list = [];
|
|
2571
|
-
this.store.map =
|
|
2399
|
+
this.store.map = new Map();
|
|
2572
2400
|
if (this.dbManager) {
|
|
2573
2401
|
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
2574
2402
|
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
2575
2403
|
});
|
|
2576
2404
|
}
|
|
2577
|
-
this.setStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY,
|
|
2578
|
-
this.emitOrdersChanged([],
|
|
2405
|
+
this.setStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY, '');
|
|
2406
|
+
this.emitOrdersChanged([], 'clear');
|
|
2579
2407
|
}
|
|
2580
|
-
}
|
|
2581
|
-
|
|
2582
|
-
0 && (module.exports = {
|
|
2583
|
-
OrderModule
|
|
2584
|
-
});
|
|
2408
|
+
}
|
|
2409
|
+
exports.OrderModule = OrderModule;
|