@pisell/pisellos 2.2.261 → 2.2.263
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/dataVariant/adapter.d.ts +50 -0
- package/dist/model/strategy/adapter/dataVariant/adapter.js +167 -0
- package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +89 -0
- package/dist/model/strategy/adapter/dataVariant/evaluator.js +780 -0
- package/dist/model/strategy/adapter/dataVariant/examples.d.ts +39 -0
- package/dist/model/strategy/adapter/dataVariant/examples.js +277 -0
- package/dist/model/strategy/adapter/dataVariant/index.d.ts +4 -0
- package/dist/model/strategy/adapter/dataVariant/index.js +4 -0
- package/dist/model/strategy/adapter/dataVariant/type.d.ts +148 -0
- package/dist/model/strategy/adapter/dataVariant/type.js +54 -0
- package/dist/model/strategy/adapter/index.d.ts +4 -0
- package/dist/model/strategy/adapter/index.js +5 -1
- package/dist/model/strategy/adapter/promotion/adapter.d.ts +0 -4
- package/dist/model/strategy/adapter/promotion/adapter.js +0 -23
- package/dist/model/strategy/adapter/promotion/evaluator.d.ts +0 -17
- package/dist/model/strategy/adapter/promotion/evaluator.js +6 -279
- package/dist/model/strategy/adapter/promotion/examples.d.ts +0 -86
- package/dist/model/strategy/adapter/promotion/examples.js +0 -99
- package/dist/model/strategy/adapter/promotion/index.d.ts +1 -1
- package/dist/model/strategy/adapter/promotion/index.js +1 -1
- package/dist/model/strategy/adapter/promotion/type.d.ts +2 -90
- package/dist/model/strategy/adapter/promotion/type.js +0 -45
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +16 -10
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +32 -1
- package/dist/modules/Discount/index.d.ts +5 -2
- package/dist/modules/Discount/index.js +30 -7
- package/dist/modules/Discount/types.d.ts +4 -0
- package/dist/modules/Order/index.d.ts +14 -2
- package/dist/modules/Order/index.js +1035 -736
- package/dist/modules/Order/types.d.ts +16 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.js +405 -0
- package/dist/modules/Order/utils.d.ts +4 -3
- package/dist/modules/Order/utils.js +54 -61
- package/dist/modules/Product/types.d.ts +22 -0
- package/dist/modules/ProductList/index.d.ts +1 -1
- package/dist/modules/ProductList/index.js +4 -2
- package/dist/modules/ProductList/types.d.ts +2 -0
- package/dist/modules/Rules/index.d.ts +2 -9
- package/dist/modules/Rules/index.js +69 -43
- package/dist/modules/Rules/types.d.ts +10 -1
- package/dist/server/index.d.ts +55 -0
- package/dist/server/index.js +1173 -753
- package/dist/server/modules/order/index.d.ts +10 -4
- package/dist/server/modules/order/index.js +404 -399
- package/dist/server/modules/order/types.d.ts +4 -0
- package/dist/server/modules/products/index.d.ts +31 -8
- package/dist/server/modules/products/index.js +549 -390
- package/dist/server/modules/products/types.d.ts +18 -0
- package/dist/solution/BaseSales/index.d.ts +21 -1
- package/dist/solution/BaseSales/index.js +1136 -789
- package/dist/solution/BaseSales/types.d.ts +6 -1
- package/dist/solution/BaseSales/types.js +1 -1
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +1 -3
- package/dist/solution/BaseSales/utils/cartPromotion.js +48 -81
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -3
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +6 -8
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +14 -1
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +59 -25
- package/dist/solution/BookingTicket/types.d.ts +2 -0
- package/dist/solution/ScanOrder/index.js +20 -31
- package/dist/solution/ShopDiscount/index.js +15 -14
- package/dist/solution/VenueBooking/index.js +19 -30
- package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +50 -0
- package/lib/model/strategy/adapter/dataVariant/adapter.js +149 -0
- package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +89 -0
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +583 -0
- package/lib/model/strategy/adapter/dataVariant/examples.d.ts +39 -0
- package/lib/model/strategy/adapter/dataVariant/examples.js +293 -0
- package/lib/model/strategy/adapter/dataVariant/index.d.ts +4 -0
- package/lib/model/strategy/adapter/dataVariant/index.js +38 -0
- package/lib/model/strategy/adapter/dataVariant/type.d.ts +148 -0
- package/lib/model/strategy/adapter/dataVariant/type.js +31 -0
- package/lib/model/strategy/adapter/index.d.ts +4 -0
- package/lib/model/strategy/adapter/index.js +13 -2
- package/lib/model/strategy/adapter/promotion/adapter.d.ts +0 -4
- package/lib/model/strategy/adapter/promotion/adapter.js +0 -20
- package/lib/model/strategy/adapter/promotion/evaluator.d.ts +0 -17
- package/lib/model/strategy/adapter/promotion/evaluator.js +0 -235
- package/lib/model/strategy/adapter/promotion/examples.d.ts +0 -86
- package/lib/model/strategy/adapter/promotion/examples.js +0 -91
- package/lib/model/strategy/adapter/promotion/index.d.ts +1 -1
- package/lib/model/strategy/adapter/promotion/index.js +0 -51
- package/lib/model/strategy/adapter/promotion/type.d.ts +2 -90
- package/lib/model/strategy/adapter/promotion/type.js +0 -2
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +5 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +1 -0
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +23 -2
- package/lib/modules/Discount/index.d.ts +5 -2
- package/lib/modules/Discount/index.js +23 -3
- package/lib/modules/Discount/types.d.ts +4 -0
- package/lib/modules/Order/index.d.ts +14 -2
- package/lib/modules/Order/index.js +326 -60
- package/lib/modules/Order/types.d.ts +16 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.js +415 -0
- package/lib/modules/Order/utils.d.ts +4 -3
- package/lib/modules/Order/utils.js +22 -23
- package/lib/modules/Product/types.d.ts +22 -0
- package/lib/modules/ProductList/index.d.ts +1 -1
- package/lib/modules/ProductList/index.js +4 -2
- package/lib/modules/ProductList/types.d.ts +2 -0
- package/lib/modules/Rules/index.d.ts +2 -9
- package/lib/modules/Rules/index.js +61 -29
- package/lib/modules/Rules/types.d.ts +10 -1
- package/lib/server/index.d.ts +55 -0
- package/lib/server/index.js +332 -34
- package/lib/server/modules/order/index.d.ts +10 -4
- package/lib/server/modules/order/index.js +198 -139
- package/lib/server/modules/order/types.d.ts +4 -0
- package/lib/server/modules/products/index.d.ts +31 -8
- package/lib/server/modules/products/index.js +134 -35
- package/lib/server/modules/products/types.d.ts +18 -0
- package/lib/solution/BaseSales/index.d.ts +21 -1
- package/lib/solution/BaseSales/index.js +313 -72
- package/lib/solution/BaseSales/types.d.ts +6 -1
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +1 -3
- package/lib/solution/BaseSales/utils/cartPromotion.js +29 -60
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -3
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +4 -5
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +8 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +33 -8
- package/lib/solution/BookingTicket/types.d.ts +2 -0
- package/lib/solution/ScanOrder/index.js +0 -8
- package/lib/solution/ShopDiscount/index.js +2 -1
- package/lib/solution/VenueBooking/index.js +0 -8
- package/package.json +1 -1
|
@@ -133,9 +133,6 @@ var PromotionEvaluator = class {
|
|
|
133
133
|
for (const product of products) {
|
|
134
134
|
const applicablePromotions = [];
|
|
135
135
|
for (const config of configs) {
|
|
136
|
-
if (this.shouldSkipStrategyForProduct(product, config)) {
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
136
|
const matchInfo = this.getProductMatchInfo(product, config);
|
|
140
137
|
if (!matchInfo.isMatch) {
|
|
141
138
|
continue;
|
|
@@ -299,16 +296,6 @@ var PromotionEvaluator = class {
|
|
|
299
296
|
if (result.giftInfo) {
|
|
300
297
|
gifts.push(result.giftInfo);
|
|
301
298
|
}
|
|
302
|
-
} else if (actionType === import_type.PROMOTION_ACTION_TYPES.ITEM_REWARD) {
|
|
303
|
-
const result = this.processItemReward(
|
|
304
|
-
group,
|
|
305
|
-
processedQuantityMap,
|
|
306
|
-
products,
|
|
307
|
-
matchedBundleIndexMap
|
|
308
|
-
);
|
|
309
|
-
pricedProducts.push(...result.products);
|
|
310
|
-
totalOriginalAmount = totalOriginalAmount.plus(result.originalAmount);
|
|
311
|
-
totalFinalAmount = totalFinalAmount.plus(result.finalAmount);
|
|
312
299
|
}
|
|
313
300
|
}
|
|
314
301
|
const remainingProducts = this.getRemainingProducts(
|
|
@@ -392,9 +379,6 @@ var PromotionEvaluator = class {
|
|
|
392
379
|
for (const product of products) {
|
|
393
380
|
const applicableStrategies = [];
|
|
394
381
|
for (const config of configs) {
|
|
395
|
-
if (this.shouldSkipStrategyForProduct(product, config)) {
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
382
|
let contextProduct = product;
|
|
399
383
|
if (!matchVariant) {
|
|
400
384
|
const productMatchRule = this.findProductMatchRule(config);
|
|
@@ -471,9 +455,6 @@ var PromotionEvaluator = class {
|
|
|
471
455
|
} else if (actionType === "X_ITEMS_FOR_Y_PRICE") {
|
|
472
456
|
const detail = actionDetail;
|
|
473
457
|
requiredQuantity = detail.x || 0;
|
|
474
|
-
} else if (actionType === "ITEM_REWARD") {
|
|
475
|
-
const detail = actionDetail;
|
|
476
|
-
requiredQuantity = detail.triggerQuantity || 1;
|
|
477
458
|
}
|
|
478
459
|
const productMatchRule = this.findProductMatchRule(config);
|
|
479
460
|
const eligibleProducts = (productMatchRule == null ? void 0 : productMatchRule.value) || [];
|
|
@@ -787,213 +768,6 @@ var PromotionEvaluator = class {
|
|
|
787
768
|
giftInfo
|
|
788
769
|
};
|
|
789
770
|
}
|
|
790
|
-
/**
|
|
791
|
-
* 处理 商品奖励 促销
|
|
792
|
-
*
|
|
793
|
-
* 1. 使用 group.products 统计触发条件商品数量
|
|
794
|
-
* 2. 按 quantityRule 计算最多奖励的目标商品数量
|
|
795
|
-
* 3. 在全购物车商品中筛选 rewardTargets
|
|
796
|
-
* 4. 按消费者最优(可节省金额从高到低)选择目标单位
|
|
797
|
-
* 5. 对目标商品拆分并写入 finalPrice,触发商品本身不改价
|
|
798
|
-
*/
|
|
799
|
-
processItemReward(group, processedQuantityMap, allProducts, matchedBundleIndexMap) {
|
|
800
|
-
const {
|
|
801
|
-
strategyId,
|
|
802
|
-
strategyMetadata,
|
|
803
|
-
actionDetail,
|
|
804
|
-
products: triggerProducts
|
|
805
|
-
} = group;
|
|
806
|
-
const detail = actionDetail;
|
|
807
|
-
const triggerQuantity = this.normalizePositiveInteger(detail.triggerQuantity, 1);
|
|
808
|
-
const rewardQuantity = this.normalizePositiveInteger(detail.rewardQuantity, 1);
|
|
809
|
-
const conditionQuantity = this.getAvailablePromotionQuantity(
|
|
810
|
-
triggerProducts,
|
|
811
|
-
processedQuantityMap,
|
|
812
|
-
matchedBundleIndexMap
|
|
813
|
-
);
|
|
814
|
-
if (conditionQuantity < triggerQuantity) {
|
|
815
|
-
return { products: [], originalAmount: 0, finalAmount: 0 };
|
|
816
|
-
}
|
|
817
|
-
const targetProducts = allProducts.filter(
|
|
818
|
-
(product) => this.isProductMatch(product, detail.rewardTargets || [])
|
|
819
|
-
);
|
|
820
|
-
const targetUnitCandidates = this.buildItemRewardTargetUnits(
|
|
821
|
-
targetProducts,
|
|
822
|
-
processedQuantityMap,
|
|
823
|
-
detail
|
|
824
|
-
);
|
|
825
|
-
if (targetUnitCandidates.length === 0) {
|
|
826
|
-
return { products: [], originalAmount: 0, finalAmount: 0 };
|
|
827
|
-
}
|
|
828
|
-
const rewardLimit = this.resolveItemRewardLimit(
|
|
829
|
-
detail,
|
|
830
|
-
conditionQuantity,
|
|
831
|
-
triggerQuantity,
|
|
832
|
-
rewardQuantity,
|
|
833
|
-
targetUnitCandidates.length
|
|
834
|
-
);
|
|
835
|
-
if (rewardLimit <= 0) {
|
|
836
|
-
return { products: [], originalAmount: 0, finalAmount: 0 };
|
|
837
|
-
}
|
|
838
|
-
const selectedUnits = [...targetUnitCandidates].sort((a, b) => {
|
|
839
|
-
const discountDiff = b.discountAmount.minus(a.discountAmount).toNumber();
|
|
840
|
-
if (discountDiff !== 0)
|
|
841
|
-
return discountDiff;
|
|
842
|
-
return b.originalPrice.minus(a.originalPrice).toNumber();
|
|
843
|
-
}).slice(0, rewardLimit);
|
|
844
|
-
const selectedByProductId = /* @__PURE__ */ new Map();
|
|
845
|
-
for (const unit of selectedUnits) {
|
|
846
|
-
const existing = selectedByProductId.get(unit.product.id);
|
|
847
|
-
if (existing) {
|
|
848
|
-
existing.quantity += 1;
|
|
849
|
-
} else {
|
|
850
|
-
selectedByProductId.set(unit.product.id, {
|
|
851
|
-
quantity: 1,
|
|
852
|
-
finalPrice: unit.finalPrice,
|
|
853
|
-
originalPrice: unit.originalPrice
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
const result = [];
|
|
858
|
-
let originalAmount = new import_decimal.default(0);
|
|
859
|
-
let finalAmount = new import_decimal.default(0);
|
|
860
|
-
for (const product of targetProducts) {
|
|
861
|
-
const key = this.getProductKey(product);
|
|
862
|
-
const processedQty = processedQuantityMap.get(key) || 0;
|
|
863
|
-
const availableQty = product.quantity - processedQty;
|
|
864
|
-
if (availableQty <= 0)
|
|
865
|
-
continue;
|
|
866
|
-
const selected = selectedByProductId.get(product.id);
|
|
867
|
-
const selectedQty = (selected == null ? void 0 : selected.quantity) || 0;
|
|
868
|
-
const remainingQty = availableQty - selectedQty;
|
|
869
|
-
if (selectedQty <= 0)
|
|
870
|
-
continue;
|
|
871
|
-
if (selectedQty > 0) {
|
|
872
|
-
result.push({
|
|
873
|
-
...product,
|
|
874
|
-
id: selectedQty === availableQty ? product.id : this.generateRandomId(),
|
|
875
|
-
originalId: product.id,
|
|
876
|
-
quantity: selectedQty,
|
|
877
|
-
finalPrice: this.formatPrice(selected.finalPrice),
|
|
878
|
-
strategyId,
|
|
879
|
-
strategyMetadata,
|
|
880
|
-
inPromotion: true,
|
|
881
|
-
isSplit: selectedQty !== product.quantity
|
|
882
|
-
});
|
|
883
|
-
originalAmount = originalAmount.plus(
|
|
884
|
-
selected.originalPrice.mul(selectedQty)
|
|
885
|
-
);
|
|
886
|
-
finalAmount = finalAmount.plus(selected.finalPrice.mul(selectedQty));
|
|
887
|
-
}
|
|
888
|
-
if (remainingQty > 0) {
|
|
889
|
-
result.push({
|
|
890
|
-
...product,
|
|
891
|
-
quantity: remainingQty,
|
|
892
|
-
finalPrice: this.formatPrice(product.price),
|
|
893
|
-
strategyId: void 0,
|
|
894
|
-
strategyMetadata: void 0,
|
|
895
|
-
inPromotion: false,
|
|
896
|
-
isSplit: selectedQty > 0
|
|
897
|
-
});
|
|
898
|
-
const remainingAmount = new import_decimal.default(product.price).mul(remainingQty);
|
|
899
|
-
originalAmount = originalAmount.plus(remainingAmount);
|
|
900
|
-
finalAmount = finalAmount.plus(remainingAmount);
|
|
901
|
-
}
|
|
902
|
-
processedQuantityMap.set(key, processedQty + availableQty);
|
|
903
|
-
}
|
|
904
|
-
return {
|
|
905
|
-
products: result,
|
|
906
|
-
originalAmount: originalAmount.toNumber(),
|
|
907
|
-
finalAmount: finalAmount.toNumber()
|
|
908
|
-
};
|
|
909
|
-
}
|
|
910
|
-
normalizePositiveInteger(value, fallback) {
|
|
911
|
-
const n = Math.floor(Number(value));
|
|
912
|
-
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
913
|
-
}
|
|
914
|
-
getAvailablePromotionQuantity(products, processedQuantityMap, matchedBundleIndexMap) {
|
|
915
|
-
let total = 0;
|
|
916
|
-
for (const product of products) {
|
|
917
|
-
const key = this.getProductKey(product);
|
|
918
|
-
const processedQty = processedQuantityMap.get(key) || 0;
|
|
919
|
-
const availableQty = product.quantity - processedQty;
|
|
920
|
-
if (availableQty <= 0)
|
|
921
|
-
continue;
|
|
922
|
-
const matchedBundleIndex = matchedBundleIndexMap == null ? void 0 : matchedBundleIndexMap.get(product.id);
|
|
923
|
-
if (matchedBundleIndex !== void 0 && product.bundle) {
|
|
924
|
-
const bundleItem = product.bundle[matchedBundleIndex];
|
|
925
|
-
total += availableQty * ((bundleItem == null ? void 0 : bundleItem.quantity) || 1);
|
|
926
|
-
} else {
|
|
927
|
-
total += availableQty;
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
return total;
|
|
931
|
-
}
|
|
932
|
-
buildItemRewardTargetUnits(products, processedQuantityMap, detail) {
|
|
933
|
-
const units = [];
|
|
934
|
-
for (const product of products) {
|
|
935
|
-
const key = this.getProductKey(product);
|
|
936
|
-
const processedQty = processedQuantityMap.get(key) || 0;
|
|
937
|
-
const availableQty = product.quantity - processedQty;
|
|
938
|
-
if (availableQty <= 0)
|
|
939
|
-
continue;
|
|
940
|
-
const originalPrice = new import_decimal.default(product.price || 0);
|
|
941
|
-
const finalPrice = this.resolveItemRewardFinalPrice(originalPrice, detail);
|
|
942
|
-
const discountAmount = originalPrice.minus(finalPrice);
|
|
943
|
-
if (discountAmount.lte(0))
|
|
944
|
-
continue;
|
|
945
|
-
for (let i = 0; i < availableQty; i++) {
|
|
946
|
-
units.push({
|
|
947
|
-
product,
|
|
948
|
-
originalPrice,
|
|
949
|
-
finalPrice,
|
|
950
|
-
discountAmount
|
|
951
|
-
});
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
return units;
|
|
955
|
-
}
|
|
956
|
-
resolveItemRewardFinalPrice(originalPrice, detail) {
|
|
957
|
-
const rewardValue = new import_decimal.default(Number(detail.rewardValue) || 0);
|
|
958
|
-
let finalPrice;
|
|
959
|
-
switch (detail.rewardMethod) {
|
|
960
|
-
case "percent_off": {
|
|
961
|
-
const percent = import_decimal.default.min(100, import_decimal.default.max(0, rewardValue));
|
|
962
|
-
finalPrice = originalPrice.mul(new import_decimal.default(100).minus(percent)).div(100);
|
|
963
|
-
break;
|
|
964
|
-
}
|
|
965
|
-
case "amount_off":
|
|
966
|
-
finalPrice = originalPrice.minus(import_decimal.default.max(0, rewardValue));
|
|
967
|
-
break;
|
|
968
|
-
case "fixed_price":
|
|
969
|
-
finalPrice = import_decimal.default.max(0, rewardValue);
|
|
970
|
-
break;
|
|
971
|
-
case "free":
|
|
972
|
-
default:
|
|
973
|
-
finalPrice = new import_decimal.default(0);
|
|
974
|
-
break;
|
|
975
|
-
}
|
|
976
|
-
return import_decimal.default.max(0, import_decimal.default.min(originalPrice, finalPrice)).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP);
|
|
977
|
-
}
|
|
978
|
-
resolveItemRewardLimit(detail, conditionQuantity, triggerQuantity, rewardQuantity, targetUnitCount) {
|
|
979
|
-
let limit = 0;
|
|
980
|
-
switch (detail.quantityRule) {
|
|
981
|
-
case "all_targets":
|
|
982
|
-
limit = targetUnitCount;
|
|
983
|
-
break;
|
|
984
|
-
case "max_per_order":
|
|
985
|
-
limit = this.normalizePositiveInteger(
|
|
986
|
-
detail.maxRewardQuantity ?? detail.rewardQuantity,
|
|
987
|
-
rewardQuantity
|
|
988
|
-
);
|
|
989
|
-
break;
|
|
990
|
-
case "per_condition_quantity":
|
|
991
|
-
default:
|
|
992
|
-
limit = Math.floor(conditionQuantity / triggerQuantity) * rewardQuantity;
|
|
993
|
-
break;
|
|
994
|
-
}
|
|
995
|
-
return Math.min(Math.max(0, limit), targetUnitCount);
|
|
996
|
-
}
|
|
997
771
|
/**
|
|
998
772
|
* 获取未参与任何促销的商品
|
|
999
773
|
*/
|
|
@@ -1065,17 +839,8 @@ var PromotionEvaluator = class {
|
|
|
1065
839
|
* 检查商品是否在策略的适用范围内
|
|
1066
840
|
*/
|
|
1067
841
|
isProductInStrategy(product, config) {
|
|
1068
|
-
if (this.shouldSkipStrategyForProduct(product, config)) {
|
|
1069
|
-
return false;
|
|
1070
|
-
}
|
|
1071
842
|
return this.getProductMatchInfo(product, config).isMatch;
|
|
1072
843
|
}
|
|
1073
|
-
shouldSkipStrategyForProduct(product, config) {
|
|
1074
|
-
return Boolean(product._promotionOnlyForItemReward) && !this.hasActionType(config, import_type.PROMOTION_ACTION_TYPES.ITEM_REWARD);
|
|
1075
|
-
}
|
|
1076
|
-
hasActionType(config, actionType) {
|
|
1077
|
-
return (config.actions || []).some((action) => (action == null ? void 0 : action.type) === actionType);
|
|
1078
|
-
}
|
|
1079
844
|
/**
|
|
1080
845
|
* 查找商品匹配规则
|
|
1081
846
|
*/
|
|
@@ -136,89 +136,3 @@ export declare const BUY_X_GET_Y_FREE_STRATEGY: {
|
|
|
136
136
|
};
|
|
137
137
|
}[];
|
|
138
138
|
};
|
|
139
|
-
/**
|
|
140
|
-
* ITEM_REWARD 策略配置示例:儿童票触发婴儿票免费
|
|
141
|
-
*
|
|
142
|
-
* 业务规则:
|
|
143
|
-
* - 条件商品:儿童票(conditions.rules.productIdAndVariantId)
|
|
144
|
-
* - 奖励商品:购物车/订单内已经存在的婴儿票(actions[0].config.rewardTargets)
|
|
145
|
-
* - 本 action 不自动新增婴儿票;每次购物车变更后由统一促销链路重算
|
|
146
|
-
*
|
|
147
|
-
* 字段说明:
|
|
148
|
-
* - type: "ITEM_REWARD" 表示商品奖励 action
|
|
149
|
-
* - target: "product" 表示本期只奖励商品行
|
|
150
|
-
* - config.rewardTargets: 奖励对象数组,支持 { product_id, product_variant_id }
|
|
151
|
-
* - config.targetSelection: "consumer_best" 表示目标商品超额时选择节省金额最高的商品
|
|
152
|
-
* - value.rewardMethod:
|
|
153
|
-
* - "free": 目标商品最终价为 0
|
|
154
|
-
* - "percent_off": 百分比折扣,rewardValue 为 0-100
|
|
155
|
-
* - "amount_off": 每个目标商品固定减免 rewardValue
|
|
156
|
-
* - "fixed_price": 目标商品最终单价为 rewardValue
|
|
157
|
-
* - value.quantityRule:
|
|
158
|
-
* - "per_condition_quantity": 每满足 triggerQuantity 个条件商品,奖励 rewardQuantity 个目标商品
|
|
159
|
-
* - "all_targets": 满足条件后奖励全部目标商品
|
|
160
|
-
* - "max_per_order": 满足条件后每单最多奖励 maxRewardQuantity 个目标商品
|
|
161
|
-
*/
|
|
162
|
-
export declare const ITEM_REWARD_STRATEGY: {
|
|
163
|
-
metadata: {
|
|
164
|
-
id: string;
|
|
165
|
-
name: {
|
|
166
|
-
en: string;
|
|
167
|
-
'zh-CN': string;
|
|
168
|
-
'zh-HK': string;
|
|
169
|
-
};
|
|
170
|
-
type: string;
|
|
171
|
-
custom: {
|
|
172
|
-
display: {
|
|
173
|
-
product_card: {
|
|
174
|
-
text: {
|
|
175
|
-
en: string;
|
|
176
|
-
'zh-CN': string;
|
|
177
|
-
'zh-HK': string;
|
|
178
|
-
};
|
|
179
|
-
type: string;
|
|
180
|
-
};
|
|
181
|
-
};
|
|
182
|
-
};
|
|
183
|
-
};
|
|
184
|
-
conditions: {
|
|
185
|
-
operator: string;
|
|
186
|
-
rules: ({
|
|
187
|
-
type: string;
|
|
188
|
-
field: string;
|
|
189
|
-
value: string;
|
|
190
|
-
operator: string;
|
|
191
|
-
} | {
|
|
192
|
-
type: string;
|
|
193
|
-
field: string;
|
|
194
|
-
value: {
|
|
195
|
-
product_id: number;
|
|
196
|
-
product_variant_id: number;
|
|
197
|
-
}[];
|
|
198
|
-
operator: string;
|
|
199
|
-
})[];
|
|
200
|
-
actionIds: string[];
|
|
201
|
-
};
|
|
202
|
-
actions: {
|
|
203
|
-
id: string;
|
|
204
|
-
type: string;
|
|
205
|
-
value: {
|
|
206
|
-
rewardMethod: string;
|
|
207
|
-
rewardValue: number;
|
|
208
|
-
quantityRule: string;
|
|
209
|
-
triggerQuantity: number;
|
|
210
|
-
rewardQuantity: number;
|
|
211
|
-
maxRewardQuantity: number;
|
|
212
|
-
};
|
|
213
|
-
valueType: string;
|
|
214
|
-
target: string;
|
|
215
|
-
priority: number;
|
|
216
|
-
config: {
|
|
217
|
-
rewardTargets: {
|
|
218
|
-
product_id: number;
|
|
219
|
-
product_variant_id: number;
|
|
220
|
-
}[];
|
|
221
|
-
targetSelection: string;
|
|
222
|
-
};
|
|
223
|
-
}[];
|
|
224
|
-
};
|
|
@@ -20,7 +20,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
var examples_exports = {};
|
|
21
21
|
__export(examples_exports, {
|
|
22
22
|
BUY_X_GET_Y_FREE_STRATEGY: () => BUY_X_GET_Y_FREE_STRATEGY,
|
|
23
|
-
ITEM_REWARD_STRATEGY: () => ITEM_REWARD_STRATEGY,
|
|
24
23
|
X_ITEMS_FOR_Y_PRICE_STRATEGY: () => X_ITEMS_FOR_Y_PRICE_STRATEGY
|
|
25
24
|
});
|
|
26
25
|
module.exports = __toCommonJS(examples_exports);
|
|
@@ -186,98 +185,8 @@ var BUY_X_GET_Y_FREE_STRATEGY = {
|
|
|
186
185
|
}
|
|
187
186
|
]
|
|
188
187
|
};
|
|
189
|
-
var ITEM_REWARD_STRATEGY = {
|
|
190
|
-
metadata: {
|
|
191
|
-
id: "STRATEGY_003",
|
|
192
|
-
name: {
|
|
193
|
-
en: "Infant ticket free with child ticket",
|
|
194
|
-
"zh-CN": "儿童票触发婴儿票免费",
|
|
195
|
-
"zh-HK": "兒童票觸發嬰兒票免費"
|
|
196
|
-
},
|
|
197
|
-
type: "promotion",
|
|
198
|
-
custom: {
|
|
199
|
-
display: {
|
|
200
|
-
product_card: {
|
|
201
|
-
text: {
|
|
202
|
-
en: "Infant ticket free",
|
|
203
|
-
"zh-CN": "婴儿票免费",
|
|
204
|
-
"zh-HK": "嬰兒票免費"
|
|
205
|
-
},
|
|
206
|
-
type: "tag"
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
},
|
|
211
|
-
conditions: {
|
|
212
|
-
operator: "and",
|
|
213
|
-
rules: [
|
|
214
|
-
{
|
|
215
|
-
type: "operator",
|
|
216
|
-
field: "currentDateTime",
|
|
217
|
-
value: "2023-01-01 00:00:00",
|
|
218
|
-
operator: ">="
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
type: "operator",
|
|
222
|
-
field: "currentDateTime",
|
|
223
|
-
value: "2030-01-01 00:00:00",
|
|
224
|
-
operator: "<="
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
type: "operator",
|
|
228
|
-
field: "productIdAndVariantId",
|
|
229
|
-
value: [
|
|
230
|
-
{
|
|
231
|
-
product_id: 1001,
|
|
232
|
-
// 条件商品:儿童票
|
|
233
|
-
product_variant_id: 0
|
|
234
|
-
// 0 = 匹配任意变体
|
|
235
|
-
}
|
|
236
|
-
],
|
|
237
|
-
operator: "product_match"
|
|
238
|
-
}
|
|
239
|
-
],
|
|
240
|
-
actionIds: ["1"]
|
|
241
|
-
},
|
|
242
|
-
actions: [
|
|
243
|
-
{
|
|
244
|
-
id: "1",
|
|
245
|
-
type: "ITEM_REWARD",
|
|
246
|
-
value: {
|
|
247
|
-
rewardMethod: "free",
|
|
248
|
-
// free | percent_off | amount_off | fixed_price
|
|
249
|
-
rewardValue: 0,
|
|
250
|
-
// free 可省略;其他 rewardMethod 使用
|
|
251
|
-
quantityRule: "per_condition_quantity",
|
|
252
|
-
// per_condition_quantity | all_targets | max_per_order
|
|
253
|
-
triggerQuantity: 1,
|
|
254
|
-
// N:每满足 N 个条件商品
|
|
255
|
-
rewardQuantity: 1,
|
|
256
|
-
// Y:奖励 Y 个目标商品
|
|
257
|
-
maxRewardQuantity: 1
|
|
258
|
-
// max_per_order 使用;本例保留为配置示意
|
|
259
|
-
},
|
|
260
|
-
valueType: "object",
|
|
261
|
-
target: "product",
|
|
262
|
-
priority: 1,
|
|
263
|
-
config: {
|
|
264
|
-
rewardTargets: [
|
|
265
|
-
{
|
|
266
|
-
product_id: 2001,
|
|
267
|
-
// 奖励对象:婴儿票
|
|
268
|
-
product_variant_id: 0
|
|
269
|
-
// 0 = 匹配任意变体
|
|
270
|
-
}
|
|
271
|
-
],
|
|
272
|
-
targetSelection: "consumer_best"
|
|
273
|
-
// consumer_best = 按可节省金额从高到低选择
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
]
|
|
277
|
-
};
|
|
278
188
|
// Annotate the CommonJS export names for ESM import in node:
|
|
279
189
|
0 && (module.exports = {
|
|
280
190
|
BUY_X_GET_Y_FREE_STRATEGY,
|
|
281
|
-
ITEM_REWARD_STRATEGY,
|
|
282
191
|
X_ITEMS_FOR_Y_PRICE_STRATEGY
|
|
283
192
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { PromotionEvaluator } from './evaluator';
|
|
2
2
|
export { PromotionAdapter } from './adapter';
|
|
3
3
|
export { default } from './adapter';
|
|
4
|
-
export { X_ITEMS_FOR_Y_PRICE_STRATEGY, BUY_X_GET_Y_FREE_STRATEGY,
|
|
4
|
+
export { X_ITEMS_FOR_Y_PRICE_STRATEGY, BUY_X_GET_Y_FREE_STRATEGY, } from './examples';
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
-
|
|
29
|
-
// src/model/strategy/adapter/promotion/index.ts
|
|
30
|
-
var promotion_exports = {};
|
|
31
|
-
__export(promotion_exports, {
|
|
32
|
-
BUY_X_GET_Y_FREE_STRATEGY: () => import_examples.BUY_X_GET_Y_FREE_STRATEGY,
|
|
33
|
-
ITEM_REWARD_STRATEGY: () => import_examples.ITEM_REWARD_STRATEGY,
|
|
34
|
-
PromotionAdapter: () => import_adapter.PromotionAdapter,
|
|
35
|
-
PromotionEvaluator: () => import_evaluator.PromotionEvaluator,
|
|
36
|
-
X_ITEMS_FOR_Y_PRICE_STRATEGY: () => import_examples.X_ITEMS_FOR_Y_PRICE_STRATEGY,
|
|
37
|
-
default: () => import_adapter2.default
|
|
38
|
-
});
|
|
39
|
-
module.exports = __toCommonJS(promotion_exports);
|
|
40
|
-
var import_evaluator = require("./evaluator");
|
|
41
|
-
var import_adapter = require("./adapter");
|
|
42
|
-
var import_adapter2 = __toESM(require("./adapter"));
|
|
43
|
-
var import_examples = require("./examples");
|
|
44
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
45
|
-
0 && (module.exports = {
|
|
46
|
-
BUY_X_GET_Y_FREE_STRATEGY,
|
|
47
|
-
ITEM_REWARD_STRATEGY,
|
|
48
|
-
PromotionAdapter,
|
|
49
|
-
PromotionEvaluator,
|
|
50
|
-
X_ITEMS_FOR_Y_PRICE_STRATEGY
|
|
51
|
-
});
|
|
@@ -12,8 +12,6 @@ export declare const PROMOTION_ACTION_TYPES: {
|
|
|
12
12
|
readonly X_ITEMS_FOR_Y_PRICE: "X_ITEMS_FOR_Y_PRICE";
|
|
13
13
|
/** 买X送Y(买X件送Y件,可累计) */
|
|
14
14
|
readonly BUY_X_GET_Y_FREE: "BUY_X_GET_Y_FREE";
|
|
15
|
-
/** 商品奖励(满足条件后,订单内指定目标商品享优惠) */
|
|
16
|
-
readonly ITEM_REWARD: "ITEM_REWARD";
|
|
17
15
|
/** 固定折扣 */
|
|
18
16
|
readonly DISCOUNT_RATE: "DISCOUNT_RATE";
|
|
19
17
|
/** 固定减价 */
|
|
@@ -68,59 +66,6 @@ export interface BuyXGetYFreeConfig {
|
|
|
68
66
|
/** 可选的赠品列表 */
|
|
69
67
|
giftProducts?: ProductIdentifier[];
|
|
70
68
|
}
|
|
71
|
-
/**
|
|
72
|
-
* 商品奖励优惠方式
|
|
73
|
-
*
|
|
74
|
-
* - free: 目标商品最终价为 0
|
|
75
|
-
* - percent_off: 目标商品按百分比折扣,rewardValue 为 0-100
|
|
76
|
-
* - amount_off: 每个目标商品固定减免 rewardValue
|
|
77
|
-
* - fixed_price: 目标商品改为固定价 rewardValue
|
|
78
|
-
*/
|
|
79
|
-
export type ItemRewardMethod = 'free' | 'percent_off' | 'amount_off' | 'fixed_price';
|
|
80
|
-
/**
|
|
81
|
-
* 商品奖励数量规则
|
|
82
|
-
*
|
|
83
|
-
* - per_condition_quantity: 每满足 N 个条件商品,奖励 Y 个目标商品
|
|
84
|
-
* - all_targets: 满足条件后奖励全部目标商品
|
|
85
|
-
* - max_per_order: 满足条件后每单最多奖励固定数量目标商品
|
|
86
|
-
*/
|
|
87
|
-
export type ItemRewardQuantityRule = 'per_condition_quantity' | 'all_targets' | 'max_per_order';
|
|
88
|
-
/** 商品奖励目标选择规则 */
|
|
89
|
-
export type ItemRewardTargetSelection = 'consumer_best';
|
|
90
|
-
/**
|
|
91
|
-
* 商品奖励 - Action Value
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* value: {
|
|
95
|
-
* rewardMethod: 'free',
|
|
96
|
-
* quantityRule: 'per_condition_quantity',
|
|
97
|
-
* triggerQuantity: 1,
|
|
98
|
-
* rewardQuantity: 1,
|
|
99
|
-
* }
|
|
100
|
-
*/
|
|
101
|
-
export interface ItemRewardValue {
|
|
102
|
-
/** 奖励方式 */
|
|
103
|
-
rewardMethod: ItemRewardMethod;
|
|
104
|
-
/** 奖励值:percent_off/amount_off/fixed_price 使用,free 可省略 */
|
|
105
|
-
rewardValue?: number;
|
|
106
|
-
/** 奖励数量规则 */
|
|
107
|
-
quantityRule: ItemRewardQuantityRule;
|
|
108
|
-
/** 每满足 N 个条件商品;默认 1 */
|
|
109
|
-
triggerQuantity?: number;
|
|
110
|
-
/** 奖励 Y 个目标商品;默认 1 */
|
|
111
|
-
rewardQuantity?: number;
|
|
112
|
-
/** 每单最多奖励 Y 个目标商品;max_per_order 使用 */
|
|
113
|
-
maxRewardQuantity?: number;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* 商品奖励 - Action Config
|
|
117
|
-
*/
|
|
118
|
-
export interface ItemRewardConfig {
|
|
119
|
-
/** 奖励对象,本期支持指定商品/变体;product_variant_id=0 表示任意变体 */
|
|
120
|
-
rewardTargets?: ProductIdentifier[];
|
|
121
|
-
/** 目标商品超额时的选择规则;本期支持 consumer_best */
|
|
122
|
-
targetSelection?: ItemRewardTargetSelection;
|
|
123
|
-
}
|
|
124
69
|
/**
|
|
125
70
|
* 商品标识
|
|
126
71
|
*
|
|
@@ -157,19 +102,10 @@ export interface BuyXGetYFreeAction extends Omit<ActionEffect, 'type' | 'value'
|
|
|
157
102
|
valueType: 'object';
|
|
158
103
|
config?: BuyXGetYFreeConfig;
|
|
159
104
|
}
|
|
160
|
-
/**
|
|
161
|
-
* 商品奖励 Action
|
|
162
|
-
*/
|
|
163
|
-
export interface ItemRewardAction extends Omit<ActionEffect, 'type' | 'value' | 'config'> {
|
|
164
|
-
type: typeof PROMOTION_ACTION_TYPES.ITEM_REWARD;
|
|
165
|
-
value: ItemRewardValue;
|
|
166
|
-
valueType: 'object';
|
|
167
|
-
config?: ItemRewardConfig;
|
|
168
|
-
}
|
|
169
105
|
/**
|
|
170
106
|
* 促销活动 Action 联合类型
|
|
171
107
|
*/
|
|
172
|
-
export type PromotionAction = XItemsForYPriceAction | BuyXGetYFreeAction
|
|
108
|
+
export type PromotionAction = XItemsForYPriceAction | BuyXGetYFreeAction;
|
|
173
109
|
/**
|
|
174
110
|
* 促销相关运算符
|
|
175
111
|
*/
|
|
@@ -234,8 +170,6 @@ export interface PromotionProduct {
|
|
|
234
170
|
quantity: number;
|
|
235
171
|
/** 原价 */
|
|
236
172
|
original_price?: number;
|
|
237
|
-
/** 内部字段:编辑态订单行只允许参与 ITEM_REWARD,避免旧促销误算历史行 */
|
|
238
|
-
_promotionOnlyForItemReward?: boolean;
|
|
239
173
|
}
|
|
240
174
|
/**
|
|
241
175
|
* 促销活动适配器转换结果
|
|
@@ -261,7 +195,7 @@ export interface PromotionTransformResult {
|
|
|
261
195
|
/**
|
|
262
196
|
* Action 详情联合类型
|
|
263
197
|
*/
|
|
264
|
-
export type PromotionActionDetail = XItemsForYPriceActionDetail | BuyXGetYFreeActionDetail
|
|
198
|
+
export type PromotionActionDetail = XItemsForYPriceActionDetail | BuyXGetYFreeActionDetail;
|
|
265
199
|
/**
|
|
266
200
|
* X件Y元 Action 详情
|
|
267
201
|
*/
|
|
@@ -292,28 +226,6 @@ export interface BuyXGetYFreeActionDetail {
|
|
|
292
226
|
/** 可选的赠品列表 */
|
|
293
227
|
giftProducts: ProductIdentifier[];
|
|
294
228
|
}
|
|
295
|
-
/**
|
|
296
|
-
* 商品奖励 Action 详情
|
|
297
|
-
*/
|
|
298
|
-
export interface ItemRewardActionDetail {
|
|
299
|
-
type: typeof PROMOTION_ACTION_TYPES.ITEM_REWARD;
|
|
300
|
-
/** 奖励方式 */
|
|
301
|
-
rewardMethod: ItemRewardMethod;
|
|
302
|
-
/** 奖励值:percent_off/amount_off/fixed_price 使用,free 为 0 */
|
|
303
|
-
rewardValue: number;
|
|
304
|
-
/** 奖励数量规则 */
|
|
305
|
-
quantityRule: ItemRewardQuantityRule;
|
|
306
|
-
/** 每满足 N 个条件商品;默认 1 */
|
|
307
|
-
triggerQuantity: number;
|
|
308
|
-
/** 奖励 Y 个目标商品;默认 1 */
|
|
309
|
-
rewardQuantity: number;
|
|
310
|
-
/** 每单最多奖励 Y 个目标商品;max_per_order 使用 */
|
|
311
|
-
maxRewardQuantity?: number;
|
|
312
|
-
/** 奖励对象,本期支持指定商品/变体 */
|
|
313
|
-
rewardTargets: ProductIdentifier[];
|
|
314
|
-
/** 目标商品超额时的选择规则 */
|
|
315
|
-
targetSelection: ItemRewardTargetSelection;
|
|
316
|
-
}
|
|
317
229
|
/**
|
|
318
230
|
* X件Y元 - 业务层计算结果
|
|
319
231
|
*
|
|
@@ -28,8 +28,6 @@ var PROMOTION_ACTION_TYPES = {
|
|
|
28
28
|
X_ITEMS_FOR_Y_PRICE: "X_ITEMS_FOR_Y_PRICE",
|
|
29
29
|
/** 买X送Y(买X件送Y件,可累计) */
|
|
30
30
|
BUY_X_GET_Y_FREE: "BUY_X_GET_Y_FREE",
|
|
31
|
-
/** 商品奖励(满足条件后,订单内指定目标商品享优惠) */
|
|
32
|
-
ITEM_REWARD: "ITEM_REWARD",
|
|
33
31
|
/** 固定折扣 */
|
|
34
32
|
DISCOUNT_RATE: "DISCOUNT_RATE",
|
|
35
33
|
/** 固定减价 */
|