704404a23faa4e9d952fc42f5c4c91321569903c..42288de2a4a83772558ac6a28be42ab49b7683b8
10 天以前 liyong
feat(quality): 添加质检单关联订单号和合同号查询功能
42288d 对比 | 目录
10 天以前 gongchunyi
fix: 会议室被占用不能被删除
f01980 对比 | 目录
2026-02-03 gongchunyi
fix: 修复供应商往来账目在无付款时仍显示合同记录
c7bd2e 对比 | 目录
2026-02-03 gongchunyi
fix: 修复客户往来账目在无回款时仍显示合同记录
45149f 对比 | 目录
2026-02-03 gongchunyi
fix: 去掉导出的销售台账中客户合同号
881465 对比 | 目录
2026-02-03 gongchunyi
fix: 采购台账返回备注数据
c48e62 对比 | 目录
2026-02-03 gongchunyi
Merge remote-tracking branch 'origin/dev_New' into dev_New
cd2aaf 对比 | 目录
2026-02-03 gongchunyi
fix: 完工数量修改为报工数量减去报废数量
34e115 对比 | 目录
2026-02-03 zss
Merge remote-tracking branch 'origin/dev_New' into dev_New
cf989c 对比 | 目录
2026-02-03 zss
添加创建时间注入
3190ae 对比 | 目录
2026-02-03 zss
添加创建时间注入
2b10b0 对比 | 目录
2026-02-03 liyong
Merge remote-tracking branch 'origin/dev_New' into dev_New
783f55 对比 | 目录
2026-02-03 liyong
feat(product-process): 生产核算字段重构
d3e304 对比 | 目录
2026-02-03 gongchunyi
fix: 根据接口类型进行拆分
ed90cf 对比 | 目录
2026-02-03 maven
yys 协同审批编号重复问题修复
7a022c 对比 | 目录
2026-02-03 maven
Merge remote-tracking branch 'origin/dev_New' into dev_New
bb78ea 对比 | 目录
2026-02-03 maven
yys 协同审批编号重复问题修复
fbcede 对比 | 目录
2026-02-03 gongchunyi
fix: 导出的生产订单数据中完成状态更改为完成进度
1f9382 对比 | 目录
2026-02-03 maven
yys 导入销售台账同步生成生产订单
670b14 对比 | 目录
2026-02-03 zss
Merge remote-tracking branch 'origin/dev_New' into dev_New
609dc0 对比 | 目录
2026-02-03 zss
代码注释完善
367402 对比 | 目录
2026-02-03 liyong
feat(product-process): 添加产品工序导入验证功能
d89e13 对比 | 目录
2026-02-03 liyong
feat(production): 添加工序质检控制功能
6dc3d1 对比 | 目录
已修改35个文件
1172 ■■■■ 文件已修改
src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/utils/DailyRedisCounter.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/collaborativeApproval/service/impl/MeetingServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/controller/HomeController.java 194 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductOrderController.java 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/SalesLedgerWorkController.java 185 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductOrderDto.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductOrderMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionProductMainMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProcessRouteItem.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductOrder.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductProcess.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductProcessRouteItem.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionProductOutput.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/SalesLedgerProductionAccounting.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionProductMainService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductProcessServiceImpl.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/SalesLedgerWorkServiceImpl.java 367 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/pojo/QualityInspect.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-new.yml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductOrderMapper.xml 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionProductMainMapper.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/SalesLedgerProductionAccountingMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/purchase/PaymentRegistrationMapper.xml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/quality/QualityInspectMapper.xml 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/ReceiptPaymentMapper.xml 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerMapper.xml 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
@@ -123,14 +123,14 @@
        LambdaQueryWrapper<ApproveNode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ApproveNode::getApproveProcessId, id);
        queryWrapper.eq(ApproveNode::getDeleteFlag, 0);
        queryWrapper.eq(ApproveNode::getApproveNodeStatus, 0);
//        queryWrapper.eq(ApproveNode::getApproveNodeStatus, 0);
        List<ApproveNode> list = list(queryWrapper);
        // 按照 approveNodeOrder 字段升序排序
        list.sort(Comparator.comparingInt(ApproveNode::getApproveNodeOrder));
        LambdaQueryWrapper<ApproveProcess> approveProcessLambdaQueryWrapper = new LambdaQueryWrapper<>();
        approveProcessLambdaQueryWrapper.eq(ApproveProcess::getApproveId, id)
                .eq(ApproveProcess::getApproveDelete, 0)
                .eq(ApproveProcess::getApproveStatus, 0)
