@pisell/pisellos 0.10.44 → 0.10.45
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/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
- package/dist/model/strategy/adapter/walletPass/evaluator.js +4 -2
- package/dist/modules/Customer/index.js +2 -1
- package/dist/modules/Discount/availability.d.ts +7 -0
- package/dist/modules/Discount/availability.js +49 -0
- package/dist/modules/Discount/index.d.ts +1 -3
- package/dist/modules/Discount/index.js +12 -151
- package/dist/modules/Discount/types.d.ts +6 -0
- package/dist/modules/Order/index.js +155 -130
- package/dist/modules/Order/utils.d.ts +1 -1
- package/dist/modules/Order/utils.js +84 -59
- package/dist/modules/Product/index.d.ts +1 -1
- package/dist/modules/Rules/index.js +50 -16
- package/dist/solution/BaseSales/types.d.ts +2 -2
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/ShopDiscount/index.d.ts +1 -0
- package/dist/solution/ShopDiscount/index.js +59 -22
- package/dist/solution/ShopDiscount/utils.d.ts +4 -2
- package/dist/solution/ShopDiscount/utils.js +40 -21
- package/lib/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
- package/lib/model/strategy/adapter/walletPass/evaluator.js +2 -0
- package/lib/modules/Customer/index.js +1 -0
- package/lib/modules/Discount/availability.d.ts +7 -0
- package/lib/modules/Discount/availability.js +43 -0
- package/lib/modules/Discount/index.d.ts +1 -3
- package/lib/modules/Discount/index.js +10 -131
- package/lib/modules/Discount/types.d.ts +6 -0
- package/lib/modules/Order/index.js +22 -8
- package/lib/modules/Order/utils.d.ts +1 -1
- package/lib/modules/Order/utils.js +20 -2
- package/lib/modules/Product/index.d.ts +1 -1
- package/lib/modules/Rules/index.js +42 -5
- package/lib/solution/BaseSales/types.d.ts +2 -2
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/ShopDiscount/index.d.ts +1 -0
- package/lib/solution/ShopDiscount/index.js +29 -3
- package/lib/solution/ShopDiscount/utils.d.ts +4 -2
- package/lib/solution/ShopDiscount/utils.js +39 -23
- package/package.json +1 -1
|
@@ -127,6 +127,7 @@ Object.defineProperty(exports, "syncManualProductDiscountProductNum", {
|
|
|
127
127
|
}
|
|
128
128
|
});
|
|
129
129
|
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
130
|
+
var _customParseFormat = _interopRequireDefault(require("dayjs/plugin/customParseFormat"));
|
|
130
131
|
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
131
132
|
var _utils = require("../Holder/utils");
|
|
132
133
|
var _utils2 = require("../../solution/ScanOrder/utils");
|
|
@@ -134,6 +135,7 @@ var _orderCollectionIdentity = require("./utils/orderCollectionIdentity");
|
|
|
134
135
|
var _salesNotes = require("./salesNotes");
|
|
135
136
|
var _manualProductDiscount = require("./utils/manualProductDiscount");
|
|
136
137
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
138
|
+
_dayjs.default.extend(_customParseFormat.default);
|
|
137
139
|
const POINT_CARD_SNAPSHOT_TAG = 'point_card';
|
|
138
140
|
const VIRTUAL_CURRENCY_SNAPSHOT_TAG = 'virtual_currency';
|
|
139
141
|
function isPlainObject(value) {
|
|
@@ -772,7 +774,23 @@ function resolveEffectivePerUnitDiscount(product) {
|
|
|
772
774
|
if (!Number.isFinite(originalPrice) || !Number.isFinite(finalPrice)) return fromList;
|
|
773
775
|
return fromList + (originalPrice - finalPrice);
|
|
774
776
|
}
|
|
775
|
-
function createDefaultOrderRulesHooks() {
|
|
777
|
+
function createDefaultOrderRulesHooks(getBookings) {
|
|
778
|
+
const getProductStartDate = product => {
|
|
779
|
+
const productUid = String(product.metadata?.unique_identification_number ?? product.unique_identification_number ?? '');
|
|
780
|
+
const bookingUid = String(product.booking_uid ?? product.metadata?.booking_uid ?? '');
|
|
781
|
+
// 每次读取当前 bookings,覆盖改期、订单回显以及直接调用 Rules 的选券入口。
|
|
782
|
+
const bookings = getBookings?.() || [];
|
|
783
|
+
const booking = bookings.find(item => productUid && String(item?.product_uid ?? item?.metadata?.product_uid ?? '') === productUid) || bookings.find(item => bookingUid && String(item?.metadata?.unique_identification_number ?? item?.booking_uid ?? '') === bookingUid);
|
|
784
|
+
if (booking) {
|
|
785
|
+
// 严格解析并保留 Invalid Date,让公共时间校验拒绝缺失/非法时间,避免回退到当前时间。
|
|
786
|
+
return (0, _dayjs.default)(`${booking.start_date} ${booking.start_time}`, ['YYYY-MM-DD HH:mm', 'YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD H:mm', 'YYYY-MM-DD H:mm:ss'], true);
|
|
787
|
+
}
|
|
788
|
+
if (getBookings && (bookingUid || product.booking_id || product.metadata?.booking_id)) {
|
|
789
|
+
return (0, _dayjs.default)('');
|
|
790
|
+
}
|
|
791
|
+
const legacyStartDate = product.metadata?.start_date || product.metadata?.startDate;
|
|
792
|
+
return legacyStartDate ? (0, _dayjs.default)(legacyStartDate) : undefined;
|
|
793
|
+
};
|
|
776
794
|
const toUnitPriceString = (totalLike, num) => {
|
|
777
795
|
const effectiveNum = Number(num) > 0 ? Number(num) : 1;
|
|
778
796
|
return new _decimal.default(Number(totalLike) || 0).dividedBy(effectiveNum).toDecimalPlaces(2).toString();
|
|
@@ -860,7 +878,7 @@ function createDefaultOrderRulesHooks() {
|
|
|
860
878
|
// 无券时会把 bundle 价还原成 original_price(手动改价套餐会从 20 回到 30)。
|
|
861
879
|
isManualDiscount: resolveRulesManualDiscountFlag(metadataAny),
|
|
862
880
|
holder_id: product.metadata?.holder_id,
|
|
863
|
-
startDate: product
|
|
881
|
+
startDate: getProductStartDate(product),
|
|
864
882
|
main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSum).toDecimalPlaces(2).toString() : undefined,
|
|
865
883
|
inPromotion: metadataAny._promotion?.inPromotion === true,
|
|
866
884
|
_promotion: metadataAny._promotion
|
|
@@ -49,5 +49,5 @@ export declare class Product extends BaseModule implements Module {
|
|
|
49
49
|
getCategories(): ProductCategory[];
|
|
50
50
|
setOtherParams(key: string, value: any): void;
|
|
51
51
|
getOtherParams(): any;
|
|
52
|
-
getProductType(): "
|
|
52
|
+
getProductType(): "duration" | "session" | "normal";
|
|
53
53
|
}
|
|
@@ -12,6 +12,7 @@ var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
|
12
12
|
var _lodashEs = require("lodash-es");
|
|
13
13
|
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
14
14
|
var _entitlementPass = require("../Discount/entitlementPass");
|
|
15
|
+
var _availability = require("../Discount/availability");
|
|
15
16
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
17
|
class RulesModule extends _BaseModule.BaseModule {
|
|
17
18
|
defaultName = 'rules';
|
|
@@ -240,7 +241,13 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
240
241
|
if (discount.isEditMode) {
|
|
241
242
|
editModeDiscount.push(discount);
|
|
242
243
|
} else {
|
|
243
|
-
|
|
244
|
+
// 试算不能把 config / 不可用原因写回原有选券;每次重新计算以清除旧原因。
|
|
245
|
+
addModeDiscount.push({
|
|
246
|
+
...discount,
|
|
247
|
+
usageLimitFailKey: (0, _availability.getDiscountUsageLimitFailKey)(discount),
|
|
248
|
+
reason: undefined,
|
|
249
|
+
reasonCode: (0, _availability.getDiscountUsageBlockReason)(discount)
|
|
250
|
+
});
|
|
244
251
|
}
|
|
245
252
|
});
|
|
246
253
|
|
|
@@ -481,8 +488,15 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
481
488
|
|
|
482
489
|
// 🔥 为每个折扣卡/商品券执行策略检查并附加config
|
|
483
490
|
const evaluator = this.getWalletPassEvaluator();
|
|
491
|
+
addModeDiscount.forEach(discount => {
|
|
492
|
+
if (discount.reasonCode) discount.config = {
|
|
493
|
+
isAvailable: false
|
|
494
|
+
};
|
|
495
|
+
});
|
|
484
496
|
if (evaluator) {
|
|
485
497
|
addModeDiscount.forEach(discount => {
|
|
498
|
+
// 即使没有匹配的动态策略,服务端状态和次数限制也不能被覆盖为可用。
|
|
499
|
+
if (discount.reasonCode) return;
|
|
486
500
|
const discountType = discount.tag || discount.type || '';
|
|
487
501
|
// 对两类全额抵扣卡和折扣卡执行附加策略检查。
|
|
488
502
|
if (['entitlement_pass', 'good_pass', 'discount_card', 'product_discount_card'].includes(discountType)) {
|
|
@@ -501,7 +515,7 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
501
515
|
balance: entitlementQuota?.type === 'unlimited' ? Number.MAX_SAFE_INTEGER : entitlementQuota?.type === 'limited' ? entitlementQuota.balance : Number(discount.balance || 0),
|
|
502
516
|
type: discountType,
|
|
503
517
|
product_id: discount.product_id,
|
|
504
|
-
unified_available_status: 1,
|
|
518
|
+
unified_available_status: discount.unified_available_status ?? 1,
|
|
505
519
|
available_product_type: discount.limited_relation_product_data?.type,
|
|
506
520
|
available_product_ids: discount.limited_relation_product_data?.product_ids
|
|
507
521
|
};
|
|
@@ -532,6 +546,8 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
532
546
|
discount.config = {
|
|
533
547
|
isAvailable: false
|
|
534
548
|
};
|
|
549
|
+
discount.reason = result.reason;
|
|
550
|
+
discount.reasonCode = result.reasonCode || 'not_meet_the_required_conditions';
|
|
535
551
|
}
|
|
536
552
|
}
|
|
537
553
|
});
|
|
@@ -672,6 +688,8 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
672
688
|
|
|
673
689
|
// 记录每个优惠券适用的商品详细信息
|
|
674
690
|
const discountApplicableProducts = new Map();
|
|
691
|
+
const discountTimeReasons = new Map();
|
|
692
|
+
const discountHolderMismatch = new Set();
|
|
675
693
|
|
|
676
694
|
// 初始化每个优惠券的适用性和可抵扣商品
|
|
677
695
|
addModeDiscount.forEach(discount => {
|
|
@@ -691,6 +709,7 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
691
709
|
|
|
692
710
|
// 辅助函数:检查商品是否对某个折扣卡可用
|
|
693
711
|
const checkItemApplicableForDiscount = (flatItem, discount) => {
|
|
712
|
+
if (discount.config?.isAvailable === false) return false;
|
|
694
713
|
let product;
|
|
695
714
|
if (flatItem.type === 'main') {
|
|
696
715
|
product = flatItem.product;
|
|
@@ -896,16 +915,23 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
896
915
|
isNeedHolder: resolveIsFormSubject(_tempVar) && !_tempVar?.isNormalProduct,
|
|
897
916
|
holder_id: _tempVar?.holder_id || product.holder_id
|
|
898
917
|
}, holders);
|
|
899
|
-
|
|
900
|
-
timeLimit =
|
|
918
|
+
const timeReason = (0, _utils.getDiscountTimeUnavailableReason)(discount, (product?.startDate || (0, _dayjs.default)()).format('YYYY-MM-DD HH:mm:ss'));
|
|
919
|
+
const timeLimit = !timeReason;
|
|
901
920
|
// 是符合折扣的商品
|
|
902
|
-
const
|
|
921
|
+
const isProductInScope = limitedData.type === 'product_all' && limitedData.filter !== 1 || limitedData.type === 'product_all' && limitedData.filter === 1 && !limitedData.exclude_product_ids.includes(product.id) || limitedData.product_ids && limitedData.product_ids.includes(product.id);
|
|
922
|
+
const isLimitedProduct = isProductInScope && isHolderMatch;
|
|
903
923
|
|
|
904
924
|
// 编辑的商品 使用了优惠券不可用
|
|
905
925
|
const isAvailableProduct = flatItem.type === 'main' ? !(product?.booking_id && product?.discount_list?.length && product?.discount_list?.every(discount => discount.id && ['entitlement_pass', 'good_pass', 'discount_card', 'product_discount_card'].includes(discount.tag || discount.type))) : !(flatItem?.booking_id && !!flatItem?.bundleItem?.discount_list?.length && flatItem?.bundleItem?.discount_list?.every(discount => discount.id));
|
|
906
926
|
|
|
907
927
|
// 套餐是否可用判断
|
|
908
928
|
const isBundleAvailable = this.checkPackageSubItemUsageRules(discount, flatItem);
|
|
929
|
+
if (isProductInScope && isBundleAvailable && !isItemRewardProductDiscount) {
|
|
930
|
+
const timeReasons = discountTimeReasons.get(discount.id) || [];
|
|
931
|
+
timeReasons.push(timeReason);
|
|
932
|
+
discountTimeReasons.set(discount.id, timeReasons);
|
|
933
|
+
if (!isHolderMatch && timeLimit) discountHolderMismatch.add(discount.id);
|
|
934
|
+
}
|
|
909
935
|
|
|
910
936
|
// 判断优惠券是否适用于该商品
|
|
911
937
|
if (isAvailableProduct && !isItemRewardProductDiscount && isLimitedProduct && timeLimit && isBundleAvailable && discount.config?.isAvailable && (!(0, _entitlementPass.isEntitlementPass)(discount) || (0, _entitlementPass.getRemainingEntitlementUses)(discount, 0, 1) > 0)) {
|
|
@@ -2028,11 +2054,19 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
2028
2054
|
|
|
2029
2055
|
// 根据是否有适用商品决定isAvailable
|
|
2030
2056
|
const isAvailable = applicableProducts.length > 0;
|
|
2057
|
+
const timeReasons = discountTimeReasons.get(discount.id) || [];
|
|
2058
|
+
const timeReason = timeReasons.length ? timeReasons.every(Boolean) ? timeReasons[0] : undefined : (0, _utils.getDiscountTimeUnavailableReason)(discount, (0, _dayjs.default)().format('YYYY-MM-DD HH:mm:ss'));
|
|
2059
|
+
const reasonCode = isAvailable ? undefined : (0, _availability.getDiscountUsageBlockReason)(discount) || timeReason || discount.reasonCode || (discountHolderMismatch.has(discount.id) ? 'holder_not_matched' : 'product_not_applicable');
|
|
2060
|
+
const availabilityReason = {
|
|
2061
|
+
reasonCode,
|
|
2062
|
+
reason: reasonCode && reasonCode === discount.reasonCode ? discount.reason : undefined
|
|
2063
|
+
};
|
|
2031
2064
|
|
|
2032
2065
|
// 如果此优惠券被明确设置为不选中,保持其状态,但正确设置isAvailable
|
|
2033
2066
|
if (typeof discount.isSelected === 'boolean' && discount.isSelected === false && discount.isManualSelect) {
|
|
2034
2067
|
return {
|
|
2035
2068
|
...discount,
|
|
2069
|
+
...availabilityReason,
|
|
2036
2070
|
isSelected: false,
|
|
2037
2071
|
isAvailable: isAvailable,
|
|
2038
2072
|
// 正确设置可用性
|
|
@@ -2046,6 +2080,8 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
2046
2080
|
if (isDiscountUsed(discount)) {
|
|
2047
2081
|
return {
|
|
2048
2082
|
...discount,
|
|
2083
|
+
reason: undefined,
|
|
2084
|
+
reasonCode: undefined,
|
|
2049
2085
|
isSelected: true,
|
|
2050
2086
|
isManualSelect: options?.scan ? false : discount.isManualSelect,
|
|
2051
2087
|
// 标记为可用,因为它已被应用
|
|
@@ -2068,6 +2104,7 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
2068
2104
|
}
|
|
2069
2105
|
return {
|
|
2070
2106
|
...discount,
|
|
2107
|
+
...availabilityReason,
|
|
2071
2108
|
// 如果有适用的商品,标记为可用
|
|
2072
2109
|
isAvailable: isAvailable,
|
|
2073
2110
|
isSelected,
|
|
@@ -441,10 +441,10 @@ export interface BaseSalesAddLogParams extends BaseSalesLogInput {
|
|
|
441
441
|
/** BaseSales.scanPromotionCode 对外的轻量结果(UI 可用 getDiscountList 或 scannedDiscountList 补 Holder) */
|
|
442
442
|
export interface BaseSalesScanCodeResult {
|
|
443
443
|
isAvailable: boolean;
|
|
444
|
-
/** 卡券已加入 Promotion
|
|
444
|
+
/** 卡券已加入 Promotion;可能因次数、时间或当前订单条件而暂时无法应用。 */
|
|
445
445
|
isAccepted?: boolean;
|
|
446
446
|
type?: 'server' | string;
|
|
447
447
|
unavailableReason?: 'time_limit' | string;
|
|
448
|
-
/**
|
|
448
|
+
/** 扫码卡券资料及最新可用状态,供 Holder 补全等流程使用。 */
|
|
449
449
|
scannedDiscountList?: Discount[];
|
|
450
450
|
}
|
|
@@ -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 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -43,6 +43,7 @@ export declare class ShopDiscountImpl extends BaseModule implements Module {
|
|
|
43
43
|
batchSearchByProductIds(productIds: number[]): Promise<Discount[]>;
|
|
44
44
|
scanCode(code: string, customerId?: number): Promise<{
|
|
45
45
|
isAvailable: boolean;
|
|
46
|
+
isAccepted?: boolean;
|
|
46
47
|
productList: Record<string, any>[];
|
|
47
48
|
discountList: Discount[];
|
|
48
49
|
type: "server" | "clientCalc";
|
|
@@ -10,6 +10,7 @@ var _Rules = require("../../modules/Rules");
|
|
|
10
10
|
var _entitlementPass = require("../../modules/Discount/entitlementPass");
|
|
11
11
|
var _utils = require("./utils");
|
|
12
12
|
var _types = require("../../modules/Rules/types");
|
|
13
|
+
var _availability = require("../../modules/Discount/availability");
|
|
13
14
|
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
14
15
|
var _lodashEs = require("lodash-es");
|
|
15
16
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -349,6 +350,7 @@ class ShopDiscountImpl extends _BaseModule.BaseModule {
|
|
|
349
350
|
const {
|
|
350
351
|
productList: newProductList,
|
|
351
352
|
discountList: newDiscountList,
|
|
353
|
+
evaluatedDiscountList,
|
|
352
354
|
isAvailable,
|
|
353
355
|
unavailableReason
|
|
354
356
|
} = rulesModule.isDiscountListAvailable({
|
|
@@ -363,6 +365,7 @@ class ShopDiscountImpl extends _BaseModule.BaseModule {
|
|
|
363
365
|
productList: this.store.productList || [],
|
|
364
366
|
discountList: this.getDiscountList()
|
|
365
367
|
};
|
|
368
|
+
let isAccepted = isAvailable;
|
|
366
369
|
if (isAvailable) {
|
|
367
370
|
this.setDiscountList(newDiscountList || []);
|
|
368
371
|
this.store.originalDiscountList = newDiscountList || [];
|
|
@@ -370,12 +373,34 @@ class ShopDiscountImpl extends _BaseModule.BaseModule {
|
|
|
370
373
|
if (this.isWalkIn() && resultDiscountList.length && this.options.otherParams?.platform === 'shop' && !((resultDiscountList[0].customer_id || 1) === 1)) {
|
|
371
374
|
await this.getCustomerWallet(resultDiscountList[0].customer_id);
|
|
372
375
|
}
|
|
376
|
+
} else {
|
|
377
|
+
const scannedIds = new Set(withScanList.map(discount => String(discount.id)));
|
|
378
|
+
const retainedScannedDiscounts = (evaluatedDiscountList || withScanList).filter(discount => scannedIds.has(String(discount.id)) && !(0, _availability.getDiscountLifecycleReason)(discount));
|
|
379
|
+
if (retainedScannedDiscounts.length) {
|
|
380
|
+
const retainedDiscounts = new Map(this.getDiscountList().map(discount => [String(discount.id), discount]));
|
|
381
|
+
retainedScannedDiscounts.forEach(discount => {
|
|
382
|
+
retainedDiscounts.set(String(discount.id), {
|
|
383
|
+
...discount,
|
|
384
|
+
isScan: true,
|
|
385
|
+
isAvailable: false,
|
|
386
|
+
isSelected: false,
|
|
387
|
+
reasonCode: discount.reasonCode || 'product_not_applicable',
|
|
388
|
+
appliedProductDetails: [],
|
|
389
|
+
savedAmount: 0
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
this.setDiscountList([...retainedDiscounts.values()]);
|
|
393
|
+
this.store.originalDiscountList = this.getDiscountList();
|
|
394
|
+
await this.store.discount?.setOriginalDiscountList(this.getDiscountList());
|
|
395
|
+
isAccepted = true;
|
|
396
|
+
}
|
|
373
397
|
}
|
|
374
398
|
return {
|
|
375
399
|
type: "clientCalc",
|
|
376
400
|
isAvailable: isAvailable || false,
|
|
401
|
+
isAccepted: Boolean(isAccepted),
|
|
377
402
|
productList: newProductList || this.store.productList || [],
|
|
378
|
-
discountList:
|
|
403
|
+
discountList: this.getDiscountList(),
|
|
379
404
|
unavailableReason
|
|
380
405
|
};
|
|
381
406
|
} catch (error) {
|
|
@@ -525,6 +550,7 @@ class ShopDiscountImpl extends _BaseModule.BaseModule {
|
|
|
525
550
|
with_discount_card: 1,
|
|
526
551
|
with_wallet_pass_holder: 1,
|
|
527
552
|
with_entitlement_pass: 1,
|
|
553
|
+
filter_order_wallet_pass_usage: 0,
|
|
528
554
|
request_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
529
555
|
...(orderId ? {
|
|
530
556
|
order_id: orderId
|
|
@@ -559,8 +585,8 @@ class ShopDiscountImpl extends _BaseModule.BaseModule {
|
|
|
559
585
|
this.store.originalDiscountList = newDiscountList;
|
|
560
586
|
await this.store.discount?.setOriginalDiscountList(newDiscountList);
|
|
561
587
|
|
|
562
|
-
//
|
|
563
|
-
const filteredDiscountList =
|
|
588
|
+
// 日程限制交给 Rules 计算可用状态,展示列表保留当前不可用的卡券。
|
|
589
|
+
const filteredDiscountList = newDiscountList;
|
|
564
590
|
this.store.filteredDiscountList = filteredDiscountList;
|
|
565
591
|
this.setDiscountList(filteredDiscountList || []);
|
|
566
592
|
if (this.store.productList?.length) {
|
|
@@ -59,12 +59,14 @@ export interface ScheduleItem {
|
|
|
59
59
|
}
|
|
60
60
|
export declare const getDateIsInSchedule: (dateTime: string, scheduleList: ScheduleItem[]) => boolean;
|
|
61
61
|
/**
|
|
62
|
-
*
|
|
62
|
+
* 根据商品使用时间过滤优惠券列表(预约开始时间或普通商品的当前时间)
|
|
63
63
|
* @param discountList 优惠券列表
|
|
64
|
-
* @param bookingTime
|
|
64
|
+
* @param bookingTime 使用时间 (格式: YYYY-MM-DD HH:mm:ss),未确定时不提前过滤
|
|
65
65
|
* @returns 过滤后的优惠券列表
|
|
66
66
|
*/
|
|
67
67
|
export declare const filterDiscountListByBookingTime: (discountList: Discount[], bookingTime: string | null) => Discount[];
|
|
68
|
+
/** 与抵扣计算共用时间判断,区分未开始、有效期不匹配和日程限制。 */
|
|
69
|
+
export declare const getDiscountTimeUnavailableReason: (discount: Discount, useTime: string) => 'not_started' | 'time_limit' | 'outside_schedule' | undefined;
|
|
68
70
|
/**
|
|
69
71
|
* 判断是否是订单级别的固定金额折扣卡
|
|
70
72
|
* @param discount 折扣
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.uniqueById = exports.isOrderLevelFixedAmountDiscount = exports.isNormalProductByDurationSchedule = exports.isAllNormalProduct = exports.getDiscountListAmountTotal = exports.getDiscountListAmount = exports.getDiscountAmount = exports.getDateIsInSchedule = exports.filterDiscountListByBookingTime = exports.calculateOrderLevelDiscountAllocation = void 0;
|
|
6
|
+
exports.uniqueById = exports.isOrderLevelFixedAmountDiscount = exports.isNormalProductByDurationSchedule = exports.isAllNormalProduct = exports.getDiscountTimeUnavailableReason = exports.getDiscountListAmountTotal = exports.getDiscountListAmount = exports.getDiscountAmount = exports.getDateIsInSchedule = exports.filterDiscountListByBookingTime = exports.calculateOrderLevelDiscountAllocation = void 0;
|
|
7
7
|
var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
8
8
|
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
9
|
+
var _isSameOrAfter = _interopRequireDefault(require("dayjs/plugin/isSameOrAfter"));
|
|
10
|
+
var _isSameOrBefore = _interopRequireDefault(require("dayjs/plugin/isSameOrBefore"));
|
|
9
11
|
var _entitlementPass = require("../../modules/Discount/entitlementPass");
|
|
10
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
+
_dayjs.default.extend(_isSameOrAfter.default);
|
|
14
|
+
_dayjs.default.extend(_isSameOrBefore.default);
|
|
11
15
|
const uniqueById = (arr, key = 'id') => {
|
|
12
16
|
const seen = new Set();
|
|
13
17
|
return arr.filter(item => !seen.has(item[key]) && seen.add(item[key]));
|
|
@@ -377,41 +381,53 @@ const isInWeeklyRepeatForDate = (targetDate, startDate, repeatRule) => {
|
|
|
377
381
|
};
|
|
378
382
|
|
|
379
383
|
/**
|
|
380
|
-
*
|
|
384
|
+
* 根据商品使用时间过滤优惠券列表(预约开始时间或普通商品的当前时间)
|
|
381
385
|
* @param discountList 优惠券列表
|
|
382
|
-
* @param bookingTime
|
|
386
|
+
* @param bookingTime 使用时间 (格式: YYYY-MM-DD HH:mm:ss),未确定时不提前过滤
|
|
383
387
|
* @returns 过滤后的优惠券列表
|
|
384
388
|
*/
|
|
385
389
|
const filterDiscountListByBookingTime = (discountList, bookingTime) => {
|
|
386
|
-
if (!bookingTime)
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
+
if (!bookingTime) return discountList;
|
|
391
|
+
return discountList.filter(discount => !getDiscountTimeUnavailableReason(discount, bookingTime));
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
/** 与抵扣计算共用时间判断,区分未开始、有效期不匹配和日程限制。 */
|
|
395
|
+
exports.filterDiscountListByBookingTime = filterDiscountListByBookingTime;
|
|
396
|
+
const getDiscountTimeUnavailableReason = (discount, useTime) => {
|
|
397
|
+
const useTimeDayjs = (0, _dayjs.default)(useTime);
|
|
398
|
+
if (!useTimeDayjs.isValid()) return 'time_limit';
|
|
399
|
+
try {
|
|
390
400
|
if (discount?.metadata?.validity_type === "custom_schedule_validity") {
|
|
391
|
-
return getDateIsInSchedule(
|
|
401
|
+
return getDateIsInSchedule(useTime, discount.custom_schedule_snapshot?.data || []) ? undefined : 'outside_schedule';
|
|
392
402
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
// 判断预约时间是否在过期时间之前(expire_time 为空时为长期有效)
|
|
402
|
-
const isBeforeExpire = discount.expire_time ? bookingTimeDayjs.isSameOrBefore((0, _dayjs.default)(discount.expire_time)) : true;
|
|
403
|
-
return isAfterStart && isBeforeExpire;
|
|
404
|
-
} catch (error) {
|
|
405
|
-
return true;
|
|
403
|
+
const isHasStart = !!discount.start_date && !!discount.start_time;
|
|
404
|
+
const startDate = (0, _dayjs.default)(`${discount.start_date} ${discount.start_time}`);
|
|
405
|
+
|
|
406
|
+
// 开始时刻包含在有效期内。
|
|
407
|
+
if (isHasStart) {
|
|
408
|
+
if (!startDate.isValid()) return 'time_limit';
|
|
409
|
+
if (useTimeDayjs.isBefore(startDate)) return 'not_started';
|
|
406
410
|
}
|
|
407
|
-
|
|
411
|
+
|
|
412
|
+
// 到期时刻不再可用;expire_time 为空时为长期有效。
|
|
413
|
+
const expireTime = discount.expire_time ? (0, _dayjs.default)(discount.expire_time) : null;
|
|
414
|
+
const isBeforeExpire = expireTime ? expireTime.isValid() && useTimeDayjs.isBefore(expireTime) : true;
|
|
415
|
+
if (!isBeforeExpire) return 'time_limit';
|
|
416
|
+
const validity = discount.extension_data?.find(field => field.field_key === 'valid_times')?.value;
|
|
417
|
+
if (validity?.restrict_use_by_schedule === true && !getDateIsInSchedule(useTime, discount.custom_schedule_snapshot?.data || [])) {
|
|
418
|
+
return 'outside_schedule';
|
|
419
|
+
}
|
|
420
|
+
return undefined;
|
|
421
|
+
} catch (error) {
|
|
422
|
+
return 'time_limit';
|
|
423
|
+
}
|
|
408
424
|
};
|
|
409
425
|
/**
|
|
410
426
|
* 判断是否是订单级别的固定金额折扣卡
|
|
411
427
|
* @param discount 折扣
|
|
412
428
|
* @returns 是否是订单级别的固定金额折扣卡
|
|
413
429
|
*/
|
|
414
|
-
exports.
|
|
430
|
+
exports.getDiscountTimeUnavailableReason = getDiscountTimeUnavailableReason;
|
|
415
431
|
const isOrderLevelFixedAmountDiscount = discount => {
|
|
416
432
|
return discount.tag === 'product_discount_card' && discount?.metadata?.discount_card_type === 'fixed_amount' && discount?.metadata?.discount_calculation_mode === 'order_level';
|
|
417
433
|
};
|