You've already forked FrameTour-BE
- 添加 PHOTO_PRINT_MU 和 PHOTO_PRINT_FX 枚举类型定义 - 实现手机照片打印和特效照片打印的基础价格计算(单价×数量) - 支持景区特定配置的价格计算逻辑 - 验证新SKU与现有 PHOTO_PRINT 的行为一致性 - 添加相关单元测试确保价格计算准确性
206 lines
8.6 KiB
Java
206 lines
8.6 KiB
Java
package com.ycwl.basic.pricing.service;
|
|
|
|
import com.ycwl.basic.pricing.dto.VoucherInfo;
|
|
import com.ycwl.basic.pricing.entity.PriceVoucherBatchConfig;
|
|
import com.ycwl.basic.pricing.entity.PriceVoucherCode;
|
|
import com.ycwl.basic.pricing.entity.PriceVoucherUsageRecord;
|
|
import com.ycwl.basic.pricing.enums.VoucherCodeStatus;
|
|
import com.ycwl.basic.pricing.enums.VoucherDiscountType;
|
|
import com.ycwl.basic.pricing.mapper.PriceVoucherBatchConfigMapper;
|
|
import com.ycwl.basic.pricing.mapper.PriceVoucherCodeMapper;
|
|
import com.ycwl.basic.pricing.mapper.PriceVoucherUsageRecordMapper;
|
|
import com.ycwl.basic.pricing.service.impl.VoucherServiceImpl;
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.mockito.InjectMocks;
|
|
import org.mockito.Mock;
|
|
import org.mockito.MockitoAnnotations;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.util.Date;
|
|
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
import static org.mockito.ArgumentMatchers.*;
|
|
import static org.mockito.Mockito.*;
|
|
|
|
/**
|
|
* 可重复使用券码服务测试
|
|
*/
|
|
public class ReusableVoucherServiceTest {
|
|
|
|
@Mock
|
|
private PriceVoucherCodeMapper voucherCodeMapper;
|
|
|
|
@Mock
|
|
private PriceVoucherBatchConfigMapper voucherBatchConfigMapper;
|
|
|
|
@Mock
|
|
private PriceVoucherUsageRecordMapper usageRecordMapper;
|
|
|
|
@InjectMocks
|
|
private VoucherServiceImpl voucherService;
|
|
|
|
private PriceVoucherCode testVoucherCode;
|
|
private PriceVoucherBatchConfig testBatchConfig;
|
|
|
|
@BeforeEach
|
|
void setUp() {
|
|
MockitoAnnotations.openMocks(this);
|
|
|
|
// 创建测试数据
|
|
testVoucherCode = new PriceVoucherCode();
|
|
testVoucherCode.setId(1L);
|
|
testVoucherCode.setCode("TEST123");
|
|
testVoucherCode.setBatchId(1L);
|
|
testVoucherCode.setScenicId(1L);
|
|
testVoucherCode.setFaceId(1001L);
|
|
testVoucherCode.setStatus(VoucherCodeStatus.CLAIMED_AVAILABLE.getCode());
|
|
testVoucherCode.setCurrentUseCount(1);
|
|
testVoucherCode.setLastUsedTime(new Date());
|
|
testVoucherCode.setDeleted(0);
|
|
|
|
testBatchConfig = new PriceVoucherBatchConfig();
|
|
testBatchConfig.setId(1L);
|
|
testBatchConfig.setBatchName("测试批次");
|
|
testBatchConfig.setDiscountType(VoucherDiscountType.REDUCE_PRICE.getCode());
|
|
testBatchConfig.setDiscountValue(new BigDecimal("10.00"));
|
|
testBatchConfig.setMaxUseCount(3); // 可使用3次
|
|
testBatchConfig.setMaxUsePerUser(2); // 每用户最多2次
|
|
testBatchConfig.setUseIntervalHours(24); // 间隔24小时
|
|
testBatchConfig.setStatus(1);
|
|
testBatchConfig.setDeleted(0);
|
|
}
|
|
|
|
@Test
|
|
void testValidateReusableVoucherCode_Success() {
|
|
// Given
|
|
when(voucherCodeMapper.selectByCode("TEST123")).thenReturn(testVoucherCode);
|
|
when(voucherBatchConfigMapper.selectById(1L)).thenReturn(testBatchConfig);
|
|
when(usageRecordMapper.countByFaceIdAndVoucherCodeId(1001L, 1L)).thenReturn(1); // 用户已使用1次
|
|
|
|
// 模拟距离上次使用已超过24小时
|
|
Date lastUseTime = new Date(System.currentTimeMillis() - 25 * 60 * 60 * 1000); // 25小时前
|
|
when(usageRecordMapper.getLastUseTimeByFaceIdAndVoucherCodeId(1001L, 1L)).thenReturn(lastUseTime);
|
|
|
|
// When
|
|
VoucherInfo result = voucherService.validateAndGetVoucherInfo("TEST123", 1001L, 1L);
|
|
|
|
// Then
|
|
assertNotNull(result);
|
|
assertEquals("TEST123", result.getVoucherCode());
|
|
assertTrue(result.getAvailable());
|
|
assertEquals(Integer.valueOf(1), result.getCurrentUseCount());
|
|
assertEquals(Integer.valueOf(3), result.getMaxUseCount());
|
|
assertEquals(Integer.valueOf(2), result.getRemainingUseCount());
|
|
}
|
|
|
|
@Test
|
|
void testValidateVoucherCode_ReachedMaxUseCount() {
|
|
// Given - 券码已达到最大使用次数
|
|
testVoucherCode.setCurrentUseCount(3);
|
|
testVoucherCode.setStatus(VoucherCodeStatus.CLAIMED_EXHAUSTED.getCode());
|
|
|
|
when(voucherCodeMapper.selectByCode("TEST123")).thenReturn(testVoucherCode);
|
|
when(voucherBatchConfigMapper.selectById(1L)).thenReturn(testBatchConfig);
|
|
|
|
// When
|
|
VoucherInfo result = voucherService.validateAndGetVoucherInfo("TEST123", 1001L, 1L);
|
|
|
|
// Then
|
|
assertNotNull(result);
|
|
assertFalse(result.getAvailable());
|
|
assertEquals("券码已用完", result.getUnavailableReason());
|
|
}
|
|
|
|
@Test
|
|
void testValidateVoucherCode_UserReachedMaxUsePerUser() {
|
|
// Given - 用户已达到个人使用上限
|
|
when(voucherCodeMapper.selectByCode("TEST123")).thenReturn(testVoucherCode);
|
|
when(voucherBatchConfigMapper.selectById(1L)).thenReturn(testBatchConfig);
|
|
when(usageRecordMapper.countByFaceIdAndVoucherCodeId(1001L, 1L)).thenReturn(2); // 用户已使用2次
|
|
|
|
// When
|
|
VoucherInfo result = voucherService.validateAndGetVoucherInfo("TEST123", 1001L, 1L);
|
|
|
|
// Then
|
|
assertNotNull(result);
|
|
assertFalse(result.getAvailable());
|
|
assertEquals("您使用该券码的次数已达上限", result.getUnavailableReason());
|
|
}
|
|
|
|
@Test
|
|
void testValidateVoucherCode_WithinInterval() {
|
|
// Given - 距离上次使用不足24小时
|
|
when(voucherCodeMapper.selectByCode("TEST123")).thenReturn(testVoucherCode);
|
|
when(voucherBatchConfigMapper.selectById(1L)).thenReturn(testBatchConfig);
|
|
when(usageRecordMapper.countByFaceIdAndVoucherCodeId(1001L, 1L)).thenReturn(1);
|
|
|
|
// 模拟距离上次使用仅10小时
|
|
Date lastUseTime = new Date(System.currentTimeMillis() - 10 * 60 * 60 * 1000);
|
|
when(usageRecordMapper.getLastUseTimeByFaceIdAndVoucherCodeId(1001L, 1L)).thenReturn(lastUseTime);
|
|
|
|
// When
|
|
VoucherInfo result = voucherService.validateAndGetVoucherInfo("TEST123", 1001L, 1L);
|
|
|
|
// Then
|
|
assertNotNull(result);
|
|
assertFalse(result.getAvailable());
|
|
assertTrue(result.getUnavailableReason().contains("请等待"));
|
|
assertTrue(result.getUnavailableReason().contains("小时后再次使用"));
|
|
}
|
|
|
|
@Test
|
|
void testMarkVoucherAsUsed_UpdateCountAndStatus() {
|
|
// Given
|
|
when(voucherCodeMapper.selectByCode("TEST123")).thenReturn(testVoucherCode);
|
|
when(voucherBatchConfigMapper.selectById(1L)).thenReturn(testBatchConfig);
|
|
|
|
// When
|
|
voucherService.markVoucherAsUsed("TEST123", "测试使用", "ORDER001", new BigDecimal("10.00"), 1L);
|
|
|
|
// Then
|
|
verify(usageRecordMapper, times(1)).insert(any(PriceVoucherUsageRecord.class));
|
|
verify(voucherCodeMapper, times(1)).updateById(any(PriceVoucherCode.class));
|
|
verify(voucherBatchConfigMapper, times(1)).updateUsedCount(eq(1L), eq(1));
|
|
}
|
|
|
|
@Test
|
|
void testMarkVoucherAsUsed_ReachMaxUseCount() {
|
|
// Given - 使用后将达到最大使用次数
|
|
testVoucherCode.setCurrentUseCount(2); // 当前已使用2次,再使用1次将达到上限3次
|
|
|
|
when(voucherCodeMapper.selectByCode("TEST123")).thenReturn(testVoucherCode);
|
|
when(voucherBatchConfigMapper.selectById(1L)).thenReturn(testBatchConfig);
|
|
|
|
// When
|
|
voucherService.markVoucherAsUsed("TEST123", "测试使用", "ORDER001", new BigDecimal("10.00"), 1L);
|
|
|
|
// Then
|
|
verify(usageRecordMapper, times(1)).insert(any(PriceVoucherUsageRecord.class));
|
|
verify(voucherCodeMapper, times(1)).updateById(argThat(voucherCode ->
|
|
voucherCode.getCurrentUseCount() == 3 &&
|
|
voucherCode.getStatus().equals(VoucherCodeStatus.CLAIMED_EXHAUSTED.getCode())
|
|
));
|
|
verify(voucherBatchConfigMapper, times(1)).updateUsedCount(eq(1L), eq(1));
|
|
}
|
|
|
|
@Test
|
|
void testMarkVoucherAsUsed_SingleUseCompatibility() {
|
|
// Given - 测试单次使用兼容性(maxUseCount = 1)
|
|
testBatchConfig.setMaxUseCount(1);
|
|
testVoucherCode.setCurrentUseCount(0);
|
|
|
|
when(voucherCodeMapper.selectByCode("TEST123")).thenReturn(testVoucherCode);
|
|
when(voucherBatchConfigMapper.selectById(1L)).thenReturn(testBatchConfig);
|
|
|
|
// When
|
|
voucherService.markVoucherAsUsed("TEST123", "测试使用", "ORDER001", new BigDecimal("10.00"), 1L);
|
|
|
|
// Then - 应该设置为USED状态以兼容原有逻辑
|
|
verify(voucherCodeMapper, times(1)).updateById(argThat(voucherCode ->
|
|
voucherCode.getCurrentUseCount() == 1 &&
|
|
voucherCode.getStatus().equals(VoucherCodeStatus.USED.getCode()) &&
|
|
voucherCode.getUsedTime() != null
|
|
));
|
|
}
|
|
} |