liding
2025-05-13 08c0e7417807e0e172640835d21f873157b03650
采购台账联调优化
已修改15个文件
已添加3个文件
541 ■■■■■ 文件已修改
src/main/java/com/ruoyi/other/pojo/TempFile.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesLedgerDto.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedgerFile.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/ISalesLedgerFileService.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerFileServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerMapper.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/other/pojo/TempFile.java
@@ -1,5 +1,6 @@
package com.ruoyi.other.pojo;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -8,6 +9,9 @@
@Data
@TableName("temp_file")
public class TempFile {
    private static final long serialVersionUID = 1L;
    @TableId
    private String tempId;         // ä¸´æ—¶æ–‡ä»¶ID(UUID)
    private String originalName;   // åŽŸå§‹æ–‡ä»¶å
    private String tempPath;       // ä¸´æ—¶å­˜å‚¨è·¯å¾„
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
@@ -3,8 +3,10 @@
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.purchase.dto.PurchaseLedgerDto;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.purchase.service.IPurchaseLedgerService;
import com.ruoyi.sales.service.ISalesLedgerService;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@@ -18,19 +20,23 @@
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.page.TableDataInfo;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
 * é‡‡è´­å°è´¦Controller
 *
 *
 * @author ruoyi
 * @date 2025-05-09
 */
@RestController
@RequestMapping("/system/ledger")
@RequestMapping("/purchase/ledger")
@AllArgsConstructor
public class PurchaseLedgerController extends BaseController {
    private IPurchaseLedgerService purchaseLedgerService;
    private ISalesLedgerService salesLedgerService;
    /**
     * æŸ¥è¯¢é‡‡è´­å°è´¦åˆ—表
@@ -57,17 +63,33 @@
     * æ–°å¢žä¿®æ”¹é‡‡è´­å°è´¦
     */
    @Log(title = "采购台账", businessType = BusinessType.INSERT)
    @PostMapping ("/addOrEditPurchase")
    public AjaxResult addOrEditPurchase(@RequestBody PurchaseLedger purchaseLedger) {
        return toAjax(purchaseLedgerService.addOrEditPurchase(purchaseLedger));
    @PostMapping("/addOrEditPurchase")
    public AjaxResult addOrEditPurchase(@RequestBody PurchaseLedgerDto purchaseLedgerDto) throws IOException {
        return toAjax(purchaseLedgerService.addOrEditPurchase(purchaseLedgerDto));
    }
    /**
     * æŸ¥è¯¢é”€å”®å°è´¦å’Œäº§å“çˆ¶å­åˆ—表
     */
    @GetMapping("/getPurchaseById")
    public PurchaseLedgerDto getPurchaseById(PurchaseLedgerDto purchaseLedgerDto) {
        return purchaseLedgerService.getPurchaseById(purchaseLedgerDto);
    }
    /**
     * åˆ é™¤é‡‡è´­å°è´¦
     */
    @Log(title = "采购台账", businessType = BusinessType.DELETE)
    @DeleteMapping("/delPurchase")
    @DeleteMapping("/delPurchase")
    public AjaxResult remove(@RequestBody Long[] ids) {
        return toAjax(purchaseLedgerService.deletePurchaseLedgerByIds(ids));
    }
    /**
     * æŸ¥è¯¢é”€å”®åˆåŒå·
     */
    @GetMapping("/getSalesNo")
    public List getSalesNo() {
        return salesLedgerService.getSalesNo();
    }
}
src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,90 @@
package com.ruoyi.purchase.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.sales.pojo.SalesLedgerFile;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import lombok.Data;
import java.util.Date;
import java.util.List;
@Data
public class PurchaseLedgerDto {
    private Long id;
    /**
     * é‡‡è´­åˆåŒå·
     */
    private String purchaseContractNumber;
    /**
     * ä¾›åº”商名称
     */
    private String supplierName;
    /**
     * å½•入人姓名id
     */
    private Long recorderId;
    /**
     * å½•入人姓名
     */
    private String recorderName;
    /**
     * é”€å”®åˆåŒå·
     */
    private String salesContractNo;
    /**
     * é¡¹ç›®åç§°
     */
    private String projectName;
    /**
     * å½•入日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date entryDate;
    /**
     * å¤‡æ³¨
     */
    private String remarks;
    /**
     * é™„件材料路径或名称
     */
    private String attachmentMaterials;
    /**
     * è®°å½•创建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createdAt;
    /**
     * è®°å½•最后更新时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date updatedAt;
    /**
     * å…³è”销售台账主表主键
     */
    private Long salesLedgerId;
    private Boolean hasChildren = false;
    private Integer Type;
    private List<SalesLedgerProduct> productData;
    private List<String> tempFileIds;
    private List<SalesLedgerFile> SalesLedgerFiles;
}
src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java
@@ -1,11 +1,10 @@
package com.ruoyi.purchase.pojo;
import java.math.BigDecimal;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
@@ -37,6 +36,11 @@
     */
    @Excel(name = "供应商名称")
    private String supplierName;
    /**
     * å½•入人姓名id
     */
    private Long recorderId;
    /**
     * å½•入人姓名
@@ -94,4 +98,12 @@
     */
    private Long salesLedgerId;
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    /**
     * åˆåŒé‡‘额(产品含税总价)
     */
    private BigDecimal contractAmount;
}
src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
@@ -2,8 +2,10 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.purchase.dto.PurchaseLedgerDto;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import java.io.IOException;
import java.util.List;
/**
@@ -16,8 +18,9 @@
    List<PurchaseLedger> selectPurchaseLedgerList(PurchaseLedger purchaseLedger);
    int addOrEditPurchase(PurchaseLedger purchaseLedger);
    int addOrEditPurchase(PurchaseLedgerDto purchaseLedgerDto) throws IOException;
    int deletePurchaseLedgerByIds(Long[] ids);
    PurchaseLedgerDto getPurchaseById(PurchaseLedgerDto purchaseLedgerDto);
}
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -1,15 +1,44 @@
package com.ruoyi.purchase.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.other.pojo.TempFile;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.purchase.dto.PurchaseLedgerDto;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.purchase.service.IPurchaseLedgerService;
import lombok.AllArgsConstructor;
import com.ruoyi.sales.mapper.SalesLedgerFileMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerFile;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
/**
 * é‡‡è´­å°è´¦Service业务层处理
@@ -18,10 +47,23 @@
 * @date 2025-05-09
 */
@Service
@AllArgsConstructor
@RequiredArgsConstructor
@Slf4j
public class PurchaseLedgerServiceImpl extends ServiceImpl<PurchaseLedgerMapper, PurchaseLedger> implements IPurchaseLedgerService {
    private PurchaseLedgerMapper purchaseLedgerMapper;
    private final PurchaseLedgerMapper purchaseLedgerMapper;
    private final SalesLedgerMapper salesLedgerMapper;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    private final SysUserMapper userMapper;
    private final TempFileMapper tempFileMapper;
    private final SalesLedgerFileMapper salesLedgerFileMapper;
    @Value("${file.upload-dir}")
    private String uploadDir;
    @Override
    public List<PurchaseLedger> selectPurchaseLedgerList(PurchaseLedger purchaseLedger) {
@@ -29,11 +71,137 @@
    }
    @Override
    public int addOrEditPurchase(PurchaseLedger purchaseLedger) {
    public int addOrEditPurchase(PurchaseLedgerDto purchaseLedgerDto) throws IOException {
        SalesLedger salesLedger = salesLedgerMapper.selectById(purchaseLedgerDto.getSalesLedgerId());
        if (salesLedger == null) {
            throw new BaseException("销售台账不存在");
        }
        SysUser sysUser = userMapper.selectUserById(purchaseLedgerDto.getRecorderId());
        // DTO转Entity
        PurchaseLedger purchaseLedger = new PurchaseLedger();
        BeanUtils.copyProperties(purchaseLedgerDto, purchaseLedger);
        purchaseLedger.setTenantId(salesLedger.getTenantId());
        purchaseLedger.setSalesContractNo(salesLedger.getSalesContractNo());
        purchaseLedger.setRecorderId(purchaseLedgerDto.getRecorderId());
        purchaseLedger.setRecorderName(sysUser.getNickName());
        // 3. æ–°å¢žæˆ–更新主表
        if (purchaseLedger.getId() == null) {
            return purchaseLedgerMapper.insert(purchaseLedger);
            purchaseLedgerMapper.insert(purchaseLedger);
        } else {
            return purchaseLedgerMapper.updateById(purchaseLedger);
            purchaseLedgerMapper.updateById(purchaseLedger);
        }
        // 4. å¤„理子表数据
        List<SalesLedgerProduct> productList = purchaseLedgerDto.getProductData();
        if (productList != null && !productList.isEmpty()) {
            handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType());
        }
        // 5. è¿ç§»ä¸´æ—¶æ–‡ä»¶åˆ°æ­£å¼ç›®å½•
        if (purchaseLedgerDto.getTempFileIds() != null && !purchaseLedgerDto.getTempFileIds().isEmpty()) {
            migrateTempFilesToFormal(purchaseLedger.getId(), purchaseLedgerDto.getTempFileIds());
        }
        return 1;
    }
    private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type) {
        // æŒ‰ID分组,区分新增和更新的记录
        Map<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream()
                .peek(p -> p.setSalesLedgerId(salesLedgerId))
                .collect(Collectors.partitioningBy(p -> p.getId() != null));
        List<SalesLedgerProduct> updateList = partitionedProducts.get(true);
        List<SalesLedgerProduct> insertList = partitionedProducts.get(false);
        // æ‰§è¡Œæ›´æ–°æ“ä½œ
        if (!updateList.isEmpty()) {
            for (SalesLedgerProduct product : updateList) {
                product.setType(type);
                salesLedgerProductMapper.updateById(product);
            }
        }
        // æ‰§è¡Œæ’入操作
        if (!insertList.isEmpty()) {
            for (SalesLedgerProduct salesLedgerProduct : insertList) {
                salesLedgerProduct.setType(type);
                salesLedgerProductMapper.insert(salesLedgerProduct);
            }
        }
    }
    /**
     * å°†ä¸´æ—¶æ–‡ä»¶è¿ç§»åˆ°æ­£å¼ç›®å½•
     *
     * @param businessId  ä¸šåŠ¡ID(销售台账ID)
     * @param tempFileIds ä¸´æ—¶æ–‡ä»¶ID列表
     * @throws IOException æ–‡ä»¶æ“ä½œå¼‚常
     */
    private void migrateTempFilesToFormal(Long businessId, List<String> tempFileIds) throws IOException {
        if (CollectionUtils.isEmpty(tempFileIds)) {
            return;
        }
        // æž„建正式目录路径(按业务类型和日期分组)
        String formalDir = uploadDir + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
        Path formalDirPath = Paths.get(formalDir);
        // ç¡®ä¿æ­£å¼ç›®å½•存在(递归创建)
        if (!Files.exists(formalDirPath)) {
            Files.createDirectories(formalDirPath);
        }
        for (String tempFileId : tempFileIds) {
            // æŸ¥è¯¢ä¸´æ—¶æ–‡ä»¶è®°å½•
            TempFile tempFile = tempFileMapper.selectById(tempFileId);
            if (tempFile == null) {
                log.warn("临时文件不存在,跳过处理: {}", tempFileId);
                continue;
            }
            // æž„建正式文件名(包含业务ID和时间戳,避免冲突)
            String originalFilename = tempFile.getOriginalName();
            String fileExtension = FilenameUtils.getExtension(originalFilename);
            String formalFilename = businessId + "_" +
                    System.currentTimeMillis() + "_" +
                    UUID.randomUUID().toString().substring(0, 8) +
                    (StringUtils.hasText(fileExtension) ? "." + fileExtension : "");
            Path formalFilePath = formalDirPath.resolve(formalFilename);
            try {
                // æ‰§è¡Œæ–‡ä»¶è¿ç§»ï¼ˆä½¿ç”¨åŽŸå­æ“ä½œç¡®ä¿å®‰å…¨æ€§ï¼‰
                Files.move(
                        Paths.get(tempFile.getTempPath()),
                        formalFilePath,
                        StandardCopyOption.REPLACE_EXISTING,
                        StandardCopyOption.ATOMIC_MOVE
                );
                log.info("文件迁移成功: {} -> {}", tempFile.getTempPath(), formalFilePath);
                // æ›´æ–°æ–‡ä»¶è®°å½•(关联到业务ID)
                SalesLedgerFile fileRecord = new SalesLedgerFile();
                fileRecord.setLedgerId(businessId);
                fileRecord.setName(originalFilename);
                fileRecord.setUrl(formalFilePath.toString());
                fileRecord.setCreateTime(LocalDateTime.now());
                salesLedgerFileMapper.insert(fileRecord);
                // åˆ é™¤ä¸´æ—¶æ–‡ä»¶è®°å½•
                tempFileMapper.deleteById(tempFile);
                log.info("文件迁移成功: {} -> {}", tempFile.getTempPath(), formalFilePath);
            } catch (IOException e) {
                log.error("文件迁移失败: {}", tempFile.getTempPath(), e);
                // å¯é€‰æ‹©å›žæ»šäº‹åŠ¡æˆ–è®°å½•å¤±è´¥æ–‡ä»¶
                throw new IOException("文件迁移异常", e);
            }
        }
    }
@@ -41,4 +209,34 @@
    public int deletePurchaseLedgerByIds(Long[] ids) {
        return purchaseLedgerMapper.deleteBatchIds(Arrays.asList(ids));
    }
    @Override
    public PurchaseLedgerDto getPurchaseById(PurchaseLedgerDto purchaseLedgerDto) {
        // 1. æŸ¥è¯¢ä¸»è¡¨
        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(purchaseLedgerDto.getId());
        if (purchaseLedger == null) {
            throw new BaseException("采购台账不存在");
        }
        // 2. æŸ¥è¯¢å­è¡¨
        LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>();
        productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId())
                .eq(SalesLedgerProduct::getType, purchaseLedgerDto.getType());
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
        // 3.查询上传文件
        LambdaQueryWrapper<SalesLedgerFile> salesLedgerFileWrapper = new LambdaQueryWrapper<>();
        salesLedgerFileWrapper.eq(SalesLedgerFile::getLedgerId, purchaseLedger.getId());
        List<SalesLedgerFile> salesLedgerFiles = salesLedgerFileMapper.selectList(salesLedgerFileWrapper);
        // 4. è½¬æ¢ DTO
        PurchaseLedgerDto resultDto = new PurchaseLedgerDto();
        BeanUtils.copyProperties(purchaseLedger, resultDto);
        if (!products.isEmpty()) {
            resultDto.setHasChildren(true);
            resultDto.setProductData(products);
            resultDto.setSalesLedgerFiles(salesLedgerFiles);
        }
        return resultDto;
    }
}
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
@@ -6,8 +6,9 @@
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.sales.dto.SalesLedgerDto;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.service.ISalesLedgerFileService;
import com.ruoyi.sales.service.ISalesLedgerService;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
@@ -23,9 +24,12 @@
 */
