Переглянути джерело

feat(bill): 优化发票开票功能支持多对账单合并

- 更新 InvoiceInfoController 中的 import 顺序和依赖
- 修改 StatementInvoiceService 接口中的 pcInsertByBo 方法返回类型从 Boolean 改为 Long
- 重构 PcStatementInvoiceController 的 add 方法返回新创建的发票 ID
- 调整 StatementInvoice 领域模型中 invoiceAmount 字段类型从 Long 改为 BigDecimal
- 重构 StatementInvoiceBo 和 StatementInvoiceVo 中的 invoiceAmount 字段类型
- 优化 StatementInvoiceServiceImpl 中的 PC 端开票逻辑,支持同一客户多个对账单合并开票
hurx 2 місяців тому
батько
коміт
d9c8580ed1
19 змінених файлів з 284 додано та 193 видалено
  1. 17 16
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/InvoiceInfoController.java
  2. 15 15
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementDetailController.java
  3. 16 21
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementInvoiceController.java
  4. 17 16
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementInvoiceDetailController.java
  5. 17 16
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementInvoiceProductController.java
  6. 15 14
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementOrderController.java
  7. 15 15
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementProductController.java
  8. 10 7
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/pc/PcStatementDetailController.java
  9. 3 2
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/pc/PcStatementInvoiceController.java
  10. 0 5
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/pc/PcStatementInvoiceDetailController.java
  11. 6 10
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/pc/PcStatementOrderController.java
  12. 7 7
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/pc/PcStatementProductController.java
  13. 5 6
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/domain/StatementDetail.java
  14. 8 6
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/domain/StatementInvoice.java
  15. 6 8
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/domain/bo/StatementInvoiceBo.java
  16. 2 7
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/domain/bo/StatementInvoiceDetailBo.java
  17. 2 1
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/domain/vo/StatementInvoiceVo.java
  18. 3 6
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/service/IStatementInvoiceService.java
  19. 120 15
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/service/impl/StatementInvoiceServiceImpl.java

+ 17 - 16
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/InvoiceInfoController.java

@@ -1,26 +1,27 @@
 package org.dromara.bill.controller;
 
-import java.util.List;
-
-import lombok.RequiredArgsConstructor;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.validation.annotation.Validated;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.common.mybatis.core.page.PageQuery;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.bill.domain.bo.InvoiceInfoBo;
+import org.dromara.bill.domain.vo.InvoiceInfoVo;
+import org.dromara.bill.service.IInvoiceInfoService;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.validate.AddGroup;
 import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
