@pisell/pisellos 0.0.568 → 0.0.570
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/effects/index.d.ts +2 -2
- package/dist/model/strategy/adapter/dataVariant/type.d.ts +3 -3
- package/dist/model/strategy/adapter/itemRule/type.d.ts +6 -6
- package/dist/model/strategy/adapter/promotion/evaluator.js +3 -2
- package/dist/model/strategy/adapter/promotion/type.d.ts +5 -5
- package/dist/model/strategy/adapter/walletPass/utils.js +7 -4
- package/dist/model/strategy/type.d.ts +1 -1
- package/dist/modules/BaseModule.d.ts +2 -2
- package/dist/modules/BaseModule.js +4 -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 +302 -0
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +149 -0
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +249 -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 +26 -5
- package/dist/modules/Cart/utils/changePrice.js +27 -20
- package/dist/modules/Customer/index.d.ts +20 -0
- package/dist/modules/Customer/index.js +172 -83
- package/dist/modules/Customer/types.d.ts +3 -1
- package/dist/modules/Discount/index.d.ts +2 -1
- package/dist/modules/Discount/index.js +37 -9
- package/dist/modules/Discount/types.d.ts +2 -1
- package/dist/modules/Holder/types.d.ts +1 -1
- package/dist/modules/OpenData/index.d.ts +8 -0
- package/dist/modules/OpenData/index.js +36 -16
- package/dist/modules/OpenData/types.d.ts +1 -1
- package/dist/modules/Order/index.d.ts +448 -23
- package/dist/modules/Order/index.js +5417 -561
- package/dist/modules/Order/types.d.ts +693 -88
- package/dist/modules/Order/types.js +68 -1
- package/dist/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
- package/dist/modules/Order/utils/bundleDiscountHydration.js +144 -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/orderCollectionIdentity.d.ts +53 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.js +405 -0
- package/dist/modules/Order/utils.d.ts +167 -18
- package/dist/modules/Order/utils.js +960 -165
- package/dist/modules/Payment/index.d.ts +10 -9
- package/dist/modules/Payment/index.js +465 -703
- package/dist/modules/Payment/types.d.ts +47 -23
- package/dist/modules/Payment/utils.d.ts +1 -1
- package/dist/modules/Payment/utils.js +4 -3
- package/dist/modules/Payment/walletpass.js +44 -29
- package/dist/modules/Product/index.d.ts +1 -1
- package/dist/modules/Product/types.d.ts +29 -7
- package/dist/modules/ProductList/index.d.ts +17 -13
- package/dist/modules/ProductList/index.js +184 -74
- package/dist/modules/ProductList/types.d.ts +17 -0
- package/dist/modules/Quotation/index.d.ts +22 -2
- package/dist/modules/Quotation/index.js +108 -42
- package/dist/modules/Quotation/types.d.ts +19 -0
- package/dist/modules/ResourcePlanner/index.d.ts +24 -0
- package/dist/modules/ResourcePlanner/index.js +181 -0
- package/dist/modules/ResourcePlanner/planner.d.ts +14 -0
- package/dist/modules/ResourcePlanner/planner.js +1069 -0
- package/dist/modules/ResourcePlanner/types.d.ts +227 -0
- package/dist/modules/ResourcePlanner/types.js +1 -0
- package/dist/modules/Rules/index.d.ts +8 -10
- package/dist/modules/Rules/index.js +222 -109
- package/dist/modules/Rules/types.d.ts +15 -4
- package/dist/modules/SalesSummary/index.d.ts +23 -26
- package/dist/modules/SalesSummary/index.js +152 -46
- package/dist/modules/SalesSummary/types.d.ts +9 -1
- package/dist/modules/SalesSummary/utils.d.ts +3 -22
- package/dist/modules/SalesSummary/utils.js +803 -163
- package/dist/modules/ScanOrderLogger/types.d.ts +2 -2
- package/dist/modules/Schedule/getDateIsInSchedule.d.ts +1 -1
- package/dist/modules/Schedule/getDateIsInSchedule.js +14 -7
- package/dist/modules/Schedule/index.d.ts +18 -5
- package/dist/modules/Schedule/index.js +78 -24
- package/dist/modules/Schedule/type.d.ts +7 -7
- package/dist/modules/Schedule/types.d.ts +11 -9
- package/dist/modules/Summary/index.js +4 -3
- package/dist/modules/SurchargeList/index.d.ts +18 -0
- package/dist/modules/SurchargeList/index.js +185 -0
- package/dist/modules/SurchargeList/types.d.ts +15 -0
- package/dist/modules/SurchargeList/types.js +1 -0
- package/dist/modules/index.d.ts +3 -0
- package/dist/modules/index.js +4 -1
- package/dist/plugins/app.d.ts +2 -0
- package/dist/plugins/request.d.ts +3 -2
- package/dist/server/index.d.ts +462 -8
- package/dist/server/index.js +6112 -656
- package/dist/server/modules/floor-plan/index.d.ts +39 -0
- package/dist/server/modules/floor-plan/index.js +595 -0
- package/dist/server/modules/floor-plan/types.d.ts +43 -0
- package/dist/server/modules/floor-plan/types.js +13 -0
- package/dist/server/modules/index.d.ts +7 -2
- package/dist/server/modules/index.js +6 -0
- package/dist/server/modules/menu/types.d.ts +1 -1
- package/dist/server/modules/order/index.d.ts +207 -14
- package/dist/server/modules/order/index.js +2326 -379
- package/dist/server/modules/order/types.d.ts +91 -20
- package/dist/server/modules/order/types.js +14 -1
- package/dist/server/modules/order/utils/filterBookings.d.ts +7 -1
- package/dist/server/modules/order/utils/filterBookings.js +118 -11
- package/dist/server/modules/order/utils/filterOrders.js +242 -14
- 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 +105 -14
- package/dist/server/modules/products/index.js +1393 -516
- package/dist/server/modules/products/types.d.ts +35 -2
- package/dist/server/modules/products/types.js +4 -0
- package/dist/server/modules/quotation/index.d.ts +39 -0
- package/dist/server/modules/quotation/index.js +278 -66
- package/dist/server/modules/resource/index.d.ts +2 -3
- package/dist/server/modules/resource/index.js +108 -86
- package/dist/server/modules/resource/types.d.ts +1 -1
- package/dist/server/modules/schedule/index.d.ts +6 -4
- package/dist/server/modules/schedule/index.js +116 -85
- package/dist/server/modules/schedule/utils.d.ts +1 -1
- package/dist/server/test.json +713 -0
- package/dist/server/types.d.ts +6 -4
- package/dist/server/utils/product.js +2 -2
- package/dist/server/utils/small-ticket.d.ts +71 -0
- package/dist/server/utils/small-ticket.js +963 -0
- package/dist/solution/BaseSales/index.d.ts +378 -0
- package/dist/solution/BaseSales/index.js +4006 -0
- package/dist/solution/BaseSales/types.d.ts +394 -0
- package/dist/solution/BaseSales/types.js +40 -0
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
- package/dist/solution/BaseSales/utils/cartPromotion.js +1450 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +144 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +157 -0
- package/dist/solution/BaseSales/utils/quotationPrice.d.ts +18 -0
- package/dist/solution/BaseSales/utils/quotationPrice.js +250 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +63 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +218 -0
- package/dist/solution/BaseSales/utils.d.ts +40 -0
- package/dist/solution/BaseSales/utils.js +263 -0
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/BookingByStep/utils/resources.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +382 -25
- package/dist/solution/BookingTicket/index.js +2506 -443
- package/dist/solution/BookingTicket/types.d.ts +191 -6
- package/dist/solution/BookingTicket/types.js +83 -10
- 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 +77 -0
- package/dist/solution/BookingTicket/utils/bookingStatus.js +136 -0
- package/dist/solution/BookingTicket/utils/cartView.d.ts +29 -0
- package/dist/solution/BookingTicket/utils/cartView.js +209 -0
- package/dist/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/dist/solution/BookingTicket/utils/exampleData.js +183 -0
- package/dist/solution/BookingTicket/utils/orderCustomer.d.ts +4 -0
- package/dist/solution/BookingTicket/utils/orderCustomer.js +31 -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/cloudSearch.d.ts +4 -0
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +41 -1
- 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/handleScan.d.ts +3 -1
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +11 -3
- 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 +25 -34
- package/dist/solution/Checkout/utils/index.js +4 -4
- package/dist/solution/RegisterAndLogin/config.js +2 -10
- package/dist/solution/Sales/index.d.ts +50 -5
- package/dist/solution/Sales/index.js +484 -92
- package/dist/solution/Sales/types.d.ts +29 -5
- package/dist/solution/ScanOrder/index.d.ts +27 -21
- package/dist/solution/ScanOrder/index.js +499 -434
- package/dist/solution/ScanOrder/types.d.ts +38 -16
- package/dist/solution/ScanOrder/types.js +4 -5
- package/dist/solution/ScanOrder/utils.d.ts +4 -1
- package/dist/solution/ScanOrder/utils.js +109 -34
- package/dist/solution/ShopDiscount/index.js +4 -4
- package/dist/solution/ShopDiscount/types.d.ts +1 -1
- package/dist/solution/ShopDiscount/utils.d.ts +2 -2
- package/dist/solution/UnifiedBookingSales/index.d.ts +183 -0
- package/dist/solution/UnifiedBookingSales/index.js +1871 -0
- package/dist/solution/UnifiedBookingSales/types.d.ts +143 -0
- package/dist/solution/UnifiedBookingSales/types.js +11 -0
- package/dist/solution/VenueBooking/index.d.ts +29 -20
- package/dist/solution/VenueBooking/index.js +301 -213
- package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
- package/dist/solution/VenueBooking/types.d.ts +1 -1
- package/dist/solution/VenueBooking/utils/slotMerge.d.ts +6 -0
- package/dist/solution/VenueBooking/utils/slotMerge.js +9 -3
- package/dist/solution/index.d.ts +2 -0
- package/dist/solution/index.js +3 -1
- package/dist/types/index.d.ts +12 -2
- package/dist/utils/task.d.ts +2 -2
- package/dist/utils/watch.d.ts +2 -2
- package/lib/effects/index.d.ts +2 -2
- package/lib/model/strategy/adapter/dataVariant/type.d.ts +3 -3
- package/lib/model/strategy/adapter/itemRule/type.d.ts +6 -6
- package/lib/model/strategy/adapter/promotion/evaluator.js +3 -2
- package/lib/model/strategy/adapter/promotion/type.d.ts +5 -5
- package/lib/model/strategy/adapter/walletPass/utils.js +6 -4
- package/lib/model/strategy/type.d.ts +1 -1
- package/lib/modules/BaseModule.d.ts +2 -2
- package/lib/modules/BaseModule.js +4 -4
- package/lib/modules/BookingContext/index.d.ts +48 -0
- package/lib/modules/BookingContext/index.js +390 -0
- package/lib/modules/BookingContext/types.d.ts +102 -0
- package/lib/modules/BookingContext/types.js +48 -0
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +286 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +148 -0
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +242 -0
- package/lib/modules/BookingContext/utils/flexible.d.ts +28 -0
- package/lib/modules/BookingContext/utils/flexible.js +63 -0
- package/lib/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
- package/lib/modules/BookingContext/utils/formatResourceList.js +35 -0
- package/lib/modules/BookingContext/utils/index.d.ts +11 -0
- package/lib/modules/BookingContext/utils/index.js +126 -0
- package/lib/modules/BookingContext/utils/noResource.d.ts +13 -0
- package/lib/modules/BookingContext/utils/noResource.js +78 -0
- package/lib/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +29 -0
- package/lib/modules/BookingContext/utils/productExtend.d.ts +72 -0
- package/lib/modules/BookingContext/utils/productExtend.js +330 -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 +24 -0
- package/lib/modules/BookingContext/utils/resources.d.ts +80 -0
- package/lib/modules/BookingContext/utils/resources.js +419 -0
- package/lib/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
- package/lib/modules/BookingContext/utils/serviceTimes.js +161 -0
- package/lib/modules/BookingContext/utils/timeSlices.d.ts +42 -0
- package/lib/modules/BookingContext/utils/timeSlices.js +114 -0
- package/lib/modules/Cart/utils/cartProduct.js +27 -5
- package/lib/modules/Cart/utils/changePrice.js +20 -14
- package/lib/modules/Customer/index.d.ts +20 -0
- package/lib/modules/Customer/index.js +63 -10
- package/lib/modules/Customer/types.d.ts +3 -1
- package/lib/modules/Discount/index.d.ts +2 -1
- package/lib/modules/Discount/index.js +18 -2
- package/lib/modules/Discount/types.d.ts +2 -1
- package/lib/modules/Holder/types.d.ts +1 -1
- package/lib/modules/OpenData/index.d.ts +8 -0
- package/lib/modules/OpenData/index.js +21 -3
- package/lib/modules/OpenData/types.d.ts +1 -1
- package/lib/modules/Order/index.d.ts +448 -23
- package/lib/modules/Order/index.js +3641 -308
- package/lib/modules/Order/types.d.ts +693 -88
- package/lib/modules/Order/types.js +55 -1
- package/lib/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
- package/lib/modules/Order/utils/bundleDiscountHydration.js +106 -0
- package/lib/modules/Order/utils/manualProductDiscount.d.ts +106 -0
- package/lib/modules/Order/utils/manualProductDiscount.js +207 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.js +353 -0
- package/lib/modules/Order/utils.d.ts +167 -18
- package/lib/modules/Order/utils.js +974 -138
- package/lib/modules/Payment/index.d.ts +10 -9
- package/lib/modules/Payment/index.js +30 -124
- package/lib/modules/Payment/types.d.ts +47 -23
- package/lib/modules/Payment/utils.d.ts +1 -1
- package/lib/modules/Payment/utils.js +4 -3
- package/lib/modules/Payment/walletpass.js +16 -6
- package/lib/modules/Product/index.d.ts +1 -1
- package/lib/modules/Product/types.d.ts +29 -7
- package/lib/modules/ProductList/index.d.ts +17 -13
- package/lib/modules/ProductList/index.js +92 -51
- package/lib/modules/ProductList/types.d.ts +17 -0
- package/lib/modules/Quotation/index.d.ts +22 -2
- package/lib/modules/Quotation/index.js +76 -20
- package/lib/modules/Quotation/types.d.ts +19 -0
- package/lib/modules/ResourcePlanner/index.d.ts +24 -0
- package/lib/modules/ResourcePlanner/index.js +147 -0
- package/lib/modules/ResourcePlanner/planner.d.ts +14 -0
- package/lib/modules/ResourcePlanner/planner.js +895 -0
- package/lib/modules/ResourcePlanner/types.d.ts +227 -0
- package/lib/modules/ResourcePlanner/types.js +5 -0
- package/lib/modules/Rules/index.d.ts +8 -10
- package/lib/modules/Rules/index.js +153 -61
- package/lib/modules/Rules/types.d.ts +15 -4
- package/lib/modules/SalesSummary/index.d.ts +23 -26
- package/lib/modules/SalesSummary/index.js +84 -16
- package/lib/modules/SalesSummary/types.d.ts +9 -1
- package/lib/modules/SalesSummary/utils.d.ts +3 -22
- package/lib/modules/SalesSummary/utils.js +616 -111
- package/lib/modules/ScanOrderLogger/types.d.ts +2 -2
- package/lib/modules/Schedule/getDateIsInSchedule.d.ts +1 -1
- package/lib/modules/Schedule/getDateIsInSchedule.js +14 -7
- package/lib/modules/Schedule/index.d.ts +18 -5
- package/lib/modules/Schedule/index.js +49 -14
- package/lib/modules/Schedule/type.d.ts +7 -7
- package/lib/modules/Schedule/types.d.ts +11 -9
- package/lib/modules/Summary/index.js +2 -2
- package/lib/modules/SurchargeList/index.d.ts +18 -0
- package/lib/modules/SurchargeList/index.js +95 -0
- package/lib/modules/SurchargeList/types.d.ts +15 -0
- package/lib/modules/SurchargeList/types.js +5 -0
- package/lib/modules/index.d.ts +3 -0
- package/lib/modules/index.js +33 -0
- package/lib/plugins/app.d.ts +2 -0
- package/lib/plugins/request.d.ts +3 -2
- package/lib/server/index.d.ts +462 -8
- package/lib/server/index.js +3901 -205
- package/lib/server/modules/floor-plan/index.d.ts +39 -0
- package/lib/server/modules/floor-plan/index.js +306 -0
- package/lib/server/modules/floor-plan/types.d.ts +43 -0
- package/lib/server/modules/floor-plan/types.js +19 -0
- package/lib/server/modules/index.d.ts +7 -2
- package/lib/server/modules/index.js +21 -0
- package/lib/server/modules/menu/types.d.ts +1 -1
- package/lib/server/modules/order/index.d.ts +207 -14
- package/lib/server/modules/order/index.js +1324 -141
- package/lib/server/modules/order/types.d.ts +91 -20
- package/lib/server/modules/order/types.js +11 -1
- package/lib/server/modules/order/utils/filterBookings.d.ts +7 -1
- package/lib/server/modules/order/utils/filterBookings.js +119 -11
- package/lib/server/modules/order/utils/filterOrders.js +238 -13
- package/lib/server/modules/payment/index.d.ts +28 -0
- package/lib/server/modules/payment/index.js +168 -0
- package/lib/server/modules/payment/types.d.ts +9 -0
- package/lib/server/modules/payment/types.js +5 -0
- package/lib/server/modules/products/index.d.ts +105 -14
- package/lib/server/modules/products/index.js +588 -97
- package/lib/server/modules/products/types.d.ts +35 -2
- package/lib/server/modules/products/types.js +3 -0
- package/lib/server/modules/quotation/index.d.ts +39 -0
- package/lib/server/modules/quotation/index.js +145 -1
- package/lib/server/modules/resource/index.d.ts +2 -3
- package/lib/server/modules/resource/index.js +71 -45
- package/lib/server/modules/resource/types.d.ts +1 -1
- package/lib/server/modules/schedule/index.d.ts +6 -4
- package/lib/server/modules/schedule/index.js +55 -44
- package/lib/server/modules/schedule/utils.d.ts +1 -1
- package/lib/server/test.json +713 -0
- package/lib/server/types.d.ts +6 -4
- package/lib/server/utils/product.js +2 -2
- package/lib/server/utils/small-ticket.d.ts +71 -0
- package/lib/server/utils/small-ticket.js +926 -0
- package/lib/solution/BaseSales/index.d.ts +378 -0
- package/lib/solution/BaseSales/index.js +2367 -0
- package/lib/solution/BaseSales/types.d.ts +394 -0
- package/lib/solution/BaseSales/types.js +47 -0
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
- package/lib/solution/BaseSales/utils/cartPromotion.js +1155 -0
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +144 -0
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +140 -0
- package/lib/solution/BaseSales/utils/quotationPrice.d.ts +18 -0
- package/lib/solution/BaseSales/utils/quotationPrice.js +231 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +63 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +215 -0
- package/lib/solution/BaseSales/utils.d.ts +40 -0
- package/lib/solution/BaseSales/utils.js +259 -0
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/BookingByStep/utils/resources.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +382 -25
- package/lib/solution/BookingTicket/index.js +1350 -76
- package/lib/solution/BookingTicket/types.d.ts +191 -6
- package/lib/solution/BookingTicket/types.js +71 -10
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
- package/lib/solution/BookingTicket/utils/addProductDecision.js +353 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +94 -0
- package/lib/solution/BookingTicket/utils/bookingStatus.d.ts +77 -0
- package/lib/solution/BookingTicket/utils/bookingStatus.js +136 -0
- package/lib/solution/BookingTicket/utils/cartView.d.ts +29 -0
- package/lib/solution/BookingTicket/utils/cartView.js +200 -0
- package/lib/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/lib/solution/BookingTicket/utils/exampleData.js +185 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.d.ts +4 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.js +35 -0
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +387 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +220 -0
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.d.ts +4 -0
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +24 -3
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +64 -0
- package/lib/solution/BookingTicket/utils/scan/handleScan.d.ts +3 -1
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +4 -2
- package/lib/solution/BookingTicket/utils/scan/index.d.ts +5 -0
- package/lib/solution/BookingTicket/utils/scan/index.js +14 -2
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +115 -0
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +83 -0
- package/lib/solution/Checkout/index.d.ts +1 -0
- package/lib/solution/Checkout/index.js +18 -19
- package/lib/solution/Checkout/utils/index.js +4 -4
- package/lib/solution/RegisterAndLogin/config.js +2 -10
- package/lib/solution/Sales/index.d.ts +50 -5
- package/lib/solution/Sales/index.js +296 -39
- package/lib/solution/Sales/types.d.ts +29 -5
- package/lib/solution/ScanOrder/index.d.ts +27 -21
- package/lib/solution/ScanOrder/index.js +144 -103
- package/lib/solution/ScanOrder/types.d.ts +38 -16
- package/lib/solution/ScanOrder/types.js +4 -5
- package/lib/solution/ScanOrder/utils.d.ts +4 -1
- package/lib/solution/ScanOrder/utils.js +98 -26
- package/lib/solution/ShopDiscount/index.js +3 -3
- package/lib/solution/ShopDiscount/types.d.ts +1 -1
- package/lib/solution/ShopDiscount/utils.d.ts +2 -2
- package/lib/solution/UnifiedBookingSales/index.d.ts +183 -0
- package/lib/solution/UnifiedBookingSales/index.js +1050 -0
- package/lib/solution/UnifiedBookingSales/types.d.ts +143 -0
- package/lib/solution/UnifiedBookingSales/types.js +14 -0
- package/lib/solution/VenueBooking/index.d.ts +29 -20
- package/lib/solution/VenueBooking/index.js +169 -94
- package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
- package/lib/solution/VenueBooking/types.d.ts +1 -1
- package/lib/solution/VenueBooking/utils/slotMerge.d.ts +6 -0
- package/lib/solution/VenueBooking/utils/slotMerge.js +9 -3
- package/lib/solution/index.d.ts +2 -0
- package/lib/solution/index.js +22 -0
- package/lib/types/index.d.ts +12 -2
- package/lib/utils/task.d.ts +2 -2
- package/lib/utils/watch.d.ts +2 -2
- package/package.json +18 -19
- package/dist/model/strategy/adapter/promotion/index.d.ts +0 -4
- package/dist/solution/Checkout/appointmentDemo.json +0 -1
- package/lib/model/strategy/adapter/promotion/index.d.ts +0 -4
- package/lib/solution/Checkout/appointmentDemo.json +0 -1
|
@@ -5,16 +5,17 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.ProductsModule = void 0;
|
|
7
7
|
var _BaseModule = require("../../../modules/BaseModule");
|
|
8
|
-
var
|
|
8
|
+
var _Quotation = require("../../../modules/Quotation");
|
|
9
9
|
var _types = require("./types");
|
|
10
10
|
var _product = require("../../utils/product");
|
|
11
11
|
/**
|
|
12
12
|
* IndexDB 存储名称
|
|
13
13
|
*/
|
|
14
14
|
const INDEXDB_STORE_NAME = 'products';
|
|
15
|
-
|
|
16
15
|
/** 商品同步防抖时间(毫秒) */
|
|
17
16
|
const PRODUCT_SYNC_DEBOUNCE_MS = 10_000;
|
|
17
|
+
/** silentRefresh 最小间隔,避免 preload 后立即全量重拉 */
|
|
18
|
+
const PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS = 30_000;
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Products 模块 - 用于获取和管理完整的商品详细数据
|
|
@@ -38,13 +39,34 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
38
39
|
// 商品格式化器列表
|
|
39
40
|
formatters = [];
|
|
40
41
|
|
|
41
|
-
//
|
|
42
|
-
|
|
42
|
+
// 是否已注册内置商品格式化器
|
|
43
|
+
isBuiltinFormatterRegistered = false;
|
|
44
|
+
// 旧报价单格式化器默认关闭,仅显式开启时作为兼容兜底注册
|
|
45
|
+
isLegacyPriceFormatterEnabled = false;
|
|
46
|
+
|
|
47
|
+
// 普通层 QuotationModule 桥接器:本地计算报价单价格,替代 /product/query/price
|
|
48
|
+
quotationPriceBridge;
|
|
49
|
+
quotationBridgeChannel;
|
|
50
|
+
quotationBridgeLoadedKey = '';
|
|
51
|
+
quotationBridgeRefreshPromise;
|
|
52
|
+
quotationBridgeRefreshKey;
|
|
53
|
+
quotationScheduleCache = new Map();
|
|
54
|
+
quotationScheduleCacheSource = null;
|
|
55
|
+
quotationScheduleCacheLoaded = false;
|
|
43
56
|
|
|
44
57
|
// ---- 商品数据同步相关 ----
|
|
45
58
|
productDataSource;
|
|
46
59
|
pendingSyncMessages = [];
|
|
47
60
|
syncTimer;
|
|
61
|
+
/** 最近一次 SSE 全量拉取完成时间 */
|
|
62
|
+
lastServerFullFetchAtMs = 0;
|
|
63
|
+
/** 最近一次 preload 完成时间(含 IndexDB 命中) */
|
|
64
|
+
lastPreloadCompletedAtMs = 0;
|
|
65
|
+
/** IndexDB 写入串行队列,避免快照与 patch 并发交错 */
|
|
66
|
+
productIndexDBSaveQueue = Promise.resolve();
|
|
67
|
+
|
|
68
|
+
/** 最近一次智能定价评估提取的 schedule 变价时间点(HH:mm),供 Server 订阅定时刷新使用 */
|
|
69
|
+
lastScheduleTimePoints = [];
|
|
48
70
|
constructor(name, version) {
|
|
49
71
|
super(name, version);
|
|
50
72
|
}
|
|
@@ -74,8 +96,8 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
74
96
|
}
|
|
75
97
|
}
|
|
76
98
|
|
|
77
|
-
//
|
|
78
|
-
this.
|
|
99
|
+
// 注册内置商品格式化器;智能定价默认替代报价单价格逻辑
|
|
100
|
+
this.registerBuiltinProductFormatters();
|
|
79
101
|
|
|
80
102
|
// 初始化 ProductDataSource 实例
|
|
81
103
|
this.initProductDataSource();
|
|
@@ -152,33 +174,30 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
152
174
|
*/
|
|
153
175
|
async loadProductsPrice({
|
|
154
176
|
ids = [],
|
|
155
|
-
|
|
156
|
-
|
|
177
|
+
schedule_date,
|
|
178
|
+
schedule_datetime,
|
|
179
|
+
customer_id
|
|
157
180
|
}) {
|
|
158
181
|
this.logInfo('开始加载商品价格', {
|
|
159
182
|
productCount: ids.length,
|
|
160
183
|
schedule_date,
|
|
184
|
+
schedule_datetime,
|
|
161
185
|
customer_id
|
|
162
186
|
});
|
|
163
187
|
const startTime = Date.now();
|
|
188
|
+
const datetime = schedule_datetime || schedule_date;
|
|
164
189
|
try {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}, {
|
|
170
|
-
cache: {
|
|
171
|
-
mode: _plugins.RequestModeENUM.REMOTE_LOCAL,
|
|
172
|
-
type: "memory"
|
|
173
|
-
}
|
|
174
|
-
});
|
|
190
|
+
await this.ensureQuotationBridgeReady(customer_id);
|
|
191
|
+
const idSet = new Set(ids);
|
|
192
|
+
const products = this.getProductsRef().filter(product => idSet.has(product.id));
|
|
193
|
+
const priceData = products.map(product => this.buildPriceDataFromQuotation(product, datetime, customer_id));
|
|
175
194
|
const duration = Date.now() - startTime;
|
|
176
195
|
this.logInfo('加载商品价格成功', {
|
|
177
196
|
productCount: ids.length,
|
|
178
|
-
priceDataCount:
|
|
197
|
+
priceDataCount: priceData.length,
|
|
179
198
|
duration: `${duration}ms`
|
|
180
199
|
});
|
|
181
|
-
return
|
|
200
|
+
return priceData;
|
|
182
201
|
} catch (error) {
|
|
183
202
|
const duration = Date.now() - startTime;
|
|
184
203
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -191,6 +210,179 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
191
210
|
}
|
|
192
211
|
}
|
|
193
212
|
|
|
213
|
+
/**
|
|
214
|
+
* 设置报价单价格桥接器。
|
|
215
|
+
* Server 层负责传入完整 schedule 模块,Products 只负责把报价单计算结果转成价格响应形状。
|
|
216
|
+
*/
|
|
217
|
+
async setupQuotationPriceBridge(params) {
|
|
218
|
+
if (!this.core) {
|
|
219
|
+
this.logWarning('setupQuotationPriceBridge: core 尚未初始化');
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const channel = params.channel || this.otherParams?.channel;
|
|
223
|
+
this.quotationBridgeChannel = channel;
|
|
224
|
+
if (!this.quotationPriceBridge) {
|
|
225
|
+
const quotation = new _Quotation.QuotationModule(`${this.name}_quotation_price_bridge`);
|
|
226
|
+
await quotation.initialize(this.core, {});
|
|
227
|
+
this.quotationPriceBridge = quotation;
|
|
228
|
+
}
|
|
229
|
+
if (params.scheduleModule) {
|
|
230
|
+
if (this.quotationScheduleCacheSource !== params.scheduleModule) {
|
|
231
|
+
this.quotationScheduleCache.clear();
|
|
232
|
+
this.quotationScheduleCacheLoaded = false;
|
|
233
|
+
this.quotationScheduleCacheSource = params.scheduleModule;
|
|
234
|
+
}
|
|
235
|
+
this.quotationPriceBridge.setScheduleResolver(id => {
|
|
236
|
+
const scheduleId = String(id);
|
|
237
|
+
if (this.quotationScheduleCache.has(scheduleId)) {
|
|
238
|
+
return this.quotationScheduleCache.get(scheduleId);
|
|
239
|
+
}
|
|
240
|
+
if (!this.quotationScheduleCacheLoaded) {
|
|
241
|
+
const scheduleList = params.scheduleModule.getScheduleList?.() || [];
|
|
242
|
+
for (const schedule of scheduleList) {
|
|
243
|
+
this.quotationScheduleCache.set(String(schedule.id), schedule);
|
|
244
|
+
}
|
|
245
|
+
this.quotationScheduleCacheLoaded = true;
|
|
246
|
+
}
|
|
247
|
+
if (this.quotationScheduleCache.has(scheduleId)) {
|
|
248
|
+
return this.quotationScheduleCache.get(scheduleId);
|
|
249
|
+
}
|
|
250
|
+
const schedules = params.scheduleModule.getScheduleListByIds?.([id]) || params.scheduleModule.getScheduleByIds?.([id]) || [];
|
|
251
|
+
if (schedules[0]) this.quotationScheduleCache.set(scheduleId, schedules[0]);
|
|
252
|
+
return schedules[0];
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
await this.refreshQuotationPriceBridge({
|
|
256
|
+
customer_id: params.customer_id
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* 刷新桥接器内的报价单列表。
|
|
262
|
+
*/
|
|
263
|
+
async refreshQuotationPriceBridge(params) {
|
|
264
|
+
if (!this.quotationPriceBridge) return;
|
|
265
|
+
const refreshKey = this.getQuotationBridgeScopeKey();
|
|
266
|
+
if (this.quotationBridgeRefreshPromise && this.quotationBridgeRefreshKey === refreshKey) {
|
|
267
|
+
await this.quotationBridgeRefreshPromise;
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (this.quotationBridgeRefreshPromise) {
|
|
271
|
+
await this.quotationBridgeRefreshPromise;
|
|
272
|
+
}
|
|
273
|
+
this.quotationBridgeRefreshKey = refreshKey;
|
|
274
|
+
this.quotationBridgeRefreshPromise = this.quotationPriceBridge.loadQuotations({
|
|
275
|
+
channel: this.quotationBridgeChannel
|
|
276
|
+
}).then(() => {
|
|
277
|
+
this.quotationBridgeLoadedKey = refreshKey;
|
|
278
|
+
}).finally(() => {
|
|
279
|
+
this.quotationBridgeRefreshPromise = undefined;
|
|
280
|
+
this.quotationBridgeRefreshKey = undefined;
|
|
281
|
+
});
|
|
282
|
+
await this.quotationBridgeRefreshPromise;
|
|
283
|
+
}
|
|
284
|
+
async ensureQuotationBridgeReady(customerId) {
|
|
285
|
+
if (!this.quotationPriceBridge) {
|
|
286
|
+
await this.setupQuotationPriceBridge({
|
|
287
|
+
channel: this.otherParams?.channel,
|
|
288
|
+
customer_id: customerId
|
|
289
|
+
});
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (this.quotationBridgeRefreshPromise) {
|
|
293
|
+
await this.quotationBridgeRefreshPromise;
|
|
294
|
+
}
|
|
295
|
+
if (this.getQuotationBridgeScopeKey() !== this.quotationBridgeLoadedKey) {
|
|
296
|
+
await this.refreshQuotationPriceBridge({
|
|
297
|
+
customer_id: customerId
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
getQuotationBridgeScopeKey() {
|
|
302
|
+
return this.quotationBridgeChannel || '';
|
|
303
|
+
}
|
|
304
|
+
getQuotedPrice(params) {
|
|
305
|
+
const quotation = this.quotationPriceBridge;
|
|
306
|
+
if (!quotation) return null;
|
|
307
|
+
const query = {
|
|
308
|
+
productId: params.productId,
|
|
309
|
+
variantId: params.variantId,
|
|
310
|
+
datetime: params.datetime,
|
|
311
|
+
customer_id: params.customerId
|
|
312
|
+
};
|
|
313
|
+
if (typeof quotation.getQuotationMatchForProduct === 'function') {
|
|
314
|
+
return quotation.getQuotationMatchForProduct(query)?.price ?? null;
|
|
315
|
+
}
|
|
316
|
+
if (typeof quotation.getPriceForProduct === 'function') {
|
|
317
|
+
return quotation.getPriceForProduct(query);
|
|
318
|
+
}
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
buildPriceDataFromQuotation(product, datetime, customerId) {
|
|
322
|
+
const quotedPrice = this.getQuotedPrice({
|
|
323
|
+
productId: product.id,
|
|
324
|
+
datetime,
|
|
325
|
+
customerId
|
|
326
|
+
});
|
|
327
|
+
const productPrice = quotedPrice ?? product.price;
|
|
328
|
+
const productBasePrice = quotedPrice ?? product.base_price ?? product.price ?? 0;
|
|
329
|
+
return {
|
|
330
|
+
id: product.id,
|
|
331
|
+
price: String(productPrice ?? 0),
|
|
332
|
+
base_price: String(productBasePrice),
|
|
333
|
+
variant: this.buildVariantPriceData(product, datetime, customerId),
|
|
334
|
+
bundle_group: this.buildBundleGroupPriceData(product, datetime, customerId)
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
buildVariantPriceData(product, datetime, customerId) {
|
|
338
|
+
if (!Array.isArray(product.variant)) return [];
|
|
339
|
+
return product.variant.map(variant => {
|
|
340
|
+
const quotedPrice = this.getQuotedPrice({
|
|
341
|
+
productId: product.id,
|
|
342
|
+
variantId: Number(variant.id),
|
|
343
|
+
datetime,
|
|
344
|
+
customerId
|
|
345
|
+
});
|
|
346
|
+
const price = quotedPrice ?? variant.price ?? product.price ?? 0;
|
|
347
|
+
const basePrice = quotedPrice ?? variant.base_price ?? variant.price ?? product.base_price ?? product.price ?? 0;
|
|
348
|
+
return {
|
|
349
|
+
id: Number(variant.id),
|
|
350
|
+
product_id: Number(variant.product_id ?? product.id),
|
|
351
|
+
base_price: Number(basePrice),
|
|
352
|
+
price: Number(price)
|
|
353
|
+
};
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
buildBundleGroupPriceData(product, datetime, customerId) {
|
|
357
|
+
if (!Array.isArray(product.bundle_group)) return [];
|
|
358
|
+
return product.bundle_group.map(group => ({
|
|
359
|
+
id: Number(group.id),
|
|
360
|
+
bundle_item: (group.bundle_item || []).map(item => {
|
|
361
|
+
const bundleProductId = Number(item.bundle_product_id);
|
|
362
|
+
const bundleVariantId = Number(item.bundle_variant_id || 0);
|
|
363
|
+
const quotedPrice = this.getQuotedPrice({
|
|
364
|
+
productId: bundleProductId,
|
|
365
|
+
variantId: bundleVariantId,
|
|
366
|
+
datetime,
|
|
367
|
+
customerId
|
|
368
|
+
});
|
|
369
|
+
const price = quotedPrice ?? item.price ?? 0;
|
|
370
|
+
const basePrice = quotedPrice ?? item.base_price ?? item.price ?? 0;
|
|
371
|
+
return {
|
|
372
|
+
id: Number(item.id),
|
|
373
|
+
product_id: Number(item.product_id ?? product.id),
|
|
374
|
+
group_id: Number(item.group_id ?? group.id),
|
|
375
|
+
bundle_product_id: bundleProductId,
|
|
376
|
+
bundle_variant_id: bundleVariantId,
|
|
377
|
+
price: Number(price),
|
|
378
|
+
base_price: basePrice,
|
|
379
|
+
price_type: item.price_type,
|
|
380
|
+
price_type_ext: item.price_type_ext
|
|
381
|
+
};
|
|
382
|
+
})
|
|
383
|
+
}));
|
|
384
|
+
}
|
|
385
|
+
|
|
194
386
|
/**
|
|
195
387
|
* 获取应用了价格的商品列表(带缓存)
|
|
196
388
|
* 使用日期作为缓存 key,同一天的商品价格会被缓存
|
|
@@ -199,12 +391,15 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
199
391
|
* @param extraContext 额外的上下文数据(可选,由 Server 层传入)
|
|
200
392
|
* @param options 可选参数
|
|
201
393
|
* @param options.changedIds 变更的商品 IDs,非空时仅对这些商品增量执行 prepare 并更新缓存
|
|
394
|
+
* @param options.productIds 指定商品 IDs,仅对这些商品执行价格计算;不传则处理全量
|
|
202
395
|
* @returns 应用了价格的商品列表
|
|
203
396
|
*/
|
|
204
397
|
async getProductsWithPrice(schedule_date, extraContext, options) {
|
|
205
398
|
const t0 = performance.now();
|
|
206
|
-
const
|
|
207
|
-
const
|
|
399
|
+
const scopedProductIds = this.normalizeProductIds(options?.productIds);
|
|
400
|
+
const cacheKey = this.getProductsPriceCacheKey(schedule_date, extraContext, scopedProductIds);
|
|
401
|
+
const scopedProductIdSet = scopedProductIds ? new Set(scopedProductIds) : undefined;
|
|
402
|
+
const changedIds = scopedProductIdSet ? options?.changedIds?.filter(id => scopedProductIdSet.has(id)) : options?.changedIds;
|
|
208
403
|
if (this.productsPriceCache.has(cacheKey)) {
|
|
209
404
|
const cachedProducts = this.productsPriceCache.get(cacheKey);
|
|
210
405
|
|
|
@@ -274,9 +469,12 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
274
469
|
return cachedProducts;
|
|
275
470
|
}
|
|
276
471
|
this.logInfo('商品价格缓存未命中,准备获取', {
|
|
277
|
-
cacheKey
|
|
472
|
+
cacheKey,
|
|
473
|
+
scopedProductCount: scopedProductIds?.length
|
|
278
474
|
});
|
|
279
|
-
const result = await this.prepareProductsWithPrice(schedule_date, extraContext
|
|
475
|
+
const result = await this.prepareProductsWithPrice(schedule_date, extraContext, scopedProductIds ? {
|
|
476
|
+
productIds: scopedProductIds
|
|
477
|
+
} : undefined);
|
|
280
478
|
this.productsPriceCache.set(cacheKey, result);
|
|
281
479
|
this.logInfo('商品价格已缓存', {
|
|
282
480
|
cacheKey,
|
|
@@ -302,7 +500,7 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
302
500
|
async prepareProductsWithPrice(schedule_date, extraContext, options) {
|
|
303
501
|
const tTotal = performance.now();
|
|
304
502
|
const targetIds = options?.productIds;
|
|
305
|
-
const isIncremental = targetIds
|
|
503
|
+
const isIncremental = Array.isArray(targetIds);
|
|
306
504
|
this.logInfo('prepareProductsWithPrice 开始处理', {
|
|
307
505
|
schedule_date,
|
|
308
506
|
mode: isIncremental ? 'incremental' : 'full',
|
|
@@ -313,8 +511,7 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
313
511
|
let products;
|
|
314
512
|
let ids;
|
|
315
513
|
if (isIncremental) {
|
|
316
|
-
|
|
317
|
-
products = this.getProductsRef().filter(p => idSet.has(p.id));
|
|
514
|
+
products = this.getProductsRefByIds(targetIds);
|
|
318
515
|
ids = products.map(p => p.id);
|
|
319
516
|
} else {
|
|
320
517
|
products = this.getProductsRef();
|
|
@@ -331,22 +528,33 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
331
528
|
productCount: products.length
|
|
332
529
|
});
|
|
333
530
|
|
|
334
|
-
// 2.
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
531
|
+
// 2. 仅在 legacy 报价单 formatter 启用时加载报价单价格;默认由智能定价覆盖商品价格。
|
|
532
|
+
let priceData = [];
|
|
533
|
+
if (this.isLegacyPriceFormatterEnabled) {
|
|
534
|
+
const tPrice = performance.now();
|
|
535
|
+
priceData = await this.loadProductsPrice({
|
|
536
|
+
ids,
|
|
537
|
+
schedule_date,
|
|
538
|
+
schedule_datetime: extraContext?.schedule_datetime,
|
|
539
|
+
customer_id: extraContext?.customer_id
|
|
540
|
+
});
|
|
541
|
+
(0, _product.perfMark)('prepareProducts.loadPrice', performance.now() - tPrice, {
|
|
542
|
+
count: ids.length
|
|
543
|
+
});
|
|
544
|
+
this.logInfo('获取商品报价单价格成功', {
|
|
545
|
+
priceDataCount: priceData?.length ?? 0
|
|
546
|
+
});
|
|
547
|
+
}
|
|
346
548
|
const context = {
|
|
347
549
|
schedule_date,
|
|
550
|
+
schedule_datetime: extraContext?.schedule_datetime,
|
|
551
|
+
customer_id: extraContext?.customer_id,
|
|
348
552
|
priceData,
|
|
349
553
|
locale: this.core?.context?.locale,
|
|
554
|
+
dataVariantEvaluator: extraContext?.dataVariantEvaluator || this.core?.context?.dataVariantEvaluator,
|
|
555
|
+
menuList: extraContext?.menuList || [],
|
|
556
|
+
scheduleList: extraContext?.scheduleList || [],
|
|
557
|
+
strategy_context: extraContext?.strategy_context,
|
|
350
558
|
...extraContext
|
|
351
559
|
};
|
|
352
560
|
|
|
@@ -381,6 +589,53 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
381
589
|
}
|
|
382
590
|
return [];
|
|
383
591
|
}
|
|
592
|
+
getProductsPriceCacheKey(schedule_date, extraContext, productIds) {
|
|
593
|
+
const datetime = extraContext?.schedule_datetime || schedule_date;
|
|
594
|
+
const productScope = productIds ? `:products:${productIds.join(',')}` : '';
|
|
595
|
+
const strategyScope = this.stringifyStable(extraContext?.strategy_context || {});
|
|
596
|
+
return `${datetime}:customer:${extraContext?.customer_id ?? ''}:strategy:${strategyScope}${productScope}`;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* 稳定序列化策略上下文,避免对象 key 顺序不同导致缓存 key 抖动。
|
|
601
|
+
*/
|
|
602
|
+
stringifyStable(value) {
|
|
603
|
+
if (value == null) return '';
|
|
604
|
+
if (Array.isArray(value)) return `[${value.map(item => this.stringifyStable(item)).join(',')}]`;
|
|
605
|
+
if (typeof value === 'object') {
|
|
606
|
+
return `{${Object.keys(value).sort().map(key => `${key}:${this.stringifyStable(value[key])}`).join(',')}}`;
|
|
607
|
+
}
|
|
608
|
+
return String(value);
|
|
609
|
+
}
|
|
610
|
+
normalizeProductIds(productIds) {
|
|
611
|
+
if (!Array.isArray(productIds)) return undefined;
|
|
612
|
+
return Array.from(new Set(productIds.map(id => Number(id)).filter(id => Number.isFinite(id)))).sort((a, b) => a - b);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* 按轻量范围返回商品 ID,不做 structuredClone。
|
|
617
|
+
*/
|
|
618
|
+
getProductIdsByScope(scope) {
|
|
619
|
+
const productIds = this.normalizeProductIds(scope.productIds) || [];
|
|
620
|
+
const collectionIds = this.normalizeProductIds(scope.collectionIds) || [];
|
|
621
|
+
if (scope.isAllProducts) {
|
|
622
|
+
return this.getProductsRef().map(product => product.id);
|
|
623
|
+
}
|
|
624
|
+
if (productIds.length === 0 && collectionIds.length === 0) return [];
|
|
625
|
+
const result = new Set();
|
|
626
|
+
for (const id of productIds) {
|
|
627
|
+
if (this.store.map.has(id)) result.add(id);
|
|
628
|
+
}
|
|
629
|
+
if (collectionIds.length === 0) return Array.from(result);
|
|
630
|
+
const collectionIdSet = new Set(collectionIds);
|
|
631
|
+
for (const product of this.getProductsRef()) {
|
|
632
|
+
if (result.has(product.id)) continue;
|
|
633
|
+
if (!Array.isArray(product.collection)) continue;
|
|
634
|
+
const isInCollection = product.collection.some(collection => collectionIdSet.has(collection.id));
|
|
635
|
+
if (isInCollection) result.add(product.id);
|
|
636
|
+
}
|
|
637
|
+
return Array.from(result);
|
|
638
|
+
}
|
|
384
639
|
|
|
385
640
|
/**
|
|
386
641
|
* 应用所有已注册的格式化器
|
|
@@ -430,18 +685,46 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
430
685
|
}
|
|
431
686
|
|
|
432
687
|
/**
|
|
433
|
-
*
|
|
434
|
-
*
|
|
688
|
+
* 注册内置商品格式化器。
|
|
689
|
+
*
|
|
690
|
+
* 智能定价默认替代报价单逻辑;报价单 formatter 仅在 enableLegacyPriceFormatter=true 时启用。
|
|
435
691
|
* @private
|
|
436
692
|
*/
|
|
437
|
-
|
|
438
|
-
if (this.
|
|
439
|
-
console.warn('[ProductsModule]
|
|
693
|
+
registerBuiltinProductFormatters() {
|
|
694
|
+
if (this.isBuiltinFormatterRegistered) {
|
|
695
|
+
console.warn('[ProductsModule] 内置商品格式化器已注册,跳过');
|
|
440
696
|
return;
|
|
441
697
|
}
|
|
698
|
+
this.isLegacyPriceFormatterEnabled = this.shouldEnableLegacyPriceFormatter();
|
|
699
|
+
const dataVariantFormatter = (products, context) => {
|
|
700
|
+
const evaluator = context.dataVariantEvaluator || this.core?.context?.dataVariantEvaluator;
|
|
701
|
+
if (!evaluator || typeof evaluator.resolveProducts !== 'function') {
|
|
702
|
+
this.lastScheduleTimePoints = [];
|
|
703
|
+
this.logWarning('智能定价评估器未注入,跳过 DataVariant 格式化', {
|
|
704
|
+
productCount: products.length
|
|
705
|
+
});
|
|
706
|
+
return products;
|
|
707
|
+
}
|
|
708
|
+
const strategyContext = context.strategy_context || {};
|
|
709
|
+
const businessData = {
|
|
710
|
+
products,
|
|
711
|
+
scheduleDateTime: context.schedule_datetime || context.schedule_date,
|
|
712
|
+
scheduleList: context.scheduleList || [],
|
|
713
|
+
menuList: context.menuList || [],
|
|
714
|
+
customerId: context.customer_id,
|
|
715
|
+
channel: strategyContext.channel,
|
|
716
|
+
orderType: strategyContext.orderType || strategyContext.order_type,
|
|
717
|
+
businessCode: strategyContext.business_code ?? strategyContext.businessCode,
|
|
718
|
+
availableWalletIds: strategyContext.available_wallet_ids,
|
|
719
|
+
custom: strategyContext
|
|
720
|
+
};
|
|
721
|
+
const result = evaluator.resolveProducts(businessData);
|
|
722
|
+
this.lastScheduleTimePoints = Array.isArray(result?.scheduleTimePoints) ? [...result.scheduleTimePoints] : [];
|
|
723
|
+
return Array.isArray(result?.products) ? result.products : products;
|
|
724
|
+
};
|
|
442
725
|
|
|
443
|
-
//
|
|
444
|
-
const
|
|
726
|
+
// 创建 legacy 报价单格式化器
|
|
727
|
+
const legacyPriceFormatter = (products, context) => {
|
|
445
728
|
if (!context.priceData || context.priceData.length === 0) {
|
|
446
729
|
return products;
|
|
447
730
|
}
|
|
@@ -453,17 +736,35 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
453
736
|
const detailValueFormatter = (products, context) => {
|
|
454
737
|
return (0, _product.applyDetailValueToProducts)(products, context);
|
|
455
738
|
};
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
739
|
+
if (this.isLegacyPriceFormatterEnabled) {
|
|
740
|
+
this.formatters.push(legacyPriceFormatter);
|
|
741
|
+
}
|
|
742
|
+
this.formatters.push(dataVariantFormatter);
|
|
459
743
|
this.formatters.push(i18nFormatter);
|
|
460
744
|
this.formatters.push(detailValueFormatter);
|
|
461
|
-
this.
|
|
745
|
+
this.isBuiltinFormatterRegistered = true;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* 是否启用旧报价单价格 formatter。
|
|
750
|
+
*
|
|
751
|
+
* 默认关闭,避免报价单逻辑覆盖智能定价结果。
|
|
752
|
+
*/
|
|
753
|
+
shouldEnableLegacyPriceFormatter() {
|
|
754
|
+
return this.otherParams?.enableLegacyPriceFormatter === true || this.core?.context?.enableLegacyPriceFormatter === true;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* 返回最近一次 prepareProductsWithPrice / DataVariant 评估提取的变价时间点(HH:mm)。
|
|
759
|
+
* 供 OS Server 商品 query 订阅定时刷新使用。
|
|
760
|
+
*/
|
|
761
|
+
getLastScheduleTimePoints() {
|
|
762
|
+
return [...this.lastScheduleTimePoints];
|
|
462
763
|
}
|
|
463
764
|
|
|
464
765
|
/**
|
|
465
766
|
* 注册商品格式化器
|
|
466
|
-
*
|
|
767
|
+
* 格式化器会按注册顺序依次执行;legacy 启用时先兜底报价,再由智能定价覆盖。
|
|
467
768
|
* @param formatter 格式化函数
|
|
468
769
|
* @param prepend 是否插入到队列开头(默认 false,追加到末尾)
|
|
469
770
|
* @example
|
|
@@ -478,8 +779,8 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
478
779
|
*/
|
|
479
780
|
registerFormatter(formatter, prepend = false) {
|
|
480
781
|
if (prepend) {
|
|
481
|
-
//
|
|
482
|
-
const insertIndex = this.
|
|
782
|
+
// 插入到内置智能定价格式化器之后;legacy 报价单启用时需跳过它。
|
|
783
|
+
const insertIndex = this.isBuiltinFormatterRegistered ? this.isLegacyPriceFormatterEnabled ? 2 : 1 : 0;
|
|
483
784
|
this.formatters.splice(insertIndex, 0, formatter);
|
|
484
785
|
} else {
|
|
485
786
|
// 追加到末尾
|
|
@@ -488,16 +789,17 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
488
789
|
}
|
|
489
790
|
|
|
490
791
|
/**
|
|
491
|
-
*
|
|
492
|
-
* @param keepBuiltin
|
|
792
|
+
* 清空所有格式化器(包括内置智能定价格式化器)
|
|
793
|
+
* @param keepBuiltin 是否保留内置智能定价格式化器(默认 true)
|
|
493
794
|
*/
|
|
494
795
|
clearFormatters(keepBuiltin = true) {
|
|
495
|
-
if (keepBuiltin && this.
|
|
496
|
-
//
|
|
497
|
-
|
|
796
|
+
if (keepBuiltin && this.isBuiltinFormatterRegistered) {
|
|
797
|
+
// 保留 legacy 兜底(如果启用)和智能定价格式化器。
|
|
798
|
+
const builtinCount = this.isLegacyPriceFormatterEnabled ? 2 : 1;
|
|
799
|
+
this.formatters = this.formatters.slice(0, builtinCount);
|
|
498
800
|
} else {
|
|
499
801
|
this.formatters = [];
|
|
500
|
-
this.
|
|
802
|
+
this.isBuiltinFormatterRegistered = false;
|
|
501
803
|
}
|
|
502
804
|
}
|
|
503
805
|
|
|
@@ -545,7 +847,8 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
545
847
|
productCount: list.length,
|
|
546
848
|
duration: `${Math.round(performance.now() - t0)}ms`
|
|
547
849
|
});
|
|
548
|
-
await this.
|
|
850
|
+
await this.replaceProductsSnapshotInIndexDB(list, 'loadProductsByServer');
|
|
851
|
+
this.lastServerFullFetchAtMs = Date.now();
|
|
549
852
|
await this.core.effects.emit(_types.ProductsHooks.onProductsLoaded, list);
|
|
550
853
|
(0, _product.perfMark)('loadProductsByServer', performance.now() - t0, {
|
|
551
854
|
count: list.length
|
|
@@ -588,7 +891,7 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
588
891
|
open_bundle: 1,
|
|
589
892
|
exclude_extension_type: ['product_party', 'product_event', 'product_series_event', 'product_package_ticket', 'ticket', 'event_item'],
|
|
590
893
|
force_ignore_cache_flag: 1,
|
|
591
|
-
with: ['category', 'collection', 'resourceRelation', 'bundleGroup.bundleItem', 'optionGroup.optionItem', 'variantGroup.variantItem'],
|
|
894
|
+
with: ['category', 'collection', 'resourceRelation', 'bundleGroup.bundleItem', 'optionGroup.optionItem', 'variantGroup.variantItem', 'dataVariants'],
|
|
592
895
|
open_deposit: 1,
|
|
593
896
|
is_append_product_description: 1,
|
|
594
897
|
with_count: ['bundleGroup', 'optionGroup'],
|
|
@@ -631,7 +934,8 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
631
934
|
async loadProductsByServerHttp(params) {
|
|
632
935
|
const productList = await this.fetchProductsByHttp(params);
|
|
633
936
|
if (productList.length > 0) {
|
|
634
|
-
await this.
|
|
937
|
+
await this.replaceProductsSnapshotInIndexDB(productList, 'loadProductsByServerHttp');
|
|
938
|
+
this.lastServerFullFetchAtMs = Date.now();
|
|
635
939
|
await this.core.effects.emit(_types.ProductsHooks.onProductsLoaded, productList);
|
|
636
940
|
}
|
|
637
941
|
return productList;
|
|
@@ -649,6 +953,25 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
649
953
|
return result;
|
|
650
954
|
}
|
|
651
955
|
|
|
956
|
+
/**
|
|
957
|
+
* 批量获取商品轻量快照,供订单详情等响应补齐展示协议字段。
|
|
958
|
+
*/
|
|
959
|
+
async getProductSnapshotsByIds(ids) {
|
|
960
|
+
const snapshots = {};
|
|
961
|
+
const seen = new Set();
|
|
962
|
+
for (const id of ids) {
|
|
963
|
+
if (!Number.isFinite(id) || seen.has(id)) continue;
|
|
964
|
+
seen.add(id);
|
|
965
|
+
const product = this.store.map.get(id);
|
|
966
|
+
if (!product) continue;
|
|
967
|
+
snapshots[String(id)] = {
|
|
968
|
+
cover: product.cover,
|
|
969
|
+
holder_config: product.holder_config
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
return snapshots;
|
|
973
|
+
}
|
|
974
|
+
|
|
652
975
|
/**
|
|
653
976
|
* 内部获取商品列表的直接引用(无拷贝)
|
|
654
977
|
* 仅供内部 formatter 流程使用,因为 formatter 会创建新对象
|
|
@@ -657,6 +980,18 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
657
980
|
return this.store.list;
|
|
658
981
|
}
|
|
659
982
|
|
|
983
|
+
/**
|
|
984
|
+
* 按 ID 从 Map 取商品引用,供内部 formatter 流程使用。
|
|
985
|
+
*/
|
|
986
|
+
getProductsRefByIds(ids) {
|
|
987
|
+
const products = [];
|
|
988
|
+
for (const id of ids) {
|
|
989
|
+
const product = this.store.map.get(id);
|
|
990
|
+
if (product) products.push(product);
|
|
991
|
+
}
|
|
992
|
+
return products;
|
|
993
|
+
}
|
|
994
|
+
|
|
660
995
|
/**
|
|
661
996
|
* 根据ID获取单个商品(从内存缓存)
|
|
662
997
|
* 使用 Map 快速查询,时间复杂度 O(1)
|
|
@@ -784,37 +1119,105 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
784
1119
|
}
|
|
785
1120
|
|
|
786
1121
|
/**
|
|
787
|
-
*
|
|
788
|
-
*
|
|
1122
|
+
* 串行执行商品 IndexDB 写入,避免快照替换与增量 patch 并发交错。
|
|
1123
|
+
*
|
|
1124
|
+
* @example
|
|
1125
|
+
* await this.runInProductIndexDBSaveQueue(async () => {
|
|
1126
|
+
* await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, products)
|
|
1127
|
+
* })
|
|
789
1128
|
*/
|
|
790
|
-
async
|
|
1129
|
+
async runInProductIndexDBSaveQueue(task) {
|
|
1130
|
+
const queuedTask = this.productIndexDBSaveQueue.then(task, task);
|
|
1131
|
+
this.productIndexDBSaveQueue = queuedTask.then(() => undefined, () => undefined);
|
|
1132
|
+
return queuedTask;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/**
|
|
1136
|
+
* 全量快照写入 IndexDB:clear + bulkUpdate,仅用于 SSE/HTTP 全量拉取。
|
|
1137
|
+
*
|
|
1138
|
+
* @example
|
|
1139
|
+
* await this.replaceProductsSnapshotInIndexDB(list, 'loadProductsByServer')
|
|
1140
|
+
*/
|
|
1141
|
+
async replaceProductsSnapshotInIndexDB(products, source) {
|
|
791
1142
|
if (!this.dbManager) {
|
|
792
|
-
this.logWarning('
|
|
1143
|
+
this.logWarning('replaceProductsSnapshotInIndexDB: dbManager 不可用');
|
|
793
1144
|
return;
|
|
794
1145
|
}
|
|
795
|
-
this.logInfo('开始保存商品数据到 IndexDB', {
|
|
796
|
-
productCount: products.length
|
|
797
|
-
});
|
|
798
1146
|
try {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1147
|
+
await this.runInProductIndexDBSaveQueue(async () => {
|
|
1148
|
+
this.logInfo('replaceProductsSnapshotInIndexDB 开始', {
|
|
1149
|
+
source,
|
|
1150
|
+
productCount: products.length
|
|
1151
|
+
});
|
|
1152
|
+
const t0 = performance.now();
|
|
1153
|
+
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
1154
|
+
if (products.length > 0) {
|
|
1155
|
+
await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, products);
|
|
1156
|
+
}
|
|
1157
|
+
(0, _product.perfMark)('replaceProductsSnapshotInIndexDB', performance.now() - t0, {
|
|
1158
|
+
count: products.length
|
|
1159
|
+
});
|
|
1160
|
+
this.logInfo('replaceProductsSnapshotInIndexDB 完成', {
|
|
1161
|
+
source,
|
|
1162
|
+
productCount: products.length
|
|
1163
|
+
});
|
|
807
1164
|
});
|
|
808
1165
|
} catch (error) {
|
|
809
1166
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
810
|
-
|
|
811
|
-
|
|
1167
|
+
this.logError('全量保存商品到 IndexDB 失败', {
|
|
1168
|
+
source,
|
|
812
1169
|
productCount: products.length,
|
|
813
1170
|
error: errorMessage
|
|
814
1171
|
});
|
|
815
1172
|
}
|
|
816
1173
|
}
|
|
817
1174
|
|
|
1175
|
+
/**
|
|
1176
|
+
* 增量 upsert 商品到 IndexDB,不清空表;用于 pubsub 批次合并后的变更商品。
|
|
1177
|
+
*
|
|
1178
|
+
* @example
|
|
1179
|
+
* await this.patchProductsInIndexDB(changedProducts, 'pubsub.processProductSyncMessages', mergeActions)
|
|
1180
|
+
*/
|
|
1181
|
+
async patchProductsInIndexDB(products, source, mergeActions = {}) {
|
|
1182
|
+
if (!this.dbManager || products.length === 0) {
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
const validProducts = products.filter(p => p?.id !== undefined && p?.id !== null);
|
|
1186
|
+
if (validProducts.length === 0) {
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
try {
|
|
1190
|
+
await this.runInProductIndexDBSaveQueue(async () => {
|
|
1191
|
+
this.logInfo('patchProductsInIndexDB 开始', {
|
|
1192
|
+
source,
|
|
1193
|
+
count: validProducts.length
|
|
1194
|
+
});
|
|
1195
|
+
const t0 = performance.now();
|
|
1196
|
+
if (typeof this.dbManager.bulkUpdate === 'function') {
|
|
1197
|
+
await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, validProducts);
|
|
1198
|
+
} else if (typeof this.dbManager.update === 'function') {
|
|
1199
|
+
for (const product of validProducts) {
|
|
1200
|
+
await this.dbManager.update(INDEXDB_STORE_NAME, product);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
(0, _product.perfMark)('patchProductsInIndexDB', performance.now() - t0, {
|
|
1204
|
+
count: validProducts.length
|
|
1205
|
+
});
|
|
1206
|
+
this.logInfo('patchProductsInIndexDB 完成', {
|
|
1207
|
+
source,
|
|
1208
|
+
count: validProducts.length
|
|
1209
|
+
});
|
|
1210
|
+
});
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1213
|
+
this.logError('增量保存商品到 IndexDB 失败', {
|
|
1214
|
+
source,
|
|
1215
|
+
error: errorMessage,
|
|
1216
|
+
productCount: validProducts.length
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
|
|
818
1221
|
/**
|
|
819
1222
|
* 同步更新商品 Map 缓存
|
|
820
1223
|
* 将 list 中的商品同步到 map,以 id 为 key
|
|
@@ -862,6 +1265,7 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
862
1265
|
duration: `${Math.round(performance.now() - tTotal)}ms`,
|
|
863
1266
|
source: 'IndexDB'
|
|
864
1267
|
});
|
|
1268
|
+
this.lastPreloadCompletedAtMs = Date.now();
|
|
865
1269
|
return;
|
|
866
1270
|
}
|
|
867
1271
|
this.logInfo('IndexDB 中没有缓存数据,准备从服务器加载');
|
|
@@ -895,6 +1299,7 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
895
1299
|
duration: `${Math.round(performance.now() - tTotal)}ms`,
|
|
896
1300
|
source: 'Server'
|
|
897
1301
|
});
|
|
1302
|
+
this.lastPreloadCompletedAtMs = Date.now();
|
|
898
1303
|
} else {
|
|
899
1304
|
(0, _product.perfMark)('preload(empty)', performance.now() - tTotal, {
|
|
900
1305
|
source: 'empty'
|
|
@@ -956,9 +1361,10 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
956
1361
|
this.productDataSource.run({
|
|
957
1362
|
pubsub: {
|
|
958
1363
|
callback: res => {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1364
|
+
// console.log('sse_products_callback', res)
|
|
1365
|
+
// this.logInfo('sse_products_callback: 收到同步消息', {
|
|
1366
|
+
// data: res?.data,
|
|
1367
|
+
// });
|
|
962
1368
|
if (!res?.data) return;
|
|
963
1369
|
const data = res.data;
|
|
964
1370
|
const channelKey = data.module || 'product';
|
|
@@ -1049,6 +1455,10 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
1049
1455
|
if (msg.relation_product_ids?.length) {
|
|
1050
1456
|
sseRefreshIds.push(...msg.relation_product_ids);
|
|
1051
1457
|
}
|
|
1458
|
+
} else if (['product_data_variant'].includes(channelKey)) {
|
|
1459
|
+
if (msg.product_ids?.length) {
|
|
1460
|
+
sseRefreshIds.push(...msg.product_ids);
|
|
1461
|
+
}
|
|
1052
1462
|
}
|
|
1053
1463
|
}
|
|
1054
1464
|
const uniqueDeleteIds = [...new Set(deleteIds)];
|
|
@@ -1060,22 +1470,51 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
1060
1470
|
await this.removeProductsByIds(uniqueDeleteIds);
|
|
1061
1471
|
}
|
|
1062
1472
|
|
|
1063
|
-
|
|
1473
|
+
/** 本批次待 patch 的商品(按 id 去重,SSE 覆盖 body) */
|
|
1474
|
+
const patchProductMap = new Map();
|
|
1475
|
+
const patchMergeActions = {};
|
|
1476
|
+
let storeMutated = uniqueDeleteIds.length > 0;
|
|
1477
|
+
|
|
1478
|
+
// 2. 处理 body 直接覆盖(仅内存,IndexDB 批次末统一 patch)
|
|
1064
1479
|
if (bodyUpdates.size > 0) {
|
|
1065
|
-
await this.applyBodyUpdatesToStore(bodyUpdates
|
|
1480
|
+
const bodyResult = await this.applyBodyUpdatesToStore(bodyUpdates, {
|
|
1481
|
+
skipIndexDB: true,
|
|
1482
|
+
skipEmit: true
|
|
1483
|
+
});
|
|
1484
|
+
for (const product of bodyResult.changedProducts) {
|
|
1485
|
+
patchProductMap.set(product.id, product);
|
|
1486
|
+
patchMergeActions[product.id] = bodyResult.mergeActions[product.id];
|
|
1487
|
+
}
|
|
1488
|
+
storeMutated = true;
|
|
1066
1489
|
}
|
|
1067
1490
|
|
|
1068
|
-
// 3. 处理 SSE
|
|
1491
|
+
// 3. 处理 SSE 增量拉取(仅内存,IndexDB 批次末统一 patch)
|
|
1492
|
+
let freshProducts = [];
|
|
1069
1493
|
if (uniqueSSEIds.length > 0) {
|
|
1070
|
-
|
|
1494
|
+
freshProducts = await this.fetchProductsBySSE(uniqueSSEIds);
|
|
1071
1495
|
if (freshProducts.length > 0) {
|
|
1072
|
-
await this.mergeProductsToStore(freshProducts
|
|
1496
|
+
const mergeResult = await this.mergeProductsToStore(freshProducts, {
|
|
1497
|
+
skipIndexDB: true,
|
|
1498
|
+
skipEmit: true
|
|
1499
|
+
});
|
|
1500
|
+
for (const product of mergeResult.changedProducts) {
|
|
1501
|
+
patchProductMap.set(product.id, product);
|
|
1502
|
+
patchMergeActions[product.id] = mergeResult.mergeActions[product.id];
|
|
1503
|
+
}
|
|
1504
|
+
storeMutated = true;
|
|
1073
1505
|
}
|
|
1074
1506
|
this.logInfo('processProductSyncMessages: SSE 增量更新完成123', {
|
|
1075
1507
|
requestedCount: uniqueSSEIds.length,
|
|
1076
1508
|
receivedCount: freshProducts.length
|
|
1077
1509
|
});
|
|
1078
1510
|
}
|
|
1511
|
+
const patchProducts = [...patchProductMap.values()];
|
|
1512
|
+
if (patchProducts.length > 0) {
|
|
1513
|
+
await this.patchProductsInIndexDB(patchProducts, 'pubsub.processProductSyncMessages', patchMergeActions);
|
|
1514
|
+
}
|
|
1515
|
+
if (storeMutated) {
|
|
1516
|
+
this.core.effects.emit(_types.ProductsHooks.onProductsChanged, this.store.list);
|
|
1517
|
+
}
|
|
1079
1518
|
|
|
1080
1519
|
// 收集所有非 delete 的变更 IDs(body + SSE + price),用于增量更新价格缓存
|
|
1081
1520
|
const allChangedIds = [...new Set([...Array.from(bodyUpdates.keys()), ...uniqueSSEIds, ...uniquePriceIds])];
|
|
@@ -1095,6 +1534,14 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
1095
1534
|
|
|
1096
1535
|
// 报价单变更 → 清除全量价格缓存,后续走全量重建
|
|
1097
1536
|
if (shouldClearPriceCache) {
|
|
1537
|
+
try {
|
|
1538
|
+
await this.refreshQuotationPriceBridge();
|
|
1539
|
+
} catch (error) {
|
|
1540
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1541
|
+
this.logError('报价单桥接刷新失败,将继续清理价格缓存', {
|
|
1542
|
+
error: errorMessage
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1098
1545
|
this.clearPriceCache();
|
|
1099
1546
|
}
|
|
1100
1547
|
await this.core.effects.emit(_types.ProductsHooks.onProductsSyncCompleted, {
|
|
@@ -1148,21 +1595,28 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
1148
1595
|
/**
|
|
1149
1596
|
* 将 body 完整数据直接覆盖到本地 store(不调用报价单接口)
|
|
1150
1597
|
* 已存在的 → 直接替换;不存在的 → 追加
|
|
1151
|
-
*
|
|
1152
|
-
*
|
|
1598
|
+
*
|
|
1599
|
+
* @example
|
|
1600
|
+
* await this.applyBodyUpdatesToStore(bodyUpdates, { skipIndexDB: true })
|
|
1153
1601
|
*/
|
|
1154
|
-
async applyBodyUpdatesToStore(bodyUpdates) {
|
|
1602
|
+
async applyBodyUpdatesToStore(bodyUpdates, options) {
|
|
1603
|
+
const changedProductIds = [...bodyUpdates.keys()];
|
|
1155
1604
|
this.logInfo('applyBodyUpdatesToStore: 开始', {
|
|
1156
1605
|
count: bodyUpdates.size
|
|
1157
1606
|
});
|
|
1158
1607
|
let updatedCount = 0;
|
|
1159
1608
|
let newCount = 0;
|
|
1160
1609
|
const appliedIds = new Set();
|
|
1610
|
+
const mergeActions = {};
|
|
1611
|
+
const changedProducts = [];
|
|
1161
1612
|
this.store.list = this.store.list.map(p => {
|
|
1162
1613
|
if (bodyUpdates.has(p.id)) {
|
|
1163
1614
|
updatedCount++;
|
|
1164
1615
|
appliedIds.add(p.id);
|
|
1165
|
-
|
|
1616
|
+
mergeActions[p.id] = 'update';
|
|
1617
|
+
const next = bodyUpdates.get(p.id);
|
|
1618
|
+
changedProducts.push(next);
|
|
1619
|
+
return next;
|
|
1166
1620
|
}
|
|
1167
1621
|
return p;
|
|
1168
1622
|
});
|
|
@@ -1170,32 +1624,50 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
1170
1624
|
if (!appliedIds.has(id)) {
|
|
1171
1625
|
this.store.list.push(body);
|
|
1172
1626
|
newCount++;
|
|
1627
|
+
mergeActions[id] = 'insert';
|
|
1628
|
+
changedProducts.push(body);
|
|
1173
1629
|
}
|
|
1174
1630
|
}
|
|
1175
1631
|
this.syncProductsMap();
|
|
1176
|
-
|
|
1177
|
-
|
|
1632
|
+
if (!options?.skipIndexDB) {
|
|
1633
|
+
await this.patchProductsInIndexDB(changedProducts, 'pubsub.bodyUpdate', mergeActions);
|
|
1634
|
+
}
|
|
1635
|
+
if (!options?.skipEmit) {
|
|
1636
|
+
this.core.effects.emit(_types.ProductsHooks.onProductsChanged, this.store.list);
|
|
1637
|
+
}
|
|
1178
1638
|
this.logInfo('applyBodyUpdatesToStore: 完成', {
|
|
1179
1639
|
updatedCount,
|
|
1180
1640
|
newCount,
|
|
1181
1641
|
totalCount: this.store.list.length
|
|
1182
1642
|
});
|
|
1643
|
+
return {
|
|
1644
|
+
changedProducts,
|
|
1645
|
+
mergeActions,
|
|
1646
|
+
updatedCount,
|
|
1647
|
+
newCount
|
|
1648
|
+
};
|
|
1183
1649
|
}
|
|
1184
1650
|
|
|
1185
1651
|
/**
|
|
1186
1652
|
* 将增量拉取的商品合并到 store
|
|
1187
1653
|
* 已存在的 → 替换;新的 → 追加
|
|
1188
|
-
*
|
|
1654
|
+
*
|
|
1655
|
+
* @example
|
|
1656
|
+
* await this.mergeProductsToStore(freshProducts, { skipIndexDB: true })
|
|
1189
1657
|
*/
|
|
1190
|
-
async mergeProductsToStore(freshProducts) {
|
|
1658
|
+
async mergeProductsToStore(freshProducts, options) {
|
|
1191
1659
|
const freshMap = new Map();
|
|
1192
1660
|
for (const p of freshProducts) {
|
|
1193
1661
|
freshMap.set(p.id, p);
|
|
1194
1662
|
}
|
|
1663
|
+
const mergeActions = {};
|
|
1664
|
+
const changedProducts = [];
|
|
1195
1665
|
const updatedList = this.store.list.map(p => {
|
|
1196
1666
|
if (freshMap.has(p.id)) {
|
|
1197
1667
|
const fresh = freshMap.get(p.id);
|
|
1198
1668
|
freshMap.delete(p.id);
|
|
1669
|
+
mergeActions[p.id] = 'update';
|
|
1670
|
+
changedProducts.push(fresh);
|
|
1199
1671
|
return fresh;
|
|
1200
1672
|
}
|
|
1201
1673
|
return p;
|
|
@@ -1205,17 +1677,30 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
1205
1677
|
const newCount = freshMap.size;
|
|
1206
1678
|
for (const p of freshMap.values()) {
|
|
1207
1679
|
updatedList.push(p);
|
|
1680
|
+
mergeActions[p.id] = 'insert';
|
|
1681
|
+
changedProducts.push(p);
|
|
1208
1682
|
}
|
|
1209
1683
|
const updatedCount = freshProducts.length - newCount;
|
|
1684
|
+
const changedProductIds = freshProducts.map(p => p.id);
|
|
1210
1685
|
this.store.list = updatedList;
|
|
1211
1686
|
this.syncProductsMap();
|
|
1212
|
-
|
|
1687
|
+
if (!options?.skipIndexDB) {
|
|
1688
|
+
await this.patchProductsInIndexDB(changedProducts, 'pubsub.mergeProductsToStore', mergeActions);
|
|
1689
|
+
}
|
|
1690
|
+
if (!options?.skipEmit) {
|
|
1691
|
+
this.core.effects.emit(_types.ProductsHooks.onProductsChanged, this.store.list);
|
|
1692
|
+
}
|
|
1213
1693
|
this.logInfo('mergeProductsToStore: 合并完成', {
|
|
1214
1694
|
updatedCount,
|
|
1215
1695
|
newCount,
|
|
1216
1696
|
totalCount: this.store.list.length
|
|
1217
1697
|
});
|
|
1218
|
-
|
|
1698
|
+
return {
|
|
1699
|
+
changedProducts,
|
|
1700
|
+
mergeActions,
|
|
1701
|
+
updatedCount,
|
|
1702
|
+
newCount
|
|
1703
|
+
};
|
|
1219
1704
|
}
|
|
1220
1705
|
|
|
1221
1706
|
/**
|
|
@@ -1225,6 +1710,12 @@ class ProductsModule extends _BaseModule.BaseModule {
|
|
|
1225
1710
|
*/
|
|
1226
1711
|
async silentRefresh() {
|
|
1227
1712
|
const t0 = performance.now();
|
|
1713
|
+
const now = Date.now();
|
|
1714
|
+
const elapsedSincePreload = now - this.lastPreloadCompletedAtMs;
|
|
1715
|
+
const elapsedSinceFullFetch = now - this.lastServerFullFetchAtMs;
|
|
1716
|
+
if (this.lastPreloadCompletedAtMs > 0 && elapsedSincePreload < PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS || this.lastServerFullFetchAtMs > 0 && elapsedSinceFullFetch < PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS) {
|
|
1717
|
+
return this.store.list;
|
|
1718
|
+
}
|
|
1228
1719
|
this.logInfo('silentRefresh 开始');
|
|
1229
1720
|
try {
|
|
1230
1721
|
const products = await this.loadProductsByServer();
|