Merge remote-tracking branch 'origin/dev_pro_河南鹤壁' into dev_pro_河南鹤壁_泽淇实业

# Conflicts:
# src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java
# src/main/resources/mapper/basic/CustomerMapper.xml
已修改13个文件
601 ■■■■■ 文件已修改
src/main/java/com/ruoyi/RuoYiApplication.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java 245 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesTrendDto.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-sdtx.yml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/CustomerMapper.xml 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/SupplierManageMapper.xml 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/collaborativeApproval/NoticeMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/RuoYiApplication.java
@@ -7,11 +7,11 @@
/**
 * 启动程序
 *
 *
 * @author ruoyi
 */
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@EnableScheduling
//@EnableScheduling
public class RuoYiApplication
{
    public static void main(String[] args)
src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java
@@ -12,6 +12,7 @@
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * 客户档案Mapper接口
@@ -20,55 +21,7 @@
 * @date 2025-05-07
 */
@Mapper
public interface CustomerMapper extends BaseMapper<Customer>
{
    /**
     * 查询客户档案
     *
     * @param id 客户档案主键
     * @return 客户档案
     */
    Customer selectCustomerById(Long id);
    /**
     * 查询客户档案列表
     *
     * @param customer 客户档案
     * @return 客户档案集合
     */
    List<Customer> selectCustomerList(Customer customer);
    /**
     * 新增客户档案
     *
     * @param customer 客户档案
     * @return 结果
     */
    int insertCustomer(Customer customer);
    /**
     * 修改客户档案
     *
     * @param customer 客户档案
     * @return 结果
     */
    int updateCustomer(Customer customer);
    /**
     * 删除客户档案
     *
     * @param id 客户档案主键
     * @return 结果
     */
    int deleteCustomerById(Long id);
    /**
     * 批量删除客户档案
     *
     * @param ids 需要删除的数据主键集合
     * @return 结果
     */
    int deleteCustomerByIds(Long[] ids);
public interface CustomerMapper extends BaseMapper<Customer> {
    IPage<CustomerVo> listPage(Page<CustomerDto> page, @Param("c") CustomerDto customer, @Param("loginUserId") Long loginUserId);
@@ -77,4 +30,8 @@
    IPage<CustomerTransactionsVo> customewTransactions(Page page, @Param("customerName") String customerName);
    IPage<CustomerTransactionsDetailsVo> customewTransactionsDetails(Page page, @Param("customerId") Long customerId);
    List<Map<String, Object>> getShippedAmountByCustomerIds(@Param("customerIds") List<Long> customerIds);
    List<Map<String, Object>> getShippedAmountBySalesLedgerIds(@Param("salesLedgerIds") List<Long> salesLedgerIds);
}
src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
@@ -34,6 +34,7 @@
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.math.BigDecimal;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
@@ -383,12 +384,56 @@
    @Override
    public IPage<CustomerTransactionsVo> customewTransactions(Page page, String customerName) {
        return customerMapper.customewTransactions(page, customerName);
        IPage<CustomerTransactionsVo> p = customerMapper.customewTransactions(page, customerName);
        List<CustomerTransactionsVo> records = p.getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            List<Long> customerIds = records.stream().map(CustomerTransactionsVo::getCustomerId).collect(Collectors.toList());
            List<Map<String, Object>> shippedAmountList = customerMapper.getShippedAmountByCustomerIds(customerIds);
            Map<Long, BigDecimal> shippedAmountMap = new HashMap<>();
            for (Map<String, Object> map : shippedAmountList) {
                if (map.get("outboundAmount") != null) {
                    shippedAmountMap.put(((Number) map.get("customerId")).longValue(), new BigDecimal(String.valueOf(map.get("outboundAmount"))));
                }
            }
            for (CustomerTransactionsVo vo : records) {
                BigDecimal outboundAmount = shippedAmountMap.getOrDefault(vo.getCustomerId(), BigDecimal.ZERO);
                vo.setShippedAmount(outboundAmount);
                BigDecimal contractAmounts = vo.getContractAmounts() == null ? BigDecimal.ZERO : vo.getContractAmounts();
                BigDecimal unshippedAmount = contractAmounts.subtract(outboundAmount);
                if (unshippedAmount.compareTo(BigDecimal.ZERO) < 0) {
                    unshippedAmount = BigDecimal.ZERO;
                }
                vo.setUnshippedAmount(unshippedAmount);
            }
        }
        return p;
    }
    @Override
    public IPage<CustomerTransactionsDetailsVo> customewTransactionsDetails(Page page, Long customerId) {
        return customerMapper.customewTransactionsDetails(page, customerId);
        IPage<CustomerTransactionsDetailsVo> p = customerMapper.customewTransactionsDetails(page, customerId);
        List<CustomerTransactionsDetailsVo> records = p.getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            List<Long> salesLedgerIds = records.stream().map(CustomerTransactionsDetailsVo::getSalesLedgerId).collect(Collectors.toList());
            List<Map<String, Object>> shippedAmountList = customerMapper.getShippedAmountBySalesLedgerIds(salesLedgerIds);
            Map<Long, BigDecimal> shippedAmountMap = new HashMap<>();
            for (Map<String, Object> map : shippedAmountList) {
                if (map.get("outboundAmount") != null) {
                    shippedAmountMap.put(((Number) map.get("salesLedgerId")).longValue(), new BigDecimal(String.valueOf(map.get("outboundAmount"))));
                }
            }
            for (CustomerTransactionsDetailsVo vo : records) {
                BigDecimal outboundAmount = shippedAmountMap.getOrDefault(vo.getSalesLedgerId(), BigDecimal.ZERO);
                vo.setShippedAmount(outboundAmount);
                BigDecimal contractAmount = vo.getContractAmount() == null ? BigDecimal.ZERO : vo.getContractAmount();
                BigDecimal unshippedAmount = contractAmount.subtract(outboundAmount);
                if (unshippedAmount.compareTo(BigDecimal.ZERO) < 0) {
                    unshippedAmount = BigDecimal.ZERO;
                }
                vo.setUnshippedAmount(unshippedAmount);
            }
        }
        return p;
    }
    /**
src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java
@@ -16,32 +16,47 @@
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.purchase.vo.SupplierTransactionsDetailsVo;
import com.ruoyi.purchase.vo.SupplierTransactionsVo;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.mapper.QualityUnqualifiedMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityUnqualified;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.stock.mapper.StockInRecordMapper;
import com.ruoyi.stock.pojo.StockInRecord;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class SupplierServiceImpl extends ServiceImpl<SupplierManageMapper,SupplierManage> implements ISupplierService {
public class SupplierServiceImpl extends ServiceImpl<SupplierManageMapper, SupplierManage> implements ISupplierService {
    private final SupplierManageMapper supplierMapper;
    private final PurchaseLedgerMapper purchaseLedgerMapper;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    private final StockInRecordMapper stockInRecordMapper;
    private final QualityInspectMapper qualityInspectMapper;
    private final QualityUnqualifiedMapper qualityUnqualifiedMapper;
    /**
     * 供应商新增
     *
     * @param supplierManage
     * @return
     */
    @Override
    public void saveSupplier(SupplierManage supplierManage) {
        LambdaQueryWrapper<SupplierManage> supplierManageLambdaQueryWrapper = new LambdaQueryWrapper<>();
        supplierManageLambdaQueryWrapper.eq(SupplierManage::getSupplierName,supplierManage.getSupplierName());
        supplierManageLambdaQueryWrapper.eq(SupplierManage::getSupplierName, supplierManage.getSupplierName());
        if (supplierMapper.selectCount(supplierManageLambdaQueryWrapper) > 0) {
            throw new RuntimeException("供应商已存在");
        }
@@ -50,6 +65,7 @@
    /**
     * 供应商删除
     *
     * @param ids
     * @return
     */
@@ -67,6 +83,7 @@
    /**
     * 供应商详情
     *
     * @param id
     * @return
     */
@@ -77,6 +94,7 @@
    /**
     * 供应商修改
     *
     * @param supplierManage
     * @return
     */
@@ -87,17 +105,19 @@
    /**
     * 供应商分页查询
     *
     * @param page
     * @param supplierManageDto
     * @return
     */
    @Override
    public IPage<SupplierManage> supplierListPage(Page page, SupplierManageDto supplierManageDto) {
        return supplierMapper.supplierListPage(page,supplierManageDto);
        return supplierMapper.supplierListPage(page, supplierManageDto);
    }
    /**
     * 供应商导出
     *
     * @param response
     * @param supplierManageDto
     */
@@ -115,19 +135,19 @@
            ExcelUtil<SupplierManageExcelDto> util = new ExcelUtil<SupplierManageExcelDto>(SupplierManageExcelDto.class);
            List<SupplierManageExcelDto> list = util.importExcel(file.getInputStream());
            ArrayList<SupplierManage> supplierManages = new ArrayList<>();
            list.stream().forEach(dto -> {
            list.forEach(dto -> {
                SupplierManage supplierManage = new SupplierManage();
                BeanUtils.copyProperties(dto,supplierManage);
                BeanUtils.copyProperties(dto, supplierManage);
                supplierManage.setMaintainTime(LocalDate.now());
                Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
                supplierManage.setMaintainUserId(Integer.parseInt(userId+""));
                supplierManage.setMaintainUserId(Integer.parseInt(userId + ""));
                supplierManages.add(supplierManage);
            });
            this.saveOrUpdateBatch(supplierManages);
            return true;
        }catch (Exception e){
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
@@ -135,11 +155,218 @@
    @Override
    public IPage<SupplierTransactionsVo> supplierTransactions(Page page, String supplierName) {
        return supplierMapper.supplierTransactions(page,supplierName);
        IPage<SupplierTransactionsVo> plPage = supplierMapper.supplierTransactions(page, supplierName);
        List<SupplierTransactionsVo> resultList = plPage.getRecords();
        if (resultList.isEmpty()) {
            return plPage;
        }
        List<Long> supplierIds = resultList.stream().map(SupplierTransactionsVo::getSupplierId).collect(Collectors.toList());
        List<PurchaseLedger> purchaseLedgers = purchaseLedgerMapper.selectList(new LambdaQueryWrapper<PurchaseLedger>()
                .in(PurchaseLedger::getSupplierId, supplierIds));
        if (purchaseLedgers.isEmpty()) {
            for (SupplierTransactionsVo vo : resultList) {
                vo.setShippedAmount(BigDecimal.ZERO);
                BigDecimal contractAmount = vo.getContractAmounts() == null ? BigDecimal.ZERO : vo.getContractAmounts();
                vo.setUnshippedAmount(contractAmount);
            }
            return plPage;
        }
        List<Long> ledgerIds = purchaseLedgers.stream().map(PurchaseLedger::getId).collect(Collectors.toList());
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
                .in(SalesLedgerProduct::getSalesLedgerId, ledgerIds)
                .eq(SalesLedgerProduct::getType, 2));
        //  不质检直接入库的 - 7
        List<StockInRecord> directInboundRecords = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>()
                .eq(StockInRecord::getRecordType, "7")
                .eq(StockInRecord::getApprovalStatus, 1)
                .in(StockInRecord::getRecordId, ledgerIds));
        //  通过质检入库的
        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                .in(QualityInspect::getPurchaseLedgerId, ledgerIds));
        List<Long> inspectIds = qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList());
        //  质检合格入库 - 10
        List<StockInRecord> qualifiedInboundRecords = new ArrayList<>();
        List<QualityUnqualified> qualityUnqualifieds = new ArrayList<>();
        if (!inspectIds.isEmpty()) {
            qualifiedInboundRecords = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>()
                    .eq(StockInRecord::getRecordType, "10")
                    .eq(StockInRecord::getApprovalStatus, 1)
                    .in(StockInRecord::getRecordId, inspectIds));
            qualityUnqualifieds = qualityUnqualifiedMapper.selectList(new LambdaQueryWrapper<QualityUnqualified>()
                    .in(QualityUnqualified::getInspectId, inspectIds));
        }
        List<Long> unqualifiedIds = qualityUnqualifieds.stream().map(QualityUnqualified::getId).collect(Collectors.toList());
        //  质检不合格入库 - 11
        List<StockInRecord> unqualifiedInboundRecords = new ArrayList<>();
        if (!unqualifiedIds.isEmpty()) {
            unqualifiedInboundRecords = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>()
                    .eq(StockInRecord::getRecordType, "11")
                    .eq(StockInRecord::getApprovalStatus, 1)
                    .in(StockInRecord::getRecordId, unqualifiedIds));
        }
        for (SupplierTransactionsVo vo : resultList) {
            BigDecimal shippedAmount = BigDecimal.ZERO;
            List<PurchaseLedger> currentLedgers = purchaseLedgers.stream().filter(pl -> pl.getSupplierId().equals(vo.getSupplierId())).toList();
            for (PurchaseLedger ledger : currentLedgers) {
                Long ledgerId = ledger.getId();
                List<StockInRecord> currentDirectRecords = directInboundRecords.stream().filter(s -> s.getRecordId().equals(ledgerId)).toList();
                for (StockInRecord sir : currentDirectRecords) {
                    List<SalesLedgerProduct> currentProducts = salesLedgerProducts.stream().filter(s -> s.getSalesLedgerId().equals(ledgerId)).toList();
                    for (SalesLedgerProduct slp : currentProducts) {
                        if (sir.getStockInNum() != null && slp.getTaxInclusiveUnitPrice() != null) {
                            shippedAmount = shippedAmount.add(sir.getStockInNum().multiply(slp.getTaxInclusiveUnitPrice()));
                        }
                    }
                }
                List<QualityInspect> currentInspects = qualityInspects.stream().filter(q -> q.getPurchaseLedgerId().equals(ledgerId)).toList();
                for (QualityInspect inspect : currentInspects) {
                    List<StockInRecord> currentQualifiedRecords = qualifiedInboundRecords.stream().filter(s -> s.getRecordId().equals(inspect.getId())).toList();
                    for (StockInRecord sir : currentQualifiedRecords) {
                        BigDecimal minPrice = getMinTaxInclusiveUnitPrice(salesLedgerProducts, ledgerId, sir.getProductModelId());
                        if (sir.getStockInNum() != null && minPrice != null) {
                            shippedAmount = shippedAmount.add(sir.getStockInNum().multiply(minPrice));
                        }
                    }
                    List<QualityUnqualified> currentUnqualifieds = qualityUnqualifieds.stream().filter(q -> q.getInspectId().equals(inspect.getId())).toList();
                    for (QualityUnqualified unqualified : currentUnqualifieds) {
                        List<StockInRecord> currentUnqualifiedRecords = unqualifiedInboundRecords.stream().filter(s -> s.getRecordId().equals(unqualified.getId())).toList();
                        for (StockInRecord sir : currentUnqualifiedRecords) {
                            BigDecimal minPrice = getMinTaxInclusiveUnitPrice(salesLedgerProducts, ledgerId, sir.getProductModelId());
                            if (sir.getStockInNum() != null && minPrice != null) {
                                shippedAmount = shippedAmount.add(sir.getStockInNum().multiply(minPrice));
                            }
                        }
                    }
                }
            }
            BigDecimal contractAmount = vo.getContractAmounts() == null ? BigDecimal.ZERO : vo.getContractAmounts();
            if (shippedAmount.subtract(contractAmount).compareTo(BigDecimal.ZERO) > 0) {
                shippedAmount = contractAmount;
            }
            vo.setShippedAmount(shippedAmount);
            vo.setUnshippedAmount(contractAmount.subtract(shippedAmount));
        }
        return plPage;
    }
    @Override
    public IPage<SupplierTransactionsDetailsVo> supplierTransactionsDetails(Page page, Long supplierId) {
        return supplierMapper.supplierTransactionsDetails(page,supplierId);
        IPage<SupplierTransactionsDetailsVo> plPage = supplierMapper.supplierTransactionsDetails(page, supplierId);
        List<SupplierTransactionsDetailsVo> resultList = plPage.getRecords();
        if (resultList.isEmpty()) {
            return plPage;
        }
        List<Long> ledgerIds = resultList.stream().map(SupplierTransactionsDetailsVo::getPurchaseLedgerId).collect(Collectors.toList());
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
                .in(SalesLedgerProduct::getSalesLedgerId, ledgerIds)
                .eq(SalesLedgerProduct::getType, 2));
        //  不质检直接入库的 - 7
        List<StockInRecord> directInboundRecords = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>()
                .eq(StockInRecord::getRecordType, "7")
                .eq(StockInRecord::getApprovalStatus, 1)
                .in(StockInRecord::getRecordId, ledgerIds));
        //  通过质检入库的
        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                .in(QualityInspect::getPurchaseLedgerId, ledgerIds));
        List<Long> inspectIds = qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList());
        //  质检合格入库 - 10
        List<StockInRecord> qualifiedInboundRecords = new ArrayList<>();
        List<QualityUnqualified> qualityUnqualifieds = new ArrayList<>();
        if (!inspectIds.isEmpty()) {
            qualifiedInboundRecords = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>()
                    .eq(StockInRecord::getRecordType, "10")
                    .eq(StockInRecord::getApprovalStatus, 1)
                    .in(StockInRecord::getRecordId, inspectIds));
            qualityUnqualifieds = qualityUnqualifiedMapper.selectList(new LambdaQueryWrapper<QualityUnqualified>()
                    .in(QualityUnqualified::getInspectId, inspectIds));
        }
        List<Long> unqualifiedIds = qualityUnqualifieds.stream().map(QualityUnqualified::getId).collect(Collectors.toList());
        //  质检不合格入库 - 11
        List<StockInRecord> unqualifiedInboundRecords = new ArrayList<>();
        if (!unqualifiedIds.isEmpty()) {
            unqualifiedInboundRecords = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>()
                    .eq(StockInRecord::getRecordType, "11")
                    .eq(StockInRecord::getApprovalStatus, 1)
                    .in(StockInRecord::getRecordId, unqualifiedIds));
        }
        for (SupplierTransactionsDetailsVo vo : resultList) {
            BigDecimal shippedAmount = BigDecimal.ZERO;
            List<StockInRecord> currentDirectRecords = directInboundRecords.stream().filter(s -> s.getRecordId().equals(vo.getPurchaseLedgerId())).toList();
            for (StockInRecord sir : currentDirectRecords) {
                List<SalesLedgerProduct> currentProducts = salesLedgerProducts.stream().filter(s -> s.getSalesLedgerId().equals(vo.getPurchaseLedgerId())).toList();
                for (SalesLedgerProduct slp : currentProducts) {
                    if (sir.getStockInNum() != null && slp.getTaxInclusiveUnitPrice() != null) {
                        shippedAmount = shippedAmount.add(sir.getStockInNum().multiply(slp.getTaxInclusiveUnitPrice()));
                    }
                }
            }
            List<QualityInspect> currentInspects = qualityInspects.stream().filter(q -> q.getPurchaseLedgerId().equals(vo.getPurchaseLedgerId())).toList();
            for (QualityInspect inspect : currentInspects) {
                List<StockInRecord> currentQualifiedRecords = qualifiedInboundRecords.stream().filter(s -> s.getRecordId().equals(inspect.getId())).toList();
                for (StockInRecord sir : currentQualifiedRecords) {
                    BigDecimal minPrice = getMinTaxInclusiveUnitPrice(salesLedgerProducts, vo.getPurchaseLedgerId(), sir.getProductModelId());
                    if (sir.getStockInNum() != null && minPrice != null) {
                        shippedAmount = shippedAmount.add(sir.getStockInNum().multiply(minPrice));
                    }
                }
                List<QualityUnqualified> currentUnqualifieds = qualityUnqualifieds.stream().filter(q -> q.getInspectId().equals(inspect.getId())).toList();
                for (QualityUnqualified unqualified : currentUnqualifieds) {
                    List<StockInRecord> currentUnqualifiedRecords = unqualifiedInboundRecords.stream().filter(s -> s.getRecordId().equals(unqualified.getId())).toList();
                    for (StockInRecord sir : currentUnqualifiedRecords) {
                        BigDecimal minPrice = getMinTaxInclusiveUnitPrice(salesLedgerProducts, vo.getPurchaseLedgerId(), sir.getProductModelId());
                        if (sir.getStockInNum() != null && minPrice != null) {
                            shippedAmount = shippedAmount.add(sir.getStockInNum().multiply(minPrice));
                        }
                    }
                }
            }
            BigDecimal contractAmount = vo.getContractAmount() == null ? BigDecimal.ZERO : vo.getContractAmount();
            if (shippedAmount.subtract(contractAmount).compareTo(BigDecimal.ZERO) > 0) {
                shippedAmount = contractAmount;
            }
            vo.setShippedAmount(shippedAmount);
            vo.setUnshippedAmount(contractAmount.subtract(shippedAmount));
        }
        return plPage;
    }
    private BigDecimal getMinTaxInclusiveUnitPrice(List<SalesLedgerProduct> allSlp, Long salesLedgerId, Long productModelId) {
        return allSlp.stream()
                .filter(s -> s.getSalesLedgerId().equals(salesLedgerId) && s.getProductModelId() != null && s.getProductModelId().equals(productModelId))
                .map(SalesLedgerProduct::getTaxInclusiveUnitPrice)
                .filter(java.util.Objects::nonNull)
                .min(BigDecimal::compareTo)
                .orElse(null);
    }
}
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -61,6 +61,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
@@ -497,9 +498,20 @@
    @Override
    public ProductionProgressDto productionProgress() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startOfMonth = now
                .with(TemporalAdjusters.firstDayOfMonth())
                .with(LocalTime.MIN);
        LocalDateTime endOfMonth = now
                .with(TemporalAdjusters.lastDayOfMonth())
                .with(LocalTime.MAX);
        ProductionProgressDto productionProgressDto = new ProductionProgressDto();
        List<ProductionProgressOrderDto> orderDetails = productionOrderMapper.selectProgressOrders(
                LocalDateTime.now().minusMonths(1), LocalDateTime.now());
        List<ProductionProgressOrderDto> orderDetails = productionOrderMapper
                .selectProgressOrders(startOfMonth, endOfMonth);
        productionProgressDto.setCompletedOrderDetails(orderDetails);
        long totalCount = orderDetails.size();
        long count = orderDetails.stream().filter(
@@ -519,7 +531,7 @@
    public ProductionTurnoverDto workInProcessTurnover() {
        ProductionTurnoverDto productionTurnoverDto = new ProductionTurnoverDto();
        List<ProductionTaskStatisticsDto> taskList = productionOperationTaskMapper
                .selectTaskStatisticsByDate(LocalDate.now().minusMonths(1), LocalDate.now());
                .selectTaskStatisticsByDate(LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()));
        long sum = taskList.stream()
                .filter(task -> defaultDecimal(task.getPlanQuantity()).compareTo(defaultDecimal(task.getCompleteQuantity())) > 0)
                .map(ProductionTaskStatisticsDto::getPlanQuantity)
@@ -1625,16 +1637,16 @@
    @Override
    public List<MapDto> orderCount() {
        LocalDate now = LocalDate.now();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String currentStart = now.withDayOfMonth(1).atStartOfDay()
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        String currentEnd = now.atTime(LocalTime.MAX).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        LocalDateTime startDateTime = now.with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay();
        LocalDateTime endDateTime = now.with(TemporalAdjusters.lastDayOfMonth()).atTime(LocalTime.MAX);
        LocalDate lastMonthDate = now.minusMonths(1);
        String lastStart = lastMonthDate.withDayOfMonth(1).atStartOfDay()
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        String lastEnd = lastMonthDate.withDayOfMonth(lastMonthDate.lengthOfMonth()).atTime(LocalTime.MAX)
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        String currentStart = startDateTime.format(dateTimeFormatter);
        String currentEnd = endDateTime.format(dateTimeFormatter);
        String lastStart = startDateTime.minusMonths(1).format(dateTimeFormatter);
        String lastEnd = endDateTime.format(dateTimeFormatter);
        int currentCreated = productionOrderMapper.countCreated(currentStart, currentEnd);
        int lastCreated = productionOrderMapper.countCreated(lastStart, lastEnd);
src/main/java/com/ruoyi/sales/dto/SalesTrendDto.java
@@ -14,6 +14,7 @@
    private String month; // 月份(如2024-12)
    private Integer orderCount; // 订单数
    private BigDecimal salesAmount; // 销售额
    private BigDecimal productQuantity; // 产品销售数量
    private BigDecimal shipRate;
}
src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
@@ -66,6 +66,7 @@
            "DATE_FORMAT(sl.entry_date, '%Y-%m') AS month, " +
            "COUNT(DISTINCT sl.id) AS order_count, " +  // 总订单数
            "SUM(slp.tax_inclusive_total_price) AS sales_amount, " +  // 销售额
            "SUM(IFNULL(slp.quantity, 0)) AS product_quantity, " +  // 产品销售数量
            // 发货率 = 发货订单数 * 100 / 总订单数(保留2位小数,避免除0报错)
            "ROUND(IF(COUNT(DISTINCT sl.id) = 0, 0, " +
            "SUM(CASE WHEN slp.approve_status = 2 THEN 1 ELSE 0 END) / COUNT(DISTINCT sl.id) * 100), 2) AS ship_rate " +
src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java
@@ -51,9 +51,16 @@
        map.put("total", new BigDecimal(totalOrders));
        map.put("shipRate", "0.00%");
        //  发货率
        //  产品销售数量
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
                .eq(SalesLedgerProduct::getType, 1));
        BigDecimal productQuantityTotal = CollectionUtils.isEmpty(products) ? BigDecimal.ZERO :
                products.stream()
                        .map(SalesLedgerProduct::getQuantity)
                        .filter(Objects::nonNull)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
        map.put("productQuantityTotal", productQuantityTotal);
        if (CollectionUtils.isEmpty(products)) {
            return AjaxResult.success(map);
        }
@@ -116,6 +123,7 @@
        List<String> dateList = new ArrayList<>();
        List<BigDecimal> orderCountList = new ArrayList<>();
        List<BigDecimal> salesAmountList = new ArrayList<>();
        List<BigDecimal> productQuantityList = new ArrayList<>();
        List<BigDecimal> shippingRateList = new ArrayList<>();
        Calendar tempCalendar = Calendar.getInstance();
@@ -136,10 +144,12 @@
            if (dto != null) {
                orderCountList.add(new BigDecimal(dto.getOrderCount()));
                salesAmountList.add(dto.getSalesAmount() != null ? dto.getSalesAmount() : BigDecimal.ZERO);
                productQuantityList.add(dto.getProductQuantity() != null ? dto.getProductQuantity() : BigDecimal.ZERO);
                shippingRateList.add(new BigDecimal(String.valueOf(dto.getShipRate())));
            } else {
                orderCountList.add(BigDecimal.ZERO);
                salesAmountList.add(BigDecimal.ZERO);
                productQuantityList.add(BigDecimal.ZERO);
                shippingRateList.add(BigDecimal.ZERO);
            }
@@ -150,6 +160,7 @@
        map.put("dateList", dateList);
        map.put("orderCountList", orderCountList);
        map.put("salesAmountList", salesAmountList);
        map.put("productQuantityList", productQuantityList);
        map.put("shippingRateList", shippingRateList);
        return AjaxResult.success(map);
    }
src/main/resources/application-sdtx.yml
@@ -1,4 +1,3 @@
# 项目相关配置
ruoyi:
  # 名称
@@ -261,8 +260,8 @@
  temp-dir: /javaWork/product-inventory-management/file/temp/uploads   # 临时目录 后期删除
  upload-dir: /javaWork/product-inventory-management/file/prod/uploads # 正式目录 后期删除
  path: /javaWork/product-inventory-management/file/path/uploads # 上传目录
  urlPrefix: /common # 链接前缀
  domain: http://127.0.0.1:7003 # 域名前缀
  urlPrefix: /prod-api/common # 链接前缀
  domain: http://36.213.156.184:9001 # 域名前缀
  expired: 120 # 过期时间(单位:分钟)
  useLimit: 10 # 使用次数
  compress: true # 是否压缩
src/main/resources/mapper/basic/CustomerMapper.xml
@@ -112,23 +112,8 @@
    <select id="customewTransactions" resultType="com.ruoyi.sales.vo.CustomerTransactionsVo">
        select T1.customer_id,
               c.customer_name,
               T1.contractAmounts,
               IFNULL(T3.outboundAmount, 0) AS shippedAmount,
               GREATEST(T1.contractAmounts - IFNULL(T3.outboundAmount, 0), 0) AS unshippedAmount
               T1.contractAmounts
        from (select customer_id, sum(contract_amount) as contractAmounts from sales_ledger group by customer_id) T1
        left join (
            SELECT
                sl.customer_id,
                sum(sor.stock_out_num * slp.tax_inclusive_unit_price) as outboundAmount
            FROM stock_out_record sor
            LEFT join shipping_info s on sor.record_id = s.id
            LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
            LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id
            WHERE sor.record_type='13'
                and sor.approval_status=1
                and slp.type = 1
            group by sl.customer_id
        ) T3 on T3.customer_id=T1.customer_id
        left join customer c on T1.customer_id = c.id
        <where>
            <if test="customerName!=null and customerName!=''">
@@ -142,24 +127,45 @@
        select sl.id salesLedgerId,
               sl.sales_contract_no,
               sl.execution_date,
               sl.contract_amount,
               IFNULL(T2.outboundAmount, 0) AS shippedAmount,
               GREATEST(sl.contract_amount - IFNULL(T2.outboundAmount, 0), 0) AS unshippedAmount
               sl.contract_amount
        from sales_ledger sl
        left join (
            SELECT
                sl.id,
                sum(sor.stock_out_num * slp.tax_inclusive_unit_price) as outboundAmount
            FROM stock_out_record sor
                     left join shipping_info s on sor.record_id = s.id
                     LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
                     LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id
            WHERE sor.record_type='13'
              and sor.approval_status=1
              and slp.type = 1
            group by  sl.id
        )T2 on T2.id = sl.id
        where sl.customer_id = #{customerId}
        order by sl.execution_date
    </select>
    <select id="getShippedAmountByCustomerIds" resultType="java.util.Map">
        SELECT
            sl.customer_id as customerId,
            sum(sor.stock_out_num * slp.tax_inclusive_unit_price) as outboundAmount
        FROM stock_out_record sor
        LEFT join shipping_info s on sor.record_id = s.id
        LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
        LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id
        WHERE sor.record_type='13'
            and sor.approval_status=1
            and slp.type = 1
            and sl.customer_id IN
            <foreach collection="customerIds" item="customerId" open="(" separator="," close=")">
                #{customerId}
            </foreach>
        group by sl.customer_id
    </select>
    <select id="getShippedAmountBySalesLedgerIds" resultType="java.util.Map">
        SELECT
            sl.id as salesLedgerId,
            sum(sor.stock_out_num * slp.tax_inclusive_unit_price) as outboundAmount
        FROM stock_out_record sor
        LEFT join shipping_info s on sor.record_id = s.id
        LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
        LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id
        WHERE sor.record_type='13'
            and sor.approval_status=1
            and slp.type = 1
            and sl.id IN
            <foreach collection="salesLedgerIds" item="id" open="(" separator="," close=")">
                #{id}
            </foreach>
        group by sl.id
    </select>
</mapper>
src/main/resources/mapper/basic/SupplierManageMapper.xml
@@ -73,66 +73,8 @@
    <select id="supplierTransactions" resultType="com.ruoyi.purchase.vo.SupplierTransactionsVo">
        SELECT T1.supplier_id,
               sm.supplier_name,
               T1.contractAmounts,
               IFNULL(T3.InboundAmount, 0) AS shippedAmount,
               T1.contractAmounts - IFNULL(T3.InboundAmount, 0) AS unshippedAmount
               T1.contractAmounts
        FROM (SELECT supplier_id, SUM(contract_amount) AS contractAmounts FROM purchase_ledger GROUP BY supplier_id) T1
        LEFT JOIN (
            SELECT t.supplier_id,
                   SUM(t.inbound_amount) AS InboundAmount
            FROM (
                SELECT sir.stock_in_num * slp.tax_inclusive_unit_price AS inbound_amount, pl.supplier_id
                FROM stock_in_record sir
                INNER JOIN sales_ledger_product slp ON slp.sales_ledger_id = sir.record_id
                INNER JOIN purchase_ledger pl ON pl.id = slp.sales_ledger_id
                WHERE sir.approval_status = 1 AND sir.record_type = 7 AND slp.type = 2
                UNION ALL
                 SELECT
                   sir.stock_in_num * slp_agg.tax_inclusive_unit_price AS inbound_amount,
                   pl2.supplier_id
               FROM stock_in_record sir
                        INNER JOIN quality_inspect qi
                                   ON qi.id = sir.record_id
                        INNER JOIN purchase_ledger pl2
                                   ON pl2.id = qi.purchase_ledger_id
                        INNER JOIN (
                   SELECT
                       sales_ledger_id,
                       product_model_id,
                       MIN(tax_inclusive_unit_price) AS tax_inclusive_unit_price
                   FROM sales_ledger_product
                   WHERE type = 2
                   GROUP BY sales_ledger_id, product_model_id
               ) slp_agg
                                   ON slp_agg.sales_ledger_id = pl2.id
                                       AND slp_agg.product_model_id = sir.product_model_id
               WHERE sir.approval_status = 1 AND sir.record_type = 10
               UNION ALL
               SELECT sir.stock_in_num * slp_agg.tax_inclusive_unit_price AS inbound_amount,
                      pl2.supplier_id
               FROM stock_in_record sir
               INNER JOIN quality_unqualified qu
        ON qu.id = sir.record_id
        INNER JOIN quality_inspect qi
        ON qi.id = qu.inspect_id
        INNER JOIN purchase_ledger pl2
        ON pl2.id = qi.purchase_ledger_id
        INNER JOIN (
        SELECT
        sales_ledger_id,
        product_model_id,
        MIN(tax_inclusive_unit_price) AS tax_inclusive_unit_price
        FROM sales_ledger_product
        WHERE type = 2
        GROUP BY sales_ledger_id, product_model_id
        ) slp_agg
        ON slp_agg.sales_ledger_id = pl2.id
        AND slp_agg.product_model_id = sir.product_model_id
        WHERE sir.approval_status = 1
        AND sir.record_type = 11
            ) t
            GROUP BY t.supplier_id
        ) T3 ON T3.supplier_id = T1.supplier_id
        LEFT JOIN supplier_manage sm ON T1.supplier_id = sm.id
        <where>
            <if test="supplierName!=null and supplierName!=''">
@@ -146,66 +88,10 @@
       SELECT pl.id purchaseLedgerId,
              pl.purchase_contract_number,
              pl.execution_date,
              pl.contract_amount,
              IFNULL(T2.InboundAmount, 0) AS shippedAmount,
              pl.contract_amount - IFNULL(T2.InboundAmount, 0) AS unshippedAmount
              pl.contract_amount
       FROM purchase_ledger pl
       LEFT JOIN (
           SELECT t.sales_ledger_id,
                  SUM(t.inbound_amount) AS InboundAmount
           FROM (
               SELECT sir.stock_in_num * slp.tax_inclusive_unit_price AS inbound_amount, slp.sales_ledger_id
               FROM stock_in_record sir
               INNER JOIN sales_ledger_product slp ON slp.sales_ledger_id = sir.record_id
               WHERE sir.approval_status = 1 AND sir.record_type = 7 AND slp.type = 2
               UNION ALL
               SELECT
                   sir.stock_in_num * slp_agg.tax_inclusive_unit_price AS inbound_amount,
                   slp_agg.sales_ledger_id
               FROM stock_in_record sir
                        INNER JOIN quality_inspect qi
                                   ON qi.id = sir.record_id
                        INNER JOIN purchase_ledger pl2
                                   ON pl2.id = qi.purchase_ledger_id
                        INNER JOIN (
                   SELECT
                       sales_ledger_id,
                       product_model_id,
                       MIN(tax_inclusive_unit_price) AS tax_inclusive_unit_price
                   FROM sales_ledger_product
                   WHERE type = 2
                   GROUP BY sales_ledger_id, product_model_id
               ) slp_agg
                                   ON slp_agg.sales_ledger_id = pl2.id
                                       AND slp_agg.product_model_id = sir.product_model_id
               WHERE sir.approval_status = 1 AND sir.record_type = 10
               UNION ALL
               SELECT sir.stock_in_num * slp_agg.tax_inclusive_unit_price AS inbound_amount,
                      slp_agg.sales_ledger_id
               FROM stock_in_record sir
                        INNER JOIN quality_unqualified qu
                                   ON qu.id = sir.record_id
                        INNER JOIN quality_inspect qi
                                   ON qi.id = qu.inspect_id
                        INNER JOIN purchase_ledger pl2
                                   ON pl2.id = qi.purchase_ledger_id
                        INNER JOIN (
                   SELECT
                       sales_ledger_id,
                       product_model_id,
                       MIN(tax_inclusive_unit_price) AS tax_inclusive_unit_price
                   FROM sales_ledger_product
                   WHERE type = 2
                   GROUP BY sales_ledger_id, product_model_id
               ) slp_agg
                                   ON slp_agg.sales_ledger_id = pl2.id
                                       AND slp_agg.product_model_id = sir.product_model_id
               WHERE sir.approval_status = 1
                 AND sir.record_type = 11
           ) t
           GROUP BY t.sales_ledger_id
       ) T2 ON T2.sales_ledger_id = pl.id
       WHERE pl.supplier_id = #{supplierId}
    </select>
</mapper>
src/main/resources/mapper/collaborativeApproval/NoticeMapper.xml
@@ -3,7 +3,7 @@
<mapper namespace="com.ruoyi.collaborativeApproval.mapper.NoticeMapper">
    <select id="listPage" resultType="com.ruoyi.collaborativeApproval.dto.NoticeDTO">
        select n.*, su.user_name as create_user_name
        select n.*, su.nick_name as create_user_name
        from notice n
        left join sys_user su on n.create_user = su.user_id
        <where>
src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml
@@ -43,7 +43,9 @@
        <if test="qualityUnqualified.entryDateEnd != null and qualityUnqualified.entryDateEnd != '' ">
            AND  check_time &lt;= DATE_FORMAT(#{qualityUnqualified.entryDateEnd},'%Y-%m-%d')
        </if>
        order by qu.check_time desc
    </select>
    <select id="qualityUnqualifiedExport" resultType="com.ruoyi.quality.pojo.QualityUnqualified">
        SELECT
        *