liyong
2026-04-21 03ffc2598a261d1dc19e77b559268bb84032a389
feat(approve): 新增销售审批功能并优化审批流程

- 添加销售审批类型(类型9)和自由协同审批类型(类型10)
- 实现销售审批流程的状态更新逻辑(同意、拒绝、审核中)
- 新增流程状态详情接口 /salesDetails/{id} 用于查询审批节点详情
- 在ApproveGetAndUpdateVo中添加审批标题字段
- 优化ApproveNodeServiceImpl中的销售详情查询逻辑
- 修复销售台账审批状态更新问题
- 重构部分代码结构,使用更简洁的导入方式
- 添加销售台账查询接口,支持按合同号查询销售台账及产品信息
- 实现超过15天未回款提醒功能
- 优化多个mapper文件中的SQL查询语句
- 更新供应商管理相关DTO,统一使用SupplierManageDto
- 添加产品型号的单价和库存预警值字段
- 优化生产工单查询的排序和筛选条件
已修改57个文件
717 ■■■■ 文件已修改
src/main/java/com/ruoyi/approve/controller/ApproveNodeController.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/IApproveNodeService.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/IApproveProcessService.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java 75 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/vo/ApproveGetAndUpdateVo.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/SupplierManageController.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/dto/SupplierManageDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/ProductModel.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/SupplierManage.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/ISupplierService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/controller/HomeController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/HomeService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductWorkOrder.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/dto/InvoicePurchaseReportDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesQuotationController.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/ReceiptPaymentDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesLedgerDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesLedgerProductDto.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesQuotationProduct.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/SalesQuotationService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 140 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/pojo/StaffLeave.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/pojo/StaffOnJob.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/impl/StaffLeaveServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/controller/StockInRecordController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/StockInRecordService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/CustomerPrivatePoolMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/device/DeviceMaintenanceMapper.xml 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductWorkOrderMapper.xml 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/purchase/InvoicePurchaseMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/purchase/ProductRecordMapper.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/InvoiceRegistrationProductMapper.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/ReceiptPaymentMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/staff/StaffOnJobMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockInRecordMapper.xml 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockOutRecordMapper.xml 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/ApproveNodeController.java
@@ -53,4 +53,16 @@
        return AjaxResult.success();
    }
    /**
     * 流程状态详情
     * @param id 流程审批id approve_id
     * @return
     */
    @GetMapping("/salesDetails/{id}")
    @ApiOperation(value = "流程状态详情")
    public AjaxResult salesDetails(@PathVariable String id) {
        return AjaxResult.success(approveNodeService.salesDetails(id));
    }
}
src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java
@@ -178,4 +178,8 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty("审批标题")
    @Excel(name = "审批标题")
    private String approveTitle;
}
src/main/java/com/ruoyi/approve/service/IApproveNodeService.java
@@ -17,5 +17,7 @@
    void updateApproveNode(ApproveNode approveNode) throws IOException;
    void delApproveNodeByApproveId(String id);
    void delApproveNodeByApproveId(Long id);
    List<ApproveNode> salesDetails(String id);
}
src/main/java/com/ruoyi/approve/service/IApproveProcessService.java
@@ -33,4 +33,5 @@
    ApproveProcess getApproveById(String id);
    void delByIds(List<Long> longs);
}
src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
@@ -26,10 +26,7 @@
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.purchase.service.impl.PurchaseLedgerServiceImpl;
import com.ruoyi.sales.mapper.*;
import com.ruoyi.sales.pojo.CommonFile;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.SalesQuotation;
import com.ruoyi.sales.pojo.ShippingInfo;
import com.ruoyi.sales.pojo.*;
import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -37,10 +34,7 @@
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.*;
@Service
//@RequiredArgsConstructor
@@ -81,6 +75,9 @@
    @Autowired
    private PurchaseLedgerServiceImpl purchaseLedgerServiceImpl;
    @Autowired
    private SalesLedgerMapper salesLedgerMapper;
    public ApproveProcess getApproveById(String id) {
@@ -232,6 +229,28 @@
            }
            salesQuotationMapper.updateById(salesQuote);
        }
        //销售审批
        if(approveProcess.getApproveType().equals(9)){
            SalesLedger salesLedger = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>()
                    .eq(SalesLedger::getSalesContractNo, approveProcess.getApproveReason())
                    .last("limit 1"));
            if(salesLedger != null) {
                if (status.equals(2)) {
                    // 同意
                    salesLedger.setApprovalStatus(3);
                } else if (status.equals(3)) {
                    // 拒绝
                    salesLedger.setApprovalStatus(4);
                } else if (status.equals(1)) {
                    // 审核中
                    salesLedger.setApprovalStatus(2);
                }
                salesLedgerMapper.updateById(salesLedger);
            }
        }
        // 出库审批修改
        if(approveProcess.getApproveType().equals(7)){
            String[] split = approveProcess.getApproveReason().split(":");
@@ -293,7 +312,7 @@
    }
    @Override
    public void delApproveNodeByApproveId(String id) {
    public void delApproveNodeByApproveId(Long id) {
        List<ApproveNode> approveNodes = approveNodeMapper.selectList(new LambdaQueryWrapper<ApproveNode>()
                .eq(ApproveNode::getApproveProcessId, id));
        UpdateWrapper<ApproveNode> queryWrapper = new UpdateWrapper<>();
@@ -304,6 +323,40 @@
        for (ApproveNode approveNode : approveNodes) {
            commonFileService.deleteByBusinessId(approveNode.getId(), FileNameType.ApproveNode.getValue());
        }
    }
    @Override
    public List<ApproveNode> salesDetails(String id) {
        LambdaQueryWrapper<ApproveNode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ApproveNode::getApproveProcessId, id);
        queryWrapper.eq(ApproveNode::getDeleteFlag, 0);
//        queryWrapper.eq(ApproveNode::getTenantId, SecurityUtils.getLoginUser().getTenantId());
        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::getTenantId, SecurityUtils.getLoginUser().getTenantId())
                .last("limit 1");
        ApproveProcess approveProcess = approveProcessMapper.selectOne(approveProcessLambdaQueryWrapper);
        if(approveProcess != null && approveProcess.getApproveStatus() == 3){
            return list;
        }
        for (ApproveNode approveNode : list) {
            List<CommonFile> commonFiles = fileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
                    .eq(CommonFile::getCommonId, approveNode.getId())
                    .eq(CommonFile::getType, FileNameType.ApproveNode.getValue()));
            if(!CollectionUtils.isEmpty(commonFiles)){
                approveNode.setUrl(commonFiles.get(0).getUrl());
            }
            if(approveNode.getApproveNodeStatus() == 1){
                continue;
            }
            approveNode.setIsShen(true);
            break;
        }
        return list;
    }
    //审批类型获取(与前端页面对应)
