@pisell/pisellos 0.0.567 → 0.0.568
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 +6 -9
- package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -2
- package/dist/model/strategy/adapter/walletPass/example.js +3 -26
- package/dist/model/strategy/adapter/walletPass/utils.js +0 -3
- package/dist/model/strategy/strategy-example.js +5 -19
- package/dist/modules/Cart/index.js +0 -3
- package/dist/modules/Cart/utils/cartProduct.js +0 -1
- package/dist/modules/Date/index.js +1 -5
- package/dist/modules/Discount/index.js +1 -4
- package/dist/modules/OpenData/index.js +0 -2
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +14 -41
- package/dist/modules/Payment/index.js +142 -270
- package/dist/modules/Payment/walletpass.js +4 -5
- package/dist/modules/Rules/index.js +0 -7
- package/dist/modules/Schedule/utils.js +0 -1
- package/dist/modules/Step/index.js +0 -1
- package/dist/plugins/request.js +1 -4
- package/dist/plugins/window.js +2 -6
- package/dist/server/index.js +88 -121
- package/dist/server/modules/menu/index.js +32 -41
- package/dist/server/modules/products/index.js +29 -49
- package/dist/server/modules/quotation/index.js +29 -38
- package/dist/server/modules/resource/index.js +3 -4
- package/dist/server/modules/schedule/index.js +32 -40
- package/dist/server/utils/product.js +0 -1
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingByStep/index.js +7 -59
- package/dist/solution/BookingByStep/utils/capacity.js +1 -11
- package/dist/solution/BookingByStep/utils/resources.js +1 -3
- package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +5 -7
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
- package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
- package/dist/solution/BuyTickets/index.js +9 -12
- package/dist/solution/Checkout/index.js +177 -246
- package/dist/solution/Checkout/utils/index.js +4 -16
- package/dist/solution/RegisterAndLogin/index.js +30 -76
- package/dist/solution/ScanOrder/index.js +50 -60
- package/dist/solution/ShopDiscount/index.js +2 -7
- package/dist/solution/VenueBooking/index.d.ts +5 -0
- package/dist/solution/VenueBooking/index.js +364 -327
- package/dist/utils/task.js +15 -18
- package/dist/utils/watch.js +0 -1
- package/lib/apis/picoding.js +2 -0
- package/lib/core/index.js +130 -131
- package/lib/effects/index.js +46 -57
- package/lib/index.js +92 -53
- package/lib/model/index.js +14 -21
- package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
- package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
- package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
- package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
- package/lib/model/strategy/adapter/index.js +100 -64
- package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
- package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
- package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
- package/lib/model/strategy/adapter/itemRule/index.js +83 -57
- package/lib/model/strategy/adapter/itemRule/type.js +97 -36
- package/lib/model/strategy/adapter/promotion/adapter.js +84 -63
- package/lib/model/strategy/adapter/promotion/evaluator.js +381 -231
- package/lib/model/strategy/adapter/promotion/examples.js +139 -159
- package/lib/model/strategy/adapter/promotion/index.js +1 -49
- package/lib/model/strategy/adapter/promotion/type.js +199 -35
- package/lib/model/strategy/adapter/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -152
- package/lib/model/strategy/adapter/walletPass/example.js +217 -190
- package/lib/model/strategy/adapter/walletPass/index.js +75 -51
- package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
- package/lib/model/strategy/adapter/walletPass/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/utils.js +652 -402
- package/lib/model/strategy/engine.js +270 -168
- package/lib/model/strategy/index.js +49 -34
- package/lib/model/strategy/strategy-example.js +243 -239
- package/lib/model/strategy/type.js +100 -40
- package/lib/modules/Account/index.js +39 -53
- package/lib/modules/Account/types.js +20 -33
- package/lib/modules/AccountList/index.js +116 -154
- package/lib/modules/AccountList/types.js +30 -31
- package/lib/modules/AccountList/utils.js +18 -30
- package/lib/modules/BaseModule.js +22 -45
- package/lib/modules/Cart/index.js +170 -124
- package/lib/modules/Cart/types.js +46 -51
- package/lib/modules/Cart/utils/cartAccount.js +40 -39
- package/lib/modules/Cart/utils/cartDate.js +56 -61
- package/lib/modules/Cart/utils/cartDiscount.js +28 -33
- package/lib/modules/Cart/utils/cartNote.js +27 -32
- package/lib/modules/Cart/utils/cartProduct.js +306 -241
- package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
- package/lib/modules/Cart/utils/cartResource.js +72 -78
- package/lib/modules/Cart/utils/changePrice.js +26 -62
- package/lib/modules/Cart/utils/index.js +106 -48
- package/lib/modules/Customer/constants.js +13 -34
- package/lib/modules/Customer/index.js +216 -153
- package/lib/modules/Customer/types.js +38 -35
- package/lib/modules/Date/index.js +116 -115
- package/lib/modules/Date/types.js +16 -28
- package/lib/modules/Date/utils.js +174 -123
- package/lib/modules/Discount/index.js +117 -113
- package/lib/modules/Discount/types.js +9 -31
- package/lib/modules/Guests/index.js +30 -56
- package/lib/modules/Guests/types.js +23 -33
- package/lib/modules/Holder/index.js +209 -189
- package/lib/modules/Holder/types.js +4 -16
- package/lib/modules/Holder/utils.js +20 -49
- package/lib/modules/OpenData/index.js +63 -74
- package/lib/modules/OpenData/types.js +4 -16
- package/lib/modules/OpenData/utils.js +44 -78
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +332 -320
- package/lib/modules/Order/types.js +24 -33
- package/lib/modules/Order/utils.js +350 -284
- package/lib/modules/Payment/cash.js +20 -33
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
- package/lib/modules/Payment/eftpos.js +16 -30
- package/lib/modules/Payment/index.js +566 -432
- package/lib/modules/Payment/mx51.js +1 -0
- package/lib/modules/Payment/types.js +216 -107
- package/lib/modules/Payment/utils.js +50 -47
- package/lib/modules/Payment/walletpass.js +221 -203
- package/lib/modules/Product/index.js +51 -46
- package/lib/modules/Product/types.js +4 -16
- package/lib/modules/Product/utils.js +32 -33
- package/lib/modules/ProductList/index.js +111 -110
- package/lib/modules/ProductList/types.js +9 -31
- package/lib/modules/Quotation/index.js +60 -82
- package/lib/modules/Quotation/types.js +4 -16
- package/lib/modules/Resource/index.js +27 -59
- package/lib/modules/Resource/types.js +22 -32
- package/lib/modules/Resource/utils.js +30 -38
- package/lib/modules/Rules/index.js +1172 -872
- package/lib/modules/Rules/types.js +17 -40
- package/lib/modules/SalesSummary/index.js +59 -68
- package/lib/modules/SalesSummary/types.js +4 -16
- package/lib/modules/SalesSummary/utils.js +176 -193
- package/lib/modules/ScanOrderLogger/index.js +59 -79
- package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
- package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
- package/lib/modules/ScanOrderLogger/types.js +4 -16
- package/lib/modules/Schedule/getDateIsInSchedule.js +334 -167
- package/lib/modules/Schedule/index.js +97 -107
- package/lib/modules/Schedule/type.js +4 -16
- package/lib/modules/Schedule/types.js +4 -16
- package/lib/modules/Schedule/utils.js +433 -291
- package/lib/modules/Step/index.js +40 -52
- package/lib/modules/Step/tyeps.js +4 -16
- package/lib/modules/Summary/index.js +66 -70
- package/lib/modules/Summary/types.js +4 -16
- package/lib/modules/Summary/utils.js +782 -429
- package/lib/modules/index.js +212 -57
- package/lib/plugins/app.js +4 -16
- package/lib/plugins/index.js +36 -25
- package/lib/plugins/request.js +137 -126
- package/lib/plugins/shopStore.js +4 -16
- package/lib/plugins/user.js +4 -16
- package/lib/plugins/window.js +171 -179
- package/lib/server/index.js +882 -623
- package/lib/server/modules/index.js +85 -59
- package/lib/server/modules/menu/index.js +146 -122
- package/lib/server/modules/menu/types.js +18 -31
- package/lib/server/modules/order/index.js +195 -231
- package/lib/server/modules/order/types.js +107 -32
- package/lib/server/modules/order/utils/filterBookings.js +174 -140
- package/lib/server/modules/order/utils/filterOrders.js +89 -60
- package/lib/server/modules/products/index.js +430 -335
- package/lib/server/modules/products/types.js +41 -34
- package/lib/server/modules/quotation/index.js +76 -77
- package/lib/server/modules/quotation/types.js +21 -31
- package/lib/server/modules/resource/index.js +216 -187
- package/lib/server/modules/resource/types.js +42 -33
- package/lib/server/modules/schedule/index.js +134 -119
- package/lib/server/modules/schedule/types.js +14 -21
- package/lib/server/modules/schedule/utils.js +334 -163
- package/lib/server/types.js +4 -16
- package/lib/server/utils/index.js +25 -23
- package/lib/server/utils/product.js +196 -139
- package/lib/server/utils/schedule.js +34 -41
- package/lib/server/utils/time.js +40 -49
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1530 -1343
- package/lib/solution/BookingByStep/types.js +40 -99
- package/lib/solution/BookingByStep/utils/capacity.js +192 -160
- package/lib/solution/BookingByStep/utils/products.js +42 -52
- package/lib/solution/BookingByStep/utils/resources.js +527 -330
- package/lib/solution/BookingByStep/utils/stock.js +65 -44
- package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +147 -122
- package/lib/solution/BookingTicket/types.js +38 -64
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +64 -80
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +82 -80
- package/lib/solution/BookingTicket/utils/scan/index.js +90 -94
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
- package/lib/solution/BuyTickets/index.js +67 -70
- package/lib/solution/BuyTickets/types.js +22 -38
- package/lib/solution/Checkout/index.js +1451 -1158
- package/lib/solution/Checkout/types.js +91 -61
- package/lib/solution/Checkout/utils/index.js +227 -158
- package/lib/solution/PlaceOrder/index.js +55 -0
- package/lib/solution/RegisterAndLogin/config.js +493 -460
- package/lib/solution/RegisterAndLogin/index.js +633 -630
- package/lib/solution/RegisterAndLogin/types.js +189 -76
- package/lib/solution/RegisterAndLogin/utils.js +183 -125
- package/lib/solution/Sales/index.js +218 -200
- package/lib/solution/Sales/types.js +27 -33
- package/lib/solution/ScanOrder/index.js +803 -840
- package/lib/solution/ScanOrder/types.js +34 -34
- package/lib/solution/ScanOrder/utils.js +372 -331
- package/lib/solution/ShopDiscount/index.js +230 -236
- package/lib/solution/ShopDiscount/types.js +15 -37
- package/lib/solution/ShopDiscount/utils.js +309 -172
- package/lib/solution/VenueBooking/index.d.ts +5 -0
- package/lib/solution/VenueBooking/index.js +886 -929
- package/lib/solution/VenueBooking/types.js +20 -40
- package/lib/solution/VenueBooking/utils/dateSummary.js +22 -54
- package/lib/solution/VenueBooking/utils/resource.js +31 -54
- package/lib/solution/VenueBooking/utils/slotMerge.js +88 -106
- package/lib/solution/VenueBooking/utils/smartPricing.js +112 -100
- package/lib/solution/VenueBooking/utils/timeSlot.js +133 -132
- package/lib/solution/VenueBooking/utils.js +130 -67
- package/lib/solution/index.js +102 -37
- package/lib/store/createStore.js +32 -29
- package/lib/types/index.js +4 -16
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +81 -47
- package/package.json +2 -1
|
@@ -1,111 +1,134 @@
|
|
|
1
|
-
|
|
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);
|
|
1
|
+
"use strict";
|
|
28
2
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
__export(utils_exports, {
|
|
32
|
-
buildSubmitPayload: () => buildSubmitPayload,
|
|
33
|
-
composeLinePrice: () => composeLinePrice,
|
|
34
|
-
createDefaultOrderRulesHooks: () => createDefaultOrderRulesHooks,
|
|
35
|
-
createDefaultTempOrder: () => createDefaultTempOrder,
|
|
36
|
-
createEmptySummary: () => import_utils3.createEmptySummary,
|
|
37
|
-
createUuidV4: () => createUuidV4,
|
|
38
|
-
ensureCartItemOriginHolder: () => ensureCartItemOriginHolder,
|
|
39
|
-
filterProductsForScanOrderMore: () => filterProductsForScanOrderMore,
|
|
40
|
-
formatDateTime: () => formatDateTime,
|
|
41
|
-
formatV1Product: () => formatV1Product,
|
|
42
|
-
generateDuration: () => generateDuration,
|
|
43
|
-
getAllDiscountList: () => getAllDiscountList,
|
|
44
|
-
isTempOrder: () => isTempOrder,
|
|
45
|
-
mergeRelationForms: () => mergeRelationForms,
|
|
46
|
-
normalizeSubmitBooking: () => normalizeSubmitBooking,
|
|
47
|
-
normalizeSubmitCollectPaxValue: () => normalizeSubmitCollectPaxValue,
|
|
48
|
-
resolveSubmitCollectPax: () => resolveSubmitCollectPax,
|
|
49
|
-
sumOptionUnitPrice: () => sumOptionUnitPrice
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
50
5
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
6
|
+
exports.buildSubmitPayload = buildSubmitPayload;
|
|
7
|
+
exports.composeLinePrice = composeLinePrice;
|
|
8
|
+
exports.createDefaultOrderRulesHooks = createDefaultOrderRulesHooks;
|
|
9
|
+
exports.createDefaultTempOrder = createDefaultTempOrder;
|
|
10
|
+
Object.defineProperty(exports, "createEmptySummary", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _utils2.createEmptySummary;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
exports.createUuidV4 = createUuidV4;
|
|
17
|
+
exports.ensureCartItemOriginHolder = ensureCartItemOriginHolder;
|
|
18
|
+
exports.filterProductsForScanOrderMore = filterProductsForScanOrderMore;
|
|
19
|
+
exports.formatDateTime = formatDateTime;
|
|
20
|
+
exports.formatV1Product = formatV1Product;
|
|
21
|
+
exports.getAllDiscountList = exports.generateDuration = void 0;
|
|
22
|
+
exports.isTempOrder = isTempOrder;
|
|
23
|
+
exports.mergeRelationForms = void 0;
|
|
24
|
+
exports.normalizeSubmitBooking = normalizeSubmitBooking;
|
|
25
|
+
exports.normalizeSubmitCollectPaxValue = normalizeSubmitCollectPaxValue;
|
|
26
|
+
exports.resolveSubmitCollectPax = resolveSubmitCollectPax;
|
|
27
|
+
exports.sumOptionUnitPrice = sumOptionUnitPrice;
|
|
28
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
29
|
+
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
30
|
+
var _utils = require("../Holder/utils");
|
|
31
|
+
var _utils2 = require("../../solution/ScanOrder/utils");
|
|
32
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
33
|
+
/**
|
|
34
|
+
* 把"含 option 的主商品单价"与 bundle 合成"单行 composite 单价"。
|
|
35
|
+
*
|
|
36
|
+
* 新语义 v2 约定:
|
|
37
|
+
* - `mainPrice` 必须是**已经包含 option 的主商品单价**(即 `metadata.main_product_selling_price`
|
|
38
|
+
* 或 `metadata.main_product_original_price`),option 价格不由本函数叠加。
|
|
39
|
+
* - 套餐价:Σ((bundle.bundle_selling_price ?? bundle.price) × (bundle.num ?? bundle.quantity ?? 1))
|
|
40
|
+
* 当 `useOriginalBundle=true` 时,改用 `bundle.original_price ?? bundle.product_price ?? bundle.price`。
|
|
41
|
+
* - 返回值:保留 2 位小数的字符串,方便直接写回 `selling_price` / `original_price` 字段。
|
|
42
|
+
*
|
|
43
|
+
* 被 `normalizeOrderProduct`、Rules setProduct 钩子、各 Solution 的 setDiscountSelected 共用,
|
|
44
|
+
* 保证合成逻辑单点来源。
|
|
45
|
+
*/
|
|
57
46
|
function composeLinePrice(params) {
|
|
58
|
-
const {
|
|
59
|
-
|
|
47
|
+
const {
|
|
48
|
+
mainPrice,
|
|
49
|
+
bundle,
|
|
50
|
+
useOriginalBundle
|
|
51
|
+
} = params;
|
|
52
|
+
let total = new _decimal.default(Number(mainPrice) || 0);
|
|
60
53
|
if (Array.isArray(bundle)) {
|
|
61
54
|
for (const item of bundle) {
|
|
62
|
-
const rawPrice = useOriginalBundle ?
|
|
63
|
-
const price = new
|
|
64
|
-
const rawNum =
|
|
65
|
-
const num = new
|
|
55
|
+
const rawPrice = useOriginalBundle ? item?.original_price ?? item?.product_price ?? item?.price : item?.bundle_selling_price ?? item?.price;
|
|
56
|
+
const price = new _decimal.default(Number(rawPrice) || 0);
|
|
57
|
+
const rawNum = item?.num ?? item?.quantity ?? 1;
|
|
58
|
+
const num = new _decimal.default(Number(rawNum) || 0);
|
|
66
59
|
total = total.plus(price.times(num));
|
|
67
60
|
}
|
|
68
61
|
}
|
|
69
62
|
return total.toDecimalPlaces(2).toFixed(2);
|
|
70
63
|
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 计算 option 单价合计:Σ(option.price × option.num)。
|
|
67
|
+
* 在新语义 v2 下,main_product_original_price = source_product_price + 本函数结果。
|
|
68
|
+
*/
|
|
71
69
|
function sumOptionUnitPrice(options) {
|
|
72
|
-
let total = new
|
|
73
|
-
if (!Array.isArray(options))
|
|
74
|
-
return total;
|
|
70
|
+
let total = new _decimal.default(0);
|
|
71
|
+
if (!Array.isArray(options)) return total;
|
|
75
72
|
for (const opt of options) {
|
|
76
|
-
const price = new
|
|
77
|
-
const num = new
|
|
73
|
+
const price = new _decimal.default(Number(opt?.price) || 0);
|
|
74
|
+
const num = new _decimal.default(Number(opt?.num) || 0);
|
|
78
75
|
total = total.plus(price.times(num));
|
|
79
76
|
}
|
|
80
77
|
return total;
|
|
81
78
|
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* OrderModule 默认 Rules 钩子工厂。
|
|
82
|
+
*
|
|
83
|
+
* 价格语义约定(订单域,v2 composite 口径):
|
|
84
|
+
* - `selling_price`:券后 **行 composite 单价**
|
|
85
|
+
* = `metadata.main_product_selling_price` + Σ(bundle_selling_price × num)。
|
|
86
|
+
* - `original_price`:券前 **行 composite 单价**
|
|
87
|
+
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
88
|
+
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
|
|
89
|
+
* 不含折扣。**权威源**。
|
|
90
|
+
* - `metadata.main_product_original_price` = source + Σ(option.price × option.num)(含 option、不含折扣)。
|
|
91
|
+
* - `metadata.main_product_selling_price` = main_original − 主商品券 per-unit amount(含 option、含折扣)。
|
|
92
|
+
* - `payment_price`:出站 payload 中由 `selling_price` 派生以兼容后端(composite)。
|
|
93
|
+
*
|
|
94
|
+
* Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
|
|
95
|
+
* - `getProduct.price` / `getProduct.original_price` 回传 **source-level 主价**
|
|
96
|
+
* (`metadata.source_product_price`)。Rules 内部 `getProductTotalPrice` /
|
|
97
|
+
* `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
|
|
98
|
+
* - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
|
|
99
|
+
* total(source + option + bundle)对齐。
|
|
100
|
+
* - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
|
|
101
|
+
* 加回 Σoptions,重新合成含 option 的 main_product_* 并派生 composite。
|
|
102
|
+
* 优先级:
|
|
103
|
+
* 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
|
|
104
|
+
* 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
|
|
105
|
+
* 3. `values.total / num`(仅当 Rules 只给出总价时的兜底)
|
|
106
|
+
*
|
|
107
|
+
* 导出为纯函数方便单测直接驱动钩子,不依赖 OrderModule 实例。
|
|
108
|
+
*/
|
|
82
109
|
function createDefaultOrderRulesHooks() {
|
|
83
110
|
const toUnitPriceString = (totalLike, num) => {
|
|
84
111
|
const effectiveNum = Number(num) > 0 ? Number(num) : 1;
|
|
85
|
-
return new
|
|
112
|
+
return new _decimal.default(Number(totalLike) || 0).dividedBy(effectiveNum).toDecimalPlaces(2).toString();
|
|
86
113
|
};
|
|
87
114
|
return {
|
|
88
|
-
getProduct:
|
|
89
|
-
|
|
115
|
+
getProduct: product => {
|
|
116
|
+
// source_product_price 是权威源;兜底链:source → mainSelling − options(反推)→ 行 selling_price
|
|
90
117
|
const metadataAny = product.metadata || {};
|
|
91
118
|
const optionSum = sumOptionUnitPrice(product.product_option_item);
|
|
92
119
|
let sourcePrice;
|
|
93
|
-
if (metadataAny.source_product_price !==
|
|
120
|
+
if (metadataAny.source_product_price !== undefined) {
|
|
94
121
|
sourcePrice = String(metadataAny.source_product_price);
|
|
95
|
-
} else if (metadataAny.main_product_selling_price !==
|
|
96
|
-
sourcePrice = new
|
|
97
|
-
Number(metadataAny.main_product_selling_price) || 0
|
|
98
|
-
).minus(optionSum).toDecimalPlaces(2).toString();
|
|
122
|
+
} else if (metadataAny.main_product_selling_price !== undefined) {
|
|
123
|
+
sourcePrice = new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSum).toDecimalPlaces(2).toString();
|
|
99
124
|
} else {
|
|
100
125
|
sourcePrice = String(product.selling_price ?? 0);
|
|
101
126
|
}
|
|
102
127
|
let sourceOriginalPrice;
|
|
103
|
-
if (metadataAny.source_product_price !==
|
|
128
|
+
if (metadataAny.source_product_price !== undefined) {
|
|
104
129
|
sourceOriginalPrice = String(metadataAny.source_product_price);
|
|
105
|
-
} else if (metadataAny.main_product_original_price !==
|
|
106
|
-
sourceOriginalPrice = new
|
|
107
|
-
Number(metadataAny.main_product_original_price) || 0
|
|
108
|
-
).minus(optionSum).toDecimalPlaces(2).toString();
|
|
130
|
+
} else if (metadataAny.main_product_original_price !== undefined) {
|
|
131
|
+
sourceOriginalPrice = new _decimal.default(Number(metadataAny.main_product_original_price) || 0).minus(optionSum).toDecimalPlaces(2).toString();
|
|
109
132
|
} else {
|
|
110
133
|
sourceOriginalPrice = sourcePrice;
|
|
111
134
|
}
|
|
@@ -115,40 +138,44 @@ function createDefaultOrderRulesHooks() {
|
|
|
115
138
|
// 否则同 SKU 不同小料会在 calcDiscount 重组时互相覆盖。
|
|
116
139
|
// 不透明 identity 契约下,normalizeOrderProduct / restoreTempOrderFromStorage 已保证 identity_key 必存在;
|
|
117
140
|
// 留 fingerprint 分支仅作 Rules 单测里直接传裸 product 时的兜底。
|
|
118
|
-
_id: product.identity_key ? `${product.product_id}_${product.product_variant_id}_${product.identity_key}` : `${product.product_id}_${product.product_variant_id}_${(0,
|
|
119
|
-
product.product_option_item,
|
|
120
|
-
product.product_bundle
|
|
121
|
-
)}`,
|
|
141
|
+
_id: product.identity_key ? `${product.product_id}_${product.product_variant_id}_${product.identity_key}` : `${product.product_id}_${product.product_variant_id}_${(0, _utils2.buildProductLineFingerprint)(product.product_option_item, product.product_bundle)}`,
|
|
122
142
|
// Rules 内部 getProductTotalPrice / getProductOriginTotalPrice 会各自再叠加 bundle + option,
|
|
123
143
|
// 所以这里必须喂 source-level(不含 option、不含 bundle、不含折扣)单价,避免双加 option。
|
|
124
144
|
price: sourcePrice,
|
|
125
145
|
// total / origin_total 使用 composite × num,跟 Rules 内部产出的 total 对齐(含 option + bundle)。
|
|
126
|
-
total: new
|
|
127
|
-
origin_total: new
|
|
128
|
-
product.original_price || product.selling_price || 0
|
|
129
|
-
).times(product.num || 1).toNumber(),
|
|
146
|
+
total: new _decimal.default(product.selling_price || 0).times(product.num || 1).toNumber(),
|
|
147
|
+
origin_total: new _decimal.default(product.original_price || product.selling_price || 0).times(product.num || 1).toNumber(),
|
|
130
148
|
original_price: sourceOriginalPrice,
|
|
131
149
|
quantity: product.num || 1,
|
|
132
150
|
num: product.num || 1,
|
|
133
151
|
discount_list: product.discount_list || [],
|
|
134
152
|
bundle: product.product_bundle || [],
|
|
135
|
-
booking_id:
|
|
153
|
+
booking_id: product._origin?.booking_id || null,
|
|
136
154
|
isClient: false,
|
|
137
|
-
isManualDiscount:
|
|
138
|
-
holder_id:
|
|
139
|
-
startDate:
|
|
155
|
+
isManualDiscount: product._origin?.isManualDiscount || false,
|
|
156
|
+
holder_id: product._origin?.holder_id,
|
|
157
|
+
startDate: product._origin?.startDate
|
|
140
158
|
};
|
|
141
159
|
},
|
|
142
160
|
setProduct: (product, values) => {
|
|
143
161
|
const nextNum = Number(values.quantity ?? product.num ?? 1) || 1;
|
|
144
162
|
const metadataAny = product.metadata || {};
|
|
145
|
-
const existedSource = metadataAny.source_product_price ?? product.selling_price ??
|
|
163
|
+
const existedSource = metadataAny.source_product_price ?? product.selling_price ?? '0';
|
|
146
164
|
const nextOptions = product.product_option_item;
|
|
147
165
|
const optionSum = sumOptionUnitPrice(nextOptions);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
166
|
+
|
|
167
|
+
// Rules 返回的 main_product_selling_price / price / total 均为 source-level。
|
|
168
|
+
// 优先级:main_product_selling_price(per-unit 券后 source)> price(还原/good_pass 分支)>
|
|
169
|
+
// total/num(仅当 Rules 只给 total 时的兜底)> 保留当前 source。
|
|
170
|
+
const nextSourceSellingPrice = values.main_product_selling_price !== undefined ? String(values.main_product_selling_price) : values.price !== undefined ? String(values.price) : values.total !== undefined ? toUnitPriceString(values.total, nextNum) : String(existedSource);
|
|
171
|
+
|
|
172
|
+
// 券前 source:values.original_price 是 source-level(Rules 层本就不含 option),
|
|
173
|
+
// 缺省时保留现有 source(券前 = 当前 source)。
|
|
174
|
+
const nextSourceOriginalPrice = values.original_price !== undefined ? String(values.original_price) : String(existedSource);
|
|
175
|
+
|
|
176
|
+
// 含 option 的 main_product_*
|
|
177
|
+
const nextMainSellingPrice = new _decimal.default(Number(nextSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
178
|
+
const nextMainOriginalPrice = new _decimal.default(Number(nextSourceOriginalPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
152
179
|
const nextBundle = values.bundle ?? product.product_bundle;
|
|
153
180
|
const composedSellingPrice = composeLinePrice({
|
|
154
181
|
mainPrice: nextMainSellingPrice,
|
|
@@ -177,47 +204,73 @@ function createDefaultOrderRulesHooks() {
|
|
|
177
204
|
}
|
|
178
205
|
};
|
|
179
206
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* 通过 session 类商品的开始时间结束时间生成商品的时长
|
|
210
|
+
* @param {CartItem} cartItem
|
|
211
|
+
* @return {*}
|
|
212
|
+
*/
|
|
213
|
+
const generateDuration = cartItem => {
|
|
214
|
+
const startDate = (0, _dayjs.default)(`${cartItem.start_date} ${cartItem.start_time}`);
|
|
215
|
+
const endDate = (0, _dayjs.default)(`${cartItem.end_date} ${cartItem.end_time}`);
|
|
216
|
+
const duration = endDate.diff(startDate, 'minutes');
|
|
217
|
+
return {
|
|
218
|
+
duration,
|
|
219
|
+
durationType: 'minutes'
|
|
220
|
+
};
|
|
185
221
|
};
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* 合并关联表单
|
|
225
|
+
* @param relationForms 关联表单
|
|
226
|
+
* @returns 合并后的关联表单
|
|
227
|
+
*/
|
|
228
|
+
exports.generateDuration = generateDuration;
|
|
229
|
+
const mergeRelationForms = relationForms => {
|
|
230
|
+
return Object.values(relationForms.reduce((acc, cur) => {
|
|
231
|
+
const {
|
|
232
|
+
form_id,
|
|
233
|
+
form_record_ids
|
|
234
|
+
} = cur;
|
|
235
|
+
// 如果 acc 中没有 form_id,则初始化一个空数组
|
|
236
|
+
if (!acc[form_id]) {
|
|
237
|
+
acc[form_id] = {
|
|
238
|
+
form_id,
|
|
239
|
+
form_record_ids: []
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 兼容 form_record_id 可能是数组或单个数字
|
|
244
|
+
const ids = Array.isArray(form_record_ids) ? form_record_ids : [form_record_ids];
|
|
245
|
+
// 过滤掉空值(null、undefined等)
|
|
246
|
+
const validIds = ids.filter(id => id != null);
|
|
247
|
+
acc[form_id].form_record_ids.push(...validIds);
|
|
248
|
+
// 去重
|
|
249
|
+
acc[form_id].form_record_ids = [...new Set(acc[form_id].form_record_ids)];
|
|
250
|
+
return acc;
|
|
251
|
+
}, {})).filter(item => item.form_record_ids.length > 0); // 过滤掉没有有效记录的表单
|
|
200
252
|
};
|
|
253
|
+
exports.mergeRelationForms = mergeRelationForms;
|
|
201
254
|
function getCustomerIdFromStorage(window) {
|
|
202
|
-
var _a;
|
|
203
255
|
try {
|
|
204
|
-
const customer = JSON.parse(
|
|
205
|
-
const customerId = Number(customer
|
|
206
|
-
return Number.isFinite(customerId) && customerId > 0 ? customerId :
|
|
256
|
+
const customer = JSON.parse(window?.getLocalStorage?.('customer') || '{}');
|
|
257
|
+
const customerId = Number(customer?.id);
|
|
258
|
+
return Number.isFinite(customerId) && customerId > 0 ? customerId : undefined;
|
|
207
259
|
} catch {
|
|
208
|
-
return
|
|
260
|
+
return undefined;
|
|
209
261
|
}
|
|
210
262
|
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* 为购物车行补齐订单所需的 holder 信息(与 cartAccount 结构保持一致)
|
|
266
|
+
*/
|
|
211
267
|
function ensureCartItemOriginHolder(cartItem, window) {
|
|
212
|
-
|
|
213
|
-
if ((_a = cartItem == null ? void 0 : cartItem._origin) == null ? void 0 : _a.holder) {
|
|
268
|
+
if (cartItem?._origin?.holder) {
|
|
214
269
|
return;
|
|
215
270
|
}
|
|
216
|
-
const holderConfig = (0,
|
|
217
|
-
|
|
218
|
-
)
|
|
219
|
-
const formRecordId = cartItem == null ? void 0 : cartItem.holder_id;
|
|
220
|
-
if (!(holderConfig == null ? void 0 : holderConfig.resource_id) || formRecordId == null) {
|
|
271
|
+
const holderConfig = (0, _utils.getProductHolderConfig)(cartItem?._productInit ?? cartItem?._productOrigin);
|
|
272
|
+
const formRecordId = cartItem?.holder_id;
|
|
273
|
+
if (!holderConfig?.resource_id || formRecordId == null) {
|
|
221
274
|
return;
|
|
222
275
|
}
|
|
223
276
|
cartItem._origin.holder = {
|
|
@@ -226,32 +279,33 @@ function ensureCartItemOriginHolder(cartItem, window) {
|
|
|
226
279
|
form_record: [formRecordId]
|
|
227
280
|
};
|
|
228
281
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
let discountList =
|
|
232
|
-
(
|
|
233
|
-
discountList = [...discountList, ...(item
|
|
234
|
-
item.discount_list =
|
|
282
|
+
;
|
|
283
|
+
const getAllDiscountList = cartItem => {
|
|
284
|
+
let discountList = cartItem?._origin?.product?.discount_list || [];
|
|
285
|
+
(cartItem?._origin?.product?.product_bundle || []).forEach(item => {
|
|
286
|
+
discountList = [...discountList, ...(item?.discount_list || [])];
|
|
287
|
+
item.discount_list = undefined;
|
|
235
288
|
});
|
|
236
289
|
return discountList;
|
|
237
290
|
};
|
|
291
|
+
|
|
292
|
+
// ─── 以下为从 ScanOrder/utils.ts 迁入的 Order 专属工具函数 ───
|
|
293
|
+
exports.getAllDiscountList = getAllDiscountList;
|
|
238
294
|
function createUuidV4() {
|
|
239
|
-
const template =
|
|
240
|
-
return template.replace(/[xy]/g,
|
|
295
|
+
const template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
|
|
296
|
+
return template.replace(/[xy]/g, char => {
|
|
241
297
|
const randomValue = Math.floor(Math.random() * 16);
|
|
242
|
-
const value = char ===
|
|
298
|
+
const value = char === 'x' ? randomValue : randomValue & 0x3 | 0x8;
|
|
243
299
|
return value.toString(16);
|
|
244
300
|
});
|
|
245
301
|
}
|
|
246
302
|
function isTempOrder(data) {
|
|
247
|
-
if (!data || typeof data !==
|
|
248
|
-
|
|
249
|
-
if (!Array.isArray(data.products))
|
|
250
|
-
return false;
|
|
303
|
+
if (!data || typeof data !== 'object') return false;
|
|
304
|
+
if (!Array.isArray(data.products)) return false;
|
|
251
305
|
return true;
|
|
252
306
|
}
|
|
253
307
|
function formatDateTime(date) {
|
|
254
|
-
const pad =
|
|
308
|
+
const pad = value => value.toString().padStart(2, '0');
|
|
255
309
|
const year = date.getFullYear();
|
|
256
310
|
const month = pad(date.getMonth() + 1);
|
|
257
311
|
const day = pad(date.getDate());
|
|
@@ -261,42 +315,51 @@ function formatDateTime(date) {
|
|
|
261
315
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
262
316
|
}
|
|
263
317
|
function normalizeSubmitPlatform(platform) {
|
|
264
|
-
return
|
|
318
|
+
return platform?.toLowerCase() === 'pc' ? 'PC' : 'H5';
|
|
265
319
|
}
|
|
320
|
+
|
|
321
|
+
// 出站重命名:后端 checkout 协议字段 option_group_item_id;
|
|
322
|
+
// tempOrder / UI 运行时一律使用 product_option_item_id。仅保留后端契约字段,
|
|
323
|
+
// 与 src/modules/Cart/utils/cartProduct.ts#formatOptionsToOrigin 形状一致。
|
|
266
324
|
function formatSubmitOptionItems(options) {
|
|
267
|
-
if (!Array.isArray(options))
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
option_group_id: d == null ? void 0 : d.option_group_id
|
|
325
|
+
if (!Array.isArray(options)) return [];
|
|
326
|
+
return options.map(d => ({
|
|
327
|
+
num: d?.num,
|
|
328
|
+
option_group_item_id: d?.option_group_item_id ?? d?.product_option_item_id,
|
|
329
|
+
option_group_id: d?.option_group_id
|
|
273
330
|
}));
|
|
274
331
|
}
|
|
275
332
|
function toBundleNumber(value, fallback = 0) {
|
|
276
333
|
const parsed = Number(value);
|
|
277
334
|
return Number.isFinite(parsed) ? parsed : fallback;
|
|
278
335
|
}
|
|
336
|
+
function toBundleCustomPriceString(value) {
|
|
337
|
+
const parsed = Number(value);
|
|
338
|
+
if (Number.isFinite(parsed)) return parsed.toFixed(2);
|
|
339
|
+
if (value === null || value === undefined || value === '') return '0.00';
|
|
340
|
+
return String(value);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 出站补齐:以 additive 方式把 bundle 项补足为后端 checkout 协议所需的形状,
|
|
344
|
+
// 同时把 Summary / Rules 运行时写到 bundle 顶层的 surcharge_fee / relation_surcharge_ids
|
|
345
|
+
// 和来自 _origin 的 product_discount_difference 汇总到 metadata。
|
|
346
|
+
// 保留原对象上已有字段(如 discount_list、metadata.custom_product_bundle_map_id)
|
|
347
|
+
// 以兼容运行时 bundle 归一化、Rules、Summary 的消费。
|
|
279
348
|
function formatSubmitBundleItems(bundle) {
|
|
280
|
-
if (!Array.isArray(bundle))
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
const
|
|
285
|
-
const sellingPriceNum = toBundleNumber(
|
|
286
|
-
rawBundle.bundle_selling_price ?? rawBundle.price,
|
|
287
|
-
0
|
|
288
|
-
);
|
|
349
|
+
if (!Array.isArray(bundle)) return [];
|
|
350
|
+
return bundle.map(b => {
|
|
351
|
+
const rawBundle = b && typeof b === 'object' ? b : {};
|
|
352
|
+
const existedMetadata = rawBundle.metadata && typeof rawBundle.metadata === 'object' ? rawBundle.metadata : {};
|
|
353
|
+
const sellingPriceNum = toBundleNumber(rawBundle.bundle_selling_price ?? rawBundle.price, 0);
|
|
289
354
|
const priceNum = toBundleNumber(rawBundle.price, sellingPriceNum);
|
|
290
|
-
const priceType = rawBundle.price_type ??
|
|
355
|
+
const priceType = rawBundle.price_type ?? '';
|
|
356
|
+
// const customPriceStr = toBundleCustomPriceString(
|
|
357
|
+
// rawBundle.custom_price ?? rawBundle.bundle_selling_price ?? rawBundle.price,
|
|
358
|
+
// );
|
|
359
|
+
|
|
291
360
|
const relationSurchargeIds = Array.isArray(rawBundle.relation_surcharge_ids) ? rawBundle.relation_surcharge_ids : Array.isArray(existedMetadata.relation_surcharge_ids) ? existedMetadata.relation_surcharge_ids : [];
|
|
292
|
-
const surchargeFee = toBundleNumber(
|
|
293
|
-
|
|
294
|
-
0
|
|
295
|
-
);
|
|
296
|
-
const productDiscountDifference = toBundleNumber(
|
|
297
|
-
existedMetadata.product_discount_difference,
|
|
298
|
-
0
|
|
299
|
-
);
|
|
361
|
+
const surchargeFee = toBundleNumber(rawBundle.surcharge_fee ?? existedMetadata.surcharge_fee, 0);
|
|
362
|
+
const productDiscountDifference = toBundleNumber(existedMetadata.product_discount_difference, 0);
|
|
300
363
|
return {
|
|
301
364
|
...rawBundle,
|
|
302
365
|
is_charge_tax: rawBundle.is_charge_tax ?? 0,
|
|
@@ -304,16 +367,16 @@ function formatSubmitBundleItems(bundle) {
|
|
|
304
367
|
bundle_variant_id: rawBundle.bundle_variant_id ?? 0,
|
|
305
368
|
num: toBundleNumber(rawBundle.num, 1),
|
|
306
369
|
extension_id: rawBundle.extension_id ?? 0,
|
|
307
|
-
extension_type: rawBundle.extension_type ??
|
|
370
|
+
extension_type: rawBundle.extension_type ?? 'normal',
|
|
308
371
|
price: priceNum,
|
|
309
372
|
price_type: priceType,
|
|
310
|
-
price_type_ext: rawBundle.price_type_ext ??
|
|
373
|
+
price_type_ext: rawBundle.price_type_ext ?? '',
|
|
311
374
|
// custom_price: customPriceStr,
|
|
312
|
-
custom_price_type: rawBundle.custom_price_type ?? priceType ??
|
|
375
|
+
custom_price_type: rawBundle.custom_price_type ?? priceType ?? '',
|
|
313
376
|
bundle_selling_price: sellingPriceNum,
|
|
314
377
|
option: formatSubmitOptionItems(rawBundle.option),
|
|
315
|
-
bundle_group_id: rawBundle
|
|
316
|
-
bundle_id: rawBundle
|
|
378
|
+
bundle_group_id: rawBundle?.group_id,
|
|
379
|
+
bundle_id: rawBundle?.id,
|
|
317
380
|
metadata: {
|
|
318
381
|
...existedMetadata,
|
|
319
382
|
surcharge_fee: surchargeFee,
|
|
@@ -323,34 +386,52 @@ function formatSubmitBundleItems(bundle) {
|
|
|
323
386
|
};
|
|
324
387
|
});
|
|
325
388
|
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* 把 tempOrder product 打包成出站 submit payload。
|
|
392
|
+
*
|
|
393
|
+
* 价格字段语义(出站口径,v2 composite):
|
|
394
|
+
* - `selling_price`:**行 composite 券后单价**
|
|
395
|
+
* = `metadata.main_product_selling_price` + Σ(bundle_selling_price × num)。
|
|
396
|
+
* - `original_price`:**行 composite 券前单价**
|
|
397
|
+
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
398
|
+
* - `payment_price`:兼容后端的出站字段,直接从 `selling_price` 派生(composite)。
|
|
399
|
+
* - `metadata.source_product_price`:主商品/variant 基础价(不含 option、不含折扣),权威源。
|
|
400
|
+
* - `metadata.main_product_original_price`:含 option、不含折扣。
|
|
401
|
+
* - `metadata.main_product_selling_price`:含 option、含主商品折扣。
|
|
402
|
+
* - `metadata.price_schema_version`:schema 版本号(当前 = 2),用于跨端协商价格口径。
|
|
403
|
+
*
|
|
404
|
+
* 本函数不再改造价格字段形状,仅做字段/metadata 裁剪。
|
|
405
|
+
*/
|
|
326
406
|
function normalizeSubmitProduct(product) {
|
|
327
|
-
const {
|
|
407
|
+
const {
|
|
408
|
+
_origin,
|
|
409
|
+
identity_key,
|
|
410
|
+
...submitProduct
|
|
411
|
+
} = product;
|
|
328
412
|
const rawMetadata = submitProduct.metadata || {};
|
|
329
413
|
const bookingUid = rawMetadata.booking_uid;
|
|
330
414
|
const cleanMetadata = {};
|
|
331
415
|
if (rawMetadata.unique_identification_number) {
|
|
332
416
|
cleanMetadata.unique_identification_number = rawMetadata.unique_identification_number;
|
|
333
417
|
}
|
|
334
|
-
const priceMetaKeys = [
|
|
335
|
-
"main_product_original_price",
|
|
336
|
-
"main_product_selling_price",
|
|
337
|
-
"source_product_price",
|
|
338
|
-
"price_schema_version"
|
|
339
|
-
];
|
|
418
|
+
const priceMetaKeys = ['main_product_original_price', 'main_product_selling_price', 'source_product_price', 'price_schema_version'];
|
|
340
419
|
for (const key of priceMetaKeys) {
|
|
341
|
-
if (rawMetadata[key] !==
|
|
420
|
+
if (rawMetadata[key] !== undefined) {
|
|
342
421
|
cleanMetadata[key] = rawMetadata[key];
|
|
343
422
|
}
|
|
344
423
|
}
|
|
345
424
|
if (rawMetadata.price_breakdown) {
|
|
346
425
|
cleanMetadata.price_breakdown = rawMetadata.price_breakdown;
|
|
347
426
|
}
|
|
348
|
-
if (rawMetadata.is_rule !==
|
|
427
|
+
if (rawMetadata.is_rule !== undefined) {
|
|
349
428
|
cleanMetadata.is_rule = rawMetadata.is_rule;
|
|
350
429
|
}
|
|
351
430
|
return {
|
|
352
431
|
...submitProduct,
|
|
353
|
-
...bookingUid ? {
|
|
432
|
+
...(bookingUid ? {
|
|
433
|
+
booking_uid: bookingUid
|
|
434
|
+
} : {}),
|
|
354
435
|
product_option_item: formatSubmitOptionItems(submitProduct.product_option_item),
|
|
355
436
|
discount_list: submitProduct.discount_list || [],
|
|
356
437
|
product_bundle: formatSubmitBundleItems(submitProduct.product_bundle),
|
|
@@ -360,15 +441,12 @@ function normalizeSubmitProduct(product) {
|
|
|
360
441
|
payment_price: submitProduct.selling_price
|
|
361
442
|
};
|
|
362
443
|
}
|
|
363
|
-
|
|
364
|
-
"unique_identification_number",
|
|
365
|
-
"collect_pax"
|
|
366
|
-
];
|
|
444
|
+
const SUBMIT_BOOKING_METADATA_WHITELIST = ['unique_identification_number', 'collect_pax'];
|
|
367
445
|
function normalizeSubmitBooking(booking) {
|
|
368
446
|
const rawMetadata = booking.metadata || {};
|
|
369
447
|
const cleanMetadata = {};
|
|
370
448
|
for (const key of SUBMIT_BOOKING_METADATA_WHITELIST) {
|
|
371
|
-
if (rawMetadata[key] !==
|
|
449
|
+
if (rawMetadata[key] !== undefined) {
|
|
372
450
|
cleanMetadata[key] = rawMetadata[key];
|
|
373
451
|
}
|
|
374
452
|
}
|
|
@@ -377,20 +455,10 @@ function normalizeSubmitBooking(booking) {
|
|
|
377
455
|
metadata: cleanMetadata
|
|
378
456
|
};
|
|
379
457
|
}
|
|
380
|
-
|
|
458
|
+
const DEFAULT_TABLE_OCCUPANCY_DURATION = 20;
|
|
381
459
|
function resolveTableOccupancyDuration(tempOrder) {
|
|
382
|
-
var _a, _b, _c, _d;
|
|
383
460
|
const metadata = tempOrder.metadata || {};
|
|
384
|
-
const candidates = [
|
|
385
|
-
metadata.table_occupancy_duration,
|
|
386
|
-
metadata.booking_duration,
|
|
387
|
-
metadata.table_duration,
|
|
388
|
-
metadata.duration,
|
|
389
|
-
(_a = metadata.table_config) == null ? void 0 : _a.occupancy_duration,
|
|
390
|
-
(_b = metadata.tableConfig) == null ? void 0 : _b.occupancy_duration,
|
|
391
|
-
(_c = metadata.resource_config) == null ? void 0 : _c.occupancy_duration,
|
|
392
|
-
(_d = metadata.resourceConfig) == null ? void 0 : _d.occupancy_duration
|
|
393
|
-
];
|
|
461
|
+
const candidates = [metadata.table_occupancy_duration, metadata.booking_duration, metadata.table_duration, metadata.duration, metadata.table_config?.occupancy_duration, metadata.tableConfig?.occupancy_duration, metadata.resource_config?.occupancy_duration, metadata.resourceConfig?.occupancy_duration];
|
|
394
462
|
for (const value of candidates) {
|
|
395
463
|
const duration = Number(value);
|
|
396
464
|
if (Number.isFinite(duration) && duration > 0) {
|
|
@@ -399,47 +467,50 @@ function resolveTableOccupancyDuration(tempOrder) {
|
|
|
399
467
|
}
|
|
400
468
|
return DEFAULT_TABLE_OCCUPANCY_DURATION;
|
|
401
469
|
}
|
|
470
|
+
|
|
471
|
+
/** 提交用人数:有限且为正则向下取整,否则为 1 */
|
|
402
472
|
function normalizeSubmitCollectPaxValue(value) {
|
|
403
473
|
const n = Number(value);
|
|
404
474
|
return Number.isFinite(n) && n > 0 ? Math.floor(n) : 1;
|
|
405
475
|
}
|
|
476
|
+
|
|
477
|
+
/** 从临时订单 metadata 解析合成 booking 的 collect_pax */
|
|
406
478
|
function resolveSubmitCollectPax(tempOrder) {
|
|
407
|
-
|
|
408
|
-
return normalizeSubmitCollectPaxValue((_a = tempOrder.metadata) == null ? void 0 : _a.collect_pax);
|
|
479
|
+
return normalizeSubmitCollectPaxValue(tempOrder.metadata?.collect_pax);
|
|
409
480
|
}
|
|
410
481
|
function createDefaultTempOrder(params) {
|
|
411
|
-
const summary = params.summary || (0,
|
|
482
|
+
const summary = params.summary || (0, _utils2.createEmptySummary)();
|
|
412
483
|
return {
|
|
413
484
|
order_id: null,
|
|
414
|
-
relation_id:
|
|
415
|
-
table_form_id:
|
|
416
|
-
resource_id:
|
|
417
|
-
order_number:
|
|
418
|
-
shop_order_number:
|
|
419
|
-
type:
|
|
420
|
-
business_code:
|
|
421
|
-
platform:
|
|
422
|
-
sales_channel:
|
|
423
|
-
order_sales_channel:
|
|
424
|
-
status:
|
|
425
|
-
payment_status:
|
|
426
|
-
shipping_status:
|
|
485
|
+
relation_id: undefined,
|
|
486
|
+
table_form_id: undefined,
|
|
487
|
+
resource_id: undefined,
|
|
488
|
+
order_number: '',
|
|
489
|
+
shop_order_number: '',
|
|
490
|
+
type: 'appointment_booking',
|
|
491
|
+
business_code: 'appointment_booking',
|
|
492
|
+
platform: 'h5',
|
|
493
|
+
sales_channel: 'my_pisel',
|
|
494
|
+
order_sales_channel: 'online_store',
|
|
495
|
+
status: 'normal',
|
|
496
|
+
payment_status: 'payment_processing',
|
|
497
|
+
shipping_status: 'unfulfilled',
|
|
427
498
|
customer_id: null,
|
|
428
|
-
customer_name:
|
|
429
|
-
country_calling_code:
|
|
430
|
-
phone:
|
|
431
|
-
email:
|
|
499
|
+
customer_name: '',
|
|
500
|
+
country_calling_code: '',
|
|
501
|
+
phone: '',
|
|
502
|
+
email: '',
|
|
432
503
|
is_price_include_tax: 1,
|
|
433
|
-
tax_title:
|
|
434
|
-
tax_country_code:
|
|
435
|
-
currency_code:
|
|
436
|
-
currency_symbol:
|
|
437
|
-
currency_format:
|
|
504
|
+
tax_title: '',
|
|
505
|
+
tax_country_code: '',
|
|
506
|
+
currency_code: '',
|
|
507
|
+
currency_symbol: '',
|
|
508
|
+
currency_format: 'symbol_first',
|
|
438
509
|
is_deposit: 0,
|
|
439
|
-
deposit_amount:
|
|
440
|
-
shop_discount:
|
|
441
|
-
surcharge_fee:
|
|
442
|
-
note:
|
|
510
|
+
deposit_amount: '0.00',
|
|
511
|
+
shop_discount: '0.00',
|
|
512
|
+
surcharge_fee: '0.00',
|
|
513
|
+
note: '',
|
|
443
514
|
schedule_date: params.now,
|
|
444
515
|
created_at: params.now,
|
|
445
516
|
products: [],
|
|
@@ -459,7 +530,7 @@ function buildSubmitPayload(params) {
|
|
|
459
530
|
const {
|
|
460
531
|
tempOrder,
|
|
461
532
|
cacheId,
|
|
462
|
-
now =
|
|
533
|
+
now = new Date(),
|
|
463
534
|
platform,
|
|
464
535
|
businessCode,
|
|
465
536
|
channel,
|
|
@@ -467,57 +538,62 @@ function buildSubmitPayload(params) {
|
|
|
467
538
|
enhance
|
|
468
539
|
} = params;
|
|
469
540
|
const scheduleDate = tempOrder.schedule_date || tempOrder.created_at || formatDateTime(now);
|
|
470
|
-
const summary = tempOrder.summary || (0,
|
|
541
|
+
const summary = tempOrder.summary || (0, _utils2.createEmptySummary)();
|
|
471
542
|
const relationId = tempOrder.relation_id;
|
|
472
543
|
const tableFormId = tempOrder.table_form_id;
|
|
473
544
|
const bookingUuid = createUuidV4();
|
|
474
|
-
const bookingStart = (0,
|
|
545
|
+
const bookingStart = (0, _dayjs.default)(now);
|
|
475
546
|
const bookingDuration = resolveTableOccupancyDuration(tempOrder);
|
|
476
|
-
const bookingEnd = bookingStart.add(bookingDuration,
|
|
547
|
+
const bookingEnd = bookingStart.add(bookingDuration, 'minute');
|
|
477
548
|
const bookings = relationId && tableFormId ? [{
|
|
478
549
|
relation_id: 0,
|
|
479
550
|
form_id: 0,
|
|
480
|
-
start_time: bookingStart.format(
|
|
481
|
-
start_date: bookingStart.format(
|
|
482
|
-
end_time: bookingEnd.format(
|
|
483
|
-
end_date: bookingEnd.format(
|
|
551
|
+
start_time: bookingStart.format('HH:mm'),
|
|
552
|
+
start_date: bookingStart.format('YYYY-MM-DD'),
|
|
553
|
+
end_time: bookingEnd.format('HH:mm'),
|
|
554
|
+
end_date: bookingEnd.format('YYYY-MM-DD'),
|
|
484
555
|
duration: bookingDuration,
|
|
485
556
|
metadata: {
|
|
486
557
|
unique_identification_number: bookingUuid,
|
|
487
558
|
collect_pax: resolveSubmitCollectPax(tempOrder)
|
|
488
559
|
},
|
|
489
|
-
select_date: bookingStart.format(
|
|
560
|
+
select_date: bookingStart.format('YYYY-MM-DD'),
|
|
490
561
|
is_all: false,
|
|
491
|
-
like_status:
|
|
562
|
+
like_status: 'common',
|
|
492
563
|
schedule_id: 0,
|
|
493
|
-
relation_type:
|
|
564
|
+
relation_type: '',
|
|
494
565
|
number: 1
|
|
495
566
|
}] : tempOrder.bookings || [];
|
|
496
567
|
const formRecordIds = relationId && tableFormId ? [{
|
|
497
568
|
form_id: tableFormId,
|
|
498
569
|
form_record_id: relationId
|
|
499
|
-
}] :
|
|
500
|
-
const {
|
|
570
|
+
}] : undefined;
|
|
571
|
+
const {
|
|
572
|
+
created_at: _createdAt,
|
|
573
|
+
summary: _summary,
|
|
574
|
+
surcharges: _surcharges,
|
|
575
|
+
...tempOrderRest
|
|
576
|
+
} = tempOrder;
|
|
501
577
|
const payload = {
|
|
502
578
|
...tempOrderRest,
|
|
503
579
|
platform: normalizeSubmitPlatform(platform ?? tempOrder.platform),
|
|
504
580
|
request_unique_idempotency_token: cacheId,
|
|
505
|
-
type: type ?? tempOrder.type ??
|
|
506
|
-
business_code: businessCode ?? tempOrder.business_code ??
|
|
507
|
-
sales_channel: tempOrder.sales_channel ||
|
|
508
|
-
order_sales_channel: channel ?? tempOrder.order_sales_channel ??
|
|
509
|
-
status: tempOrder.status ||
|
|
510
|
-
payment_status: tempOrder.payment_status ||
|
|
581
|
+
type: type ?? tempOrder.type ?? 'table-order',
|
|
582
|
+
business_code: businessCode ?? tempOrder.business_code ?? 'table-order',
|
|
583
|
+
sales_channel: tempOrder.sales_channel || 'my_pisel',
|
|
584
|
+
order_sales_channel: channel ?? tempOrder.order_sales_channel ?? 'online_store',
|
|
585
|
+
status: tempOrder.status || 'normal',
|
|
586
|
+
payment_status: tempOrder.payment_status || 'payment_processing',
|
|
511
587
|
// shipping_status: tempOrder.shipping_status || 'unfulfilled',
|
|
512
588
|
is_price_include_tax: tempOrder.is_price_include_tax ?? 1,
|
|
513
|
-
currency_format: tempOrder.currency_format ||
|
|
589
|
+
currency_format: tempOrder.currency_format || 'symbol_first',
|
|
514
590
|
is_deposit: tempOrder.is_deposit ?? 0,
|
|
515
|
-
deposit_amount: tempOrder.deposit_amount ||
|
|
516
|
-
shop_discount: tempOrder.shop_discount ||
|
|
517
|
-
surcharge_fee: summary.surcharge_fee || tempOrder.surcharge_fee ||
|
|
518
|
-
note: tempOrder.note ||
|
|
591
|
+
deposit_amount: tempOrder.deposit_amount || '0.00',
|
|
592
|
+
shop_discount: tempOrder.shop_discount || '0.00',
|
|
593
|
+
surcharge_fee: summary.surcharge_fee || tempOrder.surcharge_fee || '0.00',
|
|
594
|
+
note: tempOrder.note || '',
|
|
519
595
|
schedule_date: scheduleDate,
|
|
520
|
-
bookings: bookings.map(
|
|
596
|
+
bookings: bookings.map(booking => normalizeSubmitBooking(booking)),
|
|
521
597
|
payments: tempOrder.payments || [],
|
|
522
598
|
// discount_list: tempOrder.discount_list || [],
|
|
523
599
|
relation_forms: tempOrder.relation_forms || [],
|
|
@@ -532,22 +608,33 @@ function buildSubmitPayload(params) {
|
|
|
532
608
|
table_occupancy_duration: _tableOccupancyDuration,
|
|
533
609
|
...rest
|
|
534
610
|
} = tempOrder.metadata || {};
|
|
535
|
-
return {
|
|
611
|
+
return {
|
|
612
|
+
...rest
|
|
613
|
+
};
|
|
536
614
|
})(),
|
|
537
|
-
products: (tempOrder.products || []).map(
|
|
538
|
-
(product) => normalizeSubmitProduct(product)
|
|
539
|
-
)
|
|
615
|
+
products: (tempOrder.products || []).map(product => normalizeSubmitProduct(product))
|
|
540
616
|
};
|
|
541
|
-
return enhance ? enhance(payload, {
|
|
617
|
+
return enhance ? enhance(payload, {
|
|
618
|
+
tempOrder,
|
|
619
|
+
bookingUuid,
|
|
620
|
+
now
|
|
621
|
+
}) : payload;
|
|
542
622
|
}
|
|
623
|
+
|
|
624
|
+
/** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
|
|
543
625
|
function filterProductsForScanOrderMore(products) {
|
|
544
|
-
return (products || []).filter(
|
|
545
|
-
var _a;
|
|
546
|
-
return ((_a = p.metadata) == null ? void 0 : _a.is_rule) !== true;
|
|
547
|
-
});
|
|
626
|
+
return (products || []).filter(p => p.metadata?.is_rule !== true);
|
|
548
627
|
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* 历史 V1 加餐结构映射器。
|
|
631
|
+
*
|
|
632
|
+
* @deprecated 加餐(`PUT /order/order/product/:id`)已改为与正常 checkout 共用
|
|
633
|
+
* `ScanOrderSubmitProduct` 新结构(见 `OrderModule.submitTempOrder` 的加餐分支)。
|
|
634
|
+
* 本函数仅保留以兼容历史接入方,未来会移除。新代码请勿再调用。
|
|
635
|
+
*/
|
|
549
636
|
function formatV1Product(products) {
|
|
550
|
-
return products.map(
|
|
637
|
+
return products.map(product => {
|
|
551
638
|
return {
|
|
552
639
|
bundle: product.product_bundle,
|
|
553
640
|
key: product.product_id,
|
|
@@ -555,31 +642,10 @@ function formatV1Product(products) {
|
|
|
555
642
|
product_id: product.product_id,
|
|
556
643
|
product_variant_id: product.product_variant_id,
|
|
557
644
|
num: product.num,
|
|
558
|
-
note: String(product.note ??
|
|
645
|
+
note: String(product.note ?? ''),
|
|
559
646
|
rowKey: product.product_id,
|
|
560
647
|
session: null,
|
|
561
648
|
unique: createUuidV4()
|
|
562
649
|
};
|
|
563
650
|
});
|
|
564
|
-
}
|
|
565
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
566
|
-
0 && (module.exports = {
|
|
567
|
-
buildSubmitPayload,
|
|
568
|
-
composeLinePrice,
|
|
569
|
-
createDefaultOrderRulesHooks,
|
|
570
|
-
createDefaultTempOrder,
|
|
571
|
-
createEmptySummary,
|
|
572
|
-
createUuidV4,
|
|
573
|
-
ensureCartItemOriginHolder,
|
|
574
|
-
filterProductsForScanOrderMore,
|
|
575
|
-
formatDateTime,
|
|
576
|
-
formatV1Product,
|
|
577
|
-
generateDuration,
|
|
578
|
-
getAllDiscountList,
|
|
579
|
-
isTempOrder,
|
|
580
|
-
mergeRelationForms,
|
|
581
|
-
normalizeSubmitBooking,
|
|
582
|
-
normalizeSubmitCollectPaxValue,
|
|
583
|
-
resolveSubmitCollectPax,
|
|
584
|
-
sumOptionUnitPrice
|
|
585
|
-
});
|
|
651
|
+
}
|