//                .eq(ApproveProcess::getApproveStatus, 0)
                .last("limit 1");
        ApproveProcess approveProcess = approveProcessMapper.selectOne(approveProcessLambdaQueryWrapper);
        if(approveProcess != null && approveProcess.getApproveStatus() == 3){
src/main/java/com/ruoyi/approve/utils/DailyRedisCounter.java
@@ -4,6 +4,7 @@
import com.ruoyi.approve.mapper.ApproveProcessMapper;
import com.ruoyi.approve.pojo.ApproveProcess;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
@@ -26,6 +27,9 @@
    public DailyRedisCounter(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
    @Value("${ruoyi.approvalNumberPrefix}")
    private String approvalNumberPrefix;
    /**查缓存
     * 获取指定计数器在今日的数值,并自增1
@@ -71,7 +75,7 @@
     * @return 今日自增后的计数值
     */
    public long incrementAndGetByDb() {
        String approveId = redisTemplate.opsForValue().get("approveNum");
        String approveId = redisTemplate.opsForValue().get(approvalNumberPrefix + ":approveNum");
        if(approveId == null){
            StartAndEndDateDto dateTime = getDateTime();
            LambdaQueryWrapper<ApproveProcess> approveProcessLambdaQueryWrapper = new LambdaQueryWrapper<>();
@@ -81,16 +85,16 @@
                    .lt(ApproveProcess::getCreateTime,dateTime.getEndDate());
            Long aLong = approveProcessMapper.selectCount(approveProcessLambdaQueryWrapper);
            if(aLong == null){
                redisTemplate.opsForValue().set("approveNum","1",1L, TimeUnit.HOURS);
                redisTemplate.opsForValue().set(approvalNumberPrefix + ":approveNum","1",1L, TimeUnit.HOURS);
                return 1;
            }else{
                aLong += 1;
                redisTemplate.opsForValue().set("approveNum",aLong.toString(),1L, TimeUnit.HOURS);
                redisTemplate.opsForValue().set(approvalNumberPrefix + ":approveNum",aLong.toString(),1L, TimeUnit.HOURS);
                return aLong;
            }
        }else{
            Long num = Long.parseLong(approveId) + 1;
            redisTemplate.opsForValue().set("approveNum",num.toString(),1L, TimeUnit.HOURS);
            redisTemplate.opsForValue().set(approvalNumberPrefix + ":approveNum",num.toString(),1L, TimeUnit.HOURS);
            return Long.parseLong(approveId);
        }
src/main/java/com/ruoyi/collaborativeApproval/service/impl/MeetingServiceImpl.java
@@ -25,6 +25,7 @@
import com.ruoyi.collaborativeApproval.vo.SearchMeetingDraftVo;
import com.ruoyi.collaborativeApproval.vo.SearchMeetingRoomVo;
import com.ruoyi.collaborativeApproval.vo.SearchMeetingUseVo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.project.system.domain.SysUser;
@@ -34,7 +35,9 @@
import com.ruoyi.staff.pojo.StaffOnJob;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@@ -83,7 +86,22 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMeetingRoom(Long id) {
        if (id == null){
            throw new ServiceException("删除会议室失败,会议室ID不能为空");
        }
        LocalDateTime now = LocalDateTime.now();
        List<MeetApplication> meetApplicationList = meetApplicationMapper.selectList(Wrappers.<MeetApplication>lambdaQuery()
                .eq(MeetApplication::getRoomId, id)
                .gt(MeetApplication::getEndTime, now)
                .in(MeetApplication::getStatus, Arrays.asList(0, 1)));
        if (!meetApplicationList.isEmpty()){
            throw new ServiceException("删除会议室失败,该会议室尚有未开始或进行中的有效会议预约");
        }
        meetingRoomMapper.deleteById(id);
    }
src/main/java/com/ruoyi/home/controller/HomeController.java
@@ -69,6 +69,7 @@
        return AjaxResult.success(homeSummaryDto);
    }
    /********************************************************营销采购类**************************************************/
    @GetMapping("/supplierPurchaseRanking")
    @ApiOperation("供应商采购排名")
    public AjaxResult supplierPurchaseRanking(@RequestParam(value = "type", defaultValue = "1") Integer type) {
@@ -80,13 +81,6 @@
    @ApiOperation("客户营收贡献数值分析")
    public AjaxResult customerRevenueAnalysis(@RequestParam("customerId") Long customerId, @RequestParam(value = "type", defaultValue = "1") Integer type) {
        CustomerRevenueAnalysisDto dto = homeService.customerRevenueAnalysis(customerId, type);
        return AjaxResult.success(dto);
    }
    @GetMapping("/productCategoryDistribution")
    @ApiOperation("产品大类分布")
    public AjaxResult productCategoryDistribution() {
        ProductCategoryDistributionDto dto = homeService.productCategoryDistribution();
        return AjaxResult.success(dto);
    }
@@ -111,63 +105,23 @@
        return AjaxResult.success(list);
    }
    @GetMapping("/salesPurchaseStorageProductCount")
    @ApiOperation("销售-采购-储存产品数")
    public AjaxResult salesPurchaseStorageProductCount(){
        List<MapDto> list = homeService.salesPurchaseStorageProductCount();
        return AjaxResult.success(list);
    @GetMapping("/business")
    @Log(title = "销售-采购-库存数据", businessType = BusinessType.OTHER)
    @ApiOperation("销售-采购-库存数据")
    public AjaxResult business(HomeBusinessDto req) {
        HomeBusinessDto homeBusinessDto = homeService.business();
        return AjaxResult.success(homeBusinessDto);
    }
    @GetMapping("/productInOutAnalysis")
    @ApiOperation("产品出入库分析")
    public AjaxResult productInOutAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
        List<Map<String, Object>> result = homeService.productInOutAnalysis(type);
        return AjaxResult.success(result);
    @GetMapping("/analysisCustomerContractAmounts")
    @Log(title = "客户合同金额分析", businessType = BusinessType.OTHER)
    @ApiOperation("客户合同金额分析")
    public AjaxResult analysisCustomerContractAmounts(AnalysisCustomerContractAmountsDto req) {
        AnalysisCustomerContractAmountsDto analysisCustomerContractAmounts = homeService.analysisCustomerContractAmounts();
        return AjaxResult.success(analysisCustomerContractAmounts);
    }
    @GetMapping("/productTurnoverDays")
    @ApiOperation("产品周转天数")
    public AjaxResult productTurnoverDays(){
        List<MapDto> list = homeService.productTurnoverDays();
        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("/inputOutputAnalysis")
    @ApiOperation("投入产出分析")
    public AjaxResult inputOutputAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
@@ -176,7 +130,7 @@
    }
    @GetMapping("/processOutputAnalysis")
    @ApiOperation("工序产出分析")
    @ApiOperation("工序产出分析")
    public AjaxResult processOutputAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
        List<MapDto> list = homeService.processOutputAnalysis(type);
        return AjaxResult.success(list);
@@ -202,6 +156,21 @@
        return AjaxResult.success(homeService.orderCount());
    }
    @GetMapping("/progressStatistics")
    @ApiOperation("各生产订单的完成进度统计")
    public AjaxResult progressStatistics(){
        ProductionProgressDto productionProgressDto = homeService.productionProgress();
        return AjaxResult.success(productionProgressDto);
    }
    @GetMapping("/workInProcessTurnover")
    @ApiOperation("在制品周转情况")
    public AjaxResult workInProcessTurnover(){
        ProductionTurnoverDto productionTurnoverDto = homeService.workInProcessTurnover();
        return AjaxResult.success(productionTurnoverDto);
    }
    /********************************************************质量类*****************************************************/
    @GetMapping("/rawMaterialDetection")
    @ApiOperation("原材料检测")
    public AjaxResult rawMaterialDetection(@RequestParam(value = "type", defaultValue = "1") Integer type){
@@ -255,42 +224,6 @@
        return AjaxResult.success(list);
    }
    /********************************************************营销采购类**************************************************/
    @GetMapping("/business")
    @Log(title = "销售-采购-库存数据", businessType = BusinessType.OTHER)
    @ApiOperation("销售-采购-库存数据")
    public AjaxResult business(HomeBusinessDto req) {
        HomeBusinessDto homeBusinessDto = homeService.business();
        return AjaxResult.success(homeBusinessDto);
    }
    @GetMapping("/analysisCustomerContractAmounts")
    @Log(title = "客户合同金额分析", businessType = BusinessType.OTHER)
    @ApiOperation("客户合同金额分析")
    public AjaxResult analysisCustomerContractAmounts(AnalysisCustomerContractAmountsDto req) {
        AnalysisCustomerContractAmountsDto analysisCustomerContractAmounts = homeService.analysisCustomerContractAmounts();
        return AjaxResult.success(analysisCustomerContractAmounts);
    }
    /********************************************************生产类*****************************************************/
    @GetMapping("/progressStatistics")
    @ApiOperation("各生产订单的完成进度统计")
    public AjaxResult progressStatistics(){
        ProductionProgressDto productionProgressDto = homeService.productionProgress();
        return AjaxResult.success(productionProgressDto);
    }
    @GetMapping("/workInProcessTurnover")
    @ApiOperation("在制品周转情况")
    public AjaxResult workInProcessTurnover(){
        ProductionTurnoverDto productionTurnoverDto = homeService.workInProcessTurnover();
        return AjaxResult.success(productionTurnoverDto);
    }
    /********************************************************质量类*****************************************************/
    @GetMapping("/qualityStatistics")
    @Log(title = "质量分析", businessType = BusinessType.OTHER)
    @ApiOperation("质量分析")
@@ -299,8 +232,42 @@
        return AjaxResult.success(qualityStatisticsDto);
    }
    /********************************************************财务类*****************************************************/
    @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("/statisticsReceivablePayable")
    @Log(title = "应收应付统计", businessType = BusinessType.OTHER)
    @ApiOperation("应收应付统计")
@@ -309,17 +276,34 @@
        return AjaxResult.success(statisticsReceivablePayable);
    }
    /********************************************************仓储类*****************************************************/
    @GetMapping("/productCategoryDistribution")
    @ApiOperation("产品大类分布")
    public AjaxResult productCategoryDistribution() {
        ProductCategoryDistributionDto dto = homeService.productCategoryDistribution();
        return AjaxResult.success(dto);
    }
    @GetMapping("/salesPurchaseStorageProductCount")
    @ApiOperation("销售-采购-储存产品数")
    public AjaxResult salesPurchaseStorageProductCount(){
        List<MapDto> list = homeService.salesPurchaseStorageProductCount();
        return AjaxResult.success(list);
    }
    @GetMapping("/productInOutAnalysis")
    @ApiOperation("产品出入库分析")
    public AjaxResult productInOutAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
        List<Map<String, Object>> result = homeService.productInOutAnalysis(type);
        return AjaxResult.success(result);
    }
    @GetMapping("/productTurnoverDays")
    @ApiOperation("产品周转天数")
    public AjaxResult productTurnoverDays(){
        List<MapDto> list = homeService.productTurnoverDays();
        return AjaxResult.success(list);
    }
}
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -1729,8 +1729,7 @@
                    BigDecimal finishQty = item.getQuantity() != null ? item.getQuantity() : BigDecimal.ZERO;
                    BigDecimal scrapQty = item.getScrapQty() != null ? item.getScrapQty() : BigDecimal.ZERO;
                    dto.setFinishQuantity(
                            dto.getFinishQuantity() != null ? dto.getFinishQuantity().add(finishQty) : finishQty);
                    dto.setFinishQuantity(dto.getFinishQuantity() != null ? dto.getFinishQuantity().add(finishQty) : finishQty);
                }
            }