-import org.dromara.bill.domain.vo.InvoiceInfoVo;
-import org.dromara.bill.domain.bo.InvoiceInfoBo;
-import org.dromara.bill.service.IInvoiceInfoService;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 发票信息
@@ -65,7 +66,7 @@ public class InvoiceInfoController extends BaseController {
     @SaCheckPermission("bill:invoiceInfo:query")
     @GetMapping("/{id}")
     public R<InvoiceInfoVo> getInfo(@NotNull(message = "主键不能为空")
-                                     @PathVariable("id") Long id) {
+                                    @PathVariable("id") Long id) {
         return R.ok(invoiceInfoService.queryById(id));
     }
 

+ 15 - 15
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementDetailController.java

@@ -1,26 +1,26 @@
 package org.dromara.bill.controller;
 
-import java.util.List;
-
-import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.constraints.*;
-import cn.dev33.satoken.annotation.SaCheckPermission;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.validation.annotation.Validated;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.common.mybatis.core.page.PageQuery;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.bill.domain.bo.StatementDetailBo;
+import org.dromara.bill.domain.vo.StatementDetailVo;
+import org.dromara.bill.service.IStatementDetailService;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.validate.AddGroup;
 import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
-import org.dromara.bill.domain.vo.StatementDetailVo;
-import org.dromara.bill.domain.bo.StatementDetailBo;
-import org.dromara.bill.service.IStatementDetailService;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 对账单交易明细

+ 16 - 21
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementInvoiceController.java

@@ -1,32 +1,27 @@
 package org.dromara.bill.controller;
 
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
-import lombok.RequiredArgsConstructor;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
-import org.dromara.bill.domain.StatementInvoiceProduct;
-import org.dromara.bill.domain.bo.StatementOrderBo;
-import org.dromara.bill.domain.vo.StatementInvoiceProductVo;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.validation.annotation.Validated;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.common.mybatis.core.page.PageQuery;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.bill.domain.bo.StatementInvoiceBo;
+import org.dromara.bill.domain.vo.StatementInvoiceVo;
+import org.dromara.bill.service.IStatementInvoiceService;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.validate.AddGroup;
 import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
-import org.dromara.bill.domain.vo.StatementInvoiceVo;
-import org.dromara.bill.domain.bo.StatementInvoiceBo;
-import org.dromara.bill.service.IStatementInvoiceService;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 销售发票主

+ 17 - 16
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementInvoiceDetailController.java

@@ -1,26 +1,27 @@
 package org.dromara.bill.controller;
 
-import java.util.List;
-
-import lombok.RequiredArgsConstructor;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.validation.annotation.Validated;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.common.mybatis.core.page.PageQuery;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.bill.domain.bo.StatementInvoiceDetailBo;
+import org.dromara.bill.domain.vo.StatementInvoiceDetailVo;
+import org.dromara.bill.service.IStatementInvoiceDetailService;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.validate.AddGroup;
 import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
-import org.dromara.bill.domain.vo.StatementInvoiceDetailVo;
-import org.dromara.bill.domain.bo.StatementInvoiceDetailBo;
-import org.dromara.bill.service.IStatementInvoiceDetailService;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 销售发票明细
@@ -65,7 +66,7 @@ public class StatementInvoiceDetailController extends BaseController {
     @SaCheckPermission("bill:statementInvoiceDetail:query")
     @GetMapping("/{id}")
     public R<StatementInvoiceDetailVo> getInfo(@NotNull(message = "主键不能为空")
-                                     @PathVariable("id") Long id) {
+                                               @PathVariable("id") Long id) {
         return R.ok(statementInvoiceDetailService.queryById(id));
     }
 

+ 17 - 16
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementInvoiceProductController.java

@@ -1,26 +1,27 @@
 package org.dromara.bill.controller;
 
-import java.util.List;
-
-import lombok.RequiredArgsConstructor;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.validation.annotation.Validated;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.common.mybatis.core.page.PageQuery;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.bill.domain.bo.StatementInvoiceProductBo;
+import org.dromara.bill.domain.vo.StatementInvoiceProductVo;
+import org.dromara.bill.service.IStatementInvoiceProductService;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.validate.AddGroup;
 import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
-import org.dromara.bill.domain.vo.StatementInvoiceProductVo;
-import org.dromara.bill.domain.bo.StatementInvoiceProductBo;
-import org.dromara.bill.service.IStatementInvoiceProductService;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 销售发票商品
@@ -65,7 +66,7 @@ public class StatementInvoiceProductController extends BaseController {
     @SaCheckPermission("bill:statementInvoiceProduct:query")
     @GetMapping("/{id}")
     public R<StatementInvoiceProductVo> getInfo(@NotNull(message = "主键不能为空")
-                                     @PathVariable("id") Long id) {
+                                                @PathVariable("id") Long id) {
         return R.ok(statementInvoiceProductService.queryById(id));
     }
 

+ 15 - 14
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementOrderController.java

@@ -1,29 +1,30 @@
 package org.dromara.bill.controller;
 
-import java.util.List;
-
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
-import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.constraints.*;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.bill.domain.bo.StatementOrderBo;
 import org.dromara.bill.domain.dto.StatementOrderItem;
 import org.dromara.bill.domain.vo.StatementDetailVo;
+import org.dromara.bill.domain.vo.StatementOrderVo;
 import org.dromara.bill.domain.vo.StatementProductVo;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.validation.annotation.Validated;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.bill.service.IStatementOrderService;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.validate.AddGroup;
 import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
-import org.dromara.bill.domain.vo.StatementOrderVo;
-import org.dromara.bill.domain.bo.StatementOrderBo;
-import org.dromara.bill.service.IStatementOrderService;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 对账单主

+ 15 - 15
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/StatementProductController.java

@@ -1,26 +1,26 @@
 package org.dromara.bill.controller;
 
-import java.util.List;
-
-import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.constraints.*;
-import cn.dev33.satoken.annotation.SaCheckPermission;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.validation.annotation.Validated;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.common.mybatis.core.page.PageQuery;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.bill.domain.bo.StatementProductBo;
+import org.dromara.bill.domain.vo.StatementProductVo;
+import org.dromara.bill.service.IStatementProductService;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.validate.AddGroup;
 import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
-import org.dromara.bill.domain.vo.StatementProductVo;
-import org.dromara.bill.domain.bo.StatementProductBo;
-import org.dromara.bill.service.IStatementProductService;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 对账单商品明细

+ 10 - 7
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/pc/PcStatementDetailController.java

@@ -1,19 +1,22 @@
 package org.dromara.bill.controller.pc;
 
+import jakarta.validation.constraints.NotNull;
 import lombok.RequiredArgsConstructor;
-import jakarta.validation.constraints.*;
-import org.dromara.common.core.domain.R;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.satoken.utils.LoginHelper;
-import org.dromara.common.web.core.BaseController;
 import org.dromara.bill.domain.bo.StatementDetailBo;
 import org.dromara.bill.domain.vo.StatementDetailVo;
 import org.dromara.bill.domain.vo.StatementOrderVo;
 import org.dromara.bill.service.IStatementDetailService;
 import org.dromara.bill.service.IStatementOrderService;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 /**
  * PC端 - 对账单明细管理

+ 3 - 2
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/pc/PcStatementInvoiceController.java

@@ -62,9 +62,10 @@ public class PcStatementInvoiceController extends BaseController {
 
     /*pc端客户申请开票*/
     @PostMapping()
-    public R<Void> add(@Validated(AddGroup.class) @RequestBody StatementInvoiceBo bo) {
+    public R<Long> add(@Validated(AddGroup.class) @RequestBody StatementInvoiceBo bo) {
         Long customerId = LoginHelper.getLoginUser().getCustomerId();
         bo.setCustomerId(customerId);
-        return toAjax(statementInvoiceService.pcInsertByBo(bo));
+        Long insert = statementInvoiceService.pcInsertByBo(bo);
+        return R.ok(insert);
     }
 }

+ 0 - 5
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/pc/PcStatementInvoiceDetailController.java

@@ -2,14 +2,9 @@ package org.dromara.bill.controller.pc;
 
 import jakarta.validation.constraints.NotNull;
 import lombok.RequiredArgsConstructor;
-import org.dromara.bill.domain.StatementInvoice;
-import org.dromara.bill.domain.StatementInvoiceDetail;
-import org.dromara.bill.domain.bo.StatementDetailBo;
 import org.dromara.bill.domain.bo.StatementInvoiceDetailBo;
-import org.dromara.bill.domain.vo.StatementDetailVo;
 import org.dromara.bill.domain.vo.StatementInvoiceDetailVo;
 import org.dromara.bill.domain.vo.StatementInvoiceVo;
-import org.dromara.bill.domain.vo.StatementOrderVo;
 import org.dromara.bill.service.IStatementInvoiceDetailService;
 import org.dromara.bill.service.IStatementInvoiceService;
 import org.dromara.common.core.domain.R;

+ 6 - 10
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/pc/PcStatementOrderController.java

@@ -1,28 +1,24 @@
 package org.dromara.bill.controller.pc;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import jakarta.validation.constraints.NotNull;
 import lombok.RequiredArgsConstructor;
-import jakarta.validation.constraints.*;
+import org.dromara.bill.domain.StatementOrder;
+import org.dromara.bill.domain.bo.StatementOrderBo;
+import org.dromara.bill.domain.vo.StatementDetailVo;
+import org.dromara.bill.domain.vo.StatementOrderVo;
+import org.dromara.bill.service.IStatementOrderService;
 import org.dromara.common.core.domain.R;
-import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.log.annotation.Log;
 import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.web.core.BaseController;
-import org.dromara.bill.domain.StatementOrder;
-import org.dromara.bill.domain.bo.StatementOrderBo;
-import org.dromara.bill.domain.vo.StatementOrderVo;
-import org.dromara.bill.domain.vo.StatementDetailVo;
-import org.dromara.bill.service.IStatementOrderService;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.Arrays;
-import java.util.List;
 
 /**
  * PC端 - 对账单管理

+ 7 - 7
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/controller/pc/PcStatementProductController.java

@@ -1,19 +1,19 @@
 package org.dromara.bill.controller.pc;
 
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import jakarta.validation.constraints.NotNull;
 import lombok.RequiredArgsConstructor;
-import jakarta.validation.constraints.*;
+import org.dromara.bill.domain.bo.StatementProductBo;
+import org.dromara.bill.domain.dto.StatementOrderItem;
+import org.dromara.bill.domain.vo.StatementOrderVo;
+import org.dromara.bill.domain.vo.StatementProductVo;
+import org.dromara.bill.service.IStatementOrderService;
+import org.dromara.bill.service.IStatementProductService;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.web.core.BaseController;
-import org.dromara.bill.domain.bo.StatementProductBo;
-import org.dromara.bill.domain.dto.StatementOrderItem;
-import org.dromara.bill.domain.vo.StatementProductVo;
-import org.dromara.bill.domain.vo.StatementOrderVo;
-import org.dromara.bill.service.IStatementProductService;
-import org.dromara.bill.service.IStatementOrderService;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 

+ 5 - 6
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/domain/StatementDetail.java

@@ -1,17 +1,16 @@
 package org.dromara.bill.domain;
 
-import org.dromara.common.tenant.core.TenantEntity;
-import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
 
+import java.io.Serial;
 import java.math.BigDecimal;
 import java.util.Date;
 
-import com.fasterxml.jackson.annotation.JsonFormat;
-
-import java.io.Serial;
-
 /**
  * 对账单交易明细对象 statement_detail
  *

+ 8 - 6
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/domain/StatementInvoice.java

@@ -1,13 +1,15 @@
 package org.dromara.bill.domain;
 
-import org.dromara.common.tenant.core.TenantEntity;
-import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
-import java.util.Date;
-import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.common.tenant.core.TenantEntity;
 
 import java.io.Serial;
+import java.math.BigDecimal;
+import java.util.Date;
 
 /**
  * 销售发票主对象 statement_invoice
@@ -24,7 +26,7 @@ public class StatementInvoice extends TenantEntity {
     private static final long serialVersionUID = 1L;
 
     /**
-     * 
+     *
      */
     @TableId(value = "id")
     private Long id;
@@ -52,7 +54,7 @@ public class StatementInvoice extends TenantEntity {
     /**
      * 发票金额
      */
-    private Long invoiceAmount;
+    private BigDecimal invoiceAmount;
 
     /**
      * 发票状态

+ 6 - 8
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/domain/bo/StatementInvoiceBo.java

@@ -1,20 +1,18 @@
 package org.dromara.bill.domain.bo;
 
-import org.dromara.bill.domain.StatementInvoice;
-import org.dromara.common.mybatis.core.domain.BaseEntity;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.core.validate.EditGroup;
 import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
-import jakarta.validation.constraints.*;
+import org.dromara.bill.domain.StatementInvoice;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
 
+import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
 import java.util.Set;
 
-import com.fasterxml.jackson.annotation.JsonFormat;
-
 /**
  * 销售发票主业务对象 statement_invoice
  *
@@ -54,7 +52,7 @@ public class StatementInvoiceBo extends BaseEntity {
     /**
      * 发票金额
      */
-    private Long invoiceAmount;
+    private BigDecimal invoiceAmount;
 
     /**
      * 发票状态

+ 2 - 7
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/domain/bo/StatementInvoiceDetailBo.java

@@ -1,19 +1,14 @@
 package org.dromara.bill.domain.bo;
 
-import org.dromara.bill.domain.StatementInvoiceDetail;
-import org.dromara.common.mybatis.core.domain.BaseEntity;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.core.validate.EditGroup;
 import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
-import jakarta.validation.constraints.*;
+import org.dromara.bill.domain.StatementInvoiceDetail;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
 
 import java.math.BigDecimal;
 import java.util.Date;
 
-import com.fasterxml.jackson.annotation.JsonFormat;
-
 /**
  * 销售发票明细业务对象 statement_invoice_detail
  *

+ 2 - 1
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/domain/vo/StatementInvoiceVo.java

@@ -1,5 +1,6 @@
 package org.dromara.bill.domain.vo;
 
+import java.math.BigDecimal;
 import java.util.Date;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
@@ -66,7 +67,7 @@ public class StatementInvoiceVo implements Serializable {
      * 发票金额
      */
     @ExcelProperty(value = "发票金额")
-    private Long invoiceAmount;
+    private BigDecimal invoiceAmount;
 
     /**
      * 发票状态

+ 3 - 6
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/service/IStatementInvoiceService.java

@@ -2,16 +2,13 @@ package org.dromara.bill.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import org.dromara.bill.domain.StatementInvoice;
-import org.dromara.bill.domain.bo.StatementOrderBo;
-import org.dromara.bill.domain.vo.StatementInvoiceProductVo;
-import org.dromara.bill.domain.vo.StatementInvoiceVo;
 import org.dromara.bill.domain.bo.StatementInvoiceBo;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.bill.domain.vo.StatementInvoiceVo;
 import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
 
 import java.util.Collection;
 import java.util.List;
-import java.util.Set;
 
 /**
  * 销售发票主Service接口
@@ -60,7 +57,7 @@ public interface IStatementInvoiceService extends IService<StatementInvoice> {
      * @param bo 销售发票主
      * @return 是否新增成功
      */
-    Boolean pcInsertByBo(StatementInvoiceBo bo);
+    Long pcInsertByBo(StatementInvoiceBo bo);
 
     /**
      * 修改销售发票主

+ 120 - 15
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/service/impl/StatementInvoiceServiceImpl.java

@@ -24,9 +24,11 @@ import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.redis.utils.SequenceUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -51,6 +53,10 @@ public class StatementInvoiceServiceImpl extends ServiceImpl<StatementInvoiceMap
 
     private final StatementOrderMapper statementOrderMapper;
 
+    private final StatementDetailMapper statementDetailMapper;
+
+    private final StatementProductMapper statementProductMapper;
+
 
     /**
      * 查询销售发票主
@@ -187,33 +193,132 @@ public class StatementInvoiceServiceImpl extends ServiceImpl<StatementInvoiceMap
     }
 
     /**
-     * pc新增销售发票主
+     * PC端申请开票:支持同一客户的多个对账单合并申请
      *
-     * @param bo 销售发票主
-     * @return 是否新增成功
+     * @param bo 开票申请参数(需包含 statementOrderIds)
+     * @return 创建成功的发票主单ID,或抛出异常
      */
     @Override
-    public Boolean pcInsertByBo(StatementInvoiceBo bo) {
-        // 1. 设置发票编号
+    @Transactional(rollbackFor = Exception.class)
+    public Long pcInsertByBo(StatementInvoiceBo bo) {
+        Set<Long> statementOrderIds = bo.getStatementOrderIds();
+        if (CollectionUtil.isEmpty(statementOrderIds)) {
+            throw new IllegalArgumentException("请选择要开票的对账单");
+        }
+
+        // 1. 批量查询所有对账单
+        List<StatementOrder> statementOrders = statementOrderMapper.selectBatchIds(statementOrderIds);
+        if (statementOrders.size() != statementOrderIds.size()) {
+            throw new RuntimeException("部分对账单不存在或已被删除");
+        }
+
+        // 2. 校验是否同一客户
+        String customerNo = statementOrders.get(0).getCustomerNo();
+        String customerName = statementOrders.get(0).getCustomerName();
+        boolean sameCustomer = statementOrders.stream()
+            .allMatch(so -> customerNo.equals(so.getCustomerNo()));
+        if (!sameCustomer) {
+            throw new RuntimeException("所选对账单不属于同一客户,无法合并开票");
+        }
+
+        // 3. 计算总金额
+        BigDecimal totalAmount = statementOrders.stream()
+            .map(StatementOrder::getAmount)
+            .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+        // 4. 构建主单
+        bo.setCustomerName(customerName);
+        bo.setCustomerNo(customerNo);
+        bo.setInvoiceAmount(totalAmount);
+        bo.setInvoiceStatus(InvoiceStatus.NOT_INVOICED.getCode()); // 待确认
+
         String statementInvoiceNo = SequenceUtils.generateOrderCode("BL");
         bo.setStatementInvoiceNo(statementInvoiceNo);
 
-        // 2. 设置初始状态为“待确认”
-        bo.setInvoiceStatus(InvoiceStatus.NOT_INVOICED.getCode()); // 假设 PENDING = "0" 或 "pending"
-
-        // 3. 转换并保存主表
         StatementInvoice entity = MapstructUtils.convert(bo, StatementInvoice.class);
         validEntityBeforeSave(entity);
-        boolean success = this.save(entity);
+        boolean saved = this.save(entity);
+        if (!saved) {
+            throw new RuntimeException("保存开票申请主单失败");
+        }
 
-        if (success) {
-            bo.setId(entity.getId());
-            // 4. 保存明细、商品、发票信息(不含真实发票)
-            saveDetailsAndProductsAndInvoiceInfos(bo);
+        // 5. 批量查询所有明细和商品(按 statementOrderId + orderId)
+        List<StatementDetail> allDetails = statementDetailMapper.selectList(
+            new LambdaQueryWrapper<StatementDetail>()
+                .in(StatementDetail::getStatementOrderId, statementOrderIds)
+        );
+
+        // 构建明细和商品列表
+        List<StatementInvoiceDetailBo> detailBoList = new ArrayList<>();
+        List<StatementInvoiceProductBo> productBoList = new ArrayList<>();
+
+        // 提取所有 (statementOrderId, orderId) 组合用于查商品
+        Set<String> orderKeys = allDetails.stream()
+            .map(d -> d.getStatementOrderId() + "_" + d.getOrderId())
+            .collect(Collectors.toSet());
+
+        if (!orderKeys.isEmpty()) {
+            // 可考虑分页或分批,若数据量大
+            List<StatementProduct> allProducts = statementProductMapper.selectList(
+                new LambdaQueryWrapper<StatementProduct>()
+                    .in(StatementProduct::getStatementOrderId, statementOrderIds)
+            );
+
+            // 建立 product 映射:(statementOrderId, orderId) -> List<product>
+            Map<String, List<StatementProduct>> productMap = allProducts.stream()
+                .collect(Collectors.groupingBy(p ->
+                    p.getStatementOrderId() + "_" + p.getOrderId()
+                ));
+
+            // 构建明细和商品BO
+            for (StatementDetail detail : allDetails) {
+                StatementInvoiceDetailBo detailBo = new StatementInvoiceDetailBo();
+                detailBo.setStatementInvoiceId(entity.getId());
+                detailBo.setStatementInvoiceNo(entity.getStatementInvoiceNo());
+                detailBo.setStatementAmount(detail.getAmount());
+                detailBo.setOrderId(detail.getOrderId());
+                detailBo.setOrderNo(detail.getOrderNo());
+                detailBo.setOrderAmount(detail.getAmount());
+                detailBo.setOrderTime(detail.getOrderTime());
+                detailBo.setSigningDate(detail.getSigningDate());
+                detailBo.setUserId(LoginHelper.getUserId());
+                detailBo.setUserDeptId(LoginHelper.getDeptId());
+                detailBo.setStatementOrderId(detail.getStatementOrderId());
+                detailBo.setStatementOrderNo(detail.getStatementOrderNo());
+                detailBoList.add(detailBo);
+
+                // 添加对应商品
+                String key = detail.getStatementOrderId() + "_" + detail.getOrderId();
+                List<StatementProduct> products = productMap.get(key);
+                if (CollectionUtil.isNotEmpty(products)) {
+                    for (StatementProduct p : products) {
+                        StatementInvoiceProductBo productBo = new StatementInvoiceProductBo();
+                        productBo.setStatementInvoiceId(entity.getId());
+                        productBo.setStatementInvoiceNo(entity.getStatementInvoiceNo());
+                        productBo.setProductId(p.getProductId());
+                        productBo.setProductNo(p.getProductNo());
+                        productBo.setOrderId(p.getOrderId());
+                        productBo.setOrderNo(p.getOrderNo());
+                        productBo.setItemName(p.getItemName());
+                        productBo.setUnitId(p.getUnitId());
+                        productBo.setUnitName(p.getUnitName());
+                        productBo.setQuantity(p.getQuantity());
+                        productBo.setUnitPrice(p.getUnitPrice());
+                        productBoList.add(productBo);
+                    }
+                }
+            }
         }
 
+        // 6. 设置子表并保存
+        bo.setId(entity.getId());
+        bo.setDetailList(detailBoList);
+        bo.setProductList(productBoList);
+        // bo.setInvoiceList(null); // 申请阶段通常无真实发票信息
 
-        return success;
+        saveDetailsAndProductsAndInvoiceInfos(bo);
+
+        return entity.getId(); // 返回主单ID,便于前端跳转或提示
     }
 
     /**