@pisell/pisellos 2.2.174 → 2.2.176
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/modules/Order/index.d.ts +52 -1
- package/dist/modules/Order/index.js +730 -348
- package/dist/modules/Order/types.d.ts +140 -1
- package/dist/modules/Order/types.js +29 -0
- package/dist/modules/Order/utils.d.ts +11 -0
- package/dist/modules/Order/utils.js +43 -2
- package/dist/modules/SalesSummary/utils.js +3 -3
- package/dist/server/index.js +77 -23
- package/dist/solution/BaseSales/index.d.ts +37 -1
- package/dist/solution/BaseSales/index.js +751 -457
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +275 -0
- package/dist/solution/BaseSales/utils/cartPromotion.js +1258 -0
- package/dist/solution/BookingTicket/index.js +4 -0
- package/dist/solution/BookingTicket/utils/cartView.js +4 -2
- package/lib/model/strategy/adapter/promotion/index.js +0 -49
- package/lib/modules/Order/index.d.ts +52 -1
- package/lib/modules/Order/index.js +195 -6
- package/lib/modules/Order/types.d.ts +140 -1
- package/lib/modules/Order/types.js +1 -0
- package/lib/modules/Order/utils.d.ts +11 -0
- package/lib/modules/Order/utils.js +34 -2
- package/lib/modules/SalesSummary/utils.js +3 -3
- package/lib/server/index.js +39 -4
- package/lib/solution/BaseSales/index.d.ts +37 -1
- package/lib/solution/BaseSales/index.js +207 -1
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +275 -0
- package/lib/solution/BaseSales/utils/cartPromotion.js +836 -0
- package/lib/solution/BookingTicket/index.js +3 -0
- package/lib/solution/BookingTicket/utils/cartView.js +4 -2
- package/package.json +1 -1
|
@@ -54,6 +54,7 @@ __export(utils_exports, {
|
|
|
54
54
|
normalizeOrderProductDiscountList: () => normalizeOrderProductDiscountList,
|
|
55
55
|
normalizeSubmitBooking: () => normalizeSubmitBooking,
|
|
56
56
|
normalizeSubmitCollectPaxValue: () => normalizeSubmitCollectPaxValue,
|
|
57
|
+
resolveEffectivePerUnitDiscount: () => resolveEffectivePerUnitDiscount,
|
|
57
58
|
resolveManualDiscountMessage: () => import_manualProductDiscount.resolveManualDiscountMessage,
|
|
58
59
|
resolveManualDiscountOriginTotal: () => import_manualProductDiscount.resolveManualDiscountOriginTotal,
|
|
59
60
|
resolveManualDiscountReasonFromSources: () => import_manualProductDiscount.resolveManualDiscountReasonFromSources,
|
|
@@ -169,6 +170,33 @@ function resolveManualOverrideLineOriginalPrice(params, fallbackCompositeOrigina
|
|
|
169
170
|
}
|
|
170
171
|
return fallbackCompositeOriginal;
|
|
171
172
|
}
|
|
173
|
+
function resolveEffectivePerUnitDiscount(product) {
|
|
174
|
+
const discountList = Array.isArray(product == null ? void 0 : product.discount_list) ? product.discount_list : [];
|
|
175
|
+
const fromList = discountList.reduce(
|
|
176
|
+
(sum, discount) => sum + Number((discount == null ? void 0 : discount.amount) || 0),
|
|
177
|
+
0
|
|
178
|
+
);
|
|
179
|
+
const hasPromoDiscountItem = discountList.some((item) => (item == null ? void 0 : item.type) === "promotion");
|
|
180
|
+
if (hasPromoDiscountItem)
|
|
181
|
+
return fromList;
|
|
182
|
+
const metadata = (product == null ? void 0 : product.metadata) || {};
|
|
183
|
+
const optionSum = sumOptionUnitPrice(product == null ? void 0 : product.product_option_item).toNumber();
|
|
184
|
+
if (metadata.source_product_price != null && metadata.main_product_selling_price != null) {
|
|
185
|
+
const source = Number(metadata.source_product_price);
|
|
186
|
+
const selling = Number(metadata.main_product_selling_price) - optionSum;
|
|
187
|
+
if (Number.isFinite(source) && Number.isFinite(selling) && source !== selling) {
|
|
188
|
+
return fromList + (source - selling);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const promo = metadata._promotion;
|
|
192
|
+
if ((promo == null ? void 0 : promo.inPromotion) !== true)
|
|
193
|
+
return fromList;
|
|
194
|
+
const originalPrice = Number(promo.originalPrice);
|
|
195
|
+
const finalPrice = Number(promo.finalPrice);
|
|
196
|
+
if (!Number.isFinite(originalPrice) || !Number.isFinite(finalPrice))
|
|
197
|
+
return fromList;
|
|
198
|
+
return fromList + (originalPrice - finalPrice);
|
|
199
|
+
}
|
|
172
200
|
function createDefaultOrderRulesHooks() {
|
|
173
201
|
const toUnitPriceString = (totalLike, num) => {
|
|
174
202
|
const effectiveNum = Number(num) > 0 ? Number(num) : 1;
|
|
@@ -176,7 +204,7 @@ function createDefaultOrderRulesHooks() {
|
|
|
176
204
|
};
|
|
177
205
|
return {
|
|
178
206
|
getProduct: (product) => {
|
|
179
|
-
var _a, _b, _c, _d, _e;
|
|
207
|
+
var _a, _b, _c, _d, _e, _f;
|
|
180
208
|
const metadataAny = product.metadata || {};
|
|
181
209
|
const optionSum = sumOptionUnitPrice(product.product_option_item);
|
|
182
210
|
let sourcePrice;
|
|
@@ -228,7 +256,10 @@ function createDefaultOrderRulesHooks() {
|
|
|
228
256
|
// 无券时会把 bundle 价还原成 original_price(手动改价套餐会从 20 回到 30)。
|
|
229
257
|
isManualDiscount: resolveRulesManualDiscountFlag(metadataAny),
|
|
230
258
|
holder_id: (_c = product.metadata) == null ? void 0 : _c.holder_id,
|
|
231
|
-
startDate: ((_d = product.metadata) == null ? void 0 : _d.start_date) || ((_e = product.metadata) == null ? void 0 : _e.startDate)
|
|
259
|
+
startDate: ((_d = product.metadata) == null ? void 0 : _d.start_date) || ((_e = product.metadata) == null ? void 0 : _e.startDate),
|
|
260
|
+
main_product_selling_price: metadataAny.main_product_selling_price !== void 0 ? new import_decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSum).toDecimalPlaces(2).toString() : void 0,
|
|
261
|
+
inPromotion: ((_f = metadataAny._promotion) == null ? void 0 : _f.inPromotion) === true,
|
|
262
|
+
_promotion: metadataAny._promotion
|
|
232
263
|
};
|
|
233
264
|
},
|
|
234
265
|
setProduct: (product, values) => {
|
|
@@ -797,6 +828,7 @@ function clearTempOrderHolderAssignments(tempOrder) {
|
|
|
797
828
|
normalizeOrderProductDiscountList,
|
|
798
829
|
normalizeSubmitBooking,
|
|
799
830
|
normalizeSubmitCollectPaxValue,
|
|
831
|
+
resolveEffectivePerUnitDiscount,
|
|
800
832
|
resolveManualDiscountMessage,
|
|
801
833
|
resolveManualDiscountOriginTotal,
|
|
802
834
|
resolveManualDiscountReasonFromSources,
|
|
@@ -393,8 +393,8 @@ function calculateSalesSummary(params) {
|
|
|
393
393
|
);
|
|
394
394
|
}
|
|
395
395
|
const shopDiscountAmount = import_decimal.default.max(new import_decimal.default(Number(shopDiscount) || 0), 0);
|
|
396
|
-
const
|
|
397
|
-
const totalAmount = isPriceIncludeTax === 1 ?
|
|
396
|
+
const preTaxExpectAmount = import_decimal.default.max(0, productAmount.plus(surchargeAmount).minus(shopDiscountAmount));
|
|
397
|
+
const totalAmount = isPriceIncludeTax === 1 ? preTaxExpectAmount : preTaxExpectAmount.plus(productTaxFee);
|
|
398
398
|
const deposit = calculateProductsDeposit(products);
|
|
399
399
|
return {
|
|
400
400
|
product_quantity: productQuantity,
|
|
@@ -412,7 +412,7 @@ function calculateSalesSummary(params) {
|
|
|
412
412
|
),
|
|
413
413
|
deposit_amount: deposit ? deposit.total : "0.00",
|
|
414
414
|
deposit,
|
|
415
|
-
expect_amount: toFixed2(
|
|
415
|
+
expect_amount: toFixed2(totalAmount),
|
|
416
416
|
total_amount: toFixed2(totalAmount),
|
|
417
417
|
total_refund_amount: "0.00",
|
|
418
418
|
customer_paid_amount: "0.00",
|
package/lib/server/index.js
CHANGED
|
@@ -149,10 +149,11 @@ var Server = class {
|
|
|
149
149
|
*/
|
|
150
150
|
this.handleProductQuery = async ({ url, method, data, config }) => {
|
|
151
151
|
console.log("[Server] handleProductQuery:", url, method, data, config);
|
|
152
|
-
const { menu_list_ids, schedule_datetime, schedule_date, customer_id } = data;
|
|
152
|
+
const { menu_list_ids, schedule_datetime, schedule_date, customer_id, ids } = data;
|
|
153
153
|
const { callback, subscriberId } = config || {};
|
|
154
154
|
this.logInfo("handleProductQuery: 开始处理商品查询请求", {
|
|
155
155
|
menu_list_ids,
|
|
156
|
+
ids,
|
|
156
157
|
schedule_datetime,
|
|
157
158
|
schedule_date,
|
|
158
159
|
customer_id
|
|
@@ -160,14 +161,14 @@ var Server = class {
|
|
|
160
161
|
if (subscriberId && typeof callback === "function") {
|
|
161
162
|
this.productQuerySubscribers.set(subscriberId, {
|
|
162
163
|
callback,
|
|
163
|
-
context: { menu_list_ids, schedule_date, schedule_datetime, customer_id }
|
|
164
|
+
context: { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id }
|
|
164
165
|
});
|
|
165
166
|
this.logInfo("handleProductQuery: 已注册订阅者", {
|
|
166
167
|
subscriberId,
|
|
167
168
|
totalSubscribers: this.productQuerySubscribers.size
|
|
168
169
|
});
|
|
169
170
|
}
|
|
170
|
-
return this.computeProductQueryResult({ menu_list_ids, schedule_date, schedule_datetime, customer_id });
|
|
171
|
+
return this.computeProductQueryResult({ menu_list_ids, ids, schedule_date, schedule_datetime, customer_id });
|
|
171
172
|
};
|
|
172
173
|
/**
|
|
173
174
|
* 按商品 id 查询单条(GET /shop/product/query/:productId)
|
|
@@ -2051,9 +2052,11 @@ var Server = class {
|
|
|
2051
2052
|
*/
|
|
2052
2053
|
async computeProductQueryResult(context, options) {
|
|
2053
2054
|
const tTotal = performance.now();
|
|
2054
|
-
const { menu_list_ids, schedule_date, schedule_datetime, customer_id, product_id } = context;
|
|
2055
|
+
const { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, product_id } = context;
|
|
2056
|
+
const queryIds = Array.isArray(ids) ? ids.map((id) => Number(id)).filter((id) => Number.isFinite(id)) : [];
|
|
2055
2057
|
this.logInfo("computeProductQueryResult 开始", {
|
|
2056
2058
|
menuListIdsCount: (menu_list_ids == null ? void 0 : menu_list_ids.length) ?? 0,
|
|
2059
|
+
ids: queryIds,
|
|
2057
2060
|
schedule_datetime,
|
|
2058
2061
|
schedule_date,
|
|
2059
2062
|
customer_id,
|
|
@@ -2064,6 +2067,38 @@ var Server = class {
|
|
|
2064
2067
|
this.logError("computeProductQueryResult: Products 模块未注册");
|
|
2065
2068
|
return { message: "Products 模块未注册", data: { list: [], count: 0 } };
|
|
2066
2069
|
}
|
|
2070
|
+
if (queryIds.length > 0) {
|
|
2071
|
+
const uniqueIds = Array.from(new Set(queryIds));
|
|
2072
|
+
const tPrice2 = performance.now();
|
|
2073
|
+
const productsWithPrice = await this.products.getProductsWithPrice(schedule_date, {
|
|
2074
|
+
scheduleModule: this.getSchedule(),
|
|
2075
|
+
schedule_datetime,
|
|
2076
|
+
customer_id
|
|
2077
|
+
}, {
|
|
2078
|
+
changedIds: options == null ? void 0 : options.changedIds,
|
|
2079
|
+
productIds: uniqueIds
|
|
2080
|
+
});
|
|
2081
|
+
(0, import_product.perfMark)("computeQuery.getProductsWithPrice(ids)", performance.now() - tPrice2, {
|
|
2082
|
+
count: productsWithPrice.length,
|
|
2083
|
+
ids: uniqueIds
|
|
2084
|
+
});
|
|
2085
|
+
const filteredProducts2 = productsWithPrice.filter((p) => uniqueIds.includes(Number(p == null ? void 0 : p.id))).filter((p) => ((p == null ? void 0 : p.status) || "published") === "published");
|
|
2086
|
+
(0, import_product.perfMark)("computeProductQueryResult", performance.now() - tTotal, {
|
|
2087
|
+
mode: "ids",
|
|
2088
|
+
ids: uniqueIds,
|
|
2089
|
+
count: filteredProducts2.length
|
|
2090
|
+
});
|
|
2091
|
+
this.logInfo("computeProductQueryResult 完成(ids)", {
|
|
2092
|
+
ids: uniqueIds,
|
|
2093
|
+
count: filteredProducts2.length
|
|
2094
|
+
});
|
|
2095
|
+
return {
|
|
2096
|
+
code: 200,
|
|
2097
|
+
data: { list: filteredProducts2, count: filteredProducts2.length },
|
|
2098
|
+
message: "",
|
|
2099
|
+
status: true
|
|
2100
|
+
};
|
|
2101
|
+
}
|
|
2067
2102
|
if (product_id != null && Number.isFinite(Number(product_id))) {
|
|
2068
2103
|
const pid = Number(product_id);
|
|
2069
2104
|
const tPrice2 = performance.now();
|
|
@@ -2,7 +2,7 @@ import { Module, ModuleOptions, PisellCore } from '../../types';
|
|
|
2
2
|
import { BaseModule } from '../../modules/BaseModule';
|
|
3
3
|
import { BaseSalesOrderProduct, BaseSalesOrderProductIdentity, BaseSalesPaymentStatus, BaseSalesUpdateOrderProductQuantityParams, BaseSalesCalculateProductBookingPriceParams, BaseSalesProductBookingPriceResult, BaseSalesScanCodeResult } from './types';
|
|
4
4
|
import { OrderModule } from '../../modules/Order';
|
|
5
|
-
import type { AddProductBookingInput, LoadSalesDetailParams, OrderPaymentData, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder } from '../../modules/Order/types';
|
|
5
|
+
import type { AddProductBookingInput, LoadSalesDetailParams, OrderPaymentData, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions } from '../../modules/Order/types';
|
|
6
6
|
import type { SubmitPayloadEnhancer } from '../../modules/Order/utils';
|
|
7
7
|
import type { Discount } from '../../modules/Discount/types';
|
|
8
8
|
import { RequestPlugin, WindowPlugin } from '../../plugins';
|
|
@@ -63,6 +63,13 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
63
63
|
private getCurrentOrderCustomerId;
|
|
64
64
|
private applyQuotationScheduleResolver;
|
|
65
65
|
private loadQuotationForPriceQuery;
|
|
66
|
+
private getPriceQueryProductId;
|
|
67
|
+
private getPriceQuerySchedule;
|
|
68
|
+
private loadProductForPriceQuery;
|
|
69
|
+
private getAuthoritativeBundleItems;
|
|
70
|
+
private findAuthoritativeBundleItem;
|
|
71
|
+
private getAuthoritativeBundleUnitPrice;
|
|
72
|
+
private mergeProductForPriceQuery;
|
|
66
73
|
protected getSubmitOrderSalesChannel(): string | undefined;
|
|
67
74
|
/**
|
|
68
75
|
* 工厂入口:根据子模块名实例化对应模块。
|
|
@@ -237,6 +244,35 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
237
244
|
*/
|
|
238
245
|
setOrderProductLineNote(identity: BaseSalesOrderProductIdentity, note: string): Promise<import("../../modules/Order/types").OrderProduct[]>;
|
|
239
246
|
removeProductFromOrder(identity: BaseSalesOrderProductIdentity): Promise<import("../../modules/Order/types").OrderProduct[]>;
|
|
247
|
+
/**
|
|
248
|
+
* 注入促销评估器到底层 OrderModule。
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* solution.setPromotionEvaluator(appHelper.utils.promotionEvaluator);
|
|
252
|
+
*/
|
|
253
|
+
setPromotionEvaluator(evaluator: OrderPromotionEvaluator | null): void;
|
|
254
|
+
/**
|
|
255
|
+
* 注入赠品选择 resolver。UI 层(SalesSdk)通过 bridge 提供。
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* solution.setGiftSelectResolver(async (ctx) => bridge.request(ctx));
|
|
259
|
+
*/
|
|
260
|
+
setGiftSelectResolver(resolver: OrderGiftSelectResolver | null): void;
|
|
261
|
+
/**
|
|
262
|
+
* 为商品目录追加促销标签,供 SalesSdkProductProvider 等商品列表入口复用。
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* const products = solution.appendPromotionTags(catalogProducts);
|
|
266
|
+
*/
|
|
267
|
+
appendPromotionTags<T extends Record<string, any>>(products: T[]): T[];
|
|
268
|
+
/**
|
|
269
|
+
* 主动触发一次促销应用(一般写路径会自动触发,少数场景如客户切换后可手动调)。
|
|
270
|
+
*/
|
|
271
|
+
applyPromotion(): Promise<void>;
|
|
272
|
+
/** 最近一次促销计算输出的未满足提示。 */
|
|
273
|
+
getUnfulfilledPromotions(): OrderUnfulfilledPromotion[];
|
|
274
|
+
/** 最近一次促销计算输出的赠品操作 diff。 */
|
|
275
|
+
getLastGiftActions(): OrderLastGiftActions | null;
|
|
240
276
|
getProductList(): Promise<any>;
|
|
241
277
|
getOtherParams(): Record<string, any>;
|
|
242
278
|
setOtherParams(params: Record<string, any>, { cover }?: {
|
|
@@ -137,6 +137,140 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
137
137
|
customer_id: params.customer_id
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
|
+
getPriceQueryProductId(product) {
|
|
141
|
+
const productId = Number((product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id));
|
|
142
|
+
if (!Number.isFinite(productId))
|
|
143
|
+
return null;
|
|
144
|
+
return productId;
|
|
145
|
+
}
|
|
146
|
+
getPriceQuerySchedule(params) {
|
|
147
|
+
const booking = params.booking || {};
|
|
148
|
+
if (typeof booking.start_date === "string" && booking.start_date.trim()) {
|
|
149
|
+
const scheduleDate = booking.start_date.trim();
|
|
150
|
+
const startTime = typeof booking.start_time === "string" && booking.start_time.trim() ? booking.start_time.trim() : "00:00:00";
|
|
151
|
+
const datetime = (0, import_dayjs.default)(`${scheduleDate} ${startTime}`);
|
|
152
|
+
return {
|
|
153
|
+
schedule_date: scheduleDate,
|
|
154
|
+
schedule_datetime: datetime.isValid() ? datetime.format("YYYY-MM-DD HH:mm:ss") : `${scheduleDate} ${startTime}`
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (typeof params.datetime === "string" && params.datetime.trim()) {
|
|
158
|
+
const datetime = (0, import_dayjs.default)(params.datetime.trim());
|
|
159
|
+
if (datetime.isValid()) {
|
|
160
|
+
return {
|
|
161
|
+
schedule_date: datetime.format("YYYY-MM-DD"),
|
|
162
|
+
schedule_datetime: datetime.format("YYYY-MM-DD HH:mm:ss")
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const now = (0, import_dayjs.default)();
|
|
167
|
+
return {
|
|
168
|
+
schedule_date: now.format("YYYY-MM-DD"),
|
|
169
|
+
schedule_datetime: now.format("YYYY-MM-DD HH:mm:ss")
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
async loadProductForPriceQuery(params, customerId) {
|
|
173
|
+
var _a, _b;
|
|
174
|
+
const product = params.product || {};
|
|
175
|
+
const productId = this.getPriceQueryProductId(product);
|
|
176
|
+
if (productId === null || !this.request)
|
|
177
|
+
return null;
|
|
178
|
+
const schedule = this.getPriceQuerySchedule(params);
|
|
179
|
+
try {
|
|
180
|
+
const response = await this.request.post("/product/query", {
|
|
181
|
+
ids: [productId],
|
|
182
|
+
open_quotation: 1,
|
|
183
|
+
open_bundle: 1,
|
|
184
|
+
status: "published",
|
|
185
|
+
num: 1,
|
|
186
|
+
skip: 1,
|
|
187
|
+
customer_id: customerId,
|
|
188
|
+
schedule_date: schedule.schedule_date,
|
|
189
|
+
schedule_datetime: schedule.schedule_datetime,
|
|
190
|
+
application_code: params.channel || ((_a = this.otherParams) == null ? void 0 : _a.channel)
|
|
191
|
+
}, {
|
|
192
|
+
osServer: true,
|
|
193
|
+
customToast: () => {
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
const list = ((_b = response == null ? void 0 : response.data) == null ? void 0 : _b.list) || (response == null ? void 0 : response.list) || [];
|
|
197
|
+
if (!Array.isArray(list))
|
|
198
|
+
return null;
|
|
199
|
+
return list.find((item) => Number((item == null ? void 0 : item.id) ?? (item == null ? void 0 : item.product_id)) === productId) || null;
|
|
200
|
+
} catch (error) {
|
|
201
|
+
this.logWarning("loadProductForPriceQuery: 商品重查失败,使用入参 fallback", {
|
|
202
|
+
productId,
|
|
203
|
+
error: error instanceof Error ? error.message : String(error)
|
|
204
|
+
});
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
getAuthoritativeBundleItems(product) {
|
|
209
|
+
if (Array.isArray(product == null ? void 0 : product.product_bundle))
|
|
210
|
+
return product.product_bundle;
|
|
211
|
+
const groups = Array.isArray(product == null ? void 0 : product.bundle_group) ? product.bundle_group : Array.isArray(product == null ? void 0 : product.bundleGroup) ? product.bundleGroup : [];
|
|
212
|
+
return groups.flatMap((group) => {
|
|
213
|
+
const items = Array.isArray(group == null ? void 0 : group.bundle_item) ? group.bundle_item : Array.isArray(group == null ? void 0 : group.bundleItem) ? group.bundleItem : [];
|
|
214
|
+
return items.map((item) => ({
|
|
215
|
+
...item,
|
|
216
|
+
group_id: (item == null ? void 0 : item.group_id) ?? (group == null ? void 0 : group.id),
|
|
217
|
+
bundle_group_id: (item == null ? void 0 : item.bundle_group_id) ?? (item == null ? void 0 : item.group_id) ?? (group == null ? void 0 : group.id)
|
|
218
|
+
}));
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
findAuthoritativeBundleItem(bundle, candidates) {
|
|
222
|
+
const bundleId = bundle.bundle_id ?? bundle.id;
|
|
223
|
+
if (bundleId != null) {
|
|
224
|
+
const matchedById = candidates.find((item) => String((item == null ? void 0 : item.bundle_id) ?? (item == null ? void 0 : item.id)) === String(bundleId));
|
|
225
|
+
if (matchedById)
|
|
226
|
+
return matchedById;
|
|
227
|
+
}
|
|
228
|
+
const productId = bundle.bundle_product_id ?? bundle._bundle_product_id;
|
|
229
|
+
const groupId = bundle.bundle_group_id ?? bundle.group_id;
|
|
230
|
+
return candidates.find((item) => {
|
|
231
|
+
const itemProductId = (item == null ? void 0 : item.bundle_product_id) ?? (item == null ? void 0 : item._bundle_product_id);
|
|
232
|
+
const itemGroupId = (item == null ? void 0 : item.bundle_group_id) ?? (item == null ? void 0 : item.group_id);
|
|
233
|
+
if (productId == null || String(itemProductId) !== String(productId))
|
|
234
|
+
return false;
|
|
235
|
+
if (groupId == null)
|
|
236
|
+
return true;
|
|
237
|
+
return String(itemGroupId) === String(groupId);
|
|
238
|
+
}) || null;
|
|
239
|
+
}
|
|
240
|
+
getAuthoritativeBundleUnitPrice(bundle) {
|
|
241
|
+
return bundle.price ?? bundle.bundle_selling_price ?? bundle.custom_price ?? bundle.product_price ?? bundle.base_price;
|
|
242
|
+
}
|
|
243
|
+
mergeProductForPriceQuery(product, authoritativeProduct) {
|
|
244
|
+
if (!authoritativeProduct)
|
|
245
|
+
return product;
|
|
246
|
+
const selectedBundles = Array.isArray(product.product_bundle) ? product.product_bundle : [];
|
|
247
|
+
const authoritativeBundles = this.getAuthoritativeBundleItems(authoritativeProduct);
|
|
248
|
+
const productBundle = selectedBundles.map((bundle) => {
|
|
249
|
+
const authoritativeBundle = this.findAuthoritativeBundleItem(bundle, authoritativeBundles);
|
|
250
|
+
const unitPrice = authoritativeBundle ? this.getAuthoritativeBundleUnitPrice(authoritativeBundle) : void 0;
|
|
251
|
+
if (unitPrice === void 0 || unitPrice === null || unitPrice === "")
|
|
252
|
+
return bundle;
|
|
253
|
+
return {
|
|
254
|
+
...bundle,
|
|
255
|
+
price: unitPrice,
|
|
256
|
+
bundle_selling_price: unitPrice,
|
|
257
|
+
base_price: (authoritativeBundle == null ? void 0 : authoritativeBundle.base_price) ?? bundle.base_price,
|
|
258
|
+
product_price: (authoritativeBundle == null ? void 0 : authoritativeBundle.product_price) ?? bundle.product_price
|
|
259
|
+
};
|
|
260
|
+
});
|
|
261
|
+
return {
|
|
262
|
+
...product,
|
|
263
|
+
...authoritativeProduct,
|
|
264
|
+
id: product.id ?? authoritativeProduct.id,
|
|
265
|
+
product_id: product.product_id ?? authoritativeProduct.product_id ?? authoritativeProduct.id,
|
|
266
|
+
product_variant_id: product.product_variant_id ?? authoritativeProduct.product_variant_id ?? 0,
|
|
267
|
+
num: product.num ?? product.quantity ?? authoritativeProduct.num,
|
|
268
|
+
quantity: product.quantity ?? product.num ?? authoritativeProduct.quantity,
|
|
269
|
+
product_option_item: product.product_option_item ?? authoritativeProduct.product_option_item,
|
|
270
|
+
product_bundle: productBundle,
|
|
271
|
+
metadata: product.metadata ?? authoritativeProduct.metadata
|
|
272
|
+
};
|
|
273
|
+
}
|
|
140
274
|
getSubmitOrderSalesChannel() {
|
|
141
275
|
var _a;
|
|
142
276
|
return (_a = this.otherParams) == null ? void 0 : _a.channel;
|
|
@@ -189,10 +323,18 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
189
323
|
return coreData == null ? void 0 : coreData[key];
|
|
190
324
|
}
|
|
191
325
|
syncAppDataToTempOrder(tempOrder) {
|
|
326
|
+
const isPriceIncludeTax = this.getAppData("is_price_include_tax");
|
|
192
327
|
const taxCountryCode = this.getAppData("tax_country_code");
|
|
193
328
|
const currencyCode = this.getAppData("shop_currency_code");
|
|
194
329
|
const currencySymbol = this.getAppData("shop_symbol");
|
|
195
330
|
let isChanged = false;
|
|
331
|
+
if (isPriceIncludeTax !== void 0) {
|
|
332
|
+
const nextIsPriceIncludeTax = Number(isPriceIncludeTax);
|
|
333
|
+
if ((nextIsPriceIncludeTax === 0 || nextIsPriceIncludeTax === 1) && tempOrder.is_price_include_tax !== nextIsPriceIncludeTax) {
|
|
334
|
+
tempOrder.is_price_include_tax = nextIsPriceIncludeTax;
|
|
335
|
+
isChanged = true;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
196
338
|
if (taxCountryCode !== void 0) {
|
|
197
339
|
const nextTaxCountryCode = String(taxCountryCode || "");
|
|
198
340
|
if (tempOrder.tax_country_code !== nextTaxCountryCode) {
|
|
@@ -998,7 +1140,15 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
998
1140
|
addOrderPayment(payment) {
|
|
999
1141
|
if (!this.store.order)
|
|
1000
1142
|
throw new Error("order 模块未初始化");
|
|
1001
|
-
const
|
|
1143
|
+
const paymentRecord = payment;
|
|
1144
|
+
const metadata = paymentRecord.metadata && typeof paymentRecord.metadata === "object" ? { ...paymentRecord.metadata } : {};
|
|
1145
|
+
if (!metadata.unique_identification_number) {
|
|
1146
|
+
metadata.unique_identification_number = (0, import_utils.createUuidV4)();
|
|
1147
|
+
}
|
|
1148
|
+
const payments = this.store.order.addOrderPayment({
|
|
1149
|
+
...paymentRecord,
|
|
1150
|
+
metadata
|
|
1151
|
+
});
|
|
1002
1152
|
const amountSnapshot = this.store.order.getOrderAmountSnapshot();
|
|
1003
1153
|
const syncState = this.store.order.getOrderSyncState();
|
|
1004
1154
|
if (amountSnapshot && syncState !== "submitting") {
|
|
@@ -1209,6 +1359,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1209
1359
|
async calculateProductBookingPrice(params) {
|
|
1210
1360
|
const quotation = this.store.quotation;
|
|
1211
1361
|
const customerId = params.customer_id ?? this.getCurrentOrderCustomerId();
|
|
1362
|
+
const authoritativeProduct = await this.loadProductForPriceQuery(params, customerId);
|
|
1363
|
+
const product = this.mergeProductForPriceQuery(params.product, authoritativeProduct);
|
|
1212
1364
|
await this.loadQuotationForPriceQuery({
|
|
1213
1365
|
quotation,
|
|
1214
1366
|
customer_id: customerId,
|
|
@@ -1216,6 +1368,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1216
1368
|
});
|
|
1217
1369
|
return (0, import_quotationPrice.calculateBaseSalesProductBookingPrice)({
|
|
1218
1370
|
...params,
|
|
1371
|
+
product,
|
|
1372
|
+
fallback_price: authoritativeProduct ? void 0 : params.fallback_price,
|
|
1219
1373
|
customer_id: customerId,
|
|
1220
1374
|
quotation
|
|
1221
1375
|
});
|
|
@@ -1294,6 +1448,58 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1294
1448
|
throw error;
|
|
1295
1449
|
}
|
|
1296
1450
|
}
|
|
1451
|
+
// ─── 促销/赠品 透传(迁移自 booking usePromotion) ────────────────
|
|
1452
|
+
/**
|
|
1453
|
+
* 注入促销评估器到底层 OrderModule。
|
|
1454
|
+
*
|
|
1455
|
+
* @example
|
|
1456
|
+
* solution.setPromotionEvaluator(appHelper.utils.promotionEvaluator);
|
|
1457
|
+
*/
|
|
1458
|
+
setPromotionEvaluator(evaluator) {
|
|
1459
|
+
if (!this.store.order)
|
|
1460
|
+
throw new Error("order 模块未初始化");
|
|
1461
|
+
this.store.order.setPromotionEvaluator(evaluator);
|
|
1462
|
+
}
|
|
1463
|
+
/**
|
|
1464
|
+
* 注入赠品选择 resolver。UI 层(SalesSdk)通过 bridge 提供。
|
|
1465
|
+
*
|
|
1466
|
+
* @example
|
|
1467
|
+
* solution.setGiftSelectResolver(async (ctx) => bridge.request(ctx));
|
|
1468
|
+
*/
|
|
1469
|
+
setGiftSelectResolver(resolver) {
|
|
1470
|
+
if (!this.store.order)
|
|
1471
|
+
throw new Error("order 模块未初始化");
|
|
1472
|
+
this.store.order.setGiftSelectResolver(resolver);
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* 为商品目录追加促销标签,供 SalesSdkProductProvider 等商品列表入口复用。
|
|
1476
|
+
*
|
|
1477
|
+
* @example
|
|
1478
|
+
* const products = solution.appendPromotionTags(catalogProducts);
|
|
1479
|
+
*/
|
|
1480
|
+
appendPromotionTags(products) {
|
|
1481
|
+
if (!this.store.order)
|
|
1482
|
+
throw new Error("order 模块未初始化");
|
|
1483
|
+
return this.store.order.appendPromotionTags(products);
|
|
1484
|
+
}
|
|
1485
|
+
/**
|
|
1486
|
+
* 主动触发一次促销应用(一般写路径会自动触发,少数场景如客户切换后可手动调)。
|
|
1487
|
+
*/
|
|
1488
|
+
async applyPromotion() {
|
|
1489
|
+
if (!this.store.order)
|
|
1490
|
+
throw new Error("order 模块未初始化");
|
|
1491
|
+
await this.store.order.applyPromotion();
|
|
1492
|
+
}
|
|
1493
|
+
/** 最近一次促销计算输出的未满足提示。 */
|
|
1494
|
+
getUnfulfilledPromotions() {
|
|
1495
|
+
var _a;
|
|
1496
|
+
return ((_a = this.store.order) == null ? void 0 : _a.getUnfulfilledPromotions()) || [];
|
|
1497
|
+
}
|
|
1498
|
+
/** 最近一次促销计算输出的赠品操作 diff。 */
|
|
1499
|
+
getLastGiftActions() {
|
|
1500
|
+
var _a;
|
|
1501
|
+
return ((_a = this.store.order) == null ? void 0 : _a.getLastGiftActions()) || null;
|
|
1502
|
+
}
|
|
1297
1503
|
// 获取商品列表
|
|
1298
1504
|
// TODO 需要跟 webpos 内的对齐一下
|
|
1299
1505
|
async getProductList() {
|