@@ -1746,9 +1745,11 @@
                    .filter(i -> i.getCreateTime() != null)
                    .collect(Collectors.groupingBy(
                            i -> i.getCreateTime().toLocalDate().toString(),
                            Collectors.reducing(BigDecimal.ZERO,
                                    i -> i.getQuantity() != null ? i.getQuantity() : BigDecimal.ZERO,
                                    BigDecimal::add)));
                            Collectors.reducing(BigDecimal.ZERO, i -> {
                                BigDecimal qty = (i.getQuantity() != null) ? i.getQuantity() : BigDecimal.ZERO;
                                BigDecimal scrap = (i.getScrapQty() != null) ? i.getScrapQty() : BigDecimal.ZERO;
                                return qty.subtract(scrap);
                            }, BigDecimal::add)));
            finishMap.forEach((date, qty) -> {
                WorkOrderEfficiencyDto dto = dateMap.getOrDefault(date, new WorkOrderEfficiencyDto());
src/main/java/com/ruoyi/production/controller/ProductOrderController.java
@@ -16,6 +16,7 @@
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.List;
@RequestMapping("productOrder")
@@ -51,9 +52,31 @@
    @Log(title = "生产订单", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, ProductOrderDto productOrderDto) {
        List<ProductOrderDto> list;
        list = productOrderService.pageProductOrder(new Page<>(1, -1), productOrderDto).getRecords();
        ExcelUtil<ProductOrderDto> util = new ExcelUtil<ProductOrderDto>(ProductOrderDto.class);
        List<ProductOrderDto> list = productOrderService.pageProductOrder(new Page<>(1, -1), productOrderDto).getRecords();
        if (list != null && !list.isEmpty()) {
            list.forEach(item -> {
                // 判空
                if (item.getQuantity() == null || item.getCompleteQuantity() == null) {
                    item.setCompletionStatus(BigDecimal.ZERO);
                    return;
                }
                // 判零
                if (item.getQuantity().compareTo(BigDecimal.ZERO) == 0) {
                    item.setCompletionStatus(BigDecimal.ZERO);
                    return;
                }
                BigDecimal progress = item.getCompleteQuantity()
                        .divide(item.getQuantity(), 4, BigDecimal.ROUND_HALF_UP)
                        .multiply(new BigDecimal(100))
                        .setScale(2, BigDecimal.ROUND_HALF_UP);
                item.setCompletionStatus(progress);
            });
        }
        ExcelUtil<ProductOrderDto> util = new ExcelUtil<>(ProductOrderDto.class);
        util.exportExcel(response, list, "生产订单数据");
    }
src/main/java/com/ruoyi/production/controller/SalesLedgerWorkController.java
@@ -1,93 +1,92 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
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.production.dto.ProcessSchedulingDto;
import com.ruoyi.production.dto.ProductionReportDto;
import com.ruoyi.production.dto.SalesLedgerSchedulingProcessDto;
import com.ruoyi.production.dto.SalesLedgerWorkDto;
import com.ruoyi.production.pojo.SalesLedgerWork;
import com.ruoyi.production.service.SalesLedgerWorkService;
import com.ruoyi.production.service.impl.SalesLedgerWorkServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * @author :yys
 * @date : 2025/7/21 14:43
 */
@RestController
@Api(tags = "生产报工(排产记录)")
@RequestMapping("/salesLedger/work")
@Deprecated // 标记该类已弃用
public class SalesLedgerWorkController extends BaseController {
    @Autowired
    private SalesLedgerWorkServiceImpl salesLedgerWorkService;
    @GetMapping("/listPage")
    @Log(title = "生产报工-分页查询", businessType = BusinessType.OTHER)
    @ApiOperation("生产报工-分页查询")
    public AjaxResult listPage(Page page, SalesLedgerWorkDto salesLedgerWorkDto) {
        IPage<SalesLedgerWorkDto> listPage = salesLedgerWorkService.listPage(page, salesLedgerWorkDto);
        return AjaxResult.success(listPage);
    }
    /**
     * 导出
     * @param response
     */
    @PostMapping("/export")
    @ApiOperation("生产管理-生产报工-导出")
    public void export(HttpServletResponse response) {
        Page page = new Page(-1,-1);
        SalesLedgerWorkDto salesLedgerSchedulingDto = new SalesLedgerWorkDto();
        IPage<SalesLedgerWorkDto> result = salesLedgerWorkService.listPage(page,salesLedgerSchedulingDto);
        result.getRecords().forEach(item -> {
            item.setDaiNum(item.getFinishedNum().subtract(item.getSchedulingNum()));
            item.setStatusName(item.getStatus().toString());
        });
        ExcelUtil<SalesLedgerWorkDto> util = new ExcelUtil<>(SalesLedgerWorkDto.class);
        util.exportExcel(response, result.getRecords(), "工序排产");
    }
    @GetMapping("/list")
    @Log(title = "生产报工-查询", businessType = BusinessType.OTHER)
    @ApiOperation("生产报工-查询")
    public AjaxResult list(@RequestParam("id") Long id) {
        List<ProductionReportDto> list = salesLedgerWorkService.getList(id);
        return AjaxResult.success(list);
    }
    @PostMapping("/productionReport")
    @Log(title = "生产管理-生产报工", businessType = BusinessType.INSERT)
    @ApiOperation("生产管理-生产报工")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult productionReport(@RequestBody ProductionReportDto productionReportDto) {
        int result = salesLedgerWorkService.productionReport(productionReportDto);
        return AjaxResult.success(result);
    }
    @PostMapping("/productionReportUpdate")
    @Log(title = "生产管理-生产报工-修改", businessType = BusinessType.UPDATE)
    @ApiOperation("生产管理-生产报工-修改")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult productionReportUpdate(@RequestBody ProductionReportDto productionReportDto) {
        int result = salesLedgerWorkService.productionReportUpdate(productionReportDto);
        return AjaxResult.success(result);
    }
}
//package com.ruoyi.production.controller;
//
//import com.baomidou.mybatisplus.core.metadata.IPage;
//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
//import com.ruoyi.common.utils.poi.ExcelUtil;
//import com.ruoyi.framework.aspectj.lang.annotation.Log;
//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.production.dto.ProcessSchedulingDto;
//import com.ruoyi.production.dto.ProductionReportDto;
//import com.ruoyi.production.dto.SalesLedgerSchedulingProcessDto;
//import com.ruoyi.production.dto.SalesLedgerWorkDto;
//import com.ruoyi.production.pojo.SalesLedgerWork;
//import com.ruoyi.production.service.SalesLedgerWorkService;
//import io.swagger.annotations.Api;
//import io.swagger.annotations.ApiOperation;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.transaction.annotation.Transactional;
//import org.springframework.web.bind.annotation.*;
//
//import javax.servlet.http.HttpServletResponse;
//import java.util.List;
//
///**
// * @author :yys
// * @date : 2025/7/21 14:43
// */
//@RestController
//@Api(tags = "生产报工(排产记录)")
//@RequestMapping("/salesLedger/work")
//@Deprecated // 标记该类已弃用
//public class SalesLedgerWorkController extends BaseController {
//
//
//    @Autowired
//    private SalesLedgerWorkServiceImpl salesLedgerWorkService;
//
//    @GetMapping("/listPage")
//    @Log(title = "生产报工-分页查询", businessType = BusinessType.OTHER)
//    @ApiOperation("生产报工-分页查询")
//    public AjaxResult listPage(Page page, SalesLedgerWorkDto salesLedgerWorkDto) {
//        IPage<SalesLedgerWorkDto> listPage = salesLedgerWorkService.listPage(page, salesLedgerWorkDto);
//        return AjaxResult.success(listPage);
//    }
//
//    /**
//     * 导出
//     * @param response
//     */
//    @PostMapping("/export")
//    @ApiOperation("生产管理-生产报工-导出")
//    public void export(HttpServletResponse response) {
//        Page page = new Page(-1,-1);
//        SalesLedgerWorkDto salesLedgerSchedulingDto = new SalesLedgerWorkDto();
//        IPage<SalesLedgerWorkDto> result = salesLedgerWorkService.listPage(page,salesLedgerSchedulingDto);
//        result.getRecords().forEach(item -> {
//            item.setDaiNum(item.getFinishedNum().subtract(item.getSchedulingNum()));
//            item.setStatusName(item.getStatus().toString());
//        });
//        ExcelUtil<SalesLedgerWorkDto> util = new ExcelUtil<>(SalesLedgerWorkDto.class);
//        util.exportExcel(response, result.getRecords(), "工序排产");
//    }
//
//    @GetMapping("/list")
//    @Log(title = "生产报工-查询", businessType = BusinessType.OTHER)
//    @ApiOperation("生产报工-查询")
//    public AjaxResult list(@RequestParam("id") Long id) {
//        List<ProductionReportDto> list = salesLedgerWorkService.getList(id);
//        return AjaxResult.success(list);
//    }
//
//    @PostMapping("/productionReport")
//    @Log(title = "生产管理-生产报工", businessType = BusinessType.INSERT)
//    @ApiOperation("生产管理-生产报工")
//    @Transactional(rollbackFor = Exception.class)
//    public AjaxResult productionReport(@RequestBody ProductionReportDto productionReportDto) {
//        int result = salesLedgerWorkService.productionReport(productionReportDto);
//        return AjaxResult.success(result);
//    }
//
//
//    @PostMapping("/productionReportUpdate")
//    @Log(title = "生产管理-生产报工-修改", businessType = BusinessType.UPDATE)
//    @ApiOperation("生产管理-生产报工-修改")
//    @Transactional(rollbackFor = Exception.class)
//    public AjaxResult productionReportUpdate(@RequestBody ProductionReportDto productionReportDto) {
//        int result = salesLedgerWorkService.productionReportUpdate(productionReportDto);
//        return AjaxResult.success(result);
//    }
//
//}
src/main/java/com/ruoyi/production/dto/ProductOrderDto.java
@@ -39,8 +39,8 @@
    @Excel(name = "工艺路线编号")
    private String processRouteCode;
    @ApiModelProperty(value = "完成状态")
    @Excel(name = "完成状态")
    @ApiModelProperty(value = "完成进度")
    @Excel(name = "完成进度", suffix = "%")
    private BigDecimal completionStatus;
    @ApiModelProperty(value = "BOM编号")
@@ -54,4 +54,7 @@
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate deliveryDate;
    //是否发货(台账页面颜色控制)
    private Boolean isFh;
}
src/main/java/com/ruoyi/production/mapper/ProductOrderMapper.java
@@ -17,10 +17,6 @@
public interface ProductOrderMapper extends BaseMapper<ProductOrder> {
    IPage<ProductOrderDto> pageProductOrder(Page page, @Param("c") ProductOrderDto productOrder);
    /**
     * 根据订单ID查询工单报工
     */
     ProductOrderDto productMainByOrderId(@Param("c") ProductOrder productOrder);
    List<ProcessRoute> listProcessRoute(@Param("productModelId") Long productModelId);
src/main/java/com/ruoyi/production/mapper/ProductionProductMainMapper.java
@@ -10,6 +10,7 @@
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.ArrayList;
import java.util.List;
@Mapper
@@ -30,4 +31,6 @@
    ProductOrder getOrderByMainId(@Param("productMainId") Long productMainId);
    IPage<ProductionProductMainDto> listProductionDetails(@Param("ew") SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto, Page page);
    ArrayList<Long> listMain(List<Long> idList);
}
src/main/java/com/ruoyi/production/pojo/ProcessRouteItem.java
@@ -38,4 +38,7 @@
    private Integer dragSort;
    @ApiModelProperty(value ="是否质检")
    private Boolean isQuality;
}
src/main/java/com/ruoyi/production/pojo/ProductOrder.java
@@ -30,12 +30,13 @@
    /**
     * 销售台账产品id(sales_ledger_product)
     */
    @ApiModelProperty(value = "销售台账产品id")
    private Long saleLedgerProductId;
    /**
     * 销售台账产品id(sales_ledger_product)
     * 产品规格id
     */
    @ApiModelProperty(value = "销售台账产品id")
    @ApiModelProperty(value = "产品规格id")
    private Long productModelId;
    /**
src/main/java/com/ruoyi/production/pojo/ProductProcess.java
@@ -5,6 +5,7 @@
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
@@ -70,5 +71,8 @@
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    @ApiModelProperty(value ="是否质检")
    private Boolean isQuality;
}
src/main/java/com/ruoyi/production/pojo/ProductProcessRouteItem.java
@@ -38,4 +38,7 @@
    @ApiModelProperty(value ="拖动排序")
    private Integer dragSort;
    @ApiModelProperty(value ="是否质检")
    private Boolean isQuality;
}
src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java
@@ -24,6 +24,7 @@
    private BigDecimal quantity;
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty(value = "租户ID")
src/main/java/com/ruoyi/production/pojo/ProductionProductOutput.java
@@ -20,10 +20,11 @@
    @ApiModelProperty(value = "产品id")
    private Long productModelId;
    @ApiModelProperty(value = "报工数量")
    @ApiModelProperty(value = "报工数量(总数量)")
    private BigDecimal quantity;
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty(value = "租户ID")
src/main/java/com/ruoyi/production/pojo/SalesLedgerProductionAccounting.java
@@ -23,24 +23,9 @@
    private Long id;
    /**
     * 销售排产-报工表id
     * 报工表id
     */
    private Long salesLedgerWorkId;
    /**
     * 销售排产表id
     */
    private Long salesLedgerSchedulingId;
    /**
     * 销售台账id
     */
    private Long salesLedgerId;
    /**
     * 销售产品id
     */
    private Long salesLedgerProductId;
    private Long productMainId;
    /**
     * 生产人id
@@ -101,6 +86,5 @@
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    private Long ProductMainId;
}
src/main/java/com/ruoyi/production/service/ProductionProductMainService.java
@@ -6,10 +6,15 @@
import com.ruoyi.production.dto.ProductionProductMainDto;
import com.ruoyi.production.pojo.ProductionProductMain;
import java.util.ArrayList;
import java.util.List;
public interface ProductionProductMainService extends IService<ProductionProductMain> {
    IPage<ProductionProductMainDto> listPageProductionProductMainDto(Page page, ProductionProductMainDto productionProductMainDto);
    Boolean addProductMain(ProductionProductMainDto productionProductMainDto);
    Boolean removeProductMain(Long id);
    ArrayList<Long> listMain(List<Long> idList);
}
src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java
@@ -101,14 +101,12 @@
//                    // 删除质检
//                    qualityInspectMapper.delete(new LambdaQueryWrapper<QualityInspect>()
//                            .eq(QualityInspect::getProductMainId, mainId));
                    salesLedgerProductionAccountingMapper.delete(new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                            .eq(SalesLedgerProductionAccounting::getProductMainId, main.getId()));
                }
            }
            // 查询订单 + 删除核算
            ProductOrder productOrder = productOrderMapper.selectById(productOrderId);
            if (productOrder != null && productOrder.getSalesLedgerId() != null) {
                salesLedgerProductionAccountingMapper.delete(new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                        .eq(SalesLedgerProductionAccounting::getSalesLedgerId, productOrder.getSalesLedgerId()));
            }
            // 删除关联工单
            productWorkOrderMapper.delete(new LambdaQueryWrapper<ProductWorkOrder>()
                    .eq(ProductWorkOrder::getProductProcessRouteItemId, routeItemId));
src/main/java/com/ruoyi/production/service/impl/ProductProcessServiceImpl.java
@@ -62,11 +62,19 @@
            if(CollectionUtils.isEmpty(productProcessList)){
                return AjaxResult.warn("模板错误或导入数据为空");
            }
            productProcessList.forEach(productProcess -> {
                if (ObjectUtils.isEmpty(productProcess)) {
                    throw new RuntimeException("使用模板进行导入");
                }
                if (ObjectUtils.isEmpty(productProcess.getName())) {
                    throw new RuntimeException("工序名称不能为空");
                }
            });
            this.saveOrUpdateBatch(productProcessList);
            return AjaxResult.success(true);
        }catch (Exception e){
            e.printStackTrace();
            return AjaxResult.error("导入失败");
            return AjaxResult.error(e.getMessage());
        }
    }
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -33,6 +33,7 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -163,41 +164,46 @@
        //只有合格数量>0才能增加相应数据
        if (productQty.compareTo(BigDecimal.ZERO) > 0) {
            /*新增质检*/
            //对应的过程检或者出厂检
            List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery().eq(ProductProcessRouteItem::getProductRouteId, productProcessRouteItem.getProductRouteId()));
            int inspectType = 1;
            String process = productProcess.getName();//工序
            if (productProcessRouteItem.getDragSort() == productProcessRouteItems.size()) {
                //最后一道工序生成出厂检
                inspectType = 2;
                process = null;
            }
            Product product = productMapper.selectById(productModel.getProductId());
            QualityInspect qualityInspect = new QualityInspect();
            qualityInspect.setProductId(product.getId());
            qualityInspect.setProductName(product.getProductName());
            qualityInspect.setModel(productModel.getModel());
            qualityInspect.setUnit(productModel.getUnit());
            qualityInspect.setQuantity(productQty);
            qualityInspect.setProcess(process);
            qualityInspect.setInspectState(0);
            qualityInspect.setInspectType(inspectType);
            qualityInspect.setProductMainId(productionProductMain.getId());
            qualityInspect.setProductModelId(productModel.getId());
            qualityInspectMapper.insert(qualityInspect);
            List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process);
            if (qualityTestStandard.size() > 0) {
                qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
                qualityInspectMapper.updateById(qualityInspect);
                qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
                                .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))//默认获取最新的
                        .forEach(qualityTestStandardParam -> {
                            QualityInspectParam param = new QualityInspectParam();
                            BeanUtils.copyProperties(qualityTestStandardParam, param);
                            param.setId(null);
                            param.setInspectId(qualityInspect.getId());
                            qualityInspectParamMapper.insert(param);
                        });
            if (productProcessRouteItem.getIsQuality()) {
                //对应的过程检或者出厂检
                int inspectType = 1;
                String process = productProcess.getName();//工序
                if (productProcessRouteItem.getDragSort() == productProcessRouteItems.size()) {
                    //最后一道工序生成出厂检
                    inspectType = 2;
                    process = null;
                }
                Product product = productMapper.selectById(productModel.getProductId());
                QualityInspect qualityInspect = new QualityInspect();
                qualityInspect.setProductId(product.getId());
                qualityInspect.setProductName(product.getProductName());
                qualityInspect.setModel(productModel.getModel());
                qualityInspect.setUnit(productModel.getUnit());
                qualityInspect.setQuantity(productQty);
                qualityInspect.setProcess(process);
                qualityInspect.setInspectState(0);
                qualityInspect.setInspectType(inspectType);
                qualityInspect.setProductMainId(productionProductMain.getId());
                qualityInspect.setProductModelId(productModel.getId());
                qualityInspectMapper.insert(qualityInspect);
                List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process);
                if (qualityTestStandard.size() > 0) {
                    qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
                    qualityInspectMapper.updateById(qualityInspect);
                    qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
                                    .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))//默认获取最新的
                            .forEach(qualityTestStandardParam -> {
                                QualityInspectParam param = new QualityInspectParam();
                                BeanUtils.copyProperties(qualityTestStandardParam, param);
                                param.setId(null);
                                param.setInspectId(qualityInspect.getId());
                                qualityInspectParamMapper.insert(param);
                            });
                }
            }else {
                //直接入库
                stockUtils.addStock(productProcessRouteItem.getProductModelId(), productionProductOutput.getQuantity(), StockQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId());
            }
            /*更新工单和生产订单*/
            ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId());
