yaowanxin
10 小时以前 6f888b234148d1a4dbd1e6c28a8d9ed85ebfda09
Merge remote-tracking branch 'origin/dev_New' into dev_New
已添加2个文件
已修改24个文件
801 ■■■■■ 文件已修改
src/main/java/com/ruoyi/account/mapper/AccountExpenseMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/mapper/AccountIncomeMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/controller/HomeController.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/MonthlyExpenditureDto.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/MonthlyIncomeDto.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/HomeService.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java 381 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/SalesLedgerProductionAccountingController.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/SalesLedgerProductionAccountingDto.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionProductMainMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/SalesLedgerProductionAccountingMapper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/SalesLedgerProductionAccountingService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/SalesLedgerProductionAccountingServiceImpl.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/mapper/PurchaseLedgerMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/account/AccountExpenseMapper.xml 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/account/AccountIncomeMapper.xml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionProductMainMapper.xml 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/SalesLedgerProductionAccountingMapper.xml 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerMapper.xml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/mapper/AccountExpenseMapper.java
@@ -10,6 +10,7 @@
import com.ruoyi.dto.DateQueryDto;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.home.dto.IncomeExpenseAnalysisDto;
import java.math.BigDecimal;
import java.util.List;
@@ -24,4 +25,8 @@
    List<AccountDto2> report(@Param("dateQueryDto") DateQueryDto dateQueryDto);
    BigDecimal report1(@Param("dateQueryDto") DateQueryDto dateQueryDto, @Param("dictValue") String dictValue);
    List<IncomeExpenseAnalysisDto> selectAccountExpenseStats(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("dateFormat") String dateFormat);
    List<com.ruoyi.dto.MapDto> selectExpenseComposition(@Param("startDate") String startDate, @Param("endDate") String endDate);
}
src/main/java/com/ruoyi/account/mapper/AccountIncomeMapper.java
@@ -7,6 +7,7 @@
import com.ruoyi.account.pojo.AccountFile;
import com.ruoyi.account.pojo.AccountIncome;
import com.ruoyi.dto.DateQueryDto;
import com.ruoyi.home.dto.IncomeExpenseAnalysisDto;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -23,4 +24,7 @@
    List<AccountDto2> report(@Param("dateQueryDto") DateQueryDto dateQueryDto);
    BigDecimal report1(@Param("dateQueryDto") DateQueryDto dateQueryDto, @Param("dictValue") String dictValue);
    List<IncomeExpenseAnalysisDto> selectIncomeStats(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("dateFormat") String dateFormat);
}
src/main/java/com/ruoyi/home/controller/HomeController.java
@@ -132,6 +132,41 @@
        return AjaxResult.success(list);
    }
    @GetMapping("/incomeExpenseAnalysis")
    @ApiOperation("支收对比分析")
    public AjaxResult incomeExpenseAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type) {
        List<Map<String, Object>> result = homeService.incomeExpenseAnalysis(type);
        return AjaxResult.success(result);
    }
    @GetMapping("/profitTrendAnalysis")
    @ApiOperation("利润趋势分析")
    public AjaxResult profitTrendAnalysis(){
        List<MapDto> list = homeService.profitTrendAnalysis();
        return AjaxResult.success(list);
    }
    @GetMapping("/expenseCompositionAnalysis")
    @ApiOperation("构成分析")
    public AjaxResult expenseCompositionAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type) {
        List<MapDto> list = homeService.expenseCompositionAnalysis(type);
        return AjaxResult.success(list);
    }
    @GetMapping("/monthlyIncome")
    @ApiOperation("月度收入")
    public AjaxResult monthlyIncome(){
        MonthlyIncomeDto dto = homeService.monthlyIncome();
        return AjaxResult.success(dto);
    }
   @GetMapping("/monthlyExpenditure")
   @ApiOperation("月度支出")
   public AjaxResult monthlyExpenditure(){
        MonthlyExpenditureDto dto = homeService.monthlyExpenditure();
        return AjaxResult.success(dto);
   }
    /********************************************************营销采购类**************************************************/
    @GetMapping("/business")
    @Log(title = "销售-采购-库存数据", businessType = BusinessType.OTHER)
src/main/java/com/ruoyi/home/dto/MonthlyExpenditureDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.ruoyi.home.dto;
import lombok.Data;
import java.math.BigDecimal;
/**
 * æœˆåº¦æ”¯å‡º DTO
 */
@Data
public class MonthlyExpenditureDto {
    /**
     * æœˆåº¦æ€»æ”¯å‡º
     */
    private BigDecimal monthlyExpenditure = BigDecimal.ZERO;
    /**
     * ä»˜æ¬¾çއ (百分比)
     */
    private String paymentRate = "0.00";
    /**
     * æ¯›åˆ©æ¶¦ (金额)
     */
    private BigDecimal grossProfit = BigDecimal.ZERO;
    /**
     * åˆ©æ¶¦çއ (百分比)
     */
    private String profitMarginRate = "0.00";
}
src/main/java/com/ruoyi/home/dto/MonthlyIncomeDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.ruoyi.home.dto;
import lombok.Data;
import java.math.BigDecimal;
/**
 * æœˆåº¦æ”¶å…¥ DTO
 */
