@pisell/pisellos 0.10.6 → 0.10.8
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/BookingContext/utils/buildCacheItemFromOrderLine.js +12 -10
- package/dist/modules/Order/index.d.ts +14 -6
- package/dist/modules/Order/index.js +373 -246
- package/dist/modules/Order/types.d.ts +26 -3
- package/dist/modules/Order/types.js +11 -0
- package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
- package/dist/modules/Order/utils/discountProductLineIdentity.js +227 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +15 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.js +75 -0
- package/dist/modules/Rules/index.js +125 -52
- package/dist/modules/SalesSummary/utils.js +7 -1
- package/dist/server/index.d.ts +6 -0
- package/dist/server/index.js +810 -729
- package/dist/server/modules/order/index.d.ts +1 -0
- package/dist/server/modules/order/index.js +9 -2
- package/dist/server/modules/order/types.d.ts +1 -1
- package/dist/solution/BaseSales/index.d.ts +15 -5
- package/dist/solution/BaseSales/index.js +211 -159
- package/dist/solution/BaseSales/utils/cartPromotion.js +26 -3
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +1 -1
- package/dist/solution/BaseSales/utils.js +31 -20
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +13 -1
- package/dist/solution/BookingTicket/index.js +19 -22
- package/dist/solution/BookingTicket/types.d.ts +3 -0
- package/dist/solution/BookingTicket/utils/cartView.js +44 -32
- package/dist/solution/Sales/index.d.ts +1 -0
- package/dist/solution/Sales/index.js +16 -2
- package/dist/solution/ScanOrder/utils.js +31 -20
- package/dist/solution/UnifiedBookingSales/index.d.ts +16 -4
- package/dist/solution/UnifiedBookingSales/index.js +113 -48
- package/lib/model/strategy/adapter/promotion/index.js +0 -51
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +3 -1
- package/lib/modules/Order/index.d.ts +14 -6
- package/lib/modules/Order/index.js +192 -52
- package/lib/modules/Order/types.d.ts +26 -3
- package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
- package/lib/modules/Order/utils/discountProductLineIdentity.js +170 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +15 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.js +70 -0
- package/lib/modules/Rules/index.js +100 -20
- package/lib/modules/SalesSummary/utils.js +5 -1
- package/lib/server/index.d.ts +6 -0
- package/lib/server/index.js +51 -0
- package/lib/server/modules/order/index.d.ts +1 -0
- package/lib/server/modules/order/index.js +9 -3
- package/lib/server/modules/order/types.d.ts +1 -1
- package/lib/solution/BaseSales/index.d.ts +15 -5
- package/lib/solution/BaseSales/index.js +64 -16
- package/lib/solution/BaseSales/utils/cartPromotion.js +26 -2
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +1 -1
- package/lib/solution/BaseSales/utils.js +29 -18
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +13 -1
- package/lib/solution/BookingTicket/index.js +6 -9
- package/lib/solution/BookingTicket/types.d.ts +3 -0
- package/lib/solution/BookingTicket/utils/cartView.js +43 -30
- package/lib/solution/Sales/index.d.ts +1 -0
- package/lib/solution/Sales/index.js +15 -3
- package/lib/solution/ScanOrder/utils.js +29 -18
- package/lib/solution/UnifiedBookingSales/index.d.ts +16 -4
- package/lib/solution/UnifiedBookingSales/index.js +80 -26
- package/package.json +1 -1
|
@@ -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, BaseSalesPriceRecalculationContextChange, BaseSalesProductBookingPriceResult, BaseSalesQuotationCustomerScopeInfo, BaseSalesScanCodeResult, BaseSalesCashPaymentConfig, BaseSalesPayCashParams, BaseSalesPayCashResult, BaseSalesCommitPaymentMethodParams, BaseSalesCommitPaymentMethodResult, BaseSalesConfirmWalletPaymentResult } from './types';
|
|
4
4
|
import { OrderModule } from '../../modules/Order';
|
|
5
|
-
import type { AddProductBookingInput, LoadSalesDetailParams, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder, OrderSummary, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions } from '../../modules/Order/types';
|
|
5
|
+
import type { AddProductBookingInput, AddProductToOrderOptions, LoadSalesDetailParams, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder, OrderSummary, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, ReplaceTempOrderOptions } 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';
|
|
@@ -109,6 +109,16 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
109
109
|
private applyQuotationScheduleResolver;
|
|
110
110
|
private loadQuotationForPriceQuery;
|
|
111
111
|
private getPriceQueryProductId;
|
|
112
|
+
/**
|
|
113
|
+
* Change Time / customer reprice 必须沿用商品列表的渠道口径。
|
|
114
|
+
* SalesSdk Provider 通常将渠道存为 platform,因此不能只读取 otherParams.channel。
|
|
115
|
+
*/
|
|
116
|
+
private getPriceQueryChannel;
|
|
117
|
+
/**
|
|
118
|
+
* /product/query 的智能定价评估只读取 strategy_context;
|
|
119
|
+
* application_code 仅作为接口兼容字段,不能替代 channel / business_code。
|
|
120
|
+
*/
|
|
121
|
+
private getPriceQueryStrategyContext;
|
|
112
122
|
private getPriceQuerySchedule;
|
|
113
123
|
private loadProductsForPriceQuery;
|
|
114
124
|
private loadProductForPriceQuery;
|
|
@@ -182,7 +192,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
182
192
|
/** 获取附加费用(运费/服务费/税费等)。 */
|
|
183
193
|
getSurcharges(): ISalesSurcharge[];
|
|
184
194
|
getTempOrder(): OrderTempOrder | null;
|
|
185
|
-
replaceTempOrder(tempOrder: OrderTempOrder): Promise<OrderTempOrder>;
|
|
195
|
+
replaceTempOrder(tempOrder: OrderTempOrder, options?: ReplaceTempOrderOptions): Promise<OrderTempOrder>;
|
|
186
196
|
getOrderIdentity(): import("../../modules/Order/types").OrderIdentitySnapshot | null;
|
|
187
197
|
getOrderSnapshot(): import("../../modules/Order/types").OrderSnapshot | null;
|
|
188
198
|
getOrderSyncState(): import("../../modules/Order/types").OrderSyncState;
|
|
@@ -423,7 +433,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
423
433
|
getQuotationCustomerScopeInfo(): BaseSalesQuotationCustomerScopeInfo;
|
|
424
434
|
shouldRecalculateProductBookingPricesForContextChange(params: BaseSalesPriceRecalculationContextChange): boolean;
|
|
425
435
|
calculateProductBookingPrices(paramsList: BaseSalesCalculateProductBookingPriceParams[]): Promise<BaseSalesProductBookingPriceResult[]>;
|
|
426
|
-
addProductToOrder(product: Partial<BaseSalesOrderProduct> & BaseSalesOrderProductIdentity, booking?: AddProductBookingInput): Promise<import("../../modules/Order/types").OrderProduct[]>;
|
|
436
|
+
addProductToOrder(product: Partial<BaseSalesOrderProduct> & BaseSalesOrderProductIdentity, booking?: AddProductBookingInput, options?: AddProductToOrderOptions): Promise<import("../../modules/Order/types").OrderProduct[]>;
|
|
427
437
|
updateOrderProduct(params: UpdateOrderProductParams): Promise<import("../../modules/Order/types").OrderProduct[]>;
|
|
428
438
|
updateOrderProducts(paramsList: UpdateOrderProductParams[]): Promise<import("../../modules/Order/types").OrderProduct[]>;
|
|
429
439
|
updateOrderProductQuantity(params: BaseSalesUpdateOrderProductQuantityParams): Promise<import("../../modules/Order/types").OrderProduct[]>;
|
|
@@ -439,8 +449,8 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
439
449
|
* @example
|
|
440
450
|
* await baseSales.removeProductsFromOrder([identityA, identityB]);
|
|
441
451
|
*/
|
|
442
|
-
removeProductsFromOrder(identities: BaseSalesOrderProductIdentity[]): Promise<import("../../modules/Order/types").OrderProduct[]>;
|
|
443
|
-
removeProductFromOrder(identity: BaseSalesOrderProductIdentity): Promise<import("../../modules/Order/types").OrderProduct[]>;
|
|
452
|
+
removeProductsFromOrder(identities: BaseSalesOrderProductIdentity[], options?: RemoveProductsFromOrderOptions): Promise<import("../../modules/Order/types").OrderProduct[]>;
|
|
453
|
+
removeProductFromOrder(identity: BaseSalesOrderProductIdentity, options?: RemoveProductsFromOrderOptions): Promise<import("../../modules/Order/types").OrderProduct[]>;
|
|
444
454
|
/**
|
|
445
455
|
* 注入促销评估器到底层 OrderModule。
|
|
446
456
|
*
|
|
@@ -73,8 +73,11 @@ function isRejectedSalesSubmitResult(result) {
|
|
|
73
73
|
return candidates.some((candidate) => {
|
|
74
74
|
if (!candidate || typeof candidate !== "object")
|
|
75
75
|
return false;
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
if (candidate.code !== void 0 && candidate.code !== 200 && candidate.code !== "200") {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
const statusCode = Number(candidate.statusCode);
|
|
80
|
+
if (Number.isFinite(statusCode) && statusCode >= 400)
|
|
78
81
|
return true;
|
|
79
82
|
if (candidate.status === false || candidate.success === false || candidate.result === false) {
|
|
80
83
|
return true;
|
|
@@ -84,9 +87,9 @@ function isRejectedSalesSubmitResult(result) {
|
|
|
84
87
|
);
|
|
85
88
|
});
|
|
86
89
|
}
|
|
87
|
-
function getSalesSubmitErrorMessage(result) {
|
|
90
|
+
function getSalesSubmitErrorMessage(result, fallbackMessage) {
|
|
88
91
|
var _a, _b;
|
|
89
|
-
return (result == null ? void 0 : result.message) || (result == null ? void 0 : result.msg) || ((_a = result == null ? void 0 : result.data) == null ? void 0 : _a.message) || ((_b = result == null ? void 0 : result.data) == null ? void 0 : _b.msg) ||
|
|
92
|
+
return (result == null ? void 0 : result.message) || (result == null ? void 0 : result.msg) || ((_a = result == null ? void 0 : result.data) == null ? void 0 : _a.message) || ((_b = result == null ? void 0 : result.data) == null ? void 0 : _b.msg) || fallbackMessage;
|
|
90
93
|
}
|
|
91
94
|
function toWalletFundValue(value) {
|
|
92
95
|
try {
|
|
@@ -703,6 +706,36 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
703
706
|
return null;
|
|
704
707
|
return productId;
|
|
705
708
|
}
|
|
709
|
+
/**
|
|
710
|
+
* Change Time / customer reprice 必须沿用商品列表的渠道口径。
|
|
711
|
+
* SalesSdk Provider 通常将渠道存为 platform,因此不能只读取 otherParams.channel。
|
|
712
|
+
*/
|
|
713
|
+
getPriceQueryChannel(channel) {
|
|
714
|
+
var _a, _b, _c;
|
|
715
|
+
const strategyContext = ((_a = this.otherParams) == null ? void 0 : _a.strategy_context) && typeof this.otherParams.strategy_context === "object" ? this.otherParams.strategy_context : {};
|
|
716
|
+
const value = channel ?? strategyContext.channel ?? ((_b = this.otherParams) == null ? void 0 : _b.channel) ?? ((_c = this.otherParams) == null ? void 0 : _c.platform);
|
|
717
|
+
if (value === void 0 || value === null || String(value).trim() === "") {
|
|
718
|
+
return void 0;
|
|
719
|
+
}
|
|
720
|
+
return String(value).trim();
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* /product/query 的智能定价评估只读取 strategy_context;
|
|
724
|
+
* application_code 仅作为接口兼容字段,不能替代 channel / business_code。
|
|
725
|
+
*/
|
|
726
|
+
getPriceQueryStrategyContext(channel) {
|
|
727
|
+
var _a, _b, _c;
|
|
728
|
+
const inherited = ((_a = this.otherParams) == null ? void 0 : _a.strategy_context) && typeof this.otherParams.strategy_context === "object" ? this.otherParams.strategy_context : {};
|
|
729
|
+
const strategyContext = { ...inherited };
|
|
730
|
+
const resolvedChannel = this.getPriceQueryChannel(channel);
|
|
731
|
+
const businessCode = strategyContext.business_code ?? ((_b = this.otherParams) == null ? void 0 : _b.businessCode) ?? ((_c = this.otherParams) == null ? void 0 : _c.business_code);
|
|
732
|
+
if (resolvedChannel)
|
|
733
|
+
strategyContext.channel = resolvedChannel;
|
|
734
|
+
if (businessCode !== void 0 && businessCode !== null && String(businessCode).trim() !== "") {
|
|
735
|
+
strategyContext.business_code = String(businessCode).trim();
|
|
736
|
+
}
|
|
737
|
+
return strategyContext;
|
|
738
|
+
}
|
|
706
739
|
getPriceQuerySchedule(params) {
|
|
707
740
|
const booking = params.booking || {};
|
|
708
741
|
if (typeof booking.start_date === "string" && booking.start_date.trim()) {
|
|
@@ -730,13 +763,15 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
730
763
|
};
|
|
731
764
|
}
|
|
732
765
|
async loadProductsForPriceQuery(params) {
|
|
733
|
-
var _a
|
|
766
|
+
var _a;
|
|
734
767
|
const ids = Array.from(new Set(
|
|
735
768
|
params.ids.filter((id) => Number.isFinite(id))
|
|
736
769
|
));
|
|
737
770
|
const productsById = /* @__PURE__ */ new Map();
|
|
738
771
|
if (!ids.length || !this.request)
|
|
739
772
|
return productsById;
|
|
773
|
+
const channel = this.getPriceQueryChannel(params.channel);
|
|
774
|
+
const strategyContext = this.getPriceQueryStrategyContext(channel);
|
|
740
775
|
try {
|
|
741
776
|
const response = await this.request.post("/product/query", {
|
|
742
777
|
ids,
|
|
@@ -748,13 +783,14 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
748
783
|
customer_id: params.customerId,
|
|
749
784
|
schedule_date: params.schedule.schedule_date,
|
|
750
785
|
schedule_datetime: params.schedule.schedule_datetime,
|
|
751
|
-
application_code:
|
|
786
|
+
application_code: channel,
|
|
787
|
+
...Object.keys(strategyContext).length ? { strategy_context: strategyContext } : {}
|
|
752
788
|
}, {
|
|
753
789
|
osServer: true,
|
|
754
790
|
customToast: () => {
|
|
755
791
|
}
|
|
756
792
|
});
|
|
757
|
-
const list = ((
|
|
793
|
+
const list = ((_a = response == null ? void 0 : response.data) == null ? void 0 : _a.list) || (response == null ? void 0 : response.list) || [];
|
|
758
794
|
if (!Array.isArray(list))
|
|
759
795
|
return productsById;
|
|
760
796
|
list.forEach((item) => {
|
|
@@ -1203,10 +1239,10 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1203
1239
|
const result = ((_a = this.store.order) == null ? void 0 : _a.getTempOrder()) || null;
|
|
1204
1240
|
return result;
|
|
1205
1241
|
}
|
|
1206
|
-
async replaceTempOrder(tempOrder) {
|
|
1242
|
+
async replaceTempOrder(tempOrder, options) {
|
|
1207
1243
|
if (!this.store.order)
|
|
1208
1244
|
throw new Error("order 模块未初始化");
|
|
1209
|
-
const nextTempOrder = await this.store.order.replaceTempOrder(tempOrder);
|
|
1245
|
+
const nextTempOrder = await this.store.order.replaceTempOrder(tempOrder, options);
|
|
1210
1246
|
await this.effectsEmit("onTempOrderReplaced", { tempOrder: nextTempOrder });
|
|
1211
1247
|
return nextTempOrder;
|
|
1212
1248
|
}
|
|
@@ -2766,7 +2802,9 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
2766
2802
|
confirmPendingVoucherPayments: true
|
|
2767
2803
|
});
|
|
2768
2804
|
if (isRejectedSalesSubmitResult(submitResult)) {
|
|
2769
|
-
throw new Error(
|
|
2805
|
+
throw new Error(
|
|
2806
|
+
getSalesSubmitErrorMessage(submitResult, "Wallet 支付确认失败")
|
|
2807
|
+
);
|
|
2770
2808
|
}
|
|
2771
2809
|
} catch (error) {
|
|
2772
2810
|
this.store.order.setOrderPayments(beforePayments);
|
|
@@ -2869,6 +2907,11 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
2869
2907
|
smallTicketDataFlag: 1,
|
|
2870
2908
|
confirmPendingVoucherPayments: true
|
|
2871
2909
|
});
|
|
2910
|
+
if (isRejectedSalesSubmitResult(syncResult.submitResult)) {
|
|
2911
|
+
throw new Error(
|
|
2912
|
+
getSalesSubmitErrorMessage(syncResult.submitResult, "订单提交失败")
|
|
2913
|
+
);
|
|
2914
|
+
}
|
|
2872
2915
|
if (this.store.payment) {
|
|
2873
2916
|
const committed = this.getCommittedWalletAssets();
|
|
2874
2917
|
const walletState = this.store.payment.wallet.setCommittedWalletAssets(
|
|
@@ -2979,6 +3022,11 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
2979
3022
|
smallTicketDataFlag: 1,
|
|
2980
3023
|
confirmPendingVoucherPayments: true
|
|
2981
3024
|
});
|
|
3025
|
+
if (isRejectedSalesSubmitResult(syncResult.submitResult)) {
|
|
3026
|
+
throw new Error(
|
|
3027
|
+
getSalesSubmitErrorMessage(syncResult.submitResult, "订单提交失败")
|
|
3028
|
+
);
|
|
3029
|
+
}
|
|
2982
3030
|
if (this.store.payment) {
|
|
2983
3031
|
const committed = this.getCommittedWalletAssets();
|
|
2984
3032
|
const walletState = this.store.payment.wallet.setCommittedWalletAssets(
|
|
@@ -3200,11 +3248,11 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
3200
3248
|
});
|
|
3201
3249
|
});
|
|
3202
3250
|
}
|
|
3203
|
-
async addProductToOrder(product, booking) {
|
|
3251
|
+
async addProductToOrder(product, booking, options) {
|
|
3204
3252
|
try {
|
|
3205
3253
|
if (!this.store.order)
|
|
3206
3254
|
throw new Error("order 模块未初始化");
|
|
3207
|
-
const products = await this.store.order.addProductToOrder(product, booking);
|
|
3255
|
+
const products = await this.store.order.addProductToOrder(product, booking, options);
|
|
3208
3256
|
return products;
|
|
3209
3257
|
} catch (error) {
|
|
3210
3258
|
throw error;
|
|
@@ -3280,17 +3328,17 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
3280
3328
|
* @example
|
|
3281
3329
|
* await baseSales.removeProductsFromOrder([identityA, identityB]);
|
|
3282
3330
|
*/
|
|
3283
|
-
async removeProductsFromOrder(identities) {
|
|
3331
|
+
async removeProductsFromOrder(identities, options) {
|
|
3284
3332
|
try {
|
|
3285
3333
|
if (!this.store.order)
|
|
3286
3334
|
throw new Error("order 模块未初始化");
|
|
3287
|
-
return await this.store.order.removeProductsFromOrder(identities);
|
|
3335
|
+
return await this.store.order.removeProductsFromOrder(identities, options);
|
|
3288
3336
|
} catch (error) {
|
|
3289
3337
|
throw error;
|
|
3290
3338
|
}
|
|
3291
3339
|
}
|
|
3292
|
-
async removeProductFromOrder(identity) {
|
|
3293
|
-
return this.removeProductsFromOrder([identity]);
|
|
3340
|
+
async removeProductFromOrder(identity, options) {
|
|
3341
|
+
return this.removeProductsFromOrder([identity], options);
|
|
3294
3342
|
}
|
|
3295
3343
|
// ─── 促销/赠品 透传(迁移自 booking usePromotion) ────────────────
|
|
3296
3344
|
/**
|
|
@@ -366,9 +366,33 @@ function getProductLineNoteSignature(product) {
|
|
|
366
366
|
const uid = getOrderProductUid(product);
|
|
367
367
|
return uid ? `note:${uid}` : `note:${normalizedNote}`;
|
|
368
368
|
}
|
|
369
|
+
function hasGoodPassDiscount(product) {
|
|
370
|
+
var _a, _b;
|
|
371
|
+
const productBundle = Array.isArray(product == null ? void 0 : product.product_bundle) ? product.product_bundle : [];
|
|
372
|
+
const extendedBundle = Array.isArray((_b = (_a = product == null ? void 0 : product._extend) == null ? void 0 : _a.other) == null ? void 0 : _b.bundle) ? product._extend.other.bundle : [];
|
|
373
|
+
const discountLists = [
|
|
374
|
+
product == null ? void 0 : product.discount_list,
|
|
375
|
+
...productBundle.map((item) => item == null ? void 0 : item.discount_list),
|
|
376
|
+
...extendedBundle.map((item) => item == null ? void 0 : item.discount_list)
|
|
377
|
+
];
|
|
378
|
+
return discountLists.some(
|
|
379
|
+
(discountList) => Array.isArray(discountList) && discountList.some(
|
|
380
|
+
(item) => (item == null ? void 0 : item.type) === "good_pass" || (item == null ? void 0 : item.tag) === "good_pass"
|
|
381
|
+
)
|
|
382
|
+
);
|
|
383
|
+
}
|
|
369
384
|
function getPromotionLineMergeBoundary(product) {
|
|
370
|
-
var _a;
|
|
371
|
-
if ((
|
|
385
|
+
var _a, _b;
|
|
386
|
+
if ((product == null ? void 0 : product.product_id) === void 0 || (product == null ? void 0 : product.product_id) === null) {
|
|
387
|
+
return `custom:${getOrderProductUid(product)}`;
|
|
388
|
+
}
|
|
389
|
+
if (hasGoodPassDiscount(product)) {
|
|
390
|
+
return `good-pass:${getOrderProductUid(product)}`;
|
|
391
|
+
}
|
|
392
|
+
if (Number(((_a = product == null ? void 0 : product.product_sku) == null ? void 0 : _a.open_sold_weight) || 0) === 1) {
|
|
393
|
+
return `weighing:${getOrderProductUid(product)}`;
|
|
394
|
+
}
|
|
395
|
+
if (((_b = product == null ? void 0 : product.metadata) == null ? void 0 : _b.is_edit_for_runtime) !== true)
|
|
372
396
|
return "";
|
|
373
397
|
return `edit:${getOrderProductUid(product)}`;
|
|
374
398
|
}
|
|
@@ -217,7 +217,7 @@ function transformBaseProductToOrderProduct(params) {
|
|
|
217
217
|
}
|
|
218
218
|
const productTitle = {
|
|
219
219
|
...(sourceProduct == null ? void 0 : sourceProduct.title_i18n) || {},
|
|
220
|
-
original: (sourceProduct == null ? void 0 : sourceProduct.title) || ""
|
|
220
|
+
original: (sourceProduct == null ? void 0 : sourceProduct.original_title) || (sourceProduct == null ? void 0 : sourceProduct.title) || ""
|
|
221
221
|
};
|
|
222
222
|
return {
|
|
223
223
|
product_id: productId,
|
|
@@ -60,33 +60,44 @@ function createEmptySummary() {
|
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
function buildProductLineFingerprint(productOptionItem, productBundle) {
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
63
|
+
const normalizeOptions = (options) => {
|
|
64
|
+
const optionArr = Array.isArray(options) ? options : [];
|
|
65
|
+
return optionArr.map((item) => ({
|
|
66
|
+
option_group_item_id: Number(item == null ? void 0 : item.option_group_item_id) || 0,
|
|
67
|
+
option_group_id: Number(item == null ? void 0 : item.option_group_id) || 0,
|
|
68
|
+
num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
|
|
69
|
+
price: String((item == null ? void 0 : item.add_price) ?? (item == null ? void 0 : item.price) ?? "")
|
|
70
|
+
})).sort((p, q) => {
|
|
71
|
+
if (p.option_group_item_id !== q.option_group_item_id) {
|
|
72
|
+
return p.option_group_item_id - q.option_group_item_id;
|
|
73
|
+
}
|
|
74
|
+
if (p.option_group_id !== q.option_group_id) {
|
|
75
|
+
return p.option_group_id - q.option_group_id;
|
|
76
|
+
}
|
|
77
|
+
if (p.num !== q.num)
|
|
78
|
+
return p.num - q.num;
|
|
79
|
+
return p.price.localeCompare(q.price);
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
const normalizedOpts = normalizeOptions(productOptionItem);
|
|
79
83
|
const bundleArr = Array.isArray(productBundle) ? productBundle : [];
|
|
80
84
|
const normalizedBundles = bundleArr.map((item) => ({
|
|
81
85
|
bundle_id: Number((item == null ? void 0 : item.bundle_id) ?? (item == null ? void 0 : item.id) ?? 0) || 0,
|
|
82
86
|
product_id: Number(item == null ? void 0 : item.product_id) || 0,
|
|
83
|
-
|
|
87
|
+
product_variant_id: Number((item == null ? void 0 : item.bundle_variant_id) ?? (item == null ? void 0 : item.product_variant_id)) || 0,
|
|
88
|
+
num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
|
|
89
|
+
option: normalizeOptions(item == null ? void 0 : item.option)
|
|
84
90
|
})).sort((p, q) => {
|
|
85
91
|
if (p.bundle_id !== q.bundle_id)
|
|
86
92
|
return p.bundle_id - q.bundle_id;
|
|
87
93
|
if (p.product_id !== q.product_id)
|
|
88
94
|
return p.product_id - q.product_id;
|
|
89
|
-
|
|
95
|
+
if (p.product_variant_id !== q.product_variant_id) {
|
|
96
|
+
return p.product_variant_id - q.product_variant_id;
|
|
97
|
+
}
|
|
98
|
+
if (p.num !== q.num)
|
|
99
|
+
return p.num - q.num;
|
|
100
|
+
return JSON.stringify(p.option).localeCompare(JSON.stringify(q.option));
|
|
90
101
|
});
|
|
91
102
|
return JSON.stringify([normalizedOpts, normalizedBundles]);
|
|
92
103
|
}
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 |
|
|
329
|
+
weekNum: 0 | 2 | 1 | 6 | 4 | 3 | 5;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -447,7 +447,19 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
447
447
|
* 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
|
|
448
448
|
* 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
|
|
449
449
|
*/
|
|
450
|
-
decideAddProduct(item: any, options?: Partial<AddProductDecideContext>):
|
|
450
|
+
decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): {
|
|
451
|
+
action: "reloadCatalog";
|
|
452
|
+
} | {
|
|
453
|
+
action: "add";
|
|
454
|
+
cacheItem: any;
|
|
455
|
+
} | {
|
|
456
|
+
action: "requiresDetail";
|
|
457
|
+
payload: AddProductRequiresDetailPayload;
|
|
458
|
+
} | {
|
|
459
|
+
action: "requiresBookingEdit";
|
|
460
|
+
cacheItem: any;
|
|
461
|
+
payload: import("./utils/addProductDecision").AddProductRequiresBookingEditPayload;
|
|
462
|
+
};
|
|
451
463
|
/** 规格弹窗 callback 后的第二段决策。 */
|
|
452
464
|
decideAfterDetail(cacheItem: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
|
|
453
465
|
/**
|
|
@@ -242,6 +242,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
242
242
|
}
|
|
243
243
|
async configureIdGeneratorFromOpenData() {
|
|
244
244
|
this.setPaymentNumberDevicePrefix(null);
|
|
245
|
+
const idGenerator = this.getIdGeneratorPlugin();
|
|
246
|
+
if (!(idGenerator == null ? void 0 : idGenerator.configure)) {
|
|
247
|
+
console.warn("[BookingTicket] idGenerator 插件不可用,跳过配置");
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
245
250
|
let openDataConfig = null;
|
|
246
251
|
try {
|
|
247
252
|
openDataConfig = await this.loadOpenDataConfig();
|
|
@@ -249,11 +254,6 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
249
254
|
console.warn("[BookingTicket] OpenData 配置加载失败,跳过 idGenerator 配置", error);
|
|
250
255
|
return;
|
|
251
256
|
}
|
|
252
|
-
const idGenerator = this.getIdGeneratorPlugin();
|
|
253
|
-
if (!(idGenerator == null ? void 0 : idGenerator.configure)) {
|
|
254
|
-
console.warn("[BookingTicket] idGenerator 插件不可用,跳过配置");
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
257
|
const receiptSequenceLength = this.normalizePositiveInteger(
|
|
258
258
|
openDataConfig == null ? void 0 : openDataConfig["sale.short_number_digits"],
|
|
259
259
|
5
|
|
@@ -1599,10 +1599,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1599
1599
|
});
|
|
1600
1600
|
}
|
|
1601
1601
|
if (typeof this.store.order.addProductsToOrder === "function") {
|
|
1602
|
-
return this.store.order.addProductsToOrder(orderLines
|
|
1603
|
-
skipEditDiscountConfigRefresh: true,
|
|
1604
|
-
skipDiscountRecalculation: true
|
|
1605
|
-
});
|
|
1602
|
+
return this.store.order.addProductsToOrder(orderLines);
|
|
1606
1603
|
}
|
|
1607
1604
|
const result = [];
|
|
1608
1605
|
for (const line of orderLines) {
|
|
@@ -118,12 +118,15 @@ export interface BookingTicketCartBookingView extends ISalesBooking {
|
|
|
118
118
|
canAddTime: boolean;
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
|
+
export type BookingTicketCartLineView = BookingTicketCartBookingView | BookingTicketCartItemView;
|
|
121
122
|
/**
|
|
122
123
|
* BookingTicket 面向 UI 的购物车视图。
|
|
123
124
|
*/
|
|
124
125
|
export interface BookingTicketCartView {
|
|
125
126
|
bookings: BookingTicketCartBookingView[];
|
|
126
127
|
items: BookingTicketCartItemView[];
|
|
128
|
+
/** 以 tempOrder.products 为唯一顺序真源的统一购物车行(旧到新)。 */
|
|
129
|
+
lines: BookingTicketCartLineView[];
|
|
127
130
|
}
|
|
128
131
|
/**
|
|
129
132
|
* BookingTicket 面向 UI 的客户展示视图。
|
|
@@ -86,29 +86,27 @@ function isGiftProductLine(line) {
|
|
|
86
86
|
function buildCartView(lines, bookings, options = {}) {
|
|
87
87
|
const productLines = Array.isArray(lines) ? lines : [];
|
|
88
88
|
const bookingList = Array.isArray(bookings) ? bookings : [];
|
|
89
|
+
const childBookings = bookingList.filter((booking) => booking.parent_id !== 0);
|
|
90
|
+
const bookingsByProductUid = indexBookingsByProductUid(childBookings);
|
|
89
91
|
const linesByUid = indexProductsByUid(productLines);
|
|
90
92
|
const addTimeLinesByBookingUid = indexAddTimeProductsByBookingUid(productLines);
|
|
91
|
-
const claimedUids = /* @__PURE__ */ new Set();
|
|
92
93
|
const claimedAddTimeLines = /* @__PURE__ */ new Set();
|
|
93
|
-
|
|
94
|
-
const
|
|
94
|
+
childBookings.forEach((booking) => {
|
|
95
|
+
const bookingUid = getBookingUid(booking);
|
|
96
|
+
if (!bookingUid)
|
|
97
|
+
return;
|
|
98
|
+
(addTimeLinesByBookingUid[bookingUid] || []).forEach((line) => {
|
|
99
|
+
claimedAddTimeLines.add(line);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
const claimedBookings = /* @__PURE__ */ new Set();
|
|
103
|
+
const cartBookings = [];
|
|
104
|
+
const items = [];
|
|
105
|
+
const orderedLines = [];
|
|
106
|
+
const buildBookingView = (booking, product) => {
|
|
95
107
|
const bookingUid = getBookingUid(booking);
|
|
96
|
-
let product = null;
|
|
97
|
-
if (uid !== void 0 && uid !== null && uid !== "") {
|
|
98
|
-
const key = String(uid);
|
|
99
|
-
if (!claimedUids.has(key)) {
|
|
100
|
-
const line = linesByUid[key];
|
|
101
|
-
if (isGiftProductLine(line))
|
|
102
|
-
return acc;
|
|
103
|
-
if (line) {
|
|
104
|
-
claimedUids.add(key);
|
|
105
|
-
product = line;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
108
|
const addTimeProduct = bookingUid ? addTimeLinesByBookingUid[bookingUid] || [] : [];
|
|
110
|
-
|
|
111
|
-
acc.push({
|
|
109
|
+
return {
|
|
112
110
|
...booking,
|
|
113
111
|
_extend: {
|
|
114
112
|
product,
|
|
@@ -122,21 +120,36 @@ function buildCartView(lines, bookings, options = {}) {
|
|
|
122
120
|
shopOpeningHours: options.shopOpeningHours
|
|
123
121
|
})
|
|
124
122
|
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const items = productLines.filter((line) => {
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
productLines.forEach((line) => {
|
|
129
126
|
var _a;
|
|
130
|
-
if (isGiftProductLine(line))
|
|
131
|
-
return
|
|
132
|
-
if (claimedAddTimeLines.has(line))
|
|
133
|
-
return false;
|
|
127
|
+
if (isGiftProductLine(line) || claimedAddTimeLines.has(line))
|
|
128
|
+
return;
|
|
134
129
|
const uid = (_a = line.metadata) == null ? void 0 : _a.unique_identification_number;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
const matchedBooking = uid === void 0 || uid === null || uid === "" ? void 0 : (bookingsByProductUid[String(uid)] || []).find(
|
|
131
|
+
(booking) => !claimedBookings.has(booking)
|
|
132
|
+
);
|
|
133
|
+
if (matchedBooking) {
|
|
134
|
+
claimedBookings.add(matchedBooking);
|
|
135
|
+
const bookingView = buildBookingView(matchedBooking, line);
|
|
136
|
+
cartBookings.push(bookingView);
|
|
137
|
+
orderedLines.push(bookingView);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
items.push(line);
|
|
141
|
+
orderedLines.push(line);
|
|
142
|
+
});
|
|
143
|
+
childBookings.forEach((booking) => {
|
|
144
|
+
if (claimedBookings.has(booking))
|
|
145
|
+
return;
|
|
146
|
+
const uid = booking == null ? void 0 : booking.product_uid;
|
|
147
|
+
const linkedProduct = uid === void 0 || uid === null || uid === "" ? null : linesByUid[String(uid)] || null;
|
|
148
|
+
if (isGiftProductLine(linkedProduct))
|
|
149
|
+
return;
|
|
150
|
+
cartBookings.push(buildBookingView(booking, null));
|
|
138
151
|
});
|
|
139
|
-
return { bookings: cartBookings, items };
|
|
152
|
+
return { bookings: cartBookings, items, lines: orderedLines };
|
|
140
153
|
}
|
|
141
154
|
function isWalkInCustomer(customer) {
|
|
142
155
|
if (!customer)
|
|
@@ -95,6 +95,7 @@ export declare class SalesImpl extends BaseModule implements Module, SalesModule
|
|
|
95
95
|
* 2) 若无 active,返回已超时且仍占用中的预约(允许并发多条)
|
|
96
96
|
* 3) 若仍无,返回最近一组未来预约(同 start_time 的并发预约全部返回)
|
|
97
97
|
* 4) 最后兜底返回一条(避免资源有历史预约时完全无反馈)
|
|
98
|
+
* - includeAllFuture 时,保留选中预约并返回当天全部后续预约;仅详情接口启用。
|
|
98
99
|
*/
|
|
99
100
|
private pickBookingsForCurrentPoint;
|
|
100
101
|
/**
|
|
@@ -316,8 +316,9 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
316
316
|
* 2) 若无 active,返回已超时且仍占用中的预约(允许并发多条)
|
|
317
317
|
* 3) 若仍无,返回最近一组未来预约(同 start_time 的并发预约全部返回)
|
|
318
318
|
* 4) 最后兜底返回一条(避免资源有历史预约时完全无反馈)
|
|
319
|
+
* - includeAllFuture 时,保留选中预约并返回当天全部后续预约;仅详情接口启用。
|
|
319
320
|
*/
|
|
320
|
-
pickBookingsForCurrentPoint(current, bookings) {
|
|
321
|
+
pickBookingsForCurrentPoint(current, bookings, options = {}) {
|
|
321
322
|
if (bookings.length === 0)
|
|
322
323
|
return [];
|
|
323
324
|
const currentDayStart = current.startOf("day");
|
|
@@ -334,6 +335,13 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
334
335
|
const appendNextStartGroupIfNeeded = (selectedBookings) => {
|
|
335
336
|
if (selectedBookings.length === 0)
|
|
336
337
|
return selectedBookings;
|
|
338
|
+
if (options.includeAllFuture) {
|
|
339
|
+
const allFutureBookings = dayScopedBookings.filter((booking) => {
|
|
340
|
+
const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
|
|
341
|
+
return startAt.isValid() && startAt.isAfter(current);
|
|
342
|
+
});
|
|
343
|
+
return [...selectedBookings, ...allFutureBookings];
|
|
344
|
+
}
|
|
337
345
|
const shouldAppendNextGroup = selectedBookings.some(
|
|
338
346
|
(booking) => booking.status === "reserved" || booking.status === "occupied"
|
|
339
347
|
);
|
|
@@ -384,6 +392,8 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
384
392
|
return startAt.isValid() && startAt.isAfter(current) && startAt.isSame(current, "day");
|
|
385
393
|
});
|
|
386
394
|
if (upcoming.length > 0) {
|
|
395
|
+
if (options.includeAllFuture)
|
|
396
|
+
return upcoming;
|
|
387
397
|
const firstStartAt = this.toBookingDateTime(upcoming[0].start_date, upcoming[0].start_time).valueOf();
|
|
388
398
|
const upcomingStartGroup = upcoming.filter((booking) => {
|
|
389
399
|
const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
|
|
@@ -638,7 +648,8 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
638
648
|
const unpaidBookingList = matchedBookingList.filter((booking) => this.isUnpaidBooking(booking));
|
|
639
649
|
const bookings = this.pickBookingsForCurrentPoint(
|
|
640
650
|
current,
|
|
641
|
-
this.normalizeResourceBookings(current, deviceCurrent, matchedBookingList)
|
|
651
|
+
this.normalizeResourceBookings(current, deviceCurrent, matchedBookingList),
|
|
652
|
+
{ includeAllFuture: true }
|
|
642
653
|
);
|
|
643
654
|
const completedBookings = completedBookingList.map((booking) => {
|
|
644
655
|
return {
|
|
@@ -654,7 +665,8 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
654
665
|
});
|
|
655
666
|
const unpaidBookings = this.pickBookingsForCurrentPoint(
|
|
656
667
|
current,
|
|
657
|
-
this.normalizeResourceBookings(current, deviceCurrent, unpaidBookingList)
|
|
668
|
+
this.normalizeResourceBookings(current, deviceCurrent, unpaidBookingList),
|
|
669
|
+
{ includeAllFuture: true }
|
|
658
670
|
);
|
|
659
671
|
const orderCount = this.countBookingOrders(statsBookingList);
|
|
660
672
|
const bookingCount = statsBookingList.length;
|