yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java
@@ -7,31 +7,25 @@
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO;
import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseOrderItemMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseOrderMapper;
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.ErpPurchaseOrderInStatusEnum;
import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
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.*;
// TODO 芋艿:记录操作日志
/**
 * ERP 采购订单 Service 实现类
@@ -50,8 +44,6 @@
    @Resource
    private ErpNoRedisDAO noRedisDAO;
    @Resource
    private ErpProductService productService;
    @Resource
    private ErpSupplierService supplierService;
    @Resource
@@ -74,9 +66,9 @@
            throw exception(PURCHASE_ORDER_NO_EXISTS);
        }
        // 2.1 插入订单
        // 2.1 插入订单(采购订单不需要审批,直接为已审核状态)
        ErpPurchaseOrderDO purchaseOrder = BeanUtils.toBean(createReqVO, ErpPurchaseOrderDO.class, in -> in
                .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()));
                .setNo(no).setStatus(ErpAuditStatus.APPROVE.getStatus()));
        calculateTotalPrice(purchaseOrder, purchaseOrderItems);
        purchaseOrderMapper.insert(purchaseOrder);
        // 2.2 插入订单项
@@ -90,6 +82,7 @@
    public void updatePurchaseOrder(ErpPurchaseOrderSaveReqVO updateReqVO) {
        // 1.1 校验存在
        ErpPurchaseOrderDO purchaseOrder = validatePurchaseOrderExists(updateReqVO.getId());
        // 采购订单不允许修改(已审核状态)
        if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseOrder.getStatus())) {
            throw exception(PURCHASE_ORDER_UPDATE_FAIL_APPROVE, purchaseOrder.getNo());
        }
@@ -126,6 +119,8 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePurchaseOrderStatus(Long id, Integer status) {
        // 采购订单不再支持状态流转(不需要审批)
        // 此方法保留用于特殊情况(如反审核后重新审核)
        boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status);
        // 1.1 校验存在
        ErpPurchaseOrderDO purchaseOrder = validatePurchaseOrderExists(id);
@@ -133,12 +128,14 @@
        if (purchaseOrder.getStatus().equals(status)) {
            throw exception(approve ? PURCHASE_ORDER_APPROVE_FAIL : PURCHASE_ORDER_PROCESS_FAIL);
        }
        // 1.3 存在采购入单,无法反审核
        if (!approve && purchaseOrder.getInCount().compareTo(BigDecimal.ZERO) > 0) {
        // 1.3 存在采购入库单,无法反审核
        BigDecimal inCount = purchaseOrder.getInCount();
        if (!approve && inCount != null && inCount.compareTo(BigDecimal.ZERO) > 0) {
            throw exception(PURCHASE_ORDER_PROCESS_FAIL_EXISTS_IN);
        }
        // 1.4 存在采购退货单,无法反审核
        if (!approve && purchaseOrder.getReturnCount().compareTo(BigDecimal.ZERO) > 0) {
        BigDecimal returnCount = purchaseOrder.getReturnCount();
        if (!approve && returnCount != null && returnCount.compareTo(BigDecimal.ZERO) > 0) {
            throw exception(PURCHASE_ORDER_PROCESS_FAIL_EXISTS_RETURN);
        }
@@ -151,13 +148,8 @@
    }
    private List<ErpPurchaseOrderItemDO> validatePurchaseOrderItems(List<ErpPurchaseOrderSaveReqVO.Item> list) {
        // 1. 校验产品存在
        List<ErpProductDO> productList = productService.validProductList(
                convertSet(list, ErpPurchaseOrderSaveReqVO.Item::getProductId));
        Map<Long, ErpProductDO> productMap = convertMap(productList, ErpProductDO::getId);
        // 2. 转化为 ErpPurchaseOrderItemDO 列表
        // 转化为 ErpPurchaseOrderItemDO 列表(产品验证已移除)
        return convertList(list, o -> BeanUtils.toBean(o, ErpPurchaseOrderItemDO.class, item -> {
            item.setProductUnitId(productMap.get(item.getProductId()).getUnitId());
            item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount()));
            if (item.getTotalPrice() == null) {
                return;
@@ -171,7 +163,7 @@
    private void updatePurchaseOrderItemList(Long id, List<ErpPurchaseOrderItemDO> newList) {
        // 第一步,对比新老数据,获得添加、修改、删除的列表
        List<ErpPurchaseOrderItemDO> oldList = purchaseOrderItemMapper.selectListByOrderId(id);
        List<List<ErpPurchaseOrderItemDO>> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录
        List<List<ErpPurchaseOrderItemDO>> diffList = diffList(oldList, newList,
                (oldVal, newVal) -> oldVal.getId().equals(newVal.getId()));
        // 第二步,批量添加、修改、删除
@@ -198,7 +190,7 @@
            }
            if (inCount.compareTo(item.getCount()) > 0) {
                throw exception(PURCHASE_ORDER_ITEM_IN_FAIL_PRODUCT_EXCEED,
                        productService.getProduct(item.getProductId()).getName(), item.getCount());
                        "产品ID:" + item.getProductId(), item.getCount());
            }
            purchaseOrderItemMapper.updateById(new ErpPurchaseOrderItemDO().setId(item.getId()).setInCount(inCount));
        });
@@ -218,7 +210,7 @@
            }
            if (returnCount.compareTo(item.getInCount()) > 0) {
                throw exception(PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED,
                        productService.getProduct(item.getProductId()).getName(), item.getInCount());
                        "产品ID:" + item.getProductId(), item.getInCount());
            }
            purchaseOrderItemMapper.updateById(new ErpPurchaseOrderItemDO().setId(item.getId()).setReturnCount(returnCount));
        });
@@ -241,11 +233,9 @@
            }
        });
        // 2. 遍历删除,并记录操作日志
        // 2. 遍历删除
        purchaseOrders.forEach(purchaseOrder -> {
            // 2.1 删除订单
            purchaseOrderMapper.deleteById(purchaseOrder.getId());
            // 2.2 删除订单项
            purchaseOrderItemMapper.deleteByOrderId(purchaseOrder.getId());
        });
    }
@@ -292,4 +282,67 @@
        return purchaseOrderItemMapper.selectListByOrderIds(orderIds);
    }
}
    @Override
    public List<ErpPurchaseOrderDO> getPurchaseOrderListBySupplierIdAndStatus(Long supplierId, Integer status) {
        if (supplierId == null) {
            return Collections.emptyList();
        }
        return purchaseOrderMapper.selectList(supplierId, status);
    }
    @Override
    public List<ErpPurchaseOrderDO> getPurchaseOrderList(List<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return purchaseOrderMapper.selectByIds(ids);
    }
    @Override
    public void updatePurchaseOrderInStatus(Long orderId) {
        // 1. 获取采购订单
        ErpPurchaseOrderDO order = validatePurchaseOrderExists(orderId);
        // 2. 获取采购订单明细
        List<ErpPurchaseOrderItemDO> items = purchaseOrderItemMapper.selectListByOrderId(orderId);
        if (CollUtil.isEmpty(items)) {
            return;
        }
        // 3. 计算入库状态
        int inStatus = calculateInStatus(items);
        // 4. 更新采购订单入库状态
        purchaseOrderMapper.updateById(new ErpPurchaseOrderDO()
                .setId(orderId).setInStatus(inStatus));
    }
    /**
     * 计算入库状态
     *
     * @param items 采购订单明细列表
     * @return 入库状态
     */
    private int calculateInStatus(List<ErpPurchaseOrderItemDO> items) {
        boolean allIn = true;
        boolean anyIn = false;
        for (ErpPurchaseOrderItemDO item : items) {
            BigDecimal count = item.getCount() != null ? item.getCount() : BigDecimal.ZERO;
            BigDecimal inCount = item.getInCount() != null ? item.getInCount() : BigDecimal.ZERO;
            if (inCount.compareTo(BigDecimal.ZERO) > 0) {
                anyIn = true;
            }
            if (inCount.compareTo(count) < 0) {
                allIn = false;
            }
        }
        if (allIn) {
            return ErpPurchaseOrderInStatusEnum.ALL_IN.getStatus();
        } else if (anyIn) {
            return ErpPurchaseOrderInStatusEnum.PART_IN.getStatus();
        } else {
            return ErpPurchaseOrderInStatusEnum.NOT_IN.getStatus();
        }
    }
}