@Data
public class MonthlyIncomeDto {
    /**
     * æœˆåº¦æ”¶å…¥
     */
    private BigDecimal monthlyIncome = BigDecimal.ZERO;
    /**
     * å›žæ¬¾çއ
     */
    private String collectionRate = "0.00";
    /**
     * é€¾æœŸæ•°
     */
    private BigDecimal overdueNum = BigDecimal.ZERO;
    /**
     * é€¾æœŸçއ
     */
    private String overdueRate = "0.00";
}
src/main/java/com/ruoyi/home/service/HomeService.java
@@ -54,4 +54,14 @@
    List<Map<String, Object>> productInOutAnalysis(Integer type);
    List<MapDto> productTurnoverDays();
    List<Map<String, Object>> incomeExpenseAnalysis(Integer type);
    List<MapDto> profitTrendAnalysis();
    List<MapDto> expenseCompositionAnalysis(Integer type);
    MonthlyIncomeDto monthlyIncome();
    MonthlyExpenditureDto monthlyExpenditure();
}
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -3,7 +3,10 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.mapper.AccountIncomeMapper;
import com.ruoyi.account.pojo.AccountExpense;
import com.ruoyi.home.mapper.HomeMapper;
import com.ruoyi.account.mapper.AccountExpenseMapper;
import com.ruoyi.approve.mapper.ApproveProcessMapper;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.basic.mapper.CustomerMapper;
@@ -1098,4 +1101,382 @@
    public List<MapDto> productTurnoverDays() {
        return homeMapper.productTurnoverDays();
    }
    @Autowired
    private AccountExpenseMapper accountExpenseMapper;
    @Autowired
    private AccountIncomeMapper accountIncomeMapper;
    public List<Map<String, Object>> incomeExpenseAnalysis(Integer type) {
        LocalDate today = LocalDate.now();
        LocalDate startDate;
        LocalDate endDate;
        String dateFormat;
        DateTimeFormatter formatter;
        List<String> xAxis = new ArrayList<>();
        // 1. æ—¶é—´èŒƒå›´ & X è½´
        if (type == 3) {
            // æœ¬å­£åº¦ï¼ˆæŒ‰æœˆï¼‰
            Month currentMonth = today.getMonth();
            Month firstMonthOfQuarter = currentMonth.firstMonthOfQuarter();
            startDate = today.withMonth(firstMonthOfQuarter.getValue())
                    .with(TemporalAdjusters.firstDayOfMonth());
            endDate = startDate.plusMonths(2)
                    .with(TemporalAdjusters.lastDayOfMonth());
            dateFormat = "%Y-%m";
            formatter = DateTimeFormatter.ofPattern("yyyy-MM");
            LocalDate tmp = startDate;
            while (!tmp.isAfter(endDate)) {
                xAxis.add(tmp.format(formatter));
                tmp = tmp.plusMonths(1);
            }
        } else {
            // å‘¨ / æœˆï¼ˆæŒ‰å¤©ï¼‰
            dateFormat = "%Y-%m-%d";
            formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            if (type == 1) {
                startDate = today.with(DayOfWeek.MONDAY);
                endDate = today.with(DayOfWeek.SUNDAY);
            } else {
                startDate = today.with(TemporalAdjusters.firstDayOfMonth());
                endDate = today.with(TemporalAdjusters.lastDayOfMonth());
            }
            LocalDate tmp = startDate;
            while (!tmp.isAfter(endDate)) {
                xAxis.add(tmp.format(formatter));
                tmp = tmp.plusDays(1);
            }
        }
        String startStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String endStr = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        // 2. æŸ¥è¯¢æ•°æ®
        List<IncomeExpenseAnalysisDto> incomeList = accountIncomeMapper.selectIncomeStats(startStr, endStr, dateFormat);
//        List<IncomeExpenseAnalysisDto> purchaseList =
//                purchaseLedgerMapper.selectPurchaseStats(startStr, endStr, dateFormat);
        List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr, dateFormat);
        // 3. è½¬ Map(自动合并)
        Map<String, BigDecimal> incomeMap = incomeList.stream()
                .collect(Collectors.toMap(
                        IncomeExpenseAnalysisDto::getDateStr,
                        IncomeExpenseAnalysisDto::getAmount,
                        BigDecimal::add));
//        Map<String, BigDecimal> purchaseMap = purchaseList.stream()
//                .collect(Collectors.toMap(
//                        IncomeExpenseAnalysisDto::getDateStr,
//                        IncomeExpenseAnalysisDto::getAmount,
//                        BigDecimal::add));
        Map<String, BigDecimal> expenseMap = expenseList.stream()
                .collect(Collectors.toMap(
                        IncomeExpenseAnalysisDto::getDateStr,
                        IncomeExpenseAnalysisDto::getAmount,
                        BigDecimal::add));
        // 4. ç»„装返回
        List<Map<String, Object>> result = new ArrayList<>();
        for (String dateStr : xAxis) {
            Map<String, Object> item = new HashMap<>();
            item.put("date", dateStr);
            // æ”¶å…¥
            BigDecimal income = incomeMap.getOrDefault(dateStr, BigDecimal.ZERO);
            item.put("income", income.setScale(2, RoundingMode.HALF_UP));
            // æ”¯å‡º = é‡‡è´­ + è´¢åŠ¡æ”¯å‡º
//            BigDecimal purchase = purchaseMap.getOrDefault(dateStr, BigDecimal.ZERO);
            BigDecimal expense = expenseMap.getOrDefault(dateStr, BigDecimal.ZERO);
//            BigDecimal totalExpense = purchase.add(expense);
            BigDecimal totalExpense = expense;
            item.put("expense", totalExpense.setScale(2, RoundingMode.HALF_UP));
            result.add(item);
        }
        return result;
    }
    @Override
    public List<MapDto> profitTrendAnalysis() {
        LocalDate today = LocalDate.now();
        LocalDate startDate = today.minusMonths(11).with(TemporalAdjusters.firstDayOfMonth());
        LocalDate endDate = today.with(TemporalAdjusters.lastDayOfMonth());
        String dateFormat = "%Y-%m";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
        List<String> months = new ArrayList<>();
        LocalDate temp = startDate;
        while (!temp.isAfter(endDate)) {
            months.add(temp.format(formatter));
            temp = temp.plusMonths(1);
        }
        String startStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String endStr = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//        List<IncomeExpenseAnalysisDto> incomeList = salesLedgerMapper.selectIncomeStats(startStr, endStr, dateFormat);
        List<IncomeExpenseAnalysisDto> incomeList = new ArrayList<>();
        List<IncomeExpenseAnalysisDto> purchaseList = purchaseLedgerMapper.selectPurchaseStats(startStr, endStr, dateFormat);
        List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr, dateFormat);
        Map<String, BigDecimal> incomeMap = incomeList.stream().collect(Collectors.toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
        Map<String, BigDecimal> purchaseMap = purchaseList.stream().collect(Collectors.toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
        Map<String, BigDecimal> expenseMap = expenseList.stream().collect(Collectors.toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
        List<MapDto> result = new ArrayList<>();
        for (String month : months) {
            MapDto dto = new MapDto();
            dto.setName(month);
            BigDecimal income = incomeMap.getOrDefault(month, BigDecimal.ZERO);
            BigDecimal purchase = purchaseMap.getOrDefault(month, BigDecimal.ZERO);
             income = BigDecimal.ZERO;
            BigDecimal expense = expenseMap.getOrDefault(month, BigDecimal.ZERO);
            BigDecimal totalExpense = purchase.add(expense);
            BigDecimal profit = income.subtract(totalExpense);
            dto.setValue(profit.setScale(2, RoundingMode.HALF_UP).toString());
            result.add(dto);
        }
        return result;
    }
    @Override
    public List<MapDto> expenseCompositionAnalysis(Integer type) {
        List<MapDto> result = new ArrayList<>();
        if (type == 2) {
            List<MapDto> customerList = salesLedgerMapper.selectCustomerSalesComposition();
            if (customerList != null) {
                result.addAll(customerList);
            }
        } else {
            BigDecimal rawMaterialAmount = salesLedgerProductMapper.selectRawMaterialExpense();
            MapDto rawMaterialDto = new MapDto();
            rawMaterialDto.setName("原材料");
            rawMaterialDto.setValue(rawMaterialAmount != null ? rawMaterialAmount.toString() : "0");
            result.add(rawMaterialDto);
            List<MapDto> expenseList = accountExpenseMapper.selectExpenseComposition(null, null);
            if (expenseList != null) {
                result.addAll(expenseList);
            }
        }
        BigDecimal total = BigDecimal.ZERO;
        for (MapDto dto : result) {
            if (dto.getValue() != null) {
                total = total.add(new BigDecimal(dto.getValue()));
            }
        }
        if (total.compareTo(BigDecimal.ZERO) > 0) {
            for (MapDto dto : result) {
                if (dto.getValue() != null) {
                    BigDecimal val = new BigDecimal(dto.getValue());
                    String rate = val.divide(total, 4, RoundingMode.HALF_UP)
                            .multiply(new BigDecimal("100"))
                            .setScale(2, RoundingMode.HALF_UP)
                            .toString();
                    dto.setRate(rate);
                } else {
                    dto.setRate("0.00");
                }
            }
        } else {
            for (MapDto dto : result) {
                dto.setRate("0.00");
            }
        }
        return result;
    }
    @Override
    public MonthlyIncomeDto monthlyIncome() {
        MonthlyIncomeDto dto = new MonthlyIncomeDto();
        LocalDate now = LocalDate.now();
        YearMonth currentMonth = YearMonth.from(now);
        LocalDateTime startOfMonth = currentMonth.atDay(1).atStartOfDay();
        LocalDateTime endOfMonth = currentMonth.atEndOfMonth().atTime(23, 59, 59);
        LambdaQueryWrapper<SalesLedgerProduct> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SalesLedgerProduct::getType, 1);
        wrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
        wrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(products)) {
            return dto;
        }
        BigDecimal collected = products.stream()
                .map(SalesLedgerProduct::getInvoiceTotal)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        dto.setMonthlyIncome(collected);
        BigDecimal overdue = products.stream()
                .map(SalesLedgerProduct::getPendingInvoiceTotal)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        dto.setOverdueNum(overdue);
        BigDecimal total = collected.add(overdue);
        if (total.compareTo(BigDecimal.ZERO) > 0) {
            String collectionRate = collected.divide(total, 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100"))
                    .setScale(2, RoundingMode.HALF_UP)
                    .toString();
            dto.setCollectionRate(collectionRate);
            String overdueRate = overdue.divide(total, 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100"))
                    .setScale(2, RoundingMode.HALF_UP)
                    .toString();
            dto.setOverdueRate(overdueRate);
        }
        return dto;
    }
    public MonthlyExpenditureDto monthlyExpenditure() {
        MonthlyExpenditureDto dto = new MonthlyExpenditureDto();
        //  å½“月时间范围
        LocalDate now = LocalDate.now();
        YearMonth currentMonth = YearMonth.from(now);
        LocalDateTime startOfMonth = currentMonth.atDay(1).atStartOfDay();
        LocalDateTime endOfMonth = currentMonth.atEndOfMonth().atTime(23, 59, 59);
        //  é‡‡è´­å°è´¦ï¼ˆtype = 2)
        LambdaQueryWrapper<SalesLedgerProduct> purchaseWrapper = new LambdaQueryWrapper<>();
        purchaseWrapper.eq(SalesLedgerProduct::getType, 2);
        purchaseWrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
        purchaseWrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
        List<SalesLedgerProduct> purchaseProducts =
                salesLedgerProductMapper.selectList(purchaseWrapper);
        BigDecimal rawMaterialCost = BigDecimal.ZERO;   // åŽŸææ–™æˆæœ¬
        BigDecimal paidAmount = BigDecimal.ZERO;        // å·²ä»˜æ¬¾é‡‘额
        BigDecimal pendingAmount = BigDecimal.ZERO;     // å¾…付款金额
        if (!CollectionUtils.isEmpty(purchaseProducts)) {
            for (SalesLedgerProduct p : purchaseProducts) {
                if (p.getTaxInclusiveTotalPrice() != null) {
                    rawMaterialCost = rawMaterialCost.add(p.getTaxInclusiveTotalPrice());
                }
                if (p.getTicketsTotal() != null) {
                    paidAmount = paidAmount.add(p.getTicketsTotal());
                }
                if (p.getPendingTicketsTotal() != null) {
                    pendingAmount = pendingAmount.add(p.getPendingTicketsTotal());
                }
            }
        }
        //  å…¶ä»–费用
        LambdaQueryWrapper<AccountExpense> expenseWrapper = new LambdaQueryWrapper<>();
        expenseWrapper.ge(AccountExpense::getExpenseDate,
                java.sql.Date.valueOf(currentMonth.atDay(1)));
        expenseWrapper.le(AccountExpense::getExpenseDate,
                java.sql.Date.valueOf(currentMonth.atEndOfMonth()));
        List<AccountExpense> expenses =
                accountExpenseMapper.selectList(expenseWrapper);
        BigDecimal otherExpense = BigDecimal.ZERO;
        if (!CollectionUtils.isEmpty(expenses)) {
            for (AccountExpense e : expenses) {
                if (e.getExpenseMoney() != null) {
                    otherExpense = otherExpense.add(e.getExpenseMoney());
                }
            }
        }
        //  æœˆåº¦æ€»æ”¯å‡º
//        BigDecimal monthlyExpenditure = rawMaterialCost.add(otherExpense);
        BigDecimal monthlyExpenditure = otherExpense;
        dto.setMonthlyExpenditure(monthlyExpenditure);
        // å·²ä»˜æ¬¾ Ã·ï¼ˆå·²ä»˜æ¬¾ + å¾…付款)
        BigDecimal totalPayable = paidAmount.add(pendingAmount);
        if (totalPayable.compareTo(BigDecimal.ZERO) > 0) {
            String paymentRate = paidAmount
                    .divide(totalPayable, 4, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(100))
                    .setScale(2, RoundingMode.HALF_UP)
                    .toString();
            dto.setPaymentRate(paymentRate);
        }
        // å”®å°è´¦ï¼ˆtype = 1)
        LambdaQueryWrapper<SalesLedgerProduct> salesWrapper = new LambdaQueryWrapper<>();
        salesWrapper.eq(SalesLedgerProduct::getType, 1);
        salesWrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
        salesWrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
        List<SalesLedgerProduct> salesProducts =
                salesLedgerProductMapper.selectList(salesWrapper);
        BigDecimal revenue = BigDecimal.ZERO;
        if (!CollectionUtils.isEmpty(salesProducts)) {
            for (SalesLedgerProduct s : salesProducts) {
                if (s.getInvoiceAmount() != null) {
                    revenue = revenue.add(s.getInvoiceAmount());
                }
            }
        }
        //  æ¯›åˆ©æ¶¦ & åˆ©æ¶¦çއ
        if (revenue.compareTo(BigDecimal.ZERO) > 0) {
            // æ¯›åˆ©æ¶¦ = é”€å”®æ”¶å…¥ - åŽŸææ–™æˆæœ¬
            BigDecimal grossProfit = revenue.subtract(rawMaterialCost);
            dto.setGrossProfit(grossProfit);
            // åˆ©æ¶¦çއ = (销售收入 - æœˆåº¦æ€»æ”¯å‡º) / é”€å”®æ”¶å…¥
            BigDecimal profit = revenue.subtract(monthlyExpenditure);
            String profitMarginRate = profit
                    .divide(revenue, 4, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(100))
                    .setScale(2, RoundingMode.HALF_UP)
                    .toString();
            dto.setProfitMarginRate(profitMarginRate);
        }
        return dto;
    }
}
src/main/java/com/ruoyi/production/controller/SalesLedgerProductionAccountingController.java
@@ -8,11 +8,14 @@
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.SalesLedgerProductionAccountingDto;
import com.ruoyi.production.pojo.SalesLedgerProductionAccounting;
import com.ruoyi.production.service.SalesLedgerProductionAccountingService;
import com.ruoyi.production.service.impl.SalesLedgerProductionAccountingServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -33,7 +36,7 @@
public class SalesLedgerProductionAccountingController extends BaseController {
    @Autowired
    private SalesLedgerProductionAccountingServiceImpl salesLedgerProductionAccountingService;
    private SalesLedgerProductionAccountingService salesLedgerProductionAccountingService;
    @GetMapping("/listPage")
    @ApiOperation("生产核算-分页查询")
@@ -53,5 +56,16 @@
        ExcelUtil<SalesLedgerProductionAccountingDto> util = new ExcelUtil<SalesLedgerProductionAccountingDto>(SalesLedgerProductionAccountingDto.class);
        util.exportExcel(response, list, "生产核算数据");
    }
//----------------------------------------------------------------------------------------------------------------------------------------------------
    @GetMapping("/page")
    @ApiModelProperty("查询工人生产工资信息")
    public R pageProductionAccounting(SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto, Page page){
        return R.ok(salesLedgerProductionAccountingService.pageProductionAccounting(salesLedgerProductionAccountingDto, page));
    }
    @GetMapping("/listProductionDetails")
    @ApiModelProperty("查询工人生产工资信息")
    public R listProductionDetails(SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto, Page page){
        return R.ok(salesLedgerProductionAccountingService.listProductionDetails(salesLedgerProductionAccountingDto,page));
    }
}
src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java
@@ -7,6 +7,7 @@
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@@ -46,4 +47,11 @@
    //销售合同号
    @Excel(name = "销售合同号")
    private String salesContractNo;
    private LocalDate scheduleDate;
    private String schedulingUserName;
    private String customerName;
    private String process;
    private BigDecimal workHours;
    private BigDecimal wages;
}
src/main/java/com/ruoyi/production/dto/SalesLedgerProductionAccountingDto.java
@@ -70,4 +70,10 @@
    @ApiModelProperty(value = "结束时间")
    private String entryDateEnd;
    private BigDecimal outputNum;
    private BigDecimal outputRate;
}
src/main/java/com/ruoyi/production/mapper/ProductionProductMainMapper.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.production.dto.ProductionProductMainDto;
import com.ruoyi.production.dto.SalesLedgerProductionAccountingDto;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.production.pojo.ProductionProductMain;
import org.apache.ibatis.annotations.Mapper;
@@ -27,4 +28,6 @@
     * @return
     */
    ProductOrder getOrderByMainId(@Param("productMainId") Long productMainId);
    IPage<ProductionProductMainDto> listProductionDetails(SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto, Page page);
}
src/main/java/com/ruoyi/production/mapper/SalesLedgerProductionAccountingMapper.java
@@ -17,4 +17,5 @@
    IPage<SalesLedgerProductionAccountingDto> listPage(Page page,@Param("salesLedgerDto") SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto);
    IPage<SalesLedgerProductionAccountingDto> pageProductionAccounting(Page page, @Param("ew") SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto);
}
src/main/java/com/ruoyi/production/service/SalesLedgerProductionAccountingService.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.production.dto.ProductionProductMainDto;
import com.ruoyi.production.dto.SalesLedgerProductionAccountingDto;
import com.ruoyi.production.pojo.SalesLedgerProductionAccounting;
@@ -16,4 +17,7 @@
    IPage<SalesLedgerProductionAccountingDto> listPage(Page page, SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto);
    IPage<SalesLedgerProductionAccountingDto> pageProductionAccounting(SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto, Page page);
    IPage<ProductionProductMainDto> listProductionDetails(SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto, Page page);
}
src/main/java/com/ruoyi/production/service/impl/SalesLedgerProductionAccountingServiceImpl.java
@@ -3,7 +3,9 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.production.dto.ProductionProductMainDto;
import com.ruoyi.production.dto.SalesLedgerProductionAccountingDto;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.mapper.SalesLedgerProductionAccountingMapper;
import com.ruoyi.production.pojo.SalesLedgerProductionAccounting;
import com.ruoyi.production.service.SalesLedgerProductionAccountingService;
@@ -23,7 +25,8 @@
public class SalesLedgerProductionAccountingServiceImpl extends ServiceImpl<SalesLedgerProductionAccountingMapper, SalesLedgerProductionAccounting> implements SalesLedgerProductionAccountingService {
  
    private final SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    private final ProductionProductMainMapper productionProductMainMapper;
    @Override
    public IPage<SalesLedgerProductionAccountingDto> listPage(Page page, SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto) {
        IPage<SalesLedgerProductionAccountingDto> list = salesLedgerProductionAccountingMapper.listPage(page, salesLedgerProductionAccountingDto);
@@ -37,6 +40,17 @@
        return list;
    }
    @Override
    public IPage<SalesLedgerProductionAccountingDto> pageProductionAccounting(SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto, Page page) {
        // TODO ç®¡ç†å‘˜æŸ¥è¯¢æ‰€æœ‰ï¼Œå…¶ä»–人只能查自己
        return salesLedgerProductionAccountingMapper.pageProductionAccounting(page, salesLedgerProductionAccountingDto);
    }
    @Override
    public IPage<ProductionProductMainDto> listProductionDetails(SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto, Page page) {
        return productionProductMainMapper.listProductionDetails(salesLedgerProductionAccountingDto, page);
    }
    public static boolean isNumeric(String str) {
        if (str == null || str.isEmpty()) {
            return false;
src/main/java/com/ruoyi/purchase/mapper/PurchaseLedgerMapper.java
@@ -7,6 +7,7 @@
import com.ruoyi.purchase.dto.PurchaseLedgerDto;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.home.dto.IncomeExpenseAnalysisDto;
import java.math.BigDecimal;
import java.util.List;
@@ -24,4 +25,8 @@
    IPage<PurchaseLedgerDto> selectPurchaseLedgerListPage(IPage ipage, @Param("c") PurchaseLedgerDto purchaseLedger);
    List<PaymentRegistrationDto> getPaymentRegistrationDtoById(Long id);
    List<IncomeExpenseAnalysisDto> selectPurchaseStats(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("dateFormat") String dateFormat);
    BigDecimal selectTotalPurchaseAmount(@Param("startDate") String startDate, @Param("endDate") String endDate);
}
src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
@@ -5,6 +5,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.home.dto.IncomeExpenseAnalysisDto;
import com.ruoyi.sales.dto.SalesLedgerDto;
import com.ruoyi.sales.dto.SalesTrendDto;
import com.ruoyi.sales.dto.StatisticsTableDto;
@@ -23,6 +24,10 @@
 * @date 2025-05-08
 */
public interface SalesLedgerMapper extends BaseMapper<SalesLedger> {
    List<IncomeExpenseAnalysisDto> selectIncomeStats(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("dateFormat") String dateFormat);
    List<com.ruoyi.dto.MapDto> selectCustomerSalesComposition();
    /**
     * æŸ¥è¯¢æŒ‡å®šæ—¥æœŸçš„æ‰€æœ‰åˆåŒåºåˆ—号
     * @param datePart æ—¥æœŸéƒ¨åˆ†ï¼ˆæ ¼å¼ï¼šyyyyMMdd)
src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java
@@ -40,4 +40,6 @@
    List<Map<String, Object>> selectRawMaterialPurchaseAnalysis();
    int selectProductCountByTypeAndDate(@Param("type") Integer type, @Param("startDate") String startDate, @Param("endDate") String endDate);
    BigDecimal selectRawMaterialExpense();
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -42,6 +42,7 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
@@ -217,6 +218,7 @@
        int result;
        Long salesLedgerId = salesLedgerProduct.getSalesLedgerId();
        if (salesLedgerProduct.getId() == null) {
            salesLedgerProduct.setRegisterDate(LocalDateTime.now());
            result = salesLedgerProductMapper.insert(salesLedgerProduct);
            addProductionData(salesLedgerProduct);
        } else {
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -263,75 +263,51 @@
    @Override
    public List<MonthlyAmountDto> getAmountHalfYear(Integer type) {
        LocalDate now = LocalDate.now();
        LocalDateTime currentDateTime = LocalDateTime.now();
        // æ ¹æ® type ç¡®å®šæŸ¥è¯¢çš„æ—¶é—´é—´éš”(天数)和总查询天数
        int daysPerPeriod;
        int totalDays;
        switch (type) {
            case 1:
                daysPerPeriod = 5;   // æ¯5天查一次
                totalDays = 30;       // 6次 Ã— 5天 = 30天
                break;
            case 2:
                daysPerPeriod = 15;    // æ¯15天查一次
                totalDays = 90;       // 6次 Ã— 15天 = 90天
                break;
            case 3:
                daysPerPeriod = 30;   // æ¯30天查一次
                totalDays = 180;      // 6次 Ã— 30天 = 180天
                break;
            default:
                throw new IllegalArgumentException("Invalid type value: " + type);
        }
        List<MonthlyAmountDto> result = new ArrayList<>();
        // å¾ªçޝ6次,每次查询一个时间段的数据
        for (int i = 0; i < 6; i++) {
            // è®¡ç®—当前时间段的起始和结束时间
            LocalDateTime endTime = currentDateTime.minusDays(i * daysPerPeriod);
            LocalDateTime startTime = endTime.minusDays(daysPerPeriod);
        for (int i = 5; i >= 0; i--) {
            YearMonth yearMonth = YearMonth.from(now.minusMonths(i));
            LocalDateTime startTime = yearMonth.atDay(1).atStartOfDay();
            LocalDateTime endTime = yearMonth.atEndOfMonth().atTime(23, 59, 59);
            // æŸ¥è¯¢å›žæ¬¾é‡‘额
            //  å›žæ¬¾é‡‘额
            LambdaQueryWrapper<ReceiptPayment> receiptPaymentQuery = new LambdaQueryWrapper<>();
            receiptPaymentQuery
                    .ge(ReceiptPayment::getCreateTime, startTime)
                    .lt(ReceiptPayment::getCreateTime, endTime);
            List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(receiptPaymentQuery);
                    .le(ReceiptPayment::getCreateTime, endTime);
            // æŸ¥è¯¢å¼€ç¥¨é‡‘额
            LambdaQueryWrapper<InvoiceLedger> invoiceLedgerQuery = new LambdaQueryWrapper<>();
            invoiceLedgerQuery
                    .ge(InvoiceLedger::getCreateTime, startTime)
                    .lt(InvoiceLedger::getCreateTime, endTime);
            List<InvoiceLedger> invoiceLedgers = invoiceLedgerMapper.selectList(invoiceLedgerQuery);
            List<ReceiptPayment> receiptPayments =
                    receiptPaymentMapper.selectList(receiptPaymentQuery);
            // è®¡ç®—回款总额
            BigDecimal receiptAmount = receiptPayments.stream()
                    .map(ReceiptPayment::getReceiptPaymentAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // è®¡ç®—开票总额
            //  å¼€ç¥¨é‡‘额
            LambdaQueryWrapper<InvoiceLedger> invoiceLedgerQuery = new LambdaQueryWrapper<>();
            invoiceLedgerQuery
                    .ge(InvoiceLedger::getCreateTime, startTime)
                    .le(InvoiceLedger::getCreateTime, endTime);
            List<InvoiceLedger> invoiceLedgers =
                    invoiceLedgerMapper.selectList(invoiceLedgerQuery);
            BigDecimal invoiceAmount = invoiceLedgers.stream()
                    .map(InvoiceLedger::getInvoiceTotal)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // æž„造返回的 DTO
            MonthlyAmountDto dto = new MonthlyAmountDto();
            dto.setMonth(startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " ~ " +
                    endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            dto.setMonth(yearMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")));
            dto.setReceiptAmount(receiptAmount);
            dto.setInvoiceAmount(invoiceAmount);
            result.add(dto);
        }
        // åè½¬åˆ—表,使时间顺序从早到晚
        Collections.reverse(result);
        return result;
    }
src/main/resources/mapper/account/AccountExpenseMapper.xml
@@ -70,4 +70,26 @@
        </if>
    </select>
    <select id="selectAccountExpenseStats" resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto">
        SELECT DATE_FORMAT(expense_date, #{dateFormat}) as dateStr, IFNULL(SUM(expense_money), 0) as amount
        FROM account_expense
        WHERE expense_date BETWEEN #{startDate} AND #{endDate}
        GROUP BY dateStr
    </select>
    <select id="selectExpenseComposition" resultType="com.ruoyi.dto.MapDto">
        SELECT sdd.dict_label as name, CAST(IFNULL(SUM(ae.expense_money), 0) AS CHAR) as value
        FROM account_expense ae
        LEFT JOIN sys_dict_data sdd ON ae.expense_type = sdd.dict_value AND sdd.dict_type = 'expense_types'
        <where>
            <if test="startDate != null and startDate != ''">
                AND ae.expense_date &gt;= #{startDate}
            </if>
            <if test="endDate != null and endDate != ''">
                AND ae.expense_date &lt;= #{endDate}
            </if>
        </where>
        GROUP BY ae.expense_type, sdd.dict_label
    </select>
</mapper>
src/main/resources/mapper/account/AccountIncomeMapper.xml
@@ -69,4 +69,17 @@
            AND income_date &lt;= DATE_FORMAT(#{dateQueryDto.entryDateEnd},'%Y-%m-%d')
        </if>
    </select>
    <select id="selectIncomeStats"
            resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto">
        SELECT DATE_FORMAT(income_date, #{dateFormat}) AS dateStr,
               IFNULL(SUM(income_money), 0)            AS amount
        FROM account_income
        WHERE income_date BETWEEN #{startDate} AND #{endDate}
          AND business_type = 1
        GROUP BY dateStr
        ORDER BY dateStr
    </select>
</mapper>
src/main/resources/mapper/production/ProductionProductMainMapper.xml
@@ -14,24 +14,24 @@
    <select id="listPageProductionProductMainDto" resultType="com.ruoyi.production.dto.ProductionProductMainDto">
        select ppm.*,
               pwo.work_order_no as workOrderNo,
               pwo.status as workOrderStatus,
               u.nick_name as nickName,
               p.product_name as productName,
               pm.model as productModelName,
               ppo.quantity,
               ppo.scrap_qty,
               pm.unit,
               sl.sales_contract_no salesContractNo
        pwo.work_order_no as workOrderNo,
        pwo.status as workOrderStatus,
        u.nick_name as nickName,
        p.product_name as productName,
        pm.model as productModelName,
        ppo.quantity,
        ppo.scrap_qty,
        pm.unit,
        sl.sales_contract_no salesContractNo
        from
            production_product_main ppm
                left join product_work_order pwo on pwo.id = ppm.work_order_id
                left join product_order po on po.id = pwo.product_order_id
                left join production_product_output ppo on ppm.id = ppo.product_main_id
                left join product_model pm on pm.id = ppo.product_model_id
                left join product p on p.id = pm.product_id
                left join sales_ledger sl on sl.id = po.sales_ledger_id
                left join sys_user u on u.user_id = ppm.user_id
        production_product_main ppm
        left join product_work_order pwo on pwo.id = ppm.work_order_id
        left join product_order po on po.id = pwo.product_order_id
        left join production_product_output ppo on ppm.id = ppo.product_main_id
        left join product_model pm on pm.id = ppo.product_model_id
        left join product p on p.id = pm.product_id
        left join sales_ledger sl on sl.id = po.sales_ledger_id
        left join sys_user u on u.user_id = ppm.user_id
        <where>
            <if test="c.nickName != null and c.nickName != ''">
                and u.nick_name like concat('%',#{c.nickName},'%')
@@ -52,9 +52,33 @@
    <select id="getOrderByMainId" resultType="com.ruoyi.production.pojo.ProductOrder">
        select po.*
        from product_order po
        left join  product_work_order pwo on po.id = pwo.product_order_id
        left join production_product_main pm on work_order_id=pwo.id
        where pm.id=#{productMainId}
                 left join product_work_order pwo on po.id = pwo.product_order_id
                 left join production_product_main pm on work_order_id = pwo.id
        where pm.id = #{productMainId}
    </select>
    <select id="listProductionDetails" resultType="com.ruoyi.production.dto.ProductionProductMainDto">
        SELECT
            slpa.scheduling_date,
            slpa.scheduling_user_name,
            sl.sales_contract_no,
            sl.customer_name,
            p.product_name,
            pm.model,
            pm.unit,
            slpa.process,
            ppo.quantity,
            slpa.work_hours,
            slpa.work_hours * slpa.finished_num AS wages
        FROM
            production_product_main ppm
                LEFT JOIN sales_ledger_production_accounting slpa ON slpa.sales_ledger_work_id = ppm.id
                LEFT JOIN production_product_output ppo ON ppm.id = ppo.product_main_id
                LEFT JOIN product_work_order pwo ON pwo.id = ppm.work_order_id
                LEFT JOIN product_order po ON po.id = pwo.product_order_id
                LEFT JOIN process_route pr ON pr.id = po.route_id
                LEFT JOIN product_model pm ON po.product_model_id = pm.id
                LEFT JOIN product p ON p.id = pm.product_id
                LEFT JOIN sales_ledger sl ON po.sales_ledger_id = sl.id
    </select>
    <delete id="deleteByWorkOrderIds" parameterType="java.util.List">
src/main/resources/mapper/production/SalesLedgerProductionAccountingMapper.xml
@@ -50,4 +50,24 @@
        group by t4.id
        order by t4.scheduling_date desc
    </select>
    <select id="pageProductionAccounting"
            resultType="com.ruoyi.production.dto.SalesLedgerProductionAccountingDto">
        SELECT
            slpa.scheduling_user_id,
            slpa.scheduling_user_name,
               sum(ppout.quantity) as output_num,
               sum(slpa.finished_num * work_hours) as  wages,
               SUM(slpa.finished_num) / SUM(ppout.quantity) as output_rate
        FROM sales_ledger_production_accounting slpa
                 LEFT JOIN production_product_main ppm ON slpa.sales_ledger_work_id = ppm.id
                 LEFT JOIN production_product_output ppout ON ppm.id = ppout.product_main_id
        <where>
            <if test="ew.schedulingUserName != null and ew.schedulingUserName !=''" >
                and slpa.scheduling_user_name  = #{ew.schedulingUserName}
            </if>
        </where>
        GROUP BY slpa.scheduling_user_name
    </select>
</mapper>
src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
@@ -83,4 +83,25 @@
        WHERE
            T1.sales_ledger_product_id = #{id}
    </select>
    <select id="selectPurchaseStats" resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto">
        SELECT DATE_FORMAT(entry_date, #{dateFormat}) as dateStr, IFNULL(SUM(contract_amount), 0) as amount
        FROM purchase_ledger
        WHERE entry_date BETWEEN #{startDate} AND #{endDate}
        GROUP BY dateStr
    </select>
    <select id="selectTotalPurchaseAmount" resultType="java.math.BigDecimal">
        SELECT IFNULL(SUM(contract_amount), 0)
        FROM purchase_ledger
        <where>
            <if test="startDate != null and startDate != ''">
                AND entry_date &gt;= #{startDate}
            </if>
            <if test="endDate != null and endDate != ''">
                AND entry_date &lt;= #{endDate}
            </if>
        </where>
    </select>
</mapper>
src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -88,4 +88,17 @@
        </where>
    order by T1.entry_date desc
    </select>
    <select id="selectIncomeStats" resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto">
        SELECT DATE_FORMAT(entry_date, #{dateFormat}) as dateStr, IFNULL(SUM(contract_amount), 0) as amount
        FROM sales_ledger
        WHERE entry_date BETWEEN #{startDate} AND #{endDate}
        GROUP BY dateStr
    </select>
    <select id="selectCustomerSalesComposition" resultType="com.ruoyi.dto.MapDto">
        SELECT customer_name as name, CAST(IFNULL(SUM(contract_amount), 0) AS CHAR) as value
        FROM sales_ledger
        GROUP BY customer_name
    </select>
</mapper>
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -162,7 +162,7 @@
        left join product p on pm.product_id = p.id
    </select>
    <select id="selectProductSalesAnalysis" resultType="java.util.LinkedHashMap">
    <select id="selectProductSalesAnalysis" resultType="java.util.Map">
        SELECT
            product_category as name,
            SUM( tax_inclusive_total_price ) AS value
@@ -177,7 +177,7 @@
        LIMIT 5
    </select>
    <select id="selectRawMaterialPurchaseAnalysis" resultType="java.util.LinkedHashMap">
    <select id="selectRawMaterialPurchaseAnalysis" resultType="java.util.Map">
        SELECT
            pr.product_name AS name,
            SUM( slp.tax_inclusive_total_price ) AS value
@@ -203,4 +203,21 @@
        AND register_date &lt;= #{endDate}
    </select>
    <select id="selectRawMaterialExpense" resultType="java.math.BigDecimal">
        WITH RECURSIVE product_tree AS (SELECT id
                                        FROM product
                                        WHERE product_name = '原材料'
                                        UNION ALL
                                        SELECT p.id
                                        FROM product p
                                                 INNER JOIN product_tree pt ON p.parent_id = pt.id)
        SELECT IFNULL(SUM(slp.tax_inclusive_total_price), 0)
        FROM sales_ledger_product slp
        WHERE slp.type = 2
          AND slp.product_id IN (SELECT id
                                 FROM product_tree);
    </select>
</mapper>