| | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | 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.bpm.dal.dataobject.definition.BpmCategoryDO; |
| | |
| | | import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi; |
| | | import cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO; |
| | | import cn.iocoder.yudao.module.crm.api.contract.CrmContractApi; |
| | | import cn.iocoder.yudao.module.crm.api.contract.dto.CrmContractCreateFromSaleOrderReqDTO; |
| | | import cn.iocoder.yudao.module.crm.api.contract.dto.CrmContractRespDTO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderImportExcelVO; |
| | |
| | | import cn.iocoder.yudao.module.mes.api.mps.dto.MesProMpsRespDTO; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import com.mzt.logapi.starter.annotation.LogRecord; |
| | | import jakarta.annotation.Resource; |
| | | import org.flowable.engine.repository.ProcessDefinition; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| | | import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; |
| | | import static cn.iocoder.yudao.module.erp.enums.LogRecordConstants.*; |
| | | |
| | | /** |
| | | * ERP 销售订单 Service 实现类 |
| | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @LogRecord(type = ERP_SALE_ORDER_TYPE, subType = ERP_SALE_ORDER_IMPORT_SUB_TYPE, bizNo = "0", |
| | | success = ERP_SALE_ORDER_IMPORT_SUCCESS) |
| | | public ErpSaleOrderImportRespVO importSaleOrderList(List<ErpSaleOrderImportExcelVO> importList) { |
| | | ErpSaleOrderImportRespVO respVO = ErpSaleOrderImportRespVO.builder() |
| | | .createList(new ArrayList<>()) |
| | |
| | | .failureList(new LinkedHashMap<>()) |
| | | .build(); |
| | | if (CollUtil.isEmpty(importList)) { |
| | | // 记录导入结果汇总,供 @LogRecord 的 success 文案引用 |
| | | OperateLogUtils.putImportSummary(respVO.getCreateList(), respVO.getUpdateList(), respVO.getFailureList()); |
| | | return respVO; |
| | | } |
| | | |
| | |
| | | respVO.getFailureList().put(label, resolveImportErrorMessage(ex)); |
| | | } |
| | | } |
| | | // 记录导入结果汇总,供 @LogRecord 的 success 文案引用 |
| | | OperateLogUtils.putImportSummary(respVO.getCreateList(), respVO.getUpdateList(), respVO.getFailureList()); |
| | | return respVO; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | // 4. 创建 BPM 流程实例(审批在协同办公完成) |
| | | // 全局免审批:业务校验通过后直接执行审批通过逻辑,无需流程模型。 |
| | | if (processInstanceApi.isGlobalAutoApprove()) { |
| | | saleOrderMapper.updateById(new ErpSaleOrderDO() |
| | | .setId(id) |
| | | .setStatus(ErpAuditStatus.APPROVING.getStatus()) |
| | | .setProcessInstanceId("")); |
| | | updateSaleOrderAuditStatus(id, cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum.APPROVE.getStatus()); |
| | | return; |
| | | } |
| | | |
| | | String processInstanceId = processInstanceApi.createProcessInstance(userId, |
| | | new BpmProcessInstanceCreateReqDTO() |
| | | .setProcessDefinitionKey(processDefinitionKey) |
| | |
| | | .setId(id).setStatus(newStatus)); |
| | | } |
| | | |
| | | // 3. 审核通过时,为需要生产的明细创建 MPS |
| | | // 3. 审核通过时,为需要生产的明细创建 MPS,并自动生成销售合同草稿 |
| | | if (ErpAuditStatus.APPROVE.getStatus().equals(newStatus)) { |
| | | createMpsForSaleOrder(id, saleOrder); |
| | | createContractForSaleOrder(saleOrder); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | log.info("[createMpsForSaleOrder] 销售订单({}) 审核完成,创建 MPS {} 条", orderId, mpsCount); |
| | | } |
| | | |
| | | /** |
| | | * 销售订单审批通过后,自动生成销售合同草稿(不提交审批) |
| | | */ |
| | | private void createContractForSaleOrder(ErpSaleOrderDO saleOrder) { |
| | | // 订单本身由合同生成,避免反向生成 |
| | | if (saleOrder.getContractId() != null) { |
| | | log.info("[createContractForSaleOrder] 销售订单({}) 已关联合同({}),跳过自动生成", |
| | | saleOrder.getNo(), saleOrder.getContractNo()); |
| | | return; |
| | | } |
| | | try { |
| | | List<ErpSaleOrderItemDO> items = saleOrderItemMapper.selectListByOrderId(saleOrder.getId()); |
| | | if (CollUtil.isEmpty(items)) { |
| | | log.warn("[createContractForSaleOrder] 销售订单({}) 没有明细,跳过自动生成合同", saleOrder.getNo()); |
| | | return; |
| | | } |
| | | // 负责人优先取销售员,未填写时回退到订单创建人 |
| | | Long ownerUserId = saleOrder.getSaleUserId(); |
| | | if (ownerUserId == null && StrUtil.isNumeric(saleOrder.getCreator())) { |
| | | ownerUserId = Long.valueOf(saleOrder.getCreator()); |
| | | } |
| | | |
| | | CrmContractCreateFromSaleOrderReqDTO createReqDTO = new CrmContractCreateFromSaleOrderReqDTO(); |
| | | createReqDTO.setOrderId(saleOrder.getId()); |
| | | createReqDTO.setOrderNo(saleOrder.getNo()); |
| | | createReqDTO.setCustomerId(saleOrder.getCustomerId()); |
| | | createReqDTO.setOwnerUserId(ownerUserId); |
| | | createReqDTO.setOrderTime(saleOrder.getOrderTime()); |
| | | createReqDTO.setDiscountPercent(saleOrder.getDiscountPercent()); |
| | | createReqDTO.setDepositPrice(saleOrder.getDepositPrice()); |
| | | createReqDTO.setItems(items.stream().map(item -> { |
| | | CrmContractCreateFromSaleOrderReqDTO.Item contractItem = new CrmContractCreateFromSaleOrderReqDTO.Item(); |
| | | contractItem.setItemId(item.getProductId()); |
| | | contractItem.setItemUnitId(item.getProductUnitId()); |
| | | contractItem.setPrice(item.getProductPrice()); |
| | | contractItem.setCount(item.getCount()); |
| | | return contractItem; |
| | | }).toList()); |
| | | |
| | | CrmContractRespDTO contract = contractApi.createContractDraftFromSaleOrder(createReqDTO).getCheckedData(); |
| | | if (contract != null) { |
| | | saleOrderMapper.updateById(new ErpSaleOrderDO().setId(saleOrder.getId()) |
| | | .setContractId(contract.getId()).setContractNo(contract.getNo())); |
| | | log.info("[createContractForSaleOrder] 销售订单({}) 自动生成合同({}) 成功", |
| | | saleOrder.getNo(), contract.getNo()); |
| | | } |
| | | } catch (Exception e) { |
| | | // 合同生成失败不阻塞订单审批,记录日志便于排查 |
| | | log.error("[createContractForSaleOrder] 销售订单({}) 自动生成销售合同失败", saleOrder.getNo(), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | @Override |
| | | public PageResult<ErpSaleOrderDO> getSaleOrderPage(ErpSaleOrderPageReqVO pageReqVO) { |
| | | List<Long> permittedCustomerIds = customerApi.getPermittedCustomerIds(); |
| | | return saleOrderMapper.selectPage(pageReqVO, permittedCustomerIds); |
| | | return saleOrderMapper.selectPage(pageReqVO); |
| | | } |
| | | |
| | | // ==================== 订单项 ==================== |