@pisell/pisellos 2.1.130 → 2.1.131
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 +9 -0
- package/dist/modules/Order/index.d.ts +3 -6
- package/dist/modules/Order/index.js +119 -41
- package/dist/modules/Order/types.d.ts +23 -5
- package/dist/modules/Order/types.js +2 -0
- package/dist/modules/Order/utils.d.ts +66 -11
- package/dist/modules/Order/utils.js +281 -45
- package/dist/modules/SalesSummary/utils.js +33 -68
- package/dist/modules/ScanOrderLogger/providers/feishu.js +168 -60
- package/dist/modules/ScanOrderLogger/types.d.ts +6 -0
- package/dist/modules/Summary/utils.js +6 -21
- package/dist/solution/ScanOrder/index.d.ts +31 -6
- package/dist/solution/ScanOrder/index.js +1062 -498
- package/dist/solution/ScanOrder/types.d.ts +52 -2
- package/dist/solution/ScanOrder/types.js +16 -1
- package/dist/solution/ScanOrder/utils.d.ts +41 -5
- package/dist/solution/ScanOrder/utils.js +214 -33
- package/dist/solution/VenueBooking/index.d.ts +2 -5
- package/dist/solution/VenueBooking/index.js +35 -27
- package/lib/modules/Order/index.d.ts +3 -6
- package/lib/modules/Order/index.js +109 -30
- package/lib/modules/Order/types.d.ts +23 -5
- package/lib/modules/Order/utils.d.ts +66 -11
- package/lib/modules/Order/utils.js +181 -16
- package/lib/modules/SalesSummary/utils.js +13 -47
- package/lib/modules/ScanOrderLogger/providers/feishu.js +100 -34
- package/lib/modules/ScanOrderLogger/types.d.ts +6 -0
- package/lib/modules/Summary/utils.js +4 -18
- package/lib/solution/ScanOrder/index.d.ts +31 -6
- package/lib/solution/ScanOrder/index.js +315 -14
- package/lib/solution/ScanOrder/types.d.ts +52 -2
- package/lib/solution/ScanOrder/utils.d.ts +41 -5
- package/lib/solution/ScanOrder/utils.js +150 -20
- package/lib/solution/VenueBooking/index.d.ts +2 -5
- package/lib/solution/VenueBooking/index.js +13 -6
- package/package.json +1 -1
|
@@ -30,10 +30,12 @@ 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,
|
|
36
37
|
createUuidV4: () => createUuidV4,
|
|
38
|
+
filterProductsForScanOrderMore: () => filterProductsForScanOrderMore,
|
|
37
39
|
formatDateTime: () => formatDateTime,
|
|
38
40
|
formatV1Product: () => formatV1Product,
|
|
39
41
|
generateDuration: () => generateDuration,
|
|
@@ -42,13 +44,39 @@ __export(utils_exports, {
|
|
|
42
44
|
mergeRelationForms: () => mergeRelationForms,
|
|
43
45
|
normalizeSubmitBooking: () => normalizeSubmitBooking,
|
|
44
46
|
normalizeSubmitCollectPaxValue: () => normalizeSubmitCollectPaxValue,
|
|
45
|
-
resolveSubmitCollectPax: () => resolveSubmitCollectPax
|
|
47
|
+
resolveSubmitCollectPax: () => resolveSubmitCollectPax,
|
|
48
|
+
sumOptionUnitPrice: () => sumOptionUnitPrice
|
|
46
49
|
});
|
|
47
50
|
module.exports = __toCommonJS(utils_exports);
|
|
48
51
|
var import_dayjs = __toESM(require("dayjs"));
|
|
49
52
|
var import_decimal = __toESM(require("decimal.js"));
|
|
50
53
|
var import_utils = require("../../solution/ScanOrder/utils");
|
|
51
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
|
+
}
|
|
52
80
|
function createDefaultOrderRulesHooks() {
|
|
53
81
|
const toUnitPriceString = (totalLike, num) => {
|
|
54
82
|
const effectiveNum = Number(num) > 0 ? Number(num) : 1;
|
|
@@ -57,13 +85,47 @@ function createDefaultOrderRulesHooks() {
|
|
|
57
85
|
return {
|
|
58
86
|
getProduct: (product) => {
|
|
59
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
|
+
}
|
|
60
110
|
return {
|
|
61
111
|
id: product.product_id,
|
|
62
|
-
_id
|
|
63
|
-
|
|
112
|
+
// Rules 引擎用 _id 作为 processedProductsMap 键;必须与购物车行级 identity 一致,
|
|
113
|
+
// 否则同 SKU 不同小料会在 calcDiscount 重组时互相覆盖。
|
|
114
|
+
// 不透明 identity 契约下,normalizeOrderProduct / restoreTempOrderFromStorage 已保证 identity_key 必存在;
|
|
115
|
+
// 留 fingerprint 分支仅作 Rules 单测里直接传裸 product 时的兜底。
|
|
116
|
+
_id: product.identity_key ? `${product.product_id}_${product.product_variant_id}_${product.identity_key}` : `${product.product_id}_${product.product_variant_id}_${(0, import_utils.buildProductLineFingerprint)(
|
|
117
|
+
product.product_option_item,
|
|
118
|
+
product.product_bundle
|
|
119
|
+
)}`,
|
|
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)。
|
|
64
124
|
total: new import_decimal.default(product.selling_price || 0).times(product.num || 1).toNumber(),
|
|
65
|
-
origin_total: new import_decimal.default(
|
|
66
|
-
|
|
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,
|
|
67
129
|
quantity: product.num || 1,
|
|
68
130
|
num: product.num || 1,
|
|
69
131
|
discount_list: product.discount_list || [],
|
|
@@ -77,17 +139,37 @@ function createDefaultOrderRulesHooks() {
|
|
|
77
139
|
},
|
|
78
140
|
setProduct: (product, values) => {
|
|
79
141
|
const nextNum = Number(values.quantity ?? product.num ?? 1) || 1;
|
|
80
|
-
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
|
+
});
|
|
81
160
|
return {
|
|
82
161
|
...product,
|
|
83
|
-
selling_price:
|
|
84
|
-
original_price:
|
|
162
|
+
selling_price: composedSellingPrice,
|
|
163
|
+
original_price: composedOriginalPrice,
|
|
85
164
|
discount_list: values.discount_list ?? product.discount_list,
|
|
86
165
|
num: values.quantity ?? product.num,
|
|
87
|
-
product_bundle:
|
|
166
|
+
product_bundle: nextBundle,
|
|
88
167
|
metadata: {
|
|
89
|
-
...
|
|
90
|
-
|
|
168
|
+
...metadataAny,
|
|
169
|
+
source_product_price: nextSourceSellingPrice,
|
|
170
|
+
main_product_selling_price: nextMainSellingPrice,
|
|
171
|
+
main_product_original_price: nextMainOriginalPrice,
|
|
172
|
+
price_schema_version: 2
|
|
91
173
|
}
|
|
92
174
|
};
|
|
93
175
|
}
|
|
@@ -151,6 +233,77 @@ function formatDateTime(date) {
|
|
|
151
233
|
function normalizeSubmitPlatform(platform) {
|
|
152
234
|
return (platform == null ? void 0 : platform.toLowerCase()) === "pc" ? "PC" : "H5";
|
|
153
235
|
}
|
|
236
|
+
function formatSubmitOptionItems(options) {
|
|
237
|
+
if (!Array.isArray(options))
|
|
238
|
+
return [];
|
|
239
|
+
return options.map((d) => ({
|
|
240
|
+
num: d == null ? void 0 : d.num,
|
|
241
|
+
option_group_item_id: (d == null ? void 0 : d.option_group_item_id) ?? (d == null ? void 0 : d.product_option_item_id),
|
|
242
|
+
option_group_id: d == null ? void 0 : d.option_group_id
|
|
243
|
+
}));
|
|
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
|
+
}
|
|
257
|
+
function formatSubmitBundleItems(bundle) {
|
|
258
|
+
if (!Array.isArray(bundle))
|
|
259
|
+
return [];
|
|
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
|
+
});
|
|
306
|
+
}
|
|
154
307
|
function normalizeSubmitProduct(product) {
|
|
155
308
|
const { _origin, identity_key, ...submitProduct } = product;
|
|
156
309
|
const rawMetadata = submitProduct.metadata || {};
|
|
@@ -162,7 +315,8 @@ function normalizeSubmitProduct(product) {
|
|
|
162
315
|
const priceMetaKeys = [
|
|
163
316
|
"main_product_original_price",
|
|
164
317
|
"main_product_selling_price",
|
|
165
|
-
"source_product_price"
|
|
318
|
+
"source_product_price",
|
|
319
|
+
"price_schema_version"
|
|
166
320
|
];
|
|
167
321
|
for (const key of priceMetaKeys) {
|
|
168
322
|
if (rawMetadata[key] !== void 0) {
|
|
@@ -178,11 +332,12 @@ function normalizeSubmitProduct(product) {
|
|
|
178
332
|
return {
|
|
179
333
|
...submitProduct,
|
|
180
334
|
...bookingUid ? { booking_uid: bookingUid } : {},
|
|
181
|
-
product_option_item: submitProduct.product_option_item
|
|
335
|
+
product_option_item: formatSubmitOptionItems(submitProduct.product_option_item),
|
|
182
336
|
discount_list: submitProduct.discount_list || [],
|
|
183
|
-
product_bundle: submitProduct.product_bundle
|
|
337
|
+
product_bundle: formatSubmitBundleItems(submitProduct.product_bundle),
|
|
184
338
|
metadata: cleanMetadata,
|
|
185
|
-
//
|
|
339
|
+
// 出站兼容:后端消费 payment_price 字段,这里从 selling_price 直接派生。
|
|
340
|
+
// 新语义下 selling_price 是 composite(含 option/bundle),payment_price 同语义。
|
|
186
341
|
payment_price: submitProduct.selling_price
|
|
187
342
|
};
|
|
188
343
|
}
|
|
@@ -366,6 +521,12 @@ function buildSubmitPayload(params) {
|
|
|
366
521
|
};
|
|
367
522
|
return enhance ? enhance(payload, { tempOrder, bookingUuid, now }) : payload;
|
|
368
523
|
}
|
|
524
|
+
function filterProductsForScanOrderMore(products) {
|
|
525
|
+
return (products || []).filter((p) => {
|
|
526
|
+
var _a;
|
|
527
|
+
return ((_a = p.metadata) == null ? void 0 : _a.is_rule) !== true;
|
|
528
|
+
});
|
|
529
|
+
}
|
|
369
530
|
function formatV1Product(products) {
|
|
370
531
|
return products.map((product) => {
|
|
371
532
|
return {
|
|
@@ -375,6 +536,7 @@ function formatV1Product(products) {
|
|
|
375
536
|
product_id: product.product_id,
|
|
376
537
|
product_variant_id: product.product_variant_id,
|
|
377
538
|
num: product.num,
|
|
539
|
+
note: String(product.note ?? ""),
|
|
378
540
|
rowKey: product.product_id,
|
|
379
541
|
session: null,
|
|
380
542
|
unique: createUuidV4()
|
|
@@ -384,10 +546,12 @@ function formatV1Product(products) {
|
|
|
384
546
|
// Annotate the CommonJS export names for ESM import in node:
|
|
385
547
|
0 && (module.exports = {
|
|
386
548
|
buildSubmitPayload,
|
|
549
|
+
composeLinePrice,
|
|
387
550
|
createDefaultOrderRulesHooks,
|
|
388
551
|
createDefaultTempOrder,
|
|
389
552
|
createEmptySummary,
|
|
390
553
|
createUuidV4,
|
|
554
|
+
filterProductsForScanOrderMore,
|
|
391
555
|
formatDateTime,
|
|
392
556
|
formatV1Product,
|
|
393
557
|
generateDuration,
|
|
@@ -396,5 +560,6 @@ function formatV1Product(products) {
|
|
|
396
560
|
mergeRelationForms,
|
|
397
561
|
normalizeSubmitBooking,
|
|
398
562
|
normalizeSubmitCollectPaxValue,
|
|
399
|
-
resolveSubmitCollectPax
|
|
563
|
+
resolveSubmitCollectPax,
|
|
564
|
+
sumOptionUnitPrice
|
|
400
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,18 +204,9 @@ 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)) {
|
|
@@ -22,58 +22,124 @@ __export(feishu_exports, {
|
|
|
22
22
|
feishuLoggerProvider: () => feishuLoggerProvider
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(feishu_exports);
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
var DEFAULT_THROTTLE_MS = 3e3;
|
|
26
|
+
var pendingQueue = [];
|
|
27
|
+
var flushTimer = null;
|
|
28
|
+
var cachedProviderConfig;
|
|
29
|
+
function safeStringify(value) {
|
|
30
|
+
if (value === void 0 || value === null)
|
|
27
31
|
return "";
|
|
32
|
+
if (typeof value === "string")
|
|
33
|
+
return value;
|
|
34
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
35
|
+
return String(value);
|
|
36
|
+
}
|
|
28
37
|
try {
|
|
29
|
-
return JSON.stringify(
|
|
38
|
+
return JSON.stringify(value);
|
|
30
39
|
} catch (error) {
|
|
31
40
|
return `[unserializable: ${String(error)}]`;
|
|
32
41
|
}
|
|
33
42
|
}
|
|
34
|
-
function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
function isWebhookUsable(webhook) {
|
|
44
|
+
if (!webhook)
|
|
45
|
+
return false;
|
|
46
|
+
if (webhook.includes("REPLACE_ME"))
|
|
47
|
+
return false;
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
function buildRecordSegments(record) {
|
|
51
|
+
const context = record.context || {};
|
|
52
|
+
return [
|
|
53
|
+
[{ tag: "text", text: `[${record.level}] ${record.timestamp} ${record.title}
|
|
54
|
+
` }],
|
|
55
|
+
[{ tag: "text", text: `缓存标识: ${safeStringify(context.cacheId)}
|
|
56
|
+
` }],
|
|
57
|
+
[{ tag: "text", text: `日志来源: ${safeStringify(context)}
|
|
58
|
+
` }],
|
|
59
|
+
[{ tag: "text", text: `日志内容: ${safeStringify(record.payload)}
|
|
60
|
+
` }],
|
|
61
|
+
[{ tag: "text", text: `扩展信息: ${safeStringify(record.extra)}
|
|
62
|
+
` }],
|
|
63
|
+
[{ tag: "text", text: "------\n" }]
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
function buildFeishuBody(records) {
|
|
67
|
+
const title = records.length === 1 ? records[0].title : `ScanOrder 日志批量 (${records.length} 条)`;
|
|
68
|
+
const content = [];
|
|
69
|
+
records.forEach((record) => {
|
|
70
|
+
buildRecordSegments(record).forEach((segment) => content.push(segment));
|
|
71
|
+
});
|
|
72
|
+
return JSON.stringify({
|
|
73
|
+
msg_type: "post",
|
|
74
|
+
content: JSON.stringify({
|
|
75
|
+
post: {
|
|
76
|
+
zh_cn: {
|
|
77
|
+
title,
|
|
78
|
+
content
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async function postToFeishu(webhook, body) {
|
|
85
|
+
await fetch(webhook, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: {
|
|
88
|
+
"Content-Type": "application/json"
|
|
89
|
+
},
|
|
90
|
+
body
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
async function flushQueue() {
|
|
94
|
+
var _a;
|
|
95
|
+
flushTimer = null;
|
|
96
|
+
if (!pendingQueue.length)
|
|
97
|
+
return;
|
|
98
|
+
const records = pendingQueue.splice(0, pendingQueue.length);
|
|
99
|
+
const webhook = (_a = cachedProviderConfig == null ? void 0 : cachedProviderConfig.feishu) == null ? void 0 : _a.webhook;
|
|
100
|
+
if (!isWebhookUsable(webhook)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (typeof fetch !== "function") {
|
|
104
|
+
console.warn("[ScanOrderLogger] 当前环境不支持 fetch,跳过 Feishu 日志批量上报");
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
await postToFeishu(webhook, buildFeishuBody(records));
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.warn("[ScanOrderLogger] Feishu 批量上报失败", error);
|
|
111
|
+
}
|
|
41
112
|
}
|
|
42
113
|
var feishuLoggerProvider = {
|
|
43
114
|
async send(payload) {
|
|
44
|
-
var _a, _b;
|
|
115
|
+
var _a, _b, _c, _d;
|
|
116
|
+
cachedProviderConfig = payload.providerConfig;
|
|
45
117
|
const webhook = (_b = (_a = payload.providerConfig) == null ? void 0 : _a.feishu) == null ? void 0 : _b.webhook;
|
|
46
|
-
if (webhook && webhook.includes("REPLACE_ME"))
|
|
47
|
-
return;
|
|
48
118
|
if (!webhook) {
|
|
49
119
|
console.warn("[ScanOrderLogger] Feishu webhook 未配置,跳过日志上报");
|
|
50
120
|
return;
|
|
51
121
|
}
|
|
122
|
+
if (!isWebhookUsable(webhook))
|
|
123
|
+
return;
|
|
52
124
|
if (typeof fetch !== "function") {
|
|
53
125
|
console.warn("[ScanOrderLogger] 当前环境不支持 fetch,跳过 Feishu 日志上报");
|
|
54
126
|
return;
|
|
55
127
|
}
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
method: "POST",
|
|
72
|
-
body: JSON.stringify({
|
|
73
|
-
msg_type: "post",
|
|
74
|
-
content: `{"post":{"zh_cn":{"title":"${record.title}","content":${contentStr}}}}`
|
|
75
|
-
})
|
|
76
|
-
});
|
|
128
|
+
const throttleMs = ((_d = (_c = payload.providerConfig) == null ? void 0 : _c.feishu) == null ? void 0 : _d.throttleMs) ?? DEFAULT_THROTTLE_MS;
|
|
129
|
+
if (throttleMs <= 0) {
|
|
130
|
+
try {
|
|
131
|
+
await postToFeishu(webhook, buildFeishuBody([payload.record]));
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.warn("[ScanOrderLogger] Feishu 日志上报失败", error);
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
pendingQueue.push(payload.record);
|
|
138
|
+
if (!flushTimer) {
|
|
139
|
+
flushTimer = setTimeout(() => {
|
|
140
|
+
void flushQueue();
|
|
141
|
+
}, throttleMs);
|
|
142
|
+
}
|
|
77
143
|
}
|
|
78
144
|
};
|
|
79
145
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -2,6 +2,12 @@ export type ScanOrderLogLevel = 'info' | 'warning' | 'error' | 'debug';
|
|
|
2
2
|
export type ScanOrderLoggerProviderType = 'feishu' | 'grafana';
|
|
3
3
|
export interface ScanOrderLoggerProviderFeishuConfig {
|
|
4
4
|
webhook?: string;
|
|
5
|
+
/**
|
|
6
|
+
* 节流窗口毫秒数,默认 3000ms
|
|
7
|
+
* - >0:首条日志进入队列并启动定时器,窗口结束后合并成一条 Feishu post 统一发送
|
|
8
|
+
* - <=0:关闭节流,保持每条日志立即单独发送
|
|
9
|
+
*/
|
|
10
|
+
throttleMs?: number;
|
|
5
11
|
}
|
|
6
12
|
export interface ScanOrderLoggerProviderGrafanaConfig {
|
|
7
13
|
endpoint?: string;
|
|
@@ -423,25 +423,11 @@ var getBundleItemIsDiscountPrice = (item) => {
|
|
|
423
423
|
var getBundleItemIsMarkupOrDiscountPrice = (item) => {
|
|
424
424
|
return getBundleItemIsMarkupPrice(item) || getBundleItemIsDiscountPrice(item);
|
|
425
425
|
};
|
|
426
|
-
var getDiscountAmount = (discounts) => {
|
|
427
|
-
return (discounts || []).reduce((total, discount) => {
|
|
428
|
-
return total.add(new import_decimal.default(discount.amount || 0));
|
|
429
|
-
}, new import_decimal.default(0)).toNumber();
|
|
430
|
-
};
|
|
431
426
|
var getMainProductTotal = (item) => {
|
|
432
|
-
var _a, _b
|
|
433
|
-
let total = new import_decimal.default(
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
return !((_a2 = item2 == null ? void 0 : item2.metadata) == null ? void 0 : _a2.custom_product_bundle_map_id);
|
|
437
|
-
})) || [];
|
|
438
|
-
const mainProductDiscountAmount = getDiscountAmount(discount);
|
|
439
|
-
total = total.minus(mainProductDiscountAmount);
|
|
440
|
-
if ((item == null ? void 0 : item.option) && Array.isArray(item == null ? void 0 : item.option)) {
|
|
441
|
-
total = total.add(item == null ? void 0 : item.option.reduce((t, option) => {
|
|
442
|
-
return t.add(new import_decimal.default(option.price || 0).mul(option.num || 1));
|
|
443
|
-
}, new import_decimal.default(0)));
|
|
444
|
-
}
|
|
427
|
+
var _a, _b;
|
|
428
|
+
let total = new import_decimal.default(
|
|
429
|
+
(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
|
|
430
|
+
);
|
|
445
431
|
for (let bundleItem of (item == null ? void 0 : item.bundle) || []) {
|
|
446
432
|
if (getBundleItemIsMarkupOrDiscountPrice(bundleItem)) {
|
|
447
433
|
const bundleItemTotal = new import_decimal.default(bundleItem.bundle_selling_price ?? bundleItem.price ?? 0);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Module, ModuleOptions, PisellCore } from '../../types';
|
|
2
2
|
import { BaseModule } from '../../modules/BaseModule';
|
|
3
|
-
import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity } from './types';
|
|
3
|
+
import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderScanCodeResult } from './types';
|
|
4
|
+
import type { UpdateProductInOrderParams } from '../../modules/Order/types';
|
|
5
|
+
import type { Discount } from '../../modules/Discount/types';
|
|
4
6
|
import { type CartItemSummary, type PaxInfo, type QuantityCheckResult, type QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
|
|
5
7
|
import type { StrategyConfig } from '../../model/strategy/type';
|
|
6
8
|
export * from './types';
|
|
@@ -29,6 +31,10 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
29
31
|
private itemRuleRuntimeConfig;
|
|
30
32
|
/** 最近一次 checkResourceAvailable 从预约规则 link 拉取的商品快照 */
|
|
31
33
|
private enabledReservationRuleProducts;
|
|
34
|
+
private loginEffectDisposers;
|
|
35
|
+
private customerLoginRefreshInFlight;
|
|
36
|
+
private customerLoginRefreshIdInFlight;
|
|
37
|
+
private static readonly PISELL1_LOGIN_SUCCESS;
|
|
32
38
|
private getScanOrderLoggerContext;
|
|
33
39
|
private serializeError;
|
|
34
40
|
private addScanOrderLog;
|
|
@@ -36,7 +42,16 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
36
42
|
private logMethodSuccess;
|
|
37
43
|
private logMethodError;
|
|
38
44
|
addLog(params: ScanOrderAddLogParams): Promise<void>;
|
|
45
|
+
private normalizeCustomerId;
|
|
46
|
+
private resolveCustomerIdFromLoginPayload;
|
|
47
|
+
private clearLoginEffectListeners;
|
|
48
|
+
private registerLoginEffect;
|
|
49
|
+
private registerCustomerLoginListeners;
|
|
50
|
+
private refreshOrderMarketingAfterLogin;
|
|
39
51
|
constructor(name?: string, version?: string);
|
|
52
|
+
/** 与 `otherParams.cacheId` 一致,供宿主在 URL 变化时判断是否需要重新注册模块 */
|
|
53
|
+
getCacheId(): string | undefined;
|
|
54
|
+
private destroyRegisteredChildModules;
|
|
40
55
|
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
41
56
|
destroy(): Promise<void>;
|
|
42
57
|
retryInit(): Promise<void>;
|
|
@@ -62,14 +77,24 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
62
77
|
restoreOrder(): Promise<import("./types").ScanOrderTempOrder>;
|
|
63
78
|
getOrderProducts(): ScanOrderOrderProduct[];
|
|
64
79
|
getSummary(): Promise<import("./types").ScanOrderSummary>;
|
|
80
|
+
getDiscountList(): Discount[];
|
|
81
|
+
scanCode(code: string, customerId?: number): Promise<ScanOrderScanCodeResult>;
|
|
82
|
+
setDiscountSelected(params: {
|
|
83
|
+
discountId: number;
|
|
84
|
+
isSelected: boolean;
|
|
85
|
+
}): Promise<void>;
|
|
86
|
+
onCustomerLogin(params: {
|
|
87
|
+
customerId: number;
|
|
88
|
+
}): Promise<void>;
|
|
65
89
|
private buildSubmitPayloadEnhancer;
|
|
66
90
|
submitScanOrder<T = any>(): Promise<T>;
|
|
67
91
|
addProductToOrder(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
|
|
68
|
-
updateProductInOrder(params:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
92
|
+
updateProductInOrder(params: UpdateProductInOrderParams): Promise<ScanOrderOrderProduct[]>;
|
|
93
|
+
/**
|
|
94
|
+
* 设置单行商品备注(与整单 `updateTempOrderNote` 区分)。
|
|
95
|
+
* 多行同 SKU 时必须传入与删除/更新一致的 identity(如 `identity_key`)。
|
|
96
|
+
*/
|
|
97
|
+
setOrderProductLineNote(identity: ScanOrderOrderProductIdentity, note: string): Promise<ScanOrderOrderProduct[]>;
|
|
73
98
|
removeProductFromOrder(identity: ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
|
|
74
99
|
private loadRuntimeConfigs;
|
|
75
100
|
private syncItemRuleConfigsFromDineInConfig;
|