@@ -224,10 +230,7 @@
            productOrderMapper.updateById(productOrder);
            /*添加生产核算*/
            SalesLedgerProductionAccounting salesLedgerProductionAccounting = SalesLedgerProductionAccounting.builder()
                    .salesLedgerWorkId(productionProductMain.getId())
                    .salesLedgerSchedulingId(0L)
                    .salesLedgerId(productOrder.getSalesLedgerId())
                    .salesLedgerProductId(productOrder.getSaleLedgerProductId())
                    .productMainId(productionProductMain.getId())
                    .schedulingUserId(user.getUserId())
                    .schedulingUserName(user.getNickName())
                    .finishedNum(productQty)
@@ -256,7 +259,7 @@
        /*删除核算*/
        salesLedgerProductionAccountingMapper.delete(
                new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                        .eq(SalesLedgerProductionAccounting::getSalesLedgerWorkId, productionProductMain.getId())
                        .eq(SalesLedgerProductionAccounting::getProductMainId, productionProductMain.getId())
        );
        /*更新工单和生产订单*/
        ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(productionProductMain.getWorkOrderId());
@@ -289,10 +292,17 @@
                .eq(ProductionProductInput::getProductMainId, productionProductMain.getId()));
        //删除报废的入库记录
        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
        //删除不需要质检的合格入库
        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode());
        //删除投入对应的出库记录
        stockUtils.deleteStockOutRecord(productionProductMain.getId(), StockQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
        // 删除主表
        productionProductMainMapper.deleteById(productionProductMain.getId());
        return true;
    }
    @Override
    public ArrayList<Long> listMain(List<Long> idList) {
        return productionProductMainMapper.listMain(idList);
    }
}
src/main/java/com/ruoyi/production/service/impl/SalesLedgerWorkServiceImpl.java
@@ -1,185 +1,182 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.common.utils.SecurityUtils;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.procurementrecord.dto.Details;
import com.ruoyi.procurementrecord.dto.ProcurementAddDto;
import com.ruoyi.procurementrecord.dto.ProcurementRecordOutAdd;
import com.ruoyi.procurementrecord.service.impl.ProcurementRecordOutServiceImpl;
import com.ruoyi.procurementrecord.service.impl.ProcurementRecordServiceImpl;
import com.ruoyi.production.dto.ProductionReportDto;
import com.ruoyi.production.dto.SalesLedgerWorkDto;
import com.ruoyi.production.mapper.SalesLedgerProductionAccountingMapper;
import com.ruoyi.production.mapper.SalesLedgerWorkMapper;
import com.ruoyi.production.pojo.SalesLedgerProductionAccounting;
import com.ruoyi.production.pojo.SalesLedgerWork;
import com.ruoyi.production.service.SalesLedgerProductionAccountingService;
import com.ruoyi.production.service.SalesLedgerWorkService;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.sales.mapper.LossMapper;
import com.ruoyi.sales.pojo.Loss;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
 * @author :yys
 * @date : 2025/7/21 14:40
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SalesLedgerWorkServiceImpl extends ServiceImpl<SalesLedgerWorkMapper, SalesLedgerWork> implements SalesLedgerWorkService {
    private final SalesLedgerWorkMapper salesLedgerWorkMapper;
    private final SysUserMapper sysUserMapper;
    private final LossMapper lossMapper;
    private final SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    @Override
    public IPage<SalesLedgerWorkDto> listPage(Page page, SalesLedgerWorkDto salesLedgerWorkDto) {
        IPage<SalesLedgerWorkDto> iPage = salesLedgerWorkMapper.listPage(page, salesLedgerWorkDto);
        List<Loss> losses = lossMapper.selectList(null);
        if(!CollectionUtils.isEmpty(losses)){
            iPage.getRecords().forEach(item -> {
                String[] split = item.getSpecificationModel().split("\\*");
                if(split.length == 2 && isNumeric(split[1]) && isNumeric(split[0])){
                    // 计算损耗(100000代表 损耗的 100 和 单位转换的1000)
                    BigDecimal divide = new BigDecimal(split[0])
                            .multiply(new BigDecimal(split[1]))
                            .multiply(item.getFinishedNum())
                            .multiply(losses.get(0).getRate())
                            .divide(new BigDecimal(100000), 2, RoundingMode.HALF_UP);
                    item.setLoss(divide.toString());
                }
            });
        }
        return iPage;
    }
    public static boolean isNumeric(String str) {
        if (str == null || str.isEmpty()) {
            return false;
        }
        // 遍历字符串的每个字符,检查是否为数字
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isDigit(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }
    private final ProcurementRecordServiceImpl procurementRecordService;
    @Override
    public int productionReport(ProductionReportDto productionReportDto) {
        SalesLedgerWork salesLedgerWork = salesLedgerWorkMapper.selectById(productionReportDto.getId());
        SysUser sysUser = sysUserMapper.selectUserById(productionReportDto.getSchedulingUserId());
        if (salesLedgerWork == null) throw new RuntimeException("报工数据不存在");
        if (salesLedgerWork.getStatus() == 3) throw new RuntimeException("报工已完成");
        if (sysUser == null) throw new RuntimeException("生产人不存在");
        salesLedgerWork.setFinishedNum(salesLedgerWork.getFinishedNum().add(productionReportDto.getFinishedNum()));
        if(salesLedgerWork.getSchedulingNum().compareTo(salesLedgerWork.getFinishedNum()) <= 0){
            salesLedgerWork.setStatus(3);
        }else{
            salesLedgerWork.setStatus(2);
        }
        salesLedgerWorkMapper.updateById(salesLedgerWork);
        // 新增报工数据
        SalesLedgerProductionAccounting.SalesLedgerProductionAccountingBuilder builder = SalesLedgerProductionAccounting.builder()
                .salesLedgerWorkId(salesLedgerWork.getId())
                .salesLedgerSchedulingId(salesLedgerWork.getSalesLedgerSchedulingId())
                .salesLedgerId(salesLedgerWork.getSalesLedgerId())
                .salesLedgerProductId((long)salesLedgerWork.getSalesLedgerProductId())
                .schedulingUserId(sysUser.getUserId())
                .schedulingUserName(sysUser.getNickName())
                .finishedNum(productionReportDto.getFinishedNum())
                .workHours(salesLedgerWork.getWorkHours())
                .process(salesLedgerWork.getProcess())
                .schedulingDate(LocalDate.parse(productionReportDto.getSchedulingDate(), DateTimeFormatter.ISO_LOCAL_DATE));
        salesLedgerProductionAccountingMapper.insert(builder.build());
        // 生产报工成功 -> 入库
        LoginUser loginUser = SecurityUtils.getLoginUser();
        ProcurementAddDto procurementRecordOutAdd = new ProcurementAddDto();
        procurementRecordOutAdd.setType(2);
        procurementRecordOutAdd.setTypeName("生产入库");
        procurementRecordOutAdd.setNickName(loginUser.getNickName());
        List<Details> details = new ArrayList<>();
        Details details1 = new Details();
        details1.setInboundQuantity(productionReportDto.getFinishedNum());
        details1.setId(Integer.parseInt(salesLedgerWork.getSalesLedgerProductId().toString()));
        details1.setUnitPrice(productionReportDto.getUnitPrice());
        details1.setTotalPrice(productionReportDto.getTotalPrice());
        details.add(details1);
        procurementRecordOutAdd.setDetails(details);
        procurementRecordService.add(procurementRecordOutAdd);
        return 0;
    }
    @Override
    public int productionReportUpdate(ProductionReportDto productionReportDto) {
        SalesLedgerProductionAccounting salesLedgerProductionAccounting = salesLedgerProductionAccountingMapper.selectById(productionReportDto.getId());
        if(salesLedgerProductionAccounting == null) throw new RuntimeException("报工数据不存在");
        SysUser sysUser = sysUserMapper.selectUserById(productionReportDto.getSchedulingUserId());
        if(sysUser == null) throw new RuntimeException("生产人不存在");
        salesLedgerProductionAccounting.setFinishedNum(productionReportDto.getFinishedNum());
        salesLedgerProductionAccounting.setSchedulingUserId(sysUser.getUserId());
        salesLedgerProductionAccounting.setSchedulingUserName(sysUser.getNickName());
        salesLedgerProductionAccounting.setSchedulingDate(LocalDate.parse(productionReportDto.getSchedulingDate(), DateTimeFormatter.ISO_LOCAL_DATE));
        salesLedgerProductionAccountingMapper.updateById(salesLedgerProductionAccounting);
        // 更新报工数据
        SalesLedgerWork salesLedgerWork = salesLedgerWorkMapper.selectById(salesLedgerProductionAccounting.getSalesLedgerWorkId());
        if(salesLedgerWork == null) throw new RuntimeException("报工数据不存在");
        salesLedgerWork.setFinishedNum(productionReportDto.getFinishedNum());
        if(salesLedgerWork.getSchedulingNum().compareTo(salesLedgerWork.getFinishedNum()) <= 0){
            salesLedgerWork.setStatus(3);
        }else{
            salesLedgerWork.setStatus(2);
        }
        salesLedgerWork.setSchedulingUserId(sysUser.getUserId());
        salesLedgerWork.setSchedulingUserName(sysUser.getNickName());
        salesLedgerWork.setSchedulingDate(LocalDate.parse(productionReportDto.getSchedulingDate(), DateTimeFormatter.ISO_LOCAL_DATE));
        salesLedgerWorkMapper.updateById(salesLedgerWork);
        return 0;
    }
    @Override
    public List<ProductionReportDto> getList(Long id) {
        SalesLedgerWork salesLedgerWork = salesLedgerWorkMapper.selectById(id);
        if(salesLedgerWork == null) throw new RuntimeException("报工数据不存在");
        LambdaQueryWrapper<SalesLedgerProductionAccounting> salesLedgerProductionAccountingLambdaQueryWrapper = new LambdaQueryWrapper<>();
        salesLedgerProductionAccountingLambdaQueryWrapper.eq(SalesLedgerProductionAccounting::getSalesLedgerWorkId, id);
        List<SalesLedgerProductionAccounting> salesLedgerProductionAccountingList = salesLedgerProductionAccountingMapper.selectList(salesLedgerProductionAccountingLambdaQueryWrapper);
        if(CollectionUtils.isEmpty(salesLedgerProductionAccountingList)) throw new RuntimeException("没有生产记录数据");
        return salesLedgerProductionAccountingList.stream().map(salesLedgerProductionAccounting -> {
            ProductionReportDto productionReportDto = new ProductionReportDto();
            BeanUtils.copyProperties(salesLedgerProductionAccounting, productionReportDto);
            productionReportDto.setSchedulingDate(salesLedgerProductionAccounting.getSchedulingDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
            productionReportDto.setSchedulingNum(salesLedgerWork.getSchedulingNum());
            return productionReportDto;
        }).collect(Collectors.toList());
    }
}
//package com.ruoyi.production.service.impl;
//
//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
//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.common.utils.SecurityUtils;
//import com.ruoyi.framework.security.LoginUser;
//import com.ruoyi.framework.web.domain.AjaxResult;
//import com.ruoyi.procurementrecord.dto.Details;
//import com.ruoyi.procurementrecord.dto.ProcurementAddDto;
//import com.ruoyi.procurementrecord.dto.ProcurementRecordOutAdd;
//import com.ruoyi.procurementrecord.service.impl.ProcurementRecordOutServiceImpl;
//import com.ruoyi.procurementrecord.service.impl.ProcurementRecordServiceImpl;
//import com.ruoyi.production.dto.ProductionReportDto;
//import com.ruoyi.production.dto.SalesLedgerWorkDto;
//import com.ruoyi.production.mapper.SalesLedgerProductionAccountingMapper;
//import com.ruoyi.production.mapper.SalesLedgerWorkMapper;
//import com.ruoyi.production.pojo.SalesLedgerProductionAccounting;
//import com.ruoyi.production.pojo.SalesLedgerWork;
//import com.ruoyi.production.service.SalesLedgerProductionAccountingService;
//import com.ruoyi.production.service.SalesLedgerWorkService;
//import com.ruoyi.project.system.domain.SysUser;
//import com.ruoyi.project.system.mapper.SysUserMapper;
//import com.ruoyi.sales.mapper.LossMapper;
//import com.ruoyi.sales.pojo.Loss;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.beans.BeanUtils;
//import org.springframework.stereotype.Service;
//import org.springframework.util.CollectionUtils;
//
//import java.math.BigDecimal;
//import java.math.RoundingMode;
//import java.time.LocalDate;
//import java.time.format.DateTimeFormatter;
//import java.util.ArrayList;
//import java.util.List;
//import java.util.stream.Collectors;
//
///**
// * @author :yys
// * @date : 2025/7/21 14:40
// */
//@Service
//@RequiredArgsConstructor
//@Slf4j
//public class SalesLedgerWorkServiceImpl extends ServiceImpl<SalesLedgerWorkMapper, SalesLedgerWork> implements SalesLedgerWorkService {
//
//    private final SalesLedgerWorkMapper salesLedgerWorkMapper;
//
//    private final SysUserMapper sysUserMapper;
//
//    private final LossMapper lossMapper;
//
//    private final SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
//
//    @Override
//    public IPage<SalesLedgerWorkDto> listPage(Page page, SalesLedgerWorkDto salesLedgerWorkDto) {
//        IPage<SalesLedgerWorkDto> iPage = salesLedgerWorkMapper.listPage(page, salesLedgerWorkDto);
//        List<Loss> losses = lossMapper.selectList(null);
//        if(!CollectionUtils.isEmpty(losses)){
//            iPage.getRecords().forEach(item -> {
//                String[] split = item.getSpecificationModel().split("\\*");
//                if(split.length == 2 && isNumeric(split[1]) && isNumeric(split[0])){
//                    // 计算损耗(100000代表 损耗的 100 和 单位转换的1000)
//                    BigDecimal divide = new BigDecimal(split[0])
//                            .multiply(new BigDecimal(split[1]))
//                            .multiply(item.getFinishedNum())
//                            .multiply(losses.get(0).getRate())
//                            .divide(new BigDecimal(100000), 2, RoundingMode.HALF_UP);
//                    item.setLoss(divide.toString());
//                }
//
//            });
//        }
//        return iPage;
//    }
//
//    public static boolean isNumeric(String str) {
//        if (str == null || str.isEmpty()) {
//            return false;
//        }
//        // 遍历字符串的每个字符,检查是否为数字
//        for (int i = 0; i < str.length(); i++) {
//            if (!Character.isDigit(str.charAt(i))) {
//                return false;
//            }
//        }
//        return true;
//    }
//
//    private final ProcurementRecordServiceImpl procurementRecordService;
//
//    @Override
//    public int productionReport(ProductionReportDto productionReportDto) {
//        SalesLedgerWork salesLedgerWork = salesLedgerWorkMapper.selectById(productionReportDto.getId());
//        SysUser sysUser = sysUserMapper.selectUserById(productionReportDto.getSchedulingUserId());
//        if (salesLedgerWork == null) throw new RuntimeException("报工数据不存在");
//        if (salesLedgerWork.getStatus() == 3) throw new RuntimeException("报工已完成");
//        if (sysUser == null) throw new RuntimeException("生产人不存在");
//        salesLedgerWork.setFinishedNum(salesLedgerWork.getFinishedNum().add(productionReportDto.getFinishedNum()));
//        if(salesLedgerWork.getSchedulingNum().compareTo(salesLedgerWork.getFinishedNum()) <= 0){
//            salesLedgerWork.setStatus(3);
//        }else{
//            salesLedgerWork.setStatus(2);
//        }
//        salesLedgerWorkMapper.updateById(salesLedgerWork);
//        // 新增报工数据
//        SalesLedgerProductionAccounting.SalesLedgerProductionAccountingBuilder builder = SalesLedgerProductionAccounting.builder()
//                .productMainId(null)
//                .schedulingUserId(sysUser.getUserId())
//                .schedulingUserName(sysUser.getNickName())
//                .finishedNum(productionReportDto.getFinishedNum())
//                .workHours(salesLedgerWork.getWorkHours())
//                .process(salesLedgerWork.getProcess())
//                .schedulingDate(LocalDate.parse(productionReportDto.getSchedulingDate(), DateTimeFormatter.ISO_LOCAL_DATE));
//        salesLedgerProductionAccountingMapper.insert(builder.build());
//        // 生产报工成功 -> 入库
//        LoginUser loginUser = SecurityUtils.getLoginUser();
//        ProcurementAddDto procurementRecordOutAdd = new ProcurementAddDto();
//        procurementRecordOutAdd.setType(2);
//        procurementRecordOutAdd.setTypeName("生产入库");
//        procurementRecordOutAdd.setNickName(loginUser.getNickName());
//        List<Details> details = new ArrayList<>();
//        Details details1 = new Details();
//        details1.setInboundQuantity(productionReportDto.getFinishedNum());
//        details1.setId(Integer.parseInt(salesLedgerWork.getSalesLedgerProductId().toString()));
//        details1.setUnitPrice(productionReportDto.getUnitPrice());
//        details1.setTotalPrice(productionReportDto.getTotalPrice());
//        details.add(details1);
//        procurementRecordOutAdd.setDetails(details);
//        procurementRecordService.add(procurementRecordOutAdd);
//
//        return 0;
//    }
//
//    @Override
//    public int productionReportUpdate(ProductionReportDto productionReportDto) {
//        SalesLedgerProductionAccounting salesLedgerProductionAccounting = salesLedgerProductionAccountingMapper.selectById(productionReportDto.getId());
//        if(salesLedgerProductionAccounting == null) throw new RuntimeException("报工数据不存在");
//        SysUser sysUser = sysUserMapper.selectUserById(productionReportDto.getSchedulingUserId());
//        if(sysUser == null) throw new RuntimeException("生产人不存在");
//        salesLedgerProductionAccounting.setFinishedNum(productionReportDto.getFinishedNum());
//        salesLedgerProductionAccounting.setSchedulingUserId(sysUser.getUserId());
//        salesLedgerProductionAccounting.setSchedulingUserName(sysUser.getNickName());
//        salesLedgerProductionAccounting.setSchedulingDate(LocalDate.parse(productionReportDto.getSchedulingDate(), DateTimeFormatter.ISO_LOCAL_DATE));
//        salesLedgerProductionAccountingMapper.updateById(salesLedgerProductionAccounting);
//
//        // 更新报工数据
//        SalesLedgerWork salesLedgerWork = salesLedgerWorkMapper.selectById(salesLedgerProductionAccounting.getSalesLedgerWorkId());
//        if(salesLedgerWork == null) throw new RuntimeException("报工数据不存在");
//        salesLedgerWork.setFinishedNum(productionReportDto.getFinishedNum());
//        if(salesLedgerWork.getSchedulingNum().compareTo(salesLedgerWork.getFinishedNum()) <= 0){
//            salesLedgerWork.setStatus(3);
//        }else{
//            salesLedgerWork.setStatus(2);
//        }
//        salesLedgerWork.setSchedulingUserId(sysUser.getUserId());
//        salesLedgerWork.setSchedulingUserName(sysUser.getNickName());
//        salesLedgerWork.setSchedulingDate(LocalDate.parse(productionReportDto.getSchedulingDate(), DateTimeFormatter.ISO_LOCAL_DATE));
//        salesLedgerWorkMapper.updateById(salesLedgerWork);
//        return 0;
//    }
//
//    @Override
//    public List<ProductionReportDto> getList(Long id) {
//        SalesLedgerWork salesLedgerWork = salesLedgerWorkMapper.selectById(id);
//        if(salesLedgerWork == null) throw new RuntimeException("报工数据不存在");
//        LambdaQueryWrapper<SalesLedgerProductionAccounting> salesLedgerProductionAccountingLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        salesLedgerProductionAccountingLambdaQueryWrapper.eq(SalesLedgerProductionAccounting::getSalesLedgerWorkId, id);
//        List<SalesLedgerProductionAccounting> salesLedgerProductionAccountingList = salesLedgerProductionAccountingMapper.selectList(salesLedgerProductionAccountingLambdaQueryWrapper);
//        if(CollectionUtils.isEmpty(salesLedgerProductionAccountingList)) throw new RuntimeException("没有生产记录数据");
//        return salesLedgerProductionAccountingList.stream().map(salesLedgerProductionAccounting -> {
//            ProductionReportDto productionReportDto = new ProductionReportDto();
//            BeanUtils.copyProperties(salesLedgerProductionAccounting, productionReportDto);
//            productionReportDto.setSchedulingDate(salesLedgerProductionAccounting.getSchedulingDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
//            productionReportDto.setSchedulingNum(salesLedgerWork.getSchedulingNum());
//            return productionReportDto;
//        }).collect(Collectors.toList());
//    }
//}
src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
@@ -152,4 +152,9 @@
    @ApiModelProperty("关联检测标准主表id")
    private Long testStandardId;
    @TableField(exist = false)
    private String workOrderNo;
    @TableField(exist = false)
    private String purchaseContractNo;
}
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
@@ -37,7 +37,7 @@
    /**
     * 客户合同号
     */
    @Excel(name = "客户合同号")
    @Excel(name = "客户合同号", type = Excel.Type.IMPORT)
    private String customerContractNo;
@@ -139,5 +139,9 @@
    @TableField(exist = false)
    @ApiModelProperty(value = "交货天数差")
    private Integer deliveryDaysDiff;
    @TableField(exist = false)
    //是否发货(台账页面颜色控制)
    private Boolean isFh;
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -15,6 +15,7 @@
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.impl.SalesLedgerProductionAccountingServiceImpl;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.quality.mapper.QualityInspectMapper;
@@ -92,6 +93,8 @@
    private ProductStructureMapper productStructureMapper;
    @Autowired
    private StockInventoryMapper stockInventoryMapper;
    @Autowired
    private SalesLedgerProductionAccountingServiceImpl salesLedgerProductionAccountingServiceImpl;
    @Override
    public SalesLedgerProduct selectSalesLedgerProductById(Long id) {
@@ -228,9 +231,7 @@
            /*删除对应的生产数据并重新新增*/
            deleteProductionData(Arrays.asList(salesLedgerProduct.getId()));
            // 删除生产核算数据
            LambdaQueryWrapper<SalesLedgerProductionAccounting> reportWrapper = new LambdaQueryWrapper<>();
            reportWrapper.in(SalesLedgerProductionAccounting::getSalesLedgerId, salesLedgerId);
            salesLedgerProductionAccountingMapper.delete(reportWrapper);
            addProductionData(salesLedgerProduct);
        }
@@ -407,6 +408,8 @@
                            }
                        });
                        qualityInspectMapper.deleteByProductMainIds(productMainIds);
                        salesLedgerProductionAccountingMapper.delete(new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                                .in(SalesLedgerProductionAccounting::getProductMainId, productMainIds));
                    }
                    // 删除生产主表数据
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -25,6 +25,8 @@
import com.ruoyi.other.pojo.TempFile;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProductionProductMainService;
import com.ruoyi.production.service.impl.ProductionProductMainServiceImpl;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysDeptMapper;
@@ -146,7 +148,9 @@
    private ProductMapper productMapper;
    @Autowired
    private ProductStructureMapper productStructureMapper;
