| | |
| | | import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOrderMapper; |
| | | import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; |
| | | import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; |
| | | import cn.iocoder.yudao.module.erp.enums.ErpSaleOrderOutStatusEnum; |
| | | import cn.iocoder.yudao.module.erp.api.sale.enums.ErpSaleOrderOutStatusEnum; |
| | | import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; |
| | | import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; |
| | | import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; |
| | | import cn.iocoder.yudao.module.mes.api.mps.MesProMpsApi; |
| | | import cn.iocoder.yudao.module.mes.api.mps.dto.MesProMpsCreateReqDTO; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | |
| | | */ |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { |
| | | |
| | | @Resource |
| | |
| | | |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | |
| | | @Resource |
| | | private MdmItemApi mdmItemApi; |
| | | @Resource |
| | | private MesProMpsApi mpsApi; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | |
| | | // 2.1 插入订单 |
| | | ErpSaleOrderDO saleOrder = BeanUtils.toBean(createReqVO, ErpSaleOrderDO.class, in -> in |
| | | .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())); |
| | | .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) |
| | | .setOutCount(BigDecimal.ZERO).setOutStatus(ErpSaleOrderOutStatusEnum.NOT_OUT.getStatus())); |
| | | calculateTotalPrice(saleOrder, saleOrderItems); |
| | | saleOrderMapper.insert(saleOrder); |
| | | // 2.2 插入订单项 |
| | |
| | | if (!approve && outCount.compareTo(BigDecimal.ZERO) > 0) { |
| | | throw exception(SALE_ORDER_PROCESS_FAIL_EXISTS_OUT); |
| | | } |
| | | // 1.4 存在销售退货单,无法反审核 |
| | | BigDecimal returnCount = saleOrder.getReturnCount() != null ? saleOrder.getReturnCount() : BigDecimal.ZERO; |
| | | if (!approve && returnCount.compareTo(BigDecimal.ZERO) > 0) { |
| | | throw exception(SALE_ORDER_PROCESS_FAIL_EXISTS_RETURN); |
| | | } |
| | | |
| | | // 2. 更新状态 |
| | | int updateCount = saleOrderMapper.updateByIdAndStatus(id, saleOrder.getStatus(), |
| | |
| | | if (updateCount == 0) { |
| | | throw exception(approve ? SALE_ORDER_APPROVE_FAIL : SALE_ORDER_PROCESS_FAIL); |
| | | } |
| | | |
| | | // 3. 审核通过时,为需要生产的明细创建 MPS |
| | | if (approve) { |
| | | createMpsForSaleOrder(id, saleOrder); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 为销售订单中需要生产的明细创建 MPS |
| | | * |
| | | * @param orderId 销售订单编号 |
| | | * @param saleOrder 销售订单 |
| | | */ |
| | | private void createMpsForSaleOrder(Long orderId, ErpSaleOrderDO saleOrder) { |
| | | List<ErpSaleOrderItemDO> items = saleOrderItemMapper.selectListByOrderId(orderId); |
| | | if (CollUtil.isEmpty(items)) { |
| | | return; |
| | | } |
| | | |
| | | int mpsCount = 0; |
| | | for (ErpSaleOrderItemDO item : items) { |
| | | if (item.getNeedProduction() == null || item.getNeedProduction() != 1) { |
| | | continue; |
| | | } |
| | | try { |
| | | Long mpsId = createMpsForSaleOrderItem(saleOrder, item); |
| | | if (mpsId != null) { |
| | | mpsCount++; |
| | | // 更新销售订单明细的 MPS 关联 |
| | | saleOrderItemMapper.updateById(new ErpSaleOrderItemDO() |
| | | .setId(item.getId()) |
| | | .setMpsId(mpsId)); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("[createMpsForSaleOrder] 创建 MPS 失败,saleOrderItemId={}", item.getId(), e); |
| | | } |
| | | } |
| | | log.info("[createMpsForSaleOrder] 销售订单({}) 审核完成,创建 MPS {} 条", orderId, mpsCount); |
| | | } |
| | | |
| | | /** |
| | | * 为销售订单明细创建 MPS |
| | | */ |
| | | private Long createMpsForSaleOrderItem(ErpSaleOrderDO saleOrder, ErpSaleOrderItemDO item) { |
| | | // 获取 MDM 物料信息(用于获取产品名称) |
| | | String productName = null; |
| | | try { |
| | | MdmItemRespDTO mdmItem = mdmItemApi.getItem(item.getProductId()).getCheckedData(); |
| | | if (mdmItem != null) { |
| | | productName = mdmItem.getName(); |
| | | } |
| | | } catch (Exception e) { |
| | | log.warn("[createMpsForSaleOrderItem] 获取 MDM 物料信息失败,productId={}", item.getProductId(), e); |
| | | } |
| | | |
| | | MesProMpsCreateReqDTO createReqDTO = new MesProMpsCreateReqDTO(); |
| | | createReqDTO.setSaleOrderId(saleOrder.getId()); |
| | | createReqDTO.setSaleOrderNo(saleOrder.getNo()); |
| | | createReqDTO.setSaleOrderItemId(item.getId()); |
| | | createReqDTO.setMdmItemId(item.getProductId()); |
| | | createReqDTO.setProductName(productName); |
| | | createReqDTO.setQuantity(item.getCount()); |
| | | createReqDTO.setClientId(saleOrder.getCustomerId()); |
| | | createReqDTO.setRequestDate(formatRequestDate(saleOrder.getOrderTime())); |
| | | createReqDTO.setRemark("自动生成,来自销售订单:" + saleOrder.getNo()); |
| | | |
| | | Long mpsId = mpsApi.createMps(createReqDTO); |
| | | log.info("[createMpsForSaleOrderItem] MPS 创建成功,mpsId={}, saleOrderItemId={}", mpsId, item.getId()); |
| | | return mpsId; |
| | | } |
| | | |
| | | /** |
| | | * 格式化需求日期 |
| | | */ |
| | | private String formatRequestDate(LocalDateTime dateTime) { |
| | | if (dateTime == null) { |
| | | return null; |
| | | } |
| | | return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); |
| | | } |
| | | |
| | | @Override |
| | |
| | | BigDecimal outCount = saleOrder.getOutCount() != null ? saleOrder.getOutCount() : BigDecimal.ZERO; |
| | | if (outCount.compareTo(BigDecimal.ZERO) > 0) { |
| | | throw exception(SALE_ORDER_CANCEL_FAIL_EXISTS_OUT); |
| | | } |
| | | // 1.4 存在销售退货单,无法作废 |
| | | BigDecimal returnCount = saleOrder.getReturnCount() != null ? saleOrder.getReturnCount() : BigDecimal.ZERO; |
| | | if (returnCount.compareTo(BigDecimal.ZERO) > 0) { |
| | | throw exception(SALE_ORDER_CANCEL_FAIL_EXISTS_RETURN); |
| | | } |
| | | |
| | | // 2. 更新状态为已作废 |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void updateSaleOrderReturnCount(Long orderId, Map<Long, BigDecimal> returnCountMap) { |
| | | List<ErpSaleOrderItemDO> orderItems = saleOrderItemMapper.selectListByOrderId(orderId); |
| | | // 1. 更新每个销售订单项 |
| | | orderItems.forEach(item -> { |
| | | BigDecimal returnCount = returnCountMap.getOrDefault(item.getId(), BigDecimal.ZERO); |
| | | if (item.getReturnCount().equals(returnCount)) { |
| | | return; |
| | | } |
| | | if (returnCount.compareTo(item.getOutCount()) > 0) { |
| | | throw exception(SALE_ORDER_ITEM_RETURN_FAIL_OUT_EXCEED, |
| | | "产品ID:" + item.getProductId(), item.getOutCount()); |
| | | } |
| | | saleOrderItemMapper.updateById(new ErpSaleOrderItemDO().setId(item.getId()).setReturnCount(returnCount)); |
| | | }); |
| | | // 2. 更新销售订单 |
| | | BigDecimal totalReturnCount = getSumValue(returnCountMap.values(), value -> value, BigDecimal::add, BigDecimal.ZERO); |
| | | saleOrderMapper.updateById(new ErpSaleOrderDO().setId(orderId).setReturnCount(totalReturnCount)); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteSaleOrder(List<Long> ids) { |
| | | // 1. 校验不处于已审批 |
| | |
| | | |
| | | @Override |
| | | public PageResult<ErpSaleOrderDO> getSaleOrderPage(ErpSaleOrderPageReqVO pageReqVO) { |
| | | return saleOrderMapper.selectPage(pageReqVO); |
| | | List<Long> permittedCustomerIds = customerApi.getPermittedCustomerIds(); |
| | | return saleOrderMapper.selectPage(pageReqVO, permittedCustomerIds); |
| | | } |
| | | |
| | | // ==================== 订单项 ==================== |
| | |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |