@pisell/pisellos 2.3.55 → 2.3.56
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/BookingContext/utils/productExtend.js +5 -9
- package/dist/modules/BookingContext/utils/timeSlices.js +24 -3
- package/dist/modules/Order/index.d.ts +8 -2
- package/dist/modules/Order/index.js +636 -645
- package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
- package/dist/modules/Order/utils/discountProductLineIdentity.js +227 -0
- package/dist/modules/Rules/index.js +46 -5
- package/dist/solution/BaseSales/index.js +38 -24
- package/dist/solution/BaseSales/utils/cartPromotion.js +19 -1
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +1 -1
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +1 -4
- package/lib/model/strategy/adapter/promotion/index.js +0 -51
- package/lib/modules/BookingContext/utils/productExtend.js +4 -3
- package/lib/modules/BookingContext/utils/timeSlices.js +18 -3
- package/lib/modules/Order/index.d.ts +8 -2
- package/lib/modules/Order/index.js +161 -118
- package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
- package/lib/modules/Order/utils/discountProductLineIdentity.js +170 -0
- package/lib/modules/Rules/index.js +47 -3
- package/lib/solution/BaseSales/index.js +20 -5
- package/lib/solution/BaseSales/utils/cartPromotion.js +18 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +1 -1
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +1 -4
- package/package.json +1 -1
|
@@ -38,10 +38,21 @@ __export(timeSlices_exports, {
|
|
|
38
38
|
module.exports = __toCommonJS(timeSlices_exports);
|
|
39
39
|
var import_dayjs = __toESM(require("dayjs"));
|
|
40
40
|
var import_flexible = require("./flexible");
|
|
41
|
+
var timeSlicesCache = /* @__PURE__ */ new Map();
|
|
42
|
+
function copyTimeSlices(result) {
|
|
43
|
+
return {
|
|
44
|
+
timeSlices: [...result.timeSlices],
|
|
45
|
+
durationSlicesBasedOnTime: [...result.durationSlicesBasedOnTime]
|
|
46
|
+
};
|
|
47
|
+
}
|
|
41
48
|
function sliceDayIntoFiveMinutes(config, isDay) {
|
|
49
|
+
const timeSlice = config && config.value || 5;
|
|
50
|
+
const cacheKey = isDay ? "days" : `minutes:${timeSlice}`;
|
|
51
|
+
const cached = timeSlicesCache.get(cacheKey);
|
|
52
|
+
if (cached)
|
|
53
|
+
return copyTimeSlices(cached);
|
|
42
54
|
const startTime = (0, import_dayjs.default)().startOf("day");
|
|
43
55
|
const endTime = (0, import_dayjs.default)().endOf("day");
|
|
44
|
-
const timeSlice = config && config.value || 5;
|
|
45
56
|
const timeSlices = [];
|
|
46
57
|
const durationSlicesBasedOnTime = [];
|
|
47
58
|
let currentTime = startTime;
|
|
@@ -58,7 +69,9 @@ function sliceDayIntoFiveMinutes(config, isDay) {
|
|
|
58
69
|
});
|
|
59
70
|
currentDay += 1;
|
|
60
71
|
}
|
|
61
|
-
|
|
72
|
+
const result2 = { timeSlices, durationSlicesBasedOnTime };
|
|
73
|
+
timeSlicesCache.set(cacheKey, result2);
|
|
74
|
+
return copyTimeSlices(result2);
|
|
62
75
|
}
|
|
63
76
|
while (currentTime.isBefore(endTime)) {
|
|
64
77
|
timeSlices.push({
|
|
@@ -73,7 +86,9 @@ function sliceDayIntoFiveMinutes(config, isDay) {
|
|
|
73
86
|
});
|
|
74
87
|
currentTime = nextTime;
|
|
75
88
|
}
|
|
76
|
-
|
|
89
|
+
const result = { timeSlices, durationSlicesBasedOnTime };
|
|
90
|
+
timeSlicesCache.set(cacheKey, result);
|
|
91
|
+
return copyTimeSlices(result);
|
|
77
92
|
}
|
|
78
93
|
function findNextDuration(current, array, defaultValue) {
|
|
79
94
|
if (defaultValue !== void 0 && defaultValue !== null)
|
|
@@ -354,6 +354,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
354
354
|
updateVoucherOrderPaymentsAsync(payments: OrderPaymentSource[], options?: {
|
|
355
355
|
status?: 'paid' | 'payment_pending';
|
|
356
356
|
}): Promise<OrderPaymentData[]>;
|
|
357
|
+
private normalizeShouldMergeProductResult;
|
|
357
358
|
private shouldMergeProductToOrder;
|
|
358
359
|
private hasOrderProductLineNote;
|
|
359
360
|
/**
|
|
@@ -375,7 +376,12 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
375
376
|
* 带 booking 且 num>1 时由 `addProductToOrder` 拆成多次本方法调用(每次 num=1)。
|
|
376
377
|
*
|
|
377
378
|
* @example
|
|
378
|
-
*
|
|
379
|
+
* const pending = this.appendProductLineToTempOrder(
|
|
380
|
+
* tempOrder,
|
|
381
|
+
* { product_id: 1, num: 1 },
|
|
382
|
+
* booking,
|
|
383
|
+
* );
|
|
384
|
+
* if (pending) await pending;
|
|
379
385
|
*/
|
|
380
386
|
private appendProductLineToTempOrder;
|
|
381
387
|
/**
|
|
@@ -487,7 +493,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
487
493
|
generateIdempotencyToken(): string;
|
|
488
494
|
syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
|
|
489
495
|
createOrder(params: CommitOrderParams['query']): {
|
|
490
|
-
type: "
|
|
496
|
+
type: "appointment_booking" | "virtual";
|
|
491
497
|
platform: string;
|
|
492
498
|
sales_channel: string;
|
|
493
499
|
order_sales_channel: string;
|
|
@@ -44,6 +44,7 @@ var import_utils3 = require("../../solution/ScanOrder/utils");
|
|
|
44
44
|
var import_manualProductDiscount = require("./utils/manualProductDiscount");
|
|
45
45
|
var import_bundleDiscountHydration = require("./utils/bundleDiscountHydration");
|
|
46
46
|
var import_orderCollectionIdentity = require("./utils/orderCollectionIdentity");
|
|
47
|
+
var import_discountProductLineIdentity = require("./utils/discountProductLineIdentity");
|
|
47
48
|
var import_Discount = require("../Discount");
|
|
48
49
|
var import_Rules = require("../Rules");
|
|
49
50
|
var import_types2 = require("../Rules/types");
|
|
@@ -133,7 +134,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
133
134
|
this.draftPersistEnabled = true;
|
|
134
135
|
}
|
|
135
136
|
collectHydratedEditDiscounts(products) {
|
|
136
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
137
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
137
138
|
const discountMap = /* @__PURE__ */ new Map();
|
|
138
139
|
for (const product of (0, import_bundleDiscountHydration.expandHydratedProductsForDiscountCollection)(products)) {
|
|
139
140
|
for (const item of (product == null ? void 0 : product.discount_list) || []) {
|
|
@@ -148,16 +149,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
148
149
|
const key = Number.isFinite(id) ? id : String(resourceId);
|
|
149
150
|
const title = ((_b = item == null ? void 0 : item.discount) == null ? void 0 : _b.title) ?? {};
|
|
150
151
|
const amount = Number((item == null ? void 0 : item.amount) || 0);
|
|
152
|
+
const discountCardType = (_c = item == null ? void 0 : item.discount) == null ? void 0 : _c.discount_card_type;
|
|
153
|
+
const parValue = isDiscountCard ? discountCardType === "fixed_amount" ? ((_d = item == null ? void 0 : item.discount) == null ? void 0 : _d.fixed_amount) ?? (item == null ? void 0 : item.amount) : (_e = item == null ? void 0 : item.discount) == null ? void 0 : _e.percent : "0";
|
|
151
154
|
const detail = {
|
|
152
155
|
amount: String((item == null ? void 0 : item.amount) ?? "0"),
|
|
153
156
|
type,
|
|
154
157
|
resource_id: key,
|
|
155
158
|
title,
|
|
156
|
-
original_amount: String(((
|
|
157
|
-
num: Number(((
|
|
159
|
+
original_amount: String(((_f = item == null ? void 0 : item.discount) == null ? void 0 : _f.original_amount) ?? (item == null ? void 0 : item.amount) ?? "0"),
|
|
160
|
+
num: Number(((_g = item == null ? void 0 : item.metadata) == null ? void 0 : _g.num) ?? (product == null ? void 0 : product.num) ?? (product == null ? void 0 : product.product_quantity) ?? 1) || 1,
|
|
158
161
|
metadata: item == null ? void 0 : item.metadata,
|
|
159
162
|
discount: item == null ? void 0 : item.discount,
|
|
160
|
-
_num: Number(((
|
|
163
|
+
_num: Number(((_h = item == null ? void 0 : item.metadata) == null ? void 0 : _h.num) ?? (product == null ? void 0 : product.num) ?? (product == null ? void 0 : product.product_quantity) ?? 1) || 1
|
|
161
164
|
};
|
|
162
165
|
const existed = discountMap.get(key);
|
|
163
166
|
if (existed) {
|
|
@@ -166,7 +169,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
166
169
|
if (!isDiscountCard) {
|
|
167
170
|
existed.balance = String(Number(existed.balance || 0) + amount);
|
|
168
171
|
}
|
|
169
|
-
const productIds = Array.isArray((
|
|
172
|
+
const productIds = Array.isArray((_i = existed.limited_relation_product_data) == null ? void 0 : _i.product_ids) ? existed.limited_relation_product_data.product_ids : [];
|
|
170
173
|
if ((product == null ? void 0 : product.product_id) !== void 0 && (product == null ? void 0 : product.product_id) !== null && !productIds.includes(product.product_id)) {
|
|
171
174
|
existed.limited_relation_product_data = {
|
|
172
175
|
...existed.limited_relation_product_data || {},
|
|
@@ -189,9 +192,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
189
192
|
encoded: "",
|
|
190
193
|
code: "",
|
|
191
194
|
tag: type,
|
|
192
|
-
product_id: ((
|
|
195
|
+
product_id: ((_j = item == null ? void 0 : item.discount) == null ? void 0 : _j.discount_product_id) ?? (product == null ? void 0 : product.product_id) ?? 0,
|
|
193
196
|
relation_type: "",
|
|
194
|
-
par_value: String(
|
|
197
|
+
par_value: String(parValue ?? "0"),
|
|
195
198
|
used_par_value: String((item == null ? void 0 : item.amount) ?? "0"),
|
|
196
199
|
limit_status: "enable",
|
|
197
200
|
limited_relation_product_data: {
|
|
@@ -221,8 +224,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
221
224
|
discount: {
|
|
222
225
|
...(item == null ? void 0 : item.discount) || {},
|
|
223
226
|
resource_id: key,
|
|
224
|
-
discount_product_id: ((
|
|
225
|
-
discount_calculation_mode: ((
|
|
227
|
+
discount_product_id: ((_k = item == null ? void 0 : item.discount) == null ? void 0 : _k.discount_product_id) ?? (product == null ? void 0 : product.product_id) ?? 0,
|
|
228
|
+
discount_calculation_mode: ((_l = item == null ? void 0 : item.discount) == null ? void 0 : _l.discount_calculation_mode) ?? "item_level"
|
|
226
229
|
},
|
|
227
230
|
applicableProductDetails: [detail],
|
|
228
231
|
appliedProductDetails: [detail]
|
|
@@ -274,7 +277,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
274
277
|
const isPersistedBundleProduct = isPersistedProduct || Boolean(
|
|
275
278
|
(bundle == null ? void 0 : bundle.order_detail_id) || (bundle == null ? void 0 : bundle.orderDetailId) || (bundle == null ? void 0 : bundle.booking_id)
|
|
276
279
|
);
|
|
277
|
-
const bundleQty =
|
|
280
|
+
const bundleQty = Number(qty) || 1;
|
|
278
281
|
for (const pd of (bundle == null ? void 0 : bundle.discount_list) || []) {
|
|
279
282
|
addProductDiscountAmount(pd, bundleQty, isPersistedBundleProduct);
|
|
280
283
|
}
|
|
@@ -670,6 +673,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
670
673
|
};
|
|
671
674
|
})
|
|
672
675
|
);
|
|
676
|
+
(0, import_discountProductLineIdentity.ensureUniqueProductLineUids)(tempOrder);
|
|
677
|
+
(0, import_discountProductLineIdentity.consolidateDiscountFreeProductLines)(tempOrder);
|
|
673
678
|
}
|
|
674
679
|
if (result == null ? void 0 : result.discountList) {
|
|
675
680
|
OrderModule.populateSavedAmounts(
|
|
@@ -1878,6 +1883,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1878
1883
|
tempOrder.products = (tempOrder.products || []).map(
|
|
1879
1884
|
(product) => this.sanitizeOrderProductForTempOrder(product)
|
|
1880
1885
|
);
|
|
1886
|
+
(0, import_discountProductLineIdentity.ensureUniqueProductLineUids)(tempOrder);
|
|
1881
1887
|
}
|
|
1882
1888
|
ensureExtend(tempOrder) {
|
|
1883
1889
|
if (!tempOrder._extend || typeof tempOrder._extend !== "object") {
|
|
@@ -2533,6 +2539,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2533
2539
|
delete tempOrder._extend.customerSnapshot;
|
|
2534
2540
|
this.store.availableWalletIds = [];
|
|
2535
2541
|
this.clearCustomerBoundDiscounts(tempOrder);
|
|
2542
|
+
this.applyDiscount();
|
|
2536
2543
|
this.persistTempOrder();
|
|
2537
2544
|
this.saveDraftInBackground();
|
|
2538
2545
|
this.core.effects.emit(import_types.OrderHooks.OnOrderCustomerChange, null);
|
|
@@ -2838,21 +2845,29 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2838
2845
|
devicePrefix
|
|
2839
2846
|
});
|
|
2840
2847
|
}
|
|
2841
|
-
|
|
2848
|
+
normalizeShouldMergeProductResult(result) {
|
|
2849
|
+
if (typeof result === "boolean")
|
|
2850
|
+
return result;
|
|
2851
|
+
if (result && typeof result === "object" && typeof result.shouldMerge === "boolean") {
|
|
2852
|
+
return result.shouldMerge;
|
|
2853
|
+
}
|
|
2854
|
+
return true;
|
|
2855
|
+
}
|
|
2856
|
+
shouldMergeProductToOrder(params) {
|
|
2842
2857
|
var _a;
|
|
2843
2858
|
const onBeforeMergeProductToOrder = (_a = this.orderHooks) == null ? void 0 : _a.onBeforeMergeProductToOrder;
|
|
2844
2859
|
if (!onBeforeMergeProductToOrder)
|
|
2845
2860
|
return true;
|
|
2846
|
-
const result =
|
|
2861
|
+
const result = onBeforeMergeProductToOrder({
|
|
2847
2862
|
...params,
|
|
2848
2863
|
defaultShouldMerge: true
|
|
2849
2864
|
});
|
|
2850
|
-
if (typeof result === "
|
|
2851
|
-
return result
|
|
2852
|
-
|
|
2853
|
-
|
|
2865
|
+
if (result && typeof result === "object" && typeof result.then === "function") {
|
|
2866
|
+
return Promise.resolve(result).then(
|
|
2867
|
+
(resolved) => this.normalizeShouldMergeProductResult(resolved)
|
|
2868
|
+
);
|
|
2854
2869
|
}
|
|
2855
|
-
return
|
|
2870
|
+
return this.normalizeShouldMergeProductResult(result);
|
|
2856
2871
|
}
|
|
2857
2872
|
hasOrderProductLineNote(product) {
|
|
2858
2873
|
return typeof (product == null ? void 0 : product.note) === "string" && product.note.trim().length > 0;
|
|
@@ -2895,10 +2910,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2895
2910
|
* 带 booking 且 num>1 时由 `addProductToOrder` 拆成多次本方法调用(每次 num=1)。
|
|
2896
2911
|
*
|
|
2897
2912
|
* @example
|
|
2898
|
-
*
|
|
2913
|
+
* const pending = this.appendProductLineToTempOrder(
|
|
2914
|
+
* tempOrder,
|
|
2915
|
+
* { product_id: 1, num: 1 },
|
|
2916
|
+
* booking,
|
|
2917
|
+
* );
|
|
2918
|
+
* if (pending) await pending;
|
|
2899
2919
|
*/
|
|
2900
|
-
|
|
2901
|
-
var _a, _b, _c, _d, _e, _f
|
|
2920
|
+
appendProductLineToTempOrder(tempOrder, product, booking, options) {
|
|
2921
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2902
2922
|
const linked = booking ? this.createLinkedProductAndBooking({ product, booking }) : null;
|
|
2903
2923
|
const productToAdd = (linked == null ? void 0 : linked.product) || product;
|
|
2904
2924
|
const incomingFingerprint = (0, import_utils3.buildProductLineFingerprint)(
|
|
@@ -2957,7 +2977,107 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2957
2977
|
(0, import_utils.getProductSkuOptions)(matchedProduct),
|
|
2958
2978
|
matchedProduct.product_bundle
|
|
2959
2979
|
) : "";
|
|
2960
|
-
const
|
|
2980
|
+
const commitProductLine = (shouldMerge2) => {
|
|
2981
|
+
var _a2;
|
|
2982
|
+
if (matchedIndex === -1 || !matchedProduct || !shouldMerge2) {
|
|
2983
|
+
this.captureProductRuntime(
|
|
2984
|
+
tempOrder,
|
|
2985
|
+
productToAdd,
|
|
2986
|
+
normalizedIncoming
|
|
2987
|
+
);
|
|
2988
|
+
if (linked) {
|
|
2989
|
+
normalizedIncoming.booking_uid = linked.bookingUid;
|
|
2990
|
+
normalizedIncoming.metadata = {
|
|
2991
|
+
...normalizedIncoming.metadata || {},
|
|
2992
|
+
booking_uid: linked.bookingUid
|
|
2993
|
+
};
|
|
2994
|
+
}
|
|
2995
|
+
const insertAtIndex = options == null ? void 0 : options.insertAtIndex;
|
|
2996
|
+
if (Number.isInteger(insertAtIndex) && Number(insertAtIndex) >= 0 && Number(insertAtIndex) < tempOrder.products.length) {
|
|
2997
|
+
tempOrder.products = [
|
|
2998
|
+
...tempOrder.products.slice(0, insertAtIndex),
|
|
2999
|
+
normalizedIncoming,
|
|
3000
|
+
...tempOrder.products.slice(insertAtIndex)
|
|
3001
|
+
];
|
|
3002
|
+
} else {
|
|
3003
|
+
tempOrder.products = [...tempOrder.products, normalizedIncoming];
|
|
3004
|
+
}
|
|
3005
|
+
} else {
|
|
3006
|
+
const targetProduct = matchedProduct;
|
|
3007
|
+
const targetUid = (_a2 = targetProduct.metadata) == null ? void 0 : _a2.unique_identification_number;
|
|
3008
|
+
const normalizedProduct = (0, import_utils.mergeOrderProductDisplayFields)(
|
|
3009
|
+
targetProduct,
|
|
3010
|
+
(0, import_utils3.normalizeOrderProduct)({
|
|
3011
|
+
...productToAdd,
|
|
3012
|
+
metadata: {
|
|
3013
|
+
...productToAdd.metadata || {},
|
|
3014
|
+
unique_identification_number: targetUid
|
|
3015
|
+
}
|
|
3016
|
+
})
|
|
3017
|
+
);
|
|
3018
|
+
normalizedProduct.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
|
|
3019
|
+
normalizedProduct.discount_list
|
|
3020
|
+
);
|
|
3021
|
+
const nextNum = (0, import_utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num);
|
|
3022
|
+
const targetIsManualProductDiscount = isManualProductDiscountProduct(targetProduct);
|
|
3023
|
+
const nextDiscountList = targetIsManualProductDiscount ? (0, import_utils.normalizeOrderProductDiscountList)(
|
|
3024
|
+
(0, import_manualProductDiscount.syncManualProductDiscountProductNum)(
|
|
3025
|
+
targetProduct.discount_list,
|
|
3026
|
+
nextNum
|
|
3027
|
+
)
|
|
3028
|
+
) : normalizedProduct.discount_list;
|
|
3029
|
+
tempOrder.products[matchedIndex] = {
|
|
3030
|
+
...targetProduct,
|
|
3031
|
+
...normalizedProduct,
|
|
3032
|
+
discount_list: nextDiscountList,
|
|
3033
|
+
metadata: {
|
|
3034
|
+
...targetProduct.metadata || {},
|
|
3035
|
+
...normalizedProduct.metadata || {},
|
|
3036
|
+
unique_identification_number: targetUid
|
|
3037
|
+
},
|
|
3038
|
+
product_sku: {
|
|
3039
|
+
...targetProduct.product_sku || { option: [] },
|
|
3040
|
+
...normalizedProduct.product_sku || { option: [] },
|
|
3041
|
+
option: (0, import_utils.getProductSkuOptions)(normalizedProduct)
|
|
3042
|
+
},
|
|
3043
|
+
...targetIsManualProductDiscount ? {
|
|
3044
|
+
selling_price: targetProduct.selling_price,
|
|
3045
|
+
original_price: targetProduct.original_price,
|
|
3046
|
+
payment_price: targetProduct.payment_price,
|
|
3047
|
+
metadata: {
|
|
3048
|
+
...normalizedProduct.metadata || {},
|
|
3049
|
+
...targetProduct.metadata || {},
|
|
3050
|
+
unique_identification_number: targetUid
|
|
3051
|
+
}
|
|
3052
|
+
} : {},
|
|
3053
|
+
note: targetProduct.note,
|
|
3054
|
+
order_detail_id: targetProduct.order_detail_id,
|
|
3055
|
+
num: nextNum
|
|
3056
|
+
};
|
|
3057
|
+
this.captureProductRuntime(
|
|
3058
|
+
tempOrder,
|
|
3059
|
+
productToAdd,
|
|
3060
|
+
tempOrder.products[matchedIndex],
|
|
3061
|
+
targetUid
|
|
3062
|
+
);
|
|
3063
|
+
if (matchedIndex !== tempOrder.products.length - 1) {
|
|
3064
|
+
const mergedProduct = tempOrder.products[matchedIndex];
|
|
3065
|
+
tempOrder.products = [
|
|
3066
|
+
...tempOrder.products.slice(0, matchedIndex),
|
|
3067
|
+
...tempOrder.products.slice(matchedIndex + 1),
|
|
3068
|
+
mergedProduct
|
|
3069
|
+
];
|
|
3070
|
+
}
|
|
3071
|
+
}
|
|
3072
|
+
if (linked) {
|
|
3073
|
+
tempOrder.bookings = [...tempOrder.bookings || [], linked.booking];
|
|
3074
|
+
}
|
|
3075
|
+
};
|
|
3076
|
+
if (!matchedProduct) {
|
|
3077
|
+
commitProductLine(false);
|
|
3078
|
+
return;
|
|
3079
|
+
}
|
|
3080
|
+
const shouldMerge = this.shouldMergeProductToOrder({
|
|
2961
3081
|
incomingProduct: productToAdd,
|
|
2962
3082
|
normalizedIncoming,
|
|
2963
3083
|
matchedProduct,
|
|
@@ -2966,100 +3086,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2966
3086
|
existedFingerprint,
|
|
2967
3087
|
tempOrder,
|
|
2968
3088
|
booking
|
|
2969
|
-
})
|
|
2970
|
-
if (
|
|
2971
|
-
|
|
2972
|
-
tempOrder,
|
|
2973
|
-
productToAdd,
|
|
2974
|
-
normalizedIncoming
|
|
2975
|
-
);
|
|
2976
|
-
if (linked) {
|
|
2977
|
-
normalizedIncoming.booking_uid = linked.bookingUid;
|
|
2978
|
-
normalizedIncoming.metadata = {
|
|
2979
|
-
...normalizedIncoming.metadata || {},
|
|
2980
|
-
booking_uid: linked.bookingUid
|
|
2981
|
-
};
|
|
2982
|
-
}
|
|
2983
|
-
const insertAtIndex = options == null ? void 0 : options.insertAtIndex;
|
|
2984
|
-
if (Number.isInteger(insertAtIndex) && Number(insertAtIndex) >= 0 && Number(insertAtIndex) < tempOrder.products.length) {
|
|
2985
|
-
tempOrder.products = [
|
|
2986
|
-
...tempOrder.products.slice(0, insertAtIndex),
|
|
2987
|
-
normalizedIncoming,
|
|
2988
|
-
...tempOrder.products.slice(insertAtIndex)
|
|
2989
|
-
];
|
|
2990
|
-
} else {
|
|
2991
|
-
tempOrder.products = [...tempOrder.products, normalizedIncoming];
|
|
2992
|
-
}
|
|
2993
|
-
} else {
|
|
2994
|
-
const targetProduct = matchedProduct;
|
|
2995
|
-
const targetUid = (_g = targetProduct.metadata) == null ? void 0 : _g.unique_identification_number;
|
|
2996
|
-
const normalizedProduct = (0, import_utils.mergeOrderProductDisplayFields)(
|
|
2997
|
-
targetProduct,
|
|
2998
|
-
(0, import_utils3.normalizeOrderProduct)({
|
|
2999
|
-
...productToAdd,
|
|
3000
|
-
metadata: {
|
|
3001
|
-
...productToAdd.metadata || {},
|
|
3002
|
-
unique_identification_number: targetUid
|
|
3003
|
-
}
|
|
3004
|
-
})
|
|
3005
|
-
);
|
|
3006
|
-
normalizedProduct.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
|
|
3007
|
-
normalizedProduct.discount_list
|
|
3008
|
-
);
|
|
3009
|
-
const nextNum = (0, import_utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num);
|
|
3010
|
-
const targetIsManualProductDiscount = isManualProductDiscountProduct(targetProduct);
|
|
3011
|
-
const nextDiscountList = targetIsManualProductDiscount ? (0, import_utils.normalizeOrderProductDiscountList)(
|
|
3012
|
-
(0, import_manualProductDiscount.syncManualProductDiscountProductNum)(
|
|
3013
|
-
targetProduct.discount_list,
|
|
3014
|
-
nextNum
|
|
3015
|
-
)
|
|
3016
|
-
) : normalizedProduct.discount_list;
|
|
3017
|
-
tempOrder.products[matchedIndex] = {
|
|
3018
|
-
...targetProduct,
|
|
3019
|
-
...normalizedProduct,
|
|
3020
|
-
discount_list: nextDiscountList,
|
|
3021
|
-
metadata: {
|
|
3022
|
-
...targetProduct.metadata || {},
|
|
3023
|
-
...normalizedProduct.metadata || {},
|
|
3024
|
-
unique_identification_number: targetUid
|
|
3025
|
-
},
|
|
3026
|
-
product_sku: {
|
|
3027
|
-
...targetProduct.product_sku || { option: [] },
|
|
3028
|
-
...normalizedProduct.product_sku || { option: [] },
|
|
3029
|
-
option: (0, import_utils.getProductSkuOptions)(normalizedProduct)
|
|
3030
|
-
},
|
|
3031
|
-
...targetIsManualProductDiscount ? {
|
|
3032
|
-
selling_price: targetProduct.selling_price,
|
|
3033
|
-
original_price: targetProduct.original_price,
|
|
3034
|
-
payment_price: targetProduct.payment_price,
|
|
3035
|
-
metadata: {
|
|
3036
|
-
...normalizedProduct.metadata || {},
|
|
3037
|
-
...targetProduct.metadata || {},
|
|
3038
|
-
unique_identification_number: targetUid
|
|
3039
|
-
}
|
|
3040
|
-
} : {},
|
|
3041
|
-
note: targetProduct.note,
|
|
3042
|
-
order_detail_id: targetProduct.order_detail_id,
|
|
3043
|
-
num: nextNum
|
|
3044
|
-
};
|
|
3045
|
-
this.captureProductRuntime(
|
|
3046
|
-
tempOrder,
|
|
3047
|
-
productToAdd,
|
|
3048
|
-
tempOrder.products[matchedIndex],
|
|
3049
|
-
targetUid
|
|
3050
|
-
);
|
|
3051
|
-
if (matchedIndex !== tempOrder.products.length - 1) {
|
|
3052
|
-
const mergedProduct = tempOrder.products[matchedIndex];
|
|
3053
|
-
tempOrder.products = [
|
|
3054
|
-
...tempOrder.products.slice(0, matchedIndex),
|
|
3055
|
-
...tempOrder.products.slice(matchedIndex + 1),
|
|
3056
|
-
mergedProduct
|
|
3057
|
-
];
|
|
3058
|
-
}
|
|
3059
|
-
}
|
|
3060
|
-
if (linked) {
|
|
3061
|
-
tempOrder.bookings = [...tempOrder.bookings || [], linked.booking];
|
|
3089
|
+
});
|
|
3090
|
+
if (shouldMerge && typeof shouldMerge === "object" && typeof shouldMerge.then === "function") {
|
|
3091
|
+
return Promise.resolve(shouldMerge).then(commitProductLine);
|
|
3062
3092
|
}
|
|
3093
|
+
commitProductLine(shouldMerge);
|
|
3063
3094
|
}
|
|
3064
3095
|
/**
|
|
3065
3096
|
* 添加商品行。带 booking 时强制独立行;num>1 时拆成多条 num=1 的 product+booking(对齐 BookingByStep / ticketBooking addService)。
|
|
@@ -3087,12 +3118,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
3087
3118
|
const singleLine = (0, import_lodash_es.cloneDeep)(productRecord);
|
|
3088
3119
|
singleLine.num = 1;
|
|
3089
3120
|
delete singleLine.product_quantity;
|
|
3090
|
-
|
|
3121
|
+
const appendResult2 = this.appendProductLineToTempOrder(
|
|
3091
3122
|
tempOrder,
|
|
3092
3123
|
singleLine,
|
|
3093
3124
|
(0, import_lodash_es.cloneDeep)(booking),
|
|
3094
3125
|
{ insertAtIndex }
|
|
3095
3126
|
);
|
|
3127
|
+
if (appendResult2)
|
|
3128
|
+
await appendResult2;
|
|
3096
3129
|
if (insertAtIndex !== void 0)
|
|
3097
3130
|
insertAtIndex += 1;
|
|
3098
3131
|
}
|
|
@@ -3100,12 +3133,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
3100
3133
|
return tempOrder.products;
|
|
3101
3134
|
}
|
|
3102
3135
|
}
|
|
3103
|
-
|
|
3136
|
+
const appendResult = this.appendProductLineToTempOrder(
|
|
3104
3137
|
tempOrder,
|
|
3105
3138
|
product,
|
|
3106
3139
|
booking,
|
|
3107
3140
|
{ insertAtIndex }
|
|
3108
3141
|
);
|
|
3142
|
+
if (appendResult)
|
|
3143
|
+
await appendResult;
|
|
3109
3144
|
await this.finalizeProductOrderMutation(tempOrder);
|
|
3110
3145
|
this.logInfo("addProductToOrder success", {
|
|
3111
3146
|
product_id: product.product_id,
|
|
@@ -3140,16 +3175,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
3140
3175
|
const singleLine = (0, import_lodash_es.cloneDeep)(productRecord);
|
|
3141
3176
|
singleLine.num = 1;
|
|
3142
3177
|
delete singleLine.product_quantity;
|
|
3143
|
-
|
|
3178
|
+
const appendResult2 = this.appendProductLineToTempOrder(
|
|
3144
3179
|
tempOrder,
|
|
3145
3180
|
singleLine,
|
|
3146
3181
|
(0, import_lodash_es.cloneDeep)(booking)
|
|
3147
3182
|
);
|
|
3183
|
+
if (appendResult2)
|
|
3184
|
+
await appendResult2;
|
|
3148
3185
|
}
|
|
3149
3186
|
continue;
|
|
3150
3187
|
}
|
|
3151
3188
|
}
|
|
3152
|
-
|
|
3189
|
+
const appendResult = this.appendProductLineToTempOrder(
|
|
3190
|
+
tempOrder,
|
|
3191
|
+
product,
|
|
3192
|
+
booking
|
|
3193
|
+
);
|
|
3194
|
+
if (appendResult)
|
|
3195
|
+
await appendResult;
|
|
3153
3196
|
}
|
|
3154
3197
|
await this.finalizeProductOrderMutation(tempOrder, options);
|
|
3155
3198
|
this.logInfo("addProductsToOrder success", {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { OrderTempOrder } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* 商品券拆行的身份与回并工具。
|
|
4
|
+
*
|
|
5
|
+
* 背景:
|
|
6
|
+
* Rules.calcDiscount 应用 good_pass 时,会把一个数量行拆成若干「用券行」和
|
|
7
|
+
* 「普通余量行」。Rules 返回的拆分行可能复制同一份
|
|
8
|
+
* metadata.unique_identification_number,进而造成:
|
|
9
|
+
* - 按 UID 删除时同时命中多行;
|
|
10
|
+
* - UI 把不同券行视为同一个商品;
|
|
11
|
+
* - 后续商品更新无法准确定位目标行。
|
|
12
|
+
*
|
|
13
|
+
* 处理原则:
|
|
14
|
+
* 1. 拆分后每一行必须拥有独立 UID;
|
|
15
|
+
* 2. 原始拆分来源仅记录在 tempOrder._extend.productsByUid 的运行态索引中,
|
|
16
|
+
* 不写入商品 metadata,不污染提交协议;
|
|
17
|
+
* 3. 券被移除后,只回并被本工具确认来自同一折扣拆分源的行;
|
|
18
|
+
* 4. 预约、赠品、促销、手动折扣、备注、称重、holder 和已落库行均为硬边界。
|
|
19
|
+
*
|
|
20
|
+
* 两个导出函数都会原地更新 tempOrder。调用顺序必须是:
|
|
21
|
+
* ensureUniqueProductLineUids -> consolidateDiscountFreeProductLines。
|
|
22
|
+
*/
|
|
23
|
+
/** productsByUid 运行态记录中用于关联同一次折扣拆分的字段。 */
|
|
24
|
+
export declare const DISCOUNT_SPLIT_ORIGIN_UID_KEY = "discountSplitOriginUid";
|
|
25
|
+
/**
|
|
26
|
+
* 修复 Rules 折扣拆行复制 UID 的问题,并为拆分行记录共同来源。
|
|
27
|
+
*
|
|
28
|
+
* 第一条商品保留原 UID,后续重复行生成新 UUID;对应的 productsByUid.runtime
|
|
29
|
+
* 会复制原行 runtime(包括 origin),以保证删除、编辑及展示字段回读仍可工作。
|
|
30
|
+
*
|
|
31
|
+
* 没有 UID 的裸商品不会被补写 UID。这是为了兼容 Rules/mock 的历史协议形状;
|
|
32
|
+
* 正常 Order 写路径会在 normalize 阶段提前创建 UID。
|
|
33
|
+
*/
|
|
34
|
+
export declare function ensureUniqueProductLineUids(tempOrder: OrderTempOrder): void;
|
|
35
|
+
/**
|
|
36
|
+
* 把券移除后已经恢复原价的同源折扣拆分行重新合并。
|
|
37
|
+
*
|
|
38
|
+
* 此函数刻意不执行通用的「同 SKU 合并」:没有 discountSplitOriginUid 的普通行
|
|
39
|
+
* 可能是业务 hook、导入订单或其它流程主动拆开的,不能在折扣重算时擅自合并。
|
|
40
|
+
*
|
|
41
|
+
* payment_price、tax_fee、surcharge_fee 属于 summary 计算层的派生值。券行与普通行
|
|
42
|
+
* 在回并前可能暂时不同,因此它们不参与 mergeKey;原始价格、SKU/option/bundle
|
|
43
|
+
* 结构以及税务/商品类型配置仍参与比较,防止不同商品语义被误合并。
|
|
44
|
+
*/
|
|
45
|
+
export declare function consolidateDiscountFreeProductLines(tempOrder: OrderTempOrder): void;
|