;
    @Autowired
    private ProductionProductMainService productionProductMainService;
    ;
    @Override
    public List<SalesLedger> selectSalesLedgerList(SalesLedgerDto salesLedgerDto) {
@@ -178,7 +182,7 @@
                    .eq(ShippingInfo::getSalesLedgerProductId, product.getId())
                    .orderByDesc(ShippingInfo::getCreateTime)
                    .last("limit 1"));
            if(shippingInfo != null){
            if (shippingInfo != null) {
                product.setShippingStatus(shippingInfo.getStatus());
            }
        }
@@ -350,7 +354,7 @@
//            // 产品大类数据
//            List<Product> productList = productMapper.selectList(new LambdaQueryWrapper<Product>().in(Product::getProductName,
//                    salesLedgerProductImportDtoList.stream().map(SalesLedgerImportDto::getProductCategory).collect(Collectors.toList())));
            List<Map<String,Object>> list = productModelMapper.getProductAndModelList();
            List<Map<String, Object>> list = productModelMapper.getProductAndModelList();
            // 录入人数据
            List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getNickName,
                    salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getEntryPerson).collect(Collectors.toList())));
@@ -358,7 +362,7 @@
                SalesLedger salesLedger1 = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>()
                        .eq(SalesLedger::getSalesContractNo, salesLedgerImportDto.getSalesContractNo())
                        .last("LIMIT 1"));
                if(salesLedger1 != null){
                if (salesLedger1 != null) {
                    continue;
                }
                SalesLedger salesLedger = new SalesLedger();
@@ -391,7 +395,7 @@
                    throw new RuntimeException("销售单号:" + salesLedgerImportDto.getSalesContractNo() + ",无对应产品数据!");
                salesLedger.setContractAmount(salesLedgerProductImportDtos.stream()
                        .map(SalesLedgerProductImportDto::getTaxInclusiveTotalPrice)
                        .reduce(BigDecimal.ZERO,BigDecimal::add));
                        .reduce(BigDecimal.ZERO, BigDecimal::add));
                salesLedgerMapper.insert(salesLedger);