@@ -325,6 +378,10 @@
                return "发货审批";
            case 8:
                return "危险作业审批";
            case 9:
                return "销售审批";
            case 10:
                return "自由协同审批";
        }
        return null;
    }
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -120,6 +121,7 @@
        approveProcess.setTenantId(approveProcessVO.getApproveDeptId());
        approveProcess.setApproveUserIds(approveProcessVO.getApproveUserIds());
        approveProcess.setApproveUserCurrentId(longList.get(0));
        approveProcess.setApproveTitle(ObjectUtils.isNotEmpty(approveProcessVO.getApproveTitle()) ? approveProcessVO.getApproveTitle() : "");
        approveProcess.setApproveUserCurrentName(sysUsers
                .stream()
                .filter(SysUser -> SysUser.getUserId().equals(longList.get(0)))
@@ -221,20 +223,19 @@
        return approveProcessIPage;
    }
    public void delByIds(List<Long> ids) {
        for (Long approveId : ids) {
    @Override
    public void delByIds(List<Long> longs) {
        ApproveProcess approveProcess;
        for (Long approveId : longs) {
            //  逻辑删除审批流程
            update(new UpdateWrapper<ApproveProcess>()
                    .lambda()
                    .set(ApproveProcess::getApproveDelete, 1)
                    .eq(ApproveProcess::getId, approveId));
            // 删除对应的附件
            commonFileService.deleteByBusinessId(approveId, FileNameType.ApproveProcess.getValue());
            ApproveProcess approveProcess = approveProcessMapper.selectById(approveId);
                    .eq(ApproveProcess::getApproveId, approveId));
            //  删除审批节点
            approveNodeService.delApproveNodeByApproveId(approveProcess.getApproveId());
            approveNodeService.delApproveNodeByApproveId(approveId);
            //  只查最新一条审批流程
            ApproveProcess latestProcess = approveProcessMapper.selectOne(
@@ -247,14 +248,12 @@
                continue;
            }
            //  删除对应的消息通知
            sysNoticeService.remove(new LambdaQueryWrapper<SysNotice>()
                    .eq(SysNotice::getNoticeTitle, approveProcessType(latestProcess.getApproveType()))
                    .eq(SysNotice::getSenderId, latestProcess.getApproveUser())
                    .apply("CAST(notice_content AS CHAR) LIKE CONCAT('%', {0}, '%')", latestProcess.getApproveId()));
        }
    }
    @Override
@@ -272,7 +271,7 @@
            // 删除对应的附件
            commonFileService.deleteByBusinessId(approveProcess.getId(), FileNameType.ApproveProcess.getValue());
            //  删除审批节点
            approveNodeService.delApproveNodeByApproveId(approveId.toString());
            approveNodeService.delApproveNodeByApproveId(approveId);
            //  只查最新一条审批流程
            ApproveProcess latestProcess = approveProcessMapper.selectOne(
@@ -373,9 +372,11 @@
        if (sysUser == null) throw new RuntimeException("申请人不存在");
        approve.setApproveUserName(sysUser.getNickName());
        approve.setApproveUser(sysUser.getUserId());
        approve.setApproveTitle(approveGetAndUpdateVo.getApproveTitle());
        //审核中不可以编辑审核人
        if (approve.getApproveStatus() != 1) {
            approve.setApproveUserCurrentId(Long.parseLong(split[0]));
            approve.setApproveUserCurrentName(sysUsers.stream().filter(user -> user.getUserId().equals(Long.parseLong(split[0]))).collect(Collectors.toList()).get(0).getNickName());
        }
        updateById(approve);
@@ -442,6 +443,10 @@
                return "发货审批";
            case 8:
                return "危险作业审批";
            case 9:
                return "销售审批";
            case 10:
                return "自由协同审批";
        }
        return null;
    }
