package cn.iocoder.yudao.module.crm.service.invoice; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceSaveReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; import cn.iocoder.yudao.module.crm.dal.dataobject.invoice.CrmInvoiceDO; import cn.iocoder.yudao.module.crm.dal.mysql.invoice.CrmInvoiceMapper; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.math.BigDecimal; import java.util.ArrayList; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.INVOICE_UPDATE_FAIL_EDITING_PROHIBITED; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.INVOICE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class CrmInvoiceEditStatusTest { @Mock private CrmInvoiceMapper invoiceMapper; @Mock private CrmContractService contractService; @Mock private StorageAttachmentApi storageAttachmentApi; @Mock private BpmProcessInstanceApi bpmProcessInstanceApi; @InjectMocks private CrmInvoiceServiceImpl service; @ParameterizedTest @CsvSource({"20,审核通过", "30,审核不通过", "40,已取消", "50,已作废", "99,未知状态"}) void lockedInvoiceReportsStatusBeforeAmountChecks(int status, String name) { when(invoiceMapper.selectById(1L)).thenReturn(invoice(status)); ServiceException error = assertThrows(ServiceException.class, () -> service.updateInvoice(request())); assertEquals(INVOICE_UPDATE_FAIL_EDITING_PROHIBITED.getCode(), error.getCode()); assertTrue(error.getMessage().contains(name)); assertTrue(error.getMessage().contains("仅未提交、审批中")); verify(invoiceMapper, never()).updateById(any(CrmInvoiceDO.class)); verifyNoInteractions(contractService, storageAttachmentApi); } @ParameterizedTest @ValueSource(ints = {0, 10}) void editableInvoiceKeepsApprovalAndRelationshipFields(int status) { verifySuccessfulUpdate(status); } @ParameterizedTest @ValueSource(ints = {0, 10, 20, 30, 40, 50}) void autoApprovalAllowsEditingEveryInvoiceStatus(int status) { when(bpmProcessInstanceApi.isGlobalAutoApprove()).thenReturn(true); verifySuccessfulUpdate(status); } @Test void autoApprovalStillValidatesContractAmount() { when(bpmProcessInstanceApi.isGlobalAutoApprove()).thenReturn(true); when(invoiceMapper.selectById(1L)).thenReturn(invoice(20)); var contract = new CrmContractDO().setId(2L).setTotalPrice(new BigDecimal("50")); when(contractService.validateContract(2L)).thenReturn(contract); when(invoiceMapper.selectListByContractIdAndStatus(eq(2L), anyCollection())).thenReturn(new ArrayList<>()); var error = assertThrows(ServiceException.class, () -> service.updateInvoice(request())); assertEquals(INVOICE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT.getCode(), error.getCode()); verify(invoiceMapper, never()).updateById(any(CrmInvoiceDO.class)); verifyNoInteractions(storageAttachmentApi); } private void verifySuccessfulUpdate(int status) { when(invoiceMapper.selectById(1L)).thenReturn(invoice(status)); var contract = new CrmContractDO().setId(2L).setTotalPrice(new BigDecimal("500")); when(contractService.validateContract(2L)).thenReturn(contract); when(invoiceMapper.selectListByContractIdAndStatus(eq(2L), anyCollection())).thenReturn(new ArrayList<>()); service.updateInvoice(request()); var update = ArgumentCaptor.forClass(CrmInvoiceDO.class); verify(invoiceMapper).updateById(update.capture()); assertNull(update.getValue().getAuditStatus()); assertEquals(2L, update.getValue().getContractId()); assertEquals(3L, update.getValue().getCustomerId()); assertEquals(4L, update.getValue().getOwnerUserId()); verify(storageAttachmentApi).updateAttachments("file", "crm_invoice", 1L, null); } private static CrmInvoiceDO invoice(int status) { return new CrmInvoiceDO().setId(1L).setContractId(2L).setCustomerId(3L) .setOwnerUserId(4L).setAuditStatus(status).setPrice(new BigDecimal("100")); } private static CrmInvoiceSaveReqVO request() { return new CrmInvoiceSaveReqVO().setId(1L).setContractId(999L).setCustomerId(999L) .setOwnerUserId(999L).setPrice(new BigDecimal("100")); } }