| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- package com.ruoyi.system.service.impl;
- import com.ruoyi.common.exception.ServiceException;
- import com.ruoyi.system.domain.PosFood;
- import com.ruoyi.system.domain.PromotionActivity;
- import com.ruoyi.system.domain.PromotionActivityRule;
- import com.ruoyi.system.domain.PromotionCouponBatch;
- import com.ruoyi.system.domain.PromotionCouponRule;
- import com.ruoyi.system.mapper.PosFoodMapper;
- import com.ruoyi.system.service.ISysConfigService;
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.Test;
- import org.junit.jupiter.api.extension.ExtendWith;
- import org.mockito.InjectMocks;
- import org.mockito.Mock;
- import org.mockito.junit.jupiter.MockitoExtension;
- import java.math.BigDecimal;
- import java.util.List;
- import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
- import static org.junit.jupiter.api.Assertions.assertEquals;
- import static org.junit.jupiter.api.Assertions.assertThrows;
- import static org.mockito.Mockito.lenient;
- import static org.mockito.Mockito.when;
- import static org.mockito.Mockito.reset;
- @ExtendWith(MockitoExtension.class)
- class PromotionDiscountLimitCheckerTest {
- @Mock
- private ISysConfigService configService;
- @Mock
- private PosFoodMapper posFoodMapper;
- @InjectMocks
- private PromotionDiscountLimitChecker checker;
- @BeforeEach
- void enableTwentyPercentLimit() {
- when(configService.selectConfigByKey("promotion.discount.limit.enabled"))
- .thenReturn("true");
- // type=5 满额免运创建侧不读比例(不预估免运额),lenient 避免严格stub误报
- lenient().when(configService.selectConfigByKey("promotion.discount.limit.ratio"))
- .thenReturn("20");
- }
- @Test
- void fullReductionCouponAllowsExactLimitAndRejectsAmountAboveLimit() {
- PromotionCouponBatch batch = batch(1);
- assertDoesNotThrow(() -> checker.checkCouponBatch(batch,
- rule(null, "100", "20", null)));
- assertThrows(ServiceException.class, () -> checker.checkCouponBatch(batch,
- rule(null, "100", "20.01", null)));
- }
- @Test
- void productDiscountCouponAllowsEightTenthsAndRejectsLowerRate() {
- PromotionCouponBatch batch = batch(2);
- assertDoesNotThrow(() -> checker.checkCouponBatch(batch,
- rule(1L, null, null, "0.80")));
- assertThrows(ServiceException.class, () -> checker.checkCouponBatch(batch,
- rule(1L, null, null, "0.79")));
- }
- @Test
- void productVoucherUsesCurrentProductPriceAsLimitAnchor() {
- when(posFoodMapper.selectById(1L)).thenReturn(food(1L, "100"));
- PromotionCouponBatch batch = batch(2);
- assertDoesNotThrow(() -> checker.checkCouponBatch(batch,
- rule(1L, null, "20", null)));
- assertThrows(ServiceException.class, () -> checker.checkCouponBatch(batch,
- rule(1L, null, "20.01", null)));
- }
- @Test
- void productVoucherDoesNotRoundNinetyNineDollarLimitUpToTwenty() {
- when(posFoodMapper.selectById(1L)).thenReturn(food(1L, "99"));
- assertThrows(ServiceException.class, () -> checker.checkCouponBatch(batch(2),
- rule(1L, null, "20", null)));
- }
- @Test
- void customThirtyPercentRatioChangesAllowedVoucherAmount() {
- when(configService.selectConfigByKey("promotion.discount.limit.ratio"))
- .thenReturn("30");
- when(posFoodMapper.selectById(1L)).thenReturn(food(1L, "100"));
- PromotionCouponBatch batch = batch(2);
- assertDoesNotThrow(() -> checker.checkCouponBatch(batch,
- rule(1L, null, "30", null)));
- assertThrows(ServiceException.class, () -> checker.checkCouponBatch(batch,
- rule(1L, null, "30.01", null)));
- }
- @Test
- void invalidRatioFallsBackToTwentyPercent() {
- when(configService.selectConfigByKey("promotion.discount.limit.ratio"))
- .thenReturn("not-a-number");
- assertEquals(new BigDecimal("20"), checker.getRatioPercent());
- assertThrows(ServiceException.class, () -> checker.checkCouponBatch(batch(1),
- rule(null, "100", "21", null)));
- }
- @Test
- void disabledLimitPreservesPreviousCouponBehavior() {
- reset(configService);
- when(configService.selectConfigByKey("promotion.discount.limit.enabled"))
- .thenReturn("false");
- assertDoesNotThrow(() -> checker.checkCouponBatch(batch(1),
- rule(null, "100", "90", null)));
- }
- @Test
- void freeDeliveryCouponRequiresPositiveThreshold() {
- assertThrows(ServiceException.class, () -> checker.checkCouponBatch(batch(3),
- rule(null, null, "10", null)));
- }
- @Test
- void multiProductCouponRejectsBatchWhenAnyProductExceedsLimit() {
- when(posFoodMapper.selectById(1L)).thenReturn(food(1L, "100"));
- when(posFoodMapper.selectById(2L)).thenReturn(food(2L, "50"));
- List<PromotionCouponRule> rules = List.of(
- rule(1L, null, "20", null),
- rule(2L, null, "11", null));
- assertThrows(ServiceException.class,
- () -> checker.checkCouponBatch(batch(2), rules));
- }
- @Test
- void freeDeliveryActivityCreationSkipsReductionRatioCheck() {
- // T074:type=5 满额免运只有门槛没有减免额,创建侧不预估/不限制实际免运额
- PromotionActivity activity = new PromotionActivity();
- activity.setType(5);
- PromotionActivityRule rule = new PromotionActivityRule();
- rule.setThreshold(new BigDecimal("100"));
- assertDoesNotThrow(() -> checker.checkActivity(activity, List.of(rule)));
- }
- private PromotionCouponBatch batch(int type) {
- PromotionCouponBatch batch = new PromotionCouponBatch();
- batch.setCouponType(type);
- return batch;
- }
- private PromotionCouponRule rule(Long productId, String threshold, String amount,
- String discountRate) {
- PromotionCouponRule rule = new PromotionCouponRule();
- rule.setProductId(productId);
- rule.setThreshold(decimal(threshold));
- rule.setAmount(decimal(amount));
- rule.setDiscountRate(decimal(discountRate));
- return rule;
- }
- private PosFood food(Long id, String price) {
- PosFood food = new PosFood();
- food.setId(id);
- food.setName("food-" + id);
- food.setPrice(new BigDecimal(price));
- return food;
- }
- private BigDecimal decimal(String value) {
- return value == null ? null : new BigDecimal(value);
- }
- }
|