src/main/java/com/ruoyi/approve/vo/ApproveGetAndUpdateVo.java
@@ -52,4 +52,5 @@
     * 审批类型
     */
    private Integer approveType;
    private String approveTitle;
}
src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java
@@ -75,4 +75,6 @@
     * 报修金额
     */
    private BigDecimal maintenancePrice;
    private String approveTitle;
}
src/main/java/com/ruoyi/basic/controller/SupplierManageController.java
@@ -1,5 +1,6 @@
package com.ruoyi.basic.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.dto.SupplierManageDto;
import com.ruoyi.basic.pojo.Customer;
@@ -9,6 +10,10 @@
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.purchase.dto.PurchaseLedgerDto;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.purchase.service.IPurchaseLedgerService;
import com.ruoyi.purchase.service.impl.PurchaseLedgerServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
@@ -23,6 +28,8 @@
    @Autowired
    private ISupplierService supplierService;
    @Autowired
    private IPurchaseLedgerService purchaseLedgerService;
    /**
     * 供应商新增
@@ -30,7 +37,7 @@
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody SupplierManage supplierManage) {
    public AjaxResult add(@RequestBody SupplierManageDto supplierManage) {
        supplierService.saveSupplier(supplierManage);
        return AjaxResult.success();
    }
@@ -65,7 +72,7 @@
     * @return
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestBody SupplierManage supplierManage) {
    public AjaxResult update(@RequestBody SupplierManageDto supplierManage) {
        supplierService.supplierUpdate(supplierManage);
        return AjaxResult.success();
    }
src/main/java/com/ruoyi/basic/dto/SupplierManageDto.java
@@ -9,4 +9,8 @@
    @ApiModelProperty(value = "维护人员名称")
    private String maintainUserName;
    @ApiModelProperty(value = "供应商产品ID集合")
    private Long producutId;
}
src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -74,4 +74,13 @@
    @ApiModelProperty("顶部父产品id")
    @TableField(exist = false)
    private Long topProductParentId;
    @ApiModelProperty(value = "单价")
    @Excel(name = "单价")
    private BigDecimal price;
    @ApiModelProperty(value = "库存预警值")
    @Excel(name = "库存预警值")
    private BigDecimal stockWarningValue;
}
src/main/java/com/ruoyi/basic/pojo/SupplierManage.java
@@ -86,4 +86,8 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty("供应产品")
    private String supplyProduct;
}
src/main/java/com/ruoyi/basic/service/ISupplierService.java
@@ -5,7 +5,6 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.basic.dto.SupplierManageDto;
import com.ruoyi.basic.pojo.SupplierManage;
import com.ruoyi.framework.web.domain.AjaxResult;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
@@ -18,7 +17,7 @@
     * @param supplierManage
     * @return
     */
    void saveSupplier(SupplierManage supplierManage);
    void saveSupplier(SupplierManageDto supplierManage);
    /**
     * 供应商删除
@@ -32,14 +31,14 @@
     * @param id
     * @return
     */
    SupplierManage supplierDetail(Integer id);
    SupplierManageDto supplierDetail(Integer id);
    /**
     * 供应商修改
     * @param supplierManage
     * @return
     */
    int supplierUpdate(SupplierManage supplierManage);
    int supplierUpdate(SupplierManageDto supplierManage);
    /**
     * 供应商分页查询
src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java
@@ -7,15 +7,16 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.dto.SupplierManageDto;
import com.ruoyi.basic.excel.SupplierManageExcelDto;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.mapper.SupplierManageMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.pojo.SupplierManage;
import com.ruoyi.basic.service.ISupplierService;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -24,7 +25,9 @@
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class SupplierServiceImpl extends ServiceImpl<SupplierManageMapper,SupplierManage> implements ISupplierService {
@@ -33,6 +36,8 @@
    private SupplierManageMapper supplierMapper;
    @Autowired
    private PurchaseLedgerMapper purchaseLedgerMapper;
    @Autowired
    private ProductModelMapper productModelMapper;
    /**
     * 供应商新增
@@ -40,7 +45,7 @@
     * @return
     */
    @Override
    public void saveSupplier(SupplierManage supplierManage) {
    public void saveSupplier(SupplierManageDto supplierManage) {
        LambdaQueryWrapper<SupplierManage> supplierManageLambdaQueryWrapper = new LambdaQueryWrapper<>();
        supplierManageLambdaQueryWrapper.eq(SupplierManage::getSupplierName,supplierManage.getSupplierName());
        if (supplierMapper.selectCount(supplierManageLambdaQueryWrapper) > 0) {
@@ -72,8 +77,15 @@
     * @return
     */
    @Override
    public SupplierManage supplierDetail(Integer id) {
        return supplierMapper.selectById(id);
    public SupplierManageDto supplierDetail(Integer id) {
        SupplierManage supplierManage = supplierMapper.selectById(id);
        SupplierManageDto supplierManageDto = new SupplierManageDto();
        BeanUtils.copyProperties(supplierManage,supplierManageDto);
        ProductModel productModel = productModelMapper.selectById(supplierManage.getSupplyProduct());
        if(productModel != null) {
            supplierManageDto.setProducutId(productModel.getProductId());
        }
        return supplierManageDto;
    }
    /**
@@ -82,7 +94,7 @@
     * @return
     */
    @Override
    public int supplierUpdate(SupplierManage supplierManage) {
    public int supplierUpdate(SupplierManageDto supplierManage) {
        return supplierMapper.updateById(supplierManage);
    }
src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java
@@ -11,41 +11,12 @@
@Data
public class DeviceMaintenanceDto extends DeviceMaintenance {
    @ApiModelProperty("计划保养日期")
    private String maintenancePlanTimeReq;
    @ApiModelProperty("设备保养id")
    private Long id;
    @ApiModelProperty("设备台账id")
    private Long deviceLedgerId;
    @ApiModelProperty("设备名称")
    private String deviceName;
    @ApiModelProperty("规格型号")
    private String deviceModel;
    @ApiModelProperty("实际保养人")
    private String maintenanceActuallyName;
    @ApiModelProperty("保养结果 0 维修 1 完好")
    private String maintenanceResult;
    @ApiModelProperty("状态 0 待保养 1 完结 2 失败")
    private Integer status;
    @ApiModelProperty("创建时间")
    private LocalDateTime createTime;
    @ApiModelProperty("更新时间")
    private LocalDateTime updateTime;
    @ApiModelProperty("更新人")
    private String updateUserName;
    @ApiModelProperty("租户id")
    private Long tenantId;
    @ApiModelProperty("实际保养日期")
    private String maintenanceActuallyTimeReq;
    @ApiModelProperty("创建人名称")
    private String createUserName;
}
src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java
@@ -104,4 +104,11 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty("保养项目")
    private String maintenanceProject;
    @ApiModelProperty("保养内容")
    private String maintenanceContent;
}
src/main/java/com/ruoyi/home/controller/HomeController.java
@@ -321,4 +321,11 @@
        return AjaxResult.success(list);
    }
    @ApiOperation("超过15天待回款提示")
    @GetMapping("/overdueReceivable")
    public AjaxResult overdueReceivable() {
        return AjaxResult.success(homeService.overdueReceivable());
    }
}
src/main/java/com/ruoyi/home/service/HomeService.java
@@ -95,4 +95,7 @@
    QualityStatisticsDto qualityInspectionStatistics(Integer type);
    List<processDataProductionStatisticsDto> processDataProductionStatistics(Integer type, List<Long> processIds);
    Long overdueReceivable();
}
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.mapper.AccountIncomeMapper;
@@ -51,12 +52,14 @@
import com.ruoyi.quality.mapper.QualityUnqualifiedMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityUnqualified;
import com.ruoyi.sales.dto.ReceiptPaymentDto;
import com.ruoyi.sales.mapper.ReceiptPaymentMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.ReceiptPayment;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.service.impl.ReceiptPaymentServiceImpl;
import com.ruoyi.staff.mapper.StaffOnJobMapper;
import com.ruoyi.staff.pojo.StaffOnJob;
import com.ruoyi.stock.mapper.StockInventoryMapper;
@@ -2512,4 +2515,19 @@
        return productProcessMapper.calculateProductionStatistics(startDateTime, endDateTime, userId, processIds);
    }
    @Autowired
    private ReceiptPaymentServiceImpl receiptPaymentService;
    @Override
    public Long overdueReceivable() {
        // 通过登记日期超过15天的未回款提示
        LambdaQueryWrapper<SalesLedgerProduct> lambdaWrapper = new LambdaQueryWrapper<>();
        // 时间条件:registerDate < 当前时间 - 15天
        lambdaWrapper.apply("register_date < DATE_SUB(NOW(), INTERVAL 15 DAY)");
        // 未回款条件:pendingInvoiceTotal > 0
        lambdaWrapper.gt(SalesLedgerProduct::getPendingInvoiceTotal, 0);
        return salesLedgerProductMapper.selectCount(lambdaWrapper);
    }
}
src/main/java/com/ruoyi/production/pojo/ProductWorkOrder.java
@@ -28,6 +28,20 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 用户id
     */
    @ApiModelProperty(value = "用户id")
    private Long userId;
    /**
     * 用户昵称
     */
    @ApiModelProperty(value = "用户昵称")
    @Excel(name = "用户昵称")
    private String nickName;
    /**
     * 工艺路线项目id
     */
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
@@ -17,6 +17,7 @@
import com.ruoyi.purchase.pojo.PurchaseLedgerTemplate;
import com.ruoyi.purchase.pojo.SalesLedgerProductTemplate;
import com.ruoyi.purchase.service.IPurchaseLedgerService;
import com.ruoyi.sales.dto.SalesLedgerDto;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.service.ISalesLedgerProductService;
import com.ruoyi.sales.service.ISalesLedgerService;
@@ -196,6 +197,16 @@
        return purchaseLedgerService.getPurchaseByCode(purchaseLedgerDto);
    }
    /**
     * 查询采购台账和产品父子列表
     */
    @GetMapping("/getSalesByCode")
    public SalesLedgerDto getSalesByCode(SalesLedgerDto salesLedgerDto) {
        return salesLedgerService.getSalesByCode(salesLedgerDto);
    }
    /**
     * 删除采购台账
     */
