@pisell/pisellos 0.0.511 → 0.0.513
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/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +79 -58
- package/dist/modules/Order/types.d.ts +11 -0
- package/dist/modules/Order/utils.d.ts +63 -11
- package/dist/modules/Order/utils.js +242 -43
- package/dist/modules/SalesSummary/utils.js +36 -69
- package/dist/modules/Summary/utils.js +6 -21
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/ScanOrder/index.d.ts +3 -0
- package/dist/solution/ScanOrder/index.js +558 -498
- package/dist/solution/ScanOrder/types.d.ts +29 -2
- package/dist/solution/ScanOrder/utils.d.ts +18 -2
- package/dist/solution/ScanOrder/utils.js +111 -29
- package/dist/solution/VenueBooking/index.js +35 -27
- package/lib/model/strategy/adapter/promotion/index.js +0 -49
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +20 -7
- package/lib/modules/Order/types.d.ts +11 -0
- package/lib/modules/Order/utils.d.ts +63 -11
- package/lib/modules/Order/utils.js +149 -17
- package/lib/modules/SalesSummary/utils.js +16 -48
- package/lib/modules/Summary/utils.js +4 -18
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/ScanOrder/index.d.ts +3 -0
- package/lib/solution/ScanOrder/index.js +30 -4
- package/lib/solution/ScanOrder/types.d.ts +29 -2
- package/lib/solution/ScanOrder/utils.d.ts +18 -2
- package/lib/solution/ScanOrder/utils.js +66 -15
- package/lib/solution/VenueBooking/index.js +13 -6
- package/package.json +1 -1
|
@@ -1,21 +1,66 @@
|
|
|
1
|
+
import Decimal from 'decimal.js';
|
|
1
2
|
import { CartItem } from "../Cart";
|
|
2
3
|
import type { ScanOrderSubmitPayload, ScanOrderSubmitProduct, ScanOrderSummary, ScanOrderTempOrder } from '../../solution/ScanOrder/types';
|
|
3
4
|
import type { RulesParamsHooks } from '../Rules/types';
|
|
5
|
+
/**
|
|
6
|
+
* 把"含 option 的主商品单价"与 bundle 合成"单行 composite 单价"。
|
|
7
|
+
*
|
|
8
|
+
* 新语义 v2 约定:
|
|
9
|
+
* - `mainPrice` 必须是**已经包含 option 的主商品单价**(即 `metadata.main_product_selling_price`
|
|
10
|
+
* 或 `metadata.main_product_original_price`),option 价格不由本函数叠加。
|
|
11
|
+
* - 套餐价:Σ((bundle.bundle_selling_price ?? bundle.price) × (bundle.num ?? bundle.quantity ?? 1))
|
|
12
|
+
* 当 `useOriginalBundle=true` 时,改用 `bundle.original_price ?? bundle.product_price ?? bundle.price`。
|
|
13
|
+
* - 返回值:保留 2 位小数的字符串,方便直接写回 `selling_price` / `original_price` 字段。
|
|
14
|
+
*
|
|
15
|
+
* 被 `normalizeOrderProduct`、Rules setProduct 钩子、各 Solution 的 setDiscountSelected 共用,
|
|
16
|
+
* 保证合成逻辑单点来源。
|
|
17
|
+
*/
|
|
18
|
+
export declare function composeLinePrice(params: {
|
|
19
|
+
mainPrice: string | number | null | undefined;
|
|
20
|
+
bundle?: Array<{
|
|
21
|
+
bundle_selling_price?: any;
|
|
22
|
+
price?: any;
|
|
23
|
+
num?: any;
|
|
24
|
+
quantity?: any;
|
|
25
|
+
original_price?: any;
|
|
26
|
+
product_price?: any;
|
|
27
|
+
}> | null;
|
|
28
|
+
useOriginalBundle?: boolean;
|
|
29
|
+
}): string;
|
|
30
|
+
/**
|
|
31
|
+
* 计算 option 单价合计:Σ(option.price × option.num)。
|
|
32
|
+
* 在新语义 v2 下,main_product_original_price = source_product_price + 本函数结果。
|
|
33
|
+
*/
|
|
34
|
+
export declare function sumOptionUnitPrice(options?: Array<{
|
|
35
|
+
price?: any;
|
|
36
|
+
num?: any;
|
|
37
|
+
}> | null): Decimal;
|
|
4
38
|
/**
|
|
5
39
|
* OrderModule 默认 Rules 钩子工厂。
|
|
6
40
|
*
|
|
7
|
-
*
|
|
8
|
-
* - `selling_price
|
|
9
|
-
*
|
|
10
|
-
* - `
|
|
41
|
+
* 价格语义约定(订单域,v2 composite 口径):
|
|
42
|
+
* - `selling_price`:券后 **行 composite 单价**
|
|
43
|
+
* = `metadata.main_product_selling_price` + Σ(bundle_selling_price × num)。
|
|
44
|
+
* - `original_price`:券前 **行 composite 单价**
|
|
45
|
+
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
46
|
+
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
|
|
47
|
+
* 不含折扣。**权威源**。
|
|
48
|
+
* - `metadata.main_product_original_price` = source + Σ(option.price × option.num)(含 option、不含折扣)。
|
|
49
|
+
* - `metadata.main_product_selling_price` = main_original − 主商品券 per-unit amount(含 option、含折扣)。
|
|
50
|
+
* - `payment_price`:出站 payload 中由 `selling_price` 派生以兼容后端(composite)。
|
|
11
51
|
*
|
|
12
|
-
* Rules
|
|
13
|
-
* - `getProduct.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
52
|
+
* Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
|
|
53
|
+
* - `getProduct.price` / `getProduct.original_price` 回传 **source-level 主价**
|
|
54
|
+
* (`metadata.source_product_price`)。Rules 内部 `getProductTotalPrice` /
|
|
55
|
+
* `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
|
|
56
|
+
* - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
|
|
57
|
+
* total(source + option + bundle)对齐。
|
|
58
|
+
* - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
|
|
59
|
+
* 加回 Σoptions,重新合成含 option 的 main_product_* 并派生 composite。
|
|
60
|
+
* 优先级:
|
|
61
|
+
* 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
|
|
62
|
+
* 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
|
|
63
|
+
* 3. `values.total / num`(仅当 Rules 只给出总价时的兜底)
|
|
19
64
|
*
|
|
20
65
|
* 导出为纯函数方便单测直接驱动钩子,不依赖 OrderModule 实例。
|
|
21
66
|
*/
|
|
@@ -74,6 +119,13 @@ export declare function buildSubmitPayload(params: {
|
|
|
74
119
|
}): ScanOrderSubmitPayload;
|
|
75
120
|
/** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
|
|
76
121
|
export declare function filterProductsForScanOrderMore(products: ScanOrderSubmitProduct[]): ScanOrderSubmitProduct[];
|
|
122
|
+
/**
|
|
123
|
+
* 历史 V1 加餐结构映射器。
|
|
124
|
+
*
|
|
125
|
+
* @deprecated 加餐(`PUT /order/order/product/:id`)已改为与正常 checkout 共用
|
|
126
|
+
* `ScanOrderSubmitProduct` 新结构(见 `OrderModule.submitTempOrder` 的加餐分支)。
|
|
127
|
+
* 本函数仅保留以兼容历史接入方,未来会移除。新代码请勿再调用。
|
|
128
|
+
*/
|
|
77
129
|
export declare function formatV1Product(products: ScanOrderSubmitProduct[]): {
|
|
78
130
|
bundle: any[];
|
|
79
131
|
key: number | null;
|
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
var utils_exports = {};
|
|
31
31
|
__export(utils_exports, {
|
|
32
32
|
buildSubmitPayload: () => buildSubmitPayload,
|
|
33
|
+
composeLinePrice: () => composeLinePrice,
|
|
33
34
|
createDefaultOrderRulesHooks: () => createDefaultOrderRulesHooks,
|
|
34
35
|
createDefaultTempOrder: () => createDefaultTempOrder,
|
|
35
36
|
createEmptySummary: () => import_utils2.createEmptySummary,
|
|
@@ -43,13 +44,39 @@ __export(utils_exports, {
|
|
|
43
44
|
mergeRelationForms: () => mergeRelationForms,
|
|
44
45
|
normalizeSubmitBooking: () => normalizeSubmitBooking,
|
|
45
46
|
normalizeSubmitCollectPaxValue: () => normalizeSubmitCollectPaxValue,
|
|
46
|
-
resolveSubmitCollectPax: () => resolveSubmitCollectPax
|
|
47
|
+
resolveSubmitCollectPax: () => resolveSubmitCollectPax,
|
|
48
|
+
sumOptionUnitPrice: () => sumOptionUnitPrice
|
|
47
49
|
});
|
|
48
50
|
module.exports = __toCommonJS(utils_exports);
|
|
49
51
|
var import_dayjs = __toESM(require("dayjs"));
|
|
50
52
|
var import_decimal = __toESM(require("decimal.js"));
|
|
51
53
|
var import_utils = require("../../solution/ScanOrder/utils");
|
|
52
54
|
var import_utils2 = require("../../solution/ScanOrder/utils");
|
|
55
|
+
function composeLinePrice(params) {
|
|
56
|
+
const { mainPrice, bundle, useOriginalBundle } = params;
|
|
57
|
+
let total = new import_decimal.default(Number(mainPrice) || 0);
|
|
58
|
+
if (Array.isArray(bundle)) {
|
|
59
|
+
for (const item of bundle) {
|
|
60
|
+
const rawPrice = useOriginalBundle ? (item == null ? void 0 : item.original_price) ?? (item == null ? void 0 : item.product_price) ?? (item == null ? void 0 : item.price) : (item == null ? void 0 : item.bundle_selling_price) ?? (item == null ? void 0 : item.price);
|
|
61
|
+
const price = new import_decimal.default(Number(rawPrice) || 0);
|
|
62
|
+
const rawNum = (item == null ? void 0 : item.num) ?? (item == null ? void 0 : item.quantity) ?? 1;
|
|
63
|
+
const num = new import_decimal.default(Number(rawNum) || 0);
|
|
64
|
+
total = total.plus(price.times(num));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return total.toDecimalPlaces(2).toFixed(2);
|
|
68
|
+
}
|
|
69
|
+
function sumOptionUnitPrice(options) {
|
|
70
|
+
let total = new import_decimal.default(0);
|
|
71
|
+
if (!Array.isArray(options))
|
|
72
|
+
return total;
|
|
73
|
+
for (const opt of options) {
|
|
74
|
+
const price = new import_decimal.default(Number(opt == null ? void 0 : opt.price) || 0);
|
|
75
|
+
const num = new import_decimal.default(Number(opt == null ? void 0 : opt.num) || 0);
|
|
76
|
+
total = total.plus(price.times(num));
|
|
77
|
+
}
|
|
78
|
+
return total;
|
|
79
|
+
}
|
|
53
80
|
function createDefaultOrderRulesHooks() {
|
|
54
81
|
const toUnitPriceString = (totalLike, num) => {
|
|
55
82
|
const effectiveNum = Number(num) > 0 ? Number(num) : 1;
|
|
@@ -58,6 +85,28 @@ function createDefaultOrderRulesHooks() {
|
|
|
58
85
|
return {
|
|
59
86
|
getProduct: (product) => {
|
|
60
87
|
var _a, _b, _c, _d;
|
|
88
|
+
const metadataAny = product.metadata || {};
|
|
89
|
+
const optionSum = sumOptionUnitPrice(product.product_option_item);
|
|
90
|
+
let sourcePrice;
|
|
91
|
+
if (metadataAny.source_product_price !== void 0) {
|
|
92
|
+
sourcePrice = String(metadataAny.source_product_price);
|
|
93
|
+
} else if (metadataAny.main_product_selling_price !== void 0) {
|
|
94
|
+
sourcePrice = new import_decimal.default(
|
|
95
|
+
Number(metadataAny.main_product_selling_price) || 0
|
|
96
|
+
).minus(optionSum).toDecimalPlaces(2).toString();
|
|
97
|
+
} else {
|
|
98
|
+
sourcePrice = String(product.selling_price ?? 0);
|
|
99
|
+
}
|
|
100
|
+
let sourceOriginalPrice;
|
|
101
|
+
if (metadataAny.source_product_price !== void 0) {
|
|
102
|
+
sourceOriginalPrice = String(metadataAny.source_product_price);
|
|
103
|
+
} else if (metadataAny.main_product_original_price !== void 0) {
|
|
104
|
+
sourceOriginalPrice = new import_decimal.default(
|
|
105
|
+
Number(metadataAny.main_product_original_price) || 0
|
|
106
|
+
).minus(optionSum).toDecimalPlaces(2).toString();
|
|
107
|
+
} else {
|
|
108
|
+
sourceOriginalPrice = sourcePrice;
|
|
109
|
+
}
|
|
61
110
|
return {
|
|
62
111
|
id: product.product_id,
|
|
63
112
|
// Rules 引擎用 _id 作为 processedProductsMap 键;必须与购物车行级 identity 一致,
|
|
@@ -68,10 +117,15 @@ function createDefaultOrderRulesHooks() {
|
|
|
68
117
|
product.product_option_item,
|
|
69
118
|
product.product_bundle
|
|
70
119
|
)}`,
|
|
71
|
-
|
|
120
|
+
// Rules 内部 getProductTotalPrice / getProductOriginTotalPrice 会各自再叠加 bundle + option,
|
|
121
|
+
// 所以这里必须喂 source-level(不含 option、不含 bundle、不含折扣)单价,避免双加 option。
|
|
122
|
+
price: sourcePrice,
|
|
123
|
+
// total / origin_total 使用 composite × num,跟 Rules 内部产出的 total 对齐(含 option + bundle)。
|
|
72
124
|
total: new import_decimal.default(product.selling_price || 0).times(product.num || 1).toNumber(),
|
|
73
|
-
origin_total: new import_decimal.default(
|
|
74
|
-
|
|
125
|
+
origin_total: new import_decimal.default(
|
|
126
|
+
product.original_price || product.selling_price || 0
|
|
127
|
+
).times(product.num || 1).toNumber(),
|
|
128
|
+
original_price: sourceOriginalPrice,
|
|
75
129
|
quantity: product.num || 1,
|
|
76
130
|
num: product.num || 1,
|
|
77
131
|
discount_list: product.discount_list || [],
|
|
@@ -85,17 +139,37 @@ function createDefaultOrderRulesHooks() {
|
|
|
85
139
|
},
|
|
86
140
|
setProduct: (product, values) => {
|
|
87
141
|
const nextNum = Number(values.quantity ?? product.num ?? 1) || 1;
|
|
88
|
-
const
|
|
142
|
+
const metadataAny = product.metadata || {};
|
|
143
|
+
const existedSource = metadataAny.source_product_price ?? product.selling_price ?? "0";
|
|
144
|
+
const nextOptions = product.product_option_item;
|
|
145
|
+
const optionSum = sumOptionUnitPrice(nextOptions);
|
|
146
|
+
const nextSourceSellingPrice = values.main_product_selling_price !== void 0 ? String(values.main_product_selling_price) : values.price !== void 0 ? String(values.price) : values.total !== void 0 ? toUnitPriceString(values.total, nextNum) : String(existedSource);
|
|
147
|
+
const nextSourceOriginalPrice = values.original_price !== void 0 ? String(values.original_price) : String(existedSource);
|
|
148
|
+
const nextMainSellingPrice = new import_decimal.default(Number(nextSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
149
|
+
const nextMainOriginalPrice = new import_decimal.default(Number(nextSourceOriginalPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
150
|
+
const nextBundle = values.bundle ?? product.product_bundle;
|
|
151
|
+
const composedSellingPrice = composeLinePrice({
|
|
152
|
+
mainPrice: nextMainSellingPrice,
|
|
153
|
+
bundle: nextBundle
|
|
154
|
+
});
|
|
155
|
+
const composedOriginalPrice = composeLinePrice({
|
|
156
|
+
mainPrice: nextMainOriginalPrice,
|
|
157
|
+
bundle: nextBundle,
|
|
158
|
+
useOriginalBundle: true
|
|
159
|
+
});
|
|
89
160
|
return {
|
|
90
161
|
...product,
|
|
91
|
-
selling_price:
|
|
92
|
-
original_price:
|
|
162
|
+
selling_price: composedSellingPrice,
|
|
163
|
+
original_price: composedOriginalPrice,
|
|
93
164
|
discount_list: values.discount_list ?? product.discount_list,
|
|
94
165
|
num: values.quantity ?? product.num,
|
|
95
|
-
product_bundle:
|
|
166
|
+
product_bundle: nextBundle,
|
|
96
167
|
metadata: {
|
|
97
|
-
...
|
|
98
|
-
|
|
168
|
+
...metadataAny,
|
|
169
|
+
source_product_price: nextSourceSellingPrice,
|
|
170
|
+
main_product_selling_price: nextMainSellingPrice,
|
|
171
|
+
main_product_original_price: nextMainOriginalPrice,
|
|
172
|
+
price_schema_version: 2
|
|
99
173
|
}
|
|
100
174
|
};
|
|
101
175
|
}
|
|
@@ -168,13 +242,67 @@ function formatSubmitOptionItems(options) {
|
|
|
168
242
|
option_group_id: d == null ? void 0 : d.option_group_id
|
|
169
243
|
}));
|
|
170
244
|
}
|
|
245
|
+
function toBundleNumber(value, fallback = 0) {
|
|
246
|
+
const parsed = Number(value);
|
|
247
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
248
|
+
}
|
|
249
|
+
function toBundleCustomPriceString(value) {
|
|
250
|
+
const parsed = Number(value);
|
|
251
|
+
if (Number.isFinite(parsed))
|
|
252
|
+
return parsed.toFixed(2);
|
|
253
|
+
if (value === null || value === void 0 || value === "")
|
|
254
|
+
return "0.00";
|
|
255
|
+
return String(value);
|
|
256
|
+
}
|
|
171
257
|
function formatSubmitBundleItems(bundle) {
|
|
172
258
|
if (!Array.isArray(bundle))
|
|
173
259
|
return [];
|
|
174
|
-
return bundle.map((b) =>
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
260
|
+
return bundle.map((b) => {
|
|
261
|
+
const rawBundle = b && typeof b === "object" ? b : {};
|
|
262
|
+
const existedMetadata = rawBundle.metadata && typeof rawBundle.metadata === "object" ? rawBundle.metadata : {};
|
|
263
|
+
const sellingPriceNum = toBundleNumber(
|
|
264
|
+
rawBundle.bundle_selling_price ?? rawBundle.price,
|
|
265
|
+
0
|
|
266
|
+
);
|
|
267
|
+
const priceNum = toBundleNumber(rawBundle.price, sellingPriceNum);
|
|
268
|
+
const priceType = rawBundle.price_type ?? "";
|
|
269
|
+
const customPriceStr = toBundleCustomPriceString(
|
|
270
|
+
rawBundle.custom_price ?? rawBundle.bundle_selling_price ?? rawBundle.price
|
|
271
|
+
);
|
|
272
|
+
const relationSurchargeIds = Array.isArray(rawBundle.relation_surcharge_ids) ? rawBundle.relation_surcharge_ids : Array.isArray(existedMetadata.relation_surcharge_ids) ? existedMetadata.relation_surcharge_ids : [];
|
|
273
|
+
const surchargeFee = toBundleNumber(
|
|
274
|
+
rawBundle.surcharge_fee ?? existedMetadata.surcharge_fee,
|
|
275
|
+
0
|
|
276
|
+
);
|
|
277
|
+
const productDiscountDifference = toBundleNumber(
|
|
278
|
+
existedMetadata.product_discount_difference,
|
|
279
|
+
0
|
|
280
|
+
);
|
|
281
|
+
return {
|
|
282
|
+
...rawBundle,
|
|
283
|
+
is_charge_tax: rawBundle.is_charge_tax ?? 0,
|
|
284
|
+
tax_fee: toBundleNumber(rawBundle.tax_fee, 0),
|
|
285
|
+
bundle_variant_id: rawBundle.bundle_variant_id ?? 0,
|
|
286
|
+
num: toBundleNumber(rawBundle.num, 1),
|
|
287
|
+
extension_id: rawBundle.extension_id ?? 0,
|
|
288
|
+
extension_type: rawBundle.extension_type ?? "normal",
|
|
289
|
+
price: priceNum,
|
|
290
|
+
price_type: priceType,
|
|
291
|
+
price_type_ext: rawBundle.price_type_ext ?? "",
|
|
292
|
+
custom_price: customPriceStr,
|
|
293
|
+
custom_price_type: rawBundle.custom_price_type ?? priceType ?? "",
|
|
294
|
+
bundle_selling_price: sellingPriceNum,
|
|
295
|
+
option: formatSubmitOptionItems(rawBundle.option),
|
|
296
|
+
bundle_group_id: rawBundle == null ? void 0 : rawBundle.group_id,
|
|
297
|
+
bundle_id: rawBundle == null ? void 0 : rawBundle.id,
|
|
298
|
+
metadata: {
|
|
299
|
+
...existedMetadata,
|
|
300
|
+
surcharge_fee: surchargeFee,
|
|
301
|
+
relation_surcharge_ids: relationSurchargeIds,
|
|
302
|
+
product_discount_difference: productDiscountDifference
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
});
|
|
178
306
|
}
|
|
179
307
|
function normalizeSubmitProduct(product) {
|
|
180
308
|
const { _origin, identity_key, ...submitProduct } = product;
|
|
@@ -187,7 +315,8 @@ function normalizeSubmitProduct(product) {
|
|
|
187
315
|
const priceMetaKeys = [
|
|
188
316
|
"main_product_original_price",
|
|
189
317
|
"main_product_selling_price",
|
|
190
|
-
"source_product_price"
|
|
318
|
+
"source_product_price",
|
|
319
|
+
"price_schema_version"
|
|
191
320
|
];
|
|
192
321
|
for (const key of priceMetaKeys) {
|
|
193
322
|
if (rawMetadata[key] !== void 0) {
|
|
@@ -207,7 +336,8 @@ function normalizeSubmitProduct(product) {
|
|
|
207
336
|
discount_list: submitProduct.discount_list || [],
|
|
208
337
|
product_bundle: formatSubmitBundleItems(submitProduct.product_bundle),
|
|
209
338
|
metadata: cleanMetadata,
|
|
210
|
-
//
|
|
339
|
+
// 出站兼容:后端消费 payment_price 字段,这里从 selling_price 直接派生。
|
|
340
|
+
// 新语义下 selling_price 是 composite(含 option/bundle),payment_price 同语义。
|
|
211
341
|
payment_price: submitProduct.selling_price
|
|
212
342
|
};
|
|
213
343
|
}
|
|
@@ -416,6 +546,7 @@ function formatV1Product(products) {
|
|
|
416
546
|
// Annotate the CommonJS export names for ESM import in node:
|
|
417
547
|
0 && (module.exports = {
|
|
418
548
|
buildSubmitPayload,
|
|
549
|
+
composeLinePrice,
|
|
419
550
|
createDefaultOrderRulesHooks,
|
|
420
551
|
createDefaultTempOrder,
|
|
421
552
|
createEmptySummary,
|
|
@@ -429,5 +560,6 @@ function formatV1Product(products) {
|
|
|
429
560
|
mergeRelationForms,
|
|
430
561
|
normalizeSubmitBooking,
|
|
431
562
|
normalizeSubmitCollectPaxValue,
|
|
432
|
-
resolveSubmitCollectPax
|
|
563
|
+
resolveSubmitCollectPax,
|
|
564
|
+
sumOptionUnitPrice
|
|
433
565
|
});
|
|
@@ -48,30 +48,6 @@ function getSafeNum(num) {
|
|
|
48
48
|
return 1;
|
|
49
49
|
return Math.floor(num);
|
|
50
50
|
}
|
|
51
|
-
function getVariantPrice(product) {
|
|
52
|
-
var _a, _b;
|
|
53
|
-
const variantId = Number(product.product_variant_id || 0);
|
|
54
|
-
if (!variantId)
|
|
55
|
-
return null;
|
|
56
|
-
const metadataVariantList = (_b = (_a = product.metadata) == null ? void 0 : _a.origin) == null ? void 0 : _b.variant;
|
|
57
|
-
if (Array.isArray(metadataVariantList)) {
|
|
58
|
-
const variant = metadataVariantList.find(
|
|
59
|
-
(item) => Number(item.id) === variantId
|
|
60
|
-
);
|
|
61
|
-
if ((variant == null ? void 0 : variant.price) !== void 0 && (variant == null ? void 0 : variant.price) !== null) {
|
|
62
|
-
return toDecimal(variant.price);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
function getOptionUnitPrice(product) {
|
|
68
|
-
const optionItems = product.product_option_item || [];
|
|
69
|
-
return optionItems.reduce((sum, item) => {
|
|
70
|
-
const quantity = getSafeNum(item == null ? void 0 : item.num);
|
|
71
|
-
const itemPrice = toDecimal(item == null ? void 0 : item.price);
|
|
72
|
-
return sum.plus(itemPrice.times(quantity));
|
|
73
|
-
}, new import_decimal.default(0));
|
|
74
|
-
}
|
|
75
51
|
function getBundleUnitPrice(product, useOriginal = false) {
|
|
76
52
|
const bundleItems = product.product_bundle || [];
|
|
77
53
|
return bundleItems.reduce((sum, item) => {
|
|
@@ -81,13 +57,18 @@ function getBundleUnitPrice(product, useOriginal = false) {
|
|
|
81
57
|
}, new import_decimal.default(0));
|
|
82
58
|
}
|
|
83
59
|
function getUnitPaymentTotal(product) {
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
60
|
+
var _a, _b;
|
|
61
|
+
const mainSelling = (_a = product.metadata) == null ? void 0 : _a.main_product_selling_price;
|
|
62
|
+
const mainOriginal = (_b = product.metadata) == null ? void 0 : _b.main_product_original_price;
|
|
63
|
+
const basePrice = mainSelling !== void 0 ? toDecimal(mainSelling) : mainOriginal !== void 0 ? toDecimal(mainOriginal) : toDecimal(product.selling_price);
|
|
64
|
+
return basePrice.plus(getBundleUnitPrice(product));
|
|
87
65
|
}
|
|
88
66
|
function getUnitOriginalTotal(product) {
|
|
89
|
-
|
|
90
|
-
|
|
67
|
+
var _a, _b;
|
|
68
|
+
const mainOriginal = (_a = product.metadata) == null ? void 0 : _a.main_product_original_price;
|
|
69
|
+
const mainSelling = (_b = product.metadata) == null ? void 0 : _b.main_product_selling_price;
|
|
70
|
+
const basePrice = mainOriginal !== void 0 ? toDecimal(mainOriginal) : mainSelling !== void 0 ? toDecimal(mainSelling) : toDecimal(product.original_price || product.selling_price);
|
|
71
|
+
return basePrice.plus(getBundleUnitPrice(product, true));
|
|
91
72
|
}
|
|
92
73
|
function buildSurchargeServiceItems(products) {
|
|
93
74
|
return products.map((product) => {
|
|
@@ -207,12 +188,6 @@ function isBundleMarkupOrDiscount(item) {
|
|
|
207
188
|
const isDiscount = (item == null ? void 0 : item.price_type) === "markdown" && ((item == null ? void 0 : item.price_type_ext) === "" || !(item == null ? void 0 : item.price_type_ext));
|
|
208
189
|
return isMarkup || isDiscount;
|
|
209
190
|
}
|
|
210
|
-
function getDiscountListAmount(discountList) {
|
|
211
|
-
return (discountList || []).reduce(
|
|
212
|
-
(total, d) => total.plus(toDecimal(d.amount)),
|
|
213
|
-
new import_decimal.default(0)
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
191
|
function calculateSingleItemTax(params) {
|
|
217
192
|
const { price, taxRate, isPriceIncludeTax, isChargeTax } = params;
|
|
218
193
|
if (price.lte(0))
|
|
@@ -229,22 +204,15 @@ function calculateSingleItemTax(params) {
|
|
|
229
204
|
return price.dividedBy(divisor).times(rate);
|
|
230
205
|
}
|
|
231
206
|
function getMainProductPaymentTotal(product) {
|
|
232
|
-
var _a, _b
|
|
233
|
-
const
|
|
234
|
-
let total =
|
|
235
|
-
const mainDiscountList = ((_c = (_b = product._origin) == null ? void 0 : _b.product) == null ? void 0 : _c.discount_list) || ((_d = product._origin) == null ? void 0 : _d.discount_list) || [];
|
|
236
|
-
const mainDiscountAmount = getDiscountListAmount(
|
|
237
|
-
mainDiscountList.filter((d) => {
|
|
238
|
-
var _a2;
|
|
239
|
-
return !((_a2 = d == null ? void 0 : d.metadata) == null ? void 0 : _a2.custom_product_bundle_map_id);
|
|
240
|
-
})
|
|
241
|
-
);
|
|
242
|
-
total = total.minus(mainDiscountAmount);
|
|
243
|
-
total = total.plus(getOptionUnitPrice(product));
|
|
207
|
+
var _a, _b;
|
|
208
|
+
const mainSelling = ((_a = product.metadata) == null ? void 0 : _a.main_product_selling_price) ?? ((_b = product.metadata) == null ? void 0 : _b.main_product_original_price) ?? 0;
|
|
209
|
+
let total = toDecimal(mainSelling);
|
|
244
210
|
const bundleItems = product.product_bundle || [];
|
|
245
211
|
for (const bundleItem of bundleItems) {
|
|
246
212
|
if (isBundleMarkupOrDiscount(bundleItem)) {
|
|
247
|
-
|
|
213
|
+
const unit = toDecimal(bundleItem.bundle_selling_price ?? bundleItem.price ?? 0);
|
|
214
|
+
const qty = getSafeNum(bundleItem.num ?? bundleItem.quantity);
|
|
215
|
+
total = total.plus(unit.times(qty));
|
|
248
216
|
}
|
|
249
217
|
}
|
|
250
218
|
return import_decimal.default.max(total, 0);
|
|
@@ -437,25 +437,11 @@ var getBundleItemIsDiscountPrice = (item) => {
|
|
|
437
437
|
var getBundleItemIsMarkupOrDiscountPrice = (item) => {
|
|
438
438
|
return getBundleItemIsMarkupPrice(item) || getBundleItemIsDiscountPrice(item);
|
|
439
439
|
};
|
|
440
|
-
var getDiscountAmount = (discounts) => {
|
|
441
|
-
return (discounts || []).reduce((total, discount) => {
|
|
442
|
-
return total.add(new import_decimal.default(discount.amount || 0));
|
|
443
|
-
}, new import_decimal.default(0)).toNumber();
|
|
444
|
-
};
|
|
445
440
|
var getMainProductTotal = (item) => {
|
|
446
|
-
var _a, _b
|
|
447
|
-
let total = new import_decimal.default(
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
return !((_a2 = item2 == null ? void 0 : item2.metadata) == null ? void 0 : _a2.custom_product_bundle_map_id);
|
|
451
|
-
})) || [];
|
|
452
|
-
const mainProductDiscountAmount = getDiscountAmount(discount);
|
|
453
|
-
total = total.minus(mainProductDiscountAmount);
|
|
454
|
-
if ((item == null ? void 0 : item.option) && Array.isArray(item == null ? void 0 : item.option)) {
|
|
455
|
-
total = total.add(item == null ? void 0 : item.option.reduce((t, option) => {
|
|
456
|
-
return t.add(new import_decimal.default(option.price || 0).mul(option.num || 1));
|
|
457
|
-
}, new import_decimal.default(0)));
|
|
458
|
-
}
|
|
441
|
+
var _a, _b;
|
|
442
|
+
let total = new import_decimal.default(
|
|
443
|
+
(item == null ? void 0 : item.main_product_selling_price) ?? ((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a.main_product_selling_price) ?? ((_b = item == null ? void 0 : item.metadata) == null ? void 0 : _b.main_product_original_price) ?? 0
|
|
444
|
+
);
|
|
459
445
|
for (let bundleItem of (item == null ? void 0 : item.bundle) || []) {
|
|
460
446
|
if (getBundleItemIsMarkupOrDiscountPrice(bundleItem)) {
|
|
461
447
|
const bundleItemTotal = new import_decimal.default(bundleItem.bundle_selling_price ?? bundleItem.price ?? 0);
|
|
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
311
311
|
date: string;
|
|
312
312
|
status: string;
|
|
313
313
|
week: string;
|
|
314
|
-
weekNum: 0 |
|
|
314
|
+
weekNum: 0 | 2 | 1 | 3 | 5 | 4 | 6;
|
|
315
315
|
}[]>;
|
|
316
316
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
317
317
|
private getScheduleDataByIds;
|
|
@@ -131,7 +131,7 @@ export declare class BookingTicketImpl extends BaseModule implements Module {
|
|
|
131
131
|
* 获取当前的客户搜索条件
|
|
132
132
|
* @returns 当前搜索条件
|
|
133
133
|
*/
|
|
134
|
-
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "
|
|
134
|
+
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
|
|
135
135
|
/**
|
|
136
136
|
* 获取客户列表状态(包含滚动加载相关状态)
|
|
137
137
|
* @returns 客户状态
|
|
@@ -49,6 +49,9 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
49
49
|
private registerCustomerLoginListeners;
|
|
50
50
|
private refreshOrderMarketingAfterLogin;
|
|
51
51
|
constructor(name?: string, version?: string);
|
|
52
|
+
/** 与 `otherParams.cacheId` 一致,供宿主在 URL 变化时判断是否需要重新注册模块 */
|
|
53
|
+
getCacheId(): string | undefined;
|
|
54
|
+
private destroyRegisteredChildModules;
|
|
52
55
|
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
53
56
|
destroy(): Promise<void>;
|
|
54
57
|
retryInit(): Promise<void>;
|
|
@@ -260,6 +260,23 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
|
+
/** 与 `otherParams.cacheId` 一致,供宿主在 URL 变化时判断是否需要重新注册模块 */
|
|
264
|
+
getCacheId() {
|
|
265
|
+
return this.cacheId;
|
|
266
|
+
}
|
|
267
|
+
async destroyRegisteredChildModules() {
|
|
268
|
+
const modules = [
|
|
269
|
+
this.store.schedule,
|
|
270
|
+
this.store.salesSummary,
|
|
271
|
+
this.store.order,
|
|
272
|
+
this.store.products,
|
|
273
|
+
this.store.scanOrderLogger
|
|
274
|
+
];
|
|
275
|
+
for (const mod of modules) {
|
|
276
|
+
if (mod && typeof mod.destroy === "function")
|
|
277
|
+
await Promise.resolve(mod.destroy());
|
|
278
|
+
}
|
|
279
|
+
}
|
|
263
280
|
async initialize(core, options = {}) {
|
|
264
281
|
var _a, _b, _c, _d, _e, _f;
|
|
265
282
|
this.logMethodStart("initialize");
|
|
@@ -375,6 +392,8 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
375
392
|
this.logMethodStart("destroy");
|
|
376
393
|
this.clearLoginEffectListeners();
|
|
377
394
|
await this.core.effects.emit(import_types.ScanOrderHooks.onDestroy, {});
|
|
395
|
+
await this.destroyRegisteredChildModules();
|
|
396
|
+
super.destroy();
|
|
378
397
|
console.log("[ScanOrder] 已销毁");
|
|
379
398
|
this.logMethodSuccess("destroy");
|
|
380
399
|
}
|
|
@@ -626,7 +645,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
626
645
|
}
|
|
627
646
|
}
|
|
628
647
|
async setDiscountSelected(params) {
|
|
629
|
-
var _a, _b, _c;
|
|
648
|
+
var _a, _b, _c, _d, _e;
|
|
630
649
|
this.logMethodStart("setDiscountSelected", params);
|
|
631
650
|
try {
|
|
632
651
|
if (!this.store.order)
|
|
@@ -691,11 +710,18 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
691
710
|
(sum, pd) => sum + (pd.amount || 0),
|
|
692
711
|
0
|
|
693
712
|
);
|
|
694
|
-
const
|
|
695
|
-
product.
|
|
713
|
+
const optionSum = (0, import_utils2.sumOptionUnitPrice)(product.product_option_item);
|
|
714
|
+
const sourcePrice = ((_d = product.metadata) == null ? void 0 : _d.source_product_price) ?? (((_e = product.metadata) == null ? void 0 : _e.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
|
|
715
|
+
const newSourceSellingPrice = new import_decimal.default(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
|
|
716
|
+
const newMainSellingPrice = new import_decimal.default(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
696
717
|
if (product.metadata) {
|
|
697
|
-
product.metadata.main_product_selling_price =
|
|
718
|
+
product.metadata.main_product_selling_price = newMainSellingPrice;
|
|
719
|
+
product.metadata.price_schema_version = 2;
|
|
698
720
|
}
|
|
721
|
+
product.selling_price = (0, import_utils2.composeLinePrice)({
|
|
722
|
+
mainPrice: newMainSellingPrice,
|
|
723
|
+
bundle: product.product_bundle
|
|
724
|
+
});
|
|
699
725
|
}
|
|
700
726
|
import_Order.OrderModule.populateSavedAmounts(tempOrder.products, nextDiscountList);
|
|
701
727
|
await (discountModule == null ? void 0 : discountModule.setDiscountList(nextDiscountList));
|
|
@@ -39,14 +39,39 @@ export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
|
|
|
39
39
|
order_detail_id: number | null;
|
|
40
40
|
num: number;
|
|
41
41
|
product_option_item: any[];
|
|
42
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* 券后 **行 composite 单价** = `metadata.main_product_selling_price`
|
|
44
|
+
* + Σ((bundle.bundle_selling_price ?? bundle.price) × (bundle.num ?? 1))
|
|
45
|
+
*
|
|
46
|
+
* 新语义 v2 下 `metadata.main_product_selling_price` 已经**含 option**、含主商品折扣,
|
|
47
|
+
* 因此本字段不再叠加 option。未应用券时等同 `original_price`。
|
|
48
|
+
* Rules 钩子、主商品计税、Summary 统一读 metadata,不以此字段反推。
|
|
49
|
+
*/
|
|
43
50
|
selling_price: string;
|
|
44
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* 券前 **行 composite 单价** = `metadata.main_product_original_price`
|
|
53
|
+
* + Σ(bundle 原价 × num)
|
|
54
|
+
*
|
|
55
|
+
* 新语义 v2 下 `metadata.main_product_original_price` 已经**含 option**、不含折扣。
|
|
56
|
+
* 不承载后台划线价语义。
|
|
57
|
+
*/
|
|
45
58
|
original_price: string;
|
|
46
59
|
tax_fee: string;
|
|
47
60
|
is_charge_tax: number;
|
|
48
61
|
discount_list: any[];
|
|
49
62
|
product_bundle: any[];
|
|
63
|
+
/**
|
|
64
|
+
* 行级扩展 metadata。价格相关的权威字段:
|
|
65
|
+
*
|
|
66
|
+
* - `source_product_price`:主商品/variant 基础价(已应用报价单),**不含 option、不含折扣**。
|
|
67
|
+
* 是派生 `main_product_*` 的唯一源。variant 分支优先读 `metadata.origin.variant[vid].price`。
|
|
68
|
+
* - `main_product_original_price` = `source_product_price + Σ(option.price × option.num)`,
|
|
69
|
+
* **含 option、不含折扣**。
|
|
70
|
+
* - `main_product_selling_price` = `main_product_original_price − 主商品券 per-unit amount`,
|
|
71
|
+
* **含 option、含主商品折扣**。Rules 钩子 / Summary / 计税均以此为主商品权威源。
|
|
72
|
+
* - `price_schema_version`(当前 = 2):schema 版本 sentinel,用于跨端协商价格口径、
|
|
73
|
+
* 区分 v1 旧缓存以便 `normalizeOrderProduct` 触发迁移。
|
|
74
|
+
*/
|
|
50
75
|
metadata: Record<string, any>;
|
|
51
76
|
/** 商品行备注(如顾客对单品的特殊要求) */
|
|
52
77
|
note?: string;
|
|
@@ -68,6 +93,8 @@ export interface ScanOrderSubmitProduct extends Omit<ScanOrderOrderProduct, '_or
|
|
|
68
93
|
/**
|
|
69
94
|
* 出站兼容字段:SDK 内部不再消费 payment_price,
|
|
70
95
|
* 仅在提交后端时由 selling_price 派生,保持原有后端契约。
|
|
96
|
+
* 新语义 v2 下 selling_price 是 composite(含 option、含 bundle、含主商品折扣),
|
|
97
|
+
* 因此 payment_price 同样是 composite。
|
|
71
98
|
*/
|
|
72
99
|
payment_price: string;
|
|
73
100
|
}
|
|
@@ -108,10 +108,26 @@ export declare function isIdentityMatch(a: ScanOrderOrderProductIdentity, b: Sca
|
|
|
108
108
|
*/
|
|
109
109
|
export declare function getProductIdentityIndex(products: ScanOrderOrderProduct[], identity: ScanOrderOrderProductIdentity): number;
|
|
110
110
|
/**
|
|
111
|
-
*
|
|
111
|
+
* 对外部传入的商品对象做归一化(v2 composite 语义):
|
|
112
112
|
* - 补全可选字段默认值(未传则使用兜底值,避免后续计算时因 undefined 导致异常)
|
|
113
113
|
* - 对 num 调用 getSafeProductNum 做安全处理
|
|
114
114
|
* - 保留 _origin 供后续业务流程(如促销规则)使用
|
|
115
|
+
*
|
|
116
|
+
* 价格字段语义(metadata 权威源 + composite 派生):
|
|
117
|
+
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),**不含 option**、
|
|
118
|
+
* **不含折扣**。是推导 main_product_* 的起点。variant 分支优先读 `metadata.origin.variant[vid].price`。
|
|
119
|
+
* - `metadata.main_product_original_price`:`source + Σ(option.price × option.num)`,**含 option**、
|
|
120
|
+
* **不含折扣**。
|
|
121
|
+
* - `metadata.main_product_selling_price`:`main_product_original_price - 主商品券 per-unit amount`,
|
|
122
|
+
* **含 option**、**含折扣**。
|
|
123
|
+
* - 行级 `selling_price` = `main_product_selling_price + Σ(bundle_selling_price × num)`。
|
|
124
|
+
* - 行级 `original_price` = `main_product_original_price + Σ(bundle 原价 × num)`。
|
|
125
|
+
*
|
|
126
|
+
* 迁移与幂等:
|
|
127
|
+
* - `metadata.price_schema_version === 2` → 已新语义归一化,保留 main_product_* 原值(保留折扣)。
|
|
128
|
+
* - 其它情况(v1 / 缺字段 / 无 metadata)→ 按"main_product_selling_price 曾是 main-only"的旧约定
|
|
129
|
+
* 反推 legacyDiscount,再以新 source + options 基准重算。最终统一打上 `price_schema_version: 2`。
|
|
130
|
+
* - 因此多次 normalize 不会重复叠加 option/bundle。
|
|
115
131
|
*/
|
|
116
132
|
export declare function normalizeOrderProduct(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): ScanOrderOrderProduct;
|
|
117
133
|
/**
|
|
@@ -127,7 +143,7 @@ export declare function hasCustomCapacityProduct(products: ProductData[]): boole
|
|
|
127
143
|
/**
|
|
128
144
|
* 根据预约规则商品的 resource.type 计算桌台是否已被"占满"。
|
|
129
145
|
* - single:只要有 `lastOrderId` 即视为占用
|
|
130
|
-
* - multiple:当前时间落在 `capacity_list[i]` 的 `[start_at, end_at]`(inclusive)内的 pax 之和
|
|
146
|
+
* - multiple:当前时间落在 `capacity_list[i]` 的 `[start_at, end_at]`(inclusive)内的 pax 之和 >= 总容量
|
|
131
147
|
* - 其他('capacity' / undefined):返回 false,不施加限制
|
|
132
148
|
*/
|
|
133
149
|
export declare function computeResourceIsFull(params: {
|