@RestController
@RequestMapping("/sales/ledger")
@AllArgsConstructor
public class SalesLedgerController extends BaseController {
    @Autowired
    private ISalesLedgerService salesLedgerService;
    private ISalesLedgerFileService salesLedgerFileService;
    /**
     * æŸ¥è¯¢é”€å”®å°è´¦åˆ—表
@@ -87,4 +91,16 @@
        List<SalesLedger> list = salesLedgerService.selectSalesLedgerList(salesLedgerDto);
        return AjaxResult.success(list);
    }
    /**
     * é”€å”®å°è´¦é™„件删除
     */
    @Log(title = "销售台账附件删除", businessType = BusinessType.DELETE)
    @DeleteMapping("/delLedgerFile")
    public AjaxResult delLedgerFile(@RequestBody Long[] ids) {
        if (ids == null || ids.length == 0) {
            return AjaxResult.error("请传入要删除的ID");
        }
        return toAjax(salesLedgerFileService.deleteSalesLedgerByIds(ids));
    }
}
src/main/java/com/ruoyi/sales/dto/SalesLedgerDto.java
@@ -1,6 +1,7 @@
package com.ruoyi.sales.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.sales.pojo.SalesLedgerFile;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import lombok.Data;
@@ -23,6 +24,8 @@
    private String attachmentMaterials;
    private Boolean hasChildren = false;
    private List<SalesLedgerProduct> productData;
    private List<String> tempFileIds;
    private List<SalesLedgerFile> SalesLedgerFiles;
    private Integer Type;
}
src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
@@ -19,4 +19,6 @@
     * @return åºåˆ—号列表
     */
    List<Integer> selectSequencesByDate(@Param("datePart") String datePart);
    List getSalesNo();
}
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
@@ -91,7 +91,7 @@
    /**
     * åˆåŒé‡‘额(产品含税总价)
     */
    @Excel(name = "税率")
    @Excel(name = "合同金额")
    private BigDecimal contractAmount;
}
src/main/java/com/ruoyi/sales/pojo/SalesLedgerFile.java
@@ -9,6 +9,8 @@
@TableName("sales_ledger_file")
public class SalesLedgerFile {
    private static final long serialVersionUID = 1L;
    @TableId(type = IdType.AUTO)
    private Long id;
@@ -16,10 +18,10 @@
    private Long ledgerId;
    /** æ–‡ä»¶åç§° */
    private String fileName;
    private String name;
    /** æ–‡ä»¶è·¯å¾„ */
    private String filePath;
    private String url;
    /** åˆ›å»ºæ—¶é—´ */
    @TableField(fill = FieldFill.INSERT)
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -84,4 +84,9 @@
     */
    @Excel(name = "发票类型")
    private String invoiceType;
    /**
     * å°è´¦ç±»åž‹ 1.销售 2,采购
     */
    private Integer type;
}
src/main/java/com/ruoyi/sales/service/ISalesLedgerFileService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
package com.ruoyi.sales.service;
public interface ISalesLedgerFileService {
    int deleteSalesLedgerByIds(Long[] ids);
}
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
@@ -21,4 +21,6 @@
    int addOrUpdateSalesLedger(SalesLedgerDto salesLedgerDto);
    SalesLedgerDto getSalesLedgerWithProducts(SalesLedgerDto salesLedgerDto);
    List getSalesNo();
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerFileServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.ruoyi.sales.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.sales.mapper.SalesLedgerFileMapper;
import com.ruoyi.sales.pojo.SalesLedgerFile;
import com.ruoyi.sales.service.ISalesLedgerFileService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Arrays;
@Service
@AllArgsConstructor
public class SalesLedgerFileServiceImpl extends ServiceImpl<SalesLedgerFileMapper, SalesLedgerFile> implements ISalesLedgerFileService {
    private SalesLedgerFileMapper salesLedgerFileMapper;
    @Override
    public int deleteSalesLedgerByIds(Long[] ids) {
        return salesLedgerFileMapper.deleteBatchIds(Arrays.asList(ids));
    }
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -3,6 +3,8 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedger;
@@ -35,6 +37,8 @@
    private SalesLedgerMapper salesLedgerMapper;
    private PurchaseLedgerMapper purchaseLedgerMapper;
    @Override
    public SalesLedgerProduct selectSalesLedgerProductById(Long id) {
        return salesLedgerProductMapper.selectById(id);
@@ -43,7 +47,8 @@
    @Override
    public List<SalesLedgerProduct> selectSalesLedgerProductList(SalesLedgerProduct salesLedgerProduct) {
        LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SalesLedgerProduct::getSalesLedgerId,salesLedgerProduct.getSalesLedgerId());
        queryWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerProduct.getSalesLedgerId())
                .eq(SalesLedgerProduct::getType, salesLedgerProduct.getType());
        return salesLedgerProductMapper.selectList(queryWrapper);
    }