@@ -426,6 +430,8 @@
                    salesLedgerProduct.setApproveStatus(0);
                    salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProductImportDto.getTaxInclusiveTotalPrice());
                    salesLedgerProductMapper.insert(salesLedgerProduct);
                    // 添加生产数据
                    salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct);
                }
            }
@@ -551,25 +557,20 @@
        // 删除发货台账记录
        List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
                .in(ShippingInfo::getSalesLedgerId, idList));
        if(CollectionUtils.isNotEmpty(shippingInfos)){
        if (CollectionUtils.isNotEmpty(shippingInfos)) {
            shippingInfoServiceImpl.delete(shippingInfos.stream().map(ShippingInfo::getId).collect(Collectors.toList()));
        }
        // 删除附件表
        commonFileService.deleteByBusinessIds(idList, FileNameType.SALE.getValue());
        // 删除生产管控数据
        // 删除生产订单数据
        LambdaQueryWrapper<SalesLedgerScheduling> in = new LambdaQueryWrapper<SalesLedgerScheduling>()
                .in(SalesLedgerScheduling::getSalesLedgerId, idList);
        salesLedgerSchedulingMapper.delete(in);
        // 删除生产派工数据
        LambdaQueryWrapper<SalesLedgerWork> workOrderWrapper = new LambdaQueryWrapper<>();
        workOrderWrapper.in(SalesLedgerWork::getSalesLedgerId, idList);
        salesLedgerWorkMapper.delete(workOrderWrapper);
        // 删除生产核算数据
        LambdaQueryWrapper<SalesLedgerProductionAccounting> reportWrapper = new LambdaQueryWrapper<>();
        reportWrapper.in(SalesLedgerProductionAccounting::getSalesLedgerId, idList);
        salesLedgerProductionAccountingMapper.delete(reportWrapper);
        //查询生产报工id
        ArrayList<Long> mainIdList = productionProductMainService.listMain(idList);
        if (CollectionUtils.isNotEmpty(mainIdList)) {
            mainIdList.stream().forEach(mainId -> {
                productionProductMainService.removeProductMain(mainId);
            });
        }
        // 2. 再删除主表数据
        return salesLedgerMapper.deleteBatchIds(idList);
    }
