云
昨天 24984ff670fcce16322aa8c2460f93307ddc3f9a
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/invoice/CrmInvoiceServiceImpl.java
@@ -11,6 +11,7 @@
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
import cn.iocoder.yudao.framework.operatelog.core.util.OperateLogUtils;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceImportExcelVO;
@@ -131,12 +132,16 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = CRM_INVOICE_TYPE, subType = CRM_INVOICE_IMPORT_SUB_TYPE, bizNo = "0",
            success = CRM_INVOICE_IMPORT_SUCCESS)
    public CrmInvoiceImportRespVO importInvoiceList(List<CrmInvoiceImportExcelVO> importList) {
        CrmInvoiceImportRespVO respVO = CrmInvoiceImportRespVO.builder()
                .createList(new ArrayList<>())
                .failureList(new LinkedHashMap<>())
                .build();
        if (CollUtil.isEmpty(importList)) {
            // 空文件也要给日志文案兜底,避免 {{#importSummary}} 取不到值
            OperateLogUtils.putImportSummary(respVO.getCreateList(), null, respVO.getFailureList());
            return respVO;
        }
@@ -160,6 +165,8 @@
                respVO.getFailureList().put(label, resolveImportErrorMessage(ex));
            }
        }
        // 记录导入结果汇总,供 @LogRecord 的 success 文案引用(开票导入无「更新」分支,故传 null)
        OperateLogUtils.putImportSummary(respVO.getCreateList(), null, respVO.getFailureList());
        return respVO;
    }
@@ -395,14 +402,16 @@
        CrmInvoiceDO oldInvoice = validateInvoiceExists(updateReqVO.getId());
        updateReqVO.setOwnerUserId(oldInvoice.getOwnerUserId()).setCustomerId(oldInvoice.getCustomerId())
                .setContractId(oldInvoice.getContractId()); // 设置已存在的值
        // 1.2 校验可开票金额超过上限
        validateInvoicePriceExceedsLimit(updateReqVO);
        // 1.3 只有草稿、审批中,可以编辑;
        if (!ObjectUtils.equalsAny(oldInvoice.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(),
        // 1.2 免审批时不限制编辑状态;正常审批仅草稿、审批中可以编辑。
        if (!bpmProcessInstanceApi.isGlobalAutoApprove()
                && !ObjectUtils.equalsAny(oldInvoice.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(),
                CrmAuditStatusEnum.PROCESS.getStatus())) {
            throw exception(INVOICE_UPDATE_FAIL_EDITING_PROHIBITED);
            throw exception(INVOICE_UPDATE_FAIL_EDITING_PROHIBITED,
                    StrUtil.blankToDefault(CrmAuditStatusEnum.getNameByStatus(oldInvoice.getAuditStatus()), "未知状态"));
        }
        // 1.3 校验可开票金额超过上限
        validateInvoicePriceExceedsLimit(updateReqVO);
        // 2. 更新开票
        CrmInvoiceDO updateObj = BeanUtils.toBean(updateReqVO, CrmInvoiceDO.class);
@@ -473,6 +482,15 @@
                .setId(invoice.getId()).setContractId(invoice.getContractId()).setPrice(invoice.getPrice()));
        // 2. 创建开票审批流程实例
        // 全局免审批:业务校验通过后直接执行审批通过逻辑,无需流程模型。
        if (bpmProcessInstanceApi.isGlobalAutoApprove()) {
            invoiceMapper.updateById(new CrmInvoiceDO().setId(id).setProcessInstanceId("")
                    .setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus()));
            updateInvoiceAuditStatus(id, cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum.APPROVE.getStatus());
            LogRecordContext.putVariable("invoiceNo", invoice.getNo());
            return;
        }
        String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
                .setProcessDefinitionKey(BPM_PROCESS_DEFINITION_KEY).setBusinessKey(String.valueOf(id)));