package cn.iocoder.yudao.module.crm.service.quotation; import cn.iocoder.yudao.module.crm.dal.dataobject.bidbond.CrmBidBondDO; import cn.iocoder.yudao.module.crm.dal.dataobject.quotation.CrmSaleQuotationDO; import cn.iocoder.yudao.module.crm.dal.mysql.bidbond.CrmBidBondMapper; import cn.iocoder.yudao.module.crm.dal.mysql.quotation.CrmSaleQuotationMapper; import org.junit.jupiter.api.Test; import org.springframework.test.util.ReflectionTestUtils; import java.lang.reflect.Proxy; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; class CrmSaleQuotationExpiryHelperTest { private final CrmSaleQuotationExpiryHelper helper = new CrmSaleQuotationExpiryHelper(); @Test void isExpired_nullNeverExpires() { assertFalse(helper.isExpired(null)); } @Test void isExpired_dateOnlyRemainsValidToday() { // 前端日期控件只选到日,时间部分为 00:00:00,当天应仍有效 assertFalse(helper.isExpired(LocalDate.now().atStartOfDay())); assertTrue(helper.isExpired(LocalDate.now().minusDays(1).atStartOfDay())); } @Test void isExpired_exactTimeCompare() { assertFalse(helper.isExpired(LocalDateTime.now().plusMinutes(1))); assertTrue(helper.isExpired(LocalDateTime.now().minusMinutes(1))); } @Test void expiredQuotationIsVoided() { CrmSaleQuotationDO quote = new CrmSaleQuotationDO().setId(1L).setNo("BJ1").setStatus(0) .setValidUntil(LocalDate.now().minusDays(2).atStartOfDay()); AtomicReference updated = new AtomicReference<>(); CrmSaleQuotationMapper quoteMapper = stub(CrmSaleQuotationMapper.class, (proxy, method, args) -> switch (method.getName()) { case "updateById" -> { updated.set((CrmSaleQuotationDO) args[0]); yield 1; } default -> throw new AssertionError(method.getName()); }); ReflectionTestUtils.setField(helper, "saleQuotationMapper", quoteMapper); ReflectionTestUtils.setField(helper, "bidBondMapper", emptyBondMapper()); helper.expireIfNeeded(quote); assertEquals(5, quote.getStatus()); assertEquals(2, quote.getVoidType()); assertNotNull(quote.getVoidReason()); assertNotNull(updated.get()); assertEquals(5, updated.get().getStatus()); assertEquals(2, updated.get().getVoidType()); } @Test void bidInProgressIsSkipped() { CrmSaleQuotationDO quote = new CrmSaleQuotationDO().setId(1L).setNo("BJ1").setStatus(2).setBidBondId(9L) .setValidUntil(LocalDate.now().minusDays(2).atStartOfDay()); CrmSaleQuotationMapper quoteMapper = stub(CrmSaleQuotationMapper.class, (proxy, method, args) -> { throw new AssertionError("投标进行中不应自动作废:" + method.getName()); }); CrmBidBondMapper bondMapper = stub(CrmBidBondMapper.class, (proxy, method, args) -> List.of(new CrmBidBondDO().setId(9L).setBidResult(0))); ReflectionTestUtils.setField(helper, "saleQuotationMapper", quoteMapper); ReflectionTestUtils.setField(helper, "bidBondMapper", bondMapper); helper.expireIfNeeded(quote); assertEquals(2, quote.getStatus()); } @Test void lostBidQuotationIsExpired() { CrmSaleQuotationDO quote = new CrmSaleQuotationDO().setId(1L).setNo("BJ1").setStatus(2).setBidBondId(9L) .setValidUntil(LocalDate.now().minusDays(2).atStartOfDay()); AtomicReference updated = new AtomicReference<>(); CrmSaleQuotationMapper quoteMapper = stub(CrmSaleQuotationMapper.class, (proxy, method, args) -> switch (method.getName()) { case "updateById" -> { updated.set((CrmSaleQuotationDO) args[0]); yield 1; } default -> throw new AssertionError(method.getName()); }); CrmBidBondMapper bondMapper = stub(CrmBidBondMapper.class, (proxy, method, args) -> List.of(new CrmBidBondDO().setId(9L).setBidResult(2))); ReflectionTestUtils.setField(helper, "saleQuotationMapper", quoteMapper); ReflectionTestUtils.setField(helper, "bidBondMapper", bondMapper); helper.expireIfNeeded(quote); assertEquals(5, quote.getStatus()); assertEquals(2, quote.getVoidType()); } private static CrmBidBondMapper emptyBondMapper() { return stub(CrmBidBondMapper.class, (proxy, method, args) -> List.of()); } private static T stub(Class type, java.lang.reflect.InvocationHandler handler) { return type.cast(Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, handler)); } }