src/main/resources/application-new.yml
@@ -13,7 +13,8 @@
  addressEnabled: false
  # 验证码类型 math 数字计算 char 字符验证
  captchaType: math
  # 协同审批编号前缀(配置文件后缀命名)
  approvalNumberPrefix: NEW
# 开发环境配置
server:
  # 服务器的HTTP端口,默认为8080
src/main/resources/mapper/production/ProductOrderMapper.xml
@@ -23,9 +23,21 @@
        pb.bom_no,
        ROUND(po.complete_quantity / po.quantity * 100, 2) AS completionStatus,
        DATEDIFF(sl.delivery_date, CURDATE()) AS delivery_days_diff,
        sl.delivery_date
        sl.delivery_date,
        CASE
        WHEN shipping_status_counts.total_count = 0 THEN false
        WHEN shipping_status_counts.unshipped_count = 0 THEN true
        ELSE false
        END AS is_fh
        from product_order po
        left join sales_ledger sl on po.sales_ledger_id = sl.id
        LEFT JOIN (
        SELECT sales_ledger_id,
        COUNT(*) as total_count,
        SUM(CASE WHEN status != '已发货' THEN 1 ELSE 0 END) as unshipped_count
        FROM shipping_info
        GROUP BY sales_ledger_id
        ) shipping_status_counts ON sl.id = shipping_status_counts.sales_ledger_id
        left join sales_ledger_product slp on po.sale_ledger_product_id = slp.id
        left join product_process_route ppr on po.id = ppr.product_order_id
        left join product_bom pb on pb.id = ppr.bom_id