src/main/java/com/ruoyi/purchase/dto/InvoicePurchaseReportDto.java
@@ -12,6 +12,10 @@
    //销售合同号
    @Excel(name = "销售合同号")
    private String customerContractNo;
    //采购合同号
    @Excel(name = "采购合同号")
    private String purchaseContractNumber;
//    客户名称
    @Excel(name = "客户名称")
    private String customerName;
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -207,7 +207,7 @@
            }
            purchaseLedgerMapper.updateById(purchaseLedger);
        }
        // 6.采购审核新增
        addApproveByPurchase(loginUser, purchaseLedger);
        // 4. 处理子表数据
@@ -224,6 +224,8 @@
//                }
//            }
//        }
        purchaseLedger.setApprovalStatus(1);
        this.updateById(purchaseLedger);
        // 5. 迁移临时文件到正式目录
        if (purchaseLedgerDto.getTempFileIds() != null && !purchaseLedgerDto.getTempFileIds().isEmpty()) {
            migrateTempFilesToFormal(purchaseLedger.getId(), purchaseLedgerDto.getTempFileIds());
src/main/java/com/ruoyi/sales/controller/SalesQuotationController.java
@@ -5,11 +5,14 @@
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.sales.dto.SalesQuotationDto;
import com.ruoyi.sales.service.SalesQuotationService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/sales/quotation")
@@ -28,7 +31,7 @@
        SalesQuotationDto afterSalesService = new SalesQuotationDto();
        IPage<SalesQuotationDto> listPage = salesQuotationService.listPage(page, afterSalesService);
        ExcelUtil<SalesQuotationDto> util = new ExcelUtil<SalesQuotationDto>(SalesQuotationDto.class);
        util.exportExcel(response, listPage.getRecords() , "销售报价");
        util.exportExcel(response, listPage.getRecords() , "反馈登记");
    }
@@ -40,6 +43,21 @@
    public AjaxResult update(@RequestBody SalesQuotationDto salesQuotationDto) {
        return AjaxResult.success(salesQuotationService.edit(salesQuotationDto));
    }
    /**
     * 详情   根据客户类型和产品返回报价单价
     * @param type   客户类型
     * @param productName 产品名称
     * @param specification  规格
     * @return
     */
    @ApiOperation("详情")
    @GetMapping("/detail")
    public AjaxResult detail(@RequestParam("type") String type,
                             @RequestParam("productName")String productName,
                             @RequestParam("specification")String specification) {
        return AjaxResult.success(salesQuotationService.detail(type, productName, specification));
    }
    @DeleteMapping("/delete")
    public AjaxResult delete(@RequestBody Long id) {
        return AjaxResult.success(salesQuotationService.delete(id));
src/main/java/com/ruoyi/sales/dto/ReceiptPaymentDto.java
@@ -14,6 +14,9 @@
@Data
public class ReceiptPaymentDto extends ReceiptPayment {
    @ApiModelProperty(value = "true:查询超过十五天的未回款记录")
    private Boolean timeOut;
    @ApiModelProperty(value = "客户合同号")
    @Excel(name = "客户合同号")
src/main/java/com/ruoyi/sales/dto/SalesLedgerDto.java
@@ -58,4 +58,8 @@
    @ApiModelProperty(value = "交货日期")
    private LocalDate deliveryDate;
    @ApiModelProperty(value = "审批人ids")
    private String approveUserIds;
}
src/main/java/com/ruoyi/sales/dto/SalesLedgerProductDto.java
@@ -15,6 +15,13 @@
@Data
public class SalesLedgerProductDto extends SalesLedgerProduct {
    /**
     * 登记结束日期
     */
//    @JsonFormat(pattern = "yyyy-MM-dd",shape = JsonFormat.Shape.STRING)
    private String registrationtDate;
    /**
     * 采购合同号
     */
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
@@ -158,5 +158,15 @@
    @TableField(exist = false)
    private Boolean hasProductionRecord;
    @ApiModelProperty(value = "审批状态")
    private Integer approvalStatus;
    @ApiModelProperty(value = "审批人ids")
    @TableField(exist = false)
    private String approveUserIds;
}
src/main/java/com/ruoyi/sales/pojo/SalesQuotationProduct.java
@@ -4,6 +4,7 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@@ -21,8 +22,14 @@
    private String specification;
    @ApiModelProperty(value = "单位")
    private String unit;
    @ApiModelProperty(value = "一批商单价")
    private BigDecimal unitPrice;
    @ApiModelProperty(value = "终端商单价")
    private BigDecimal unitPriceTwo;
    @ApiModelProperty(value = "单价")
    private Double unitPrice;
    private BigDecimal unitPriceThree;
    @ApiModelProperty(value = "数量")
    private Integer quantity;
    @ApiModelProperty(value = "金额")
@@ -46,7 +53,4 @@
    @ApiModelProperty(value = "租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
}
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
@@ -54,4 +54,6 @@
    List<LossProductModelDto> getSalesLedgerWithProductsLoss(Long salesLedgerId);
    IPage<SalesLedgerDto> listSalesLedger(SalesLedgerDto salesLedgerDto, Page page);
    SalesLedgerDto getSalesByCode(SalesLedgerDto salesLedgerDto);
}
src/main/java/com/ruoyi/sales/service/SalesQuotationService.java
@@ -6,6 +6,8 @@
import com.ruoyi.sales.pojo.SalesQuotation;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.math.BigDecimal;
public interface SalesQuotationService extends IService<SalesQuotation> {
    IPage listPage(Page page, SalesQuotationDto salesQuotationDto);
@@ -14,4 +16,6 @@
    boolean delete(Long id);
    boolean edit(SalesQuotationDto salesQuotationDto);
    BigDecimal detail(String type, String productName, String specification);
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -9,6 +9,9 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.account.service.AccountIncomeService;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.approve.service.IApproveProcessService;
import com.ruoyi.approve.vo.ApproveProcessVO;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.mapper.CustomerPrivatePoolMapper;
@@ -85,34 +88,64 @@
    private static final String LOCK_PREFIX = "contract_no_lock:";
    private static final long LOCK_WAIT_TIMEOUT = 10; // 锁等待超时时间(秒)
    private static final long LOCK_EXPIRE_TIME = 30;  // 锁自动过期时间(秒)
    private final AccountIncomeService accountIncomeService;
    private final SalesLedgerMapper salesLedgerMapper;
    private final CustomerMapper customerMapper;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    private final SalesLedgerProductServiceImpl salesLedgerProductServiceImpl;
    private final CommonFileMapper commonFileMapper;
    private final TempFileMapper tempFileMapper;
    private final ReceiptPaymentMapper receiptPaymentMapper;
    private final ShippingInfoServiceImpl shippingInfoServiceImpl;
    private final CommonFileServiceImpl commonFileService;
    private final ShippingInfoMapper shippingInfoMapper;
    private final InvoiceLedgerMapper invoiceLedgerMapper;
    private final SalesLedgerSchedulingMapper salesLedgerSchedulingMapper;
    private final SalesLedgerWorkMapper salesLedgerWorkMapper;
    private final SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
    private final InvoiceRegistrationMapper invoiceRegistrationMapper;
    private final ProductOrderMapper productOrderMapper;
    private final ProcessRouteMapper processRouteMapper;
    private final ProductProcessRouteMapper productProcessRouteMapper;
    private final ProcessRouteItemMapper processRouteItemMapper;
    private final ProductProcessRouteItemMapper productProcessRouteItemMapper;
    private final ProductWorkOrderMapper productWorkOrderMapper;
    private final ProductionProductMainMapper productionProductMainMapper;
    private final ProductionProductOutputMapper productionProductOutputMapper;
    private final ProductionProductInputMapper productionProductInputMapper;
    private final QualityInspectMapper qualityInspectMapper;
    private final RedisTemplate<String, String> redisTemplate;
    @Autowired
    private AccountIncomeService accountIncomeService;
    @Autowired
    private SalesLedgerMapper salesLedgerMapper;
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private SalesLedgerProductMapper salesLedgerProductMapper;
    @Autowired
    private SalesLedgerProductServiceImpl salesLedgerProductServiceImpl;
    @Autowired
    private CommonFileMapper commonFileMapper;
    @Autowired
    private TempFileMapper tempFileMapper;
    @Autowired
    private ReceiptPaymentMapper receiptPaymentMapper;
    @Autowired
    private ShippingInfoServiceImpl shippingInfoServiceImpl;
    @Autowired
    private CommonFileServiceImpl commonFileService;
    @Autowired
    private ShippingInfoMapper shippingInfoMapper;
    @Autowired
    private InvoiceLedgerMapper invoiceLedgerMapper;
    @Autowired
    private SalesLedgerSchedulingMapper salesLedgerSchedulingMapper;
    @Autowired
    private SalesLedgerWorkMapper salesLedgerWorkMapper;
    @Autowired
    private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    @Autowired
    private InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
    @Autowired
    private InvoiceRegistrationMapper invoiceRegistrationMapper;
    @Autowired
    private ProductOrderMapper productOrderMapper;
    @Autowired
    private ProcessRouteMapper processRouteMapper;
    @Autowired
    private ProductProcessRouteMapper productProcessRouteMapper;
    @Autowired
    private ProcessRouteItemMapper processRouteItemMapper;
    @Autowired
    private ProductProcessRouteItemMapper productProcessRouteItemMapper;
    @Autowired
    private ProductWorkOrderMapper productWorkOrderMapper;
    @Autowired
    private ProductionProductMainMapper productionProductMainMapper;
    @Autowired
    private ProductionProductOutputMapper productionProductOutputMapper;
    @Autowired
    private ProductionProductInputMapper productionProductInputMapper;
    @Autowired
    private QualityInspectMapper qualityInspectMapper;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private IApproveProcessService approveProcessService;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Value("${file.upload-dir}")
@@ -502,6 +535,32 @@
        return salesLedgerDtoIPage;
    }
    @Override
    public SalesLedgerDto getSalesByCode(SalesLedgerDto salesLedgerDto) {
        // 1. 查询主表
        SalesLedger salesLedger = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>()
                .eq(SalesLedger::getSalesContractNo, salesLedgerDto.getSalesContractNo())
                .last("LIMIT 1"));
        if (salesLedger == null) {
            throw new BaseException("销售台账不存在");
        }
        // 2. 查询子表
        LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>();
        productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId())
                .eq(SalesLedgerProduct::getType, 1);
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
        // 4. 转换 DTO
        SalesLedgerDto resultDto = new SalesLedgerDto();
        BeanUtils.copyProperties(salesLedger, resultDto);
        if (!products.isEmpty()) {
            resultDto.setHasChildren(true);
            resultDto.setProductData(products);
        }
        return resultDto;
    }
    /**
     * 下划线命名转驼峰命名
     */