@@ -92,7 +97,6 @@
    public int addOrUpdateSalesLedgerProduct(SalesLedgerProduct salesLedgerProduct) {
        int result;
        Long salesLedgerId = salesLedgerProduct.getSalesLedgerId();
        if (salesLedgerProduct.getId() == null) {
            result = salesLedgerProductMapper.insert(salesLedgerProduct);
        } else {
@@ -103,19 +107,29 @@
        if (result > 0 && salesLedgerId != null) {
            // æŸ¥è¯¢è¯¥ä¸»è¡¨ä¸‹çš„æ‰€æœ‰å­è¡¨æ•°æ®
            LambdaQueryWrapper<SalesLedgerProduct> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId);
            wrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)
                    .eq(SalesLedgerProduct::getType, salesLedgerProduct.getType());
            List<SalesLedgerProduct> productList = salesLedgerProductMapper.selectList(wrapper);
            // è°ƒç”¨é€šç”¨æ–¹æ³•更新主表金额
            updateMainContractAmount(
                    salesLedgerId,
                    productList,
                    SalesLedgerProduct::getTaxInclusiveTotalPrice,
                    salesLedgerMapper,
                    SalesLedger.class
            );
            if (salesLedgerProduct.getType() == 1) {
                // è°ƒç”¨é€šç”¨æ–¹æ³•更新主表金额
                updateMainContractAmount(
                        salesLedgerId,
                        productList,
                        SalesLedgerProduct::getTaxInclusiveTotalPrice,
                        salesLedgerMapper,
                        SalesLedger.class
                );
            } else {
                // è°ƒç”¨é€šç”¨æ–¹æ³•更新主表金额
                updateMainContractAmount(
                        salesLedgerId,
                        productList,
                        SalesLedgerProduct::getTaxInclusiveTotalPrice,
                        purchaseLedgerMapper,
                        PurchaseLedger.class
                );
            }
        }
        return result;
    }
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.pojo.Customer;
@@ -28,7 +29,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
@@ -52,11 +52,11 @@
@Slf4j
public class SalesLedgerServiceImpl extends ServiceImpl<SalesLedgerMapper, SalesLedger> implements ISalesLedgerService {
    private final  SalesLedgerMapper salesLedgerMapper;
    private final SalesLedgerMapper salesLedgerMapper;
    private final  CustomerMapper customerMapper;
    private final CustomerMapper customerMapper;
    private final  SalesLedgerProductMapper salesLedgerProductMapper;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    private final SalesLedgerFileMapper salesLedgerFileMapper;
@@ -92,14 +92,58 @@
        productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId());
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
        // 3. è½¬æ¢ DTO
        // 3.查询上传文件
        LambdaQueryWrapper<SalesLedgerFile> salesLedgerFileWrapper = new LambdaQueryWrapper<>();
        salesLedgerFileWrapper.eq(SalesLedgerFile::getLedgerId, salesLedger.getId());
        List<SalesLedgerFile> salesLedgerFiles = salesLedgerFileMapper.selectList(salesLedgerFileWrapper);
        // 4. è½¬æ¢ DTO
        SalesLedgerDto resultDto = new SalesLedgerDto();
        BeanUtils.copyProperties(salesLedger, resultDto);
        if (!products.isEmpty()) {
            resultDto.setHasChildren(true);
            resultDto.setProductData(products);
            resultDto.setSalesLedgerFiles(salesLedgerFiles);
        }
        return resultDto;
    }
    @Override
    public List<Map<String, Object>> getSalesNo() {
        LambdaQueryWrapper<SalesLedger> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(SalesLedger::getId, SalesLedger::getSalesContractNo);
        // èŽ·å–åŽŸå§‹æŸ¥è¯¢ç»“æžœ
        List<Map<String, Object>> result = salesLedgerMapper.selectMaps(queryWrapper);
        // å°†ä¸‹åˆ’线命名转换为驼峰命名
        return result.stream().map(map -> map.entrySet().stream()
                .collect(Collectors.toMap(
                        entry -> underlineToCamel(entry.getKey()),
                        Map.Entry::getValue))
        ).collect(Collectors.toList());
    }
    /**
     * ä¸‹åˆ’线命名转驼峰命名
     */
    private String underlineToCamel(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (c == '_') {
                if (++i < len) {
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            } else {
                sb.append(Character.toLowerCase(c));
            }
        }
        return sb.toString();
    }
    @Override
