@pisell/pisellos 0.0.569 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.js +10 -6
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -3
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/model/strategy/adapter/walletPass/evaluator.js +7 -5
- package/dist/model/strategy/adapter/walletPass/example.js +26 -3
- package/dist/model/strategy/adapter/walletPass/index.js +5 -5
- package/dist/model/strategy/adapter/walletPass/type.d.ts +0 -3
- package/dist/model/strategy/adapter/walletPass/utils.d.ts +0 -26
- package/dist/model/strategy/adapter/walletPass/utils.js +17 -92
- package/dist/model/strategy/strategy-example.js +19 -5
- package/dist/modules/BaseModule.d.ts +1 -1
- package/dist/modules/BaseModule.js +8 -10
- package/dist/modules/Cart/index.js +3 -0
- package/dist/modules/Cart/utils/cartProduct.js +1 -0
- package/dist/modules/Cart/utils/cartResource.js +0 -2
- package/dist/modules/Cart/utils/changePrice.js +9 -16
- package/dist/modules/Date/index.js +5 -1
- package/dist/modules/Discount/index.d.ts +0 -1
- package/dist/modules/Discount/index.js +7 -22
- package/dist/modules/Discount/types.d.ts +0 -1
- package/dist/modules/OpenData/index.js +2 -0
- package/dist/modules/Order/index.js +70 -40
- package/dist/modules/Payment/index.js +162 -97
- package/dist/modules/Payment/types.d.ts +4 -8
- package/dist/modules/Payment/walletpass.d.ts +0 -2
- package/dist/modules/Payment/walletpass.js +5 -4
- package/dist/modules/ProductList/index.d.ts +1 -1
- package/dist/modules/ProductList/index.js +3 -12
- package/dist/modules/ProductList/types.d.ts +0 -1
- package/dist/modules/Rules/index.js +126 -427
- package/dist/modules/SalesSummary/utils.js +1 -2
- package/dist/modules/Schedule/getDateIsInSchedule.js +0 -5
- package/dist/modules/Schedule/index.js +1 -0
- package/dist/modules/Schedule/utils.js +1 -0
- package/dist/modules/Step/index.js +1 -0
- package/dist/modules/Summary/utils.js +22 -43
- package/dist/plugins/request.js +4 -1
- package/dist/plugins/window.js +6 -2
- package/dist/server/index.js +129 -97
- package/dist/server/modules/menu/index.js +41 -32
- package/dist/server/modules/order/index.js +4 -2
- package/dist/server/modules/products/index.js +42 -24
- package/dist/server/modules/quotation/index.js +38 -29
- package/dist/server/modules/resource/index.js +4 -3
- package/dist/server/modules/schedule/index.js +35 -27
- package/dist/server/utils/product.js +1 -0
- package/dist/solution/BaseSales/index.js +41 -38
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingByStep/index.js +60 -11
- package/dist/solution/BookingByStep/utils/capacity.js +11 -1
- package/dist/solution/BookingByStep/utils/resources.js +3 -1
- package/dist/solution/BookingByStep/utils/timeslots.js +43 -2
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +2 -0
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +7 -6
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +31 -25
- package/dist/solution/BookingTicket/utils/scan/index.js +10 -6
- package/dist/solution/BuyTickets/index.js +12 -9
- package/dist/solution/Checkout/index.js +252 -177
- package/dist/solution/Checkout/utils/index.js +16 -4
- package/dist/solution/RegisterAndLogin/index.js +76 -30
- package/dist/solution/ScanOrder/index.js +60 -50
- package/dist/solution/ShopDiscount/index.js +14 -15
- package/dist/solution/ShopDiscount/types.d.ts +4 -5
- package/dist/solution/ShopDiscount/utils.d.ts +0 -9
- package/dist/solution/ShopDiscount/utils.js +0 -9
- package/dist/solution/VenueBooking/index.d.ts +3 -31
- package/dist/solution/VenueBooking/index.js +496 -651
- package/dist/solution/VenueBooking/types.d.ts +1 -3
- package/dist/solution/VenueBooking/types.js +0 -1
- package/dist/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
- package/dist/solution/VenueBooking/utils/dateSummary.js +25 -12
- package/dist/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
- package/dist/solution/VenueBooking/utils/timeSlot.js +4 -9
- package/dist/types/index.d.ts +1 -1
- package/dist/utils/task.js +18 -15
- package/dist/utils/watch.js +1 -0
- package/lib/apis/picoding.js +0 -2
- package/lib/core/index.js +132 -130
- package/lib/effects/index.js +57 -46
- package/lib/index.d.ts +0 -1
- package/lib/index.js +50 -92
- package/lib/model/index.js +21 -14
- package/lib/model/strategy/adapter/dataVariant/adapter.js +50 -38
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +236 -162
- package/lib/model/strategy/adapter/dataVariant/examples.js +237 -229
- package/lib/model/strategy/adapter/dataVariant/index.js +34 -39
- package/lib/model/strategy/adapter/dataVariant/type.js +28 -57
- package/lib/model/strategy/adapter/index.js +64 -100
- package/lib/model/strategy/adapter/itemRule/adapter.js +144 -156
- package/lib/model/strategy/adapter/itemRule/evaluator.js +48 -36
- package/lib/model/strategy/adapter/itemRule/examples.js +225 -295
- package/lib/model/strategy/adapter/itemRule/index.js +57 -83
- package/lib/model/strategy/adapter/itemRule/type.js +36 -97
- package/lib/model/strategy/adapter/promotion/adapter.js +63 -84
- package/lib/model/strategy/adapter/promotion/evaluator.js +231 -381
- package/lib/model/strategy/adapter/promotion/examples.js +159 -139
- package/lib/model/strategy/adapter/promotion/index.js +49 -1
- package/lib/model/strategy/adapter/promotion/type.js +35 -199
- package/lib/model/strategy/adapter/type.js +16 -4
- package/lib/model/strategy/adapter/walletPass/evaluator.js +152 -180
- package/lib/model/strategy/adapter/walletPass/example.js +190 -217
- package/lib/model/strategy/adapter/walletPass/index.js +51 -75
- package/lib/model/strategy/adapter/walletPass/locales.js +58 -36
- package/lib/model/strategy/adapter/walletPass/type.d.ts +0 -3
- package/lib/model/strategy/adapter/walletPass/type.js +16 -4
- package/lib/model/strategy/adapter/walletPass/utils.d.ts +0 -26
- package/lib/model/strategy/adapter/walletPass/utils.js +383 -678
- package/lib/model/strategy/engine.js +168 -270
- package/lib/model/strategy/index.js +34 -49
- package/lib/model/strategy/strategy-example.js +239 -243
- package/lib/model/strategy/type.js +40 -100
- package/lib/modules/Account/index.js +53 -39
- package/lib/modules/Account/types.js +33 -20
- package/lib/modules/AccountList/index.js +154 -116
- package/lib/modules/AccountList/types.js +31 -30
- package/lib/modules/AccountList/utils.js +30 -18
- package/lib/modules/BaseModule.d.ts +1 -1
- package/lib/modules/BaseModule.js +46 -25
- package/lib/modules/BookingContext/index.js +136 -158
- package/lib/modules/BookingContext/types.js +32 -46
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +143 -131
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +82 -75
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +150 -170
- package/lib/modules/BookingContext/utils/flexible.js +55 -38
- package/lib/modules/BookingContext/utils/formatResourceList.js +34 -19
- package/lib/modules/BookingContext/utils/index.js +41 -124
- package/lib/modules/BookingContext/utils/noResource.js +70 -58
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +41 -14
- package/lib/modules/BookingContext/utils/productExtend.js +155 -202
- package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
- package/lib/modules/BookingContext/utils/resourceSelection.js +41 -19
- package/lib/modules/BookingContext/utils/resources.js +167 -209
- package/lib/modules/BookingContext/utils/serviceTimes.js +116 -115
- package/lib/modules/BookingContext/utils/timeSlices.js +80 -70
- package/lib/modules/Cart/index.js +124 -170
- package/lib/modules/Cart/types.js +51 -46
- package/lib/modules/Cart/utils/cartAccount.js +39 -40
- package/lib/modules/Cart/utils/cartDate.js +61 -56
- package/lib/modules/Cart/utils/cartDiscount.js +33 -28
- package/lib/modules/Cart/utils/cartNote.js +32 -27
- package/lib/modules/Cart/utils/cartProduct.js +251 -321
- package/lib/modules/Cart/utils/cartRelationForms.js +35 -29
- package/lib/modules/Cart/utils/cartResource.js +78 -72
- package/lib/modules/Cart/utils/changePrice.js +50 -28
- package/lib/modules/Cart/utils/index.js +48 -106
- package/lib/modules/Customer/constants.js +34 -13
- package/lib/modules/Customer/index.js +169 -232
- package/lib/modules/Customer/types.js +35 -38
- package/lib/modules/Date/index.js +115 -116
- package/lib/modules/Date/types.js +28 -16
- package/lib/modules/Date/utils.js +123 -174
- package/lib/modules/Discount/index.d.ts +0 -1
- package/lib/modules/Discount/index.js +128 -130
- package/lib/modules/Discount/types.d.ts +0 -1
- package/lib/modules/Discount/types.js +31 -9
- package/lib/modules/Guests/index.js +56 -30
- package/lib/modules/Guests/types.js +33 -23
- package/lib/modules/Holder/index.js +189 -209
- package/lib/modules/Holder/types.js +16 -4
- package/lib/modules/Holder/utils.js +49 -20
- package/lib/modules/OpenData/index.js +76 -69
- package/lib/modules/OpenData/types.js +16 -4
- package/lib/modules/OpenData/utils.js +78 -44
- package/lib/modules/Order/index.js +1909 -1572
- package/lib/modules/Order/types.js +35 -78
- package/lib/modules/Order/utils/bundleDiscountHydration.js +74 -41
- package/lib/modules/Order/utils/manualProductDiscount.js +123 -124
- package/lib/modules/Order/utils/orderCollectionIdentity.js +210 -148
- package/lib/modules/Order/utils.js +634 -799
- package/lib/modules/Payment/cash.js +33 -20
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +76 -145
- package/lib/modules/Payment/eftpos.js +30 -16
- package/lib/modules/Payment/index.js +378 -518
- package/lib/modules/Payment/mx51.js +0 -1
- package/lib/modules/Payment/types.d.ts +4 -8
- package/lib/modules/Payment/types.js +107 -216
- package/lib/modules/Payment/utils.js +48 -51
- package/lib/modules/Payment/walletpass.d.ts +0 -2
- package/lib/modules/Payment/walletpass.js +211 -226
- package/lib/modules/Product/index.js +46 -51
- package/lib/modules/Product/types.js +16 -4
- package/lib/modules/Product/utils.js +33 -32
- package/lib/modules/ProductList/index.d.ts +1 -1
- package/lib/modules/ProductList/index.js +117 -117
- package/lib/modules/ProductList/types.d.ts +0 -1
- package/lib/modules/ProductList/types.js +31 -9
- package/lib/modules/Quotation/index.js +100 -66
- package/lib/modules/Quotation/types.js +16 -4
- package/lib/modules/Resource/index.js +59 -27
- package/lib/modules/Resource/types.js +32 -22
- package/lib/modules/Resource/utils.js +38 -30
- package/lib/modules/ResourcePlanner/index.js +61 -60
- package/lib/modules/ResourcePlanner/planner.js +384 -346
- package/lib/modules/ResourcePlanner/types.js +16 -4
- package/lib/modules/Rules/index.js +903 -1475
- package/lib/modules/Rules/types.js +40 -17
- package/lib/modules/SalesSummary/index.js +90 -85
- package/lib/modules/SalesSummary/types.js +16 -4
- package/lib/modules/SalesSummary/utils.js +427 -351
- package/lib/modules/ScanOrderLogger/index.js +79 -59
- package/lib/modules/ScanOrderLogger/providers/feishu.js +78 -54
- package/lib/modules/ScanOrderLogger/providers/grafana.js +36 -13
- package/lib/modules/ScanOrderLogger/types.js +16 -4
- package/lib/modules/Schedule/getDateIsInSchedule.js +163 -339
- package/lib/modules/Schedule/index.js +114 -100
- package/lib/modules/Schedule/type.js +16 -4
- package/lib/modules/Schedule/types.js +16 -4
- package/lib/modules/Schedule/utils.js +291 -433
- package/lib/modules/Step/index.js +52 -40
- package/lib/modules/Step/tyeps.js +16 -4
- package/lib/modules/Summary/index.js +71 -66
- package/lib/modules/Summary/types.js +16 -4
- package/lib/modules/Summary/utils.js +418 -791
- package/lib/modules/SurchargeList/index.js +60 -46
- package/lib/modules/SurchargeList/types.js +16 -4
- package/lib/modules/index.js +63 -245
- package/lib/plugins/app.js +16 -4
- package/lib/plugins/index.js +25 -36
- package/lib/plugins/request.js +126 -137
- package/lib/plugins/shopStore.js +16 -4
- package/lib/plugins/user.js +16 -4
- package/lib/plugins/window.js +179 -171
- package/lib/server/index.js +2337 -2675
- package/lib/server/modules/floor-plan/index.js +123 -102
- package/lib/server/modules/floor-plan/types.js +30 -15
- package/lib/server/modules/index.js +68 -106
- package/lib/server/modules/menu/index.js +122 -146
- package/lib/server/modules/menu/types.js +31 -18
- package/lib/server/modules/order/index.js +642 -567
- package/lib/server/modules/order/types.js +32 -117
- package/lib/server/modules/order/utils/filterBookings.js +194 -219
- package/lib/server/modules/order/utils/filterOrders.js +92 -118
- package/lib/server/modules/payment/index.js +83 -59
- package/lib/server/modules/payment/types.js +16 -4
- package/lib/server/modules/products/index.js +459 -575
- package/lib/server/modules/products/types.js +34 -44
- package/lib/server/modules/quotation/index.js +172 -137
- package/lib/server/modules/quotation/types.js +31 -21
- package/lib/server/modules/resource/index.js +184 -213
- package/lib/server/modules/resource/types.js +33 -42
- package/lib/server/modules/schedule/index.js +123 -135
- package/lib/server/modules/schedule/types.js +21 -14
- package/lib/server/modules/schedule/utils.js +163 -334
- package/lib/server/types.js +16 -4
- package/lib/server/utils/index.js +23 -25
- package/lib/server/utils/product.js +139 -196
- package/lib/server/utils/schedule.js +41 -34
- package/lib/server/utils/small-ticket.js +456 -478
- package/lib/server/utils/time.js +49 -40
- package/lib/solution/BaseSales/index.js +1016 -850
- package/lib/solution/BaseSales/types.js +37 -41
- package/lib/solution/BaseSales/utils/cartPromotion.js +460 -611
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +105 -85
- package/lib/solution/BaseSales/utils/quotationPrice.js +114 -56
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +143 -102
- package/lib/solution/BaseSales/utils.js +140 -155
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1340 -1530
- package/lib/solution/BookingByStep/types.js +99 -40
- package/lib/solution/BookingByStep/utils/capacity.js +160 -192
- package/lib/solution/BookingByStep/utils/products.js +52 -42
- package/lib/solution/BookingByStep/utils/resources.js +330 -527
- package/lib/solution/BookingByStep/utils/stock.js +44 -65
- package/lib/solution/BookingByStep/utils/timeslots.js +131 -129
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +459 -543
- package/lib/solution/BookingTicket/types.js +77 -99
- package/lib/solution/BookingTicket/utils/addProductDecision.js +184 -219
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +89 -58
- package/lib/solution/BookingTicket/utils/bookingStatus.js +78 -107
- package/lib/solution/BookingTicket/utils/cartView.js +94 -110
- package/lib/solution/BookingTicket/utils/exampleData.js +0 -185
- package/lib/solution/BookingTicket/utils/orderCustomer.js +41 -18
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +86 -219
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +93 -144
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +91 -79
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +41 -54
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +81 -84
- package/lib/solution/BookingTicket/utils/scan/index.js +104 -98
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +43 -90
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +64 -52
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +58 -56
- package/lib/solution/BuyTickets/index.js +70 -67
- package/lib/solution/BuyTickets/types.js +38 -22
- package/lib/solution/Checkout/index.js +1158 -1451
- package/lib/solution/Checkout/types.js +61 -91
- package/lib/solution/Checkout/utils/index.js +156 -228
- package/lib/solution/PlaceOrder/index.js +0 -55
- package/lib/solution/RegisterAndLogin/config.js +460 -493
- package/lib/solution/RegisterAndLogin/index.js +630 -633
- package/lib/solution/RegisterAndLogin/types.js +76 -189
- package/lib/solution/RegisterAndLogin/utils.js +125 -183
- package/lib/solution/Sales/index.js +320 -317
- package/lib/solution/Sales/types.js +33 -27
- package/lib/solution/ScanOrder/index.js +862 -831
- package/lib/solution/ScanOrder/types.js +34 -33
- package/lib/solution/ScanOrder/utils.js +371 -406
- package/lib/solution/ShopDiscount/index.js +233 -235
- package/lib/solution/ShopDiscount/types.d.ts +4 -5
- package/lib/solution/ShopDiscount/types.js +37 -15
- package/lib/solution/ShopDiscount/utils.d.ts +0 -9
- package/lib/solution/ShopDiscount/utils.js +172 -309
- package/lib/solution/UnifiedBookingSales/index.js +405 -379
- package/lib/solution/UnifiedBookingSales/types.js +31 -12
- package/lib/solution/VenueBooking/index.d.ts +3 -31
- package/lib/solution/VenueBooking/index.js +916 -967
- package/lib/solution/VenueBooking/types.d.ts +1 -3
- package/lib/solution/VenueBooking/types.js +39 -20
- package/lib/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
- package/lib/solution/VenueBooking/utils/dateSummary.js +62 -25
- package/lib/solution/VenueBooking/utils/resource.js +54 -31
- package/lib/solution/VenueBooking/utils/slotMerge.js +107 -94
- package/lib/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
- package/lib/solution/VenueBooking/utils/timeSlot.js +133 -138
- package/lib/solution/VenueBooking/utils.js +67 -130
- package/lib/solution/index.js +41 -124
- package/lib/store/createStore.js +29 -32
- package/lib/types/index.d.ts +1 -1
- package/lib/types/index.js +16 -4
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +47 -81
- package/package.json +2 -4
- package/dist/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
- package/dist/solution/VenueBooking/utils/smartPricing.js +0 -233
- package/lib/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
- package/lib/solution/VenueBooking/utils/smartPricing.js +0 -192
|
@@ -1,137 +1,94 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Object.
|
|
4
|
-
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/solution/BaseSales/utils/cartPromotion.ts
|
|
30
|
+
var cartPromotion_exports = {};
|
|
31
|
+
__export(cartPromotion_exports, {
|
|
32
|
+
appendPromotionTags: () => appendPromotionTags,
|
|
33
|
+
buildConsolidateKeyForPromotion: () => buildConsolidateKeyForPromotion,
|
|
34
|
+
calculateUnfulfilledPromotions: () => calculateUnfulfilledPromotions,
|
|
35
|
+
extractProductMatchIdentifiersFromStrategyConfig: () => extractProductMatchIdentifiersFromStrategyConfig,
|
|
36
|
+
getOrderProductBasePrice: () => getOrderProductBasePrice,
|
|
37
|
+
getOrderProductOriginalPriceForPromotion: () => getOrderProductOriginalPriceForPromotion,
|
|
38
|
+
getOrderProductUid: () => getOrderProductUid,
|
|
39
|
+
mergeIdenticalPromotionCartLines: () => mergeIdenticalPromotionCartLines,
|
|
40
|
+
processCartPromotion: () => processCartPromotion,
|
|
41
|
+
resolveStrategyEligibleProducts: () => resolveStrategyEligibleProducts,
|
|
42
|
+
resolveStrategyRequiredQuantity: () => resolveStrategyRequiredQuantity
|
|
5
43
|
});
|
|
6
|
-
exports
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
exports.getOrderProductOriginalPriceForPromotion = getOrderProductOriginalPriceForPromotion;
|
|
12
|
-
exports.getOrderProductUid = getOrderProductUid;
|
|
13
|
-
exports.mergeIdenticalPromotionCartLines = mergeIdenticalPromotionCartLines;
|
|
14
|
-
exports.processCartPromotion = processCartPromotion;
|
|
15
|
-
exports.resolveStrategyEligibleProducts = resolveStrategyEligibleProducts;
|
|
16
|
-
exports.resolveStrategyRequiredQuantity = resolveStrategyRequiredQuantity;
|
|
17
|
-
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
18
|
-
var _lodashEs = require("lodash-es");
|
|
19
|
-
var _utils = require("../../../modules/Order/utils");
|
|
20
|
-
var _utils2 = require("../../ScanOrder/utils");
|
|
21
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
22
|
-
/**
|
|
23
|
-
* Cart promotion 工具集(OS 内部纯函数)
|
|
24
|
-
*
|
|
25
|
-
* 这是 `private-materials/components/booking/hooks/usePromotion.ts` 中促销/赠品
|
|
26
|
-
* 核心计算(evaluator → 拆分 / 计价 → 赠品差异化 / 未满足提示 / 标签)的 OS 等价实现。
|
|
27
|
-
*
|
|
28
|
-
* 与 legacy 的关键差异:
|
|
29
|
-
* - legacy 操作 booking `_extend.*` 形状;OS 操作 `OrderProduct.metadata.*` 形状。
|
|
30
|
-
* - 行唯一标识不再用 `_id`,统一改用 `metadata.unique_identification_number`。
|
|
31
|
-
* - 赠品标签存到 `metadata._giftInfo`;主商品促销信息存到 `metadata._promotion`;
|
|
32
|
-
* 商品卡列表的促销 tag 存到 `metadata._promotionTags`。
|
|
33
|
-
*
|
|
34
|
-
* 仅暴露纯函数,不持有任何状态;评估器以参数注入。
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* const evaluator = appHelper.utils.promotionEvaluator;
|
|
38
|
-
* const result = processCartPromotion(tempOrder.products, evaluator);
|
|
39
|
-
* // result.products: 处理后的商品(带 _promotion / 拆分)
|
|
40
|
-
* // result.giftActions: 需要 add / reduce / remove 的赠品操作
|
|
41
|
-
* // result.unfulfilledPromotions: 未满足策略列表(购物车底部 alert)
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
|
-
// ============================================
|
|
45
|
-
// 类型定义
|
|
46
|
-
// ============================================
|
|
47
|
-
|
|
48
|
-
/** Cart 评估器协议(只描述本文件用到的方法,避免循环依赖) */
|
|
49
|
-
|
|
50
|
-
/** 单个赠品减量项 */
|
|
51
|
-
|
|
52
|
-
/** 赠品新增项 */
|
|
53
|
-
|
|
54
|
-
/** 赠品操作集合(OS 侧根据它落地 tempOrder.products) */
|
|
55
|
-
|
|
56
|
-
/** 未满足促销提示项(购物车底部 alert 数据源) */
|
|
57
|
-
|
|
58
|
-
/** 商品卡促销标签结构(写入 `metadata._promotionTags`) */
|
|
59
|
-
|
|
60
|
-
/** processCartPromotion 输出 */
|
|
61
|
-
|
|
62
|
-
// ============================================
|
|
63
|
-
// 字段适配 helper
|
|
64
|
-
// ============================================
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* 获取商品的「主商品基础价」用于评估器入参。
|
|
68
|
-
*
|
|
69
|
-
* 优先级(与 OS v2 schema 一致):
|
|
70
|
-
* 1. `metadata.source_product_price`
|
|
71
|
-
* 2. `metadata.main_product_original_price` 减去 option 合计
|
|
72
|
-
* 3. `original_price`
|
|
73
|
-
*/
|
|
44
|
+
module.exports = __toCommonJS(cartPromotion_exports);
|
|
45
|
+
var import_decimal = __toESM(require("decimal.js"));
|
|
46
|
+
var import_lodash_es = require("lodash-es");
|
|
47
|
+
var import_utils = require("../../../modules/Order/utils");
|
|
48
|
+
var import_utils2 = require("../../ScanOrder/utils");
|
|
74
49
|
function getOrderProductBasePrice(product) {
|
|
75
|
-
const metadata = product
|
|
76
|
-
const optionSum = (0,
|
|
77
|
-
if (metadata.source_product_price !==
|
|
78
|
-
const
|
|
79
|
-
return Number.isFinite(
|
|
50
|
+
const metadata = (product == null ? void 0 : product.metadata) || {};
|
|
51
|
+
const optionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(product)).toNumber();
|
|
52
|
+
if (metadata.source_product_price !== void 0) {
|
|
53
|
+
const v2 = Number(metadata.source_product_price);
|
|
54
|
+
return Number.isFinite(v2) ? v2 : 0;
|
|
80
55
|
}
|
|
81
|
-
if (metadata.main_product_original_price !==
|
|
82
|
-
const
|
|
83
|
-
return Number.isFinite(
|
|
56
|
+
if (metadata.main_product_original_price !== void 0) {
|
|
57
|
+
const v2 = Number(metadata.main_product_original_price) - optionSum;
|
|
58
|
+
return Number.isFinite(v2) ? v2 : 0;
|
|
84
59
|
}
|
|
85
|
-
const v = Number(product
|
|
60
|
+
const v = Number((product == null ? void 0 : product.original_price) ?? (product == null ? void 0 : product.selling_price) ?? 0);
|
|
86
61
|
return Number.isFinite(v) ? v : 0;
|
|
87
62
|
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* 促销均摊专用原价(对齐 legacy `getMainOriginalPrice` 语义)。
|
|
91
|
-
*
|
|
92
|
-
* 必须用券前原价做 X_ITEMS_FOR_Y_PRICE 比例拆分;`source_product_price` 在上一轮 applyPromotion
|
|
93
|
-
* 后可能已被写成促销价(如 5 / 9 / 1),若继续用它会导致同商品两行出现 9+1 而非 5+5。
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* getOrderProductOriginalPriceForPromotion({ metadata: { source_product_price: '9', main_product_original_price: '5.80' } });
|
|
97
|
-
* // => 5.8
|
|
98
|
-
*/
|
|
99
63
|
function getOrderProductOriginalPriceForPromotion(product) {
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
64
|
+
var _a;
|
|
65
|
+
const metadata = (product == null ? void 0 : product.metadata) || {};
|
|
66
|
+
const optionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(product)).toNumber();
|
|
67
|
+
if (metadata.main_product_original_price !== void 0 && metadata.main_product_original_price !== null && metadata.main_product_original_price !== "") {
|
|
103
68
|
const v = Number(metadata.main_product_original_price) - optionSum;
|
|
104
|
-
if (Number.isFinite(v) && v >= 0)
|
|
69
|
+
if (Number.isFinite(v) && v >= 0)
|
|
70
|
+
return v;
|
|
105
71
|
}
|
|
106
|
-
const promoOriginal = metadata._promotion
|
|
107
|
-
if (promoOriginal !==
|
|
72
|
+
const promoOriginal = (_a = metadata._promotion) == null ? void 0 : _a.originalPrice;
|
|
73
|
+
if (promoOriginal !== void 0 && promoOriginal !== null && promoOriginal !== "") {
|
|
108
74
|
const v = Number(promoOriginal);
|
|
109
|
-
if (Number.isFinite(v) && v >= 0)
|
|
75
|
+
if (Number.isFinite(v) && v >= 0)
|
|
76
|
+
return v;
|
|
110
77
|
}
|
|
111
78
|
return getOrderProductBasePrice(product);
|
|
112
79
|
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* 写入/清除促销 discount_list(type=promotion)。
|
|
116
|
-
*
|
|
117
|
-
* applyDiscount → applyProductDiscountPrices 会从 source_product_price 减去 discount_list 合计
|
|
118
|
-
* 重算 main_product_selling_price;保留券前 source 时必须同步写入促销差额,否则会还原成原价。
|
|
119
|
-
*
|
|
120
|
-
* @example
|
|
121
|
-
* updatePromotionDiscountList(line, { title: '2 items for $10', amount: '17.00', original_amount: '22.00', fixed_amount: '17.00' });
|
|
122
|
-
*/
|
|
123
80
|
function updatePromotionDiscountList(item, promotionDiscount) {
|
|
124
81
|
let discountList = Array.isArray(item.discount_list) ? [...item.discount_list] : [];
|
|
125
|
-
discountList = discountList.filter(d => d
|
|
82
|
+
discountList = discountList.filter((d) => (d == null ? void 0 : d.type) !== "promotion");
|
|
126
83
|
if (promotionDiscount) {
|
|
127
84
|
discountList.push({
|
|
128
|
-
type:
|
|
85
|
+
type: "promotion",
|
|
129
86
|
amount: promotionDiscount.amount,
|
|
130
87
|
discount: {
|
|
131
88
|
original_amount: promotionDiscount.original_amount,
|
|
132
89
|
fixed_amount: promotionDiscount.fixed_amount,
|
|
133
90
|
title: promotionDiscount.title,
|
|
134
|
-
resource_id:
|
|
91
|
+
resource_id: ""
|
|
135
92
|
}
|
|
136
93
|
});
|
|
137
94
|
}
|
|
@@ -141,38 +98,30 @@ function updatePromotionDiscountList(item, promotionDiscount) {
|
|
|
141
98
|
delete item.discount_list;
|
|
142
99
|
}
|
|
143
100
|
}
|
|
144
|
-
|
|
145
|
-
const BUY_X_GET_Y_FREE = 'BUY_X_GET_Y_FREE';
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* 将促销单价写入 OrderProduct(含 metadata 三字段 + promotion discount_list)。
|
|
149
|
-
*
|
|
150
|
-
* @example
|
|
151
|
-
* applyPromoUnitPriceToLine(newItem, { promoUnitPrice: '5.00', originalBasePrice: 1, strategyTitle: '2 for 10' });
|
|
152
|
-
*/
|
|
101
|
+
var X_ITEMS_FOR_Y_PRICE = "X_ITEMS_FOR_Y_PRICE";
|
|
153
102
|
function applyPromoUnitPriceToLine(item, input) {
|
|
154
103
|
const metadata = item.metadata || (item.metadata = {});
|
|
155
|
-
const optionSum = (0,
|
|
156
|
-
const promoUnitPrice = new
|
|
157
|
-
const mainSelling = new
|
|
158
|
-
const catalogSource = new
|
|
104
|
+
const optionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(item)).toNumber();
|
|
105
|
+
const promoUnitPrice = new import_decimal.default(Number(input.promoUnitPrice) || 0).toDecimalPlaces(2).toFixed(2);
|
|
106
|
+
const mainSelling = new import_decimal.default(Number(promoUnitPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
107
|
+
const catalogSource = new import_decimal.default(input.originalBasePrice).toDecimalPlaces(2).toFixed(2);
|
|
159
108
|
metadata.source_product_price = catalogSource;
|
|
160
|
-
metadata.main_product_original_price = new
|
|
109
|
+
metadata.main_product_original_price = new import_decimal.default(Number(catalogSource) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
161
110
|
metadata.main_product_selling_price = mainSelling;
|
|
162
111
|
metadata.price_schema_version = 2;
|
|
163
|
-
item.selling_price = (0,
|
|
112
|
+
item.selling_price = (0, import_utils.composeLinePrice)({
|
|
164
113
|
mainPrice: mainSelling,
|
|
165
114
|
bundle: item.product_bundle
|
|
166
115
|
});
|
|
167
|
-
item.original_price = (0,
|
|
116
|
+
item.original_price = (0, import_utils.composeLinePrice)({
|
|
168
117
|
mainPrice: metadata.main_product_original_price,
|
|
169
118
|
bundle: item.product_bundle,
|
|
170
119
|
useOriginalBundle: true
|
|
171
120
|
});
|
|
172
|
-
const discountAmount = new
|
|
121
|
+
const discountAmount = new import_decimal.default(input.originalBasePrice).minus(Number(promoUnitPrice) || 0).toDecimalPlaces(2).toFixed(2);
|
|
173
122
|
if (Number(catalogSource) !== Number(promoUnitPrice)) {
|
|
174
123
|
updatePromotionDiscountList(item, {
|
|
175
|
-
title: input.strategyTitle ||
|
|
124
|
+
title: input.strategyTitle || "",
|
|
176
125
|
amount: discountAmount,
|
|
177
126
|
original_amount: catalogSource,
|
|
178
127
|
fixed_amount: discountAmount
|
|
@@ -182,86 +131,90 @@ function applyPromoUnitPriceToLine(item, input) {
|
|
|
182
131
|
}
|
|
183
132
|
}
|
|
184
133
|
function getPromotionActionType(promotion) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
134
|
+
var _a, _b;
|
|
135
|
+
if (promotion == null ? void 0 : promotion.actionType)
|
|
136
|
+
return String(promotion.actionType);
|
|
137
|
+
const actions = (_a = promotion == null ? void 0 : promotion.strategyMetadata) == null ? void 0 : _a.actions;
|
|
138
|
+
if (Array.isArray(actions) && ((_b = actions[0]) == null ? void 0 : _b.type))
|
|
139
|
+
return String(actions[0].type);
|
|
140
|
+
return void 0;
|
|
189
141
|
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* 同款行凑满 X件Y元 且仅该行参与时,按 Y/X 计算期望单价(2 件 $10 → $5)。
|
|
193
|
-
*
|
|
194
|
-
* @example
|
|
195
|
-
* resolveXItemsExpectedUnitPrice({ actionType: 'X_ITEMS_FOR_Y_PRICE', actionDetail: { x: 2, price: 10 } }, 2);
|
|
196
|
-
*/
|
|
197
142
|
function resolveXItemsExpectedUnitPrice(promotion, sourceCartNum) {
|
|
198
|
-
if (getPromotionActionType(promotion) !== X_ITEMS_FOR_Y_PRICE)
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
if (
|
|
204
|
-
|
|
143
|
+
if (getPromotionActionType(promotion) !== X_ITEMS_FOR_Y_PRICE)
|
|
144
|
+
return void 0;
|
|
145
|
+
const detail = promotion == null ? void 0 : promotion.actionDetail;
|
|
146
|
+
const x = Number(detail == null ? void 0 : detail.x);
|
|
147
|
+
const y = Number(detail == null ? void 0 : detail.price);
|
|
148
|
+
if (!Number.isFinite(x) || x <= 0 || !Number.isFinite(y))
|
|
149
|
+
return void 0;
|
|
150
|
+
if (sourceCartNum < x)
|
|
151
|
+
return void 0;
|
|
152
|
+
return Number(new import_decimal.default(y).div(x).toDecimalPlaces(2).toFixed(2));
|
|
205
153
|
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* 合并「同商品 + 同规格指纹 + 同促销策略 + 同促销单价」的参与促销行(num 累加)。
|
|
209
|
-
* 避免 Browse Items 连续加购同款时拆成多行且单价被错误均摊。
|
|
210
|
-
*
|
|
211
|
-
* @example
|
|
212
|
-
* mergeIdenticalPromotionCartLines(processedProducts);
|
|
213
|
-
*/
|
|
214
154
|
function mergeIdenticalPromotionCartLines(products) {
|
|
155
|
+
var _a, _b, _c, _d;
|
|
215
156
|
if (!Array.isArray(products) || products.length <= 1) {
|
|
216
|
-
return [...
|
|
157
|
+
return [...products || []];
|
|
217
158
|
}
|
|
218
159
|
const merged = [];
|
|
219
|
-
const indexByKey = new Map();
|
|
160
|
+
const indexByKey = /* @__PURE__ */ new Map();
|
|
220
161
|
for (const line of products) {
|
|
221
162
|
if (getGiftInfo(line)) {
|
|
222
163
|
merged.push(line);
|
|
223
164
|
continue;
|
|
224
165
|
}
|
|
225
|
-
const promotion = line
|
|
226
|
-
if (!promotion
|
|
166
|
+
const promotion = (_a = line == null ? void 0 : line.metadata) == null ? void 0 : _a._promotion;
|
|
167
|
+
if (!(promotion == null ? void 0 : promotion.inPromotion) || !promotion.strategyId) {
|
|
227
168
|
merged.push(line);
|
|
228
169
|
continue;
|
|
229
170
|
}
|
|
230
|
-
const fingerprint = (0,
|
|
231
|
-
|
|
232
|
-
|
|
171
|
+
const fingerprint = (0, import_utils2.buildProductLineFingerprint)(
|
|
172
|
+
(0, import_utils.getProductSkuOptions)(line),
|
|
173
|
+
line.product_bundle
|
|
174
|
+
);
|
|
175
|
+
const unitPrice = String(
|
|
176
|
+
((_b = line.metadata) == null ? void 0 : _b.source_product_price) ?? line.selling_price ?? ""
|
|
177
|
+
);
|
|
178
|
+
const promoUnitPrice = String(
|
|
179
|
+
promotion.finalPrice ?? ((_c = line.metadata) == null ? void 0 : _c.main_product_selling_price) ?? ""
|
|
180
|
+
);
|
|
233
181
|
const noteSignature = getProductLineNoteSignature(line);
|
|
234
182
|
const lineMergeBoundary = getPromotionLineMergeBoundary(line);
|
|
235
|
-
const bookingUid = line
|
|
236
|
-
const orderDetailId = line
|
|
237
|
-
const mergeKey = [
|
|
183
|
+
const bookingUid = (line == null ? void 0 : line.booking_uid) ?? ((_d = line == null ? void 0 : line.metadata) == null ? void 0 : _d.booking_uid);
|
|
184
|
+
const orderDetailId = (line == null ? void 0 : line.order_detail_id) ?? (line == null ? void 0 : line.orderDetailId);
|
|
185
|
+
const mergeKey = [
|
|
186
|
+
line.product_id,
|
|
187
|
+
line.product_variant_id ?? 0,
|
|
188
|
+
fingerprint,
|
|
189
|
+
noteSignature,
|
|
190
|
+
lineMergeBoundary,
|
|
191
|
+
bookingUid ? String(bookingUid) : "",
|
|
192
|
+
orderDetailId !== void 0 && orderDetailId !== null && orderDetailId !== "" ? String(orderDetailId) : "",
|
|
193
|
+
promotion.strategyId,
|
|
194
|
+
unitPrice,
|
|
195
|
+
promoUnitPrice
|
|
196
|
+
].join("#");
|
|
238
197
|
const hitIndex = indexByKey.get(mergeKey);
|
|
239
|
-
if (hitIndex ===
|
|
198
|
+
if (hitIndex === void 0) {
|
|
240
199
|
indexByKey.set(mergeKey, merged.length);
|
|
241
200
|
merged.push(line);
|
|
242
201
|
continue;
|
|
243
202
|
}
|
|
244
203
|
const target = merged[hitIndex];
|
|
245
|
-
target.num = (0,
|
|
204
|
+
target.num = (0, import_utils2.getSafeProductNum)(Number(target.num || 0) + Number(line.num || 0));
|
|
246
205
|
}
|
|
247
206
|
return merged;
|
|
248
207
|
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* 同一原购物车行被多个「inPromotion」评估结果命中时(如买赠不改价 + X件Y元),
|
|
252
|
-
* 优先保留 X件Y元 定价,并恢复加购前的行数量。
|
|
253
|
-
*
|
|
254
|
-
* @example
|
|
255
|
-
* dedupePromotionProcessedLines(processedProducts);
|
|
256
|
-
*/
|
|
257
208
|
function dedupePromotionProcessedLines(lines) {
|
|
258
|
-
|
|
209
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
210
|
+
if (!Array.isArray(lines) || lines.length <= 1)
|
|
211
|
+
return [...lines || []];
|
|
259
212
|
const passthrough = [];
|
|
260
|
-
const buckets = new Map();
|
|
213
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
261
214
|
for (const line of lines) {
|
|
262
|
-
const promo = line
|
|
263
|
-
const originalUid = String(line._originalProductUid || getOrderProductUid(line) ||
|
|
264
|
-
if (!promo
|
|
215
|
+
const promo = (_a = line == null ? void 0 : line.metadata) == null ? void 0 : _a._promotion;
|
|
216
|
+
const originalUid = String(line._originalProductUid || getOrderProductUid(line) || "");
|
|
217
|
+
if (!(promo == null ? void 0 : promo.inPromotion) || !originalUid) {
|
|
265
218
|
passthrough.push(line);
|
|
266
219
|
continue;
|
|
267
220
|
}
|
|
@@ -269,11 +222,13 @@ function dedupePromotionProcessedLines(lines) {
|
|
|
269
222
|
group.push(line);
|
|
270
223
|
buckets.set(originalUid, group);
|
|
271
224
|
}
|
|
272
|
-
const promotionDelta = line => {
|
|
273
|
-
|
|
274
|
-
const
|
|
275
|
-
const
|
|
276
|
-
|
|
225
|
+
const promotionDelta = (line) => {
|
|
226
|
+
var _a2;
|
|
227
|
+
const promo = (_a2 = line.metadata) == null ? void 0 : _a2._promotion;
|
|
228
|
+
const original = Number(promo == null ? void 0 : promo.originalPrice);
|
|
229
|
+
const final = Number(promo == null ? void 0 : promo.finalPrice);
|
|
230
|
+
if (!Number.isFinite(original) || !Number.isFinite(final))
|
|
231
|
+
return 0;
|
|
277
232
|
return Math.abs(original - final);
|
|
278
233
|
};
|
|
279
234
|
const deduped = [...passthrough];
|
|
@@ -282,53 +237,73 @@ function dedupePromotionProcessedLines(lines) {
|
|
|
282
237
|
deduped.push(group[0]);
|
|
283
238
|
continue;
|
|
284
239
|
}
|
|
285
|
-
const sourceCartNum = Math.max(
|
|
286
|
-
|
|
287
|
-
|
|
240
|
+
const sourceCartNum = Math.max(
|
|
241
|
+
...group.map((line) => Number(line._sourceCartNum || line.num || 0))
|
|
242
|
+
);
|
|
243
|
+
const pricingLines = group.filter((line) => promotionDelta(line) > 0);
|
|
244
|
+
const xItemsLines = (pricingLines.length ? pricingLines : group).filter(
|
|
245
|
+
(line) => {
|
|
246
|
+
var _a2;
|
|
247
|
+
return getPromotionActionType((_a2 = line.metadata) == null ? void 0 : _a2._promotion) === X_ITEMS_FOR_Y_PRICE;
|
|
248
|
+
}
|
|
249
|
+
);
|
|
288
250
|
const pool = xItemsLines.length ? xItemsLines : pricingLines.length ? pricingLines : group;
|
|
289
251
|
let winner = pool[0];
|
|
290
|
-
const expectedUnit = resolveXItemsExpectedUnitPrice(
|
|
252
|
+
const expectedUnit = resolveXItemsExpectedUnitPrice(
|
|
253
|
+
(_b = winner.metadata) == null ? void 0 : _b._promotion,
|
|
254
|
+
sourceCartNum
|
|
255
|
+
);
|
|
291
256
|
if (expectedUnit != null && pool.length > 1) {
|
|
292
257
|
winner = pool.reduce((best, line) => {
|
|
293
|
-
|
|
294
|
-
const
|
|
258
|
+
var _a2, _b2, _c2, _d2;
|
|
259
|
+
const bestDiff = Math.abs(Number((_b2 = (_a2 = best.metadata) == null ? void 0 : _a2._promotion) == null ? void 0 : _b2.finalPrice) - expectedUnit);
|
|
260
|
+
const lineDiff = Math.abs(Number((_d2 = (_c2 = line.metadata) == null ? void 0 : _c2._promotion) == null ? void 0 : _d2.finalPrice) - expectedUnit);
|
|
295
261
|
return lineDiff < bestDiff ? line : best;
|
|
296
262
|
}, pool[0]);
|
|
297
263
|
} else if (pool.length > 1 && !expectedUnit) {
|
|
298
264
|
winner = pool.reduce((best, line) => {
|
|
299
|
-
|
|
300
|
-
const
|
|
301
|
-
const
|
|
265
|
+
var _a2, _b2, _c2, _d2, _e2, _f2;
|
|
266
|
+
const bestFinal = Number((_b2 = (_a2 = best.metadata) == null ? void 0 : _a2._promotion) == null ? void 0 : _b2.finalPrice);
|
|
267
|
+
const lineFinal = Number((_d2 = (_c2 = line.metadata) == null ? void 0 : _c2._promotion) == null ? void 0 : _d2.finalPrice);
|
|
268
|
+
const original = Number((_f2 = (_e2 = line.metadata) == null ? void 0 : _e2._promotion) == null ? void 0 : _f2.originalPrice);
|
|
302
269
|
if (Number.isFinite(original) && lineFinal >= original && bestFinal >= original) {
|
|
303
270
|
return lineFinal < bestFinal ? line : best;
|
|
304
271
|
}
|
|
305
272
|
return promotionDelta(line) > promotionDelta(best) ? line : best;
|
|
306
273
|
}, pool[0]);
|
|
307
274
|
}
|
|
308
|
-
|
|
309
|
-
// X件Y元:评估器会按单件均摊产出多条 inPromotion 行(如 $1 + $9),
|
|
310
|
-
// dedupe 应合并为「同组 X件Y元 行 num 之和」,不能用 sourceCartNum(整单 3 件)。
|
|
311
|
-
const winnerIsXItems = getPromotionActionType(winner.metadata?._promotion) === X_ITEMS_FOR_Y_PRICE;
|
|
275
|
+
const winnerIsXItems = getPromotionActionType((_c = winner.metadata) == null ? void 0 : _c._promotion) === X_ITEMS_FOR_Y_PRICE;
|
|
312
276
|
if (winnerIsXItems) {
|
|
313
|
-
const xItemsGroupLines = group.filter(
|
|
314
|
-
|
|
315
|
-
|
|
277
|
+
const xItemsGroupLines = group.filter(
|
|
278
|
+
(line) => {
|
|
279
|
+
var _a2;
|
|
280
|
+
return getPromotionActionType((_a2 = line.metadata) == null ? void 0 : _a2._promotion) === X_ITEMS_FOR_Y_PRICE;
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
const evaluatedPromoQty = xItemsGroupLines.reduce(
|
|
284
|
+
(sum, line) => sum + Number(line.num || 0),
|
|
285
|
+
0
|
|
286
|
+
);
|
|
287
|
+
winner.num = (0, import_utils2.getSafeProductNum)(evaluatedPromoQty || winner.num || 1);
|
|
316
288
|
} else {
|
|
317
|
-
winner.num = (0,
|
|
289
|
+
winner.num = (0, import_utils2.getSafeProductNum)(sourceCartNum || winner.num || 1);
|
|
318
290
|
}
|
|
319
|
-
const recomputeUnit = resolveXItemsExpectedUnitPrice(
|
|
291
|
+
const recomputeUnit = resolveXItemsExpectedUnitPrice(
|
|
292
|
+
(_d = winner.metadata) == null ? void 0 : _d._promotion,
|
|
293
|
+
sourceCartNum
|
|
294
|
+
);
|
|
320
295
|
if (recomputeUnit != null) {
|
|
321
296
|
const promo = winner.metadata._promotion;
|
|
322
297
|
applyPromoUnitPriceToLine(winner, {
|
|
323
298
|
promoUnitPrice: recomputeUnit,
|
|
324
299
|
originalBasePrice: Number(promo.originalPrice),
|
|
325
|
-
strategyTitle: promo.strategyMetadata
|
|
300
|
+
strategyTitle: (_e = promo.strategyMetadata) == null ? void 0 : _e.name
|
|
326
301
|
});
|
|
327
302
|
promo.finalPrice = recomputeUnit;
|
|
328
303
|
}
|
|
329
304
|
for (const line of group) {
|
|
330
|
-
const giftInfo = line.metadata
|
|
331
|
-
if (giftInfo && winner.metadata
|
|
305
|
+
const giftInfo = (_g = (_f = line.metadata) == null ? void 0 : _f._promotion) == null ? void 0 : _g.giftInfo;
|
|
306
|
+
if (giftInfo && ((_h = winner.metadata) == null ? void 0 : _h._promotion) && !winner.metadata._promotion.giftInfo) {
|
|
332
307
|
winner.metadata._promotion.giftInfo = giftInfo;
|
|
333
308
|
}
|
|
334
309
|
}
|
|
@@ -336,127 +311,132 @@ function dedupePromotionProcessedLines(lines) {
|
|
|
336
311
|
}
|
|
337
312
|
return deduped;
|
|
338
313
|
}
|
|
339
|
-
|
|
340
|
-
/** 获取行 uid(统一以 `metadata.unique_identification_number` 为唯一键) */
|
|
341
314
|
function getOrderProductUid(product) {
|
|
342
|
-
|
|
315
|
+
var _a;
|
|
316
|
+
return String(
|
|
317
|
+
((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.unique_identification_number) ?? (product == null ? void 0 : product.unique_identification_number) ?? ""
|
|
318
|
+
);
|
|
343
319
|
}
|
|
344
320
|
function getGiftInfo(product) {
|
|
345
|
-
|
|
321
|
+
var _a;
|
|
322
|
+
return ((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a._giftInfo) || (product == null ? void 0 : product._giftInfo) || null;
|
|
346
323
|
}
|
|
347
324
|
function getProductLineNoteSignature(product) {
|
|
348
|
-
const note = product
|
|
349
|
-
if (typeof note !==
|
|
325
|
+
const note = product == null ? void 0 : product.note;
|
|
326
|
+
if (typeof note !== "string")
|
|
327
|
+
return "";
|
|
350
328
|
const normalizedNote = note.trim();
|
|
351
|
-
if (!normalizedNote)
|
|
329
|
+
if (!normalizedNote)
|
|
330
|
+
return "";
|
|
352
331
|
const uid = getOrderProductUid(product);
|
|
353
332
|
return uid ? `note:${uid}` : `note:${normalizedNote}`;
|
|
354
333
|
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* 编辑订单时,历史行仍参与整车促销评估,但不能与本次新增行合并。
|
|
358
|
-
* 以历史行 uid 作为促销前后的行边界;新增行返回空边界,仍保留原有合并语义。
|
|
359
|
-
*/
|
|
360
334
|
function getPromotionLineMergeBoundary(product) {
|
|
361
|
-
|
|
335
|
+
var _a;
|
|
336
|
+
if (((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.is_edit_for_runtime) !== true)
|
|
337
|
+
return "";
|
|
362
338
|
return `edit:${getOrderProductUid(product)}`;
|
|
363
339
|
}
|
|
364
340
|
function isPersistedGeneratedVoucher(product) {
|
|
365
|
-
const orderDetailId = product
|
|
366
|
-
if (orderDetailId ===
|
|
341
|
+
const orderDetailId = (product == null ? void 0 : product.order_detail_id) ?? (product == null ? void 0 : product.orderDetailId);
|
|
342
|
+
if (orderDetailId === void 0 || orderDetailId === null || orderDetailId === "") {
|
|
367
343
|
return false;
|
|
368
344
|
}
|
|
369
|
-
const metadata = product
|
|
370
|
-
return product
|
|
345
|
+
const metadata = (product == null ? void 0 : product.metadata) || {};
|
|
346
|
+
return (product == null ? void 0 : product.extension_type) === "product_voucher" || metadata.parent_order_detail_id !== void 0 || metadata.gift_card_type !== void 0;
|
|
371
347
|
}
|
|
372
348
|
function getProductBundleForEvaluator(product) {
|
|
373
|
-
const bundles = Array.isArray(product
|
|
374
|
-
return bundles.map(b => ({
|
|
375
|
-
product_id: b
|
|
376
|
-
product_variant_id: b
|
|
377
|
-
quantity: Number(b
|
|
378
|
-
price: Number(b
|
|
379
|
-
original_price: Number(b
|
|
380
|
-
id: b
|
|
381
|
-
_bundle_product_id: b
|
|
349
|
+
const bundles = Array.isArray(product == null ? void 0 : product.product_bundle) ? product.product_bundle : [];
|
|
350
|
+
return bundles.map((b) => ({
|
|
351
|
+
product_id: (b == null ? void 0 : b.bundle_product_id) ?? (b == null ? void 0 : b._bundle_product_id) ?? (b == null ? void 0 : b.product_id),
|
|
352
|
+
product_variant_id: (b == null ? void 0 : b.bundle_variant_id) ?? (b == null ? void 0 : b.product_variant_id) ?? 0,
|
|
353
|
+
quantity: Number((b == null ? void 0 : b.num) ?? (b == null ? void 0 : b.quantity) ?? 1) || 1,
|
|
354
|
+
price: Number((b == null ? void 0 : b.bundle_selling_price) ?? (b == null ? void 0 : b.price) ?? 0) || 0,
|
|
355
|
+
original_price: Number((b == null ? void 0 : b.original_price) ?? (b == null ? void 0 : b.product_price) ?? (b == null ? void 0 : b.price) ?? 0) || 0,
|
|
356
|
+
id: (b == null ? void 0 : b.bundle_id) ?? (b == null ? void 0 : b.id) ?? 0,
|
|
357
|
+
_bundle_product_id: (b == null ? void 0 : b._bundle_product_id) ?? (b == null ? void 0 : b.bundle_product_id) ?? (b == null ? void 0 : b.product_id)
|
|
382
358
|
}));
|
|
383
359
|
}
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* 促销评估前合并同 SKU 拆分行(含促销/原价行),避免加购后仅前 2 件享受优惠。
|
|
387
|
-
* 带 `booking_uid` 的预约行不参与合并(每次加车独立 booking + 商品行)。
|
|
388
|
-
*
|
|
389
|
-
* @example
|
|
390
|
-
* consolidateMainProductsForPromotion([
|
|
391
|
-
* { item: promoLineNum2, originalListIndex: 0 },
|
|
392
|
-
* { item: regularLineNum2, originalListIndex: 1 },
|
|
393
|
-
* ]);
|
|
394
|
-
* // => 单行 num=4,清除 _promotion 后重新评估
|
|
395
|
-
*/
|
|
396
360
|
function buildConsolidateKeyForPromotion(item) {
|
|
397
|
-
|
|
361
|
+
var _a;
|
|
362
|
+
const fingerprint = (0, import_utils2.buildProductLineFingerprint)(
|
|
363
|
+
(0, import_utils.getProductSkuOptions)(item),
|
|
364
|
+
item.product_bundle
|
|
365
|
+
);
|
|
398
366
|
const noteSignature = getProductLineNoteSignature(item);
|
|
399
367
|
const lineMergeBoundary = getPromotionLineMergeBoundary(item);
|
|
400
|
-
const bookingUid = item
|
|
401
|
-
const orderDetailId = item
|
|
402
|
-
if (orderDetailId !==
|
|
403
|
-
return [
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
368
|
+
const bookingUid = (item == null ? void 0 : item.booking_uid) ?? ((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a.booking_uid);
|
|
369
|
+
const orderDetailId = (item == null ? void 0 : item.order_detail_id) ?? (item == null ? void 0 : item.orderDetailId);
|
|
370
|
+
if (orderDetailId !== void 0 && orderDetailId !== null && orderDetailId !== "") {
|
|
371
|
+
return [
|
|
372
|
+
item.product_id,
|
|
373
|
+
item.product_variant_id ?? 0,
|
|
374
|
+
fingerprint,
|
|
375
|
+
noteSignature,
|
|
376
|
+
lineMergeBoundary,
|
|
377
|
+
String(orderDetailId)
|
|
378
|
+
].join("#");
|
|
379
|
+
}
|
|
380
|
+
if (bookingUid !== void 0 && bookingUid !== null && String(bookingUid) !== "") {
|
|
381
|
+
return [
|
|
382
|
+
item.product_id,
|
|
383
|
+
item.product_variant_id ?? 0,
|
|
384
|
+
fingerprint,
|
|
385
|
+
noteSignature,
|
|
386
|
+
lineMergeBoundary,
|
|
387
|
+
String(bookingUid)
|
|
388
|
+
].join("#");
|
|
389
|
+
}
|
|
390
|
+
return [
|
|
391
|
+
item.product_id,
|
|
392
|
+
item.product_variant_id ?? 0,
|
|
393
|
+
fingerprint,
|
|
394
|
+
noteSignature,
|
|
395
|
+
lineMergeBoundary
|
|
396
|
+
].join("#");
|
|
409
397
|
}
|
|
410
398
|
function consolidateMainProductsForPromotion(entries) {
|
|
399
|
+
var _a, _b;
|
|
411
400
|
if (!Array.isArray(entries) || entries.length <= 1) {
|
|
412
|
-
return [...
|
|
401
|
+
return [...entries || []];
|
|
413
402
|
}
|
|
414
|
-
const groups = new Map();
|
|
415
|
-
for (const {
|
|
416
|
-
item,
|
|
417
|
-
originalListIndex
|
|
418
|
-
} of entries) {
|
|
403
|
+
const groups = /* @__PURE__ */ new Map();
|
|
404
|
+
for (const { item, originalListIndex } of entries) {
|
|
419
405
|
const key = buildConsolidateKeyForPromotion(item);
|
|
420
|
-
const wasInPromotion = item
|
|
406
|
+
const wasInPromotion = ((_b = (_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a._promotion) == null ? void 0 : _b.inPromotion) === true;
|
|
421
407
|
const existing = groups.get(key);
|
|
422
408
|
if (!existing) {
|
|
423
|
-
const mergedItem = (0,
|
|
409
|
+
const mergedItem = (0, import_lodash_es.cloneDeep)(item);
|
|
424
410
|
const metadata = mergedItem.metadata || {};
|
|
425
411
|
delete metadata._promotion;
|
|
426
412
|
mergedItem.metadata = metadata;
|
|
427
413
|
if (Array.isArray(mergedItem.product_bundle)) {
|
|
428
414
|
for (const bundle of mergedItem.product_bundle) {
|
|
429
|
-
if (bundle && typeof bundle ===
|
|
415
|
+
if (bundle && typeof bundle === "object")
|
|
416
|
+
delete bundle._promotion;
|
|
430
417
|
}
|
|
431
418
|
}
|
|
432
419
|
if (wasInPromotion) {
|
|
433
420
|
mergedItem._wasInPromotionBeforeConsolidate = true;
|
|
434
421
|
}
|
|
435
|
-
groups.set(key, {
|
|
436
|
-
item: mergedItem,
|
|
437
|
-
originalListIndex
|
|
438
|
-
});
|
|
422
|
+
groups.set(key, { item: mergedItem, originalListIndex });
|
|
439
423
|
continue;
|
|
440
424
|
}
|
|
441
|
-
existing.item.num = (0,
|
|
425
|
+
existing.item.num = (0, import_utils2.getSafeProductNum)(
|
|
426
|
+
Number(existing.item.num || 0) + Number(item.num || 0)
|
|
427
|
+
);
|
|
442
428
|
if (wasInPromotion) {
|
|
443
429
|
existing.item._wasInPromotionBeforeConsolidate = true;
|
|
444
430
|
}
|
|
445
431
|
}
|
|
446
432
|
return Array.from(groups.values());
|
|
447
433
|
}
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* X件Y元 整组凑满时按每组 x 件拆开展示(4 件 → 2 行各 2 件 $10)。
|
|
451
|
-
*
|
|
452
|
-
* @example
|
|
453
|
-
* splitXItemsPromoLinesByGroup(mergedLines, strategyActionMap);
|
|
454
|
-
*/
|
|
455
434
|
function splitXItemsPromoLinesByGroup(lines, strategyActionMap) {
|
|
435
|
+
var _a;
|
|
456
436
|
const result = [];
|
|
457
437
|
for (const line of lines) {
|
|
458
|
-
const promo = line
|
|
459
|
-
if (!promo
|
|
438
|
+
const promo = (_a = line == null ? void 0 : line.metadata) == null ? void 0 : _a._promotion;
|
|
439
|
+
if (!(promo == null ? void 0 : promo.inPromotion) || !promo.strategyId) {
|
|
460
440
|
result.push(line);
|
|
461
441
|
continue;
|
|
462
442
|
}
|
|
@@ -465,105 +445,76 @@ function splitXItemsPromoLinesByGroup(lines, strategyActionMap) {
|
|
|
465
445
|
continue;
|
|
466
446
|
}
|
|
467
447
|
const actionMeta = strategyActionMap.get(promo.strategyId);
|
|
468
|
-
const detail = actionMeta
|
|
469
|
-
const x = Number(detail
|
|
448
|
+
const detail = (actionMeta == null ? void 0 : actionMeta.actionDetail) ?? promo.actionDetail;
|
|
449
|
+
const x = Number(detail == null ? void 0 : detail.x);
|
|
470
450
|
const num = Number(line.num || 0);
|
|
471
|
-
const isCumulative = detail
|
|
451
|
+
const isCumulative = (detail == null ? void 0 : detail.cumulative) !== false;
|
|
472
452
|
if (!isCumulative || !Number.isFinite(x) || x <= 0 || num <= x || num % x !== 0) {
|
|
473
453
|
result.push(line);
|
|
474
454
|
continue;
|
|
475
455
|
}
|
|
476
456
|
const groupCount = num / x;
|
|
477
457
|
for (let i = 0; i < groupCount; i++) {
|
|
478
|
-
const splitLine = (0,
|
|
479
|
-
splitLine.num = (0,
|
|
458
|
+
const splitLine = (0, import_lodash_es.cloneDeep)(line);
|
|
459
|
+
splitLine.num = (0, import_utils2.getSafeProductNum)(x);
|
|
480
460
|
splitLine.metadata = {
|
|
481
|
-
...
|
|
482
|
-
unique_identification_number: (0,
|
|
461
|
+
...splitLine.metadata || {},
|
|
462
|
+
unique_identification_number: (0, import_utils.createUuidV4)()
|
|
483
463
|
};
|
|
484
464
|
result.push(splitLine);
|
|
485
465
|
}
|
|
486
466
|
}
|
|
487
467
|
return result;
|
|
488
468
|
}
|
|
489
|
-
|
|
490
|
-
/** 生成新 numeric id(仅用于评估器内部追踪) */
|
|
491
469
|
function generateNumericId() {
|
|
492
|
-
return Math.floor(Math.random() *
|
|
470
|
+
return Math.floor(Math.random() * 1e9) + Date.now();
|
|
493
471
|
}
|
|
494
|
-
|
|
495
|
-
/**
|
|
496
|
-
* 把 OrderProduct 转成 evaluator 的 PromotionProduct(仅评估期使用)。
|
|
497
|
-
*
|
|
498
|
-
* 注意:评估器是「无状态、按 product_id + variant 组」工作的;这里给每行分配一个
|
|
499
|
-
* numericId 用于关联回原 OrderProduct(通过 originalItemMap)。
|
|
500
|
-
*/
|
|
501
472
|
function convertToPromotionProduct(product, index) {
|
|
502
|
-
const metadata = product
|
|
473
|
+
const metadata = (product == null ? void 0 : product.metadata) || {};
|
|
503
474
|
const numericId = generateNumericId();
|
|
504
475
|
const originalItem = product;
|
|
505
476
|
return {
|
|
506
477
|
id: numericId,
|
|
507
|
-
product_id: Number(product
|
|
508
|
-
product_variant_id: Number(product
|
|
509
|
-
name: metadata.product_name || product
|
|
478
|
+
product_id: Number((product == null ? void 0 : product.product_id) ?? 0) || 0,
|
|
479
|
+
product_variant_id: Number((product == null ? void 0 : product.product_variant_id) ?? 0) || 0,
|
|
480
|
+
name: metadata.product_name || (product == null ? void 0 : product.title) || "",
|
|
510
481
|
price: getOrderProductOriginalPriceForPromotion(product),
|
|
511
|
-
quantity: Number(product
|
|
482
|
+
quantity: Number((product == null ? void 0 : product.num) ?? 1) || 1,
|
|
512
483
|
bundle: getProductBundleForEvaluator(product),
|
|
513
484
|
_originalItem: originalItem,
|
|
514
485
|
_originalId: getOrderProductUid(product),
|
|
515
486
|
_originalIndex: index
|
|
516
487
|
};
|
|
517
488
|
}
|
|
518
|
-
|
|
519
|
-
// ============================================
|
|
520
|
-
// 主流程:processCartPromotion
|
|
521
|
-
// ============================================
|
|
522
|
-
|
|
523
|
-
/**
|
|
524
|
-
* 计算赠品差异化操作(toAdd / toReduce / toRemove)。
|
|
525
|
-
*
|
|
526
|
-
* 与 legacy `calculateGiftActions` 等价;唯一差别是行键从 `_id` 改成 `metadata.unique_identification_number`。
|
|
527
|
-
*/
|
|
528
489
|
function calculateGiftActions(gifts, existingGifts) {
|
|
490
|
+
var _a, _b, _c;
|
|
529
491
|
const toAdd = [];
|
|
530
492
|
const toReduce = [];
|
|
531
493
|
const toRemove = [];
|
|
532
|
-
|
|
533
|
-
// 按 strategyId 分组现有赠品
|
|
534
|
-
const existingByStrategy = new Map();
|
|
494
|
+
const existingByStrategy = /* @__PURE__ */ new Map();
|
|
535
495
|
for (const gift of existingGifts) {
|
|
536
|
-
const strategyId = getGiftInfo(gift)
|
|
537
|
-
if (!strategyId)
|
|
496
|
+
const strategyId = (_a = getGiftInfo(gift)) == null ? void 0 : _a.strategyId;
|
|
497
|
+
if (!strategyId)
|
|
498
|
+
continue;
|
|
538
499
|
const existing = existingByStrategy.get(strategyId);
|
|
539
|
-
const qty = Number(gift
|
|
500
|
+
const qty = Number((gift == null ? void 0 : gift.num) ?? 1) || 1;
|
|
540
501
|
if (existing) {
|
|
541
502
|
existing.items.push(gift);
|
|
542
503
|
existing.totalQuantity += qty;
|
|
543
504
|
} else {
|
|
544
|
-
existingByStrategy.set(strategyId, {
|
|
545
|
-
items: [gift],
|
|
546
|
-
totalQuantity: qty
|
|
547
|
-
});
|
|
505
|
+
existingByStrategy.set(strategyId, { items: [gift], totalQuantity: qty });
|
|
548
506
|
}
|
|
549
507
|
}
|
|
550
|
-
const processedStrategyIds = new Set();
|
|
508
|
+
const processedStrategyIds = /* @__PURE__ */ new Set();
|
|
551
509
|
for (const giftInfo of gifts) {
|
|
552
|
-
const {
|
|
553
|
-
strategyId,
|
|
554
|
-
strategyName,
|
|
555
|
-
giftCount,
|
|
556
|
-
giftOptions,
|
|
557
|
-
sourceProductIds
|
|
558
|
-
} = giftInfo;
|
|
510
|
+
const { strategyId, strategyName, giftCount, giftOptions, sourceProductIds } = giftInfo;
|
|
559
511
|
processedStrategyIds.add(strategyId);
|
|
560
512
|
const existing = existingByStrategy.get(strategyId);
|
|
561
|
-
const existingCount = existing
|
|
513
|
+
const existingCount = (existing == null ? void 0 : existing.totalQuantity) ?? 0;
|
|
562
514
|
const diff = giftCount - existingCount;
|
|
563
515
|
if (diff > 0) {
|
|
564
|
-
|
|
565
|
-
const
|
|
566
|
-
const strategyChanged = lastEvaluated === undefined || giftCount !== lastEvaluated;
|
|
516
|
+
const lastEvaluated = (_c = getGiftInfo((_b = existing == null ? void 0 : existing.items) == null ? void 0 : _b[0])) == null ? void 0 : _c.lastEvaluatedGiftCount;
|
|
517
|
+
const strategyChanged = lastEvaluated === void 0 || giftCount !== lastEvaluated;
|
|
567
518
|
if (strategyChanged) {
|
|
568
519
|
toAdd.push({
|
|
569
520
|
strategyId,
|
|
@@ -574,124 +525,99 @@ function calculateGiftActions(gifts, existingGifts) {
|
|
|
574
525
|
});
|
|
575
526
|
}
|
|
576
527
|
} else if (diff < 0) {
|
|
577
|
-
// 减赠品:后进先出
|
|
578
528
|
let remaining = Math.abs(diff);
|
|
579
529
|
const reduceItems = [];
|
|
580
530
|
const removeIds = [];
|
|
581
|
-
const reversed = [...(existing
|
|
531
|
+
const reversed = [...(existing == null ? void 0 : existing.items) || []].reverse();
|
|
582
532
|
for (const giftItem of reversed) {
|
|
583
|
-
if (remaining <= 0)
|
|
533
|
+
if (remaining <= 0)
|
|
534
|
+
break;
|
|
584
535
|
const uid = getOrderProductUid(giftItem);
|
|
585
|
-
const qty = Number(giftItem
|
|
536
|
+
const qty = Number((giftItem == null ? void 0 : giftItem.num) ?? 1) || 1;
|
|
586
537
|
if (qty <= remaining) {
|
|
587
538
|
removeIds.push(uid);
|
|
588
539
|
remaining -= qty;
|
|
589
540
|
} else {
|
|
590
|
-
reduceItems.push({
|
|
591
|
-
uid,
|
|
592
|
-
currentQuantity: qty,
|
|
593
|
-
newQuantity: qty - remaining
|
|
594
|
-
});
|
|
541
|
+
reduceItems.push({ uid, currentQuantity: qty, newQuantity: qty - remaining });
|
|
595
542
|
remaining = 0;
|
|
596
543
|
}
|
|
597
544
|
}
|
|
598
|
-
if (reduceItems.length > 0)
|
|
599
|
-
strategyId,
|
|
600
|
-
items: reduceItems
|
|
601
|
-
});
|
|
545
|
+
if (reduceItems.length > 0)
|
|
546
|
+
toReduce.push({ strategyId, items: reduceItems });
|
|
602
547
|
toRemove.push(...removeIds);
|
|
603
548
|
}
|
|
604
549
|
}
|
|
605
|
-
|
|
606
|
-
// 失效策略的赠品:全部 remove
|
|
607
550
|
for (const [strategyId, existing] of existingByStrategy) {
|
|
608
|
-
if (processedStrategyIds.has(strategyId))
|
|
551
|
+
if (processedStrategyIds.has(strategyId))
|
|
552
|
+
continue;
|
|
609
553
|
for (const giftItem of existing.items) {
|
|
610
554
|
toRemove.push(getOrderProductUid(giftItem));
|
|
611
555
|
}
|
|
612
556
|
}
|
|
613
|
-
return {
|
|
614
|
-
toAdd,
|
|
615
|
-
toReduce,
|
|
616
|
-
toRemove
|
|
617
|
-
};
|
|
557
|
+
return { toAdd, toReduce, toRemove };
|
|
618
558
|
}
|
|
619
|
-
|
|
620
|
-
/**
|
|
621
|
-
* 从策略配置的 product_match 规则提取可参与商品列表。
|
|
622
|
-
*
|
|
623
|
-
* @example
|
|
624
|
-
* extractProductMatchIdentifiersFromStrategyConfig(strategyConfig);
|
|
625
|
-
* // => [{ product_id: 60736, product_variant_id: 0 }]
|
|
626
|
-
*/
|
|
627
559
|
function extractProductMatchIdentifiersFromStrategyConfig(strategyConfig) {
|
|
628
|
-
|
|
629
|
-
|
|
560
|
+
var _a;
|
|
561
|
+
const rules = (_a = strategyConfig == null ? void 0 : strategyConfig.conditions) == null ? void 0 : _a.rules;
|
|
562
|
+
if (!Array.isArray(rules))
|
|
563
|
+
return [];
|
|
630
564
|
for (const rule of rules) {
|
|
631
|
-
if (rule
|
|
632
|
-
return rule.value.map(item => ({
|
|
633
|
-
product_id: Number(item
|
|
634
|
-
product_variant_id: Number(item
|
|
635
|
-
})).filter(item => item.product_id > 0);
|
|
565
|
+
if ((rule == null ? void 0 : rule.field) === "productIdAndVariantId" && ((rule == null ? void 0 : rule.operator) === "product_match" || (rule == null ? void 0 : rule.operator) === "object_in") && Array.isArray(rule == null ? void 0 : rule.value)) {
|
|
566
|
+
return rule.value.map((item) => ({
|
|
567
|
+
product_id: Number(item == null ? void 0 : item.product_id) || 0,
|
|
568
|
+
product_variant_id: Number(item == null ? void 0 : item.product_variant_id) || 0
|
|
569
|
+
})).filter((item) => item.product_id > 0);
|
|
636
570
|
}
|
|
637
571
|
}
|
|
638
572
|
return [];
|
|
639
573
|
}
|
|
640
|
-
|
|
641
|
-
/**
|
|
642
|
-
* 解析策略凑单所需件数(evaluator 原始返回可能不含 requiredQuantity)。
|
|
643
|
-
*
|
|
644
|
-
* @example
|
|
645
|
-
* resolveStrategyRequiredQuantity({ actionType: 'X_ITEMS_FOR_Y_PRICE', actionDetail: { x: 2 } });
|
|
646
|
-
*/
|
|
647
574
|
function resolveStrategyRequiredQuantity(matched) {
|
|
648
575
|
const preset = Number(matched.requiredQuantity);
|
|
649
|
-
if (Number.isFinite(preset) && preset > 0)
|
|
576
|
+
if (Number.isFinite(preset) && preset > 0)
|
|
577
|
+
return preset;
|
|
650
578
|
const detail = matched.actionDetail || {};
|
|
651
|
-
if (matched.actionType ===
|
|
579
|
+
if (matched.actionType === "X_ITEMS_FOR_Y_PRICE") {
|
|
652
580
|
return Number(detail.x) || 2;
|
|
653
581
|
}
|
|
654
|
-
if (matched.actionType ===
|
|
582
|
+
if (matched.actionType === "BUY_X_GET_Y_FREE") {
|
|
655
583
|
return Number(detail.buyQuantity) || 1;
|
|
656
584
|
}
|
|
657
585
|
return 1;
|
|
658
586
|
}
|
|
659
|
-
|
|
660
|
-
/**
|
|
661
|
-
* 解析 Browse Items 弹窗候选商品(优先 eligibleProducts,否则读 strategyConfig)。
|
|
662
|
-
*
|
|
663
|
-
* @example
|
|
664
|
-
* resolveStrategyEligibleProducts(matchedStrategy);
|
|
665
|
-
*/
|
|
666
587
|
function resolveStrategyEligibleProducts(matched) {
|
|
667
588
|
if (Array.isArray(matched.eligibleProducts) && matched.eligibleProducts.length > 0) {
|
|
668
589
|
return matched.eligibleProducts;
|
|
669
590
|
}
|
|
670
591
|
return extractProductMatchIdentifiersFromStrategyConfig(matched.strategyConfig);
|
|
671
592
|
}
|
|
672
|
-
|
|
673
|
-
/**
|
|
674
|
-
* 计算未满足促销条件(用于购物车底部「再买 N 件即可享受 XX」alert)。
|
|
675
|
-
*
|
|
676
|
-
* 数据源:商品的 `metadata._promotion.inPromotion === false`(来自 processCartPromotion
|
|
677
|
-
* 第 8 步追加的「有适用策略但当前未参与促销」标记)。
|
|
678
|
-
*/
|
|
679
593
|
function calculateUnfulfilledPromotions(processedProducts, applicableStrategiesResult, mainProducts) {
|
|
680
|
-
|
|
594
|
+
var _a, _b;
|
|
595
|
+
const unfulfilledMap = /* @__PURE__ */ new Map();
|
|
681
596
|
for (let i = 0; i < processedProducts.length; i++) {
|
|
682
597
|
const product = processedProducts[i];
|
|
683
|
-
const promotion = product
|
|
684
|
-
if (!promotion || promotion.inPromotion !== false)
|
|
598
|
+
const promotion = (_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a._promotion;
|
|
599
|
+
if (!promotion || promotion.inPromotion !== false)
|
|
600
|
+
continue;
|
|
685
601
|
const strategyId = promotion.strategyId;
|
|
686
|
-
if (!strategyId)
|
|
687
|
-
|
|
688
|
-
const
|
|
689
|
-
|
|
602
|
+
if (!strategyId)
|
|
603
|
+
continue;
|
|
604
|
+
const lookupUid = String(
|
|
605
|
+
(product == null ? void 0 : product._originalProductUid) ?? ((_b = product == null ? void 0 : product.metadata) == null ? void 0 : _b.unique_identification_number) ?? ""
|
|
606
|
+
);
|
|
607
|
+
const originalIndex = mainProducts.findIndex(
|
|
608
|
+
(item) => getOrderProductUid(item) === lookupUid
|
|
609
|
+
);
|
|
610
|
+
if (originalIndex === -1)
|
|
611
|
+
continue;
|
|
690
612
|
const strategyData = applicableStrategiesResult[originalIndex];
|
|
691
|
-
if (!strategyData || !strategyData.hasApplicableStrategy)
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
613
|
+
if (!strategyData || !strategyData.hasApplicableStrategy)
|
|
614
|
+
continue;
|
|
615
|
+
const matched = strategyData.applicableStrategies.find(
|
|
616
|
+
(s) => s.strategyId === strategyId
|
|
617
|
+
);
|
|
618
|
+
if (!matched)
|
|
619
|
+
continue;
|
|
620
|
+
const quantity = Number((product == null ? void 0 : product.num) ?? 1) || 1;
|
|
695
621
|
if (unfulfilledMap.has(strategyId)) {
|
|
696
622
|
unfulfilledMap.get(strategyId).currentQuantity += quantity;
|
|
697
623
|
} else {
|
|
@@ -712,47 +638,32 @@ function calculateUnfulfilledPromotions(processedProducts, applicableStrategiesR
|
|
|
712
638
|
for (const data of unfulfilledMap.values()) {
|
|
713
639
|
const needQuantity = data.requiredQuantity - data.currentQuantity;
|
|
714
640
|
if (needQuantity > 0) {
|
|
715
|
-
result.push({
|
|
716
|
-
...data,
|
|
717
|
-
needQuantity
|
|
718
|
-
});
|
|
641
|
+
result.push({ ...data, needQuantity });
|
|
719
642
|
}
|
|
720
643
|
}
|
|
721
644
|
return result;
|
|
722
645
|
}
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* 给商品列表追加促销标签(写入 `metadata._promotionTags`),供 ProductCard 渲染。
|
|
726
|
-
*
|
|
727
|
-
* - 没有适用策略的商品会清除 `_promotionTags`(避免脏数据)。
|
|
728
|
-
* - 仅基于 product_id 匹配(matchVariant=false),与商品卡通用场景对齐。
|
|
729
|
-
*
|
|
730
|
-
* @example
|
|
731
|
-
* const list = appendPromotionTags(catalog, evaluator);
|
|
732
|
-
* // list[i].metadata._promotionTags = [{ text, type, strategyId }]
|
|
733
|
-
*/
|
|
734
646
|
function appendPromotionTags(products, evaluator) {
|
|
735
647
|
if (!Array.isArray(products) || products.length === 0 || !evaluator) {
|
|
736
648
|
return products || [];
|
|
737
649
|
}
|
|
738
|
-
|
|
739
|
-
// 评估器期望的 product shape,最少字段集
|
|
740
650
|
const evaluatorInput = products.map((item, index) => ({
|
|
741
651
|
id: index,
|
|
742
|
-
product_id: Number(item
|
|
743
|
-
product_variant_id: Number(item
|
|
744
|
-
name: item
|
|
745
|
-
price: Number(item
|
|
746
|
-
quantity: Number(item
|
|
652
|
+
product_id: Number((item == null ? void 0 : item.id) ?? (item == null ? void 0 : item.product_id) ?? 0) || 0,
|
|
653
|
+
product_variant_id: Number((item == null ? void 0 : item.product_variant_id) ?? 0) || 0,
|
|
654
|
+
name: (item == null ? void 0 : item.title) || (item == null ? void 0 : item.name) || "",
|
|
655
|
+
price: Number((item == null ? void 0 : item.price) ?? 0) || 0,
|
|
656
|
+
quantity: Number((item == null ? void 0 : item.quantity) ?? 1) || 1,
|
|
747
657
|
bundle: []
|
|
748
658
|
}));
|
|
749
|
-
const strategies = evaluator.getProductsApplicableStrategies(
|
|
750
|
-
products: evaluatorInput
|
|
751
|
-
|
|
659
|
+
const strategies = evaluator.getProductsApplicableStrategies(
|
|
660
|
+
{ products: evaluatorInput },
|
|
661
|
+
false
|
|
662
|
+
);
|
|
752
663
|
return products.map((item, index) => {
|
|
753
664
|
const data = strategies[index];
|
|
754
665
|
const tags = [];
|
|
755
|
-
if (data
|
|
666
|
+
if (data == null ? void 0 : data.hasApplicableStrategy) {
|
|
756
667
|
for (const strategy of data.applicableStrategies) {
|
|
757
668
|
if (strategy.display) {
|
|
758
669
|
tags.push({
|
|
@@ -763,58 +674,24 @@ function appendPromotionTags(products, evaluator) {
|
|
|
763
674
|
}
|
|
764
675
|
}
|
|
765
676
|
}
|
|
766
|
-
// 商品卡兼容两种位置:顶层 `_promotionTags` 与 `metadata._promotionTags`
|
|
767
|
-
// ProductCard 现有实现读顶层(详见 productSelect/ProductCard/index.tsx),
|
|
768
|
-
// 此处同时写顶层以保持视图直连;OrderProduct 行版本走 metadata(避免顶层非协议字段)。
|
|
769
677
|
if (tags.length === 0) {
|
|
770
|
-
const {
|
|
771
|
-
_promotionTags,
|
|
772
|
-
...rest
|
|
773
|
-
} = item;
|
|
774
|
-
void _promotionTags;
|
|
678
|
+
const { _promotionTags, ...rest } = item;
|
|
775
679
|
return rest;
|
|
776
680
|
}
|
|
777
|
-
return {
|
|
778
|
-
...item,
|
|
779
|
-
_promotionTags: tags
|
|
780
|
-
};
|
|
681
|
+
return { ...item, _promotionTags: tags };
|
|
781
682
|
});
|
|
782
683
|
}
|
|
783
|
-
|
|
784
|
-
/**
|
|
785
|
-
* 处理购物车的促销计算与赠品差异化。
|
|
786
|
-
*
|
|
787
|
-
* 流程:
|
|
788
|
-
* 1. 分离 main / gift / edit-product 三类(带 `booking_id` 的编辑态商品不参与促销)
|
|
789
|
-
* 2. 转 PromotionProduct 喂评估器 → 拿到 `evaluateCartWithPricing` 与 `getProductsApplicableStrategies`
|
|
790
|
-
* 3. 把 PricedProduct 映射回 OrderProduct 形态:
|
|
791
|
-
* - 参与促销的,写 `metadata._promotion` + 调整 `selling_price` / `main_product_selling_price`
|
|
792
|
-
* - 拆分的,生成新 uid,复制原行其它字段
|
|
793
|
-
* 4. 计算 `_giftInfo` 挂主商品(每个策略首个主商品)
|
|
794
|
-
* 5. 计算 `giftActions`(toAdd / toReduce / toRemove)
|
|
795
|
-
* 6. 计算 `unfulfilledPromotions`
|
|
796
|
-
*
|
|
797
|
-
* @example
|
|
798
|
-
* const { products, giftActions, unfulfilledPromotions } = processCartPromotion(
|
|
799
|
-
* tempOrder.products,
|
|
800
|
-
* evaluator,
|
|
801
|
-
* );
|
|
802
|
-
*/
|
|
803
684
|
function processCartPromotion(list, evaluator, options) {
|
|
685
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
804
686
|
const empty = {
|
|
805
687
|
products: Array.isArray(list) ? [...list] : [],
|
|
806
688
|
totalDiscount: 0,
|
|
807
689
|
gifts: [],
|
|
808
|
-
giftActions: {
|
|
809
|
-
toAdd: [],
|
|
810
|
-
toReduce: [],
|
|
811
|
-
toRemove: []
|
|
812
|
-
},
|
|
690
|
+
giftActions: { toAdd: [], toReduce: [], toRemove: [] },
|
|
813
691
|
unfulfilledPromotions: []
|
|
814
692
|
};
|
|
815
|
-
if (!list || list.length === 0 || !evaluator)
|
|
816
|
-
|
|
817
|
-
// 0. 分类
|
|
693
|
+
if (!list || list.length === 0 || !evaluator)
|
|
694
|
+
return empty;
|
|
818
695
|
const mainProductsWithIndex = [];
|
|
819
696
|
const existingGiftsWithIndex = [];
|
|
820
697
|
const editProductsWithIndex = [];
|
|
@@ -822,47 +699,34 @@ function processCartPromotion(list, evaluator, options) {
|
|
|
822
699
|
const item = list[i];
|
|
823
700
|
const giftInfo = getGiftInfo(item);
|
|
824
701
|
if (isPersistedGeneratedVoucher(item)) {
|
|
825
|
-
editProductsWithIndex.push({
|
|
826
|
-
item,
|
|
827
|
-
originalListIndex: i
|
|
828
|
-
});
|
|
702
|
+
editProductsWithIndex.push({ item, originalListIndex: i });
|
|
829
703
|
} else if (giftInfo) {
|
|
830
|
-
existingGiftsWithIndex.push({
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
});
|
|
834
|
-
} else if (item?.booking_id !== undefined && item?.booking_id !== null && item.booking_id !== 0 && item.booking_id !== '0') {
|
|
835
|
-
editProductsWithIndex.push({
|
|
836
|
-
item,
|
|
837
|
-
originalListIndex: i
|
|
838
|
-
});
|
|
704
|
+
existingGiftsWithIndex.push({ item, originalListIndex: i });
|
|
705
|
+
} else if ((item == null ? void 0 : item.booking_id) !== void 0 && (item == null ? void 0 : item.booking_id) !== null && item.booking_id !== 0 && item.booking_id !== "0") {
|
|
706
|
+
editProductsWithIndex.push({ item, originalListIndex: i });
|
|
839
707
|
} else {
|
|
840
|
-
mainProductsWithIndex.push({
|
|
841
|
-
item,
|
|
842
|
-
originalListIndex: i
|
|
843
|
-
});
|
|
708
|
+
mainProductsWithIndex.push({ item, originalListIndex: i });
|
|
844
709
|
}
|
|
845
710
|
}
|
|
846
|
-
const consolidatedMainProductsWithIndex = consolidateMainProductsForPromotion(
|
|
847
|
-
|
|
848
|
-
|
|
711
|
+
const consolidatedMainProductsWithIndex = consolidateMainProductsForPromotion(
|
|
712
|
+
mainProductsWithIndex
|
|
713
|
+
);
|
|
714
|
+
const mainProducts = consolidatedMainProductsWithIndex.map((x) => x.item);
|
|
715
|
+
const existingGifts = existingGiftsWithIndex.map((x) => x.item);
|
|
849
716
|
if (mainProducts.length === 0) {
|
|
850
|
-
const editProducts = editProductsWithIndex.map(x => x.item);
|
|
717
|
+
const editProducts = editProductsWithIndex.map((x) => x.item);
|
|
851
718
|
if (existingGifts.length > 0) {
|
|
852
719
|
const toRemove = [];
|
|
853
720
|
for (const gift of existingGifts) {
|
|
854
721
|
const uid = getOrderProductUid(gift);
|
|
855
|
-
if (uid)
|
|
722
|
+
if (uid)
|
|
723
|
+
toRemove.push(uid);
|
|
856
724
|
}
|
|
857
725
|
return {
|
|
858
726
|
products: editProducts,
|
|
859
727
|
totalDiscount: 0,
|
|
860
728
|
gifts: [],
|
|
861
|
-
giftActions: {
|
|
862
|
-
toAdd: [],
|
|
863
|
-
toReduce: [],
|
|
864
|
-
toRemove
|
|
865
|
-
},
|
|
729
|
+
giftActions: { toAdd: [], toReduce: [], toRemove },
|
|
866
730
|
unfulfilledPromotions: []
|
|
867
731
|
};
|
|
868
732
|
}
|
|
@@ -871,108 +735,92 @@ function processCartPromotion(list, evaluator, options) {
|
|
|
871
735
|
products: editProducts.length > 0 ? editProducts : [...list]
|
|
872
736
|
};
|
|
873
737
|
}
|
|
874
|
-
|
|
875
|
-
// 1. 转 PromotionProduct
|
|
876
738
|
const promotionProducts = [];
|
|
877
|
-
const originalItemMap = new Map();
|
|
878
|
-
const productsForStrategies = consolidatedMainProductsWithIndex.map(({
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
739
|
+
const originalItemMap = /* @__PURE__ */ new Map();
|
|
740
|
+
const productsForStrategies = consolidatedMainProductsWithIndex.map(({ item }, i) => {
|
|
741
|
+
var _a2;
|
|
742
|
+
return {
|
|
743
|
+
id: i,
|
|
744
|
+
product_id: Number((item == null ? void 0 : item.product_id) ?? 0) || 0,
|
|
745
|
+
product_variant_id: Number((item == null ? void 0 : item.product_variant_id) ?? 0) || 0,
|
|
746
|
+
name: ((_a2 = item == null ? void 0 : item.metadata) == null ? void 0 : _a2.product_name) || (item == null ? void 0 : item.title) || "",
|
|
747
|
+
price: getOrderProductBasePrice(item),
|
|
748
|
+
quantity: Number((item == null ? void 0 : item.num) ?? 1) || 1,
|
|
749
|
+
bundle: getProductBundleForEvaluator(item)
|
|
750
|
+
};
|
|
751
|
+
});
|
|
889
752
|
for (let i = 0; i < consolidatedMainProductsWithIndex.length; i++) {
|
|
890
|
-
const {
|
|
891
|
-
item,
|
|
892
|
-
originalListIndex
|
|
893
|
-
} = consolidatedMainProductsWithIndex[i];
|
|
753
|
+
const { item, originalListIndex } = consolidatedMainProductsWithIndex[i];
|
|
894
754
|
const promotionProduct = convertToPromotionProduct(item, originalListIndex);
|
|
895
755
|
promotionProducts.push(promotionProduct);
|
|
896
|
-
originalItemMap.set(promotionProduct.id, {
|
|
897
|
-
item,
|
|
898
|
-
index: originalListIndex
|
|
899
|
-
});
|
|
756
|
+
originalItemMap.set(promotionProduct.id, { item, index: originalListIndex });
|
|
900
757
|
}
|
|
901
|
-
|
|
902
|
-
// 2. 拿适用策略
|
|
903
758
|
const applicableStrategiesResult = evaluator.getProductsApplicableStrategies({
|
|
904
759
|
products: productsForStrategies,
|
|
905
|
-
channel: options
|
|
760
|
+
channel: options == null ? void 0 : options.channel
|
|
906
761
|
});
|
|
907
|
-
const strategyActionMap = new Map();
|
|
762
|
+
const strategyActionMap = /* @__PURE__ */ new Map();
|
|
908
763
|
for (const row of applicableStrategiesResult || []) {
|
|
909
|
-
for (const strategy of row
|
|
910
|
-
if (!strategy
|
|
764
|
+
for (const strategy of (row == null ? void 0 : row.applicableStrategies) || []) {
|
|
765
|
+
if (!(strategy == null ? void 0 : strategy.strategyId))
|
|
766
|
+
continue;
|
|
911
767
|
strategyActionMap.set(strategy.strategyId, {
|
|
912
768
|
actionType: strategy.actionType,
|
|
913
769
|
actionDetail: strategy.actionDetail
|
|
914
770
|
});
|
|
915
771
|
}
|
|
916
772
|
}
|
|
917
|
-
|
|
918
|
-
// 3. 评估器
|
|
919
773
|
const result = evaluator.evaluateCartWithPricing({
|
|
920
774
|
products: promotionProducts,
|
|
921
|
-
channel: options
|
|
775
|
+
channel: options == null ? void 0 : options.channel
|
|
922
776
|
});
|
|
923
|
-
|
|
924
|
-
// 4. 收集每个策略的 sourceProductIds(参与策略的主商品 uid)
|
|
925
|
-
const strategySourceProductIds = new Map();
|
|
777
|
+
const strategySourceProductIds = /* @__PURE__ */ new Map();
|
|
926
778
|
for (const priced of result.products) {
|
|
927
779
|
if (priced.inPromotion && priced.strategyId) {
|
|
928
780
|
const sourceId = priced.originalId ?? priced.id;
|
|
929
781
|
const originalData = originalItemMap.get(sourceId);
|
|
930
782
|
if (originalData) {
|
|
931
783
|
const uid = getOrderProductUid(originalData.item);
|
|
932
|
-
if (!uid)
|
|
784
|
+
if (!uid)
|
|
785
|
+
continue;
|
|
933
786
|
const arr = strategySourceProductIds.get(priced.strategyId) || [];
|
|
934
|
-
if (!arr.includes(uid))
|
|
787
|
+
if (!arr.includes(uid))
|
|
788
|
+
arr.push(uid);
|
|
935
789
|
strategySourceProductIds.set(priced.strategyId, arr);
|
|
936
790
|
}
|
|
937
791
|
}
|
|
938
792
|
}
|
|
939
|
-
|
|
940
|
-
// 5. 扩展 gifts,加 sourceProductIds
|
|
941
|
-
const extendedGifts = result.gifts.map(gift => ({
|
|
793
|
+
const extendedGifts = result.gifts.map((gift) => ({
|
|
942
794
|
...gift,
|
|
943
795
|
sourceProductIds: strategySourceProductIds.get(gift.strategyId) || []
|
|
944
796
|
}));
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
const strategyGiftInfoOwner = new Map();
|
|
797
|
+
const strategyGiftInfoMap = /* @__PURE__ */ new Map();
|
|
798
|
+
for (const gift of extendedGifts)
|
|
799
|
+
strategyGiftInfoMap.set(gift.strategyId, gift);
|
|
800
|
+
const strategyGiftInfoOwner = /* @__PURE__ */ new Map();
|
|
950
801
|
const processedProducts = [];
|
|
951
802
|
for (const priced of result.products) {
|
|
952
803
|
const rawSourceId = priced.originalId ?? priced.id;
|
|
953
804
|
const sourceId = Number(rawSourceId);
|
|
954
|
-
const originalData = Number.isFinite(sourceId) ? originalItemMap.get(sourceId) :
|
|
955
|
-
if (!originalData)
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
index: originalIndex
|
|
959
|
-
} = originalData;
|
|
805
|
+
const originalData = Number.isFinite(sourceId) ? originalItemMap.get(sourceId) : void 0;
|
|
806
|
+
if (!originalData)
|
|
807
|
+
continue;
|
|
808
|
+
const { item: originalItem, index: originalIndex } = originalData;
|
|
960
809
|
const pricedProductId = Number(priced.product_id ?? 0);
|
|
961
810
|
const originalProductId = Number(originalItem.product_id ?? 0);
|
|
962
811
|
if (pricedProductId > 0 && originalProductId > 0 && pricedProductId !== originalProductId) {
|
|
963
812
|
continue;
|
|
964
813
|
}
|
|
965
|
-
const newItem = (0,
|
|
814
|
+
const newItem = (0, import_lodash_es.cloneDeep)(originalItem);
|
|
966
815
|
const metadata = newItem.metadata || {};
|
|
967
|
-
const sourceCartNum = (0,
|
|
816
|
+
const sourceCartNum = (0, import_utils2.getSafeProductNum)(originalItem.num);
|
|
968
817
|
newItem._sourceCartNum = sourceCartNum;
|
|
969
|
-
|
|
970
|
-
// 清掉历史促销字段
|
|
971
|
-
const wasInPromotion = metadata._promotion?.inPromotion === true || originalItem._wasInPromotionBeforeConsolidate === true;
|
|
818
|
+
const wasInPromotion = ((_a = metadata._promotion) == null ? void 0 : _a.inPromotion) === true || originalItem._wasInPromotionBeforeConsolidate === true;
|
|
972
819
|
delete metadata._promotion;
|
|
973
820
|
if (Array.isArray(newItem.product_bundle)) {
|
|
974
821
|
for (const b of newItem.product_bundle) {
|
|
975
|
-
if (b && typeof b ===
|
|
822
|
+
if (b && typeof b === "object")
|
|
823
|
+
delete b._promotion;
|
|
976
824
|
}
|
|
977
825
|
}
|
|
978
826
|
const originalBasePrice = getOrderProductOriginalPriceForPromotion(originalItem);
|
|
@@ -980,32 +828,29 @@ function processCartPromotion(list, evaluator, options) {
|
|
|
980
828
|
const priceUnchangedPromo = priced.inPromotion && Number(priced.finalPrice) === Number(originalBasePrice);
|
|
981
829
|
if (shouldModifyPrice) {
|
|
982
830
|
if (priced.inPromotion && !priceUnchangedPromo) {
|
|
983
|
-
const promoUnitPrice = new
|
|
831
|
+
const promoUnitPrice = new import_decimal.default(priced.finalPrice).toDecimalPlaces(2).toFixed(2);
|
|
984
832
|
applyPromoUnitPriceToLine(newItem, {
|
|
985
833
|
promoUnitPrice,
|
|
986
834
|
originalBasePrice,
|
|
987
|
-
strategyTitle: priced.strategyMetadata
|
|
835
|
+
strategyTitle: (_b = priced.strategyMetadata) == null ? void 0 : _b.name
|
|
988
836
|
});
|
|
989
837
|
} else {
|
|
990
|
-
|
|
991
|
-
const
|
|
992
|
-
const
|
|
993
|
-
const mainRestore = new _decimal.default(Number(sourceRestore) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
838
|
+
const optionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(newItem)).toNumber();
|
|
839
|
+
const sourceRestore = new import_decimal.default(originalBasePrice).toDecimalPlaces(2).toFixed(2);
|
|
840
|
+
const mainRestore = new import_decimal.default(Number(sourceRestore) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
994
841
|
metadata.source_product_price = sourceRestore;
|
|
995
842
|
metadata.main_product_selling_price = mainRestore;
|
|
996
843
|
metadata.price_schema_version = 2;
|
|
997
|
-
newItem.selling_price = (0,
|
|
844
|
+
newItem.selling_price = (0, import_utils.composeLinePrice)({
|
|
998
845
|
mainPrice: mainRestore,
|
|
999
846
|
bundle: newItem.product_bundle
|
|
1000
847
|
});
|
|
1001
848
|
updatePromotionDiscountList(newItem, null);
|
|
1002
849
|
}
|
|
1003
850
|
}
|
|
1004
|
-
newItem.num = priced.isSplit ? (0,
|
|
1005
|
-
|
|
1006
|
-
// 拆分行:生成新 uid,复制原行
|
|
851
|
+
newItem.num = priced.isSplit ? (0, import_utils2.getSafeProductNum)(priced.quantity) : sourceCartNum;
|
|
1007
852
|
if (priced.isSplit) {
|
|
1008
|
-
metadata.unique_identification_number = (0,
|
|
853
|
+
metadata.unique_identification_number = (0, import_utils.createUuidV4)();
|
|
1009
854
|
}
|
|
1010
855
|
if (priced.strategyId) {
|
|
1011
856
|
const actionMeta = strategyActionMap.get(priced.strategyId);
|
|
@@ -1015,19 +860,17 @@ function processCartPromotion(list, evaluator, options) {
|
|
|
1015
860
|
inPromotion: priced.inPromotion,
|
|
1016
861
|
originalPrice: originalBasePrice,
|
|
1017
862
|
finalPrice: priced.finalPrice,
|
|
1018
|
-
actionType: actionMeta
|
|
1019
|
-
actionDetail: actionMeta
|
|
863
|
+
actionType: actionMeta == null ? void 0 : actionMeta.actionType,
|
|
864
|
+
actionDetail: actionMeta == null ? void 0 : actionMeta.actionDetail
|
|
1020
865
|
};
|
|
1021
866
|
const bundleIdx = priced.matchedBundleIndex;
|
|
1022
|
-
if (bundleIdx !==
|
|
867
|
+
if (bundleIdx !== void 0 && Array.isArray(newItem.product_bundle) && newItem.product_bundle[bundleIdx]) {
|
|
1023
868
|
newItem.product_bundle[bundleIdx]._promotion = promotionInfo;
|
|
1024
869
|
} else {
|
|
1025
870
|
metadata._promotion = promotionInfo;
|
|
1026
871
|
}
|
|
1027
872
|
}
|
|
1028
873
|
newItem.metadata = metadata;
|
|
1029
|
-
|
|
1030
|
-
// 5.1 第一个参与「买X送Y」策略的主商品,挂 giftInfo
|
|
1031
874
|
if (priced.inPromotion && priced.strategyId) {
|
|
1032
875
|
const gift = strategyGiftInfoMap.get(priced.strategyId);
|
|
1033
876
|
if (gift && Array.isArray(gift.giftOptions) && gift.giftOptions.length > 0 && !strategyGiftInfoOwner.has(priced.strategyId)) {
|
|
@@ -1037,79 +880,74 @@ function processCartPromotion(list, evaluator, options) {
|
|
|
1037
880
|
giftOptions: gift.giftOptions
|
|
1038
881
|
};
|
|
1039
882
|
const bundleIdx = priced.matchedBundleIndex;
|
|
1040
|
-
if (bundleIdx !==
|
|
883
|
+
if (bundleIdx !== void 0 && Array.isArray(newItem.product_bundle) && ((_c = newItem.product_bundle[bundleIdx]) == null ? void 0 : _c._promotion)) {
|
|
1041
884
|
newItem.product_bundle[bundleIdx]._promotion.giftInfo = giftInfoData;
|
|
1042
885
|
} else if (metadata._promotion) {
|
|
1043
886
|
metadata._promotion.giftInfo = giftInfoData;
|
|
1044
887
|
}
|
|
1045
|
-
strategyGiftInfoOwner.set(
|
|
888
|
+
strategyGiftInfoOwner.set(
|
|
889
|
+
priced.strategyId,
|
|
890
|
+
getOrderProductUid(newItem)
|
|
891
|
+
);
|
|
1046
892
|
}
|
|
1047
893
|
}
|
|
1048
|
-
|
|
1049
|
-
// 记录原商品 uid(用于排序与未满足匹配)
|
|
1050
894
|
newItem._sortIndex = originalIndex;
|
|
1051
895
|
newItem._sortSubIndex = priced.inPromotion ? 0 : 1;
|
|
1052
896
|
newItem._originalProductUid = getOrderProductUid(originalItem);
|
|
1053
897
|
processedProducts.push(newItem);
|
|
1054
898
|
}
|
|
1055
|
-
|
|
1056
|
-
// 7. 赠品/编辑商品原样拼回;同时同步赠品的 sourceProductIds / sourceProductId
|
|
1057
|
-
for (const {
|
|
1058
|
-
item,
|
|
1059
|
-
originalListIndex
|
|
1060
|
-
} of existingGiftsWithIndex) {
|
|
899
|
+
for (const { item, originalListIndex } of existingGiftsWithIndex) {
|
|
1061
900
|
const next = item;
|
|
1062
901
|
next._sortIndex = originalListIndex;
|
|
1063
902
|
next._sortSubIndex = 0;
|
|
1064
|
-
const strategyId = getGiftInfo(next)
|
|
903
|
+
const strategyId = (_d = getGiftInfo(next)) == null ? void 0 : _d.strategyId;
|
|
1065
904
|
if (strategyId) {
|
|
1066
905
|
const latest = strategyGiftInfoMap.get(strategyId);
|
|
1067
906
|
const owner = strategyGiftInfoOwner.get(strategyId);
|
|
1068
|
-
if (latest && next.metadata
|
|
907
|
+
if (latest && ((_e = next.metadata) == null ? void 0 : _e._giftInfo)) {
|
|
1069
908
|
next.metadata._giftInfo.sourceProductIds = latest.sourceProductIds;
|
|
1070
909
|
}
|
|
1071
|
-
if (owner && next.metadata
|
|
910
|
+
if (owner && ((_f = next.metadata) == null ? void 0 : _f._giftInfo)) {
|
|
1072
911
|
next.metadata._giftInfo.sourceProductId = owner;
|
|
1073
912
|
}
|
|
1074
913
|
}
|
|
1075
914
|
processedProducts.push(next);
|
|
1076
915
|
}
|
|
1077
|
-
for (const {
|
|
1078
|
-
item,
|
|
1079
|
-
originalListIndex
|
|
1080
|
-
} of editProductsWithIndex) {
|
|
916
|
+
for (const { item, originalListIndex } of editProductsWithIndex) {
|
|
1081
917
|
const next = item;
|
|
1082
918
|
next._sortIndex = originalListIndex;
|
|
1083
919
|
next._sortSubIndex = 0;
|
|
1084
920
|
processedProducts.push(next);
|
|
1085
921
|
}
|
|
1086
|
-
|
|
1087
|
-
// 8. 排序回原顺序,参与促销的拆分行排在前
|
|
1088
922
|
processedProducts.sort((a, b) => {
|
|
1089
|
-
if (a._sortIndex !== b._sortIndex)
|
|
923
|
+
if (a._sortIndex !== b._sortIndex)
|
|
924
|
+
return a._sortIndex - b._sortIndex;
|
|
1090
925
|
return a._sortSubIndex - b._sortSubIndex;
|
|
1091
926
|
});
|
|
1092
|
-
|
|
1093
|
-
// 8.1 同款参与促销行:先去重(买赠+满减并存)再合并 num
|
|
1094
927
|
const dedupedPromotionLines = dedupePromotionProcessedLines(processedProducts);
|
|
1095
928
|
processedProducts.splice(0, processedProducts.length, ...dedupedPromotionLines);
|
|
1096
929
|
const mergedPromotionLines = mergeIdenticalPromotionCartLines(processedProducts);
|
|
1097
930
|
processedProducts.splice(0, processedProducts.length, ...mergedPromotionLines);
|
|
1098
931
|
const splitPromoLines = splitXItemsPromoLinesByGroup(processedProducts, strategyActionMap);
|
|
1099
932
|
processedProducts.splice(0, processedProducts.length, ...splitPromoLines);
|
|
1100
|
-
|
|
1101
|
-
// 9. 给「有适用策略但未参与促销」的主商品打 inPromotion:false
|
|
1102
933
|
for (const product of processedProducts) {
|
|
1103
934
|
const metadata = product.metadata || {};
|
|
1104
|
-
if (metadata._promotion)
|
|
1105
|
-
|
|
935
|
+
if (metadata._promotion)
|
|
936
|
+
continue;
|
|
937
|
+
if (getGiftInfo(product))
|
|
938
|
+
continue;
|
|
1106
939
|
const lookupUid = String(product._originalProductUid ?? getOrderProductUid(product));
|
|
1107
|
-
const originalIndex = mainProducts.findIndex(
|
|
1108
|
-
|
|
940
|
+
const originalIndex = mainProducts.findIndex(
|
|
941
|
+
(item) => getOrderProductUid(item) === lookupUid
|
|
942
|
+
);
|
|
943
|
+
if (originalIndex === -1)
|
|
944
|
+
continue;
|
|
1109
945
|
const strategyData = applicableStrategiesResult[originalIndex];
|
|
1110
|
-
if (!strategyData || !strategyData.hasApplicableStrategy)
|
|
946
|
+
if (!strategyData || !strategyData.hasApplicableStrategy)
|
|
947
|
+
continue;
|
|
1111
948
|
const first = strategyData.applicableStrategies[0];
|
|
1112
|
-
if (!first)
|
|
949
|
+
if (!first)
|
|
950
|
+
continue;
|
|
1113
951
|
const originalPrice = getOrderProductOriginalPriceForPromotion(mainProducts[originalIndex]);
|
|
1114
952
|
metadata._promotion = {
|
|
1115
953
|
strategyId: first.strategyId,
|
|
@@ -1120,24 +958,21 @@ function processCartPromotion(list, evaluator, options) {
|
|
|
1120
958
|
};
|
|
1121
959
|
product.metadata = metadata;
|
|
1122
960
|
}
|
|
1123
|
-
|
|
1124
|
-
// 10. 赠品操作(在更新 lastEvaluatedGiftCount 前做对比)
|
|
1125
961
|
const giftActions = calculateGiftActions(extendedGifts, existingGifts);
|
|
1126
|
-
|
|
1127
|
-
// 10.1 更新 lastEvaluatedGiftCount,便于下次评估时判别「策略已变」
|
|
1128
962
|
for (const gift of existingGifts) {
|
|
1129
|
-
const strategyId = getGiftInfo(gift)
|
|
1130
|
-
if (!strategyId)
|
|
963
|
+
const strategyId = (_g = getGiftInfo(gift)) == null ? void 0 : _g.strategyId;
|
|
964
|
+
if (!strategyId)
|
|
965
|
+
continue;
|
|
1131
966
|
const latest = strategyGiftInfoMap.get(strategyId);
|
|
1132
|
-
if (latest && gift.metadata
|
|
967
|
+
if (latest && ((_h = gift.metadata) == null ? void 0 : _h._giftInfo)) {
|
|
1133
968
|
gift.metadata._giftInfo.lastEvaluatedGiftCount = latest.giftCount;
|
|
1134
969
|
}
|
|
1135
970
|
}
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
971
|
+
const unfulfilledPromotions = calculateUnfulfilledPromotions(
|
|
972
|
+
processedProducts,
|
|
973
|
+
applicableStrategiesResult,
|
|
974
|
+
mainProducts
|
|
975
|
+
);
|
|
1141
976
|
for (const product of processedProducts) {
|
|
1142
977
|
delete product._sortIndex;
|
|
1143
978
|
delete product._sortSubIndex;
|
|
@@ -1152,4 +987,18 @@ function processCartPromotion(list, evaluator, options) {
|
|
|
1152
987
|
giftActions,
|
|
1153
988
|
unfulfilledPromotions
|
|
1154
989
|
};
|
|
1155
|
-
}
|
|
990
|
+
}
|
|
991
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
992
|
+
0 && (module.exports = {
|
|
993
|
+
appendPromotionTags,
|
|
994
|
+
buildConsolidateKeyForPromotion,
|
|
995
|
+
calculateUnfulfilledPromotions,
|
|
996
|
+
extractProductMatchIdentifiersFromStrategyConfig,
|
|
997
|
+
getOrderProductBasePrice,
|
|
998
|
+
getOrderProductOriginalPriceForPromotion,
|
|
999
|
+
getOrderProductUid,
|
|
1000
|
+
mergeIdenticalPromotionCartLines,
|
|
1001
|
+
processCartPromotion,
|
|
1002
|
+
resolveStrategyEligibleProducts,
|
|
1003
|
+
resolveStrategyRequiredQuantity
|
|
1004
|
+
});
|