@@ -614,9 +673,21 @@
                salesLedger.setSalesContractNo(contractNo);
                salesLedgerMapper.insert(salesLedger);
            } else {
                ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
                        .eq(ApproveProcess::getApproveType, 9)
                        .eq(ApproveProcess::getApproveReason, salesLedger.getSalesContractNo())
                        .eq(ApproveProcess::getApproveDelete, 0)
                        .last("limit 1"));
                if (one != null) {
                    approveProcessService.delByIds(Collections.singletonList(one.getId()));
                }
                salesLedgerMapper.updateById(salesLedger);
            }
            LoginUser loginUser = SecurityUtils.getLoginUser();
            addApproveByPurchase(loginUser, salesLedger);
            salesLedger.setApprovalStatus(1);
            this.updateById(salesLedger);
            // 4. 处理子表数据
            List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
            if (productList != null && !productList.isEmpty()) {
@@ -637,9 +708,22 @@
            return 1;
        } catch (IOException e) {
            throw new BaseException("文件迁移失败: " + e.getMessage());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public void addApproveByPurchase(LoginUser loginUser, SalesLedger salesLedger) throws Exception {
        ApproveProcessVO approveProcessVO = new ApproveProcessVO();
        approveProcessVO.setApproveType(9);
        approveProcessVO.setApproveDeptId(loginUser.getDeptIds()[0]);
        approveProcessVO.setApproveReason(salesLedger.getSalesContractNo());
        approveProcessVO.setApproveUserIds(salesLedger.getApproveUserIds());
        approveProcessVO.setApproveUser(loginUser.getUserId());
        approveProcessVO.setApproveTime(LocalDate.now().toString());
        approveProcessService.addApprove(approveProcessVO);
    }
    /**
     * 将临时文件迁移到正式目录
     *
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java
@@ -13,6 +13,7 @@
import com.ruoyi.approve.vo.ApproveProcessVO;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.framework.security.LoginUser;
@@ -28,8 +29,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@@ -43,8 +44,7 @@
    @Autowired
    private SalesQuotationProductService salesQuotationProductService;
    @Autowired
    private ApproveProcessServiceImpl approveProcessService;
    @Override
    public IPage<SalesQuotationDto> listPage(Page page, SalesQuotationDto salesQuotationDto) {
        IPage<SalesQuotationDto> salesQuotationDtoIPage = salesQuotationMapper.listPage(page, salesQuotationDto);
@@ -60,7 +60,7 @@
    @Override
    public boolean add(SalesQuotationDto salesQuotationDto) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
//        LoginUser loginUser = SecurityUtils.getLoginUser();
        SalesQuotation salesQuotation = new SalesQuotation();
        BeanUtils.copyProperties(salesQuotationDto, salesQuotation);
        String quotationNo = OrderUtils.countTodayByCreateTime(salesQuotationMapper, "QT","quotation_no");
@@ -76,24 +76,25 @@
            salesQuotationProduct.setSalesQuotationId(salesQuotation.getId());
            return salesQuotationProduct;
        }).collect(Collectors.toList());
        salesQuotationProductService.saveBatch(products);
        salesQuotationProductService.saveOrUpdateBatch(products);
        // 报价审批
        ApproveProcessVO approveProcessVO = new ApproveProcessVO();
        approveProcessVO.setApproveType(6);
        approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId());
        approveProcessVO.setApproveReason(quotationNo);
        approveProcessVO.setApproveUserIds(salesQuotationDto.getApproveUserIds());
        approveProcessVO.setApproveUser(loginUser.getUserId());
        approveProcessVO.setApproveTime(LocalDate.now().toString());
        approveProcessVO.setPrice(salesQuotationDto.getTotalAmount());
        try {
            approveProcessService.addApprove(approveProcessVO);
        }catch (Exception e){
            log.error("SalesQuotationServiceImpl error:{}", e);
            throw new RuntimeException("审批失败");
        }
//        ApproveProcessVO approveProcessVO = new ApproveProcessVO();
//        approveProcessVO.setApproveType(6);
//        approveProcessVO.setApproveDeptId(loginUser.getTenantId());
//        approveProcessVO.setApproveReason(quotationNo);
//        approveProcessVO.setApproveUserIds(salesQuotationDto.getApproveUserIds());
//        approveProcessVO.setApproveUser(loginUser.getUserId());
//        approveProcessVO.setApproveTime(LocalDate.now().toString());
//        approveProcessVO.setPrice(salesQuotationDto.getTotalAmount());
//        try {
//            approveProcessService.addApprove(approveProcessVO);
//        }catch (Exception e){
//            log.error("SalesQuotationServiceImpl error:{}", e);
//            throw new RuntimeException("审批失败");
//        }
        return true;
    }
    @Override
    public boolean edit(SalesQuotationDto salesQuotationDto) {
        SalesQuotation salesQuotation = new SalesQuotation();
@@ -118,26 +119,37 @@
        }).collect(Collectors.toList());
        salesQuotationProductService.saveBatch(products);
        // 修改报价审批
        vo.setApproveUserIds(salesQuotationDto.getApproveUserIds());
        vo.setApproveType(6);
        vo.setApproveReason(salesQuotationDto.getQuotationNo());
        approveProcessService.updateApproveUser(vo);
//        // 修改报价审批
//        vo.setApproveUserIds(salesQuotationDto.getApproveUserIds());
//        vo.setApproveType(6);
//        vo.setApproveReason(salesQuotationDto.getQuotationNo());
//        approveProcessService.updateApproveUser(vo);
        return true;
    }
    @Override
    public BigDecimal detail(String type, String productName, String specification) {
        if (StringUtils.isEmpty(type)) return null;
        SalesQuotationProduct salesQuotationProduct = salesQuotationProductMapper.selectOne(new LambdaQueryWrapper<SalesQuotationProduct>()
                .eq(SalesQuotationProduct::getProduct, productName)
                .eq(SalesQuotationProduct::getSpecification, specification)
                .orderByDesc(SalesQuotationProduct::getCreateTime)
                .last("limit 1"));
        if (salesQuotationProduct == null) return null;
        switch (type) {
            case "一批商":
                return salesQuotationProduct.getUnitPrice();
            case "终端商":
                return salesQuotationProduct.getUnitPriceTwo();
            default:
                return salesQuotationProduct.getUnitPriceThree();
        }
    }
    @Override
    public boolean delete(Long id) {
        SalesQuotation salesQuotation = salesQuotationMapper.selectById(id);
        if(salesQuotation==null) return false;
        salesQuotationMapper.deleteById(id);
        salesQuotationProductMapper.delete(new LambdaQueryWrapper<SalesQuotationProduct>().eq(SalesQuotationProduct::getSalesQuotationId, id));
        // 删除报价审批
        ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
                .eq(ApproveProcess::getApproveType, 6)
                .eq(ApproveProcess::getApproveReason, salesQuotation.getQuotationNo()));
        if(one != null){
            approveProcessService.delByIds(Collections.singletonList(one.getId()));
        }
        return true;
    }
src/main/java/com/ruoyi/staff/pojo/StaffLeave.java
@@ -51,4 +51,8 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty(value = "工作交接")
    private String workTransfer;
}
src/main/java/com/ruoyi/staff/pojo/StaffOnJob.java
@@ -250,4 +250,8 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty(value = "薪资")
    private BigDecimal salary;
}
src/main/java/com/ruoyi/staff/service/impl/StaffLeaveServiceImpl.java
@@ -66,6 +66,7 @@
        // 新增离职记录
        StaffLeave staffLeave = new StaffLeave();
        staffLeave.setStaffOnJobId(staffLeaveDto.getStaffOnJobId());
        staffLeave.setWorkTransfer(staffLeaveDto.getWorkTransfer());
        staffLeave.setReason(staffLeaveDto.getReason());
        String reason = staffLeaveDto.getReason();
        if (StaffLeaveReasonOther.getCode().equals(reason)){
@@ -98,6 +99,7 @@
        String reason = staffLeaveDto.getReason();
        leave.setReason(reason);
        leave.setWorkTransfer(staffLeaveDto.getWorkTransfer());
        leave.setLeaveDate(staffLeaveDto.getLeaveDate());
        // 校验离职原因是否为其他,如果是其他,备注赋值
        if (StaffLeaveReasonOther.getCode().equals(reason)){
src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
@@ -186,7 +186,11 @@
                    .filter(Objects::nonNull) // 过滤null对象,避免空指针
                    .forEach(staff -> staff.setStaffOnJobId(id)); // 赋值
            staffEducationService.saveBatch(staffOnJobPrams.getStaffEducationList());
            staffOnJobPrams.setFirstStudy(staffOnJobPrams.getStaffEducationList().get(staffOnJobPrams.getStaffEducationList().size()-1).getEducation());
            staffOnJobPrams.setProfession(staffOnJobPrams.getStaffEducationList().get(staffOnJobPrams.getStaffEducationList().size()-1).getMajor());
        }
        // 新增工作经历
        if(CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffWorkExperienceList())){
            staffOnJobPrams.getStaffWorkExperienceList().stream()
@@ -200,7 +204,11 @@
                    .filter(Objects::nonNull) // 过滤null对象,避免空指针
                    .forEach(staff -> staff.setStaffOnJobId(id)); // 赋值
            staffEmergencyContactServiceImpl.saveBatch(staffOnJobPrams.getStaffEmergencyContactList());
            staffOnJobPrams.setEmergencyContact(staffOnJobPrams.getStaffEmergencyContactList().get(0).getContactName());
            staffOnJobPrams.setEmergencyContactPhone(staffOnJobPrams.getStaffEmergencyContactList().get(0).getContactPhone());
        }
        staffOnJobMapper.updateById(staffOnJobPrams);
    }
src/main/java/com/ruoyi/stock/controller/StockInRecordController.java
@@ -5,7 +5,9 @@
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.stock.dto.StockInRecordDto;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.service.StockInRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java
@@ -26,4 +26,6 @@
    //现存量
    private String currentStock;
    private Long topParentProductId;
}
src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java
@@ -25,4 +25,6 @@
    private String timeStr;
    private String createBy;
    private Long topParentProductId;
}
src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.stock.dto.StockInRecordDto;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.execl.StockInRecordExportData;
import com.ruoyi.stock.pojo.StockInRecord;
import org.apache.ibatis.annotations.Param;
@@ -11,7 +12,8 @@
import java.util.List;
public interface StockInRecordMapper extends BaseMapper<StockInRecord> {
    IPage<StockInRecordDto> listPage(Page page, @Param("params") StockInRecordDto stockInRecordDto);
    IPage<StockInRecordDto> listPage(Page page, @Param("ew") StockInRecordDto stockInRecordDto);
    List<StockInRecordExportData> listStockInRecordExportData(@Param("params") StockInRecordDto stockInRecordDto);
}
src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java
@@ -21,7 +21,7 @@
 */
@Mapper
public interface StockOutRecordMapper extends BaseMapper<StockOutRecord> {
    IPage<StockOutRecordDto> listPage(Page page, @Param("params") StockOutRecordDto stockOutRecordDto);
    IPage<StockOutRecordDto> listPage(Page page, @Param("ew") StockOutRecordDto stockOutRecordDto);
    List<StockOutRecordExportData> listStockOutRecordExportData(@Param("params") StockOutRecordDto stockOutRecordDto);
src/main/java/com/ruoyi/stock/service/StockInRecordService.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.stock.dto.StockInRecordDto;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.pojo.StockInRecord;
import javax.servlet.http.HttpServletResponse;
@@ -19,4 +20,5 @@
    int batchDelete(List<Long> ids);
    void exportStockInRecord(HttpServletResponse response, StockInRecordDto stockInRecordDto);
}
src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
@@ -110,4 +110,6 @@
        ExcelUtil<StockInRecordExportData> util = new ExcelUtil<>(StockInRecordExportData.class);
        util.exportExcel(response,list, "入库记录信息");
    }
}
src/main/resources/mapper/basic/CustomerPrivatePoolMapper.xml
@@ -42,7 +42,7 @@
                and c.customer_type = #{c.customerType}
            </if>
            <if test="c.boundId != null">
                and cpp.boundId = #{c.boundId}
                and cpp.bound_id = #{c.boundId}
            </if>
        </where>