@@ -148,7 +192,7 @@
            // 4. å¤„理子表数据
            List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
            if (productList != null && !productList.isEmpty()) {
                handleSalesLedgerProducts(salesLedger.getId(), productList);
                handleSalesLedgerProducts(salesLedger.getId(), productList,salesLedgerDto.getType());
                updateMainContractAmount(
                        salesLedger.getId(),
                        productList,
@@ -197,7 +241,8 @@
            // æŸ¥è¯¢ä¸´æ—¶æ–‡ä»¶è®°å½•
            TempFile tempFile = tempFileMapper.selectById(tempFileId);
            if (tempFile == null) {
                throw new FileNotFoundException("临时文件不存在: " + tempFileId);
                log.warn("临时文件不存在,跳过处理: {}", tempFileId);
                continue;
            }
            // æž„建正式文件名(包含业务ID和时间戳,避免冲突)
@@ -223,8 +268,8 @@
                // æ›´æ–°æ–‡ä»¶è®°å½•(关联到业务ID)
                SalesLedgerFile fileRecord = new SalesLedgerFile();
                fileRecord.setLedgerId(businessId);
                fileRecord.setFileName(originalFilename);
                fileRecord.setFilePath(formalFilePath.toString());
                fileRecord.setName(originalFilename);
                fileRecord.setUrl(formalFilePath.toString());
                fileRecord.setCreateTime(LocalDateTime.now());
                salesLedgerFileMapper.insert(fileRecord);
@@ -241,7 +286,7 @@
    }
    private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products) {
    private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products,Integer type) {
        // æŒ‰ID分组,区分新增和更新的记录
        Map<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream()
                .peek(p -> p.setSalesLedgerId(salesLedgerId))
@@ -253,12 +298,14 @@
        // æ‰§è¡Œæ›´æ–°æ“ä½œ
        if (!updateList.isEmpty()) {
            for (SalesLedgerProduct product : updateList) {
                product.setType(type);
                salesLedgerProductMapper.updateById(product);
            }
        }
        // æ‰§è¡Œæ’入操作
        if (!insertList.isEmpty()) {
            for (SalesLedgerProduct salesLedgerProduct : insertList) {
                salesLedgerProduct.setType(type);
                salesLedgerProductMapper.insert(salesLedgerProduct);
            }
        }
src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -9,4 +9,7 @@
        FROM sales_ledger
        WHERE SUBSTR(sales_contract_no, 1, 8) = #{datePart}
    </select>
    <select id="getSalesNo" resultType="com.ruoyi.sales.pojo.SalesLedger">
    </select>
</mapper>