昨天 b17d24985527421ee9df504af8eccf24cf1aa7f3
refactor(invoice): 重构开票登记导出功能

- 移除 InvoiceRegisAndProductExcelDto 类
- 更新 InvoiceRegistrationController 中导出方法参数类型
- 修改 InvoiceRegistrationMapper 移除相关查询方法
- 删除 InvoiceRegistrationMapper.xml 中的 Excel 查询 SQL
- 更新 InvoiceRegistrationService 接口参数类型
- 在 InvoiceRegistrationServiceImpl 中替换导出实现逻辑
- 添加 SalesLedgerDto 的 ids 字段用于指定导出范围
- 在 SalesLedgerMapper.xml 中添加 ID 集合查询条件
- 新增 InvoiceRegistrationExportVo 作为导出对象
- 添加文档说明开票登记导出功能的使用方式
已删除1个文件
已添加2个文件
已修改8个文件
291 ■■■■■ 文件已修改
.gitignore 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/invoice_registration_export.md 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/InvoiceRegistrationController.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesLedgerDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/excel/InvoiceRegisAndProductExcelDto.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/excel/InvoiceRegistrationExportVo.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/mapper/InvoiceRegistrationMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/InvoiceRegistrationService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java 51 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/InvoiceRegistrationMapper.xml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -18,6 +18,7 @@
.project
.settings
.springBeans
.claude
### IntelliJ IDEA ###
.idea
docs/invoice_registration_export.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
# å¼€ç¥¨ç™»è®°åˆ—表导出
## æ¶‰åŠé¡µé¢
- é”€å”®ç®¡ç† â†’ å¼€ç¥¨ç™»è®°ï¼ˆ`src/views/salesManagement/invoiceRegistration/index.vue`)
## API
| æ–¹æ³• | è·¯å¾„ | è¯´æ˜Ž |
|------|------|------|
| POST | /invoiceRegistration/export | å¯¼å‡ºå¼€ç¥¨ç™»è®°åˆ—表(与页面列表口径一致) |
**请求参数(form è¡¨å•):**
导出范围规则:**勾选了行则按勾选导出(传 ids);未勾选导出全部数据(不传参数)**。
| å‚æ•° | ç±»åž‹ | å¿…å¡« | è¯´æ˜Ž |
|------|------|------|------|
| ids | List<Long> | å¦ | å‹¾é€‰çš„销售台账 ID é›†åˆï¼Œform åºåˆ—化形如 `ids[0]=1&ids[1]=2`;传了则仅导出这些行,不传导出全部 |
**响应:** Excel äºŒè¿›åˆ¶æµï¼ˆblob),文件名建议 `开票登记信息.xlsx`,列固定为:
| åˆ—名 | è¯´æ˜Ž |
|------|------|
| é”€å”®åˆåŒå· | sales_contract_no |
| å®¢æˆ·åˆåŒå· | customer_contract_no |
| å®¢æˆ·åç§° | customer_name |
| åˆåŒé‡‘额 | sales_ledger.contract_amount |
| å·²å¼€ç¥¨é‡‘额 | å¼€ç¥¨å°è´¦ invoice_ledger æ±‡æ€»ï¼Œå£å¾„同列表页 |
| æœªå¼€ç¥¨é‡‘额 | åˆåŒé‡‘额 - å·²å¼€ç¥¨é‡‘额 |
## å‰ç«¯ä¿®æ”¹ç‚¹
### 1. æœç´¢åŒºæ–°å¢žå¯¼å‡ºæŒ‰é’®
```html
<el-form-item>
  <el-button type="primary" @click="handleQuery"> æœç´¢ </el-button>
  <el-button @click="resetForm"> é‡ç½® </el-button>
  <el-button @click="handleOut" type="primary">导出</el-button>
</el-form-item>
```
### 2. å¯¼å‡ºæ–¹æ³•
```js
// å¯¼å‡ºï¼šå‹¾é€‰åˆ™å¯¼å‡ºé€‰ä¸­è¡Œï¼Œæœªå‹¾é€‰å¯¼å‡ºå…¨éƒ¨
const handleOut = () => {
  const exportIds = selectedRows.value.map((item) => item.id);
  const confirmMsg = exportIds.length
    ? `已选中 ${exportIds.length} æ¡æ•°æ®ï¼Œå°†å¯¼å‡ºé€‰ä¸­å†…容,是否确认?`
    : "未选中数据,将导出全部数据,是否确认?";
  ElMessageBox.confirm(confirmMsg, "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      const params = exportIds.length ? { ids: exportIds } : {};
      proxy.download("/invoiceRegistration/export", params, "开票登记信息.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
```
## æ³¨æ„äº‹é¡¹
- æŽ¥å£ä¸º POST(form è¡¨å•),使用项目内置 `proxy.download` å³å¯ï¼Œä¸è¦æŒ‰ GET è°ƒç”¨ã€‚
- å¯¼å‡ºä¸Žé¡µé¢æœç´¢æ¡ä»¶æ— å…³ï¼šå‹¾é€‰å¯¼é€‰ä¸­ï¼Œä¸å‹¾é€‰å¯¼å…¨éƒ¨ã€‚
- åˆ—表页数据源为 `/sales/ledger/listPage`,导出与其口径一致;接口路径不变(`/invoiceRegistration/export`),仅返回列内容由原来的"开票登记+产品明细"改为合同维度 6 åˆ—。
src/main/java/com/ruoyi/sales/controller/InvoiceRegistrationController.java
@@ -86,10 +86,10 @@
    /**
     * å¼€ç¥¨ç™»è®°å¯¼å‡º
     * @param response
     * @param invoiceRegistrationDto
     * @param salesLedgerDto
     */
    @PostMapping("/export")
    public void invoiceRegistrationExport(HttpServletResponse response, InvoiceRegistrationDto invoiceRegistrationDto) {
        invoiceRegistrationService.invoiceRegistrationExport(response, invoiceRegistrationDto);
    public void invoiceRegistrationExport(HttpServletResponse response, SalesLedgerDto salesLedgerDto) {
        invoiceRegistrationService.invoiceRegistrationExport(response, salesLedgerDto);
    }
}
src/main/java/com/ruoyi/sales/dto/SalesLedgerDto.java
@@ -54,4 +54,7 @@
    @ApiModelProperty(value = "付款方式")
    private String paymentMethod;
    @ApiModelProperty(value = "指定导出的销售台账ID集合")
    private List<Long> ids;
}
src/main/java/com/ruoyi/sales/excel/InvoiceRegisAndProductExcelDto.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/sales/excel/InvoiceRegistrationExportVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.ruoyi.sales.excel;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
/**
 * å¼€ç¥¨ç™»è®°åˆ—表导出对象
 */
