@pisell/pisellos 2.2.310 → 2.2.312-vm.0
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/apis/picoding.d.ts.map +1 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/effects/index.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/inventory/index.d.ts +92 -0
- package/dist/inventory/index.d.ts.map +1 -0
- package/dist/inventory/index.js +509 -0
- package/dist/model/index.d.ts.map +1 -0
- package/dist/model/strategy/adapter/dataVariant/adapter.d.ts.map +1 -0
- package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts.map +1 -0
- package/dist/model/strategy/adapter/dataVariant/examples.d.ts.map +1 -0
- package/dist/model/strategy/adapter/dataVariant/index.d.ts.map +1 -0
- package/dist/model/strategy/adapter/dataVariant/type.d.ts.map +1 -0
- package/dist/model/strategy/adapter/index.d.ts.map +1 -0
- package/dist/model/strategy/adapter/itemRule/adapter.d.ts.map +1 -0
- package/dist/model/strategy/adapter/itemRule/evaluator.d.ts.map +1 -0
- package/dist/model/strategy/adapter/itemRule/examples.d.ts.map +1 -0
- package/dist/model/strategy/adapter/itemRule/index.d.ts.map +1 -0
- package/dist/model/strategy/adapter/itemRule/type.d.ts.map +1 -0
- package/dist/model/strategy/adapter/promotion/adapter.d.ts.map +1 -0
- package/dist/model/strategy/adapter/promotion/evaluator.d.ts.map +1 -0
- package/dist/model/strategy/adapter/promotion/examples.d.ts.map +1 -0
- package/dist/model/strategy/adapter/promotion/index.d.ts.map +1 -0
- package/dist/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/model/strategy/adapter/promotion/type.d.ts.map +1 -0
- package/dist/model/strategy/adapter/type.d.ts.map +1 -0
- package/dist/model/strategy/adapter/walletPass/evaluator.d.ts.map +1 -0
- package/dist/model/strategy/adapter/walletPass/example.d.ts.map +1 -0
- package/dist/model/strategy/adapter/walletPass/index.d.ts.map +1 -0
- package/dist/model/strategy/adapter/walletPass/locales.d.ts.map +1 -0
- package/dist/model/strategy/adapter/walletPass/type.d.ts.map +1 -0
- package/dist/model/strategy/adapter/walletPass/utils.d.ts.map +1 -0
- package/dist/model/strategy/engine.d.ts.map +1 -0
- package/dist/model/strategy/index.d.ts.map +1 -0
- package/dist/model/strategy/strategy-example.d.ts.map +1 -0
- package/dist/model/strategy/type.d.ts.map +1 -0
- package/dist/modules/Account/index.d.ts.map +1 -0
- package/dist/modules/Account/types.d.ts.map +1 -0
- package/dist/modules/AccountList/index.d.ts.map +1 -0
- package/dist/modules/AccountList/types.d.ts.map +1 -0
- package/dist/modules/AccountList/utils.d.ts.map +1 -0
- package/dist/modules/BaseModule.d.ts.map +1 -0
- package/dist/modules/BookingContext/index.d.ts.map +1 -0
- package/dist/modules/BookingContext/types.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/flexible.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/formatResourceList.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/index.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/noResource.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/orderLineDisplay.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/productExtend.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/resourceErrors.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/resourceSelection.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/resources.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/serviceTimes.d.ts.map +1 -0
- package/dist/modules/BookingContext/utils/timeSlices.d.ts.map +1 -0
- package/dist/modules/Cart/index.d.ts.map +1 -0
- package/dist/modules/Cart/types.d.ts.map +1 -0
- package/dist/modules/Cart/utils/cartAccount.d.ts.map +1 -0
- package/dist/modules/Cart/utils/cartDate.d.ts.map +1 -0
- package/dist/modules/Cart/utils/cartDiscount.d.ts.map +1 -0
- package/dist/modules/Cart/utils/cartNote.d.ts.map +1 -0
- package/dist/modules/Cart/utils/cartProduct.d.ts.map +1 -0
- package/dist/modules/Cart/utils/cartRelationForms.d.ts.map +1 -0
- package/dist/modules/Cart/utils/cartResource.d.ts.map +1 -0
- package/dist/modules/Cart/utils/changePrice.d.ts.map +1 -0
- package/dist/modules/Cart/utils/index.d.ts.map +1 -0
- package/dist/modules/Customer/constants.d.ts.map +1 -0
- package/dist/modules/Customer/index.d.ts.map +1 -0
- package/dist/modules/Customer/types.d.ts.map +1 -0
- package/dist/modules/Date/index.d.ts.map +1 -0
- package/dist/modules/Date/types.d.ts.map +1 -0
- package/dist/modules/Date/utils.d.ts.map +1 -0
- package/dist/modules/Discount/availability.d.ts.map +1 -0
- package/dist/modules/Discount/entitlementPass.d.ts.map +1 -0
- package/dist/modules/Discount/index.d.ts.map +1 -0
- package/dist/modules/Discount/index.js +1 -0
- package/dist/modules/Discount/types.d.ts.map +1 -0
- package/dist/modules/Guests/index.d.ts.map +1 -0
- package/dist/modules/Guests/types.d.ts.map +1 -0
- package/dist/modules/Holder/index.d.ts.map +1 -0
- package/dist/modules/Holder/types.d.ts.map +1 -0
- package/dist/modules/Holder/utils.d.ts.map +1 -0
- package/dist/modules/OpenData/index.d.ts.map +1 -0
- package/dist/modules/OpenData/types.d.ts.map +1 -0
- package/dist/modules/OpenData/utils.d.ts.map +1 -0
- package/dist/modules/Order/index.d.ts +25 -3
- package/dist/modules/Order/index.d.ts.map +1 -0
- package/dist/modules/Order/index.js +1647 -1211
- package/dist/modules/Order/payment-utils.d.ts.map +1 -0
- package/dist/modules/Order/salesNotes.d.ts.map +1 -0
- package/dist/modules/Order/types.d.ts +7 -0
- package/dist/modules/Order/types.d.ts.map +1 -0
- package/dist/modules/Order/utils/bundleDiscountHydration.d.ts.map +1 -0
- package/dist/modules/Order/utils/discountProductLineIdentity.d.ts.map +1 -0
- package/dist/modules/Order/utils/discountProductLineIdentity.js +2 -2
- package/dist/modules/Order/utils/manualProductDiscount.d.ts.map +1 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.d.ts.map +1 -0
- package/dist/modules/Order/utils/productVoucherGroups.d.ts +15 -0
- package/dist/modules/Order/utils/productVoucherGroups.d.ts.map +1 -0
- package/dist/modules/Order/utils/productVoucherGroups.js +115 -0
- package/dist/modules/Order/utils/virtualSettlement.d.ts.map +1 -0
- package/dist/modules/Order/utils/weighedProduct.d.ts.map +1 -0
- package/dist/modules/Order/utils.d.ts +5 -3
- package/dist/modules/Order/utils.d.ts.map +1 -0
- package/dist/modules/Order/utils.js +32 -11
- package/dist/modules/Payment/cash.d.ts.map +1 -0
- package/dist/modules/Payment/cashRecommendationAlgorithm.d.ts.map +1 -0
- package/dist/modules/Payment/eftpos.d.ts.map +1 -0
- package/dist/modules/Payment/index.d.ts.map +1 -0
- package/dist/modules/Payment/mx51.d.ts.map +1 -0
- package/dist/modules/Payment/types.d.ts.map +1 -0
- package/dist/modules/Payment/utils.d.ts.map +1 -0
- package/dist/modules/Payment/walletpass.d.ts.map +1 -0
- package/dist/modules/Product/index.d.ts.map +1 -0
- package/dist/modules/Product/types.d.ts.map +1 -0
- package/dist/modules/Product/utils.d.ts.map +1 -0
- package/dist/modules/ProductList/clientDataVariants.d.ts.map +1 -0
- package/dist/modules/ProductList/index.d.ts.map +1 -0
- package/dist/modules/ProductList/index.js +33 -12
- package/dist/modules/ProductList/types.d.ts.map +1 -0
- package/dist/modules/Quotation/index.d.ts.map +1 -0
- package/dist/modules/Quotation/types.d.ts.map +1 -0
- package/dist/modules/Resource/index.d.ts.map +1 -0
- package/dist/modules/Resource/types.d.ts.map +1 -0
- package/dist/modules/Resource/utils.d.ts.map +1 -0
- package/dist/modules/ResourcePlanner/index.d.ts.map +1 -0
- package/dist/modules/ResourcePlanner/localClock.d.ts.map +1 -0
- package/dist/modules/ResourcePlanner/planner.d.ts.map +1 -0
- package/dist/modules/ResourcePlanner/types.d.ts.map +1 -0
- package/dist/modules/Rules/index.d.ts +2 -0
- package/dist/modules/Rules/index.d.ts.map +1 -0
- package/dist/modules/Rules/index.js +29 -21
- package/dist/modules/Rules/types.d.ts.map +1 -0
- package/dist/modules/SalesSummary/index.d.ts.map +1 -0
- package/dist/modules/SalesSummary/types.d.ts.map +1 -0
- package/dist/modules/SalesSummary/utils.d.ts.map +1 -0
- package/dist/modules/ScanOrderLogger/index.d.ts.map +1 -0
- package/dist/modules/ScanOrderLogger/providers/feishu.d.ts.map +1 -0
- package/dist/modules/ScanOrderLogger/providers/grafana.d.ts.map +1 -0
- package/dist/modules/ScanOrderLogger/types.d.ts.map +1 -0
- package/dist/modules/Schedule/getDateIsInSchedule.d.ts.map +1 -0
- package/dist/modules/Schedule/index.d.ts.map +1 -0
- package/dist/modules/Schedule/type.d.ts.map +1 -0
- package/dist/modules/Schedule/types.d.ts.map +1 -0
- package/dist/modules/Schedule/utils.d.ts.map +1 -0
- package/dist/modules/Step/index.d.ts.map +1 -0
- package/dist/modules/Step/tyeps.d.ts.map +1 -0
- package/dist/modules/Summary/index.d.ts.map +1 -0
- package/dist/modules/Summary/types.d.ts.map +1 -0
- package/dist/modules/Summary/utils.d.ts.map +1 -0
- package/dist/modules/SurchargeList/index.d.ts.map +1 -0
- package/dist/modules/SurchargeList/types.d.ts.map +1 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/plugins/app.d.ts.map +1 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/request.d.ts.map +1 -0
- package/dist/plugins/shopStore.d.ts.map +1 -0
- package/dist/plugins/user.d.ts.map +1 -0
- package/dist/plugins/window.d.ts.map +1 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/modules/floor-plan/index.d.ts.map +1 -0
- package/dist/server/modules/floor-plan/index.js +34 -3
- package/dist/server/modules/floor-plan/types.d.ts.map +1 -0
- package/dist/server/modules/index.d.ts.map +1 -0
- package/dist/server/modules/menu/index.d.ts.map +1 -0
- package/dist/server/modules/menu/types.d.ts.map +1 -0
- package/dist/server/modules/order/index.d.ts.map +1 -0
- package/dist/server/modules/order/types.d.ts.map +1 -0
- package/dist/server/modules/order/utils/filterBookings.d.ts.map +1 -0
- package/dist/server/modules/order/utils/filterOrders.d.ts.map +1 -0
- package/dist/server/modules/payment/index.d.ts.map +1 -0
- package/dist/server/modules/payment/types.d.ts.map +1 -0
- package/dist/server/modules/products/index.d.ts.map +1 -0
- package/dist/server/modules/products/types.d.ts.map +1 -0
- package/dist/server/modules/quotation/index.d.ts.map +1 -0
- package/dist/server/modules/quotation/types.d.ts.map +1 -0
- package/dist/server/modules/resource/index.d.ts.map +1 -0
- package/dist/server/modules/resource/types.d.ts.map +1 -0
- package/dist/server/modules/schedule/index.d.ts.map +1 -0
- package/dist/server/modules/schedule/types.d.ts.map +1 -0
- package/dist/server/modules/schedule/utils.d.ts.map +1 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/utils/index.d.ts.map +1 -0
- package/dist/server/utils/product.d.ts.map +1 -0
- package/dist/server/utils/schedule.d.ts.map +1 -0
- package/dist/server/utils/small-ticket.d.ts.map +1 -0
- package/dist/server/utils/time.d.ts.map +1 -0
- package/dist/solution/BaseSales/index.d.ts +16 -1
- package/dist/solution/BaseSales/index.d.ts.map +1 -0
- package/dist/solution/BaseSales/index.js +1363 -1176
- package/dist/solution/BaseSales/types.d.ts.map +1 -0
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts.map +1 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts.map +1 -0
- package/dist/solution/BaseSales/utils/quotationPrice.d.ts.map +1 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts.map +1 -0
- package/dist/solution/BaseSales/utils.d.ts.map +1 -0
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingByStep/index.d.ts.map +1 -0
- package/dist/solution/BookingByStep/types.d.ts.map +1 -0
- package/dist/solution/BookingByStep/utils/capacity.d.ts.map +1 -0
- package/dist/solution/BookingByStep/utils/products.d.ts.map +1 -0
- package/dist/solution/BookingByStep/utils/resources.d.ts.map +1 -0
- package/dist/solution/BookingByStep/utils/stock.d.ts.map +1 -0
- package/dist/solution/BookingByStep/utils/timeslots.d.ts.map +1 -0
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts.map +1 -0
- package/dist/solution/BookingTicket/index.js +198 -108
- package/dist/solution/BookingTicket/types.d.ts +14 -2
- package/dist/solution/BookingTicket/types.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +1 -1
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/addProductDecision.js +4 -3
- package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/bookingStatus.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/cartView.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/exampleData.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/orderCustomer.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +94 -58
- package/dist/solution/BookingTicket/utils/scan/applyProductVoucherCollectionScan.d.ts +10 -0
- package/dist/solution/BookingTicket/utils/scan/applyProductVoucherCollectionScan.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/scan/applyProductVoucherCollectionScan.js +117 -0
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +1 -0
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/scan/handleScan.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +2 -1
- package/dist/solution/BookingTicket/utils/scan/index.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/scan/scanCache.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/scan/scanProductValues.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/sessionCatalogStale.d.ts.map +1 -0
- package/dist/solution/BookingTicket/utils/weighingProductSku.d.ts.map +1 -0
- package/dist/solution/BuyTickets/index.d.ts.map +1 -0
- package/dist/solution/BuyTickets/types.d.ts.map +1 -0
- package/dist/solution/Checkout/index.d.ts.map +1 -0
- package/dist/solution/Checkout/types.d.ts.map +1 -0
- package/dist/solution/Checkout/utils/index.d.ts.map +1 -0
- package/dist/solution/PlaceOrder/index.d.ts.map +1 -0
- package/dist/solution/RegisterAndLogin/config.d.ts.map +1 -0
- package/dist/solution/RegisterAndLogin/index.d.ts.map +1 -0
- package/dist/solution/RegisterAndLogin/types.d.ts.map +1 -0
- package/dist/solution/RegisterAndLogin/utils.d.ts.map +1 -0
- package/dist/solution/Sales/index.d.ts.map +1 -0
- package/dist/solution/Sales/types.d.ts.map +1 -0
- package/dist/solution/ScanOrder/index.d.ts.map +1 -0
- package/dist/solution/ScanOrder/types.d.ts.map +1 -0
- package/dist/solution/ScanOrder/utils.d.ts.map +1 -0
- package/dist/solution/ShopDiscount/index.d.ts.map +1 -0
- package/dist/solution/ShopDiscount/types.d.ts.map +1 -0
- package/dist/solution/ShopDiscount/utils.d.ts.map +1 -0
- package/dist/solution/UnifiedBookingSales/index.d.ts +1 -1
- package/dist/solution/UnifiedBookingSales/index.d.ts.map +1 -0
- package/dist/solution/UnifiedBookingSales/index.js +63 -43
- package/dist/solution/UnifiedBookingSales/remoteOccupancyCache.d.ts.map +1 -0
- package/dist/solution/UnifiedBookingSales/types.d.ts.map +1 -0
- package/dist/solution/VenueBooking/index.d.ts.map +1 -0
- package/dist/solution/VenueBooking/types.d.ts.map +1 -0
- package/dist/solution/VenueBooking/utils/dateSummary.d.ts.map +1 -0
- package/dist/solution/VenueBooking/utils/resource.d.ts.map +1 -0
- package/dist/solution/VenueBooking/utils/slotMerge.d.ts.map +1 -0
- package/dist/solution/VenueBooking/utils/timeSlot.d.ts.map +1 -0
- package/dist/solution/VenueBooking/utils.d.ts.map +1 -0
- package/dist/solution/index.d.ts.map +1 -0
- package/dist/store/createStore.d.ts.map +1 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/os-private-payload.d.ts.map +1 -0
- package/dist/utils/payment-number.d.ts.map +1 -0
- package/dist/utils/platform.d.ts +2 -0
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +6 -0
- package/dist/utils/task.d.ts.map +1 -0
- package/dist/utils/watch.d.ts.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +12 -0
- package/lib/inventory/index.d.ts +92 -0
- package/lib/inventory/index.js +287 -0
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/Discount/index.js +1 -0
- package/lib/modules/Order/index.d.ts +25 -3
- package/lib/modules/Order/index.js +145 -11
- package/lib/modules/Order/types.d.ts +7 -0
- package/lib/modules/Order/utils/discountProductLineIdentity.js +1 -1
- package/lib/modules/Order/utils/productVoucherGroups.d.ts +15 -0
- package/lib/modules/Order/utils/productVoucherGroups.js +64 -0
- package/lib/modules/Order/utils.d.ts +5 -3
- package/lib/modules/Order/utils.js +29 -10
- package/lib/modules/ProductList/index.js +15 -0
- package/lib/modules/Rules/index.d.ts +2 -0
- package/lib/modules/Rules/index.js +6 -0
- package/lib/server/modules/floor-plan/index.js +29 -1
- package/lib/solution/BaseSales/index.d.ts +16 -1
- package/lib/solution/BaseSales/index.js +89 -9
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +36 -2
- package/lib/solution/BookingTicket/types.d.ts +14 -2
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +1 -1
- package/lib/solution/BookingTicket/utils/addProductDecision.js +4 -3
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +14 -2
- package/lib/solution/BookingTicket/utils/scan/applyProductVoucherCollectionScan.d.ts +10 -0
- package/lib/solution/BookingTicket/utils/scan/applyProductVoucherCollectionScan.js +71 -0
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +1 -0
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +2 -1
- package/lib/solution/UnifiedBookingSales/index.d.ts +1 -1
- package/lib/solution/UnifiedBookingSales/index.js +14 -3
- package/lib/utils/platform.d.ts +2 -0
- package/lib/utils/platform.js +7 -0
- package/package.json +4 -2
|
@@ -11,6 +11,7 @@ var _utils2 = require("../Product/utils");
|
|
|
11
11
|
var _weighedProduct = require("./utils/weighedProduct");
|
|
12
12
|
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
13
13
|
var _availability = require("../Discount/availability");
|
|
14
|
+
var _productVoucherGroups = require("./utils/productVoucherGroups");
|
|
14
15
|
var _osPrivatePayload = require("../../utils/os-private-payload");
|
|
15
16
|
var _salesNotes = require("./salesNotes");
|
|
16
17
|
var _paymentUtils = require("./payment-utils");
|
|
@@ -137,6 +138,62 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
137
138
|
rulesHooksOverride;
|
|
138
139
|
moduleHooksOverride;
|
|
139
140
|
orderHooks;
|
|
141
|
+
cartCommandQueue = Promise.resolve();
|
|
142
|
+
queueCartCommand(run) {
|
|
143
|
+
if (!this.orderHooks?.onBeforeCartCommit && !this.store.tempOrder?._extend?.productVoucherGroups?.length) return run();
|
|
144
|
+
const pending = this.cartCommandQueue.then(run, run);
|
|
145
|
+
this.cartCommandQueue = pending.catch(() => undefined);
|
|
146
|
+
return pending;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Use the exact Order normalizers/merge rules on a private draft, not a second projection. */
|
|
150
|
+
beginCartMutation() {
|
|
151
|
+
const current = this.ensureTempOrder();
|
|
152
|
+
const guard = this.orderHooks?.onBeforeCartCommit;
|
|
153
|
+
if (!guard && !current._extend?.productVoucherGroups?.length) return {
|
|
154
|
+
draft: current,
|
|
155
|
+
commit: undefined
|
|
156
|
+
};
|
|
157
|
+
const before = (0, _lodashEs.cloneDeep)(current);
|
|
158
|
+
const draft = (0, _lodashEs.cloneDeep)(current);
|
|
159
|
+
return {
|
|
160
|
+
draft,
|
|
161
|
+
commit: async () => {
|
|
162
|
+
(0, _productVoucherGroups.validateProductVoucherGroups)(draft, this.getDiscountList(), before);
|
|
163
|
+
await guard?.({
|
|
164
|
+
currentItems: (0, _lodashEs.cloneDeep)(before.products),
|
|
165
|
+
proposedItems: (0, _lodashEs.cloneDeep)(draft.products)
|
|
166
|
+
});
|
|
167
|
+
if (this.store.tempOrder !== current || guard !== this.orderHooks?.onBeforeCartCommit || !(0, _lodashEs.isEqual)(current, before)) {
|
|
168
|
+
throw Object.assign(new Error('The cart changed. Please try again.'), {
|
|
169
|
+
code: 'SALES_GUARD_REJECTED'
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
Object.assign(current, draft);
|
|
173
|
+
return current;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Serializes checkout preparation with local cart commands; hydration remains outside this guard. */
|
|
179
|
+
async prepareCheckout(prepare) {
|
|
180
|
+
const run = async () => {
|
|
181
|
+
const order = this.ensureTempOrder();
|
|
182
|
+
(0, _productVoucherGroups.validateProductVoucherGroups)(order, this.getDiscountList(), undefined, true);
|
|
183
|
+
const items = (0, _lodashEs.cloneDeep)(order.products);
|
|
184
|
+
const result = await prepare(items);
|
|
185
|
+
if (this.store.tempOrder !== order || !(0, _lodashEs.isEqual)(order.products, items)) {
|
|
186
|
+
throw Object.assign(new Error('The cart changed. Please try again.'), {
|
|
187
|
+
code: 'SALES_GUARD_REJECTED'
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
(0, _productVoucherGroups.validateProductVoucherGroups)(order, this.getDiscountList(), undefined, true);
|
|
191
|
+
return result;
|
|
192
|
+
};
|
|
193
|
+
const pending = this.cartCommandQueue.then(run, run);
|
|
194
|
+
this.cartCommandQueue = pending.catch(() => undefined);
|
|
195
|
+
return pending;
|
|
196
|
+
}
|
|
140
197
|
otherParams;
|
|
141
198
|
// ─── 促销/赠品 ────────────────────────────────────
|
|
142
199
|
/** 评估器引用;由 SalesSdkProvider 注入,未注入时 applyPromotion 静默跳过 */
|
|
@@ -424,8 +481,11 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
424
481
|
* @example
|
|
425
482
|
* orderModule.updateOtherParams({ cacheId: 'cache-2', channel: 'pos' });
|
|
426
483
|
*/
|
|
427
|
-
updateOtherParams(params) {
|
|
484
|
+
updateOtherParams(params, options) {
|
|
428
485
|
const otherParams = params || {};
|
|
486
|
+
if (options && Object.prototype.hasOwnProperty.call(options, 'hooks')) {
|
|
487
|
+
this.moduleHooksOverride = options.hooks;
|
|
488
|
+
}
|
|
429
489
|
this.syncSessionStorageOptions(otherParams);
|
|
430
490
|
this.salesSummaryModuleName = otherParams.salesSummaryModuleName;
|
|
431
491
|
this.rulesHooksOverride = otherParams.rules?.hooks;
|
|
@@ -509,6 +569,26 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
509
569
|
hooks: this.rulesHooksOverride || this.createDefaultRulesHooks()
|
|
510
570
|
});
|
|
511
571
|
this.store.rules = rules;
|
|
572
|
+
rules.setDiscountScope((product, discount) => (0, _productVoucherGroups.allowsProductVoucher)(this.store.tempOrder, product, discount));
|
|
573
|
+
}
|
|
574
|
+
setProductVoucherGroups(groups) {
|
|
575
|
+
const order = this.ensureTempOrder();
|
|
576
|
+
const ids = new Set();
|
|
577
|
+
const keys = new Set();
|
|
578
|
+
const known = new Map(this.getDiscountList().map(discount => [String(discount.id), discount]));
|
|
579
|
+
for (const group of groups) {
|
|
580
|
+
if (!group.key || keys.has(group.key)) throw (0, _productVoucherGroups.voucherGroupError)();
|
|
581
|
+
keys.add(group.key);
|
|
582
|
+
for (const id of group.discountIds) {
|
|
583
|
+
const discount = known.get(String(id));
|
|
584
|
+
if (!discount || (discount.tag || discount.type) !== 'good_pass' || ids.has(String(id))) throw (0, _productVoucherGroups.voucherGroupError)();
|
|
585
|
+
ids.add(String(id));
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
this.ensureExtend(order).productVoucherGroups = (0, _lodashEs.cloneDeep)(groups);
|
|
589
|
+
}
|
|
590
|
+
validateProductVoucherSelection() {
|
|
591
|
+
(0, _productVoucherGroups.validateProductVoucherGroups)(this.ensureTempOrder(), this.getDiscountList(), undefined, true);
|
|
512
592
|
}
|
|
513
593
|
createDefaultRulesHooks() {
|
|
514
594
|
return (0, _utils.createDefaultOrderRulesHooks)(() => this.store.tempOrder?.bookings || []);
|
|
@@ -660,7 +740,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
660
740
|
apply: false
|
|
661
741
|
});
|
|
662
742
|
}
|
|
663
|
-
async scanCode(code, customerId) {
|
|
743
|
+
async scanCode(code, customerId, options) {
|
|
664
744
|
if (this.isActiveVirtualSettlementOrder(this.store.tempOrder)) {
|
|
665
745
|
return {
|
|
666
746
|
type: 'clientCalc',
|
|
@@ -671,16 +751,22 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
671
751
|
unavailableReason: _types2.UnavailableReason.ProductNotApplicable
|
|
672
752
|
};
|
|
673
753
|
}
|
|
754
|
+
const scanOrderKey = this.getDiscountConfigOrderIdentityKey(this.store.tempOrder);
|
|
674
755
|
const resultDiscountWithReason = (await this.store.discount?.batchSearch(code, {
|
|
675
756
|
customerId
|
|
676
757
|
})) || {
|
|
677
758
|
discountList: [],
|
|
678
759
|
unavailableReasonKey: null
|
|
679
760
|
};
|
|
761
|
+
if (scanOrderKey !== this.getDiscountConfigOrderIdentityKey(this.store.tempOrder)) {
|
|
762
|
+
throw Object.assign(new Error('The scan session ended.'), {
|
|
763
|
+
code: 'SALES_GUARD_REJECTED'
|
|
764
|
+
});
|
|
765
|
+
}
|
|
680
766
|
const {
|
|
681
|
-
discountList: resultDiscountList,
|
|
682
767
|
unavailableReasonKey
|
|
683
768
|
} = resultDiscountWithReason;
|
|
769
|
+
const resultDiscountList = resultDiscountWithReason.discountList.filter(discount => !options?.productVouchersOnly || (discount.tag || discount.type) === 'good_pass');
|
|
684
770
|
const rulesModule = this.store.rules;
|
|
685
771
|
if (!rulesModule) {
|
|
686
772
|
return {
|
|
@@ -707,7 +793,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
707
793
|
isScan: true
|
|
708
794
|
}));
|
|
709
795
|
const currentSelected = this.getDiscountList().filter(n => n.isSelected);
|
|
710
|
-
if (currentSelected.length && currentSelected.some(n => withScanList.some(m => m.id === n.id))) {
|
|
796
|
+
if (currentSelected.length && (options?.productVouchersOnly ? withScanList.every(scanned => currentSelected.some(selected => selected.id === scanned.id)) : currentSelected.some(n => withScanList.some(m => m.id === n.id)))) {
|
|
711
797
|
await this.syncScannedDiscountsToOriginalDiscountList(this.getDiscountList());
|
|
712
798
|
return {
|
|
713
799
|
type: 'clientCalc',
|
|
@@ -2196,8 +2282,12 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2196
2282
|
...existed,
|
|
2197
2283
|
...(origin !== undefined ? {
|
|
2198
2284
|
origin
|
|
2285
|
+
} : {}),
|
|
2286
|
+
...(rawProduct._productVoucherGroupKey ? {
|
|
2287
|
+
productVoucherGroupKey: rawProduct._productVoucherGroupKey
|
|
2199
2288
|
} : {})
|
|
2200
2289
|
};
|
|
2290
|
+
delete normalizedProduct._productVoucherGroupKey;
|
|
2201
2291
|
delete normalizedProduct._origin;
|
|
2202
2292
|
delete normalizedProduct.unique_identification_number;
|
|
2203
2293
|
}
|
|
@@ -3463,6 +3553,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3463
3553
|
const isIncomingCustomItem = productToAdd.metadata?.origin?.isCustomItem === true || productToAdd._origin?.isCustomItem === true;
|
|
3464
3554
|
const shouldForceNewLine = disableMerge || !!booking || hasIncomingGoodPass || isIncomingPersistedEntitlementPass || hasIncomingBookingUid || isIncomingCustomItem || isWeighingProduct;
|
|
3465
3555
|
const matchedIndex = shouldForceNewLine ? -1 : tempOrder.products.findIndex(item => {
|
|
3556
|
+
if ((0, _productVoucherGroups.productVoucherGroupKey)(tempOrder, item) !== productToAdd._productVoucherGroupKey) return false;
|
|
3466
3557
|
if (this.hasGoodPassDiscount(item)) return false;
|
|
3467
3558
|
const isRuntimeEntitlementPass = this.isRuntimeEntitlementAppend(item, tempOrder);
|
|
3468
3559
|
if (isIncomingEntitlementAppend !== isRuntimeEntitlementPass) {
|
|
@@ -3642,7 +3733,18 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3642
3733
|
* // → tempOrder.products 新增 3 行,每行 num=1,bookings 3 条
|
|
3643
3734
|
*/
|
|
3644
3735
|
async addProductToOrder(product, booking, options) {
|
|
3645
|
-
|
|
3736
|
+
return this.queueCartCommand(() => this.addProductToOrderDraft(product, booking, options));
|
|
3737
|
+
}
|
|
3738
|
+
async addProductToOrderDraft(product, booking, options) {
|
|
3739
|
+
const mutation = this.beginCartMutation();
|
|
3740
|
+
let tempOrder = mutation.draft;
|
|
3741
|
+
if (options?.productVoucherGroupKey) {
|
|
3742
|
+
if (!tempOrder._extend?.productVoucherGroups?.some(group => group.key === options.productVoucherGroupKey)) throw (0, _productVoucherGroups.voucherGroupError)();
|
|
3743
|
+
product = {
|
|
3744
|
+
...product,
|
|
3745
|
+
_productVoucherGroupKey: options.productVoucherGroupKey
|
|
3746
|
+
};
|
|
3747
|
+
}
|
|
3646
3748
|
const salesNoteDrafts = (options?.salesNotes || []).map(draft => ({
|
|
3647
3749
|
note_type: String(draft.note_type || '').trim(),
|
|
3648
3750
|
text: {
|
|
@@ -3736,6 +3838,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3736
3838
|
rollbackProductAndNotesMutation();
|
|
3737
3839
|
throw error;
|
|
3738
3840
|
}
|
|
3841
|
+
if (mutation.commit) tempOrder = await mutation.commit();
|
|
3739
3842
|
await this.finalizeProductOrderMutation(tempOrder);
|
|
3740
3843
|
this.logInfo('addProductToOrder success', {
|
|
3741
3844
|
product_id: product.product_id,
|
|
@@ -3754,7 +3857,11 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3754
3857
|
* ]);
|
|
3755
3858
|
*/
|
|
3756
3859
|
async addProductsToOrder(items, options) {
|
|
3757
|
-
|
|
3860
|
+
return this.queueCartCommand(() => this.addProductsToOrderDraft(items, options));
|
|
3861
|
+
}
|
|
3862
|
+
async addProductsToOrderDraft(items, options) {
|
|
3863
|
+
const mutation = this.beginCartMutation();
|
|
3864
|
+
let tempOrder = mutation.draft;
|
|
3758
3865
|
if (!Array.isArray(items) || items.length === 0) return tempOrder.products;
|
|
3759
3866
|
for (const item of items || []) {
|
|
3760
3867
|
const {
|
|
@@ -3777,6 +3884,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3777
3884
|
const appendResult = this.appendProductLineToTempOrder(tempOrder, product, booking);
|
|
3778
3885
|
if (appendResult) await appendResult;
|
|
3779
3886
|
}
|
|
3887
|
+
if (mutation.commit) tempOrder = await mutation.commit();
|
|
3780
3888
|
await this.finalizeProductOrderMutation(tempOrder, options);
|
|
3781
3889
|
this.logInfo('addProductsToOrder success', {
|
|
3782
3890
|
itemsCount: items.length
|
|
@@ -4109,9 +4217,14 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4109
4217
|
return tempOrder.products[productIndex].metadata?.unique_identification_number;
|
|
4110
4218
|
}
|
|
4111
4219
|
async updateOrderProduct(params) {
|
|
4112
|
-
|
|
4220
|
+
return this.queueCartCommand(() => this.updateOrderProductDraft(params));
|
|
4221
|
+
}
|
|
4222
|
+
async updateOrderProductDraft(params) {
|
|
4223
|
+
const mutation = this.beginCartMutation();
|
|
4224
|
+
let tempOrder = mutation.draft;
|
|
4113
4225
|
const reapplyWeighedDiscountProductUids = [];
|
|
4114
4226
|
const updatedProductUid = this.applyOrderProductUpdateToTempOrder(tempOrder, params, reapplyWeighedDiscountProductUids);
|
|
4227
|
+
if (mutation.commit) tempOrder = await mutation.commit();
|
|
4115
4228
|
const promotionPayload = await this.evaluatePromotion();
|
|
4116
4229
|
this.applyDiscount({
|
|
4117
4230
|
reapplyWeighedDiscountProductUids,
|
|
@@ -4129,7 +4242,11 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4129
4242
|
return tempOrder.products;
|
|
4130
4243
|
}
|
|
4131
4244
|
async updateOrderProducts(paramsList) {
|
|
4132
|
-
|
|
4245
|
+
return this.queueCartCommand(() => this.updateOrderProductsDraft(paramsList));
|
|
4246
|
+
}
|
|
4247
|
+
async updateOrderProductsDraft(paramsList) {
|
|
4248
|
+
const mutation = this.beginCartMutation();
|
|
4249
|
+
let tempOrder = mutation.draft;
|
|
4133
4250
|
if (!paramsList.length) {
|
|
4134
4251
|
return tempOrder.products;
|
|
4135
4252
|
}
|
|
@@ -4142,6 +4259,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4142
4259
|
}
|
|
4143
4260
|
return acc;
|
|
4144
4261
|
}, []);
|
|
4262
|
+
if (mutation.commit) tempOrder = await mutation.commit();
|
|
4145
4263
|
await this.finalizeAfterProductsMutation(tempOrder, {
|
|
4146
4264
|
reapplyWeighedDiscountProductUids,
|
|
4147
4265
|
reapplyBookingDiscountProductUids: reapplyBookingDiscountProductUids.length ? reapplyBookingDiscountProductUids : undefined
|
|
@@ -4152,6 +4270,9 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4152
4270
|
return tempOrder.products;
|
|
4153
4271
|
}
|
|
4154
4272
|
async updateOrderProductQuantity(params) {
|
|
4273
|
+
return this.queueCartCommand(() => this.updateOrderProductQuantityDraft(params));
|
|
4274
|
+
}
|
|
4275
|
+
async updateOrderProductQuantityDraft(params) {
|
|
4155
4276
|
const {
|
|
4156
4277
|
product_id,
|
|
4157
4278
|
product_variant_id,
|
|
@@ -4161,7 +4282,8 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4161
4282
|
product_sku,
|
|
4162
4283
|
product_bundle
|
|
4163
4284
|
} = params;
|
|
4164
|
-
const
|
|
4285
|
+
const mutation = this.beginCartMutation();
|
|
4286
|
+
let tempOrder = mutation.draft;
|
|
4165
4287
|
this.repairDuplicateProductLineIdentities(tempOrder);
|
|
4166
4288
|
const identityLookup = {
|
|
4167
4289
|
product_id,
|
|
@@ -4218,6 +4340,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4218
4340
|
}
|
|
4219
4341
|
}
|
|
4220
4342
|
tempOrder.products[productIndex] = normalizedProduct;
|
|
4343
|
+
if (mutation.commit) tempOrder = await mutation.commit();
|
|
4221
4344
|
this.prepareVirtualSettlementTempOrder(tempOrder);
|
|
4222
4345
|
const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder);
|
|
4223
4346
|
const promotionPayload = !isVirtualSettlement ? await this.evaluatePromotion() : null;
|
|
@@ -4294,7 +4417,11 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4294
4417
|
* await order.removeProductsFromOrder([identityA, identityB]);
|
|
4295
4418
|
*/
|
|
4296
4419
|
async removeProductsFromOrder(identities, options) {
|
|
4297
|
-
|
|
4420
|
+
return this.queueCartCommand(() => this.removeProductsFromOrderDraft(identities, options));
|
|
4421
|
+
}
|
|
4422
|
+
async removeProductsFromOrderDraft(identities, options) {
|
|
4423
|
+
const mutation = this.beginCartMutation();
|
|
4424
|
+
let tempOrder = mutation.draft;
|
|
4298
4425
|
if (!identities.length) {
|
|
4299
4426
|
return tempOrder.products;
|
|
4300
4427
|
}
|
|
@@ -4361,6 +4488,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4361
4488
|
}
|
|
4362
4489
|
}
|
|
4363
4490
|
this.removeSalesNotesForMissingProductLines(tempOrder);
|
|
4491
|
+
if (mutation.commit) tempOrder = await mutation.commit();
|
|
4364
4492
|
await this.finalizeAfterProductsMutation(tempOrder);
|
|
4365
4493
|
this.logInfo('removeProductsFromOrder success', {
|
|
4366
4494
|
identities
|
|
@@ -4376,7 +4504,11 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4376
4504
|
* 普通整单 note 保持不变;以商品行为主体的 Sales Notes 同步删除。
|
|
4377
4505
|
*/
|
|
4378
4506
|
async clearOrderCartLines() {
|
|
4379
|
-
|
|
4507
|
+
return this.queueCartCommand(() => this.clearOrderCartLinesDraft());
|
|
4508
|
+
}
|
|
4509
|
+
async clearOrderCartLinesDraft() {
|
|
4510
|
+
const mutation = this.beginCartMutation();
|
|
4511
|
+
let tempOrder = mutation.draft;
|
|
4380
4512
|
this.ensureSalesNotesLoadedForMutation(tempOrder);
|
|
4381
4513
|
tempOrder.products = [];
|
|
4382
4514
|
tempOrder.bookings = [];
|
|
@@ -4389,6 +4521,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4389
4521
|
productsByUid: {}
|
|
4390
4522
|
};
|
|
4391
4523
|
}
|
|
4524
|
+
if (mutation.commit) tempOrder = await mutation.commit();
|
|
4392
4525
|
const promotionPayload = await this.evaluatePromotion();
|
|
4393
4526
|
this.applyDiscount();
|
|
4394
4527
|
this.sanitizeTempOrderProducts(tempOrder);
|
|
@@ -4525,6 +4658,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4525
4658
|
}
|
|
4526
4659
|
async runSubmitTempOrder(params) {
|
|
4527
4660
|
const tempOrder = this.ensureTempOrder();
|
|
4661
|
+
(0, _productVoucherGroups.validateProductVoucherGroups)(tempOrder, this.getDiscountList(), undefined, true);
|
|
4528
4662
|
this.prepareVirtualSettlementTempOrder(tempOrder);
|
|
4529
4663
|
const isOnlineStorePlatform = this.isOnlineStorePlatform();
|
|
4530
4664
|
const shouldConfirmPendingVoucherPayments = params?.confirmPendingVoucherPayments !== false;
|
|
@@ -438,6 +438,8 @@ export type AddProductBookingInput = Record<string, any>;
|
|
|
438
438
|
* 避免步进器修改数量改变该组展示位置。
|
|
439
439
|
*/
|
|
440
440
|
export interface AddProductToOrderOptions {
|
|
441
|
+
/** Associates a selection with an existing runtime voucher group. */
|
|
442
|
+
productVoucherGroupKey?: string;
|
|
441
443
|
insertAfterProductUid?: string;
|
|
442
444
|
/** 跳过同商品/规格匹配,始终新增购物车行。 */
|
|
443
445
|
disableMerge?: boolean;
|
|
@@ -517,6 +519,11 @@ export type OrderProductMergeDecisionResult = boolean | {
|
|
|
517
519
|
[key: string]: any;
|
|
518
520
|
};
|
|
519
521
|
export interface OrderHooksConfig {
|
|
522
|
+
/** Awaited before a local cart draft is published. Reject to leave the live order unchanged. */
|
|
523
|
+
onBeforeCartCommit?: (context: {
|
|
524
|
+
currentItems: readonly OrderProduct[];
|
|
525
|
+
proposedItems: readonly OrderProduct[];
|
|
526
|
+
}) => void | Promise<void>;
|
|
520
527
|
onBeforeMergeProductToOrder?: (context: OrderProductMergeDecisionContext) => OrderProductMergeDecisionResult | Promise<OrderProductMergeDecisionResult>;
|
|
521
528
|
}
|
|
522
529
|
/**
|
|
@@ -192,7 +192,7 @@ function consolidateDiscountFreeProductLines(tempOrder) {
|
|
|
192
192
|
bundle_selling_price: String(bundle?.bundle_selling_price ?? '')
|
|
193
193
|
}))
|
|
194
194
|
});
|
|
195
|
-
const mergeKey = [discountSplitOriginUid, product.product_id, product.product_variant_id ?? 0, fingerprint, priceSignature].join('#');
|
|
195
|
+
const mergeKey = [discountSplitOriginUid, productUid ? tempOrder._extend?.productsByUid?.[productUid]?.productVoucherGroupKey ?? '' : '', product.product_id, product.product_variant_id ?? 0, fingerprint, priceSignature].join('#');
|
|
196
196
|
const matchedIndex = productIndexByKey.get(mergeKey);
|
|
197
197
|
|
|
198
198
|
// 当前拆分来源 + 商品结构组合第一次出现时,保留该行作为回并目标。
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Discount } from '../../Discount/types';
|
|
2
|
+
import type { OrderTempOrder } from '../types';
|
|
3
|
+
/** Runtime-only allocation constraints. Never copied into order/product metadata. */
|
|
4
|
+
export interface ProductVoucherGroup {
|
|
5
|
+
key: string;
|
|
6
|
+
discountIds: Array<number | string>;
|
|
7
|
+
}
|
|
8
|
+
export declare function productVoucherGroupKey(order: OrderTempOrder, product: any): string | undefined;
|
|
9
|
+
export declare function isUsableProductVoucher(discount: Discount): boolean;
|
|
10
|
+
export declare function voucherGroupError(): Error & {
|
|
11
|
+
code: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function allowsProductVoucher(order: OrderTempOrder | null | undefined, product: any, discount: Discount): boolean;
|
|
14
|
+
/** Reductions stay possible when a voucher expires; checkout always requires full coverage. */
|
|
15
|
+
export declare function validateProductVoucherGroups(order: OrderTempOrder, discounts: Discount[], previous?: OrderTempOrder, requireCoverage?: boolean): void;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.allowsProductVoucher = allowsProductVoucher;
|
|
7
|
+
exports.isUsableProductVoucher = isUsableProductVoucher;
|
|
8
|
+
exports.productVoucherGroupKey = productVoucherGroupKey;
|
|
9
|
+
exports.validateProductVoucherGroups = validateProductVoucherGroups;
|
|
10
|
+
exports.voucherGroupError = voucherGroupError;
|
|
11
|
+
var _availability = require("../../Discount/availability");
|
|
12
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
13
|
+
var _utils = require("../../../solution/ShopDiscount/utils");
|
|
14
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
+
/** Runtime-only allocation constraints. Never copied into order/product metadata. */
|
|
16
|
+
|
|
17
|
+
function productVoucherGroupKey(order, product) {
|
|
18
|
+
const uid = product?.metadata?.unique_identification_number ?? product?.unique_identification_number;
|
|
19
|
+
return order._extend?.productsByUid?.[String(uid)]?.productVoucherGroupKey;
|
|
20
|
+
}
|
|
21
|
+
function isUsableProductVoucher(discount) {
|
|
22
|
+
return (discount.tag || discount.type) === 'good_pass' && !discount.isEditMode && !discount.isDisabled && !(0, _availability.getDiscountUsageBlockReason)(discount) && !(0, _utils.getDiscountTimeUnavailableReason)(discount, (0, _dayjs.default)().format('YYYY-MM-DD HH:mm:ss'));
|
|
23
|
+
}
|
|
24
|
+
function voucherGroupError() {
|
|
25
|
+
return Object.assign(new Error('The selected items no longer match the available vouchers. Please adjust your selection.'), {
|
|
26
|
+
code: 'PRODUCT_VOUCHER_GROUP_INVALID'
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function allowsProductVoucher(order, product, discount) {
|
|
30
|
+
const groups = order?._extend?.productVoucherGroups;
|
|
31
|
+
if (!order || !groups?.length) return true;
|
|
32
|
+
const key = productVoucherGroupKey(order, product);
|
|
33
|
+
if (!key) return !groups.some(group => group.discountIds.some(id => String(id) === String(discount.id)));
|
|
34
|
+
return (discount.tag || discount.type) === 'good_pass' && Boolean(groups.find(group => group.key === key)?.discountIds.some(id => String(id) === String(discount.id)));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Reductions stay possible when a voucher expires; checkout always requires full coverage. */
|
|
38
|
+
function validateProductVoucherGroups(order, discounts, previous, requireCoverage = false) {
|
|
39
|
+
const groups = order._extend?.productVoucherGroups;
|
|
40
|
+
if (!groups?.length) return;
|
|
41
|
+
const usedIds = new Set();
|
|
42
|
+
const byId = new Map(discounts.filter(isUsableProductVoucher).map(discount => [String(discount.id), discount]));
|
|
43
|
+
const quantity = item => Number(item.num ?? item.product_quantity ?? 0);
|
|
44
|
+
for (const group of groups) {
|
|
45
|
+
const items = order.products.filter(item => productVoucherGroupKey(order, item) === group.key);
|
|
46
|
+
const selected = items.reduce((sum, item) => sum + quantity(item), 0);
|
|
47
|
+
const before = previous?.products.filter(item => productVoucherGroupKey(previous, item) === group.key).reduce((sum, item) => sum + quantity(item), 0) ?? 0;
|
|
48
|
+
if (!requireCoverage && previous && selected <= before) continue;
|
|
49
|
+
const ids = new Set(group.discountIds.map(String).filter(id => byId.has(id)));
|
|
50
|
+
if (!Number.isInteger(selected) || selected < 0 || selected > ids.size) throw voucherGroupError();
|
|
51
|
+
if (!requireCoverage) continue;
|
|
52
|
+
for (const item of items) {
|
|
53
|
+
const applied = (item.discount_list || []).filter(entry => (entry.type || entry.tag) === 'good_pass');
|
|
54
|
+
// Rules splits a good_pass allocation into one physical line per instance.
|
|
55
|
+
const id = String(applied[0]?.discount?.resource_id ?? '');
|
|
56
|
+
const voucher = byId.get(id);
|
|
57
|
+
if (quantity(item) !== 1 || applied.length !== 1 || !ids.has(id) || !voucher?.isAvailable || voucher.config?.isAvailable === false || usedIds.has(id)) throw voucherGroupError();
|
|
58
|
+
usedIds.add(id);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (order.products.some(item => !groups.some(group => group.key === productVoucherGroupKey(order, item)))) {
|
|
62
|
+
throw voucherGroupError();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -121,8 +121,9 @@ export declare function getBundleSellingMagnitude(bundle: Record<string, any> |
|
|
|
121
121
|
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
122
122
|
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
|
|
123
123
|
* 不含折扣。**权威源**。
|
|
124
|
-
* - `
|
|
125
|
-
* - `metadata.
|
|
124
|
+
* - `product_sku.option[].add_price` 保留单规格折前单价;Rules 的 option.price 只用于本次计算。
|
|
125
|
+
* - `metadata.main_product_original_price` = source + Σ(option.add_price × option.num)(含 option、不含折扣)。
|
|
126
|
+
* - `metadata.main_product_selling_price` = main_original − 行内 per-unit amount(含主商品及 option 优惠)。
|
|
126
127
|
* - `payment_price`:出站 payload 中为行 composite 已减整单折扣均摊价(无折扣时与 `selling_price` 同义)。
|
|
127
128
|
*
|
|
128
129
|
* Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
|
|
@@ -131,8 +132,9 @@ export declare function getBundleSellingMagnitude(bundle: Record<string, any> |
|
|
|
131
132
|
* `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
|
|
132
133
|
* - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
|
|
133
134
|
* total(source + option + bundle)对齐。
|
|
135
|
+
* - `getProduct.options` 用单规格原价参与重算;主商品折后价从 main_selling 减去 option 折后合计反推。
|
|
134
136
|
* - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
|
|
135
|
-
*
|
|
137
|
+
* 加回单规格原价合计,再减去 optionDiscountAmount;保留订单单规格原价供取消折扣及后续重算。
|
|
136
138
|
* 优先级:
|
|
137
139
|
* 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
|
|
138
140
|
* 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
|
|
@@ -632,8 +632,9 @@ function getBundleSellingMagnitude(bundle) {
|
|
|
632
632
|
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
633
633
|
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
|
|
634
634
|
* 不含折扣。**权威源**。
|
|
635
|
-
* - `
|
|
636
|
-
* - `metadata.
|
|
635
|
+
* - `product_sku.option[].add_price` 保留单规格折前单价;Rules 的 option.price 只用于本次计算。
|
|
636
|
+
* - `metadata.main_product_original_price` = source + Σ(option.add_price × option.num)(含 option、不含折扣)。
|
|
637
|
+
* - `metadata.main_product_selling_price` = main_original − 行内 per-unit amount(含主商品及 option 优惠)。
|
|
637
638
|
* - `payment_price`:出站 payload 中为行 composite 已减整单折扣均摊价(无折扣时与 `selling_price` 同义)。
|
|
638
639
|
*
|
|
639
640
|
* Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
|
|
@@ -642,8 +643,9 @@ function getBundleSellingMagnitude(bundle) {
|
|
|
642
643
|
* `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
|
|
643
644
|
* - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
|
|
644
645
|
* total(source + option + bundle)对齐。
|
|
646
|
+
* - `getProduct.options` 用单规格原价参与重算;主商品折后价从 main_selling 减去 option 折后合计反推。
|
|
645
647
|
* - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
|
|
646
|
-
*
|
|
648
|
+
* 加回单规格原价合计,再减去 optionDiscountAmount;保留订单单规格原价供取消折扣及后续重算。
|
|
647
649
|
* 优先级:
|
|
648
650
|
* 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
|
|
649
651
|
* 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
|
|
@@ -842,6 +844,14 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
842
844
|
const effectiveNum = Number(num) > 0 ? Number(num) : 1;
|
|
843
845
|
return new _decimal.default(Number(totalLike) || 0).dividedBy(effectiveNum).toDecimalPlaces(2).toString();
|
|
844
846
|
};
|
|
847
|
+
|
|
848
|
+
// optionDiscountAmount 已是每件主商品内的单规格优惠合计,不再乘商品数量。
|
|
849
|
+
const getOptionDiscountAmount = discountList => {
|
|
850
|
+
return (discountList || []).reduce((total, discount) => {
|
|
851
|
+
if (discount?.metadata?.custom_product_bundle_map_id) return total;
|
|
852
|
+
return total.plus(Number(discount?.metadata?.optionDiscountAmount) || 0);
|
|
853
|
+
}, new _decimal.default(0));
|
|
854
|
+
};
|
|
845
855
|
const getBundleIdentity = bundle => {
|
|
846
856
|
return [bundle.bundle_id ?? bundle.id ?? '', bundle.bundle_product_id ?? bundle._bundle_product_id ?? bundle.product_id ?? '', bundle.bundle_variant_id ?? bundle.variant_id ?? bundle.product_variant_id ?? 0, bundle.bundle_group_id ?? bundle.group_id ?? ''].join('|');
|
|
847
857
|
};
|
|
@@ -884,12 +894,14 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
884
894
|
getProduct: product => {
|
|
885
895
|
// source_product_price 是权威源;兜底链:source → mainSelling − options(反推)→ 行 selling_price
|
|
886
896
|
const metadataAny = product.metadata || {};
|
|
887
|
-
const
|
|
897
|
+
const productOptions = getProductSkuOptions(product);
|
|
898
|
+
const optionSum = sumOptionUnitPrice(productOptions);
|
|
899
|
+
const optionSellingSum = optionSum.minus(getOptionDiscountAmount(product.discount_list));
|
|
888
900
|
let sourcePrice;
|
|
889
901
|
if (metadataAny.source_product_price !== undefined) {
|
|
890
902
|
sourcePrice = String(metadataAny.source_product_price);
|
|
891
903
|
} else if (metadataAny.main_product_selling_price !== undefined) {
|
|
892
|
-
sourcePrice = new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(
|
|
904
|
+
sourcePrice = new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSellingSum).toDecimalPlaces(2).toString();
|
|
893
905
|
} else {
|
|
894
906
|
sourcePrice = String(product.selling_price ?? 0);
|
|
895
907
|
}
|
|
@@ -919,6 +931,11 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
919
931
|
num: product.num || 1,
|
|
920
932
|
discount_list: product.discount_list || [],
|
|
921
933
|
bundle: product.product_bundle || [],
|
|
934
|
+
// 仅在 Rules 入参中映射 price,避免折后价污染订单的 add_price。
|
|
935
|
+
options: productOptions.map(option => ({
|
|
936
|
+
...option,
|
|
937
|
+
price: option.add_price
|
|
938
|
+
})),
|
|
922
939
|
booking_id: product.metadata?.booking_id || null,
|
|
923
940
|
isClient: false,
|
|
924
941
|
// 勿写死 false:否则 Rules 不会走 total≠origin_total 的手动价推断,
|
|
@@ -926,7 +943,7 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
926
943
|
isManualDiscount: resolveRulesManualDiscountFlag(metadataAny),
|
|
927
944
|
holder_id: product.metadata?.holder_id,
|
|
928
945
|
startDate: getProductStartDate(product),
|
|
929
|
-
main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(
|
|
946
|
+
main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSellingSum).toDecimalPlaces(2).toString() : undefined,
|
|
930
947
|
inPromotion: metadataAny._promotion?.inPromotion === true,
|
|
931
948
|
_promotion: metadataAny._promotion
|
|
932
949
|
};
|
|
@@ -937,8 +954,10 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
937
954
|
const existedSource = metadataAny.source_product_price ?? product.selling_price ?? '0';
|
|
938
955
|
const nextOptions = getProductSkuOptions(product);
|
|
939
956
|
const optionSum = sumOptionUnitPrice(nextOptions);
|
|
957
|
+
const nextDiscountList = values.discount_list ?? product.discount_list;
|
|
958
|
+
const optionSellingSum = optionSum.minus(getOptionDiscountAmount(nextDiscountList));
|
|
940
959
|
|
|
941
|
-
// Rules 返回的 main_product_selling_price / price
|
|
960
|
+
// Rules 返回的 main_product_selling_price / price 为不含 option 的主商品价。
|
|
942
961
|
// 优先级:main_product_selling_price(per-unit 券后 source)> price(还原/good_pass 分支)>
|
|
943
962
|
// total/num(仅当 Rules 只给 total 时的兜底)> 保留当前 source。
|
|
944
963
|
const nextSourceSellingPrice = values.main_product_selling_price !== undefined ? String(values.main_product_selling_price) : values.price !== undefined ? String(values.price) : values.total !== undefined ? toUnitPriceString(values.total, nextNum) : String(existedSource);
|
|
@@ -947,8 +966,8 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
947
966
|
// 缺省时保留现有 source(券前 = 当前 source)。
|
|
948
967
|
const nextSourceOriginalPrice = values.original_price !== undefined ? String(values.original_price) : String(existedSource);
|
|
949
968
|
|
|
950
|
-
//
|
|
951
|
-
const nextMainSellingPrice = new _decimal.default(Number(nextSourceSellingPrice) || 0).plus(
|
|
969
|
+
// 成交价只加回 option 折后合计;原价仍使用订单中保存的 option 原价。
|
|
970
|
+
const nextMainSellingPrice = new _decimal.default(Number(nextSourceSellingPrice) || 0).plus(optionSellingSum).toDecimalPlaces(2).toFixed(2);
|
|
952
971
|
const nextMainOriginalPrice = new _decimal.default(Number(nextSourceOriginalPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
953
972
|
const nextBundle = values.bundle !== undefined ? mergeRulesBundlePrices(product.product_bundle, values.bundle) : product.product_bundle;
|
|
954
973
|
const composedSellingPrice = composeLinePrice({
|
|
@@ -969,7 +988,7 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
969
988
|
...product,
|
|
970
989
|
selling_price: composedSellingPrice,
|
|
971
990
|
original_price: finalOriginalPrice,
|
|
972
|
-
discount_list:
|
|
991
|
+
discount_list: nextDiscountList,
|
|
973
992
|
num: values.quantity ?? product.num,
|
|
974
993
|
product_bundle: nextBundle,
|
|
975
994
|
metadata: {
|
|
@@ -66,7 +66,13 @@ class ProductList extends _BaseModule.BaseModule {
|
|
|
66
66
|
* productList.updateOtherParams({ channel: 'pos' });
|
|
67
67
|
*/
|
|
68
68
|
updateOtherParams(params) {
|
|
69
|
+
const previousScope = this.otherParams.catalogScopeKey;
|
|
69
70
|
this.otherParams = params || {};
|
|
71
|
+
if (previousScope !== this.otherParams.catalogScopeKey && (previousScope || this.otherParams.catalogScopeKey)) {
|
|
72
|
+
this.store.list = [];
|
|
73
|
+
this.rawProductPriceSources.clear();
|
|
74
|
+
this.core.effects.emit(`${this.name}:changed`, this.store.list);
|
|
75
|
+
}
|
|
70
76
|
}
|
|
71
77
|
async storeChange(path, value) {
|
|
72
78
|
// No longer needed - products are stored as plain objects instead of Product instances
|
|
@@ -101,6 +107,12 @@ class ProductList extends _BaseModule.BaseModule {
|
|
|
101
107
|
status = 'published',
|
|
102
108
|
strategy_context
|
|
103
109
|
} = {}, options) {
|
|
110
|
+
const scope = this.otherParams.catalogScopeKey;
|
|
111
|
+
const assertScope = () => {
|
|
112
|
+
if (scope !== this.otherParams.catalogScopeKey) throw Object.assign(new Error('Product catalog context changed'), {
|
|
113
|
+
name: 'AbortError'
|
|
114
|
+
});
|
|
115
|
+
};
|
|
104
116
|
// // 如果 schedule_ids 为空,则需要尝试从 schedule 模块里获取
|
|
105
117
|
// if (!schedule_ids?.length) {
|
|
106
118
|
// const schedule_ids_data = this.store.schedule
|
|
@@ -180,6 +192,7 @@ class ProductList extends _BaseModule.BaseModule {
|
|
|
180
192
|
const handledByOsServer = (0, _clientDataVariants.isProductQueryHandledByOsServer)(this.core, this.request);
|
|
181
193
|
const originalCallback = options?.callback;
|
|
182
194
|
const subscriptionCallback = typeof originalCallback === 'function' ? async result => {
|
|
195
|
+
if (scope !== this.otherParams.catalogScopeKey) return;
|
|
183
196
|
const callbackList = result?.data?.list;
|
|
184
197
|
if (!Array.isArray(callbackList)) {
|
|
185
198
|
originalCallback(result);
|
|
@@ -197,6 +210,7 @@ class ProductList extends _BaseModule.BaseModule {
|
|
|
197
210
|
queryPayload,
|
|
198
211
|
handledByOsServer
|
|
199
212
|
});
|
|
213
|
+
assertScope();
|
|
200
214
|
await this.addProduct(products);
|
|
201
215
|
originalCallback(handledByOsServer ? result : {
|
|
202
216
|
...result,
|
|
@@ -212,6 +226,7 @@ class ProductList extends _BaseModule.BaseModule {
|
|
|
212
226
|
subscriberId: options?.subscriberId,
|
|
213
227
|
customToast: () => {}
|
|
214
228
|
});
|
|
229
|
+
assertScope();
|
|
215
230
|
if (!handledByOsServer && Array.isArray(productsData.data.list)) {
|
|
216
231
|
this.replaceRawProductQueryResult(productsData.data.list, product_ids);
|
|
217
232
|
}
|
|
@@ -9,6 +9,8 @@ export declare class RulesModule extends BaseModule implements Module, RulesModu
|
|
|
9
9
|
private store;
|
|
10
10
|
window: WindowPlugin;
|
|
11
11
|
private hooks;
|
|
12
|
+
private discountScope?;
|
|
13
|
+
setDiscountScope(scope: (product: any, discount: Discount) => boolean): void;
|
|
12
14
|
constructor(name?: string, version?: string);
|
|
13
15
|
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
14
16
|
setRulesList(rulesList: Rules[]): Promise<void>;
|