src/main/resources/mapper/device/DeviceMaintenanceMapper.xml
@@ -21,7 +21,9 @@
        dl.device_name,
        dm.machinery_category,
        dl.device_model,
        su.nick_name as create_user_name
        su.nick_name as create_user_name,
        dm.maintenance_project,
        dm.maintenance_content
        from device_maintenance dm
        left join device_ledger dl on dm.device_ledger_id = dl.id
        left join sys_user su on dm.create_user = su.user_id
@@ -67,7 +69,9 @@
               dm.maintenance_actually_name,
               dl.device_name,
               dl.device_model,
               su.user_name as create_user_name
               su.user_name as create_user_name,
               dm.maintenance_project,
               dm.maintenance_content
        from device_maintenance dm
                 left join device_ledger dl on dm.device_ledger_id = dl.id
                 left join sys_user su on dm.create_user = su.user_id
src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml
@@ -272,6 +272,7 @@
                and t1.create_time like  concat('%',#{req.timeStr},'%')
            </if>
        </where>
        GROUP BY t3.product_name,t2.model,t1.inbound_num
        order by t1.create_time desc
    </select>
    <select id="listPageCopyByProduction" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDtoCopy">
src/main/resources/mapper/production/ProductWorkOrderMapper.xml
@@ -38,7 +38,7 @@
        LEFT JOIN product_process pp ON pp.id = ppri.process_id
        LEFT JOIN product_model pm ON pm.id = ppri.product_model_id
        LEFT JOIN product p ON p.id = pm.product_id
        where 1=1
        <where>
            <if test="c.workOrderNo != null and c.workOrderNo != ''">
               and pwo.work_order_no like concat('%',#{c.workOrderNo},'%')
            </if>
@@ -48,6 +48,8 @@
            <if test="c.productOrderNpsNo != null and c.productOrderNpsNo != ''">
               and po.nps_no like concat('%',#{c.productOrderNpsNo},'%')
            </if>
        </where>
        order by pwo.id desc
    </select>
    <select id="getProductWorkOrderFlowCard" resultType="com.ruoyi.production.dto.ProductWorkOrderDto">
        SELECT
src/main/resources/mapper/purchase/InvoicePurchaseMapper.xml
@@ -10,6 +10,7 @@
        sl.sales_contract_no AS customerContractNo,
        sl.customer_name,
        sl.contract_amount AS contract_amount,
        pl.purchase_contract_number,
        SUM( pl.contract_amount ) AS purchase_amount,
        (
        sl.contract_amount - SUM( pl.contract_amount )) AS balance,
src/main/resources/mapper/purchase/ProductRecordMapper.xml
@@ -35,6 +35,9 @@
        </if>
        <if test="c.createdAtStart != null and c.createdAtStart != ''">
            and pr.created_at &gt;= str_to_date(#{c.createdAtStart}, '%Y-%m-%d')
        </if>
        <if test="c.invoiceAmount != null">
            and pr.tickets_amount like concat('%',#{c.invoiceAmount},'%')
        </if>
        <if test="c.createdAtEnd != null and c.createdAtEnd != ''">
            and pr.created_at &lt; date_add(str_to_date(#{c.createdAtEnd}, '%Y-%m-%d'), interval 1 day)
src/main/resources/mapper/sales/InvoiceRegistrationProductMapper.xml
@@ -118,6 +118,9 @@
                AND T3.invoice_date &lt; date_add(str_to_date(#{invoiceRegistrationProductDto.invoiceDateEnd},
                '%Y-%m-%d'), interval 1 day)
            </if>
            <if test="invoiceRegistrationProductDto.invoiceTotal != null">
                AND T3.invoice_total like concat('%',#{invoiceRegistrationProductDto.invoiceTotal},'%')
            </if>
            <if test="invoiceRegistrationProductDto.createTimeStart != null ">
                AND T1.create_time &gt;= date_format(#{invoiceRegistrationProductDto.createTimeStart}, '%Y-%m-%d
                %H:%i:%s')
src/main/resources/mapper/sales/ReceiptPaymentMapper.xml
@@ -102,6 +102,10 @@
            <if test="req.customerName != null and req.customerName !=''">
                AND T3.customer_name LIKE CONCAT('%',#{req.customerName},'%')
            </if>
            <if test="req.timeOut != null and req.timeOut">
                AND T1.invoice_date &lt; DATE_SUB(CURDATE(), INTERVAL 15 DAY)
                AND (T1.invoice_total - IFNULL(T6.receipt_payment_amount_total ,0)) > 0
            </if>
            <if test="req.invoiceLedgerId != null">
                AND T1.id = #{req.invoiceLedgerId}
            </if>
src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -50,6 +50,7 @@
        T1.entry_date,
        T1.salesman,
        T1.customer_id,
        T1.approval_status,
        T1.customer_name,
        T1.entry_person,
        T1.remarks,
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -99,6 +99,13 @@
            <if test="req.status != null and req.status ">
                AND slp.pending_tickets_total &gt; 0
            </if>
            <if test="req.ticketsTotal != null and req.ticketsTotal.doubleValue() != 0.0">
                AND slp.tickets_total = #{req.ticketsTotal}
            </if>
            <if test="req.registrationtDate != null and req.registrationtDate != ''">
                AND DATE(slp.register_date) = #{req.registrationtDate}
            </if>
        </where>
        order by slp.register_date desc
    </select>
src/main/resources/mapper/staff/StaffOnJobMapper.xml
@@ -6,7 +6,7 @@
        staff_on_job.*,
        sp.post_name as postName,
        sd.dept_name as deptName,
        t1.contract_start_time
        DATE_SUB(staff_on_job.contract_expire_time, INTERVAL CAST(staff_on_job.contract_term AS SIGNED) YEAR) AS contractStartTime
        FROM staff_on_job
        LEFT JOIN
        sys_post sp ON sp.post_id = staff_on_job.sys_post_id
src/main/resources/mapper/stock/StockInRecordMapper.xml
@@ -3,32 +3,48 @@
<mapper namespace="com.ruoyi.stock.mapper.StockInRecordMapper">
    <select id="listPage" resultType="com.ruoyi.stock.dto.StockInRecordDto">
        WITH RECURSIVE product_tree AS (
        SELECT id, product_name, parent_id, 1 as level
        FROM product
        WHERE id = #{ew.topParentProductId}
        UNION ALL
        SELECT p.id, p.product_name, p.parent_id, pt.level + 1
        FROM product p
        INNER JOIN product_tree pt ON p.parent_id = pt.id
        )
        SELECT
        sir.*,
        p.product_name as product_name,
        pm.model,
        pm.unit,
        u.nick_name as createBy
        u.nick_name as createBy,
        p.id as product_id,
        pt.level as product_level
        FROM stock_in_record as sir
        LEFT JOIN product_model as pm on sir.product_model_id = pm.id
        LEFT JOIN product as p on pm.product_id = p.id
        INNER JOIN product_model as pm on sir.product_model_id = pm.id
        INNER JOIN product as p on pm.product_id = p.id
        LEFT JOIN sys_user as u on sir.create_user = u.user_id
        INNER JOIN product_tree pt on p.id = pt.id
        <where>
            <if test="params.timeStr != null and params.timeStr != ''">
                and sir.create_time like concat('%',#{params.timeStr},'%')
            <if test="ew.productName != null and ew.productName !=''">
                AND (p.product_name LIKE CONCAT('%',#{ew.productName},'%') OR pm.model LIKE
                CONCAT('%',#{ew.productName},'%'))
            </if>
            <if test="params.productName != null and params.productName != ''">
                and p.product_name like concat('%',#{params.productName},'%')
            <if test="ew.recordType != null and ew.recordType !=''">
                AND sir.record_type = #{ew.recordType}
            </if>
            <if test="params.type != null and params.type != ''">
                and sir.type = #{params.type}
            <if test="ew.model != null and ew.model !=''">
                AND pm.model = #{ew.model}
            </if>
            <if test="params.recordType != null and params.recordType != ''">
                and sir.record_type = #{params.recordType}
            <if test="ew.timeStr != null and ew.timeStr !=''">
                AND DATE(sir.create_time) = #{ew.timeStr}
            </if>
        </where>
        order by sir.id desc
        ORDER BY pt.level ASC, sir.create_time DESC
    </select>
    <select id="listStockInRecordExportData" resultType="com.ruoyi.stock.execl.StockInRecordExportData">
        SELECT
        sir.*,
src/main/resources/mapper/stock/StockOutRecordMapper.xml
@@ -18,32 +18,47 @@
    </resultMap>
    <select id="listPage" resultType="com.ruoyi.stock.dto.StockOutRecordDto">
        WITH RECURSIVE product_tree AS (
        SELECT id, product_name, parent_id, 1 as level
        FROM product
        WHERE id = #{ew.topParentProductId}
        UNION ALL
        SELECT p.id, p.product_name, p.parent_id, pt.level + 1
        FROM product p
        INNER JOIN product_tree pt ON p.parent_id = pt.id
        )
        SELECT
        sor.*,
        p.product_name as productName,
        pm.model,
        pm.unit,
        u.nick_name as createBy
        u.nick_name as createBy,
        p.id as product_id,
        pt.level as product_level
        FROM stock_out_record as sor
        LEFT JOIN product_model as pm on sor.product_model_id = pm.id
        LEFT JOIN product as p on pm.product_id = p.id
        INNER JOIN product_model as pm on sor.product_model_id = pm.id
        INNER JOIN product as p on pm.product_id = p.id
        LEFT JOIN sys_user as u on sor.create_user = u.user_id
        INNER JOIN product_tree pt on p.id = pt.id
        <where>
            <if test="params.timeStr != null and params.timeStr != ''">
                and sor.create_time like concat('%',#{params.timeStr},'%')
            <if test="ew.productName != null and ew.productName !=''">
                AND (p.product_name LIKE CONCAT('%',#{ew.productName},'%') OR pm.model LIKE CONCAT('%',#{ew.productName},'%'))
            </if>
            <if test="params.productName != null and params.productName != ''">
                and p.product_name like concat('%',#{params.productName},'%')
            <if test="ew.recordType != null and ew.recordType !=''">
                AND sor.record_type = #{ew.recordType}
            </if>
            <if test="params.type != null and params.type != ''">
                and sor.type = #{params.type}
            <if test="ew.model != null and ew.model !=''">
                AND pm.model = #{ew.model}
            </if>
            <if test="params.recordType != null and params.recordType != ''">
                and sor.record_type = #{params.recordType}
            <if test="ew.timeStr != null and ew.timeStr !=''">
                AND DATE(sor.create_time) = #{ew.timeStr}
            </if>
        </where>
        order by sor.id desc
        ORDER BY pt.level ASC, sor.create_time DESC
    </select>
    <select id="listStockOutRecordExportData" resultType="com.ruoyi.stock.execl.StockOutRecordExportData">
        SELECT
        sor.*,