@Data
public class InvoiceRegistrationExportVo {
    @Excel(name = "销售合同号")
    private String salesContractNo;
    @Excel(name = "客户合同号")
    private String customerContractNo;
    @Excel(name = "客户名称")
    private String customerName;
    @Excel(name = "合同金额")
    private BigDecimal contractAmount;
    @Excel(name = "已开票金额")
    private BigDecimal invoiceTotal;
    @Excel(name = "未开票金额")
    private BigDecimal noInvoiceAmountTotal;
}
src/main/java/com/ruoyi/sales/mapper/InvoiceRegistrationMapper.java
@@ -4,11 +4,8 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.sales.dto.InvoiceRegistrationDto;
import com.ruoyi.sales.excel.InvoiceRegisAndProductExcelDto;
import com.ruoyi.sales.pojo.InvoiceRegistration;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface InvoiceRegistrationMapper extends BaseMapper<InvoiceRegistration> {
@@ -19,10 +16,4 @@
     * @return
     */
    IPage<InvoiceRegistrationDto> invoiceRegistrationListPage(Page page, @Param("invoiceRegistrationDto") InvoiceRegistrationDto invoiceRegistrationDto);
    /**
     * å¼€ç¥¨ç™»è®°å¯¼å‡ºæ•°æ®æŸ¥è¯¢
     * @return
     */
    List<InvoiceRegisAndProductExcelDto> invoiceRegisAndProductExcelDtoList();
}
src/main/java/com/ruoyi/sales/service/InvoiceRegistrationService.java
@@ -59,7 +59,7 @@
    /**
     * å¼€ç¥¨ç™»è®°å¯¼å‡º
     * @param response
     * @param invoiceRegistrationDto
     * @param salesLedgerDto
     */
    void invoiceRegistrationExport(HttpServletResponse response, InvoiceRegistrationDto invoiceRegistrationDto);
    void invoiceRegistrationExport(HttpServletResponse response, SalesLedgerDto salesLedgerDto);
}
src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java
@@ -7,14 +7,16 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.sales.dto.InvoiceLedgerDto;
import com.ruoyi.sales.dto.InvoiceRegistrationDto;
import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
import com.ruoyi.sales.dto.SalesLedgerDto;
import com.ruoyi.sales.excel.InvoiceRegisAndProductExcelDto;
import com.ruoyi.sales.excel.InvoiceRegistrationExportVo;
import com.ruoyi.sales.mapper.*;
import com.ruoyi.sales.pojo.InvoiceLedger;
import com.ruoyi.sales.pojo.InvoiceRegistration;
import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.service.InvoiceRegistrationService;
import org.apache.commons.collections4.CollectionUtils;
@@ -26,7 +28,10 @@
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@@ -43,6 +48,9 @@
    @Autowired
    private InvoiceLedgerMapper invoiceLedgerMapper;
    @Autowired
    private SalesLedgerMapper salesLedgerMapper;
    /**
     * å¼€ç¥¨ç™»è®°è®°å½•新增
@@ -178,13 +186,44 @@
    /**
     * å¼€ç¥¨ç™»è®°å¯¼å‡º
     * å¯¼å‡ºåˆ—:销售合同号、客户合同号、客户名称、合同金额、已开票金额、未开票金额
     * å·²å¼€ç¥¨/未开票金额口径与 /sales/ledger/listPage é¡µé¢ä¸€è‡´
     * @param response
     * @param invoiceRegistrationDto
     * @param salesLedgerDto
     */
    @Override
    public void invoiceRegistrationExport(HttpServletResponse response, InvoiceRegistrationDto invoiceRegistrationDto) {
        List<InvoiceRegisAndProductExcelDto> invoiceRegisAndProductExcelDtoList = invoiceRegistrationMapper.invoiceRegisAndProductExcelDtoList();
        ExcelUtil<InvoiceRegisAndProductExcelDto> util = new ExcelUtil<InvoiceRegisAndProductExcelDto>(InvoiceRegisAndProductExcelDto.class);
        util.exportExcel(response, invoiceRegisAndProductExcelDtoList, "开票登记信息");
    public void invoiceRegistrationExport(HttpServletResponse response, SalesLedgerDto salesLedgerDto) {
        Page page = new Page();
        page.setCurrent(-1);
        page.setSize(-1);
        IPage<SalesLedger> iPage = salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto);
        List<SalesLedger> records = iPage.getRecords();
        // æŒ‰é”€å”®å°è´¦æ±‡æ€»å·²å¼€ç¥¨é‡‘额
        Map<Integer, BigDecimal> invoicedMap = new HashMap<>();
        List<Long> salesLedgerIds = records.stream().map(SalesLedger::getId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(salesLedgerIds)) {
            List<InvoiceLedgerDto> invoiceLedgerDtoList = invoiceLedgerMapper.invoicedTotal(salesLedgerIds);
            for (InvoiceLedgerDto invoiceLedgerDto : invoiceLedgerDtoList) {
                invoicedMap.put(invoiceLedgerDto.getSalesLedgerId(), invoiceLedgerDto.getInvoiceTotal());
            }
        }
        List<InvoiceRegistrationExportVo> exportList = new ArrayList<>();
        for (SalesLedger record : records) {
            BigDecimal contractAmount = record.getContractAmount() == null ? BigDecimal.ZERO : record.getContractAmount();
            BigDecimal invoiceTotal = invoicedMap.getOrDefault(record.getId().intValue(), BigDecimal.ZERO);
            BigDecimal noInvoiceAmountTotal = contractAmount.subtract(invoiceTotal);
            InvoiceRegistrationExportVo exportVo = new InvoiceRegistrationExportVo();
            exportVo.setSalesContractNo(record.getSalesContractNo());
            exportVo.setCustomerContractNo(record.getCustomerContractNo());
            exportVo.setCustomerName(record.getCustomerName());
            exportVo.setContractAmount(contractAmount);
            exportVo.setInvoiceTotal(invoiceTotal);
            exportVo.setNoInvoiceAmountTotal(noInvoiceAmountTotal);
            exportList.add(exportVo);
        }
        ExcelUtil<InvoiceRegistrationExportVo> util = new ExcelUtil<InvoiceRegistrationExportVo>(InvoiceRegistrationExportVo.class);
        util.exportExcel(response, exportList, "开票登记信息");
    }
}
src/main/resources/mapper/sales/InvoiceRegistrationMapper.xml
@@ -34,39 +34,4 @@
        ) T4 ON T1.id = T4.invoice_registration_id
    </select>
    <select id="invoiceRegisAndProductExcelDtoList" resultType="com.ruoyi.sales.excel.InvoiceRegisAndProductExcelDto">
        SELECT
            T1.id              ,
            T1.sales_ledger_id   ,
            T1.sales_contract_no ,
            T1.customer_id       ,
            T1.salesman          ,
            T1.project_name      ,
            T1.create_time       ,
            T1.create_user       ,
            T1.update_time       ,
            T1.update_user       ,
            T1.tenant_id,
            T2.customer_contract_no,
            T3.customer_name,
            T2.contract_amount,
            T4.product_category,
            T4.specification_model,
            T4.unit,
            T4.quantity,
            T4.tax_rate,
            T4.tax_inclusive_unit_price,
            T4.tax_inclusive_total_price,
            T4.tax_exclusive_total_price,
            T4.invoice_type,
            T4.invoice_num,
            T4.invoice_amount,
            T4.no_invoice_num,
            T4.no_invoice_amount
        FROM invoice_registration T1
                 JOIN sales_ledger T2 ON T1.sales_ledger_id = T2.id
                 JOIN customer T3 ON T1.customer_id = T3.id
                JOIN invoice_registration_product T4 ON T1.id = T4.invoice_registration_id
        ORDER BY T1.id ASC
    </select>
</mapper>
src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -81,6 +81,12 @@
            <if test="salesLedgerDto.entryDateEnd != null and salesLedgerDto.entryDateEnd != '' ">
                AND  T1.entry_date &lt;= DATE_FORMAT(#{salesLedgerDto.entryDateEnd},'%Y-%m-%d')
            </if>
            <if test="salesLedgerDto.ids != null and salesLedgerDto.ids.size() > 0">
                AND T1.id IN
                <foreach collection="salesLedgerDto.ids" item="item" open="(" close=")" separator=",">
                    #{item}
                </foreach>
            </if>
        </where>
    </select>
</mapper>