@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,120 +1,126 @@
|
|
|
1
|
-
|
|
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);
|
|
2
28
|
|
|
3
|
-
|
|
4
|
-
|
|
29
|
+
// src/solution/ScanOrder/utils.ts
|
|
30
|
+
var utils_exports = {};
|
|
31
|
+
__export(utils_exports, {
|
|
32
|
+
aggregateItemRuleLimit: () => aggregateItemRuleLimit,
|
|
33
|
+
attachItemRuleLimitsToTopLevelProducts: () => attachItemRuleLimitsToTopLevelProducts,
|
|
34
|
+
buildItemRuleBusinessData: () => buildItemRuleBusinessData,
|
|
35
|
+
buildProductKey: () => buildProductKey,
|
|
36
|
+
buildProductLineFingerprint: () => buildProductLineFingerprint,
|
|
37
|
+
buildQuantityLimitIndex: () => buildQuantityLimitIndex,
|
|
38
|
+
collectLinkProductIdsFromReservationRules: () => collectLinkProductIdsFromReservationRules,
|
|
39
|
+
computeResourceIsFull: () => computeResourceIsFull,
|
|
40
|
+
createEmptySummary: () => createEmptySummary,
|
|
41
|
+
extractStrategyModelIdsFromTableConfig: () => extractStrategyModelIdsFromTableConfig,
|
|
42
|
+
filterProductsForScanOrderMore: () => filterProductsForScanOrderMore,
|
|
43
|
+
findReservationRuleProductByResourceId: () => findReservationRuleProductByResourceId,
|
|
44
|
+
getProductIdentityIndex: () => getProductIdentityIndex,
|
|
45
|
+
getSafeProductNum: () => getSafeProductNum,
|
|
46
|
+
getTopLevelProductId: () => getTopLevelProductId,
|
|
47
|
+
getTopLevelVariantId: () => getTopLevelVariantId,
|
|
48
|
+
hasCustomCapacityProduct: () => hasCustomCapacityProduct,
|
|
49
|
+
isIdentityMatch: () => isIdentityMatch,
|
|
50
|
+
isSkuOnlyDeleteIdentity: () => isSkuOnlyDeleteIdentity,
|
|
51
|
+
normalizeEnabledItemRuleIds: () => normalizeEnabledItemRuleIds,
|
|
52
|
+
normalizeItemRuleStrategies: () => normalizeItemRuleStrategies,
|
|
53
|
+
normalizeOrderProduct: () => normalizeOrderProduct,
|
|
54
|
+
pickFirstCustomCapacityDimensionId: () => pickFirstCustomCapacityDimensionId,
|
|
55
|
+
pickFirstCustomCapacityPaxBounds: () => pickFirstCustomCapacityPaxBounds,
|
|
56
|
+
pickFirstDurationMinutesFromProducts: () => pickFirstDurationMinutesFromProducts,
|
|
57
|
+
resolveSkuMatchedQuantityLimits: () => resolveSkuMatchedQuantityLimits,
|
|
58
|
+
toBoolean: () => toBoolean,
|
|
59
|
+
toNonNegativeInt: () => toNonNegativeInt,
|
|
60
|
+
toNonNegativeNumber: () => toNonNegativeNumber,
|
|
61
|
+
toPositiveString: () => toPositiveString,
|
|
62
|
+
toPriceString: () => toPriceString
|
|
5
63
|
});
|
|
6
|
-
exports
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
exports.buildQuantityLimitIndex = buildQuantityLimitIndex;
|
|
12
|
-
exports.collectLinkProductIdsFromReservationRules = collectLinkProductIdsFromReservationRules;
|
|
13
|
-
exports.computeResourceIsFull = computeResourceIsFull;
|
|
14
|
-
exports.createEmptySummary = createEmptySummary;
|
|
15
|
-
exports.extractStrategyModelIdsFromTableConfig = extractStrategyModelIdsFromTableConfig;
|
|
16
|
-
exports.filterProductsForScanOrderMore = filterProductsForScanOrderMore;
|
|
17
|
-
exports.findReservationRuleProductByResourceId = findReservationRuleProductByResourceId;
|
|
18
|
-
exports.getProductIdentityIndex = getProductIdentityIndex;
|
|
19
|
-
exports.getSafeProductNum = getSafeProductNum;
|
|
20
|
-
exports.getTopLevelProductId = getTopLevelProductId;
|
|
21
|
-
exports.getTopLevelVariantId = getTopLevelVariantId;
|
|
22
|
-
exports.hasCustomCapacityProduct = hasCustomCapacityProduct;
|
|
23
|
-
exports.isIdentityMatch = isIdentityMatch;
|
|
24
|
-
exports.isSkuOnlyDeleteIdentity = isSkuOnlyDeleteIdentity;
|
|
25
|
-
exports.normalizeEnabledItemRuleIds = normalizeEnabledItemRuleIds;
|
|
26
|
-
exports.normalizeItemRuleStrategies = normalizeItemRuleStrategies;
|
|
27
|
-
exports.normalizeOrderProduct = normalizeOrderProduct;
|
|
28
|
-
exports.pickFirstCustomCapacityDimensionId = pickFirstCustomCapacityDimensionId;
|
|
29
|
-
exports.pickFirstCustomCapacityPaxBounds = pickFirstCustomCapacityPaxBounds;
|
|
30
|
-
exports.pickFirstDurationMinutesFromProducts = pickFirstDurationMinutesFromProducts;
|
|
31
|
-
exports.resolveSkuMatchedQuantityLimits = resolveSkuMatchedQuantityLimits;
|
|
32
|
-
exports.toBoolean = toBoolean;
|
|
33
|
-
exports.toNonNegativeInt = toNonNegativeInt;
|
|
34
|
-
exports.toNonNegativeNumber = toNonNegativeNumber;
|
|
35
|
-
exports.toPositiveString = toPositiveString;
|
|
36
|
-
exports.toPriceString = toPriceString;
|
|
37
|
-
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
38
|
-
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
39
|
-
var _utils = require("../../modules/Order/utils");
|
|
40
|
-
var _manualProductDiscount = require("../../modules/Order/utils/manualProductDiscount");
|
|
41
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
42
|
-
/**
|
|
43
|
-
* 构建金额全为 0 的空 summary。
|
|
44
|
-
* 作为尚未计算金额时的兜底默认值,避免下游因 undefined 报错。
|
|
45
|
-
*/
|
|
64
|
+
module.exports = __toCommonJS(utils_exports);
|
|
65
|
+
var import_dayjs = __toESM(require("dayjs"));
|
|
66
|
+
var import_decimal = __toESM(require("decimal.js"));
|
|
67
|
+
var import_utils = require("../../modules/Order/utils");
|
|
68
|
+
var import_manualProductDiscount = require("../../modules/Order/utils/manualProductDiscount");
|
|
46
69
|
function createEmptySummary() {
|
|
47
70
|
return {
|
|
48
71
|
product_quantity: 0,
|
|
49
|
-
product_original_amount:
|
|
50
|
-
product_amount:
|
|
51
|
-
product_expect_amount:
|
|
52
|
-
product_tax_fee:
|
|
53
|
-
shipping_fee:
|
|
54
|
-
shipping_tax_fee:
|
|
55
|
-
tax_fee:
|
|
56
|
-
surcharge_fee:
|
|
72
|
+
product_original_amount: "0.00",
|
|
73
|
+
product_amount: "0.00",
|
|
74
|
+
product_expect_amount: "0.00",
|
|
75
|
+
product_tax_fee: "0.00",
|
|
76
|
+
shipping_fee: "0.00",
|
|
77
|
+
shipping_tax_fee: "0.00",
|
|
78
|
+
tax_fee: "0.00",
|
|
79
|
+
surcharge_fee: "0.00",
|
|
57
80
|
surcharges: [],
|
|
58
|
-
discount_amount:
|
|
59
|
-
deposit_amount:
|
|
60
|
-
expect_amount:
|
|
61
|
-
total_amount:
|
|
62
|
-
total_refund_amount:
|
|
63
|
-
customer_paid_amount:
|
|
64
|
-
order_paid_amount:
|
|
65
|
-
amount_gap:
|
|
66
|
-
rounding_amount:
|
|
67
|
-
pay_service_charge_amount:
|
|
81
|
+
discount_amount: "0.00",
|
|
82
|
+
deposit_amount: "0.00",
|
|
83
|
+
expect_amount: "0.00",
|
|
84
|
+
total_amount: "0.00",
|
|
85
|
+
total_refund_amount: "0.00",
|
|
86
|
+
customer_paid_amount: "0.00",
|
|
87
|
+
order_paid_amount: "0.00",
|
|
88
|
+
amount_gap: "0.00",
|
|
89
|
+
rounding_amount: "0.00",
|
|
90
|
+
pay_service_charge_amount: "0.00"
|
|
68
91
|
};
|
|
69
92
|
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* 商品数量安全取值。
|
|
73
|
-
* - NaN / undefined / < 1 均视作 1(最低起订量)
|
|
74
|
-
* - 有值时取整(不支持小数数量)
|
|
75
|
-
*/
|
|
76
93
|
function getSafeProductNum(num) {
|
|
77
|
-
if (!num || Number.isNaN(num))
|
|
78
|
-
|
|
94
|
+
if (!num || Number.isNaN(num))
|
|
95
|
+
return 1;
|
|
96
|
+
if (num < 1)
|
|
97
|
+
return 1;
|
|
79
98
|
return Math.floor(num);
|
|
80
99
|
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* 宽松布尔值转换。
|
|
84
|
-
* 兼容后端/配置中心常见的 boolean / number / string 表达,统一归一成 true/false。
|
|
85
|
-
*/
|
|
86
100
|
function toBoolean(value) {
|
|
87
|
-
if (typeof value ===
|
|
88
|
-
|
|
89
|
-
if (typeof value ===
|
|
101
|
+
if (typeof value === "boolean")
|
|
102
|
+
return value;
|
|
103
|
+
if (typeof value === "number")
|
|
104
|
+
return value !== 0;
|
|
105
|
+
if (typeof value === "string") {
|
|
90
106
|
const normalized = value.trim().toLowerCase();
|
|
91
|
-
return [
|
|
107
|
+
return ["1", "true", "yes", "y", "on"].includes(normalized);
|
|
92
108
|
}
|
|
93
109
|
return false;
|
|
94
110
|
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* 将值归一化为有效的正向字符串。
|
|
98
|
-
* null / undefined / 空串 / '0' / 'null' 统一视为无效值并返回 undefined。
|
|
99
|
-
*/
|
|
100
111
|
function toPositiveString(value) {
|
|
101
|
-
if (value === null || value ===
|
|
112
|
+
if (value === null || value === void 0 || value === "")
|
|
113
|
+
return void 0;
|
|
102
114
|
const normalized = String(value).trim();
|
|
103
|
-
if (!normalized || normalized ===
|
|
104
|
-
return
|
|
115
|
+
if (!normalized || normalized === "0" || normalized.toLowerCase() === "null") {
|
|
116
|
+
return void 0;
|
|
105
117
|
}
|
|
106
118
|
return normalized;
|
|
107
119
|
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* 归一化 item rule 策略模型 ID 列表。
|
|
111
|
-
* - 支持 string / number 混合输入
|
|
112
|
-
* - 仅保留 > 0 的合法数字
|
|
113
|
-
* - 自动去重
|
|
114
|
-
*/
|
|
115
120
|
function normalizeEnabledItemRuleIds(rawIds) {
|
|
116
|
-
if (!Array.isArray(rawIds))
|
|
117
|
-
|
|
121
|
+
if (!Array.isArray(rawIds))
|
|
122
|
+
return [];
|
|
123
|
+
const uniqueIds = /* @__PURE__ */ new Set();
|
|
118
124
|
for (const item of rawIds) {
|
|
119
125
|
const strategyId = Number(item);
|
|
120
126
|
if (Number.isFinite(strategyId) && strategyId > 0) {
|
|
@@ -123,27 +129,27 @@ function normalizeEnabledItemRuleIds(rawIds) {
|
|
|
123
129
|
}
|
|
124
130
|
return Array.from(uniqueIds);
|
|
125
131
|
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* 从 tableConfig 中提取合法策略模型 ID 列表。
|
|
129
|
-
*/
|
|
130
132
|
function extractStrategyModelIdsFromTableConfig(tableConfig) {
|
|
131
|
-
const rawIds = Array.isArray(tableConfig
|
|
132
|
-
return rawIds.map(id => Number(id)).filter(id => Number.isFinite(id) && id > 0);
|
|
133
|
+
const rawIds = Array.isArray(tableConfig == null ? void 0 : tableConfig.strategy_model_ids) ? tableConfig.strategy_model_ids : [];
|
|
134
|
+
return rawIds.map((id) => Number(id)).filter((id) => Number.isFinite(id) && id > 0);
|
|
133
135
|
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* 仅保留 item_rule 类型策略。
|
|
137
|
-
*/
|
|
138
136
|
function normalizeItemRuleStrategies(configs) {
|
|
139
|
-
if (!Array.isArray(configs))
|
|
140
|
-
|
|
137
|
+
if (!Array.isArray(configs))
|
|
138
|
+
return [];
|
|
139
|
+
return configs.filter(
|
|
140
|
+
(config) => {
|
|
141
|
+
var _a;
|
|
142
|
+
return Boolean(
|
|
143
|
+
config && typeof config === "object" && ((_a = config == null ? void 0 : config.metadata) == null ? void 0 : _a.type) === "item_rule"
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
);
|
|
141
147
|
}
|
|
142
148
|
function toNonNegativeNumber(value) {
|
|
143
|
-
if (typeof value ===
|
|
149
|
+
if (typeof value === "number") {
|
|
144
150
|
return Number.isFinite(value) && value >= 0 ? value : 0;
|
|
145
151
|
}
|
|
146
|
-
if (typeof value ===
|
|
152
|
+
if (typeof value === "string") {
|
|
147
153
|
const parsed = Number(value);
|
|
148
154
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
|
|
149
155
|
}
|
|
@@ -152,45 +158,49 @@ function toNonNegativeNumber(value) {
|
|
|
152
158
|
function toNonNegativeInt(value) {
|
|
153
159
|
return Math.floor(toNonNegativeNumber(value));
|
|
154
160
|
}
|
|
155
|
-
function toPriceString(value, fallback =
|
|
161
|
+
function toPriceString(value, fallback = "0.00") {
|
|
156
162
|
const parsedValue = Number(value);
|
|
157
|
-
if (Number.isNaN(parsedValue))
|
|
163
|
+
if (Number.isNaN(parsedValue))
|
|
164
|
+
return fallback;
|
|
158
165
|
return parsedValue.toFixed(2);
|
|
159
166
|
}
|
|
160
167
|
function buildProductKey(productId, productVariantId) {
|
|
161
168
|
return `${productId}_${productVariantId}`;
|
|
162
169
|
}
|
|
163
|
-
|
|
164
|
-
/** 加餐接口只提交本次新增商品,过滤掉首单预约占位规则行。 */
|
|
165
170
|
function filterProductsForScanOrderMore(products = []) {
|
|
166
|
-
return products.filter(product =>
|
|
171
|
+
return products.filter((product) => {
|
|
172
|
+
var _a;
|
|
173
|
+
return ((_a = product.metadata) == null ? void 0 : _a.is_rule) !== true;
|
|
174
|
+
});
|
|
167
175
|
}
|
|
168
176
|
function getTopLevelProductId(product) {
|
|
169
177
|
const rawProductId = product.product_id ?? product.id;
|
|
170
178
|
const productId = Number(rawProductId);
|
|
171
|
-
if (!Number.isFinite(productId) || productId <= 0)
|
|
179
|
+
if (!Number.isFinite(productId) || productId <= 0)
|
|
180
|
+
return null;
|
|
172
181
|
return productId;
|
|
173
182
|
}
|
|
174
183
|
function getTopLevelVariantId(product) {
|
|
175
184
|
const rawVariantId = product.product_variant_id ?? product.variant_id;
|
|
176
|
-
if (rawVariantId ===
|
|
185
|
+
if (rawVariantId === void 0 || rawVariantId === null || rawVariantId === "") {
|
|
177
186
|
return null;
|
|
178
187
|
}
|
|
179
188
|
const variantId = Number(rawVariantId);
|
|
180
|
-
if (!Number.isFinite(variantId) || variantId <= 0)
|
|
189
|
+
if (!Number.isFinite(variantId) || variantId <= 0)
|
|
190
|
+
return null;
|
|
181
191
|
return variantId;
|
|
182
192
|
}
|
|
183
193
|
function buildQuantityLimitIndex(limits) {
|
|
184
|
-
const exactLimitMap = new Map();
|
|
185
|
-
const productLimitMap = new Map();
|
|
194
|
+
const exactLimitMap = /* @__PURE__ */ new Map();
|
|
195
|
+
const productLimitMap = /* @__PURE__ */ new Map();
|
|
186
196
|
for (const limit of limits) {
|
|
187
197
|
const targets = limit.targets || [];
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if (targets.length !== 1) continue;
|
|
198
|
+
if (targets.length !== 1)
|
|
199
|
+
continue;
|
|
191
200
|
const target = targets[0];
|
|
192
201
|
const productId = Number(target.product_id);
|
|
193
|
-
if (!Number.isFinite(productId) || productId <= 0)
|
|
202
|
+
if (!Number.isFinite(productId) || productId <= 0)
|
|
203
|
+
continue;
|
|
194
204
|
const variantId = Number(target.product_variant_id);
|
|
195
205
|
const hasVariant = Number.isFinite(variantId) && variantId > 0;
|
|
196
206
|
if (hasVariant) {
|
|
@@ -208,53 +218,44 @@ function buildQuantityLimitIndex(limits) {
|
|
|
208
218
|
};
|
|
209
219
|
}
|
|
210
220
|
function resolveSkuMatchedQuantityLimits(params) {
|
|
211
|
-
const {
|
|
212
|
-
productId,
|
|
213
|
-
variantId,
|
|
214
|
-
limitIndex
|
|
215
|
-
} = params;
|
|
221
|
+
const { productId, variantId, limitIndex } = params;
|
|
216
222
|
const exactMatched = variantId && variantId > 0 ? limitIndex.exactLimitMap.get(buildProductKey(productId, variantId)) || [] : [];
|
|
217
223
|
const productMatched = limitIndex.productLimitMap.get(productId) || [];
|
|
218
224
|
return [...exactMatched, ...productMatched];
|
|
219
225
|
}
|
|
220
226
|
function aggregateItemRuleLimit(matchedLimits) {
|
|
221
|
-
if (!matchedLimits.length)
|
|
227
|
+
if (!matchedLimits.length)
|
|
228
|
+
return null;
|
|
222
229
|
let min;
|
|
223
230
|
let max;
|
|
224
231
|
let remainingMax;
|
|
225
232
|
let exact;
|
|
226
233
|
let mustInclude = false;
|
|
227
|
-
|
|
228
|
-
// 聚合 validationMessage 按 min / max 两个方向分别输出:
|
|
229
|
-
// - maxValidationMessage:触发"当前 max / remainingMax / exact"的那条规则的文案
|
|
230
|
-
// - minValidationMessage:触发"当前 min / exact"的那条规则的文案
|
|
231
|
-
// 各自再回退到其他带文案的规则(最后回退到第一条非空 validationMessage)。
|
|
232
|
-
// 前端可根据"加号/减号被拦"的方向取对应文案。
|
|
233
234
|
let maxSourceLimit;
|
|
234
235
|
let remainingMaxSourceLimit;
|
|
235
236
|
let exactSourceLimit;
|
|
236
237
|
let minSourceLimit;
|
|
237
238
|
let firstMessagedLimit;
|
|
238
239
|
for (const limit of matchedLimits) {
|
|
239
|
-
if (typeof limit.requiredMin ===
|
|
240
|
-
if (min ===
|
|
240
|
+
if (typeof limit.requiredMin === "number" && Number.isFinite(limit.requiredMin)) {
|
|
241
|
+
if (min === void 0 || limit.requiredMin > min) {
|
|
241
242
|
min = limit.requiredMin;
|
|
242
243
|
minSourceLimit = limit;
|
|
243
244
|
}
|
|
244
245
|
}
|
|
245
|
-
if (typeof limit.requiredMax ===
|
|
246
|
-
if (max ===
|
|
246
|
+
if (typeof limit.requiredMax === "number" && Number.isFinite(limit.requiredMax)) {
|
|
247
|
+
if (max === void 0 || limit.requiredMax < max) {
|
|
247
248
|
max = limit.requiredMax;
|
|
248
249
|
maxSourceLimit = limit;
|
|
249
250
|
}
|
|
250
251
|
}
|
|
251
|
-
if (typeof limit.remainingMax ===
|
|
252
|
-
if (remainingMax ===
|
|
252
|
+
if (typeof limit.remainingMax === "number" && Number.isFinite(limit.remainingMax)) {
|
|
253
|
+
if (remainingMax === void 0 || limit.remainingMax < remainingMax) {
|
|
253
254
|
remainingMax = limit.remainingMax;
|
|
254
255
|
remainingMaxSourceLimit = limit;
|
|
255
256
|
}
|
|
256
257
|
}
|
|
257
|
-
if (typeof limit.requiredExact ===
|
|
258
|
+
if (typeof limit.requiredExact === "number" && Number.isFinite(limit.requiredExact)) {
|
|
258
259
|
exact = limit.requiredExact;
|
|
259
260
|
exactSourceLimit = limit;
|
|
260
261
|
}
|
|
@@ -263,19 +264,16 @@ function aggregateItemRuleLimit(matchedLimits) {
|
|
|
263
264
|
firstMessagedLimit = limit;
|
|
264
265
|
}
|
|
265
266
|
}
|
|
266
|
-
if (typeof exact ===
|
|
267
|
+
if (typeof exact === "number" && Number.isFinite(exact)) {
|
|
267
268
|
min = exact;
|
|
268
269
|
max = exact;
|
|
269
270
|
}
|
|
270
271
|
const maxMessageSource = maxSourceLimit || remainingMaxSourceLimit || exactSourceLimit || firstMessagedLimit;
|
|
271
272
|
const minMessageSource = minSourceLimit || exactSourceLimit || firstMessagedLimit;
|
|
272
|
-
const maxValidationMessage = maxMessageSource
|
|
273
|
-
const rawMaxValidationMessage = maxMessageSource
|
|
274
|
-
const minValidationMessage = minMessageSource
|
|
275
|
-
const rawMinValidationMessage = minMessageSource
|
|
276
|
-
|
|
277
|
-
// validationMessage / rawValidationMessage 保留为"最严格限制"的聚合文案,
|
|
278
|
-
// 便于旧消费者(只关心 max 侧)不破坏。优先 max → min。
|
|
273
|
+
const maxValidationMessage = maxMessageSource == null ? void 0 : maxMessageSource.validationMessage;
|
|
274
|
+
const rawMaxValidationMessage = maxMessageSource == null ? void 0 : maxMessageSource.rawValidationMessage;
|
|
275
|
+
const minValidationMessage = minMessageSource == null ? void 0 : minMessageSource.validationMessage;
|
|
276
|
+
const rawMinValidationMessage = minMessageSource == null ? void 0 : minMessageSource.rawValidationMessage;
|
|
279
277
|
const validationMessage = maxValidationMessage ?? minValidationMessage;
|
|
280
278
|
const rawValidationMessage = rawMaxValidationMessage ?? rawMinValidationMessage;
|
|
281
279
|
return {
|
|
@@ -293,34 +291,28 @@ function aggregateItemRuleLimit(matchedLimits) {
|
|
|
293
291
|
};
|
|
294
292
|
}
|
|
295
293
|
function buildItemRuleBusinessData(params) {
|
|
296
|
-
const {
|
|
297
|
-
tempOrder,
|
|
298
|
-
runtimeConfig,
|
|
299
|
-
itemRuleConfigs
|
|
300
|
-
} = params;
|
|
294
|
+
const { tempOrder, runtimeConfig, itemRuleConfigs } = params;
|
|
301
295
|
const rawPax = runtimeConfig.pax || {};
|
|
302
296
|
const adultPax = toNonNegativeInt(rawPax.adult);
|
|
303
297
|
const childPax = toNonNegativeInt(rawPax.child);
|
|
304
298
|
const totalPax = toNonNegativeInt(rawPax.total) || adultPax + childPax || 1;
|
|
305
299
|
const cartItems = tempOrder.products.reduce((result, product) => {
|
|
306
|
-
if (typeof product.product_id !==
|
|
300
|
+
if (typeof product.product_id !== "number")
|
|
301
|
+
return result;
|
|
307
302
|
result.push({
|
|
308
303
|
product_id: product.product_id,
|
|
309
304
|
quantity: toNonNegativeInt(product.num),
|
|
310
|
-
...
|
|
311
|
-
product_variant_id: product.product_variant_id
|
|
312
|
-
} : {})
|
|
305
|
+
...typeof product.product_variant_id === "number" ? { product_variant_id: product.product_variant_id } : {}
|
|
313
306
|
});
|
|
314
307
|
return result;
|
|
315
308
|
}, []);
|
|
316
309
|
const historicalItems = Array.isArray(runtimeConfig.historicalItems) ? runtimeConfig.historicalItems.reduce((result, item) => {
|
|
317
|
-
if (typeof item
|
|
310
|
+
if (typeof (item == null ? void 0 : item.product_id) !== "number")
|
|
311
|
+
return result;
|
|
318
312
|
result.push({
|
|
319
313
|
product_id: item.product_id,
|
|
320
314
|
quantity: toNonNegativeInt(item.quantity),
|
|
321
|
-
...
|
|
322
|
-
product_variant_id: item.product_variant_id
|
|
323
|
-
} : {})
|
|
315
|
+
...typeof item.product_variant_id === "number" ? { product_variant_id: item.product_variant_id } : {}
|
|
324
316
|
});
|
|
325
317
|
return result;
|
|
326
318
|
}, []) : [];
|
|
@@ -332,20 +324,23 @@ function buildItemRuleBusinessData(params) {
|
|
|
332
324
|
},
|
|
333
325
|
cartItems,
|
|
334
326
|
historicalItems,
|
|
335
|
-
serviceType: runtimeConfig.serviceType ||
|
|
336
|
-
submissionIndex: typeof runtimeConfig.submissionIndex ===
|
|
327
|
+
serviceType: runtimeConfig.serviceType || "dine-in",
|
|
328
|
+
submissionIndex: typeof runtimeConfig.submissionIndex === "number" ? toNonNegativeInt(runtimeConfig.submissionIndex) : tempOrder.order_id ? 1 : 0,
|
|
337
329
|
custom: runtimeConfig.custom || {},
|
|
338
330
|
strategyConfigs: itemRuleConfigs
|
|
339
331
|
};
|
|
340
332
|
}
|
|
341
333
|
function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
|
|
342
|
-
if (!Array.isArray(productList))
|
|
334
|
+
if (!Array.isArray(productList))
|
|
335
|
+
return productList;
|
|
343
336
|
const limitIndex = buildQuantityLimitIndex(limits || []);
|
|
344
337
|
for (const item of productList) {
|
|
345
|
-
if (!item || typeof item !==
|
|
338
|
+
if (!item || typeof item !== "object")
|
|
339
|
+
continue;
|
|
346
340
|
const productItem = item;
|
|
347
341
|
const productId = getTopLevelProductId(productItem);
|
|
348
|
-
if (productId === null)
|
|
342
|
+
if (productId === null)
|
|
343
|
+
continue;
|
|
349
344
|
const variantId = getTopLevelVariantId(productItem);
|
|
350
345
|
const matchedLimits = limits.length ? resolveSkuMatchedQuantityLimits({
|
|
351
346
|
productId,
|
|
@@ -355,134 +350,94 @@ function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
|
|
|
355
350
|
const aggregatedLimit = aggregateItemRuleLimit(matchedLimits);
|
|
356
351
|
if (aggregatedLimit) {
|
|
357
352
|
productItem.item_rule_limit = aggregatedLimit;
|
|
358
|
-
} else if (
|
|
353
|
+
} else if ("item_rule_limit" in productItem) {
|
|
359
354
|
delete productItem.item_rule_limit;
|
|
360
355
|
}
|
|
361
356
|
}
|
|
362
357
|
return productList;
|
|
363
358
|
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* 将选项行 / 套餐行归一成稳定 JSON,用于「同 SKU 是否合并」判断。
|
|
367
|
-
* 数组元素先按主键排序再序列化,避免顺序差异导致误判为不同行。
|
|
368
|
-
*/
|
|
369
359
|
function buildProductLineFingerprint(productOptionItem, productBundle) {
|
|
370
360
|
const optArr = Array.isArray(productOptionItem) ? productOptionItem : [];
|
|
371
|
-
const normalizedOpts = optArr.map(item => ({
|
|
372
|
-
option_group_item_id: Number(item
|
|
373
|
-
option_group_id: Number(item
|
|
374
|
-
num: typeof item
|
|
375
|
-
price: String(item
|
|
361
|
+
const normalizedOpts = optArr.map((item) => ({
|
|
362
|
+
option_group_item_id: Number(item == null ? void 0 : item.option_group_item_id) || 0,
|
|
363
|
+
option_group_id: Number(item == null ? void 0 : item.option_group_id) || 0,
|
|
364
|
+
num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
|
|
365
|
+
price: String((item == null ? void 0 : item.add_price) ?? (item == null ? void 0 : item.price) ?? "")
|
|
376
366
|
})).sort((p, q) => {
|
|
377
367
|
if (p.option_group_item_id !== q.option_group_item_id) {
|
|
378
368
|
return p.option_group_item_id - q.option_group_item_id;
|
|
379
369
|
}
|
|
380
|
-
if (p.option_group_id !== q.option_group_id)
|
|
381
|
-
|
|
370
|
+
if (p.option_group_id !== q.option_group_id)
|
|
371
|
+
return p.option_group_id - q.option_group_id;
|
|
372
|
+
if (p.num !== q.num)
|
|
373
|
+
return p.num - q.num;
|
|
382
374
|
return p.price.localeCompare(q.price);
|
|
383
375
|
});
|
|
384
376
|
const bundleArr = Array.isArray(productBundle) ? productBundle : [];
|
|
385
|
-
const normalizedBundles = bundleArr.map(item => ({
|
|
386
|
-
bundle_id: Number(item
|
|
387
|
-
product_id: Number(item
|
|
388
|
-
num: typeof item
|
|
377
|
+
const normalizedBundles = bundleArr.map((item) => ({
|
|
378
|
+
bundle_id: Number((item == null ? void 0 : item.bundle_id) ?? (item == null ? void 0 : item.id) ?? 0) || 0,
|
|
379
|
+
product_id: Number(item == null ? void 0 : item.product_id) || 0,
|
|
380
|
+
num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1
|
|
389
381
|
})).sort((p, q) => {
|
|
390
|
-
if (p.bundle_id !== q.bundle_id)
|
|
391
|
-
|
|
382
|
+
if (p.bundle_id !== q.bundle_id)
|
|
383
|
+
return p.bundle_id - q.bundle_id;
|
|
384
|
+
if (p.product_id !== q.product_id)
|
|
385
|
+
return p.product_id - q.product_id;
|
|
392
386
|
return p.num - q.num;
|
|
393
387
|
});
|
|
394
388
|
return JSON.stringify([normalizedOpts, normalizedBundles]);
|
|
395
389
|
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* removeProductFromOrder 仅传 SKU 时的通配 identity(对象上未声明选项键)。
|
|
399
|
-
* 与显式 `product_sku: { option: [] }` 区分:后者只匹配「无选项」行。
|
|
400
|
-
*/
|
|
401
390
|
function isSkuOnlyDeleteIdentity(x) {
|
|
402
|
-
if (x.unique_identification_number || x.identity_key)
|
|
403
|
-
|
|
391
|
+
if (x.unique_identification_number || x.identity_key)
|
|
392
|
+
return false;
|
|
393
|
+
return !("product_sku" in x) && !("product_bundle" in x);
|
|
404
394
|
}
|
|
405
395
|
function fingerprintForIdentityWithOptionKeys(x) {
|
|
406
396
|
const row = x;
|
|
407
|
-
const opts =
|
|
408
|
-
const buds =
|
|
397
|
+
const opts = "product_sku" in row ? (0, import_utils.getProductSkuOptions)(row) : [];
|
|
398
|
+
const buds = "product_bundle" in row ? Array.isArray(row.product_bundle) ? row.product_bundle : [] : [];
|
|
409
399
|
return buildProductLineFingerprint(opts, buds);
|
|
410
400
|
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* 判断两个商品 identity 是否匹配(不透明 identity 契约)。
|
|
414
|
-
*
|
|
415
|
-
* 调用约定:始终 `isIdentityMatch(line, callerIdentity)`。
|
|
416
|
-
* - 若 SKU(product_id + product_variant_id)不一致 → 不匹配。
|
|
417
|
-
* - **双方都带** `identity_key` → 严格字符串相等比较(不再猜测合成 key / metadata 桥接)。
|
|
418
|
-
* 这是 opaque identity 契约的标准路径:UI 删改时透传 SDK 回灌的 identity_key。
|
|
419
|
-
* - 否则(即至少一侧未声明 identity_key)→ 进入「SKU 通配 / 显式空选项 / 指纹」回退路径,
|
|
420
|
-
* 忽略线侧 identity_key,按内容语义匹配。这给「行已 opaque、调用方却想按 SKU 通配 / 选项指纹删除」留兼容入口。
|
|
421
|
-
*/
|
|
422
401
|
function isIdentityMatch(a, b) {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
const
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
402
|
+
var _a, _b;
|
|
403
|
+
if (a.product_id !== b.product_id || a.product_variant_id !== b.product_variant_id)
|
|
404
|
+
return false;
|
|
405
|
+
const aUid = ((_a = a.metadata) == null ? void 0 : _a.unique_identification_number) ?? a.unique_identification_number ?? a.identity_key;
|
|
406
|
+
const bUid = ((_b = b.metadata) == null ? void 0 : _b.unique_identification_number) ?? b.unique_identification_number ?? b.identity_key;
|
|
407
|
+
const aHasKey = typeof aUid === "string" && aUid.length > 0;
|
|
408
|
+
const bHasKey = typeof bUid === "string" && bUid.length > 0;
|
|
409
|
+
if (aHasKey && bHasKey)
|
|
410
|
+
return aUid === bUid;
|
|
411
|
+
if (isSkuOnlyDeleteIdentity(a) || isSkuOnlyDeleteIdentity(b))
|
|
412
|
+
return true;
|
|
430
413
|
return fingerprintForIdentityWithOptionKeys(a) === fingerprintForIdentityWithOptionKeys(b);
|
|
431
414
|
}
|
|
432
|
-
|
|
433
|
-
/**
|
|
434
|
-
* 根据 identity 在商品列表中定位下标。
|
|
435
|
-
* 用于判断商品是否已存在(已存在则累加数量,否则新增)。
|
|
436
|
-
*/
|
|
437
415
|
function getProductIdentityIndex(products, identity) {
|
|
438
|
-
return products.findIndex(item => isIdentityMatch(item, identity));
|
|
416
|
+
return products.findIndex((item) => isIdentityMatch(item, identity));
|
|
439
417
|
}
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* 对外部传入的商品对象做归一化(v2 composite 语义):
|
|
443
|
-
* - 补全可选字段默认值(未传则使用兜底值,避免后续计算时因 undefined 导致异常)
|
|
444
|
-
* - 对 num 调用 getSafeProductNum 做安全处理
|
|
445
|
-
* - 保留 _origin 供后续业务流程(如促销规则)使用
|
|
446
|
-
*
|
|
447
|
-
* 价格字段语义(metadata 权威源 + composite 派生):
|
|
448
|
-
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),**不含 option**、
|
|
449
|
-
* **不含折扣**。是推导 main_product_* 的起点。variant 分支优先读 `metadata.origin.variant[vid].price`。
|
|
450
|
-
* - `metadata.main_product_original_price`:`source + Σ(option.price × option.num)`,**含 option**、
|
|
451
|
-
* **不含折扣**。
|
|
452
|
-
* - `metadata.main_product_selling_price`:`main_product_original_price - 主商品券 per-unit amount`,
|
|
453
|
-
* **含 option**、**含折扣**。
|
|
454
|
-
* - 行级 `selling_price` = `main_product_selling_price + Σ(bundle_selling_price × num)`。
|
|
455
|
-
* - 行级 `original_price` = `main_product_original_price + Σ(bundle 原价 × num)`。
|
|
456
|
-
*
|
|
457
|
-
* 迁移与幂等:
|
|
458
|
-
* - `metadata.price_schema_version === 2` → 已新语义归一化,保留 main_product_* 原值(保留折扣)。
|
|
459
|
-
* - 其它情况(v1 / 缺字段 / 无 metadata)→ 按"main_product_selling_price 曾是 main-only"的旧约定
|
|
460
|
-
* 反推 legacyDiscount,再以新 source + options 基准重算。最终统一打上 `price_schema_version: 2`。
|
|
461
|
-
* - 因此多次 normalize 不会重复叠加 option/bundle。
|
|
462
|
-
*/
|
|
463
418
|
function normalizeOrderProduct(product) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
// 不透明 identity 契约:每条订单行必须带 identity_key。
|
|
468
|
-
// 调用方未传时由 SDK 自动生成 UUID,后续 update/remove 只做严格比对,避免猜测合成 key。
|
|
469
|
-
const resolvedIdentityKey = product.metadata?.unique_identification_number ? String(product.metadata.unique_identification_number) : product.unique_identification_number && String(product.unique_identification_number).length > 0 ? String(product.unique_identification_number) : product.identity_key && String(product.identity_key).length > 0 ? String(product.identity_key) : (0, _utils.createUuidV4)();
|
|
419
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
420
|
+
const metadata = { ...product.metadata || {} };
|
|
421
|
+
const resolvedIdentityKey = ((_a = product.metadata) == null ? void 0 : _a.unique_identification_number) ? String(product.metadata.unique_identification_number) : product.unique_identification_number && String(product.unique_identification_number).length > 0 ? String(product.unique_identification_number) : product.identity_key && String(product.identity_key).length > 0 ? String(product.identity_key) : (0, import_utils.createUuidV4)();
|
|
470
422
|
metadata.unique_identification_number = resolvedIdentityKey;
|
|
471
423
|
const priceOverride = metadata.price_override;
|
|
472
|
-
const originOtherBundle = metadata.origin
|
|
424
|
+
const originOtherBundle = (_d = (_c = (_b = metadata.origin) == null ? void 0 : _b._extend) == null ? void 0 : _c.other) == null ? void 0 : _d.bundle;
|
|
473
425
|
let bundleInput = product.product_bundle || [];
|
|
474
|
-
if (priceOverride !==
|
|
475
|
-
const priceById = new Map();
|
|
476
|
-
originOtherBundle.forEach(item => {
|
|
477
|
-
if (item
|
|
426
|
+
if (priceOverride !== void 0 && priceOverride !== null && priceOverride !== "" && Array.isArray(originOtherBundle) && originOtherBundle.length > 0) {
|
|
427
|
+
const priceById = /* @__PURE__ */ new Map();
|
|
428
|
+
originOtherBundle.forEach((item) => {
|
|
429
|
+
if ((item == null ? void 0 : item.id) == null)
|
|
430
|
+
return;
|
|
478
431
|
const unit = item.price ?? item.bundle_selling_price;
|
|
479
|
-
if (unit ===
|
|
432
|
+
if (unit === void 0 || unit === null)
|
|
433
|
+
return;
|
|
480
434
|
priceById.set(String(item.id), String(unit));
|
|
481
435
|
});
|
|
482
436
|
const base = Array.isArray(bundleInput) && bundleInput.length > 0 ? bundleInput : originOtherBundle;
|
|
483
|
-
bundleInput = base.map(item => {
|
|
484
|
-
const unit = priceById.get(String(item
|
|
485
|
-
if (unit ===
|
|
437
|
+
bundleInput = base.map((item) => {
|
|
438
|
+
const unit = priceById.get(String(item == null ? void 0 : item.id));
|
|
439
|
+
if (unit === void 0)
|
|
440
|
+
return item;
|
|
486
441
|
return {
|
|
487
442
|
...item,
|
|
488
443
|
price: unit,
|
|
@@ -490,7 +445,7 @@ function normalizeOrderProduct(product) {
|
|
|
490
445
|
};
|
|
491
446
|
});
|
|
492
447
|
}
|
|
493
|
-
const normalizedBundle = bundleInput.map(item => {
|
|
448
|
+
const normalizedBundle = bundleInput.map((item) => {
|
|
494
449
|
const magnitudeSource = {
|
|
495
450
|
...item,
|
|
496
451
|
// 计算 markdown 净额时,只把真实毛价交给 helper;若只有 bundle_selling_price,
|
|
@@ -503,114 +458,94 @@ function normalizeOrderProduct(product) {
|
|
|
503
458
|
bundle_product_id: item.bundle_product_id ?? item._bundle_product_id,
|
|
504
459
|
bundle_group_id: item.bundle_group_id ?? item.group_id,
|
|
505
460
|
// price 保留毛价(markdown 仍为 5),由 price_type 决定符号。
|
|
506
|
-
price: item.price ?? item.custom_price ?? item.bundle_selling_price ??
|
|
507
|
-
price_type: item.price_type ?? item.custom_price_type ??
|
|
508
|
-
price_type_ext: item.price_type_ext ?? item.custom_price_type_ext ??
|
|
461
|
+
price: item.price ?? item.custom_price ?? item.bundle_selling_price ?? "0.00",
|
|
462
|
+
price_type: item.price_type ?? item.custom_price_type ?? "",
|
|
463
|
+
price_type_ext: item.price_type_ext ?? item.custom_price_type_ext ?? ""
|
|
509
464
|
};
|
|
510
|
-
|
|
511
|
-
normalizedItem.
|
|
512
|
-
if (normalizedItem.price_type === 'markdown' && (normalizedItem.price_type_ext === '' || normalizedItem.price_type_ext === undefined || normalizedItem.price_type_ext === null)) {
|
|
465
|
+
normalizedItem.bundle_selling_price = (0, import_utils.getBundleSellingMagnitude)(magnitudeSource).toFixed(2);
|
|
466
|
+
if (normalizedItem.price_type === "markdown" && (normalizedItem.price_type_ext === "" || normalizedItem.price_type_ext === void 0 || normalizedItem.price_type_ext === null)) {
|
|
513
467
|
normalizedItem.custom_price = normalizedItem.custom_price ?? normalizedItem.price;
|
|
514
468
|
normalizedItem.price = normalizedItem.bundle_selling_price;
|
|
515
469
|
}
|
|
516
|
-
if ((normalizedItem.price_type ===
|
|
470
|
+
if ((normalizedItem.price_type === "markdown" || normalizedItem.price_type === "markup") && (normalizedItem.price_type_ext === "" || normalizedItem.price_type_ext === void 0 || normalizedItem.price_type_ext === null)) {
|
|
517
471
|
delete normalizedItem.original_total;
|
|
518
472
|
}
|
|
519
473
|
return normalizedItem;
|
|
520
474
|
});
|
|
521
|
-
const normalizedOptions = (0,
|
|
522
|
-
const optionSum = (0,
|
|
475
|
+
const normalizedOptions = (0, import_utils.normalizeProductSkuOptions)((_e = product.product_sku) == null ? void 0 : _e.option);
|
|
476
|
+
const optionSum = (0, import_utils.sumOptionUnitPrice)(normalizedOptions);
|
|
523
477
|
const productSku = {
|
|
524
|
-
...(0,
|
|
478
|
+
...(0, import_utils.ensureProductSku)(product),
|
|
525
479
|
option: normalizedOptions
|
|
526
480
|
};
|
|
527
|
-
|
|
528
|
-
// 1) 解析 source_product_price。
|
|
529
|
-
// 优先级:
|
|
530
|
-
// 1) metadata.source_product_price(v2 权威)
|
|
531
|
-
// 2) variantPrice(命中 variant_id,从 metadata.origin.variant[vid].price 读)
|
|
532
|
-
// 3) _origin.price / _origin.base_price(后端语义的基础价)
|
|
533
|
-
// 4) v1 兼容:无 v2 标记但存在 metadata.main_product_original_price(v1 main-only,即旧 source)
|
|
534
|
-
// 5) 入参 original_price(v1 addProduct 约定:original_price 为 pre-discount 基础价)
|
|
535
|
-
// 6) 入参 selling_price(最末兜底,新添加路径 caller 只给 selling_price)
|
|
536
|
-
const isV2 = metadata.price_schema_version === 2 || metadata.price_schema_version === '2';
|
|
481
|
+
const isV2 = metadata.price_schema_version === 2 || metadata.price_schema_version === "2";
|
|
537
482
|
const variantId = Number(product.product_variant_id || 0);
|
|
538
|
-
const variantList = variantId ? metadata
|
|
539
|
-
const variantPrice = Array.isArray(variantList) ? variantList.find(v => Number(v
|
|
483
|
+
const variantList = variantId ? (_f = metadata == null ? void 0 : metadata.origin) == null ? void 0 : _f.variant : null;
|
|
484
|
+
const variantPrice = Array.isArray(variantList) ? (_g = variantList.find((v) => Number(v == null ? void 0 : v.id) === variantId)) == null ? void 0 : _g.price : void 0;
|
|
540
485
|
const resolvedSource = (() => {
|
|
541
|
-
|
|
486
|
+
var _a2, _b2;
|
|
487
|
+
if (metadata.source_product_price !== void 0) {
|
|
542
488
|
return String(metadata.source_product_price);
|
|
543
489
|
}
|
|
544
|
-
if (variantPrice !==
|
|
490
|
+
if (variantPrice !== void 0 && variantPrice !== null) {
|
|
545
491
|
return String(variantPrice);
|
|
546
492
|
}
|
|
547
|
-
const originPrice = product._origin
|
|
548
|
-
if (originPrice !==
|
|
493
|
+
const originPrice = (_a2 = product._origin) == null ? void 0 : _a2.price;
|
|
494
|
+
if (originPrice !== void 0 && originPrice !== null) {
|
|
549
495
|
return String(originPrice);
|
|
550
496
|
}
|
|
551
|
-
const originBasePrice = product._origin
|
|
552
|
-
if (originBasePrice !==
|
|
497
|
+
const originBasePrice = (_b2 = product._origin) == null ? void 0 : _b2.base_price;
|
|
498
|
+
if (originBasePrice !== void 0 && originBasePrice !== null) {
|
|
553
499
|
return String(originBasePrice);
|
|
554
500
|
}
|
|
555
|
-
if (!isV2 && metadata.main_product_original_price !==
|
|
501
|
+
if (!isV2 && metadata.main_product_original_price !== void 0) {
|
|
556
502
|
return String(metadata.main_product_original_price);
|
|
557
503
|
}
|
|
558
|
-
return product.original_price ?? product.selling_price ??
|
|
504
|
+
return product.original_price ?? product.selling_price ?? "0.00";
|
|
559
505
|
})();
|
|
560
|
-
|
|
561
|
-
// 2) 派生 main_product_original_price(含 option、不含折扣)
|
|
562
|
-
const mainOriginalDec = new _decimal.default(Number(resolvedSource) || 0).plus(optionSum);
|
|
506
|
+
const mainOriginalDec = new import_decimal.default(Number(resolvedSource) || 0).plus(optionSum);
|
|
563
507
|
const mainOriginalStr = mainOriginalDec.toDecimalPlaces(2).toFixed(2);
|
|
564
|
-
|
|
565
|
-
// 3) 派生 main_product_selling_price(含 option、含主商品折扣)
|
|
566
|
-
// - v2 数据:直接沿用 metadata.main_product_selling_price(保留折扣)
|
|
567
|
-
// - v1 metadata:main_product_selling_price 旧语义是 main-only(≈ source-level 折后价),
|
|
568
|
-
// 反推 legacyDiscount = main_original(旧) - main_selling(旧),再用新 main_original - legacyDiscount
|
|
569
|
-
// - v1 addProduct 入参:top-level selling_price < original_price 表示主商品折扣;
|
|
570
|
-
// 用差额作为 legacyDiscount 映射到新 main_selling
|
|
571
|
-
// - 其它:视为无折扣,main_selling = main_original
|
|
572
508
|
let mainSellingDec;
|
|
573
509
|
if (isV2 && metadata.main_product_selling_price != null) {
|
|
574
|
-
mainSellingDec = new
|
|
510
|
+
mainSellingDec = new import_decimal.default(Number(metadata.main_product_selling_price) || 0);
|
|
575
511
|
} else if (metadata.main_product_selling_price != null && metadata.main_product_original_price != null) {
|
|
576
|
-
const legacyOriginal = new
|
|
577
|
-
const legacySelling = new
|
|
512
|
+
const legacyOriginal = new import_decimal.default(Number(metadata.main_product_original_price) || 0);
|
|
513
|
+
const legacySelling = new import_decimal.default(Number(metadata.main_product_selling_price) || 0);
|
|
578
514
|
const legacyDiscount = legacyOriginal.minus(legacySelling);
|
|
579
515
|
mainSellingDec = mainOriginalDec.minus(legacyDiscount);
|
|
580
|
-
} else if (product.original_price != null && product.selling_price != null && new
|
|
581
|
-
|
|
582
|
-
|
|
516
|
+
} else if (product.original_price != null && product.selling_price != null && new import_decimal.default(Number(product.original_price) || 0).greaterThan(
|
|
517
|
+
new import_decimal.default(Number(product.selling_price) || 0)
|
|
518
|
+
)) {
|
|
519
|
+
const topOriginal = new import_decimal.default(Number(product.original_price) || 0);
|
|
520
|
+
const topSelling = new import_decimal.default(Number(product.selling_price) || 0);
|
|
583
521
|
const legacyDiscount = topOriginal.minus(topSelling);
|
|
584
522
|
mainSellingDec = mainOriginalDec.minus(legacyDiscount);
|
|
585
523
|
} else {
|
|
586
524
|
mainSellingDec = mainOriginalDec;
|
|
587
525
|
}
|
|
588
526
|
const mainSellingStr = mainSellingDec.toDecimalPlaces(2).toFixed(2);
|
|
589
|
-
|
|
590
|
-
// 4) 落盘 metadata:三字段 + schema 版本 sentinel
|
|
591
527
|
metadata.source_product_price = resolvedSource;
|
|
592
528
|
metadata.main_product_original_price = mainOriginalStr;
|
|
593
529
|
metadata.main_product_selling_price = mainSellingStr;
|
|
594
530
|
metadata.price_schema_version = 2;
|
|
595
|
-
|
|
596
|
-
// 5) 合成行级 composite(main 已含 option,本步只叠 bundle)
|
|
597
|
-
const composedSellingPrice = (0, _utils.composeLinePrice)({
|
|
531
|
+
const composedSellingPrice = (0, import_utils.composeLinePrice)({
|
|
598
532
|
mainPrice: mainSellingStr,
|
|
599
533
|
bundle: normalizedBundle
|
|
600
534
|
});
|
|
601
|
-
const composedOriginalPrice = (0,
|
|
535
|
+
const composedOriginalPrice = (0, import_utils.composeLinePrice)({
|
|
602
536
|
mainPrice: mainOriginalStr,
|
|
603
537
|
bundle: normalizedBundle,
|
|
604
538
|
useOriginalBundle: true
|
|
605
539
|
});
|
|
606
|
-
const finalOriginalPrice = (0,
|
|
607
|
-
num: product.num,
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
540
|
+
const finalOriginalPrice = (0, import_utils.resolveManualOverrideLineOriginalPrice)(
|
|
541
|
+
{ num: product.num, metadata, lineOriginalPrice: product.original_price },
|
|
542
|
+
composedOriginalPrice
|
|
543
|
+
);
|
|
544
|
+
const hasManualProductDiscount = (product.discount_list || []).some(
|
|
545
|
+
(item) => (item == null ? void 0 : item.type) === "product"
|
|
546
|
+
);
|
|
612
547
|
const manualOriginalPrice = hasManualProductDiscount && product.original_price != null ? String(product.original_price) : finalOriginalPrice;
|
|
613
|
-
const discountList = (0,
|
|
548
|
+
const discountList = (0, import_manualProductDiscount.ensureManualProductDiscountList)({
|
|
614
549
|
discountList: product.discount_list,
|
|
615
550
|
metadata,
|
|
616
551
|
originalPrice: manualOriginalPrice,
|
|
@@ -625,147 +560,177 @@ function normalizeOrderProduct(product) {
|
|
|
625
560
|
product_sku: productSku,
|
|
626
561
|
selling_price: composedSellingPrice,
|
|
627
562
|
original_price: manualOriginalPrice,
|
|
628
|
-
tax_fee: product.tax_fee ||
|
|
563
|
+
tax_fee: product.tax_fee || "0.00",
|
|
629
564
|
is_charge_tax: product.is_charge_tax ?? 0,
|
|
630
565
|
discount_list: discountList,
|
|
631
566
|
product_bundle: normalizedBundle,
|
|
632
567
|
metadata,
|
|
633
|
-
note: product.note != null ? String(product.note) :
|
|
568
|
+
note: product.note != null ? String(product.note) : ""
|
|
634
569
|
};
|
|
635
570
|
}
|
|
636
|
-
|
|
637
|
-
/**
|
|
638
|
-
* 从 reservation.enabled_reservation_rules 中收集 type=link 的商品 id。
|
|
639
|
-
*/
|
|
640
571
|
function collectLinkProductIdsFromReservationRules(rules) {
|
|
641
|
-
if (!Array.isArray(rules))
|
|
572
|
+
if (!Array.isArray(rules))
|
|
573
|
+
return [];
|
|
642
574
|
const ids = [];
|
|
643
575
|
for (const entry of rules) {
|
|
644
|
-
if (!entry || typeof entry !==
|
|
576
|
+
if (!entry || typeof entry !== "object")
|
|
577
|
+
continue;
|
|
645
578
|
const rec = entry;
|
|
646
|
-
if (rec.type !==
|
|
647
|
-
|
|
579
|
+
if (rec.type !== "link")
|
|
580
|
+
continue;
|
|
581
|
+
if (!Array.isArray(rec.value))
|
|
582
|
+
continue;
|
|
648
583
|
for (const v of rec.value) {
|
|
649
584
|
const n = Number(v);
|
|
650
|
-
if (Number.isFinite(n) && n > 0)
|
|
585
|
+
if (Number.isFinite(n) && n > 0)
|
|
586
|
+
ids.push(Math.floor(n));
|
|
651
587
|
}
|
|
652
588
|
}
|
|
653
589
|
return [...new Set(ids)];
|
|
654
590
|
}
|
|
655
|
-
|
|
656
|
-
/**
|
|
657
|
-
* 找到第一个归属指定桌台的预约规则商品。
|
|
658
|
-
* 归属判断基于商品资源中的 default_resource / optional_resource。
|
|
659
|
-
*/
|
|
660
591
|
function findReservationRuleProductByResourceId(products, resourceId) {
|
|
592
|
+
var _a;
|
|
661
593
|
const numericResourceId = Number(resourceId);
|
|
662
|
-
if (!Number.isFinite(numericResourceId) || numericResourceId <= 0)
|
|
594
|
+
if (!Number.isFinite(numericResourceId) || numericResourceId <= 0)
|
|
595
|
+
return void 0;
|
|
663
596
|
for (const product of products) {
|
|
664
|
-
const resources = product
|
|
665
|
-
if (!Array.isArray(resources))
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
const
|
|
669
|
-
|
|
597
|
+
const resources = (_a = product == null ? void 0 : product.product_resource) == null ? void 0 : _a.resources;
|
|
598
|
+
if (!Array.isArray(resources))
|
|
599
|
+
continue;
|
|
600
|
+
const hasMatchedResource = resources.some((resource) => {
|
|
601
|
+
const defaultResources = Array.isArray(resource == null ? void 0 : resource.default_resource) ? resource.default_resource : [];
|
|
602
|
+
const optionalResources = Array.isArray(resource == null ? void 0 : resource.optional_resource) ? resource.optional_resource : [];
|
|
603
|
+
return [...defaultResources, ...optionalResources].some(
|
|
604
|
+
(id) => Number(id) === numericResourceId
|
|
605
|
+
);
|
|
670
606
|
});
|
|
671
|
-
if (hasMatchedResource)
|
|
607
|
+
if (hasMatchedResource)
|
|
608
|
+
return product;
|
|
672
609
|
}
|
|
673
|
-
return
|
|
610
|
+
return void 0;
|
|
674
611
|
}
|
|
675
|
-
|
|
676
|
-
/**
|
|
677
|
-
* 返回列表中第一个带有效 duration.value(分钟)的商品时长。
|
|
678
|
-
*/
|
|
679
612
|
function pickFirstDurationMinutesFromProducts(products) {
|
|
613
|
+
var _a;
|
|
680
614
|
for (const product of products) {
|
|
681
|
-
const value = product
|
|
615
|
+
const value = (_a = product == null ? void 0 : product.duration) == null ? void 0 : _a.value;
|
|
682
616
|
const n = Number(value);
|
|
683
|
-
if (Number.isFinite(n) && n > 0)
|
|
617
|
+
if (Number.isFinite(n) && n > 0)
|
|
618
|
+
return Math.floor(n);
|
|
684
619
|
}
|
|
685
|
-
return
|
|
620
|
+
return void 0;
|
|
686
621
|
}
|
|
687
|
-
|
|
688
|
-
/** 是否存在 capacity.type === 'custom' 的商品 */
|
|
689
622
|
function hasCustomCapacityProduct(products) {
|
|
690
|
-
return products.some(p =>
|
|
623
|
+
return products.some((p) => {
|
|
624
|
+
var _a;
|
|
625
|
+
return ((_a = p == null ? void 0 : p.capacity) == null ? void 0 : _a.type) === "custom";
|
|
626
|
+
});
|
|
691
627
|
}
|
|
692
|
-
|
|
693
|
-
/**
|
|
694
|
-
* 根据预约规则商品的 resource.type 计算桌台是否已被"占满"。
|
|
695
|
-
* - single:只要有 `lastOrderId` 即视为占用
|
|
696
|
-
* - multiple:当前时间落在 `capacity_list[i]` 的 `[start_at, end_at]`(inclusive)内的 pax 之和 >= 总容量
|
|
697
|
-
* - 其他('capacity' / undefined):返回 false,不施加限制
|
|
698
|
-
*/
|
|
699
628
|
function computeResourceIsFull(params) {
|
|
700
|
-
const {
|
|
701
|
-
|
|
702
|
-
lastOrderId
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
} = params;
|
|
706
|
-
if (resourceSelectType === 'single') return Boolean(lastOrderId);
|
|
707
|
-
if (resourceSelectType !== 'multiple') return false;
|
|
629
|
+
const { resourceSelectType, lastOrderId, capacityList, capacity } = params;
|
|
630
|
+
if (resourceSelectType === "single")
|
|
631
|
+
return Boolean(lastOrderId);
|
|
632
|
+
if (resourceSelectType !== "multiple")
|
|
633
|
+
return false;
|
|
708
634
|
const totalCapacity = Number(capacity);
|
|
709
|
-
if (!Number.isFinite(totalCapacity) || totalCapacity <= 0)
|
|
710
|
-
|
|
635
|
+
if (!Number.isFinite(totalCapacity) || totalCapacity <= 0)
|
|
636
|
+
return false;
|
|
637
|
+
const now = (0, import_dayjs.default)();
|
|
711
638
|
let occupied = 0;
|
|
712
639
|
for (const slot of capacityList || []) {
|
|
713
|
-
const start = (0,
|
|
714
|
-
const end = (0,
|
|
715
|
-
if (!start.isValid() || !end.isValid())
|
|
640
|
+
const start = (0, import_dayjs.default)(slot == null ? void 0 : slot.start_at);
|
|
641
|
+
const end = (0, import_dayjs.default)(slot == null ? void 0 : slot.end_at);
|
|
642
|
+
if (!start.isValid() || !end.isValid())
|
|
643
|
+
continue;
|
|
716
644
|
if ((now.isAfter(start) || now.isSame(start)) && (now.isBefore(end) || now.isSame(end))) {
|
|
717
|
-
const pax = Number(slot
|
|
718
|
-
if (Number.isFinite(pax) && pax > 0)
|
|
645
|
+
const pax = Number(slot == null ? void 0 : slot.pax);
|
|
646
|
+
if (Number.isFinite(pax) && pax > 0)
|
|
647
|
+
occupied += pax;
|
|
719
648
|
}
|
|
720
649
|
}
|
|
721
650
|
return occupied >= totalCapacity;
|
|
722
651
|
}
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* 在商品列表中找到第一个 `capacity.type === 'custom'` 的商品,取其 `custom` 数组第一项的 min/max。
|
|
726
|
-
* 仅返回有限数字字段;若均无法解析则返回 `undefined`。
|
|
727
|
-
*/
|
|
728
652
|
function pickFirstCustomCapacityPaxBounds(products) {
|
|
729
653
|
for (const p of products) {
|
|
730
|
-
const cap = p
|
|
731
|
-
if (!cap || cap.type !==
|
|
732
|
-
|
|
654
|
+
const cap = p == null ? void 0 : p.capacity;
|
|
655
|
+
if (!cap || cap.type !== "custom")
|
|
656
|
+
continue;
|
|
657
|
+
if (!Array.isArray(cap.custom) || cap.custom.length === 0)
|
|
658
|
+
continue;
|
|
733
659
|
const row = cap.custom[0];
|
|
734
|
-
if (!row || typeof row !==
|
|
660
|
+
if (!row || typeof row !== "object")
|
|
661
|
+
continue;
|
|
735
662
|
const raw = row;
|
|
736
663
|
const out = {};
|
|
737
|
-
if (raw.min !== null && raw.min !==
|
|
664
|
+
if (raw.min !== null && raw.min !== void 0 && raw.min !== "") {
|
|
738
665
|
const min = Number(raw.min);
|
|
739
|
-
if (Number.isFinite(min))
|
|
666
|
+
if (Number.isFinite(min))
|
|
667
|
+
out.min = min;
|
|
740
668
|
}
|
|
741
|
-
if (raw.max !== null && raw.max !==
|
|
669
|
+
if (raw.max !== null && raw.max !== void 0 && raw.max !== "") {
|
|
742
670
|
const max = Number(raw.max);
|
|
743
|
-
if (Number.isFinite(max))
|
|
671
|
+
if (Number.isFinite(max))
|
|
672
|
+
out.max = max;
|
|
744
673
|
}
|
|
745
|
-
if (out.min !==
|
|
674
|
+
if (out.min !== void 0 || out.max !== void 0)
|
|
675
|
+
return out;
|
|
746
676
|
}
|
|
747
|
-
return
|
|
677
|
+
return void 0;
|
|
748
678
|
}
|
|
749
|
-
|
|
750
|
-
/**
|
|
751
|
-
* 第一个 `capacity.type === 'custom'` 的商品,取其 `custom[0].id`(提交 booking metadata.capacity 维度 id)。
|
|
752
|
-
* 无匹配时返回 `undefined`,调用方应回退为 `0`。
|
|
753
|
-
*/
|
|
754
679
|
function pickFirstCustomCapacityDimensionId(products) {
|
|
755
680
|
for (const p of products) {
|
|
756
|
-
const cap = p
|
|
757
|
-
if (!cap || cap.type !==
|
|
758
|
-
|
|
681
|
+
const cap = p == null ? void 0 : p.capacity;
|
|
682
|
+
if (!cap || cap.type !== "custom")
|
|
683
|
+
continue;
|
|
684
|
+
if (!Array.isArray(cap.custom) || cap.custom.length === 0)
|
|
685
|
+
continue;
|
|
759
686
|
const row = cap.custom[0];
|
|
760
|
-
if (!row || typeof row !==
|
|
687
|
+
if (!row || typeof row !== "object")
|
|
688
|
+
continue;
|
|
761
689
|
const id = row.id;
|
|
762
|
-
if (id === null || id ===
|
|
763
|
-
|
|
764
|
-
if (typeof id ===
|
|
690
|
+
if (id === null || id === void 0 || id === "")
|
|
691
|
+
continue;
|
|
692
|
+
if (typeof id === "number" && Number.isFinite(id))
|
|
693
|
+
return id;
|
|
694
|
+
if (typeof id === "string") {
|
|
765
695
|
const trimmed = id.trim();
|
|
766
|
-
if (!trimmed)
|
|
696
|
+
if (!trimmed)
|
|
697
|
+
continue;
|
|
767
698
|
return trimmed;
|
|
768
699
|
}
|
|
769
700
|
}
|
|
770
|
-
return
|
|
771
|
-
}
|
|
701
|
+
return void 0;
|
|
702
|
+
}
|
|
703
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
704
|
+
0 && (module.exports = {
|
|
705
|
+
aggregateItemRuleLimit,
|
|
706
|
+
attachItemRuleLimitsToTopLevelProducts,
|
|
707
|
+
buildItemRuleBusinessData,
|
|
708
|
+
buildProductKey,
|
|
709
|
+
buildProductLineFingerprint,
|
|
710
|
+
buildQuantityLimitIndex,
|
|
711
|
+
collectLinkProductIdsFromReservationRules,
|
|
712
|
+
computeResourceIsFull,
|
|
713
|
+
createEmptySummary,
|
|
714
|
+
extractStrategyModelIdsFromTableConfig,
|
|
715
|
+
filterProductsForScanOrderMore,
|
|
716
|
+
findReservationRuleProductByResourceId,
|
|
717
|
+
getProductIdentityIndex,
|
|
718
|
+
getSafeProductNum,
|
|
719
|
+
getTopLevelProductId,
|
|
720
|
+
getTopLevelVariantId,
|
|
721
|
+
hasCustomCapacityProduct,
|
|
722
|
+
isIdentityMatch,
|
|
723
|
+
isSkuOnlyDeleteIdentity,
|
|
724
|
+
normalizeEnabledItemRuleIds,
|
|
725
|
+
normalizeItemRuleStrategies,
|
|
726
|
+
normalizeOrderProduct,
|
|
727
|
+
pickFirstCustomCapacityDimensionId,
|
|
728
|
+
pickFirstCustomCapacityPaxBounds,
|
|
729
|
+
pickFirstDurationMinutesFromProducts,
|
|
730
|
+
resolveSkuMatchedQuantityLimits,
|
|
731
|
+
toBoolean,
|
|
732
|
+
toNonNegativeInt,
|
|
733
|
+
toNonNegativeNumber,
|
|
734
|
+
toPositiveString,
|
|
735
|
+
toPriceString
|
|
736
|
+
});
|