@pisell/pisellos 2.2.244 → 2.2.245
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/model/strategy/adapter/promotion/evaluator.js +3 -2
- package/dist/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/model/strategy/adapter/walletPass/utils.js +7 -4
- package/dist/modules/BookingContext/index.d.ts +48 -0
- package/dist/modules/BookingContext/index.js +566 -0
- package/dist/modules/BookingContext/types.d.ts +102 -0
- package/dist/modules/BookingContext/types.js +51 -0
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +284 -0
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +145 -0
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +218 -0
- package/dist/modules/BookingContext/utils/flexible.d.ts +28 -0
- package/dist/modules/BookingContext/utils/flexible.js +56 -0
- package/dist/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
- package/dist/modules/BookingContext/utils/formatResourceList.js +38 -0
- package/dist/modules/BookingContext/utils/index.d.ts +11 -0
- package/dist/modules/BookingContext/utils/index.js +11 -0
- package/dist/modules/BookingContext/utils/noResource.d.ts +13 -0
- package/dist/modules/BookingContext/utils/noResource.js +77 -0
- package/dist/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
- package/dist/modules/BookingContext/utils/orderLineDisplay.js +36 -0
- package/dist/modules/BookingContext/utils/productExtend.d.ts +72 -0
- package/dist/modules/BookingContext/utils/productExtend.js +339 -0
- package/dist/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
- package/dist/modules/BookingContext/utils/resourceErrors.js +74 -0
- package/dist/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
- package/dist/modules/BookingContext/utils/resourceSelection.js +24 -0
- package/dist/modules/BookingContext/utils/resources.d.ts +80 -0
- package/dist/modules/BookingContext/utils/resources.js +486 -0
- package/dist/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
- package/dist/modules/BookingContext/utils/serviceTimes.js +151 -0
- package/dist/modules/BookingContext/utils/timeSlices.d.ts +42 -0
- package/dist/modules/BookingContext/utils/timeSlices.js +100 -0
- package/dist/modules/Cart/utils/cartProduct.js +24 -3
- package/dist/modules/Cart/utils/changePrice.js +11 -11
- package/dist/modules/Customer/index.d.ts +20 -0
- package/dist/modules/Customer/index.js +172 -83
- package/dist/modules/Customer/types.d.ts +2 -0
- package/dist/modules/Discount/index.d.ts +1 -1
- package/dist/modules/Discount/index.js +13 -6
- package/dist/modules/Discount/types.d.ts +1 -0
- package/dist/modules/OpenData/index.d.ts +8 -0
- package/dist/modules/OpenData/index.js +37 -17
- package/dist/modules/Order/index.d.ts +275 -19
- package/dist/modules/Order/index.js +3493 -809
- package/dist/modules/Order/types.d.ts +286 -31
- package/dist/modules/Order/types.js +38 -0
- package/dist/modules/Order/utils/manualProductDiscount.d.ts +106 -0
- package/dist/modules/Order/utils/manualProductDiscount.js +210 -0
- package/dist/modules/Order/utils.d.ts +147 -5
- package/dist/modules/Order/utils.js +750 -104
- package/dist/modules/Payment/index.d.ts +10 -13
- package/dist/modules/Payment/index.js +467 -837
- package/dist/modules/Payment/types.d.ts +2 -0
- package/dist/modules/Payment/utils.js +2 -1
- package/dist/modules/Payment/walletpass.js +41 -25
- package/dist/modules/ProductList/index.d.ts +16 -12
- package/dist/modules/ProductList/index.js +133 -59
- package/dist/modules/ProductList/types.d.ts +14 -0
- package/dist/modules/Quotation/index.d.ts +0 -1
- package/dist/modules/Quotation/index.js +25 -22
- package/dist/modules/Rules/index.d.ts +4 -0
- package/dist/modules/Rules/index.js +97 -70
- package/dist/modules/Rules/types.d.ts +1 -0
- package/dist/modules/SalesSummary/index.d.ts +8 -25
- package/dist/modules/SalesSummary/index.js +86 -35
- package/dist/modules/SalesSummary/types.d.ts +4 -1
- package/dist/modules/SalesSummary/utils.d.ts +2 -25
- package/dist/modules/SalesSummary/utils.js +794 -162
- package/dist/modules/Schedule/index.d.ts +7 -0
- package/dist/modules/Schedule/index.js +24 -2
- package/dist/modules/Summary/index.js +4 -3
- package/dist/modules/SurchargeList/index.d.ts +16 -0
- package/dist/modules/SurchargeList/index.js +162 -0
- package/dist/modules/SurchargeList/types.d.ts +11 -0
- package/dist/modules/SurchargeList/types.js +1 -0
- package/dist/modules/index.d.ts +2 -0
- package/dist/modules/index.js +3 -1
- package/dist/plugins/request.d.ts +1 -0
- package/dist/server/index.d.ts +204 -1
- package/dist/server/index.js +3654 -922
- package/dist/server/modules/index.d.ts +2 -0
- package/dist/server/modules/index.js +2 -0
- package/dist/server/modules/order/index.d.ts +120 -3
- package/dist/server/modules/order/index.js +1758 -448
- package/dist/server/modules/order/types.d.ts +32 -3
- package/dist/server/modules/order/types.js +8 -0
- package/dist/server/modules/order/utils/filterBookings.js +26 -3
- package/dist/server/modules/order/utils/filterOrders.js +23 -8
- package/dist/server/modules/payment/index.d.ts +28 -0
- package/dist/server/modules/payment/index.js +305 -0
- package/dist/server/modules/payment/types.d.ts +9 -0
- package/dist/server/modules/payment/types.js +1 -0
- package/dist/server/modules/products/index.d.ts +34 -7
- package/dist/server/modules/products/index.js +631 -317
- package/dist/server/modules/resource/index.d.ts +2 -0
- package/dist/server/modules/resource/index.js +29 -3
- package/dist/server/modules/schedule/index.d.ts +4 -4
- package/dist/server/modules/schedule/index.js +111 -88
- package/dist/server/test.json +713 -0
- package/dist/server/utils/small-ticket.d.ts +71 -0
- package/dist/server/utils/small-ticket.js +840 -0
- package/dist/solution/BaseSales/index.d.ts +133 -10
- package/dist/solution/BaseSales/index.js +1950 -447
- package/dist/solution/BaseSales/types.d.ts +82 -6
- package/dist/solution/BaseSales/types.js +5 -4
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
- package/dist/solution/BaseSales/utils/cartPromotion.js +1438 -0
- package/dist/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
- package/dist/solution/BaseSales/utils/quotationPrice.js +237 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +105 -24
- package/dist/solution/BaseSales/utils.d.ts +1 -1
- package/dist/solution/BaseSales/utils.js +62 -21
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +271 -11
- package/dist/solution/BookingTicket/index.js +1777 -242
- package/dist/solution/BookingTicket/types.d.ts +118 -1
- package/dist/solution/BookingTicket/types.js +41 -2
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
- package/dist/solution/BookingTicket/utils/addProductDecision.js +346 -0
- package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
- package/dist/solution/BookingTicket/utils/addTimeAvailability.js +95 -0
- package/dist/solution/BookingTicket/utils/bookingStatus.d.ts +40 -0
- package/dist/solution/BookingTicket/utils/bookingStatus.js +70 -0
- package/dist/solution/BookingTicket/utils/cartView.d.ts +9 -1
- package/dist/solution/BookingTicket/utils/cartView.js +94 -7
- package/dist/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/dist/solution/BookingTicket/utils/exampleData.js +183 -0
- package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
- package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.js +438 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +400 -0
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +56 -0
- package/dist/solution/BookingTicket/utils/scan/index.d.ts +5 -0
- package/dist/solution/BookingTicket/utils/scan/index.js +20 -8
- package/dist/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
- package/dist/solution/BookingTicket/utils/scan/scanProductValues.js +150 -0
- package/dist/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
- package/dist/solution/BookingTicket/utils/sessionCatalogStale.js +78 -0
- package/dist/solution/Checkout/index.d.ts +1 -0
- package/dist/solution/Checkout/index.js +10 -9
- package/dist/solution/RegisterAndLogin/config.js +2 -10
- package/dist/solution/ScanOrder/index.d.ts +9 -3
- package/dist/solution/ScanOrder/index.js +241 -134
- package/dist/solution/ScanOrder/types.d.ts +9 -5
- package/dist/solution/ScanOrder/types.js +2 -3
- package/dist/solution/ScanOrder/utils.d.ts +1 -1
- package/dist/solution/ScanOrder/utils.js +84 -22
- package/dist/solution/VenueBooking/index.d.ts +5 -2
- package/dist/solution/VenueBooking/index.js +110 -59
- package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
- package/dist/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
- package/dist/solution/VenueBooking/utils/slotMerge.js +10 -0
- package/dist/types/index.d.ts +10 -0
- package/lib/model/strategy/adapter/promotion/evaluator.js +2 -1
- package/lib/model/strategy/adapter/promotion/index.js +49 -0
- package/lib/model/strategy/adapter/walletPass/utils.js +3 -2
- package/lib/modules/BookingContext/index.d.ts +48 -0
- package/lib/modules/BookingContext/index.js +368 -0
- package/lib/modules/BookingContext/types.d.ts +102 -0
- package/lib/modules/BookingContext/types.js +34 -0
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +276 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +151 -0
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +201 -0
- package/lib/modules/BookingContext/utils/flexible.d.ts +28 -0
- package/lib/modules/BookingContext/utils/flexible.js +80 -0
- package/lib/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
- package/lib/modules/BookingContext/utils/formatResourceList.js +50 -0
- package/lib/modules/BookingContext/utils/index.d.ts +11 -0
- package/lib/modules/BookingContext/utils/index.js +43 -0
- package/lib/modules/BookingContext/utils/noResource.d.ts +13 -0
- package/lib/modules/BookingContext/utils/noResource.js +90 -0
- package/lib/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +56 -0
- package/lib/modules/BookingContext/utils/productExtend.d.ts +72 -0
- package/lib/modules/BookingContext/utils/productExtend.js +283 -0
- package/lib/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
- package/lib/modules/BookingContext/utils/resourceErrors.js +80 -0
- package/lib/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
- package/lib/modules/BookingContext/utils/resourceSelection.js +46 -0
- package/lib/modules/BookingContext/utils/resources.d.ts +80 -0
- package/lib/modules/BookingContext/utils/resources.js +377 -0
- package/lib/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
- package/lib/modules/BookingContext/utils/serviceTimes.js +162 -0
- package/lib/modules/BookingContext/utils/timeSlices.d.ts +42 -0
- package/lib/modules/BookingContext/utils/timeSlices.js +124 -0
- package/lib/modules/Cart/utils/cartProduct.js +20 -3
- package/lib/modules/Cart/utils/changePrice.js +12 -20
- package/lib/modules/Customer/index.d.ts +20 -0
- package/lib/modules/Customer/index.js +64 -11
- package/lib/modules/Customer/types.d.ts +2 -0
- package/lib/modules/Discount/index.d.ts +1 -1
- package/lib/modules/Discount/index.js +9 -1
- package/lib/modules/Discount/types.d.ts +1 -0
- package/lib/modules/OpenData/index.d.ts +8 -0
- package/lib/modules/OpenData/index.js +19 -5
- package/lib/modules/Order/index.d.ts +275 -19
- package/lib/modules/Order/index.js +2245 -336
- package/lib/modules/Order/types.d.ts +286 -31
- package/lib/modules/Order/types.js +1 -0
- package/lib/modules/Order/utils/manualProductDiscount.d.ts +106 -0
- package/lib/modules/Order/utils/manualProductDiscount.js +206 -0
- package/lib/modules/Order/utils.d.ts +147 -5
- package/lib/modules/Order/utils.js +615 -46
- package/lib/modules/Payment/index.d.ts +10 -13
- package/lib/modules/Payment/index.js +18 -150
- package/lib/modules/Payment/types.d.ts +2 -0
- package/lib/modules/Payment/utils.js +2 -1
- package/lib/modules/Payment/walletpass.js +16 -3
- package/lib/modules/ProductList/index.d.ts +16 -12
- package/lib/modules/ProductList/index.js +41 -4
- package/lib/modules/ProductList/types.d.ts +14 -0
- package/lib/modules/Quotation/index.d.ts +0 -1
- package/lib/modules/Quotation/index.js +19 -16
- package/lib/modules/Rules/index.d.ts +4 -0
- package/lib/modules/Rules/index.js +137 -120
- package/lib/modules/Rules/types.d.ts +1 -0
- package/lib/modules/SalesSummary/index.d.ts +8 -25
- package/lib/modules/SalesSummary/index.js +30 -4
- package/lib/modules/SalesSummary/types.d.ts +4 -1
- package/lib/modules/SalesSummary/utils.d.ts +2 -25
- package/lib/modules/SalesSummary/utils.js +645 -91
- package/lib/modules/Schedule/index.d.ts +7 -0
- package/lib/modules/Schedule/index.js +17 -1
- package/lib/modules/Summary/index.js +5 -4
- package/lib/modules/SurchargeList/index.d.ts +16 -0
- package/lib/modules/SurchargeList/index.js +89 -0
- package/lib/modules/SurchargeList/types.d.ts +11 -0
- package/lib/modules/SurchargeList/types.js +17 -0
- package/lib/modules/index.d.ts +2 -0
- package/lib/modules/index.js +5 -1
- package/lib/plugins/request.d.ts +1 -0
- package/lib/server/index.d.ts +204 -1
- package/lib/server/index.js +1891 -59
- package/lib/server/modules/index.d.ts +2 -0
- package/lib/server/modules/index.js +3 -0
- package/lib/server/modules/order/index.d.ts +120 -3
- package/lib/server/modules/order/index.js +883 -94
- package/lib/server/modules/order/types.d.ts +32 -3
- package/lib/server/modules/order/utils/filterBookings.js +24 -5
- package/lib/server/modules/order/utils/filterOrders.js +15 -6
- package/lib/server/modules/payment/index.d.ts +28 -0
- package/lib/server/modules/payment/index.js +192 -0
- package/lib/server/modules/payment/types.d.ts +9 -0
- package/lib/server/modules/payment/types.js +17 -0
- package/lib/server/modules/products/index.d.ts +34 -7
- package/lib/server/modules/products/index.js +189 -54
- package/lib/server/modules/resource/index.d.ts +2 -0
- package/lib/server/modules/resource/index.js +27 -3
- package/lib/server/modules/schedule/index.d.ts +4 -4
- package/lib/server/modules/schedule/index.js +47 -40
- package/lib/server/test.json +713 -0
- package/lib/server/utils/small-ticket.d.ts +71 -0
- package/lib/server/utils/small-ticket.js +800 -0
- package/lib/solution/BaseSales/index.d.ts +133 -10
- package/lib/solution/BaseSales/index.js +1111 -63
- package/lib/solution/BaseSales/types.d.ts +82 -6
- package/lib/solution/BaseSales/types.js +3 -1
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
- package/lib/solution/BaseSales/utils/cartPromotion.js +992 -0
- package/lib/solution/BaseSales/utils/quotationPrice.d.ts +7 -0
- package/lib/solution/BaseSales/utils/quotationPrice.js +277 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +106 -18
- package/lib/solution/BaseSales/utils.d.ts +1 -1
- package/lib/solution/BaseSales/utils.js +54 -10
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +271 -11
- package/lib/solution/BookingTicket/index.js +922 -29
- package/lib/solution/BookingTicket/types.d.ts +118 -1
- package/lib/solution/BookingTicket/types.js +11 -0
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
- package/lib/solution/BookingTicket/utils/addProductDecision.js +318 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +125 -0
- package/lib/solution/BookingTicket/utils/bookingStatus.d.ts +40 -0
- package/lib/solution/BookingTicket/utils/bookingStatus.js +44 -2
- package/lib/solution/BookingTicket/utils/cartView.d.ts +9 -1
- package/lib/solution/BookingTicket/utils/cartView.js +61 -6
- package/lib/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/lib/solution/BookingTicket/utils/exampleData.js +0 -0
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +254 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +169 -0
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +51 -0
- package/lib/solution/BookingTicket/utils/scan/index.d.ts +5 -0
- package/lib/solution/BookingTicket/utils/scan/index.js +17 -3
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +127 -0
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +85 -0
- package/lib/solution/Checkout/index.d.ts +1 -0
- package/lib/solution/Checkout/index.js +1 -2
- package/lib/solution/RegisterAndLogin/config.js +2 -10
- package/lib/solution/ScanOrder/index.d.ts +9 -3
- package/lib/solution/ScanOrder/index.js +153 -70
- package/lib/solution/ScanOrder/types.d.ts +9 -5
- package/lib/solution/ScanOrder/utils.d.ts +1 -1
- package/lib/solution/ScanOrder/utils.js +83 -17
- package/lib/solution/VenueBooking/index.d.ts +5 -2
- package/lib/solution/VenueBooking/index.js +54 -17
- package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
- package/lib/solution/VenueBooking/utils/slotMerge.d.ts +4 -0
- package/lib/solution/VenueBooking/utils/slotMerge.js +10 -0
- package/lib/types/index.d.ts +10 -0
- package/package.json +1 -1
- package/dist/solution/Checkout/appointmentDemo.json +0 -1
- package/lib/solution/Checkout/appointmentDemo.json +0 -1
package/lib/server/index.js
CHANGED
|
@@ -41,6 +41,7 @@ var import_schedule = require("./modules/schedule");
|
|
|
41
41
|
var import_resource = require("./modules/resource");
|
|
42
42
|
var import_floor_plan = require("./modules/floor-plan");
|
|
43
43
|
var import_types = require("./modules/floor-plan/types");
|
|
44
|
+
var import_payment = require("./modules/payment");
|
|
44
45
|
var import_schedule2 = require("./utils/schedule");
|
|
45
46
|
var import_types2 = require("./modules/products/types");
|
|
46
47
|
var import_product = require("./utils/product");
|
|
@@ -48,9 +49,22 @@ var import_order = require("./modules/order");
|
|
|
48
49
|
var import_types3 = require("./modules/order/types");
|
|
49
50
|
var import_filterOrders = require("./modules/order/utils/filterOrders");
|
|
50
51
|
var import_filterBookings = require("./modules/order/utils/filterBookings");
|
|
52
|
+
var import_small_ticket = require("./utils/small-ticket");
|
|
51
53
|
__reExport(server_exports, require("./modules"), module.exports);
|
|
54
|
+
var PRODUCT_TITLE_SNAPSHOT_KEYS = [
|
|
55
|
+
"en",
|
|
56
|
+
"ja",
|
|
57
|
+
"pt",
|
|
58
|
+
"auto",
|
|
59
|
+
"zh-CN",
|
|
60
|
+
"zh-HK",
|
|
61
|
+
"kitchen",
|
|
62
|
+
"original"
|
|
63
|
+
];
|
|
52
64
|
var Server = class {
|
|
53
65
|
constructor(core) {
|
|
66
|
+
this.quotationAvailableCache = /* @__PURE__ */ new Map();
|
|
67
|
+
this.quotationAvailableInFlight = /* @__PURE__ */ new Map();
|
|
54
68
|
/** GET 前缀路由(最长前缀优先匹配) */
|
|
55
69
|
this.prefixRouterGet = [];
|
|
56
70
|
// 路由注册表
|
|
@@ -69,6 +83,8 @@ var Server = class {
|
|
|
69
83
|
this.bookingRemoteCache = /* @__PURE__ */ new Map();
|
|
70
84
|
this.BOOKING_REMOTE_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
71
85
|
this.BOOKING_REMOTE_CACHE_MAX_ENTRIES = 80;
|
|
86
|
+
this.salesSearchSubscribers = /* @__PURE__ */ new Map();
|
|
87
|
+
this.deviceTaskActionsRegistered = false;
|
|
72
88
|
this.floorPlanQuerySubscribers = /* @__PURE__ */ new Map();
|
|
73
89
|
// 模块注册表 - 定义所有可用的模块配置
|
|
74
90
|
this.moduleRegistry = {
|
|
@@ -120,6 +136,15 @@ var Server = class {
|
|
|
120
136
|
list: []
|
|
121
137
|
}
|
|
122
138
|
},
|
|
139
|
+
payment: {
|
|
140
|
+
name: "payment",
|
|
141
|
+
moduleClass: import_payment.PaymentServerModule,
|
|
142
|
+
moduleName: "server_payment",
|
|
143
|
+
version: "1.0.0",
|
|
144
|
+
defaultStore: {
|
|
145
|
+
payMethods: []
|
|
146
|
+
}
|
|
147
|
+
},
|
|
123
148
|
resource: {
|
|
124
149
|
name: "resource",
|
|
125
150
|
moduleClass: import_resource.ResourceModule,
|
|
@@ -143,31 +168,67 @@ var Server = class {
|
|
|
143
168
|
}
|
|
144
169
|
}
|
|
145
170
|
};
|
|
171
|
+
this.handlePaymentMethods = async ({ data, config }) => {
|
|
172
|
+
const payment = await this.getPaymentRouteModule();
|
|
173
|
+
const payMethods = await payment.getPayMethodListAsync({
|
|
174
|
+
shouldFilter: (data == null ? void 0 : data.filterPaymentMethods) === true || (config == null ? void 0 : config.filterPaymentMethods) === true
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
code: 200,
|
|
178
|
+
status: true,
|
|
179
|
+
data: payMethods
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
this.handleQuotationAvailable = async ({ data }) => {
|
|
183
|
+
const queryPayload = data && typeof data === "object" ? { ...data } : {};
|
|
184
|
+
const cacheKey = this.stableSerialize(queryPayload);
|
|
185
|
+
if (this.quotationAvailableCache.has(cacheKey)) {
|
|
186
|
+
this.logInfo("handleQuotationAvailable: 命中运行时缓存", { cacheKey });
|
|
187
|
+
return this.quotationAvailableCache.get(cacheKey);
|
|
188
|
+
}
|
|
189
|
+
const inFlight = this.quotationAvailableInFlight.get(cacheKey);
|
|
190
|
+
if (inFlight) {
|
|
191
|
+
this.logInfo("handleQuotationAvailable: 复用进行中的请求", { cacheKey });
|
|
192
|
+
return inFlight;
|
|
193
|
+
}
|
|
194
|
+
const requestPromise = this.fetchQuotationAvailableFromAPI(queryPayload).then((response) => {
|
|
195
|
+
if (this.isSuccessfulRemoteResponse(response)) {
|
|
196
|
+
this.quotationAvailableCache.set(cacheKey, response);
|
|
197
|
+
}
|
|
198
|
+
return response;
|
|
199
|
+
}).finally(() => {
|
|
200
|
+
this.quotationAvailableInFlight.delete(cacheKey);
|
|
201
|
+
});
|
|
202
|
+
this.quotationAvailableInFlight.set(cacheKey, requestPromise);
|
|
203
|
+
return requestPromise;
|
|
204
|
+
};
|
|
146
205
|
/**
|
|
147
206
|
* 处理商品查询请求
|
|
148
207
|
* 存储订阅者信息,便于数据变更时推送最新结果
|
|
149
208
|
*/
|
|
150
209
|
this.handleProductQuery = async ({ url, method, data, config }) => {
|
|
151
210
|
console.log("[Server] handleProductQuery:", url, method, data, config);
|
|
152
|
-
const { menu_list_ids, schedule_datetime, schedule_date, customer_id } = data;
|
|
211
|
+
const { menu_list_ids, schedule_datetime, schedule_date, customer_id, ids, extension_type } = data;
|
|
153
212
|
const { callback, subscriberId } = config || {};
|
|
154
213
|
this.logInfo("handleProductQuery: 开始处理商品查询请求", {
|
|
155
214
|
menu_list_ids,
|
|
215
|
+
ids,
|
|
156
216
|
schedule_datetime,
|
|
157
217
|
schedule_date,
|
|
158
|
-
customer_id
|
|
218
|
+
customer_id,
|
|
219
|
+
extension_type
|
|
159
220
|
});
|
|
160
221
|
if (subscriberId && typeof callback === "function") {
|
|
161
222
|
this.productQuerySubscribers.set(subscriberId, {
|
|
162
223
|
callback,
|
|
163
|
-
context: { menu_list_ids, schedule_date, schedule_datetime, customer_id }
|
|
224
|
+
context: { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type }
|
|
164
225
|
});
|
|
165
226
|
this.logInfo("handleProductQuery: 已注册订阅者", {
|
|
166
227
|
subscriberId,
|
|
167
228
|
totalSubscribers: this.productQuerySubscribers.size
|
|
168
229
|
});
|
|
169
230
|
}
|
|
170
|
-
return this.computeProductQueryResult({ menu_list_ids, schedule_date, schedule_datetime, customer_id });
|
|
231
|
+
return this.computeProductQueryResult({ menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type });
|
|
171
232
|
};
|
|
172
233
|
/**
|
|
173
234
|
* 按商品 id 查询单条(GET /shop/product/query/:productId)
|
|
@@ -269,6 +330,41 @@ var Server = class {
|
|
|
269
330
|
}
|
|
270
331
|
return { code: 200, message: "ok", status: true };
|
|
271
332
|
};
|
|
333
|
+
/**
|
|
334
|
+
* 处理 sales 单模块搜索:请求透传后端,仅在 OS 层维护已返回订单号集合。
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* await this.handleSalesSearchModule({ url: '/shop/es/search/sales', method: 'post', data: { keyword: 'A' } })
|
|
338
|
+
*/
|
|
339
|
+
this.handleSalesSearchModule = async ({ data, config }) => {
|
|
340
|
+
return this.handleSalesSearchRequest("single", "/shop/es/search/sales", data, config);
|
|
341
|
+
};
|
|
342
|
+
/**
|
|
343
|
+
* 处理 sales 聚合搜索:请求透传后端,仅订阅 sales 分组的已返回订单号。
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* await this.handleSalesSearchAggregate({ url: '/shop/es/search', method: 'post', data: { modules: [] } })
|
|
347
|
+
*/
|
|
348
|
+
this.handleSalesSearchAggregate = async ({ data, config }) => {
|
|
349
|
+
return this.handleSalesSearchRequest("aggregate", "/shop/es/search", data, config);
|
|
350
|
+
};
|
|
351
|
+
/**
|
|
352
|
+
* 取消 sales 搜索订阅。
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* await this.handleUnsubscribeSalesSearch({ data: { subscriberId: 'global-search-order' } } as any)
|
|
356
|
+
*/
|
|
357
|
+
this.handleUnsubscribeSalesSearch = async ({ data }) => {
|
|
358
|
+
const { subscriberId } = data || {};
|
|
359
|
+
if (subscriberId) {
|
|
360
|
+
this.salesSearchSubscribers.delete(subscriberId);
|
|
361
|
+
this.logInfo("handleUnsubscribeSalesSearch: 已移除订阅者", {
|
|
362
|
+
subscriberId,
|
|
363
|
+
remaining: this.salesSearchSubscribers.size
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
return { code: 200, message: "ok", status: true };
|
|
367
|
+
};
|
|
272
368
|
/**
|
|
273
369
|
* 日历(compact_fields)场景下要直接在 SSE 层排除的订单类型:
|
|
274
370
|
* 这些类型不会出现在日历上,拉取它们只会浪费带宽并增加前端过滤成本。
|
|
@@ -372,7 +468,13 @@ var Server = class {
|
|
|
372
468
|
* @example 批量:GET /update/localOrder?order_ids=96971,96972,96973
|
|
373
469
|
*/
|
|
374
470
|
this.handleUpdateLocalOrder = async ({ url, data }) => {
|
|
375
|
-
var _a;
|
|
471
|
+
var _a, _b;
|
|
472
|
+
if (typeof (data == null ? void 0 : data.order_id) === "string" && ((_a = data == null ? void 0 : data.order_id) == null ? void 0 : _a.startsWith("LOCAL_"))) {
|
|
473
|
+
return {
|
|
474
|
+
code: 200,
|
|
475
|
+
status: true
|
|
476
|
+
};
|
|
477
|
+
}
|
|
376
478
|
const batchIds = this.parseOrderIdsParam(url, data);
|
|
377
479
|
if (batchIds.length > 0) {
|
|
378
480
|
return this.handleUpdateLocalOrdersBatch(batchIds);
|
|
@@ -388,7 +490,7 @@ var Server = class {
|
|
|
388
490
|
this.logError("handleUpdateLocalOrder: Order 模块未注册");
|
|
389
491
|
return { code: 500, status: false, message: "Order 模块未注册", data: null };
|
|
390
492
|
}
|
|
391
|
-
if (!((
|
|
493
|
+
if (!((_b = this.app) == null ? void 0 : _b.request)) {
|
|
392
494
|
this.logError("handleUpdateLocalOrder: app.request 不可用");
|
|
393
495
|
return { code: 500, status: false, message: "app.request 不可用", data: null };
|
|
394
496
|
}
|
|
@@ -451,34 +553,149 @@ var Server = class {
|
|
|
451
553
|
};
|
|
452
554
|
}
|
|
453
555
|
};
|
|
556
|
+
this.handleOrderSalesCheckout = async ({ data }) => {
|
|
557
|
+
return this.handleOrderCheckoutSubmit({
|
|
558
|
+
backendPath: "/shop/order/sales/checkout",
|
|
559
|
+
data,
|
|
560
|
+
title: "handleOrderSalesCheckout"
|
|
561
|
+
});
|
|
562
|
+
};
|
|
563
|
+
this.handleOrderCheckout = async ({ data }) => {
|
|
564
|
+
return this.handleOrderCheckoutSubmit({
|
|
565
|
+
backendPath: "/order/checkout",
|
|
566
|
+
data,
|
|
567
|
+
title: "handleOrderCheckout"
|
|
568
|
+
});
|
|
569
|
+
};
|
|
570
|
+
this.handleLocalPrintOrder = async ({ data }) => {
|
|
571
|
+
var _a;
|
|
572
|
+
try {
|
|
573
|
+
const inputOrder = (data == null ? void 0 : data.order) && typeof data.order === "object" ? data.order : data;
|
|
574
|
+
if (!inputOrder || typeof inputOrder !== "object") {
|
|
575
|
+
return {
|
|
576
|
+
code: 400,
|
|
577
|
+
status: false,
|
|
578
|
+
message: "订单数据不能为空",
|
|
579
|
+
data: { printed: false, order: null }
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
const shouldLookup = this.shouldLookupLocalPrintOrder(inputOrder) || this.shouldLookupLocalPrintOrder(data);
|
|
583
|
+
this.logInfo("handleLocalPrintOrder: 是否需要查找本地订单", {
|
|
584
|
+
shouldLookup,
|
|
585
|
+
inputOrder,
|
|
586
|
+
data
|
|
587
|
+
});
|
|
588
|
+
const lookup = shouldLookup ? this.getLocalPrintOrderLookup(inputOrder) ?? this.getLocalPrintOrderLookup(data) : void 0;
|
|
589
|
+
let sourceOrder = inputOrder;
|
|
590
|
+
if (shouldLookup) {
|
|
591
|
+
if (lookup === void 0) {
|
|
592
|
+
return {
|
|
593
|
+
code: 400,
|
|
594
|
+
status: false,
|
|
595
|
+
message: "订单 lookup 缺失",
|
|
596
|
+
data: { printed: false, order: null }
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
if (!((_a = this.order) == null ? void 0 : _a.getLocalOrderByLookup)) {
|
|
600
|
+
return {
|
|
601
|
+
code: 500,
|
|
602
|
+
status: false,
|
|
603
|
+
message: "Order 模块未注册",
|
|
604
|
+
data: { printed: false, order: null }
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
const localOrder = await this.order.getLocalOrderByLookup(lookup);
|
|
608
|
+
if (!localOrder) {
|
|
609
|
+
return {
|
|
610
|
+
code: 404,
|
|
611
|
+
status: false,
|
|
612
|
+
message: "订单不存在",
|
|
613
|
+
data: { printed: false, order: null }
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
sourceOrder = {
|
|
617
|
+
...localOrder,
|
|
618
|
+
...inputOrder,
|
|
619
|
+
order_id: localOrder.order_id ?? inputOrder.order_id ?? inputOrder.orderId,
|
|
620
|
+
external_sale_number: localOrder.external_sale_number ?? inputOrder.external_sale_number ?? inputOrder.externalSaleNumber
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
const checkoutData = await this.ensureCheckoutOrderNumbers(
|
|
624
|
+
{
|
|
625
|
+
...sourceOrder,
|
|
626
|
+
small_ticket_data_flag: 1
|
|
627
|
+
},
|
|
628
|
+
"handleLocalPrintOrder"
|
|
629
|
+
);
|
|
630
|
+
const printableOrder = {
|
|
631
|
+
...checkoutData,
|
|
632
|
+
need_sync: checkoutData.need_sync ?? 1
|
|
633
|
+
};
|
|
634
|
+
this.logInfo("handleLocalPrintOrder: 本地打印小票,构建触发任务前", {
|
|
635
|
+
checkoutData,
|
|
636
|
+
printableOrder
|
|
637
|
+
});
|
|
638
|
+
const printResult = await this.dispatchLocalReceiptPrint({
|
|
639
|
+
checkoutData,
|
|
640
|
+
order: printableOrder,
|
|
641
|
+
response: null,
|
|
642
|
+
requireFullyPaid: false
|
|
643
|
+
});
|
|
644
|
+
return {
|
|
645
|
+
code: 200,
|
|
646
|
+
status: true,
|
|
647
|
+
message: "",
|
|
648
|
+
data: {
|
|
649
|
+
printed: printResult.printed,
|
|
650
|
+
order: printResult.order
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
} catch (error) {
|
|
654
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
655
|
+
this.logError("handleLocalPrintOrder: 本地打印小票失败", { error: message });
|
|
656
|
+
return {
|
|
657
|
+
code: 500,
|
|
658
|
+
status: false,
|
|
659
|
+
message,
|
|
660
|
+
data: { printed: false, order: null }
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
};
|
|
454
664
|
this.handleOrderSalesDetail = async ({ url, data, path }) => {
|
|
455
665
|
var _a;
|
|
456
666
|
const requestPath = this.parseRequestPath(url, path);
|
|
457
|
-
const
|
|
458
|
-
this.logInfo("handleOrderSalesDetail: 开始处理", { url, path: requestPath,
|
|
459
|
-
if (!
|
|
460
|
-
this.logWarning("handleOrderSalesDetail:
|
|
461
|
-
return { code: 400, status: false, message: "
|
|
667
|
+
const lookup = this.extractOrderSalesDetailLookup(requestPath);
|
|
668
|
+
this.logInfo("handleOrderSalesDetail: 开始处理", { url, path: requestPath, lookup });
|
|
669
|
+
if (!lookup) {
|
|
670
|
+
this.logWarning("handleOrderSalesDetail: lookup 缺失", { url, path: requestPath });
|
|
671
|
+
return { code: 400, status: false, message: "订单 lookup 缺失", data: null };
|
|
462
672
|
}
|
|
463
673
|
if (!this.order) {
|
|
464
674
|
this.logError("handleOrderSalesDetail: Order 模块未注册");
|
|
465
675
|
return { code: 500, status: false, message: "Order 模块未注册", data: null };
|
|
466
676
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
677
|
+
if (!this.shouldForceRemoteSalesDetail(data)) {
|
|
678
|
+
const localOrder = await this.order.getLocalOrderByLookup(lookup);
|
|
679
|
+
if (localOrder) {
|
|
680
|
+
this.logInfo("handleOrderSalesDetail: 命中本地订单", { lookup });
|
|
681
|
+
return {
|
|
682
|
+
code: 200,
|
|
683
|
+
status: true,
|
|
684
|
+
message: "",
|
|
685
|
+
data: localOrder
|
|
686
|
+
};
|
|
687
|
+
}
|
|
476
688
|
}
|
|
477
689
|
if (!((_a = this.app) == null ? void 0 : _a.request)) {
|
|
478
690
|
this.logError("handleOrderSalesDetail: app.request 不可用");
|
|
479
|
-
return {
|
|
691
|
+
return {
|
|
692
|
+
code: 500,
|
|
693
|
+
status: false,
|
|
694
|
+
message: "app.request 不可用",
|
|
695
|
+
data: null
|
|
696
|
+
};
|
|
480
697
|
}
|
|
481
|
-
const backendPath = this.buildOrderSalesDetailBackendPath(
|
|
698
|
+
const backendPath = this.buildOrderSalesDetailBackendPath(lookup, data);
|
|
482
699
|
try {
|
|
483
700
|
const response = await this.app.request.get(backendPath, {
|
|
484
701
|
lookup_mode: "multi"
|
|
@@ -489,8 +706,8 @@ var Server = class {
|
|
|
489
706
|
});
|
|
490
707
|
const fresh = (response == null ? void 0 : response.data) ?? response;
|
|
491
708
|
if (!fresh || typeof fresh !== "object" || fresh.order_id == null) {
|
|
492
|
-
this.
|
|
493
|
-
|
|
709
|
+
this.logInfo("handleOrderSalesDetail: 后端返回订单为空", {
|
|
710
|
+
lookup,
|
|
494
711
|
backendPath
|
|
495
712
|
});
|
|
496
713
|
return {
|
|
@@ -501,9 +718,9 @@ var Server = class {
|
|
|
501
718
|
};
|
|
502
719
|
}
|
|
503
720
|
await this.order.upsertOrdersFromRemote([fresh]);
|
|
504
|
-
const savedOrder = await this.order.
|
|
721
|
+
const savedOrder = await this.order.getLocalOrderByLookup(lookup);
|
|
505
722
|
if (!savedOrder) {
|
|
506
|
-
this.logError("handleOrderSalesDetail: 订单写入后回读失败", {
|
|
723
|
+
this.logError("handleOrderSalesDetail: 订单写入后回读失败", { lookup });
|
|
507
724
|
return {
|
|
508
725
|
code: 500,
|
|
509
726
|
status: false,
|
|
@@ -511,7 +728,7 @@ var Server = class {
|
|
|
511
728
|
data: null
|
|
512
729
|
};
|
|
513
730
|
}
|
|
514
|
-
this.logInfo("handleOrderSalesDetail: 远端订单已同步到本地", {
|
|
731
|
+
this.logInfo("handleOrderSalesDetail: 远端订单已同步到本地", { lookup });
|
|
515
732
|
return {
|
|
516
733
|
code: 200,
|
|
517
734
|
status: true,
|
|
@@ -521,7 +738,7 @@ var Server = class {
|
|
|
521
738
|
} catch (error) {
|
|
522
739
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
523
740
|
this.logError("handleOrderSalesDetail: 请求失败", {
|
|
524
|
-
|
|
741
|
+
lookup,
|
|
525
742
|
backendPath,
|
|
526
743
|
error: errorMessage
|
|
527
744
|
});
|
|
@@ -890,6 +1107,7 @@ var Server = class {
|
|
|
890
1107
|
moduleConfigs
|
|
891
1108
|
});
|
|
892
1109
|
this.registerServerRoutes();
|
|
1110
|
+
this.registerDeviceTaskActions();
|
|
893
1111
|
const registeredModules = await this.registerModules(moduleConfigs);
|
|
894
1112
|
if (autoPreload) {
|
|
895
1113
|
await this.preloadModulesData(registeredModules, options);
|
|
@@ -905,10 +1123,11 @@ var Server = class {
|
|
|
905
1123
|
this.core.effects.on(import_types.FloorPlanHooks.onFloorPlansChanged, () => {
|
|
906
1124
|
void this.recomputeAndNotifyFloorPlanQuery();
|
|
907
1125
|
});
|
|
908
|
-
this.core.effects.on(import_types3.OrderHooks.onOrdersChanged, () => {
|
|
1126
|
+
this.core.effects.on(import_types3.OrderHooks.onOrdersChanged, (payload) => {
|
|
909
1127
|
this.recomputeAndNotifyOrderQuery();
|
|
910
1128
|
this.recomputeAndNotifyBookingQuery();
|
|
911
1129
|
this.syncBookingRemoteCacheFromOrderChanges();
|
|
1130
|
+
this.notifySalesSearchSubscribers(payload);
|
|
912
1131
|
});
|
|
913
1132
|
const duration = Date.now() - startTime;
|
|
914
1133
|
this.logInfo("Server 初始化完成", {
|
|
@@ -917,20 +1136,236 @@ var Server = class {
|
|
|
917
1136
|
});
|
|
918
1137
|
return registeredModules;
|
|
919
1138
|
}
|
|
1139
|
+
registerDeviceTaskActions() {
|
|
1140
|
+
if (this.deviceTaskActionsRegistered)
|
|
1141
|
+
return;
|
|
1142
|
+
const deviceTask = this.getDeviceTaskPlugin();
|
|
1143
|
+
if (!(deviceTask == null ? void 0 : deviceTask.registerAction)) {
|
|
1144
|
+
this.logWarning("registerDeviceTaskActions: deviceTask 插件不可用");
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
const registeredActions = new Set(
|
|
1148
|
+
typeof deviceTask.getActions === "function" ? (deviceTask.getActions() || []).map((action) => action == null ? void 0 : action.action).filter(Boolean) : []
|
|
1149
|
+
);
|
|
1150
|
+
const register = (definition) => {
|
|
1151
|
+
var _a;
|
|
1152
|
+
if (registeredActions.has(definition.action))
|
|
1153
|
+
return;
|
|
1154
|
+
(_a = deviceTask.registerAction) == null ? void 0 : _a.call(deviceTask, definition);
|
|
1155
|
+
registeredActions.add(definition.action);
|
|
1156
|
+
};
|
|
1157
|
+
register({
|
|
1158
|
+
action: "sync_sales",
|
|
1159
|
+
name: "同步订单",
|
|
1160
|
+
validate: (payload) => (payload == null ? void 0 : payload.backendPath) && (payload == null ? void 0 : payload.data) ? null : "缺少 backendPath 或 data",
|
|
1161
|
+
handler: (ctx) => this.handleSyncSalesTask(ctx)
|
|
1162
|
+
});
|
|
1163
|
+
this.deviceTaskActionsRegistered = true;
|
|
1164
|
+
this.logInfo("DeviceTask actions 已注册", {
|
|
1165
|
+
actions: ["sync_sales"]
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
async handleSyncSalesTask(ctx) {
|
|
1169
|
+
var _a, _b, _c;
|
|
1170
|
+
const payload = ((_a = ctx.task) == null ? void 0 : _a.payload) || {};
|
|
1171
|
+
const backendPath = payload.backendPath;
|
|
1172
|
+
const data = payload.data;
|
|
1173
|
+
const title = payload.title || "sync_sales";
|
|
1174
|
+
if (!backendPath || !data) {
|
|
1175
|
+
return this.taskFail("INVALID_PAYLOAD", "缺少 backendPath 或 data");
|
|
1176
|
+
}
|
|
1177
|
+
if (!((_b = this.app) == null ? void 0 : _b.request)) {
|
|
1178
|
+
this.logError(`${title}: sync_sales app.request 不可用`);
|
|
1179
|
+
return this.taskTimeout("app.request 不可用");
|
|
1180
|
+
}
|
|
1181
|
+
try {
|
|
1182
|
+
const syncResult = await this.runCheckoutSync({
|
|
1183
|
+
backendPath,
|
|
1184
|
+
data,
|
|
1185
|
+
title,
|
|
1186
|
+
externalSaleNumber: payload.external_sale_number,
|
|
1187
|
+
deviceId: (_c = ctx.task) == null ? void 0 : _c.device_id,
|
|
1188
|
+
persistCheckoutDataWithResponse: false
|
|
1189
|
+
});
|
|
1190
|
+
if (syncResult.rejected) {
|
|
1191
|
+
this.logError(`${title}: sync_sales 后端明确失败`, {
|
|
1192
|
+
backendPath,
|
|
1193
|
+
response: syncResult.errorResponse
|
|
1194
|
+
});
|
|
1195
|
+
return this.taskFail(
|
|
1196
|
+
"BACKEND_REJECTED",
|
|
1197
|
+
syncResult.message || "后端明确拒绝 checkout",
|
|
1198
|
+
syncResult.errorResponse
|
|
1199
|
+
);
|
|
1200
|
+
}
|
|
1201
|
+
return this.taskOk({
|
|
1202
|
+
order: syncResult.syncedOrder ?? null,
|
|
1203
|
+
response: syncResult.normalizedResponse
|
|
1204
|
+
});
|
|
1205
|
+
} catch (error) {
|
|
1206
|
+
const backendError = this.extractBackendErrorResponse(error);
|
|
1207
|
+
if (backendError) {
|
|
1208
|
+
const message = (backendError == null ? void 0 : backendError.message) || "后端明确拒绝 checkout";
|
|
1209
|
+
this.logError(`${title}: sync_sales 后端明确失败`, {
|
|
1210
|
+
backendPath,
|
|
1211
|
+
backendError
|
|
1212
|
+
});
|
|
1213
|
+
return this.taskFail("BACKEND_REJECTED", message, backendError);
|
|
1214
|
+
}
|
|
1215
|
+
const errorMessage = this.getUnknownErrorMessage(error);
|
|
1216
|
+
this.logError(`${title}: sync_sales 请求未明确成功`, {
|
|
1217
|
+
backendPath,
|
|
1218
|
+
error: errorMessage,
|
|
1219
|
+
error_detail: this.normalizeUnknownError(error)
|
|
1220
|
+
});
|
|
1221
|
+
return this.taskTimeout(errorMessage);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
async runCheckoutSync(params) {
|
|
1225
|
+
var _a, _b;
|
|
1226
|
+
const { backendPath, title } = params;
|
|
1227
|
+
const normalizedData = await this.normalizeCheckoutSubmitData(params.data, title);
|
|
1228
|
+
const checkoutData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
|
|
1229
|
+
const remoteCheckoutData = this.omitCheckoutSyncMode(checkoutData);
|
|
1230
|
+
if (!((_b = (_a = this.app) == null ? void 0 : _a.request) == null ? void 0 : _b.post)) {
|
|
1231
|
+
throw new Error("app.request 不可用");
|
|
1232
|
+
}
|
|
1233
|
+
const response = await this.app.request.post(backendPath, remoteCheckoutData, {
|
|
1234
|
+
isShopApi: true,
|
|
1235
|
+
customToast: () => {
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1238
|
+
if (this.isCheckoutResponseRejected(response)) {
|
|
1239
|
+
return {
|
|
1240
|
+
rejected: true,
|
|
1241
|
+
message: (response == null ? void 0 : response.message) || "后端明确拒绝 checkout",
|
|
1242
|
+
errorResponse: response,
|
|
1243
|
+
response,
|
|
1244
|
+
normalizedResponse: this.normalizeCheckoutResponse(response),
|
|
1245
|
+
checkoutData: remoteCheckoutData
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
const fresh = this.extractOrderDataFromCheckoutResponse(response);
|
|
1249
|
+
const externalSaleNumber = this.getCheckoutExternalSaleNumber(
|
|
1250
|
+
remoteCheckoutData,
|
|
1251
|
+
{
|
|
1252
|
+
external_sale_number: params.externalSaleNumber,
|
|
1253
|
+
data: remoteCheckoutData
|
|
1254
|
+
}
|
|
1255
|
+
);
|
|
1256
|
+
const syncedOrder = await this.persistSyncedCheckoutOrder({
|
|
1257
|
+
backendPath,
|
|
1258
|
+
checkoutData: remoteCheckoutData,
|
|
1259
|
+
externalSaleNumber,
|
|
1260
|
+
fresh,
|
|
1261
|
+
title,
|
|
1262
|
+
persistCheckoutDataWithResponse: params.persistCheckoutDataWithResponse === true
|
|
1263
|
+
});
|
|
1264
|
+
const printableSyncedOrder = syncedOrder ? this.buildSyncedOrderForPrint({
|
|
1265
|
+
syncedOrder,
|
|
1266
|
+
checkoutResponseOrder: fresh
|
|
1267
|
+
}) : void 0;
|
|
1268
|
+
if (printableSyncedOrder && this.shouldPrintSyncedOrder({
|
|
1269
|
+
checkoutData: remoteCheckoutData,
|
|
1270
|
+
syncedOrder: printableSyncedOrder
|
|
1271
|
+
})) {
|
|
1272
|
+
await this.dispatchPrintOtherReceiptTask({
|
|
1273
|
+
checkoutData: remoteCheckoutData,
|
|
1274
|
+
syncedOrder: printableSyncedOrder,
|
|
1275
|
+
response,
|
|
1276
|
+
deviceId: params.deviceId
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
return {
|
|
1280
|
+
rejected: false,
|
|
1281
|
+
response,
|
|
1282
|
+
normalizedResponse: this.normalizeCheckoutResponse(response),
|
|
1283
|
+
checkoutData: remoteCheckoutData,
|
|
1284
|
+
syncedOrder,
|
|
1285
|
+
fresh
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
omitCheckoutSyncMode(data) {
|
|
1289
|
+
if (!data || typeof data !== "object")
|
|
1290
|
+
return data;
|
|
1291
|
+
const next = { ...data };
|
|
1292
|
+
delete next.sync_mode;
|
|
1293
|
+
delete next.syncMode;
|
|
1294
|
+
return next;
|
|
1295
|
+
}
|
|
1296
|
+
async persistSyncedCheckoutOrder(params) {
|
|
1297
|
+
const {
|
|
1298
|
+
backendPath,
|
|
1299
|
+
checkoutData,
|
|
1300
|
+
externalSaleNumber,
|
|
1301
|
+
fresh,
|
|
1302
|
+
title,
|
|
1303
|
+
persistCheckoutDataWithResponse
|
|
1304
|
+
} = params;
|
|
1305
|
+
const shouldMergeRemoteOrder = fresh ? this.isMergeableCheckoutOrder(fresh, externalSaleNumber) : false;
|
|
1306
|
+
let syncedOrder;
|
|
1307
|
+
if (this.order && fresh && (shouldMergeRemoteOrder || persistCheckoutDataWithResponse)) {
|
|
1308
|
+
syncedOrder = persistCheckoutDataWithResponse ? {
|
|
1309
|
+
...checkoutData,
|
|
1310
|
+
...fresh,
|
|
1311
|
+
external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
|
|
1312
|
+
need_sync: 0
|
|
1313
|
+
} : {
|
|
1314
|
+
...fresh,
|
|
1315
|
+
external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
|
|
1316
|
+
need_sync: 0
|
|
1317
|
+
};
|
|
1318
|
+
await this.order.upsertOrdersFromRemote([syncedOrder]);
|
|
1319
|
+
this.logInfo(`${title}: sync_sales 完整订单已同步到本地`, {
|
|
1320
|
+
order_id: fresh.order_id,
|
|
1321
|
+
external_sale_number: syncedOrder.external_sale_number,
|
|
1322
|
+
order_number: fresh.order_number,
|
|
1323
|
+
mergedRemoteOrder: shouldMergeRemoteOrder,
|
|
1324
|
+
persistedCheckoutDataWithResponse: persistCheckoutDataWithResponse
|
|
1325
|
+
});
|
|
1326
|
+
} else if (this.order && externalSaleNumber && typeof this.order.markOrderSyncedByExternalSaleNumber === "function") {
|
|
1327
|
+
const patch = this.buildCheckoutSyncSuccessPatch(fresh);
|
|
1328
|
+
const result = await this.order.markOrderSyncedByExternalSaleNumber({
|
|
1329
|
+
externalSaleNumber,
|
|
1330
|
+
patch
|
|
1331
|
+
});
|
|
1332
|
+
syncedOrder = (result == null ? void 0 : result.order) || {
|
|
1333
|
+
...checkoutData,
|
|
1334
|
+
...patch,
|
|
1335
|
+
external_sale_number: externalSaleNumber,
|
|
1336
|
+
need_sync: 0
|
|
1337
|
+
};
|
|
1338
|
+
this.logInfo(`${title}: sync_sales 已按 external_sale_number 标记本地订单`, {
|
|
1339
|
+
order_id: (syncedOrder == null ? void 0 : syncedOrder.order_id) ?? null,
|
|
1340
|
+
external_sale_number: externalSaleNumber,
|
|
1341
|
+
hasRemoteOrder: !!fresh,
|
|
1342
|
+
mergedRemoteOrder: false
|
|
1343
|
+
});
|
|
1344
|
+
} else {
|
|
1345
|
+
this.logWarning(`${title}: sync_sales Order 模块未注册`, {
|
|
1346
|
+
backendPath,
|
|
1347
|
+
external_sale_number: externalSaleNumber,
|
|
1348
|
+
order_id: fresh == null ? void 0 : fresh.order_id
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
return syncedOrder;
|
|
1352
|
+
}
|
|
920
1353
|
/**
|
|
921
1354
|
* 将普通层 QuotationModule 的报价单计算能力桥接到 Server Products 模块。
|
|
922
1355
|
*/
|
|
923
1356
|
async setupProductsQuotationPriceBridge() {
|
|
924
1357
|
var _a;
|
|
925
1358
|
if (!this.products) {
|
|
926
|
-
this.
|
|
1359
|
+
this.logInfo("setupProductsQuotationPriceBridge: Products 模块未注册");
|
|
927
1360
|
return;
|
|
928
1361
|
}
|
|
929
1362
|
if (!this.schedule) {
|
|
930
|
-
this.
|
|
1363
|
+
this.logInfo("setupProductsQuotationPriceBridge: Schedule 模块未注册");
|
|
931
1364
|
return;
|
|
932
1365
|
}
|
|
933
1366
|
try {
|
|
1367
|
+
await this.schedule.loadAllSchedule();
|
|
1368
|
+
this.products.clearPriceCache();
|
|
934
1369
|
await this.products.setupQuotationPriceBridge({
|
|
935
1370
|
scheduleModule: this.schedule,
|
|
936
1371
|
channel: (_a = this.core.context) == null ? void 0 : _a.channel
|
|
@@ -1218,6 +1653,26 @@ var Server = class {
|
|
|
1218
1653
|
path: "/shop/order/v2/list/unsubscribe",
|
|
1219
1654
|
handler: this.handleUnsubscribeOrderQuery.bind(this)
|
|
1220
1655
|
},
|
|
1656
|
+
{
|
|
1657
|
+
method: "post",
|
|
1658
|
+
path: "/shop/es/search/sales",
|
|
1659
|
+
handler: this.handleSalesSearchModule.bind(this)
|
|
1660
|
+
},
|
|
1661
|
+
{
|
|
1662
|
+
method: "post",
|
|
1663
|
+
path: "/shop/es/search/sales/unsubscribe",
|
|
1664
|
+
handler: this.handleUnsubscribeSalesSearch.bind(this)
|
|
1665
|
+
},
|
|
1666
|
+
{
|
|
1667
|
+
method: "post",
|
|
1668
|
+
path: "/shop/es/search",
|
|
1669
|
+
handler: this.handleSalesSearchAggregate.bind(this)
|
|
1670
|
+
},
|
|
1671
|
+
{
|
|
1672
|
+
method: "post",
|
|
1673
|
+
path: "/shop/es/search/unsubscribe",
|
|
1674
|
+
handler: this.handleUnsubscribeSalesSearch.bind(this)
|
|
1675
|
+
},
|
|
1221
1676
|
{
|
|
1222
1677
|
method: "get",
|
|
1223
1678
|
path: "/shop/schedule/booking",
|
|
@@ -1237,6 +1692,36 @@ var Server = class {
|
|
|
1237
1692
|
method: "get",
|
|
1238
1693
|
path: "/update/localOrder",
|
|
1239
1694
|
handler: this.handleUpdateLocalOrder.bind(this)
|
|
1695
|
+
},
|
|
1696
|
+
{
|
|
1697
|
+
method: "get",
|
|
1698
|
+
path: "/shop/pay/custom-payment/all",
|
|
1699
|
+
handler: this.handlePaymentMethods.bind(this)
|
|
1700
|
+
},
|
|
1701
|
+
{
|
|
1702
|
+
method: "get",
|
|
1703
|
+
path: "/shop/quotation/available",
|
|
1704
|
+
handler: this.handleQuotationAvailable.bind(this)
|
|
1705
|
+
},
|
|
1706
|
+
{
|
|
1707
|
+
method: "get",
|
|
1708
|
+
path: "/quotation/available",
|
|
1709
|
+
handler: this.handleQuotationAvailable.bind(this)
|
|
1710
|
+
},
|
|
1711
|
+
{
|
|
1712
|
+
method: "post",
|
|
1713
|
+
path: "/shop/order/sales/checkout",
|
|
1714
|
+
handler: this.handleOrderSalesCheckout.bind(this)
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
method: "post",
|
|
1718
|
+
path: "/order/checkout",
|
|
1719
|
+
handler: this.handleOrderCheckout.bind(this)
|
|
1720
|
+
},
|
|
1721
|
+
{
|
|
1722
|
+
method: "post",
|
|
1723
|
+
path: "/shop/local/print-order",
|
|
1724
|
+
handler: this.handleLocalPrintOrder.bind(this)
|
|
1240
1725
|
}
|
|
1241
1726
|
]);
|
|
1242
1727
|
this.registerPrefixRoutes([
|
|
@@ -1252,6 +1737,50 @@ var Server = class {
|
|
|
1252
1737
|
}
|
|
1253
1738
|
]);
|
|
1254
1739
|
}
|
|
1740
|
+
async getPaymentRouteModule() {
|
|
1741
|
+
if (this.payment)
|
|
1742
|
+
return this.payment;
|
|
1743
|
+
if (this.paymentRouteModule)
|
|
1744
|
+
return this.paymentRouteModule;
|
|
1745
|
+
if (this.paymentRouteModuleInFlight)
|
|
1746
|
+
return this.paymentRouteModuleInFlight;
|
|
1747
|
+
this.paymentRouteModuleInFlight = (async () => {
|
|
1748
|
+
const module2 = new import_payment.PaymentServerModule("server_payment_route", "1.0.0");
|
|
1749
|
+
await module2.initialize(this.core, {
|
|
1750
|
+
store: { payMethods: [] }
|
|
1751
|
+
});
|
|
1752
|
+
this.paymentRouteModule = module2;
|
|
1753
|
+
return module2;
|
|
1754
|
+
})().finally(() => {
|
|
1755
|
+
this.paymentRouteModuleInFlight = void 0;
|
|
1756
|
+
});
|
|
1757
|
+
return this.paymentRouteModuleInFlight;
|
|
1758
|
+
}
|
|
1759
|
+
async fetchQuotationAvailableFromAPI(data) {
|
|
1760
|
+
var _a;
|
|
1761
|
+
const requester = ((_a = this.app) == null ? void 0 : _a.request) || this.core.getPlugin("request");
|
|
1762
|
+
if (!(requester == null ? void 0 : requester.get)) {
|
|
1763
|
+
this.logError("fetchQuotationAvailableFromAPI: request 不可用");
|
|
1764
|
+
return {
|
|
1765
|
+
code: 500,
|
|
1766
|
+
message: "request 不可用",
|
|
1767
|
+
data: { list: [] },
|
|
1768
|
+
status: false
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
return requester.get("/shop/quotation/available", data);
|
|
1772
|
+
}
|
|
1773
|
+
isSuccessfulRemoteResponse(response) {
|
|
1774
|
+
if (!response)
|
|
1775
|
+
return false;
|
|
1776
|
+
if (response.status === false)
|
|
1777
|
+
return false;
|
|
1778
|
+
if (typeof response.status === "number" && response.status >= 400)
|
|
1779
|
+
return false;
|
|
1780
|
+
if (response.code !== void 0 && response.code !== 200 && response.code !== "200")
|
|
1781
|
+
return false;
|
|
1782
|
+
return true;
|
|
1783
|
+
}
|
|
1255
1784
|
/**
|
|
1256
1785
|
* 根据 subscriberId 移除商品查询订阅者
|
|
1257
1786
|
*/
|
|
@@ -1265,40 +1794,196 @@ var Server = class {
|
|
|
1265
1794
|
}
|
|
1266
1795
|
}
|
|
1267
1796
|
/**
|
|
1268
|
-
*
|
|
1797
|
+
* 执行 sales 搜索并登记可见订单号。
|
|
1798
|
+
* 搜索参数完全透传后端,OS 不做过滤、筛选、排序。
|
|
1269
1799
|
*
|
|
1270
1800
|
* @example
|
|
1271
|
-
* this.
|
|
1801
|
+
* const result = await this.handleSalesSearchRequest('single', '/shop/es/search/sales', { keyword: '1001' }, {})
|
|
1272
1802
|
*/
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
const
|
|
1277
|
-
if (
|
|
1278
|
-
|
|
1803
|
+
async handleSalesSearchRequest(kind, backendPath, data, config) {
|
|
1804
|
+
const queryPayload = data && typeof data === "object" ? { ...data } : {};
|
|
1805
|
+
const result = await this.fetchSalesSearchFromAPI(backendPath, queryPayload);
|
|
1806
|
+
const { callback, subscriberId, resetVisibleOrderIds } = config || {};
|
|
1807
|
+
if (subscriberId && typeof callback === "function") {
|
|
1808
|
+
const contextSignature = this.buildSalesSearchSignature(kind, queryPayload);
|
|
1809
|
+
const existing = this.salesSearchSubscribers.get(subscriberId);
|
|
1810
|
+
const shouldReset = resetVisibleOrderIds === true || !existing || existing.kind !== kind || existing.contextSignature !== contextSignature;
|
|
1811
|
+
const visibleOrderIds = shouldReset ? /* @__PURE__ */ new Set() : new Set(existing.visibleOrderIds);
|
|
1812
|
+
for (const orderId of this.extractSalesSearchOrderIds(kind, result)) {
|
|
1813
|
+
visibleOrderIds.add(orderId);
|
|
1814
|
+
}
|
|
1815
|
+
this.salesSearchSubscribers.set(subscriberId, {
|
|
1816
|
+
callback,
|
|
1817
|
+
kind,
|
|
1818
|
+
contextSignature,
|
|
1819
|
+
visibleOrderIds,
|
|
1820
|
+
lastResponseData: this.extractSalesSearchResponseData(result)
|
|
1821
|
+
});
|
|
1822
|
+
this.logInfo("handleSalesSearchRequest: 已注册/更新订阅者", {
|
|
1823
|
+
subscriberId,
|
|
1824
|
+
kind,
|
|
1825
|
+
shouldReset,
|
|
1826
|
+
visibleCount: visibleOrderIds.size
|
|
1827
|
+
});
|
|
1279
1828
|
}
|
|
1280
|
-
|
|
1281
|
-
if (!text)
|
|
1282
|
-
return null;
|
|
1283
|
-
return text.split("T")[0].split(" ")[0] || null;
|
|
1829
|
+
return result;
|
|
1284
1830
|
}
|
|
1285
1831
|
/**
|
|
1286
|
-
*
|
|
1832
|
+
* 透传调用后端 sales 搜索接口。
|
|
1287
1833
|
*
|
|
1288
1834
|
* @example
|
|
1289
|
-
* this.
|
|
1835
|
+
* const res = await this.fetchSalesSearchFromAPI('/shop/es/search/sales', { keyword: '1001' })
|
|
1290
1836
|
*/
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
return
|
|
1296
|
-
|
|
1297
|
-
|
|
1837
|
+
async fetchSalesSearchFromAPI(backendPath, data) {
|
|
1838
|
+
var _a;
|
|
1839
|
+
if (!((_a = this.app) == null ? void 0 : _a.request)) {
|
|
1840
|
+
this.logError("fetchSalesSearchFromAPI: app.request 不可用", { backendPath });
|
|
1841
|
+
return {
|
|
1842
|
+
code: 500,
|
|
1843
|
+
message: "app.request 不可用",
|
|
1844
|
+
data: backendPath === "/shop/es/search" ? { results: [] } : { list: [], count: 0 },
|
|
1845
|
+
status: false
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1848
|
+
try {
|
|
1849
|
+
const response = await this.app.request.post(backendPath, data, {
|
|
1850
|
+
isShopApi: true
|
|
1851
|
+
});
|
|
1852
|
+
const payload = (response == null ? void 0 : response.data) ?? response;
|
|
1853
|
+
return {
|
|
1854
|
+
code: (response == null ? void 0 : response.code) ?? 200,
|
|
1855
|
+
status: (response == null ? void 0 : response.status) ?? true,
|
|
1856
|
+
message: (response == null ? void 0 : response.message) ?? "",
|
|
1857
|
+
data: payload
|
|
1858
|
+
};
|
|
1859
|
+
} catch (error) {
|
|
1860
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1861
|
+
this.logError("fetchSalesSearchFromAPI: 请求失败", {
|
|
1862
|
+
backendPath,
|
|
1863
|
+
error: errorMessage
|
|
1864
|
+
});
|
|
1865
|
+
return {
|
|
1866
|
+
code: 500,
|
|
1867
|
+
message: errorMessage,
|
|
1868
|
+
data: backendPath === "/shop/es/search" ? { results: [] } : { list: [], count: 0 },
|
|
1869
|
+
status: false
|
|
1870
|
+
};
|
|
1871
|
+
}
|
|
1298
1872
|
}
|
|
1299
1873
|
/**
|
|
1300
|
-
*
|
|
1301
|
-
*
|
|
1874
|
+
* 构建搜索订阅签名;页码变化不重置,可继续累计 visibleOrderIds。
|
|
1875
|
+
*
|
|
1876
|
+
* @example
|
|
1877
|
+
* const signature = this.buildSalesSearchSignature('single', { keyword: 'A', page: 2 })
|
|
1878
|
+
*/
|
|
1879
|
+
buildSalesSearchSignature(kind, payload) {
|
|
1880
|
+
return this.stableSerialize({
|
|
1881
|
+
kind,
|
|
1882
|
+
payload: this.stripSalesSearchPageParams(payload)
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
/**
|
|
1886
|
+
* 移除页码参数,保留 page size、keyword、filters、sort 等查询语义参数。
|
|
1887
|
+
*
|
|
1888
|
+
* @example
|
|
1889
|
+
* this.stripSalesSearchPageParams({ page: 2, per_page: 20, keyword: 'A' })
|
|
1890
|
+
*/
|
|
1891
|
+
stripSalesSearchPageParams(value) {
|
|
1892
|
+
if (Array.isArray(value)) {
|
|
1893
|
+
return value.map((item) => this.stripSalesSearchPageParams(item));
|
|
1894
|
+
}
|
|
1895
|
+
if (!value || typeof value !== "object")
|
|
1896
|
+
return value;
|
|
1897
|
+
const next = {};
|
|
1898
|
+
for (const [key, item] of Object.entries(value)) {
|
|
1899
|
+
if (key === "page" || key === "skip")
|
|
1900
|
+
continue;
|
|
1901
|
+
next[key] = this.stripSalesSearchPageParams(item);
|
|
1902
|
+
}
|
|
1903
|
+
return next;
|
|
1904
|
+
}
|
|
1905
|
+
/**
|
|
1906
|
+
* 提取响应 data,兼容 OS 包装结构与后端直接响应结构。
|
|
1907
|
+
*
|
|
1908
|
+
* @example
|
|
1909
|
+
* const data = this.extractSalesSearchResponseData(result)
|
|
1910
|
+
*/
|
|
1911
|
+
extractSalesSearchResponseData(result) {
|
|
1912
|
+
return (result == null ? void 0 : result.data) ?? result;
|
|
1913
|
+
}
|
|
1914
|
+
/**
|
|
1915
|
+
* 从搜索响应中提取 sales 命中的订单号。
|
|
1916
|
+
*
|
|
1917
|
+
* @example
|
|
1918
|
+
* const ids = this.extractSalesSearchOrderIds('single', result)
|
|
1919
|
+
*/
|
|
1920
|
+
extractSalesSearchOrderIds(kind, result) {
|
|
1921
|
+
var _a;
|
|
1922
|
+
const data = this.extractSalesSearchResponseData(result);
|
|
1923
|
+
const list = kind === "aggregate" ? (_a = this.findSalesSearchAggregateGroup(data)) == null ? void 0 : _a.list : data == null ? void 0 : data.list;
|
|
1924
|
+
if (!Array.isArray(list))
|
|
1925
|
+
return [];
|
|
1926
|
+
return list.map((item) => this.getSalesSearchOrderId(item)).filter((id) => !!id);
|
|
1927
|
+
}
|
|
1928
|
+
/**
|
|
1929
|
+
* 查找聚合搜索响应中的 sales 分组。
|
|
1930
|
+
*
|
|
1931
|
+
* @example
|
|
1932
|
+
* const group = this.findSalesSearchAggregateGroup({ results: [{ module: 'sales' }] })
|
|
1933
|
+
*/
|
|
1934
|
+
findSalesSearchAggregateGroup(data) {
|
|
1935
|
+
const results = Array.isArray(data == null ? void 0 : data.results) ? data.results : [];
|
|
1936
|
+
return results.find((item) => (item == null ? void 0 : item.module) === "sales") || null;
|
|
1937
|
+
}
|
|
1938
|
+
/**
|
|
1939
|
+
* 从订单或搜索命中项中取订单号。
|
|
1940
|
+
*
|
|
1941
|
+
* @example
|
|
1942
|
+
* const id = this.getSalesSearchOrderId({ order_id: 1001 })
|
|
1943
|
+
*/
|
|
1944
|
+
getSalesSearchOrderId(order) {
|
|
1945
|
+
if (!order || typeof order !== "object")
|
|
1946
|
+
return null;
|
|
1947
|
+
const raw = order.order_id ?? order.id;
|
|
1948
|
+
if (raw === void 0 || raw === null || raw === "")
|
|
1949
|
+
return null;
|
|
1950
|
+
return String(raw);
|
|
1951
|
+
}
|
|
1952
|
+
/**
|
|
1953
|
+
* 从查询值中提取 YYYY-MM-DD 日期串。
|
|
1954
|
+
*
|
|
1955
|
+
* @example
|
|
1956
|
+
* this.extractQueryDate('2026-04-15 09:58:00') // => '2026-04-15'
|
|
1957
|
+
*/
|
|
1958
|
+
extractQueryDate(raw) {
|
|
1959
|
+
if (raw == null)
|
|
1960
|
+
return null;
|
|
1961
|
+
const date = (0, import_dayjs.default)(raw);
|
|
1962
|
+
if (date.isValid()) {
|
|
1963
|
+
return date.format("YYYY-MM-DD");
|
|
1964
|
+
}
|
|
1965
|
+
const text = String(raw).trim();
|
|
1966
|
+
if (!text)
|
|
1967
|
+
return null;
|
|
1968
|
+
return text.split("T")[0].split(" ")[0] || null;
|
|
1969
|
+
}
|
|
1970
|
+
/**
|
|
1971
|
+
* 判断时间范围是否「开始和结束都不是今天」。
|
|
1972
|
+
*
|
|
1973
|
+
* @example
|
|
1974
|
+
* this.isRangeBothNotToday('2026-04-13', '2026-04-14') // => true
|
|
1975
|
+
*/
|
|
1976
|
+
isRangeBothNotToday(startRaw, endRaw) {
|
|
1977
|
+
const startDate = this.extractQueryDate(startRaw);
|
|
1978
|
+
const endDate = this.extractQueryDate(endRaw);
|
|
1979
|
+
if (!startDate || !endDate)
|
|
1980
|
+
return false;
|
|
1981
|
+
const today = (0, import_dayjs.default)().format("YYYY-MM-DD");
|
|
1982
|
+
return startDate !== today && endDate !== today;
|
|
1983
|
+
}
|
|
1984
|
+
/**
|
|
1985
|
+
* 订单查询是否走本地:
|
|
1986
|
+
* - 当 start_time 与 end_time 都不是今天时,走远端;
|
|
1302
1987
|
* - 其余情况走本地。
|
|
1303
1988
|
*/
|
|
1304
1989
|
shouldUseLocalOrderQuery(data) {
|
|
@@ -1704,6 +2389,734 @@ var Server = class {
|
|
|
1704
2389
|
};
|
|
1705
2390
|
}
|
|
1706
2391
|
}
|
|
2392
|
+
getDeviceTaskPlugin() {
|
|
2393
|
+
var _a, _b;
|
|
2394
|
+
return ((_b = (_a = this.app) == null ? void 0 : _a.getPlugin) == null ? void 0 : _b.call(_a, "deviceTask")) || null;
|
|
2395
|
+
}
|
|
2396
|
+
getIdGeneratorPlugin() {
|
|
2397
|
+
var _a, _b;
|
|
2398
|
+
return ((_b = (_a = this.app) == null ? void 0 : _a.getPlugin) == null ? void 0 : _b.call(_a, "idGenerator")) || null;
|
|
2399
|
+
}
|
|
2400
|
+
getAppData(key) {
|
|
2401
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
|
|
2402
|
+
const getData = (_b = (_a = this.core.getPlugin("app")) == null ? void 0 : _a.getData) == null ? void 0 : _b.call(_a);
|
|
2403
|
+
if (typeof getData === "function")
|
|
2404
|
+
return getData(key);
|
|
2405
|
+
const directValue = (_d = (_c = this.app) == null ? void 0 : _c.getData) == null ? void 0 : _d.call(_c, key);
|
|
2406
|
+
if (directValue !== void 0)
|
|
2407
|
+
return directValue;
|
|
2408
|
+
const coreData = ((_i = (_g = (_f = (_e = this.app) == null ? void 0 : _e.models) == null ? void 0 : _f.getStore) == null ? void 0 : (_h = _g.call(_f)).getDataByModel) == null ? void 0 : _i.call(_h, "core", "core")) || ((_o = (_m = (_l = (_k = (_j = this.app) == null ? void 0 : _j.data) == null ? void 0 : _k.store) == null ? void 0 : _l.getStore) == null ? void 0 : (_n = _m.call(_l)).getDataByModel) == null ? void 0 : _o.call(_n, "core", "core")) || ((_v = (_u = (_s = (_r = (_q = (_p = this.app) == null ? void 0 : _p.data) == null ? void 0 : _q.store) == null ? void 0 : _r.getStore) == null ? void 0 : (_t = _s.call(_r)).getDataByModel) == null ? void 0 : _u.call(_t, "core")) == null ? void 0 : _v.core);
|
|
2409
|
+
return coreData == null ? void 0 : coreData[key];
|
|
2410
|
+
}
|
|
2411
|
+
getSmallTicketShopInfo() {
|
|
2412
|
+
const shopInfo = this.getAppData("shop_info") || {};
|
|
2413
|
+
return {
|
|
2414
|
+
...shopInfo,
|
|
2415
|
+
currency_symbol: shopInfo.currency_symbol || this.getAppData("shop_symbol") || this.getAppData("currency_symbol"),
|
|
2416
|
+
currency_code: shopInfo.currency_code || this.getAppData("shop_currency_code") || this.getAppData("currency_code"),
|
|
2417
|
+
tax_title: shopInfo.tax_title || this.getAppData("tax_title"),
|
|
2418
|
+
tax_country_code: shopInfo.tax_country_code || this.getAppData("tax_country_code"),
|
|
2419
|
+
is_price_include_tax: shopInfo.is_price_include_tax ?? this.getAppData("is_price_include_tax")
|
|
2420
|
+
};
|
|
2421
|
+
}
|
|
2422
|
+
taskOk(result) {
|
|
2423
|
+
return { status: "success", result };
|
|
2424
|
+
}
|
|
2425
|
+
taskFail(code, message, result) {
|
|
2426
|
+
return {
|
|
2427
|
+
status: "failed",
|
|
2428
|
+
error: { code, message },
|
|
2429
|
+
...result !== void 0 ? { result } : {}
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
2432
|
+
taskTimeout(message) {
|
|
2433
|
+
return {
|
|
2434
|
+
status: "timeout",
|
|
2435
|
+
error: { code: "TIMEOUT", message }
|
|
2436
|
+
};
|
|
2437
|
+
}
|
|
2438
|
+
async getShortNumberOrDeviceId() {
|
|
2439
|
+
const getAsyncIotDeviceInfo = this.getAppData("async_iot_device_info");
|
|
2440
|
+
if (getAsyncIotDeviceInfo) {
|
|
2441
|
+
const res = await (getAsyncIotDeviceInfo == null ? void 0 : getAsyncIotDeviceInfo());
|
|
2442
|
+
if (res == null ? void 0 : res.short_number) {
|
|
2443
|
+
return res == null ? void 0 : res.short_number;
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
return String(this.getAppData("device_id") || 0).slice(-2);
|
|
2447
|
+
}
|
|
2448
|
+
buildCheckoutTaskIdempotencyKey(data) {
|
|
2449
|
+
const identity = (data == null ? void 0 : data.request_unique_idempotency_token) || (data == null ? void 0 : data.external_sale_number) || (data == null ? void 0 : data.order_id) || (data == null ? void 0 : data.shop_order_number) || (data == null ? void 0 : data.shop_full_order_number);
|
|
2450
|
+
if (identity === void 0 || identity === null || identity === "")
|
|
2451
|
+
return void 0;
|
|
2452
|
+
return `sync_sales:${identity}`;
|
|
2453
|
+
}
|
|
2454
|
+
isBlankCheckoutValue(value) {
|
|
2455
|
+
return value === void 0 || value === null || value === "";
|
|
2456
|
+
}
|
|
2457
|
+
isLocalCheckoutOrderId(orderId) {
|
|
2458
|
+
return typeof orderId === "string" && orderId.startsWith("LOCAL_");
|
|
2459
|
+
}
|
|
2460
|
+
async normalizeCheckoutSubmitData(data, title) {
|
|
2461
|
+
if (!data || typeof data !== "object")
|
|
2462
|
+
return data;
|
|
2463
|
+
const next = { ...data };
|
|
2464
|
+
const externalSaleNumber = next.external_sale_number;
|
|
2465
|
+
const shouldClearLocalOrderId = this.isLocalCheckoutOrderId(next.order_id);
|
|
2466
|
+
if (shouldClearLocalOrderId)
|
|
2467
|
+
next.order_id = null;
|
|
2468
|
+
const hasCheckoutOrderNumbers = !this.isBlankCheckoutValue(next.shop_order_number) && !this.isBlankCheckoutValue(next.shop_full_order_number);
|
|
2469
|
+
if (hasCheckoutOrderNumbers) {
|
|
2470
|
+
this.logInfo(`${title}: checkout 已携带订单号,跳过查重`, {
|
|
2471
|
+
original_order_id: data.order_id,
|
|
2472
|
+
order_id: next.order_id,
|
|
2473
|
+
external_sale_number: externalSaleNumber,
|
|
2474
|
+
shop_order_number: next.shop_order_number,
|
|
2475
|
+
shop_full_order_number: next.shop_full_order_number
|
|
2476
|
+
});
|
|
2477
|
+
return next;
|
|
2478
|
+
}
|
|
2479
|
+
if (this.isBlankCheckoutValue(externalSaleNumber)) {
|
|
2480
|
+
if (shouldClearLocalOrderId) {
|
|
2481
|
+
this.logInfo(`${title}: checkout 本地订单号已清理`, {
|
|
2482
|
+
original_order_id: data.order_id,
|
|
2483
|
+
order_id: next.order_id
|
|
2484
|
+
});
|
|
2485
|
+
}
|
|
2486
|
+
return next;
|
|
2487
|
+
}
|
|
2488
|
+
if (!this.order || typeof this.order.getLocalOrderFromMemoryByLookup !== "function") {
|
|
2489
|
+
if (shouldClearLocalOrderId) {
|
|
2490
|
+
this.logInfo(`${title}: checkout 本地订单号已清理`, {
|
|
2491
|
+
original_order_id: data.order_id,
|
|
2492
|
+
external_sale_number: externalSaleNumber
|
|
2493
|
+
});
|
|
2494
|
+
}
|
|
2495
|
+
return next;
|
|
2496
|
+
}
|
|
2497
|
+
try {
|
|
2498
|
+
const localOrder = this.order.getLocalOrderFromMemoryByLookup(externalSaleNumber);
|
|
2499
|
+
if (!localOrder) {
|
|
2500
|
+
if (shouldClearLocalOrderId) {
|
|
2501
|
+
this.logInfo(`${title}: checkout 本地订单号已清理`, {
|
|
2502
|
+
original_order_id: data.order_id,
|
|
2503
|
+
external_sale_number: externalSaleNumber,
|
|
2504
|
+
localOrderFound: false
|
|
2505
|
+
});
|
|
2506
|
+
}
|
|
2507
|
+
return next;
|
|
2508
|
+
}
|
|
2509
|
+
if (this.isBlankCheckoutValue(next.shop_order_number)) {
|
|
2510
|
+
next.shop_order_number = localOrder.shop_order_number;
|
|
2511
|
+
}
|
|
2512
|
+
if (this.isBlankCheckoutValue(next.shop_full_order_number)) {
|
|
2513
|
+
next.shop_full_order_number = localOrder.shop_full_order_number;
|
|
2514
|
+
}
|
|
2515
|
+
this.logInfo(`${title}: checkout 已复用本地订单号`, {
|
|
2516
|
+
original_order_id: data.order_id,
|
|
2517
|
+
order_id: next.order_id,
|
|
2518
|
+
external_sale_number: externalSaleNumber,
|
|
2519
|
+
local_order_id: localOrder.order_id,
|
|
2520
|
+
shop_order_number: next.shop_order_number,
|
|
2521
|
+
shop_full_order_number: next.shop_full_order_number
|
|
2522
|
+
});
|
|
2523
|
+
delete next.vouchers;
|
|
2524
|
+
return next;
|
|
2525
|
+
} catch (error) {
|
|
2526
|
+
this.logWarning(`${title}: checkout 查找本地订单失败`, {
|
|
2527
|
+
external_sale_number: externalSaleNumber,
|
|
2528
|
+
error: this.getUnknownErrorMessage(error),
|
|
2529
|
+
error_detail: this.normalizeUnknownError(error)
|
|
2530
|
+
});
|
|
2531
|
+
return next;
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
async ensureCheckoutOrderNumbers(data, title) {
|
|
2535
|
+
if (!data || typeof data !== "object")
|
|
2536
|
+
return data;
|
|
2537
|
+
const next = { ...data };
|
|
2538
|
+
const needsShopOrderNumber = next.shop_order_number === void 0 || next.shop_order_number === null || next.shop_order_number === "";
|
|
2539
|
+
const needsShopFullOrderNumber = next.shop_full_order_number === void 0 || next.shop_full_order_number === null || next.shop_full_order_number === "";
|
|
2540
|
+
if (!needsShopOrderNumber && !needsShopFullOrderNumber)
|
|
2541
|
+
return next;
|
|
2542
|
+
const idGenerator = this.getIdGeneratorPlugin();
|
|
2543
|
+
if (!idGenerator) {
|
|
2544
|
+
this.logWarning(`${title}: idGenerator 插件不可用,无法生成订单号`, {
|
|
2545
|
+
needsShopOrderNumber,
|
|
2546
|
+
needsShopFullOrderNumber
|
|
2547
|
+
});
|
|
2548
|
+
return next;
|
|
2549
|
+
}
|
|
2550
|
+
try {
|
|
2551
|
+
if (needsShopOrderNumber && idGenerator.generateShopOrderNumber) {
|
|
2552
|
+
next.shop_order_number = await idGenerator.generateShopOrderNumber({
|
|
2553
|
+
biz: next.business_code || "ticket"
|
|
2554
|
+
});
|
|
2555
|
+
}
|
|
2556
|
+
if (needsShopFullOrderNumber && idGenerator.generateReceiptId) {
|
|
2557
|
+
next.shop_full_order_number = await idGenerator.generateReceiptId({
|
|
2558
|
+
biz: next.business_code || "ticket"
|
|
2559
|
+
});
|
|
2560
|
+
}
|
|
2561
|
+
this.logInfo(`${title}: checkout 订单号已准备`, {
|
|
2562
|
+
shop_order_number: next.shop_order_number,
|
|
2563
|
+
shop_full_order_number: next.shop_full_order_number
|
|
2564
|
+
});
|
|
2565
|
+
} catch (error) {
|
|
2566
|
+
this.logError(`${title}: 生成 checkout 订单号失败`, {
|
|
2567
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2568
|
+
});
|
|
2569
|
+
}
|
|
2570
|
+
return next;
|
|
2571
|
+
}
|
|
2572
|
+
async dispatchCheckoutSyncTask(params) {
|
|
2573
|
+
var _a, _b, _c, _d;
|
|
2574
|
+
this.registerDeviceTaskActions();
|
|
2575
|
+
const deviceTask = this.getDeviceTaskPlugin();
|
|
2576
|
+
const debugDeviceId = await this.getShortNumberOrDeviceId();
|
|
2577
|
+
const debugIdempotencyKey = this.buildCheckoutTaskIdempotencyKey(params.data);
|
|
2578
|
+
if (!(deviceTask == null ? void 0 : deviceTask.dispatch)) {
|
|
2579
|
+
this.logError(`${params.title}: deviceTask.dispatch 不可用`);
|
|
2580
|
+
return;
|
|
2581
|
+
}
|
|
2582
|
+
try {
|
|
2583
|
+
const result = await deviceTask.dispatch({
|
|
2584
|
+
action: "sync_sales",
|
|
2585
|
+
device_id: debugDeviceId,
|
|
2586
|
+
payload: {
|
|
2587
|
+
backendPath: params.backendPath,
|
|
2588
|
+
data: params.data,
|
|
2589
|
+
external_sale_number: (_a = params.data) == null ? void 0 : _a.external_sale_number,
|
|
2590
|
+
title: params.title
|
|
2591
|
+
},
|
|
2592
|
+
retry_limit: 5,
|
|
2593
|
+
idempotency_key: debugIdempotencyKey,
|
|
2594
|
+
name: "同步订单",
|
|
2595
|
+
source: "server",
|
|
2596
|
+
source_type: "order",
|
|
2597
|
+
source_id: ((_b = params.data) == null ? void 0 : _b.order_id) || ((_c = params.data) == null ? void 0 : _c.external_sale_number) || ((_d = params.data) == null ? void 0 : _d.shop_order_number)
|
|
2598
|
+
});
|
|
2599
|
+
this.logInfo(`${params.title}: sync_sales 任务已派发`, {
|
|
2600
|
+
uuid: result == null ? void 0 : result.uuid,
|
|
2601
|
+
status: result == null ? void 0 : result.status,
|
|
2602
|
+
reused: result == null ? void 0 : result.reused
|
|
2603
|
+
});
|
|
2604
|
+
} catch (error) {
|
|
2605
|
+
this.logError(`${params.title}: 派发 sync_sales 任务失败`, {
|
|
2606
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2607
|
+
});
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
async dispatchPrintOtherReceiptTask(params) {
|
|
2611
|
+
var _a, _b, _c, _d, _e;
|
|
2612
|
+
const deviceTask = this.getDeviceTaskPlugin();
|
|
2613
|
+
if (!(deviceTask == null ? void 0 : deviceTask.dispatch)) {
|
|
2614
|
+
this.logWarning("dispatchPrintOtherReceiptTask: deviceTask.dispatch 不可用");
|
|
2615
|
+
return;
|
|
2616
|
+
}
|
|
2617
|
+
try {
|
|
2618
|
+
let printIdentity = this.getPrintOrderIdentity(params.syncedOrder);
|
|
2619
|
+
const deviceId = await this.getShortNumberOrDeviceId();
|
|
2620
|
+
await deviceTask.dispatch({
|
|
2621
|
+
action: "print_all",
|
|
2622
|
+
device_id: params.deviceId ?? deviceId,
|
|
2623
|
+
payload: {
|
|
2624
|
+
type: params.receiptOnly ? "0" : "99",
|
|
2625
|
+
data: params.receiptOnly ? {
|
|
2626
|
+
order_id: printIdentity,
|
|
2627
|
+
small_ticket_data: (_b = (_a = params.syncedOrder) == null ? void 0 : _a.payment_info) == null ? void 0 : _b.small_ticket_data
|
|
2628
|
+
} : {
|
|
2629
|
+
order_id: printIdentity,
|
|
2630
|
+
machine_code_print_info: (_d = (_c = params.syncedOrder) == null ? void 0 : _c.payment_info) == null ? void 0 : _d.machine_code_print_info,
|
|
2631
|
+
machine_code_print_info_v2: (_e = params.syncedOrder) == null ? void 0 : _e.machine_code_print_info_v2,
|
|
2632
|
+
skip_receipt: true
|
|
2633
|
+
}
|
|
2634
|
+
},
|
|
2635
|
+
idempotency_key: this.buildPrintOtherReceiptIdempotencyKey(params.syncedOrder, {
|
|
2636
|
+
receiptOnly: params.receiptOnly
|
|
2637
|
+
}),
|
|
2638
|
+
name: "打印转发",
|
|
2639
|
+
source: "server",
|
|
2640
|
+
source_type: "order",
|
|
2641
|
+
source_id: printIdentity
|
|
2642
|
+
});
|
|
2643
|
+
} catch (error) {
|
|
2644
|
+
this.logError("dispatchPrintOtherReceiptTask: 派发失败", {
|
|
2645
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
buildPrintOtherReceiptIdempotencyKey(order, options) {
|
|
2650
|
+
const identity = (order == null ? void 0 : order.external_sale_number) || (order == null ? void 0 : order.shop_order_number) || (order == null ? void 0 : order.shop_full_order_number) || (order == null ? void 0 : order.order_id);
|
|
2651
|
+
if (identity === void 0 || identity === null || identity === "")
|
|
2652
|
+
return void 0;
|
|
2653
|
+
return `${(options == null ? void 0 : options.receiptOnly) ? "print_receipt" : "print_voucher"}:${identity}:${Date.now()}`;
|
|
2654
|
+
}
|
|
2655
|
+
getPrintOrderIdentity(order) {
|
|
2656
|
+
return (order == null ? void 0 : order.order_id) || (order == null ? void 0 : order.external_sale_number) || (order == null ? void 0 : order.shop_order_number) || (order == null ? void 0 : order.shop_full_order_number);
|
|
2657
|
+
}
|
|
2658
|
+
async dispatchLocalReceiptPrint(params) {
|
|
2659
|
+
var _a;
|
|
2660
|
+
if (params.requireFullyPaid && !this.isSalesOrderFullyPaid(params.order)) {
|
|
2661
|
+
return { printed: false, order: params.order };
|
|
2662
|
+
}
|
|
2663
|
+
const printableOrder = await this.withLocalSmallTicketData(params.order, {
|
|
2664
|
+
requireFullyPaid: params.requireFullyPaid
|
|
2665
|
+
});
|
|
2666
|
+
if (!(0, import_small_ticket.hasSmallTicketData)((_a = printableOrder.payment_info) == null ? void 0 : _a.small_ticket_data)) {
|
|
2667
|
+
return { printed: false, order: printableOrder };
|
|
2668
|
+
}
|
|
2669
|
+
this.logInfo("dispatchLocalReceiptPrint: 构建触发任务前", {
|
|
2670
|
+
checkoutData: params.checkoutData,
|
|
2671
|
+
printableOrder,
|
|
2672
|
+
response: params.response
|
|
2673
|
+
});
|
|
2674
|
+
await this.dispatchPrintOtherReceiptTask({
|
|
2675
|
+
checkoutData: params.checkoutData,
|
|
2676
|
+
syncedOrder: printableOrder,
|
|
2677
|
+
response: params.response,
|
|
2678
|
+
receiptOnly: true
|
|
2679
|
+
});
|
|
2680
|
+
return { printed: true, order: printableOrder };
|
|
2681
|
+
}
|
|
2682
|
+
shouldLookupLocalPrintOrder(input) {
|
|
2683
|
+
const flag = (input == null ? void 0 : input.lookup_order_from_db) ?? (input == null ? void 0 : input.lookupOrderFromDb);
|
|
2684
|
+
return flag === true || flag === 1 || flag === "1";
|
|
2685
|
+
}
|
|
2686
|
+
getLocalPrintOrderLookup(input) {
|
|
2687
|
+
const orderId = (input == null ? void 0 : input.order_id) ?? (input == null ? void 0 : input.orderId);
|
|
2688
|
+
if (orderId !== void 0 && orderId !== null && orderId !== "")
|
|
2689
|
+
return orderId;
|
|
2690
|
+
const externalSaleNumber = (input == null ? void 0 : input.external_sale_number) ?? (input == null ? void 0 : input.externalSaleNumber);
|
|
2691
|
+
if (externalSaleNumber !== void 0 && externalSaleNumber !== null && externalSaleNumber !== "") {
|
|
2692
|
+
return externalSaleNumber;
|
|
2693
|
+
}
|
|
2694
|
+
return void 0;
|
|
2695
|
+
}
|
|
2696
|
+
async handleOrderCheckoutSubmit(params) {
|
|
2697
|
+
const { backendPath, data, title } = params;
|
|
2698
|
+
this.logInfo(`${title}: 开始处理`, {
|
|
2699
|
+
backendPath,
|
|
2700
|
+
order_id: data == null ? void 0 : data.order_id,
|
|
2701
|
+
external_sale_number: data == null ? void 0 : data.external_sale_number,
|
|
2702
|
+
order_number: data == null ? void 0 : data.order_number
|
|
2703
|
+
});
|
|
2704
|
+
if ((data == null ? void 0 : data.sync_mode) || (data == null ? void 0 : data.syncMode)) {
|
|
2705
|
+
return this.handleSyncCheckoutSubmit({
|
|
2706
|
+
backendPath,
|
|
2707
|
+
data,
|
|
2708
|
+
title
|
|
2709
|
+
});
|
|
2710
|
+
}
|
|
2711
|
+
const normalizedData = await this.normalizeCheckoutSubmitData(data, title);
|
|
2712
|
+
const checkoutData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
|
|
2713
|
+
const pendingResult = await this.handlePendingSyncCheckoutOrder({
|
|
2714
|
+
backendPath,
|
|
2715
|
+
data: checkoutData,
|
|
2716
|
+
title,
|
|
2717
|
+
reason: "checkout 已转入设备任务同步"
|
|
2718
|
+
});
|
|
2719
|
+
if ((pendingResult == null ? void 0 : pendingResult.status) === true) {
|
|
2720
|
+
const pendingOrder = pendingResult.data;
|
|
2721
|
+
if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && // TODO 这里先加个兼容,只有 type 为 virtual 才走打印
|
|
2722
|
+
// 后期需要迁移到 picoding ,根据工作流配置
|
|
2723
|
+
checkoutData.type === "virtual") {
|
|
2724
|
+
await this.dispatchLocalReceiptPrint({
|
|
2725
|
+
checkoutData,
|
|
2726
|
+
order: pendingOrder,
|
|
2727
|
+
response: pendingResult,
|
|
2728
|
+
requireFullyPaid: true
|
|
2729
|
+
});
|
|
2730
|
+
}
|
|
2731
|
+
await this.dispatchCheckoutSyncTask({
|
|
2732
|
+
backendPath,
|
|
2733
|
+
data: checkoutData,
|
|
2734
|
+
title
|
|
2735
|
+
});
|
|
2736
|
+
}
|
|
2737
|
+
if (!pendingResult.data.order_id) {
|
|
2738
|
+
return {
|
|
2739
|
+
...pendingResult,
|
|
2740
|
+
data: {
|
|
2741
|
+
...pendingResult.data,
|
|
2742
|
+
order_id: pendingResult.data.external_sale_number
|
|
2743
|
+
}
|
|
2744
|
+
};
|
|
2745
|
+
}
|
|
2746
|
+
return pendingResult;
|
|
2747
|
+
}
|
|
2748
|
+
async handleSyncCheckoutSubmit(params) {
|
|
2749
|
+
var _a, _b;
|
|
2750
|
+
const { backendPath, data, title } = params;
|
|
2751
|
+
if (!((_b = (_a = this.app) == null ? void 0 : _a.request) == null ? void 0 : _b.post)) {
|
|
2752
|
+
this.logError(`${title}: sync checkout app.request 不可用`);
|
|
2753
|
+
return {
|
|
2754
|
+
code: 500,
|
|
2755
|
+
status: false,
|
|
2756
|
+
message: "app.request 不可用",
|
|
2757
|
+
data: null
|
|
2758
|
+
};
|
|
2759
|
+
}
|
|
2760
|
+
try {
|
|
2761
|
+
const syncResult = await this.runCheckoutSync({
|
|
2762
|
+
backendPath,
|
|
2763
|
+
data,
|
|
2764
|
+
title,
|
|
2765
|
+
persistCheckoutDataWithResponse: true
|
|
2766
|
+
});
|
|
2767
|
+
if (syncResult.rejected) {
|
|
2768
|
+
const normalized = this.normalizeCheckoutResponse(syncResult.errorResponse);
|
|
2769
|
+
return {
|
|
2770
|
+
...normalized,
|
|
2771
|
+
status: false,
|
|
2772
|
+
message: syncResult.message || (normalized == null ? void 0 : normalized.message) || "后端明确拒绝 checkout",
|
|
2773
|
+
data: (normalized == null ? void 0 : normalized.data) ?? null
|
|
2774
|
+
};
|
|
2775
|
+
}
|
|
2776
|
+
return this.withSyncedOrderIdInCheckoutResponse(
|
|
2777
|
+
syncResult.normalizedResponse,
|
|
2778
|
+
syncResult.syncedOrder
|
|
2779
|
+
);
|
|
2780
|
+
} catch (error) {
|
|
2781
|
+
const backendError = this.extractBackendErrorResponse(error);
|
|
2782
|
+
if (backendError) {
|
|
2783
|
+
const normalized = this.normalizeCheckoutResponse(backendError);
|
|
2784
|
+
return {
|
|
2785
|
+
...normalized,
|
|
2786
|
+
status: false,
|
|
2787
|
+
message: (backendError == null ? void 0 : backendError.message) || (normalized == null ? void 0 : normalized.message) || "后端明确拒绝 checkout",
|
|
2788
|
+
data: (normalized == null ? void 0 : normalized.data) ?? null
|
|
2789
|
+
};
|
|
2790
|
+
}
|
|
2791
|
+
const message = this.getUnknownErrorMessage(error);
|
|
2792
|
+
this.logError(`${title}: sync checkout 请求未明确成功`, {
|
|
2793
|
+
backendPath,
|
|
2794
|
+
error: message,
|
|
2795
|
+
error_detail: this.normalizeUnknownError(error)
|
|
2796
|
+
});
|
|
2797
|
+
return {
|
|
2798
|
+
code: 500,
|
|
2799
|
+
status: false,
|
|
2800
|
+
message,
|
|
2801
|
+
data: null
|
|
2802
|
+
};
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
async handlePendingSyncCheckoutOrder(params) {
|
|
2806
|
+
var _a, _b, _c, _d;
|
|
2807
|
+
const { backendPath, data, title, reason } = params;
|
|
2808
|
+
const pendingOrder = await this.buildPendingSyncCheckoutOrder(data);
|
|
2809
|
+
if (!pendingOrder) {
|
|
2810
|
+
this.logError(`${title}: checkout 失败且订单缺少本地存储标识`, {
|
|
2811
|
+
backendPath,
|
|
2812
|
+
reason
|
|
2813
|
+
});
|
|
2814
|
+
return {
|
|
2815
|
+
code: 500,
|
|
2816
|
+
status: false,
|
|
2817
|
+
message: "订单缺少本地存储标识,无法写入待同步队列",
|
|
2818
|
+
data: null
|
|
2819
|
+
};
|
|
2820
|
+
}
|
|
2821
|
+
if (!this.order || typeof this.order.upsertPendingSyncOrders !== "function") {
|
|
2822
|
+
this.logError(`${title}: Order 模块不支持本地待同步写入`, {
|
|
2823
|
+
backendPath,
|
|
2824
|
+
reason
|
|
2825
|
+
});
|
|
2826
|
+
return {
|
|
2827
|
+
code: 500,
|
|
2828
|
+
status: false,
|
|
2829
|
+
message: "Order 模块不支持本地待同步写入",
|
|
2830
|
+
data: null
|
|
2831
|
+
};
|
|
2832
|
+
}
|
|
2833
|
+
try {
|
|
2834
|
+
await this.order.upsertPendingSyncOrders([pendingOrder]);
|
|
2835
|
+
this.logInfo(`${title}: 订单已写入本地待同步`, {
|
|
2836
|
+
backendPath,
|
|
2837
|
+
reason,
|
|
2838
|
+
order_id: pendingOrder.order_id,
|
|
2839
|
+
external_sale_number: pendingOrder.external_sale_number,
|
|
2840
|
+
order_number: pendingOrder.order_number
|
|
2841
|
+
});
|
|
2842
|
+
const changeGivenAmount = (_a = pendingOrder == null ? void 0 : pendingOrder.payments) == null ? void 0 : _a.reduce((sum, payment) => {
|
|
2843
|
+
var _a2;
|
|
2844
|
+
return sum + this.toAmountNumber((_a2 = payment == null ? void 0 : payment.metadata) == null ? void 0 : _a2.change_given_amount);
|
|
2845
|
+
}, 0);
|
|
2846
|
+
return {
|
|
2847
|
+
code: 200,
|
|
2848
|
+
status: true,
|
|
2849
|
+
message: "",
|
|
2850
|
+
data: {
|
|
2851
|
+
...pendingOrder,
|
|
2852
|
+
amount_gap: (_b = pendingOrder == null ? void 0 : pendingOrder.summary) == null ? void 0 : _b.amount_gap,
|
|
2853
|
+
expect_amount: (_c = pendingOrder == null ? void 0 : pendingOrder.summary) == null ? void 0 : _c.expect_amount,
|
|
2854
|
+
total_amount: (_d = pendingOrder == null ? void 0 : pendingOrder.summary) == null ? void 0 : _d.total_amount,
|
|
2855
|
+
payment_status: pendingOrder == null ? void 0 : pendingOrder.payment_status,
|
|
2856
|
+
payment_info: {
|
|
2857
|
+
...(pendingOrder == null ? void 0 : pendingOrder.payment_info) || {},
|
|
2858
|
+
current_change_given_amount: changeGivenAmount
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
};
|
|
2862
|
+
} catch (error) {
|
|
2863
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2864
|
+
this.logError(`${title}: 写入本地待同步订单失败`, {
|
|
2865
|
+
backendPath,
|
|
2866
|
+
reason,
|
|
2867
|
+
error: errorMessage
|
|
2868
|
+
});
|
|
2869
|
+
return { code: 500, status: false, message: errorMessage, data: null };
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
async buildPendingSyncCheckoutOrder(data) {
|
|
2873
|
+
if (!data || typeof data !== "object")
|
|
2874
|
+
return null;
|
|
2875
|
+
const hasStorageKey = data.external_sale_number !== void 0 && data.external_sale_number !== null && data.external_sale_number !== "" ? true : data.order_id !== void 0 && data.order_id !== null && data.order_id !== "";
|
|
2876
|
+
if (!hasStorageKey)
|
|
2877
|
+
return null;
|
|
2878
|
+
const pendingOrder = {
|
|
2879
|
+
...data,
|
|
2880
|
+
need_sync: 1
|
|
2881
|
+
};
|
|
2882
|
+
const productMap = await this.buildSmallTicketProductMap(pendingOrder);
|
|
2883
|
+
const orderWithProductTitles = this.withPendingSyncProductTitles(
|
|
2884
|
+
pendingOrder,
|
|
2885
|
+
productMap
|
|
2886
|
+
);
|
|
2887
|
+
return this.withLocalSmallTicketData(
|
|
2888
|
+
orderWithProductTitles,
|
|
2889
|
+
{ requireFullyPaid: true, productMap }
|
|
2890
|
+
);
|
|
2891
|
+
}
|
|
2892
|
+
shouldBuildSmallTicketData(order) {
|
|
2893
|
+
var _a;
|
|
2894
|
+
if (!order || typeof order !== "object")
|
|
2895
|
+
return false;
|
|
2896
|
+
if ((0, import_small_ticket.hasSmallTicketData)((_a = order.payment_info) == null ? void 0 : _a.small_ticket_data))
|
|
2897
|
+
return false;
|
|
2898
|
+
return Number(order.small_ticket_data_flag ?? order.smallTicketDataFlag ?? 0) === 1;
|
|
2899
|
+
}
|
|
2900
|
+
shouldPrintSyncedOrder(params) {
|
|
2901
|
+
if (this.hasPaymentStatus(params.syncedOrder)) {
|
|
2902
|
+
return this.isSalesOrderFullyPaid(params.syncedOrder);
|
|
2903
|
+
}
|
|
2904
|
+
return this.isSalesOrderFullyPaid(params.checkoutData);
|
|
2905
|
+
}
|
|
2906
|
+
hasPaymentStatus(order) {
|
|
2907
|
+
return (order == null ? void 0 : order.payment_status) !== void 0 && (order == null ? void 0 : order.payment_status) !== null && (order == null ? void 0 : order.payment_status) !== "";
|
|
2908
|
+
}
|
|
2909
|
+
isSalesOrderFullyPaid(order) {
|
|
2910
|
+
var _a, _b, _c;
|
|
2911
|
+
if (!order || typeof order !== "object")
|
|
2912
|
+
return false;
|
|
2913
|
+
const paymentStatus = String(order.payment_status || "").toLowerCase();
|
|
2914
|
+
if (paymentStatus === "paid" || paymentStatus === "finished")
|
|
2915
|
+
return true;
|
|
2916
|
+
if (paymentStatus === "partially_paid" || paymentStatus === "payment_processing" || paymentStatus === "pending" || paymentStatus === "unpaid") {
|
|
2917
|
+
return false;
|
|
2918
|
+
}
|
|
2919
|
+
const amountGap = ((_a = order.summary) == null ? void 0 : _a.amount_gap) ?? order.amount_gap;
|
|
2920
|
+
if (amountGap !== void 0 && amountGap !== null && amountGap !== "") {
|
|
2921
|
+
return this.toAmountNumber(amountGap) <= 0;
|
|
2922
|
+
}
|
|
2923
|
+
const paidAmount = this.sumPaidOrderPayments(order.payments);
|
|
2924
|
+
const targetAmount = this.toAmountNumber(
|
|
2925
|
+
((_b = order.summary) == null ? void 0 : _b.expect_amount) ?? ((_c = order.summary) == null ? void 0 : _c.total_amount) ?? order.expect_amount ?? order.total_amount
|
|
2926
|
+
);
|
|
2927
|
+
if (targetAmount <= 0)
|
|
2928
|
+
return paidAmount > 0;
|
|
2929
|
+
return paidAmount >= targetAmount;
|
|
2930
|
+
}
|
|
2931
|
+
sumPaidOrderPayments(payments) {
|
|
2932
|
+
if (!Array.isArray(payments))
|
|
2933
|
+
return 0;
|
|
2934
|
+
return payments.reduce((sum, payment) => {
|
|
2935
|
+
const status = String((payment == null ? void 0 : payment.status) || "").toLowerCase();
|
|
2936
|
+
if (status === "voided" || status === "failed" || status === "cancelled")
|
|
2937
|
+
return sum;
|
|
2938
|
+
return sum + this.toAmountNumber((payment == null ? void 0 : payment.amount) ?? (payment == null ? void 0 : payment.origin_amount));
|
|
2939
|
+
}, 0);
|
|
2940
|
+
}
|
|
2941
|
+
toAmountNumber(value) {
|
|
2942
|
+
if (typeof value === "number")
|
|
2943
|
+
return Number.isFinite(value) ? value : 0;
|
|
2944
|
+
if (typeof value !== "string")
|
|
2945
|
+
return 0;
|
|
2946
|
+
const parsed = Number(value.replace(/[^\d.-]/g, ""));
|
|
2947
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
2948
|
+
}
|
|
2949
|
+
async buildSmallTicketProductMap(order) {
|
|
2950
|
+
var _a;
|
|
2951
|
+
const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : [];
|
|
2952
|
+
const productIdSet = /* @__PURE__ */ new Set();
|
|
2953
|
+
products.forEach((product) => {
|
|
2954
|
+
const productId = (product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id);
|
|
2955
|
+
if (productId !== void 0 && productId !== null && productId !== "") {
|
|
2956
|
+
productIdSet.add(productId);
|
|
2957
|
+
}
|
|
2958
|
+
if (Array.isArray(product == null ? void 0 : product.product_bundle)) {
|
|
2959
|
+
product.product_bundle.forEach((bundle) => {
|
|
2960
|
+
const bundleProductId = (bundle == null ? void 0 : bundle.bundle_product_id) ?? (bundle == null ? void 0 : bundle._bundle_product_id) ?? (bundle == null ? void 0 : bundle.product_id);
|
|
2961
|
+
if (bundleProductId !== void 0 && bundleProductId !== null && bundleProductId !== "") {
|
|
2962
|
+
productIdSet.add(bundleProductId);
|
|
2963
|
+
}
|
|
2964
|
+
});
|
|
2965
|
+
}
|
|
2966
|
+
});
|
|
2967
|
+
const productIds = Array.from(productIdSet);
|
|
2968
|
+
if (!productIds.length || typeof ((_a = this.products) == null ? void 0 : _a.getProductById) !== "function")
|
|
2969
|
+
return {};
|
|
2970
|
+
const entries = await Promise.all(
|
|
2971
|
+
productIds.map(async (id) => {
|
|
2972
|
+
var _a2, _b;
|
|
2973
|
+
try {
|
|
2974
|
+
const product = await ((_b = (_a2 = this.products) == null ? void 0 : _a2.getProductById) == null ? void 0 : _b.call(_a2, Number(id)));
|
|
2975
|
+
return product ? [String(id), product] : null;
|
|
2976
|
+
} catch (error) {
|
|
2977
|
+
this.logWarning("buildSmallTicketProductMap: 查询本地商品失败", {
|
|
2978
|
+
product_id: id,
|
|
2979
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2980
|
+
});
|
|
2981
|
+
return null;
|
|
2982
|
+
}
|
|
2983
|
+
})
|
|
2984
|
+
);
|
|
2985
|
+
return entries.reduce((map, entry) => {
|
|
2986
|
+
if (!entry)
|
|
2987
|
+
return map;
|
|
2988
|
+
const [id, product] = entry;
|
|
2989
|
+
map[id] = product;
|
|
2990
|
+
return map;
|
|
2991
|
+
}, {});
|
|
2992
|
+
}
|
|
2993
|
+
withPendingSyncProductTitles(order, productMap) {
|
|
2994
|
+
const products = Array.isArray(order.products) ? order.products : null;
|
|
2995
|
+
if (!(products == null ? void 0 : products.length))
|
|
2996
|
+
return order;
|
|
2997
|
+
return {
|
|
2998
|
+
...order,
|
|
2999
|
+
products: products.map((product) => ({
|
|
3000
|
+
...product,
|
|
3001
|
+
product_title: this.buildProductTitleSnapshot(product, productMap)
|
|
3002
|
+
}))
|
|
3003
|
+
};
|
|
3004
|
+
}
|
|
3005
|
+
buildProductTitleSnapshot(product, productMap) {
|
|
3006
|
+
var _a, _b;
|
|
3007
|
+
const productId = product.product_id ?? product.id;
|
|
3008
|
+
const fallbackProduct = productId !== void 0 && productId !== null ? productMap[productId] || productMap[String(productId)] : null;
|
|
3009
|
+
const ownTitle = product.product_title || product.title || product.name || ((_a = product.product) == null ? void 0 : _a.title);
|
|
3010
|
+
const fallbackTitle = (fallbackProduct == null ? void 0 : fallbackProduct.product_title) || (fallbackProduct == null ? void 0 : fallbackProduct.title) || (fallbackProduct == null ? void 0 : fallbackProduct.name) || (fallbackProduct == null ? void 0 : fallbackProduct.format_title) || ((_b = fallbackProduct == null ? void 0 : fallbackProduct.product) == null ? void 0 : _b.title);
|
|
3011
|
+
const currentLocale = this.getProductTitleSnapshotCurrentLocale();
|
|
3012
|
+
const autoTitle = this.resolveFirstProductTitleValue(ownTitle) || this.resolveFirstProductTitleValue(fallbackTitle);
|
|
3013
|
+
return PRODUCT_TITLE_SNAPSHOT_KEYS.reduce((snapshot, key) => {
|
|
3014
|
+
snapshot[key] = this.resolveProductTitleValue(ownTitle, key, currentLocale) || this.resolveProductTitleValue(fallbackTitle, key, currentLocale) || (key === "auto" || key === "original" ? autoTitle : null);
|
|
3015
|
+
return snapshot;
|
|
3016
|
+
}, {});
|
|
3017
|
+
}
|
|
3018
|
+
getProductTitleSnapshotCurrentLocale() {
|
|
3019
|
+
var _a, _b;
|
|
3020
|
+
const shopInfo = this.getSmallTicketShopInfo();
|
|
3021
|
+
const rawLocale = shopInfo.primary_locale || this.getAppData("locale") || this.getAppData("language") || ((_a = this.core.context) == null ? void 0 : _a.locale) || ((_b = this.core.context) == null ? void 0 : _b.language);
|
|
3022
|
+
return this.normalizeProductTitleSnapshotLocale(rawLocale);
|
|
3023
|
+
}
|
|
3024
|
+
normalizeProductTitleSnapshotLocale(value) {
|
|
3025
|
+
if (typeof value !== "string" || !value)
|
|
3026
|
+
return null;
|
|
3027
|
+
const normalized = value.replace("_", "-");
|
|
3028
|
+
const matchedKey = PRODUCT_TITLE_SNAPSHOT_KEYS.find((key) => key === normalized);
|
|
3029
|
+
return matchedKey ?? null;
|
|
3030
|
+
}
|
|
3031
|
+
resolveProductTitleValue(value, key, currentLocale) {
|
|
3032
|
+
if (value === void 0 || value === null || value === "")
|
|
3033
|
+
return null;
|
|
3034
|
+
if (typeof value !== "object") {
|
|
3035
|
+
const title = String(value);
|
|
3036
|
+
if (key === "auto" || key === "original")
|
|
3037
|
+
return title;
|
|
3038
|
+
if (key === currentLocale && this.canAssignStringProductTitleToLocale(title, currentLocale))
|
|
3039
|
+
return title;
|
|
3040
|
+
return null;
|
|
3041
|
+
}
|
|
3042
|
+
const normalizedKey = key.replace("-", "_");
|
|
3043
|
+
const dashedKey = key.replace("_", "-");
|
|
3044
|
+
const rawValue = value[key] ?? value[normalizedKey] ?? value[dashedKey] ?? (key === "auto" ? value.default : void 0);
|
|
3045
|
+
if (rawValue === void 0 || rawValue === null || rawValue === "")
|
|
3046
|
+
return null;
|
|
3047
|
+
if (typeof rawValue === "object")
|
|
3048
|
+
return this.resolveFirstProductTitleValue(rawValue);
|
|
3049
|
+
return String(rawValue);
|
|
3050
|
+
}
|
|
3051
|
+
canAssignStringProductTitleToLocale(title, locale) {
|
|
3052
|
+
if (!locale)
|
|
3053
|
+
return false;
|
|
3054
|
+
if (locale === "zh-CN" || locale === "zh-HK" || locale === "kitchen") {
|
|
3055
|
+
return this.hasCjkText(title);
|
|
3056
|
+
}
|
|
3057
|
+
if (locale === "ja")
|
|
3058
|
+
return /[\u3040-\u30ff]/.test(title) || this.hasCjkText(title);
|
|
3059
|
+
if (locale === "en" || locale === "pt")
|
|
3060
|
+
return !this.hasCjkText(title);
|
|
3061
|
+
return false;
|
|
3062
|
+
}
|
|
3063
|
+
hasCjkText(value) {
|
|
3064
|
+
return /[\u3400-\u9fff]/.test(value);
|
|
3065
|
+
}
|
|
3066
|
+
resolveFirstProductTitleValue(value) {
|
|
3067
|
+
if (value === void 0 || value === null || value === "")
|
|
3068
|
+
return null;
|
|
3069
|
+
if (typeof value !== "object")
|
|
3070
|
+
return String(value);
|
|
3071
|
+
const preferredKeys = [
|
|
3072
|
+
"auto",
|
|
3073
|
+
"en",
|
|
3074
|
+
"original",
|
|
3075
|
+
"zh-CN",
|
|
3076
|
+
"zh_CN",
|
|
3077
|
+
"zh-HK",
|
|
3078
|
+
"zh_HK",
|
|
3079
|
+
"kitchen",
|
|
3080
|
+
"ja",
|
|
3081
|
+
"pt",
|
|
3082
|
+
"default"
|
|
3083
|
+
];
|
|
3084
|
+
for (const key of preferredKeys) {
|
|
3085
|
+
const rawValue = value[key];
|
|
3086
|
+
if (rawValue !== void 0 && rawValue !== null && rawValue !== "")
|
|
3087
|
+
return String(rawValue);
|
|
3088
|
+
}
|
|
3089
|
+
const firstValue = Object.values(value).find(
|
|
3090
|
+
(item) => item !== void 0 && item !== null && item !== ""
|
|
3091
|
+
);
|
|
3092
|
+
return firstValue === void 0 ? null : String(firstValue);
|
|
3093
|
+
}
|
|
3094
|
+
async withLocalSmallTicketData(order, options) {
|
|
3095
|
+
if (!this.shouldBuildSmallTicketData(order))
|
|
3096
|
+
return order;
|
|
3097
|
+
if ((options == null ? void 0 : options.requireFullyPaid) && !this.isSalesOrderFullyPaid(order))
|
|
3098
|
+
return order;
|
|
3099
|
+
try {
|
|
3100
|
+
const productMap = (options == null ? void 0 : options.productMap) ?? await this.buildSmallTicketProductMap(order);
|
|
3101
|
+
const smallTicketData = (0, import_small_ticket.buildSmallTicketData)({
|
|
3102
|
+
order,
|
|
3103
|
+
shopInfo: this.getSmallTicketShopInfo(),
|
|
3104
|
+
productMap
|
|
3105
|
+
});
|
|
3106
|
+
return {
|
|
3107
|
+
...order,
|
|
3108
|
+
payment_info: {
|
|
3109
|
+
...order.payment_info || {},
|
|
3110
|
+
small_ticket_data: smallTicketData
|
|
3111
|
+
}
|
|
3112
|
+
};
|
|
3113
|
+
} catch (error) {
|
|
3114
|
+
this.logError("withLocalSmallTicketData: 生成本地小票数据失败", {
|
|
3115
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3116
|
+
});
|
|
3117
|
+
return order;
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
1707
3120
|
/**
|
|
1708
3121
|
* 解析 order_ids 入参,兼容 url query / data 字段、字符串(csv) / 数组两种形态。
|
|
1709
3122
|
* 自动 trim、去空、按字符串去重,输出归一化后的字符串数组。
|
|
@@ -1856,12 +3269,15 @@ var Server = class {
|
|
|
1856
3269
|
return null;
|
|
1857
3270
|
}
|
|
1858
3271
|
}
|
|
1859
|
-
|
|
3272
|
+
extractOrderSalesDetailLookup(url) {
|
|
1860
3273
|
const path = this.parseRequestPath(url);
|
|
1861
3274
|
const match = path.match(/^\/shop\/order\/sales\/([^/?#]+)$/);
|
|
1862
3275
|
return (match == null ? void 0 : match[1]) ? decodeURIComponent(match[1]) : null;
|
|
1863
3276
|
}
|
|
1864
|
-
|
|
3277
|
+
shouldForceRemoteSalesDetail(data) {
|
|
3278
|
+
return (data == null ? void 0 : data.forceRemote) === true || (data == null ? void 0 : data.force_remote) === true;
|
|
3279
|
+
}
|
|
3280
|
+
buildOrderSalesDetailBackendPath(lookup, data) {
|
|
1865
3281
|
const rawWith = data && typeof data === "object" ? data.with : void 0;
|
|
1866
3282
|
const withFields = Array.isArray(rawWith) && rawWith.length > 0 ? rawWith : ["products", "scheduleEvents"];
|
|
1867
3283
|
const searchParams = new URLSearchParams();
|
|
@@ -1872,7 +3288,198 @@ var Server = class {
|
|
|
1872
3288
|
});
|
|
1873
3289
|
searchParams.append("lookup_mode", "multi");
|
|
1874
3290
|
const query = searchParams.toString();
|
|
1875
|
-
return `/shop/order/sales/${encodeURIComponent(
|
|
3291
|
+
return `/shop/order/sales/${encodeURIComponent(lookup)}${query ? `?${query}` : ""}`;
|
|
3292
|
+
}
|
|
3293
|
+
extractOrderDataFromCheckoutResponse(response) {
|
|
3294
|
+
var _a, _b;
|
|
3295
|
+
const candidates = [
|
|
3296
|
+
(_a = response == null ? void 0 : response.data) == null ? void 0 : _a.order,
|
|
3297
|
+
(_b = response == null ? void 0 : response.data) == null ? void 0 : _b.sales,
|
|
3298
|
+
response == null ? void 0 : response.data,
|
|
3299
|
+
response == null ? void 0 : response.order,
|
|
3300
|
+
response == null ? void 0 : response.sales,
|
|
3301
|
+
response
|
|
3302
|
+
];
|
|
3303
|
+
for (const candidate of candidates) {
|
|
3304
|
+
if (!candidate || typeof candidate !== "object")
|
|
3305
|
+
continue;
|
|
3306
|
+
if (candidate.order_id !== void 0 && candidate.order_id !== null) {
|
|
3307
|
+
return candidate;
|
|
3308
|
+
}
|
|
3309
|
+
}
|
|
3310
|
+
return null;
|
|
3311
|
+
}
|
|
3312
|
+
getCheckoutExternalSaleNumber(data, payload) {
|
|
3313
|
+
var _a;
|
|
3314
|
+
const candidates = [
|
|
3315
|
+
payload == null ? void 0 : payload.external_sale_number,
|
|
3316
|
+
data == null ? void 0 : data.external_sale_number,
|
|
3317
|
+
(_a = payload == null ? void 0 : payload.data) == null ? void 0 : _a.external_sale_number
|
|
3318
|
+
];
|
|
3319
|
+
const value = candidates.find((candidate) => candidate !== void 0 && candidate !== null && candidate !== "");
|
|
3320
|
+
return value === void 0 ? void 0 : String(value);
|
|
3321
|
+
}
|
|
3322
|
+
buildCheckoutSyncSuccessPatch(fresh) {
|
|
3323
|
+
if (!fresh)
|
|
3324
|
+
return {};
|
|
3325
|
+
const patch = {};
|
|
3326
|
+
if (fresh.order_id !== void 0 && fresh.order_id !== null)
|
|
3327
|
+
patch.order_id = fresh.order_id;
|
|
3328
|
+
if (fresh.order_number !== void 0 && fresh.order_number !== null) {
|
|
3329
|
+
patch.order_number = fresh.order_number;
|
|
3330
|
+
}
|
|
3331
|
+
return patch;
|
|
3332
|
+
}
|
|
3333
|
+
buildSyncedOrderForPrint(params) {
|
|
3334
|
+
const { syncedOrder, checkoutResponseOrder } = params;
|
|
3335
|
+
if (!checkoutResponseOrder || typeof checkoutResponseOrder !== "object")
|
|
3336
|
+
return syncedOrder;
|
|
3337
|
+
const printableOrder = { ...syncedOrder };
|
|
3338
|
+
const responseOrder = checkoutResponseOrder;
|
|
3339
|
+
if (responseOrder.order_id !== void 0 && responseOrder.order_id !== null) {
|
|
3340
|
+
printableOrder.order_id = responseOrder.order_id;
|
|
3341
|
+
}
|
|
3342
|
+
if (responseOrder.payment_status !== void 0 && responseOrder.payment_status !== null) {
|
|
3343
|
+
printableOrder.payment_status = responseOrder.payment_status;
|
|
3344
|
+
}
|
|
3345
|
+
if (responseOrder.expect_amount !== void 0 && responseOrder.expect_amount !== null) {
|
|
3346
|
+
printableOrder.expect_amount = responseOrder.expect_amount;
|
|
3347
|
+
}
|
|
3348
|
+
if (responseOrder.machine_code_print_info_v2 !== void 0) {
|
|
3349
|
+
printableOrder.machine_code_print_info_v2 = responseOrder.machine_code_print_info_v2;
|
|
3350
|
+
}
|
|
3351
|
+
if (responseOrder.payment_info && typeof responseOrder.payment_info === "object") {
|
|
3352
|
+
printableOrder.payment_info = {
|
|
3353
|
+
...syncedOrder.payment_info || {},
|
|
3354
|
+
...responseOrder.payment_info
|
|
3355
|
+
};
|
|
3356
|
+
}
|
|
3357
|
+
return printableOrder;
|
|
3358
|
+
}
|
|
3359
|
+
isMergeableCheckoutOrder(order, externalSaleNumber) {
|
|
3360
|
+
if (!order || typeof order !== "object")
|
|
3361
|
+
return false;
|
|
3362
|
+
const orderExternalSaleNumber = order.external_sale_number;
|
|
3363
|
+
if (externalSaleNumber && orderExternalSaleNumber !== void 0 && orderExternalSaleNumber !== null && String(orderExternalSaleNumber) !== externalSaleNumber) {
|
|
3364
|
+
return false;
|
|
3365
|
+
}
|
|
3366
|
+
if (externalSaleNumber && (orderExternalSaleNumber === void 0 || orderExternalSaleNumber === null || orderExternalSaleNumber === "")) {
|
|
3367
|
+
return false;
|
|
3368
|
+
}
|
|
3369
|
+
return Array.isArray(order.products) || Array.isArray(order.bookings) || Array.isArray(order.payments) || !!order.summary || order.order_number !== void 0 || order.payment_status !== void 0 || order.status !== void 0;
|
|
3370
|
+
}
|
|
3371
|
+
normalizeCheckoutResponse(response) {
|
|
3372
|
+
if (response && typeof response === "object" && (response.code !== void 0 || response.status !== void 0)) {
|
|
3373
|
+
return response;
|
|
3374
|
+
}
|
|
3375
|
+
return {
|
|
3376
|
+
code: 200,
|
|
3377
|
+
status: true,
|
|
3378
|
+
message: "",
|
|
3379
|
+
data: response
|
|
3380
|
+
};
|
|
3381
|
+
}
|
|
3382
|
+
withSyncedOrderIdInCheckoutResponse(response, syncedOrder) {
|
|
3383
|
+
const normalized = this.normalizeCheckoutResponse(response);
|
|
3384
|
+
const orderId = syncedOrder == null ? void 0 : syncedOrder.order_id;
|
|
3385
|
+
if (orderId === void 0 || orderId === null)
|
|
3386
|
+
return normalized;
|
|
3387
|
+
if (!(normalized == null ? void 0 : normalized.data) || typeof normalized.data !== "object")
|
|
3388
|
+
return normalized;
|
|
3389
|
+
return {
|
|
3390
|
+
...normalized,
|
|
3391
|
+
data: {
|
|
3392
|
+
...normalized.data,
|
|
3393
|
+
order_id: normalized.data.order_id ?? orderId
|
|
3394
|
+
}
|
|
3395
|
+
};
|
|
3396
|
+
}
|
|
3397
|
+
isCheckoutResponseRejected(response) {
|
|
3398
|
+
const normalized = this.normalizeCheckoutResponse(response);
|
|
3399
|
+
const isErrorCode = (normalized == null ? void 0 : normalized.code) !== void 0 && normalized.code !== 200 && normalized.code !== "200";
|
|
3400
|
+
const isErrorStatus = (normalized == null ? void 0 : normalized.status) === false || typeof (normalized == null ? void 0 : normalized.status) === "number" && normalized.status >= 400;
|
|
3401
|
+
const isErrorSuccess = (normalized == null ? void 0 : normalized.success) === false;
|
|
3402
|
+
return isErrorCode || isErrorStatus || isErrorSuccess;
|
|
3403
|
+
}
|
|
3404
|
+
getUnknownErrorMessage(error) {
|
|
3405
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3406
|
+
if (error instanceof Error && error.message)
|
|
3407
|
+
return error.message;
|
|
3408
|
+
if (typeof error === "string")
|
|
3409
|
+
return error;
|
|
3410
|
+
const candidates = [
|
|
3411
|
+
error == null ? void 0 : error.message,
|
|
3412
|
+
(_b = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message,
|
|
3413
|
+
(_c = error == null ? void 0 : error.data) == null ? void 0 : _c.message,
|
|
3414
|
+
(_e = (_d = error == null ? void 0 : error.response) == null ? void 0 : _d.body) == null ? void 0 : _e.message,
|
|
3415
|
+
(_f = error == null ? void 0 : error.body) == null ? void 0 : _f.message
|
|
3416
|
+
];
|
|
3417
|
+
const message = candidates.find((candidate) => typeof candidate === "string" && candidate !== "");
|
|
3418
|
+
if (message)
|
|
3419
|
+
return message;
|
|
3420
|
+
const normalized = this.normalizeUnknownError(error);
|
|
3421
|
+
if (typeof normalized === "string")
|
|
3422
|
+
return normalized;
|
|
3423
|
+
try {
|
|
3424
|
+
return JSON.stringify(normalized);
|
|
3425
|
+
} catch {
|
|
3426
|
+
return String(error);
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
normalizeUnknownError(error) {
|
|
3430
|
+
var _a, _b;
|
|
3431
|
+
if (error instanceof Error) {
|
|
3432
|
+
const normalized = {
|
|
3433
|
+
name: error.name,
|
|
3434
|
+
message: error.message,
|
|
3435
|
+
stack: error.stack
|
|
3436
|
+
};
|
|
3437
|
+
const record = error;
|
|
3438
|
+
if (((_a = record.response) == null ? void 0 : _a.data) !== void 0)
|
|
3439
|
+
normalized.responseData = record.response.data;
|
|
3440
|
+
if (record.data !== void 0)
|
|
3441
|
+
normalized.data = record.data;
|
|
3442
|
+
if (((_b = record.response) == null ? void 0 : _b.body) !== void 0)
|
|
3443
|
+
normalized.responseBody = record.response.body;
|
|
3444
|
+
if (record.body !== void 0)
|
|
3445
|
+
normalized.body = record.body;
|
|
3446
|
+
return this.safeJsonClone(normalized);
|
|
3447
|
+
}
|
|
3448
|
+
if (!error || typeof error !== "object")
|
|
3449
|
+
return String(error);
|
|
3450
|
+
return this.safeJsonClone(error);
|
|
3451
|
+
}
|
|
3452
|
+
safeJsonClone(value) {
|
|
3453
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
3454
|
+
try {
|
|
3455
|
+
return JSON.parse(JSON.stringify(value, (_key, current) => {
|
|
3456
|
+
if (!current || typeof current !== "object")
|
|
3457
|
+
return current;
|
|
3458
|
+
if (seen.has(current))
|
|
3459
|
+
return "[Circular]";
|
|
3460
|
+
seen.add(current);
|
|
3461
|
+
return current;
|
|
3462
|
+
}));
|
|
3463
|
+
} catch {
|
|
3464
|
+
return String(value);
|
|
3465
|
+
}
|
|
3466
|
+
}
|
|
3467
|
+
extractBackendErrorResponse(error) {
|
|
3468
|
+
var _a, _b;
|
|
3469
|
+
const candidates = [
|
|
3470
|
+
(_a = error == null ? void 0 : error.response) == null ? void 0 : _a.data,
|
|
3471
|
+
error == null ? void 0 : error.data,
|
|
3472
|
+
(_b = error == null ? void 0 : error.response) == null ? void 0 : _b.body,
|
|
3473
|
+
error == null ? void 0 : error.body
|
|
3474
|
+
];
|
|
3475
|
+
return candidates.find(
|
|
3476
|
+
(candidate) => this.isExplicitBackendErrorResponse(candidate)
|
|
3477
|
+
) || null;
|
|
3478
|
+
}
|
|
3479
|
+
isExplicitBackendErrorResponse(candidate) {
|
|
3480
|
+
if (!candidate || typeof candidate !== "object")
|
|
3481
|
+
return false;
|
|
3482
|
+
return candidate.code !== void 0 || candidate.status !== void 0 || typeof candidate.message === "string";
|
|
1876
3483
|
}
|
|
1877
3484
|
/**
|
|
1878
3485
|
* 从 url 或路由 path 解析 pathname(不含 query,去掉末尾 /)
|
|
@@ -2040,6 +3647,38 @@ var Server = class {
|
|
|
2040
3647
|
status: true
|
|
2041
3648
|
};
|
|
2042
3649
|
}
|
|
3650
|
+
/**
|
|
3651
|
+
* 规范商品扩展类型过滤参数。
|
|
3652
|
+
*
|
|
3653
|
+
* @example
|
|
3654
|
+
* const types = this.normalizeProductExtensionTypes(['product_add_time']);
|
|
3655
|
+
*/
|
|
3656
|
+
normalizeProductExtensionTypes(extension_type) {
|
|
3657
|
+
if (!Array.isArray(extension_type))
|
|
3658
|
+
return [];
|
|
3659
|
+
return extension_type.map((item) => String(item || "").trim()).filter(Boolean);
|
|
3660
|
+
}
|
|
3661
|
+
/**
|
|
3662
|
+
* 请求包含 product_add_time 时,按传入 extension_type 数组配置过滤商品。
|
|
3663
|
+
*
|
|
3664
|
+
* @example
|
|
3665
|
+
* const list = this.filterProductsByExtensionTypes(products, ['product_add_time']);
|
|
3666
|
+
*/
|
|
3667
|
+
filterProductsByExtensionTypes(products, extension_type) {
|
|
3668
|
+
const extensionTypes = this.normalizeProductExtensionTypes(extension_type);
|
|
3669
|
+
if (!extensionTypes.includes("product_add_time"))
|
|
3670
|
+
return products;
|
|
3671
|
+
return products.filter((product) => extensionTypes.includes(String((product == null ? void 0 : product.extension_type) || "")));
|
|
3672
|
+
}
|
|
3673
|
+
/**
|
|
3674
|
+
* 判断本次查询是否需要跳过餐牌过滤,直接按扩展类型拉商品。
|
|
3675
|
+
*
|
|
3676
|
+
* @example
|
|
3677
|
+
* const skipMenu = this.shouldQueryProductsByExtensionTypes(['product_add_time']);
|
|
3678
|
+
*/
|
|
3679
|
+
shouldQueryProductsByExtensionTypes(extension_type) {
|
|
3680
|
+
return this.normalizeProductExtensionTypes(extension_type).includes("product_add_time");
|
|
3681
|
+
}
|
|
2043
3682
|
/**
|
|
2044
3683
|
* 商品查询的核心计算逻辑(编排 Products、Menu、Schedule 模块)
|
|
2045
3684
|
* 供 handleProductQuery 首次返回及 pubsub 变更推送复用
|
|
@@ -2049,12 +3688,15 @@ var Server = class {
|
|
|
2049
3688
|
*/
|
|
2050
3689
|
async computeProductQueryResult(context, options) {
|
|
2051
3690
|
const tTotal = performance.now();
|
|
2052
|
-
const { menu_list_ids, schedule_date, schedule_datetime, customer_id, product_id } = context;
|
|
3691
|
+
const { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type, product_id } = context;
|
|
3692
|
+
const queryIds = Array.isArray(ids) ? ids.map((id) => Number(id)).filter((id) => Number.isFinite(id)) : [];
|
|
2053
3693
|
this.logInfo("computeProductQueryResult 开始", {
|
|
2054
3694
|
menuListIdsCount: (menu_list_ids == null ? void 0 : menu_list_ids.length) ?? 0,
|
|
3695
|
+
ids: queryIds,
|
|
2055
3696
|
schedule_datetime,
|
|
2056
3697
|
schedule_date,
|
|
2057
3698
|
customer_id,
|
|
3699
|
+
extension_type,
|
|
2058
3700
|
product_id,
|
|
2059
3701
|
changedIds: options == null ? void 0 : options.changedIds
|
|
2060
3702
|
});
|
|
@@ -2062,6 +3704,39 @@ var Server = class {
|
|
|
2062
3704
|
this.logError("computeProductQueryResult: Products 模块未注册");
|
|
2063
3705
|
return { message: "Products 模块未注册", data: { list: [], count: 0 } };
|
|
2064
3706
|
}
|
|
3707
|
+
if (queryIds.length > 0) {
|
|
3708
|
+
const uniqueIds = Array.from(new Set(queryIds));
|
|
3709
|
+
const tPrice2 = performance.now();
|
|
3710
|
+
const productsWithPrice = await this.products.getProductsWithPrice(schedule_date, {
|
|
3711
|
+
scheduleModule: this.getSchedule(),
|
|
3712
|
+
schedule_datetime,
|
|
3713
|
+
customer_id
|
|
3714
|
+
}, {
|
|
3715
|
+
changedIds: options == null ? void 0 : options.changedIds,
|
|
3716
|
+
productIds: uniqueIds
|
|
3717
|
+
});
|
|
3718
|
+
(0, import_product.perfMark)("computeQuery.getProductsWithPrice(ids)", performance.now() - tPrice2, {
|
|
3719
|
+
count: productsWithPrice.length,
|
|
3720
|
+
ids: uniqueIds
|
|
3721
|
+
});
|
|
3722
|
+
const filteredProducts2 = productsWithPrice.filter((p) => uniqueIds.includes(Number(p == null ? void 0 : p.id))).filter((p) => ((p == null ? void 0 : p.status) || "published") === "published");
|
|
3723
|
+
const extensionFilteredProducts = this.filterProductsByExtensionTypes(filteredProducts2, extension_type);
|
|
3724
|
+
(0, import_product.perfMark)("computeProductQueryResult", performance.now() - tTotal, {
|
|
3725
|
+
mode: "ids",
|
|
3726
|
+
ids: uniqueIds,
|
|
3727
|
+
count: extensionFilteredProducts.length
|
|
3728
|
+
});
|
|
3729
|
+
this.logInfo("computeProductQueryResult 完成(ids)", {
|
|
3730
|
+
ids: uniqueIds,
|
|
3731
|
+
count: extensionFilteredProducts.length
|
|
3732
|
+
});
|
|
3733
|
+
return {
|
|
3734
|
+
code: 200,
|
|
3735
|
+
data: { list: extensionFilteredProducts, count: extensionFilteredProducts.length },
|
|
3736
|
+
message: "",
|
|
3737
|
+
status: true
|
|
3738
|
+
};
|
|
3739
|
+
}
|
|
2065
3740
|
if (product_id != null && Number.isFinite(Number(product_id))) {
|
|
2066
3741
|
const pid = Number(product_id);
|
|
2067
3742
|
const tPrice2 = performance.now();
|
|
@@ -2074,7 +3749,10 @@ var Server = class {
|
|
|
2074
3749
|
count: allProductsWithPrice.length,
|
|
2075
3750
|
productId: pid
|
|
2076
3751
|
});
|
|
2077
|
-
const published =
|
|
3752
|
+
const published = this.filterProductsByExtensionTypes(
|
|
3753
|
+
allProductsWithPrice.filter((p) => ((p == null ? void 0 : p.status) || "published") === "published"),
|
|
3754
|
+
extension_type
|
|
3755
|
+
);
|
|
2078
3756
|
const item = published.find((p) => Number(p.id) === pid) ?? null;
|
|
2079
3757
|
(0, import_product.perfMark)("computeProductQueryResult", performance.now() - tTotal, {
|
|
2080
3758
|
mode: "single",
|
|
@@ -2092,6 +3770,57 @@ var Server = class {
|
|
|
2092
3770
|
status: true
|
|
2093
3771
|
};
|
|
2094
3772
|
}
|
|
3773
|
+
if (this.shouldQueryProductsByExtensionTypes(extension_type)) {
|
|
3774
|
+
const tPrice2 = performance.now();
|
|
3775
|
+
let filteredProducts2 = await this.products.getProductsWithPrice(schedule_date, {
|
|
3776
|
+
scheduleModule: this.getSchedule(),
|
|
3777
|
+
schedule_datetime,
|
|
3778
|
+
customer_id
|
|
3779
|
+
}, {
|
|
3780
|
+
changedIds: options == null ? void 0 : options.changedIds
|
|
3781
|
+
});
|
|
3782
|
+
(0, import_product.perfMark)("computeQuery.getProductsWithPrice(extensionType)", performance.now() - tPrice2, {
|
|
3783
|
+
count: filteredProducts2.length,
|
|
3784
|
+
extension_type
|
|
3785
|
+
});
|
|
3786
|
+
const tStatus2 = performance.now();
|
|
3787
|
+
const beforeStatusCount2 = filteredProducts2.length;
|
|
3788
|
+
filteredProducts2 = filteredProducts2.filter((p) => ((p == null ? void 0 : p.status) || "published") === "published");
|
|
3789
|
+
(0, import_product.perfMark)("computeQuery.filterByStatus(extensionType)", performance.now() - tStatus2, {
|
|
3790
|
+
before: beforeStatusCount2,
|
|
3791
|
+
after: filteredProducts2.length
|
|
3792
|
+
});
|
|
3793
|
+
const tExtensionType2 = performance.now();
|
|
3794
|
+
const beforeExtensionTypeCount2 = filteredProducts2.length;
|
|
3795
|
+
filteredProducts2 = this.filterProductsByExtensionTypes(filteredProducts2, extension_type);
|
|
3796
|
+
(0, import_product.perfMark)("computeQuery.filterByExtensionType(extensionType)", performance.now() - tExtensionType2, {
|
|
3797
|
+
before: beforeExtensionTypeCount2,
|
|
3798
|
+
after: filteredProducts2.length,
|
|
3799
|
+
extension_type
|
|
3800
|
+
});
|
|
3801
|
+
const tSort2 = performance.now();
|
|
3802
|
+
filteredProducts2 = filteredProducts2.sort((a, b) => {
|
|
3803
|
+
const sortDiff = Number(b.sort) - Number(a.sort);
|
|
3804
|
+
if (sortDiff !== 0)
|
|
3805
|
+
return sortDiff;
|
|
3806
|
+
return (a.title || "").localeCompare(b.title || "");
|
|
3807
|
+
});
|
|
3808
|
+
(0, import_product.perfMark)("computeQuery.sort(extensionType)", performance.now() - tSort2, { count: filteredProducts2.length });
|
|
3809
|
+
(0, import_product.perfMark)("computeProductQueryResult", performance.now() - tTotal, {
|
|
3810
|
+
mode: "extensionType",
|
|
3811
|
+
filteredCount: filteredProducts2.length
|
|
3812
|
+
});
|
|
3813
|
+
this.logInfo("computeProductQueryResult 完成(extension_type)", {
|
|
3814
|
+
filteredCount: filteredProducts2.length,
|
|
3815
|
+
extension_type
|
|
3816
|
+
});
|
|
3817
|
+
return {
|
|
3818
|
+
code: 200,
|
|
3819
|
+
data: { list: filteredProducts2, count: filteredProducts2.length },
|
|
3820
|
+
message: "",
|
|
3821
|
+
status: true
|
|
3822
|
+
};
|
|
3823
|
+
}
|
|
2095
3824
|
if (!this.menu) {
|
|
2096
3825
|
this.logError("computeProductQueryResult: Menu 模块未注册");
|
|
2097
3826
|
return { message: "Menu 模块未注册", data: { list: [], count: 0 } };
|
|
@@ -2141,6 +3870,14 @@ var Server = class {
|
|
|
2141
3870
|
before: beforeStatusCount,
|
|
2142
3871
|
after: filteredProducts.length
|
|
2143
3872
|
});
|
|
3873
|
+
const tExtensionType = performance.now();
|
|
3874
|
+
const beforeExtensionTypeCount = filteredProducts.length;
|
|
3875
|
+
filteredProducts = this.filterProductsByExtensionTypes(filteredProducts, extension_type);
|
|
3876
|
+
(0, import_product.perfMark)("computeQuery.filterByExtensionType", performance.now() - tExtensionType, {
|
|
3877
|
+
before: beforeExtensionTypeCount,
|
|
3878
|
+
after: filteredProducts.length,
|
|
3879
|
+
extension_type
|
|
3880
|
+
});
|
|
2144
3881
|
const tSort = performance.now();
|
|
2145
3882
|
filteredProducts = filteredProducts.sort((a, b) => {
|
|
2146
3883
|
const sortDiff = Number(b.sort) - Number(a.sort);
|
|
@@ -2234,6 +3971,101 @@ var Server = class {
|
|
|
2234
3971
|
totalNotifyDurationMs: notifyEndAt - notifyStartAt
|
|
2235
3972
|
});
|
|
2236
3973
|
}
|
|
3974
|
+
/**
|
|
3975
|
+
* 订单变更后通知 sales 搜索订阅者。
|
|
3976
|
+
* 仅回传当前查询已返回订单号集合中的变更订单。
|
|
3977
|
+
*
|
|
3978
|
+
* @example
|
|
3979
|
+
* this.notifySalesSearchSubscribers({ list: [], changedOrders: [order], source: 'pubsub.bodyUpsert' })
|
|
3980
|
+
*/
|
|
3981
|
+
notifySalesSearchSubscribers(payload) {
|
|
3982
|
+
if (this.salesSearchSubscribers.size === 0)
|
|
3983
|
+
return;
|
|
3984
|
+
const changedOrders = this.extractChangedOrdersFromPayload(payload);
|
|
3985
|
+
if (changedOrders.length === 0) {
|
|
3986
|
+
return;
|
|
3987
|
+
}
|
|
3988
|
+
for (const [subscriberId, subscriber] of this.salesSearchSubscribers.entries()) {
|
|
3989
|
+
try {
|
|
3990
|
+
const changedVisibleOrders = changedOrders.filter((order) => {
|
|
3991
|
+
const orderId = this.getSalesSearchOrderId(order);
|
|
3992
|
+
return !!orderId && subscriber.visibleOrderIds.has(orderId);
|
|
3993
|
+
});
|
|
3994
|
+
if (changedVisibleOrders.length === 0) {
|
|
3995
|
+
continue;
|
|
3996
|
+
}
|
|
3997
|
+
subscriber.callback(
|
|
3998
|
+
this.buildSalesSearchDeltaResponse(subscriber, changedVisibleOrders)
|
|
3999
|
+
);
|
|
4000
|
+
this.logInfo("notifySalesSearchSubscribers: 已推送 delta", {
|
|
4001
|
+
subscriberId,
|
|
4002
|
+
kind: subscriber.kind,
|
|
4003
|
+
count: changedVisibleOrders.length
|
|
4004
|
+
});
|
|
4005
|
+
} catch (error) {
|
|
4006
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4007
|
+
this.logError("notifySalesSearchSubscribers: 推送失败", {
|
|
4008
|
+
subscriberId,
|
|
4009
|
+
error: errorMessage
|
|
4010
|
+
});
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
}
|
|
4014
|
+
/**
|
|
4015
|
+
* 从订单变更事件中提取明确 delta。
|
|
4016
|
+
*
|
|
4017
|
+
* @example
|
|
4018
|
+
* const list = this.extractChangedOrdersFromPayload(payload)
|
|
4019
|
+
*/
|
|
4020
|
+
extractChangedOrdersFromPayload(payload) {
|
|
4021
|
+
if (!payload || Array.isArray(payload))
|
|
4022
|
+
return [];
|
|
4023
|
+
return Array.isArray(payload.changedOrders) ? payload.changedOrders : [];
|
|
4024
|
+
}
|
|
4025
|
+
/**
|
|
4026
|
+
* 构建与当前搜索接口一致的 delta 响应。
|
|
4027
|
+
*
|
|
4028
|
+
* @example
|
|
4029
|
+
* const response = this.buildSalesSearchDeltaResponse(subscriber, [order])
|
|
4030
|
+
*/
|
|
4031
|
+
buildSalesSearchDeltaResponse(subscriber, changedOrders) {
|
|
4032
|
+
if (subscriber.kind === "aggregate") {
|
|
4033
|
+
return this.buildAggregateSalesSearchDeltaResponse(subscriber, changedOrders);
|
|
4034
|
+
}
|
|
4035
|
+
const data = subscriber.lastResponseData || {};
|
|
4036
|
+
return {
|
|
4037
|
+
code: 200,
|
|
4038
|
+
status: true,
|
|
4039
|
+
message: "",
|
|
4040
|
+
data: {
|
|
4041
|
+
...data,
|
|
4042
|
+
list: changedOrders
|
|
4043
|
+
}
|
|
4044
|
+
};
|
|
4045
|
+
}
|
|
4046
|
+
/**
|
|
4047
|
+
* 构建聚合搜索接口的 sales 分组 delta 响应。
|
|
4048
|
+
*
|
|
4049
|
+
* @example
|
|
4050
|
+
* const response = this.buildAggregateSalesSearchDeltaResponse(subscriber, [order])
|
|
4051
|
+
*/
|
|
4052
|
+
buildAggregateSalesSearchDeltaResponse(subscriber, changedOrders) {
|
|
4053
|
+
const data = subscriber.lastResponseData || {};
|
|
4054
|
+
const results = Array.isArray(data == null ? void 0 : data.results) ? data.results : [];
|
|
4055
|
+
const hasSalesGroup = results.some((item) => (item == null ? void 0 : item.module) === "sales");
|
|
4056
|
+
const nextResults = hasSalesGroup ? results.map(
|
|
4057
|
+
(item) => (item == null ? void 0 : item.module) === "sales" ? { ...item, list: changedOrders } : item
|
|
4058
|
+
) : [{ module: "sales", list: changedOrders, count: changedOrders.length }];
|
|
4059
|
+
return {
|
|
4060
|
+
code: 200,
|
|
4061
|
+
status: true,
|
|
4062
|
+
message: "",
|
|
4063
|
+
data: {
|
|
4064
|
+
...data,
|
|
4065
|
+
results: nextResults
|
|
4066
|
+
}
|
|
4067
|
+
};
|
|
4068
|
+
}
|
|
2237
4069
|
/**
|
|
2238
4070
|
* 预约数据变更后,遍历订阅者重新计算并通过 callback 推送
|
|
2239
4071
|
*/
|