@@ -50,23 +62,11 @@
            </if>
        </where>
    </select>
    <select id="productMainByOrderId" resultType="com.ruoyi.production.dto.ProductOrderDto">
        select po.*,
               pwo.work_order_no,
               pwo.report_work,
               pwo.status,
               pwo.quantity,
               pwo.plan_quantity
        from product_order po
                 left join product_work_order pwo on po.id = pwo.product_order_id
        where po.id = #{c.id}
    </select>
    <select id="listProcessRoute" resultType="com.ruoyi.production.pojo.ProcessRoute">
        select pr.*
        from process_route pr
                 left join product_model pm on pr.product_model_id = pm.id
                 left join sales_ledger_product slp on pm.id = slp.product_model_id
        where slp.id = #{productModelId}
        where pm.id = #{productModelId}
    </select>
    <select id="listProcessBom" resultType="com.ruoyi.production.dto.ProductStructureDto">
        select ps.id,
src/main/resources/mapper/production/ProductionProductMainMapper.xml
@@ -71,7 +71,7 @@
        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 sales_ledger_production_accounting slpa ON slpa.product_main_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
@@ -93,6 +93,20 @@
            </if>
        </where>
    </select>
    <select id="listMain" resultType="java.lang.Long">
        SELECT ppm.id 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 sales_ledger sl on sl.id = po.sales_ledger_id
        <where>
            <if test="idList != null and idList.size() > 0">
                and sl.id in
                <foreach item="id" collection="idList" open="(" separator="," close=")">
                    #{id}
                </foreach>
            </if>
        </where>
    </select>
    <delete id="deleteByWorkOrderIds" parameterType="java.util.List">
        DELETE FROM production_product_main
src/main/resources/mapper/production/SalesLedgerProductionAccountingMapper.xml
@@ -68,7 +68,7 @@
        '%'
        ) 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_main ppm ON slpa.product_main_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 !=''">
src/main/resources/mapper/purchase/PaymentRegistrationMapper.xml
@@ -199,6 +199,7 @@
        </where>
        GROUP BY T1.supplier_name
    </select>
    <select id="supplierNameListPageDetails" resultType="com.ruoyi.purchase.dto.PaymentRegistrationDto">
        SELECT
        T1.supplier_id,
@@ -209,7 +210,7 @@
        T1.purchase_contract_number,
        T2.payment_date
        FROM purchase_ledger T1
        LEFT JOIN payment_registration T2 ON T1.id = T2.purchase_ledger_id
        INNER JOIN payment_registration T2 ON T1.id = T2.purchase_ledger_id
        <where>
            T1.supplier_id = #{req.supplierId}
            <if test="req.supplierName != null and req.supplierName != '' ">
src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
@@ -28,7 +28,8 @@
        pl.approve_user_ids,
        sm.is_white,
        pl.approval_status,
        pl.payment_method
        pl.payment_method,
        pl.remarks
        from purchase_ledger pl
        left join sales_ledger_product slp on slp.sales_ledger_id = pl.id and slp.type=2
        left join product_record pr on pl.id = pr.purchase_ledger_id
src/main/resources/mapper/quality/QualityInspectMapper.xml
@@ -3,30 +3,49 @@
<mapper namespace="com.ruoyi.quality.mapper.QualityInspectMapper">
    <select id="qualityInspectListPage" resultType="com.ruoyi.quality.pojo.QualityInspect">
        SELECT
        *
        FROM quality_inspect
        where
        qi.*,
        <choose>
            <when test="qualityInspect.inspectType == 0">
                pl.purchase_contract_number as purchase_contract_no
            </when>
            <otherwise>
                pwo.work_order_no
            </otherwise>
        </choose>
        FROM
        quality_inspect qi
        <choose>
            <when test="qualityInspect.inspectType == 0 ">
                LEFT JOIN purchase_ledger pl ON pl.id = qi.purchase_ledger_id
            </when>
            <otherwise>
                LEFT JOIN production_product_main ppm ON qi.product_main_id = ppm.id
                LEFT JOIN product_work_order pwo ON ppm.work_order_id = pwo.id
            </otherwise>
        </choose>
        WHERE
        inspect_type=#{qualityInspect.inspectType}
        <if test="qualityInspect.supplier != null and qualityInspect.supplier != '' ">
            AND supplier like concat('%',#{qualityInspect.supplier},'%')
            AND qi.supplier like concat('%',#{qualityInspect.supplier},'%')
        </if>
        <if test="qualityInspect.customer != null and qualityInspect.customer != '' ">
            AND customer like concat('%',#{qualityInspect.customer},'%')
            AND qi.customer like concat('%',#{qualityInspect.customer},'%')
        </if>
        <if test="qualityInspect.process != null and qualityInspect.process != '' ">
            AND process like concat('%',#{qualityInspect.process},'%')
            AND qi.process like concat('%',#{qualityInspect.process},'%')
        </if>
        <if test="qualityInspect.productName != null and qualityInspect.productName != '' ">
            AND product_name like concat('%',#{qualityInspect.productName},'%')
            AND qi.product_name like concat('%',#{qualityInspect.productName},'%')
        </if>
        <if test="qualityInspect.entryDateStart != null and qualityInspect.entryDateStart != '' ">
            AND check_time &gt;= DATE_FORMAT(#{qualityInspect.entryDateStart},'%Y-%m-%d')
            AND qi.check_time &gt;= DATE_FORMAT(#{qualityInspect.entryDateStart},'%Y-%m-%d')
        </if>
        <if test="qualityInspect.entryDateEnd != null and qualityInspect.entryDateEnd != '' ">
            AND check_time &lt;= DATE_FORMAT(#{qualityInspect.entryDateEnd},'%Y-%m-%d')
            AND qi.check_time &lt;= DATE_FORMAT(#{qualityInspect.entryDateEnd},'%Y-%m-%d')
        </if>
        ORDER BY check_time DESC
        ORDER BY qi.check_time DESC
    </select>
    <select id="qualityInspectExport" resultType="com.ruoyi.quality.pojo.QualityInspect">
        SELECT
        *
src/main/resources/mapper/sales/ReceiptPaymentMapper.xml
@@ -432,22 +432,23 @@
        </where>
    </select>
    <select id="invoiceLedgerSalesAccount" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto">
        SELECT
        T1.sales_contract_no,
        SUM(contract_amount) AS invoice_total,
        IFNULL( SUM(T2.receipt_payment_amount) , 0 ) AS receipt_payment_amount,
        IFNULL((IFNULL(SUM(contract_amount),0)  - IFNULL(SUM(T2.receipt_payment_amount),0)),0) AS unReceipt_payment_amount,
        T1.contract_amount AS invoice_total,
        IFNULL(SUM(T2.receipt_payment_amount), 0) AS receipt_payment_amount,
        IFNULL((T1.contract_amount - IFNULL(SUM(T2.receipt_payment_amount), 0)), 0) AS unReceipt_payment_amount,
        T2.receipt_payment_date
        FROM sales_ledger T1
        LEFT JOIN receipt_payment T2 ON T1.id = T2.sales_ledger_id
        INNER JOIN receipt_payment T2 ON T1.id = T2.sales_ledger_id
        <where>
            T1.customer_id = #{invoiceLedgerDto.customerId}
            <if test="invoiceLedgerDto.searchText != null and invoiceLedgerDto.searchText != '' ">
                T1.customer_name LIKE CONCAT ('%',#{invoiceLedgerDto.searchText},'%')
                AND T1.customer_name LIKE CONCAT ('%', #{invoiceLedgerDto.searchText}, '%')
            </if>
        </where>
        GROUP BY T1.sales_contract_no,T2.receipt_payment_date
        GROUP BY T1.id, T1.sales_contract_no, T1.contract_amount, T2.receipt_payment_date
    </select>
</mapper>
src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -43,8 +43,7 @@
    </select>
    <select id="selectSalesLedgerListPage" resultType="com.ruoyi.sales.pojo.SalesLedger">
        SELECT
        T1.id,
        SELECT T1.id,
        T1.sales_contract_no,
        T1.customer_contract_no,
        T1.project_name,
@@ -57,15 +56,26 @@
        T1.attachment_materials,
        T1.tenant_id,
        T1.contract_amount,
        T1.contract_amount as noInvoiceAmountTotal,
        T1.contract_amount                    as noInvoiceAmountTotal,
        T1.execution_date,
        T2.nick_name AS entry_person_name,
        T2.nick_name                          AS entry_person_name,
        T1.payment_method,
        T1.delivery_date,
        DATEDIFF(T1.delivery_date, CURDATE()) AS delivery_days_diff
        FROM
        sales_ledger T1
        DATEDIFF(T1.delivery_date, CURDATE()) AS delivery_days_diff,
        CASE
        WHEN shipping_status_counts.total_count = 0 THEN false
        WHEN shipping_status_counts.unshipped_count = 0 THEN true
        ELSE false
        END AS is_fh
        FROM sales_ledger T1
        LEFT JOIN sys_user T2 ON T1.entry_person = T2.user_id
        LEFT JOIN (
        SELECT sales_ledger_id,
        COUNT(*) as total_count,
        SUM(CASE WHEN status != '已发货' THEN 1 ELSE 0 END) as unshipped_count
        FROM shipping_info
        GROUP BY sales_ledger_id
        ) shipping_status_counts ON T1.id = shipping_status_counts.sales_ledger_id
        <where>
            <if test="salesLedgerDto.customerName != null and salesLedgerDto.customerName != '' ">
                AND  T1.customer_name LIKE CONCAT('%',#{salesLedgerDto.customerName},'%')