已修改43个文件
已添加5个文件
1629 ■■■■ 文件已修改
src/main/java/com/ruoyi/common/config/IgnoreTableConfig.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysUserController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/mapper/SysDeptMapper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/service/ISysDeptService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/service/impl/SysDeptServiceImpl.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PaymentRegistrationController.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/TicketRegistrationController.java 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/dto/PaymentRegistrationDto.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/dto/TicketRegistrationDto.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/mapper/ProductRecordMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/pojo/PaymentRegistration.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/pojo/ProductRecord.java 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/pojo/TicketRegistration.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/IPaymentRegistrationService.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/IProductRecordService.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/ITicketRegistrationService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java 299 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 103 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/TicketRegistrationServiceImpl.java 115 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/ReceiptPaymentController.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/InvoiceLedgerDto.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/MonthlyAmountDto.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/ReceiptPaymentDto.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/mapper/InvoiceLedgerMapper.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/mapper/ReceiptPaymentMapper.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/ReceiptPayment.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/ReceiptPaymentService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/InvoiceLedgerServiceImpl.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/ReceiptPaymentServiceImpl.java 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-druid.yml 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/purchase/PaymentRegistrationMapper.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/InvoiceLedgerMapper.xml 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/InvoiceRegistrationProductMapper.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/ReceiptPaymentMapper.xml 133 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/system/SysDeptMapper.xml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/system/SysUserMapper.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/config/IgnoreTableConfig.java
@@ -29,7 +29,6 @@
        IGNORE_TABLES.add("sales_ledger_file");
        IGNORE_TABLES.add("temp_file");
        IGNORE_TABLES.add("common_file");
        IGNORE_TABLES.add("DepartmentHierarchy");
    }
}
src/main/java/com/ruoyi/project/system/controller/SysUserController.java
@@ -140,6 +140,11 @@
        }
        user.setCreateBy(getUsername());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        // æŸ¥è¯¢é¡¶å±‚部门父id做为租户tenant_id
        Long tenantId = deptService.maxLevelDeptId(user.getDeptId());
        if(tenantId != null){
            user.setTenantId(tenantId.intValue());
        }
        return toAjax(userService.insertUser(user));
    }
src/main/java/com/ruoyi/project/system/mapper/SysDeptMapper.java
@@ -115,4 +115,11 @@
     * @return ç»“æžœ
     */
    public int deleteDeptById(Long deptId);
    /**
     * æŸ¥è¯¢é¡¶å±‚部门id
     * @param deptId
     * @return
     */
    Long maxLevelDeptId(Long deptId);
}
src/main/java/com/ruoyi/project/system/service/ISysDeptService.java
@@ -121,4 +121,11 @@
     * @return ç»“æžœ
     */
    public int deleteDeptById(Long deptId);
    /**
     * æŸ¥è¯¢é¡¶å±‚部门id
     * @param deptId
     * @return
     */
    Long maxLevelDeptId(Long deptId);
}
src/main/java/com/ruoyi/project/system/service/impl/SysDeptServiceImpl.java
@@ -294,6 +294,16 @@
    }
    /**
     * æŸ¥è¯¢é¡¶å±‚部门id
     * @param deptId
     * @return
     */
    @Override
    public Long maxLevelDeptId(Long deptId) {
        return deptMapper.maxLevelDeptId(deptId);
    }
    /**
     * é€’归列表
     */
    private void recursionFn(List<SysDept> list, SysDept t)
src/main/java/com/ruoyi/purchase/controller/PaymentRegistrationController.java
@@ -1,5 +1,7 @@
package com.ruoyi.purchase.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.controller.BaseController;
@@ -13,17 +15,17 @@
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
 * ä»˜æ¬¾ç™»è®°Controller
 *
 *
 * @author ruoyi
 * @date 2025-05-15
 */
@RestController
@RequestMapping("/purchase/paymentRegistration")
public class PaymentRegistrationController extends BaseController
{
public class PaymentRegistrationController extends BaseController {
    @Autowired
    private IPaymentRegistrationService paymentRegistrationService;
@@ -32,8 +34,7 @@
     */
//    @PreAuthorize("@ss.hasPermi('system:registration:list')")
    @GetMapping("/list")
    public TableDataInfo list(PaymentRegistrationDto paymentRegistrationDto)
    {
    public TableDataInfo list(PaymentRegistrationDto paymentRegistrationDto) {
        startPage();
        List<PaymentRegistrationDto> list = paymentRegistrationService.selectPaymentRegistrationList(paymentRegistrationDto);
        return getDataTable(list);
@@ -55,8 +56,7 @@
     * èŽ·å–ä»˜æ¬¾ç™»è®°è¯¦ç»†ä¿¡æ¯
     */
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id)
    {
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(paymentRegistrationService.selectPaymentRegistrationById(id));
    }
@@ -65,8 +65,7 @@
     */
    @Log(title = "付款登记", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody PaymentRegistration paymentRegistration)
    {
    public AjaxResult add(@RequestBody PaymentRegistration paymentRegistration) {
        return toAjax(paymentRegistrationService.insertPaymentRegistration(paymentRegistration));
    }
@@ -75,8 +74,7 @@
     */
    @Log(title = "付款登记", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody PaymentRegistration paymentRegistration)
    {
    public AjaxResult edit(@RequestBody PaymentRegistration paymentRegistration) {
        return toAjax(paymentRegistrationService.updatePaymentRegistration(paymentRegistration));
    }
@@ -84,9 +82,8 @@
     * åˆ é™¤ä»˜æ¬¾ç™»è®°
     */
    @Log(title = "付款登记", businessType = BusinessType.DELETE)
    @DeleteMapping("/del")
    public AjaxResult remove(@RequestBody Long[] ids)
    {
    @DeleteMapping("/del")
    public AjaxResult remove(@RequestBody Long[] ids) {
        return toAjax(paymentRegistrationService.deletePaymentRegistrationByIds(ids));
    }
@@ -94,8 +91,7 @@
     * èŽ·å–ä»˜æ¬¾ç™»è®°è¯¦ç»†ä¿¡æ¯
     */
    @GetMapping(value = "/byPurchaseId/{id}")
    public AjaxResult getPurchaseInfo(@PathVariable("id") Long id)
    {
    public AjaxResult getPurchaseInfo(@PathVariable("id") Long id) {
        return success(paymentRegistrationService.selectPaymentRegistrationByPurchaseId(id));
    }
@@ -103,8 +99,18 @@
     * èŽ·å–ä»˜æ¬¾ç™»è®°è¯¦ç»†ä¿¡æ¯
     */
    @GetMapping(value = "/paymentLedgerList")
    public AjaxResult paymentLedgerList(PaymentLedgerDto paymentLedgerDto)
    {
        return success(paymentRegistrationService.selectPaymentLedgerList(paymentLedgerDto));
    public AjaxResult paymentLedgerList(PaymentLedgerDto paymentLedgerDto, Page page,
                                        Integer detailPageNum,
                                        Integer detailPageSize) {
        IPage<Map<String, Object>> mapIPage = paymentRegistrationService.selectPaymentLedgerList(paymentLedgerDto, page, detailPageNum, detailPageSize);
        return success(mapIPage);
    }
    /**
     * èŽ·å–æœ¬æœˆåº”ä»˜ä¿¡æ¯
     */
    @GetMapping(value = "/paymentMonthList")
    public AjaxResult paymentMonthList() {
        return success(paymentRegistrationService.paymentMonthList());
    }
}
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
@@ -95,10 +95,18 @@
    }
    /**
     * æ ¹æ®id查询采购合同号
     */
    @GetMapping("/getPurchaseNoById")
    public AjaxResult getPurchaseNoById(Long id) {
        return AjaxResult.success(purchaseLedgerService.getPurchaseNoById(id));
    }
    /**
     * æ ¹æ®é‡‡è´­åˆåŒå·æŸ¥è¯¢äº§å“
     */
    @GetMapping("/getProduct")
    public List getProduct(PurchaseLedgerDto purchaseLedgerDto){
    public List getProduct(PurchaseLedgerDto purchaseLedgerDto) {
        return purchaseLedgerService.getProduct(purchaseLedgerDto);
    }
@@ -106,7 +114,7 @@
     * æ ¹æ®é‡‡è´­åˆåŒå·æŸ¥è¯¢äº§å“
     */
    @GetMapping("/getInfo")
    public PurchaseLedgerDto getInfo(PurchaseLedgerDto purchaseLedgerDto){
        return purchaseLedgerService.getInfo(purchaseLedgerDto);
    public AjaxResult getInfo(PurchaseLedgerDto purchaseLedgerDto) {
        return AjaxResult.success(purchaseLedgerService.getInfo(purchaseLedgerDto));
    }
}
src/main/java/com/ruoyi/purchase/controller/TicketRegistrationController.java
@@ -7,7 +7,9 @@
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.purchase.dto.TicketRegistrationDto;
import com.ruoyi.purchase.pojo.ProductRecord;
import com.ruoyi.purchase.pojo.TicketRegistration;
import com.ruoyi.purchase.service.IProductRecordService;
import com.ruoyi.purchase.service.ITicketRegistrationService;
import com.ruoyi.sales.service.ICommonFileService;
import lombok.AllArgsConstructor;
@@ -20,7 +22,7 @@
/**
 * æ¥ç¥¨ç™»è®°Controller
 *
 *
 * @author ruoyi
 * @date 2025-05-13
 */
@@ -33,12 +35,13 @@
    private ICommonFileService commonFileService;
    private IProductRecordService productRecordService;
    /**
     * æŸ¥è¯¢æ¥ç¥¨ç™»è®°åˆ—表
     */
    @GetMapping("/list")
    public TableDataInfo list(TicketRegistration ticketRegistration)
    {
    public TableDataInfo list(TicketRegistration ticketRegistration) {
        startPage();
        List<TicketRegistration> list = ticketRegistrationService.selectTicketRegistrationList(ticketRegistration);
        return getDataTable(list);
@@ -49,8 +52,7 @@
     */
    @Log(title = "来票登记", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, TicketRegistration ticketRegistration)
    {
    public void export(HttpServletResponse response, TicketRegistration ticketRegistration) {
        List<TicketRegistration> list = ticketRegistrationService.selectTicketRegistrationList(ticketRegistration);
        ExcelUtil<TicketRegistration> util = new ExcelUtil<TicketRegistration>(TicketRegistration.class);
        util.exportExcel(response, list, "来票登记数据");
@@ -68,7 +70,7 @@
     * æ–°å¢žä¿®æ”¹æ¥ç¥¨ç™»è®°
     */
    @Log(title = "来票登记", businessType = BusinessType.INSERT)
    @PostMapping  ("/addOrUpdateRegistration")
    @PostMapping("/addOrUpdateRegistration")
    public AjaxResult addOrUpdateRegistration(@RequestBody TicketRegistrationDto ticketRegistrationDto) throws IOException {
        return toAjax(ticketRegistrationService.addOrUpdateRegistration(ticketRegistrationDto));
    }
@@ -77,9 +79,8 @@
     * åˆ é™¤æ¥ç¥¨ç™»è®°
     */
    @Log(title = "来票登记", businessType = BusinessType.DELETE)
    @DeleteMapping("/delRegistration")
    public AjaxResult delRegistration(@RequestBody Long[] ids)
    {
    @DeleteMapping("/delRegistration")
    public AjaxResult delRegistration(@RequestBody Long[] ids) {
        return toAjax(ticketRegistrationService.delRegistration(ids));
    }
@@ -92,4 +93,20 @@
        }
    }
    /**
     * æŸ¥è¯¢äº§å“ä¿¡æ¯å¼€ç¥¨è®°å½•列表
     */
    @GetMapping("/productRecordList")
    public List<ProductRecord> productRecordList(TicketRegistrationDto ticketRegistrationDto) {
        List<ProductRecord> list = productRecordService.selectProductRecordList(ticketRegistrationDto);
        return list;
    }
    /**
     * æŸ¥è¯¢å‘票号
     */
    @GetMapping("/getTicketNo")
    public AjaxResult getTicketNo(TicketRegistrationDto ticketRegistrationDto) {
        return AjaxResult.success(ticketRegistrationService.getTicketNo(ticketRegistrationDto));
    }
}
src/main/java/com/ruoyi/purchase/dto/PaymentRegistrationDto.java
@@ -30,5 +30,8 @@
    private BigDecimal unPaymentAmount;
    // ç¨Žçއ
    private BigDecimal taxRate;
    private String taxRate;
    // ç™»è®°äºº
    private String registrant;
}
src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
@@ -5,6 +5,7 @@
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@@ -116,4 +117,21 @@
     * äº§å“è§„æ ¼id
     */
    private Long productModelId;
    /**
     * å‘票号
     */
    private String invoiceNumber;
    /**
     * å‘票金额(元)
     */
    private BigDecimal invoiceAmount;
    /**
     * æ¥ç¥¨ç™»è®°id
     */
    private Long ticketRegistrationId;
}
src/main/java/com/ruoyi/purchase/dto/TicketRegistrationDto.java
@@ -1,13 +1,20 @@
package com.ruoyi.purchase.dto;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.purchase.pojo.TicketRegistration;
import com.ruoyi.sales.pojo.CommonFile;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import lombok.Data;
import java.util.List;
/**
 * æ¥ç¥¨ç™»è®°è¡¨
 */
@Data
public class TicketRegistrationDto {
@TableName("ticket_registration")
public class TicketRegistrationDto extends TicketRegistration {
    /**
     * ä¸»é”®ID
src/main/java/com/ruoyi/purchase/mapper/ProductRecordMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package com.ruoyi.purchase.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.purchase.pojo.ProductRecord;
/**
 * é‡‡è´­å°è´¦äº§å“å¼€ç¥¨è®°å½•Mapper接口
 *
 * @author ruoyi
 * @date 2025-05-23
 */
public interface ProductRecordMapper extends BaseMapper<ProductRecord> {
}
src/main/java/com/ruoyi/purchase/pojo/PaymentRegistration.java
@@ -43,7 +43,7 @@
    /**
     * å‘票id
     */
    private Long invoicePurchaseId;
    private Long ticketRegistrationId;
    /**
     * æœ¬æ¬¡ä»˜æ¬¾é‡‘额
@@ -54,6 +54,11 @@
     * ä»˜æ¬¾å½¢å¼
     */
    private String paymentMethod;
    /**
     * ç¨Žçއ
     */
    private String taxRate;
    /**
     * ç™»è®°äºº
@@ -70,6 +75,12 @@
    private Date paymentDate;
    /**
     * ç™»è®°æ—¥æœŸ
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date registrationtDate;
    /**
     * åˆ›å»ºæ—¥æœŸ
     */
    @TableField(fill = FieldFill.INSERT)
src/main/java/com/ruoyi/purchase/pojo/ProductRecord.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,124 @@
package com.ruoyi.purchase.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
 * é‡‡è´­å°è´¦äº§å“å¼€ç¥¨è®°å½•对象 product_record
 *
 * @author ruoyi
 * @date 2025-05-23
 */
@Data
@TableName("product_record")
public class ProductRecord {
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®id
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * æ¥ç¥¨ç™»è®°id
     */
    private Long ticketRegistrationId;
    /**
     * é‡‡è´­å°è´¦id
     */
    private Long purchaseLedgerId;
    /**
     * äº§å“å¤§ç±»
     */
    private String productCategory;
    /**
     * è§„格型号
     */
    private String specificationModel;
    /**
     * å•位
     */
    private String unit;
    /**
     * æ•°é‡
     */
    private BigDecimal quantity;
    /**
     * ç¨Žçއ
     */
    private BigDecimal taxRate;
    /**
     * å«ç¨Žå•ä»·
     */
    private BigDecimal taxInclusiveUnitPrice;
    /**
     * å«ç¨Žæ€»ä»·
     */
    private BigDecimal taxInclusiveTotalPrice;
    /**
     * ä¸å«ç¨Žæ€»ä»·
     */
    private BigDecimal taxExclusiveTotalPrice;
    /**
     * å‘票类型
     */
    private String invoiceType;
    /**
     * 1.销售台账,2.采购台账
     */
    private String type;
    /**
     * æœ¬æ¬¡æ¥ç¥¨æ•°
     */
    private Long ticketsNum;
    /**
     * æœ¬æ¬¡æ¥ç¥¨é‡‘额(元)
     */
    private BigDecimal ticketsAmount;
    /**
     * æœªæ¥ç¥¨æ•°
     */
    private Long futureTickets;
    /**
     * æœªæ¥ç¥¨é‡‘额(元)
     */
    private BigDecimal futureTicketsAmount;
    /**
     * äº§å“id
     */
    private Long productId;
    /**
     * åž‹å·id
     */
    private Long productModelId;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createdAt;
}
src/main/java/com/ruoyi/purchase/pojo/TicketRegistration.java
@@ -78,6 +78,12 @@
    private BigDecimal invoiceAmount;
    /**
     * å¼€ç¥¨äººID
     */
    @Excel(name = "开票人")
    private String issUerId;
    /**
     * å¼€ç¥¨äºº
     */
    @Excel(name = "开票人")
src/main/java/com/ruoyi/purchase/service/IPaymentRegistrationService.java
@@ -1,10 +1,13 @@
package com.ruoyi.purchase.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.purchase.dto.PaymentLedgerDto;
import com.ruoyi.purchase.dto.PaymentRegistrationDto;
import com.ruoyi.purchase.pojo.PaymentRegistration;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
@@ -63,5 +66,9 @@
     */
    PaymentRegistration selectPaymentRegistrationByPurchaseId(Long purchaseId);
    List<Map<String, Object>> selectPaymentLedgerList(PaymentLedgerDto paymentLedgerDto);
    IPage<Map<String, Object>> selectPaymentLedgerList(PaymentLedgerDto paymentLedgerDto, Page page,
                                                       Integer detailPageNum,
                                                       Integer detailPageSize);
    Map<String, BigDecimal> paymentMonthList();
}
src/main/java/com/ruoyi/purchase/service/IProductRecordService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.purchase.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.purchase.dto.TicketRegistrationDto;
import com.ruoyi.purchase.pojo.ProductRecord;
import java.util.List;
/**
 * é‡‡è´­å°è´¦äº§å“å¼€ç¥¨è®°å½•Service接口
 *
 * @author ruoyi
 * @date 2025-05-23
 */
public interface IProductRecordService extends IService<ProductRecord> {
    List<ProductRecord> selectProductRecordList(TicketRegistrationDto ticketRegistrationDto);
}
src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
@@ -29,4 +29,6 @@
    PurchaseLedgerDto getInfo(PurchaseLedgerDto purchaseLedgerDto);
    List getPurchasesNo();
    PurchaseLedgerDto getPurchaseNoById(Long id);
}
src/main/java/com/ruoyi/purchase/service/ITicketRegistrationService.java
@@ -22,4 +22,6 @@
    int delRegistration(Long[] ids);
    TicketRegistrationDto getRegistrationById(TicketRegistrationDto ticketRegistrationDto);
    List getTicketNo(TicketRegistrationDto ticketRegistrationDto);
}
src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java
@@ -2,6 +2,9 @@
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.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.mapper.SupplierManageMapper;
import com.ruoyi.basic.pojo.SupplierManage;
@@ -10,23 +13,24 @@
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.purchase.dto.PaymentLedgerDto;
import com.ruoyi.purchase.dto.PaymentRegistrationDto;
import com.ruoyi.purchase.mapper.InvoicePurchaseMapper;
import com.ruoyi.purchase.mapper.PaymentRegistrationMapper;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.InvoicePurchase;
import com.ruoyi.purchase.mapper.*;
import com.ruoyi.purchase.pojo.PaymentRegistration;
import com.ruoyi.purchase.pojo.ProductRecord;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.purchase.pojo.TicketRegistration;
import com.ruoyi.purchase.service.IPaymentRegistrationService;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.*;
import java.util.stream.Collectors;
@@ -37,24 +41,23 @@
 * @date 2025-05-15
 */
@Service
@AllArgsConstructor
public class PaymentRegistrationServiceImpl extends ServiceImpl<PaymentRegistrationMapper, PaymentRegistration> implements IPaymentRegistrationService {
    @Autowired
    private PaymentRegistrationMapper paymentRegistrationMapper;
    @Autowired
    private PurchaseLedgerMapper purchaseLedgerMapper;
    @Autowired
    private InvoicePurchaseMapper invoicePurchaseMapper;
    @Autowired
    private SalesLedgerMapper salesLedgerMapper;
    @Autowired
    private SupplierManageMapper supplierManageMapper;
    @Autowired
    private SalesLedgerProductMapper salesLedgerProductMapper;
    private TicketRegistrationMapper ticketRegistrationMapper;
    private ProductRecordMapper productRecordMapper;
    /**
     * æŸ¥è¯¢ä»˜æ¬¾ç™»è®°
@@ -78,7 +81,7 @@
        List<PaymentRegistrationDto> list = paymentRegistrationMapper.selectPaymentRegistrationList(paymentRegistrationDto);
        for (PaymentRegistrationDto registrationDto : list) {
            List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper.selectList(new QueryWrapper<PaymentRegistration>()
                    .eq("invoice_purchase_id", registrationDto.getInvoicePurchaseId()));
                    .eq("ticket_registration_id", registrationDto.getTicketRegistrationId()));
            BigDecimal total = paymentRegistrations.stream().map(PaymentRegistration::getCurrentPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            registrationDto.setUnPaymentAmount(registrationDto.getInvoiceAmount().subtract(total));
        }
@@ -103,25 +106,24 @@
        paymentRegistration.setSaleLedgerId(salesLedger.getId());
        paymentRegistration.setSupplierId(purchaseLedger.getSupplierId());
        List<InvoicePurchase> invoicePurchases = invoicePurchaseMapper.selectList(new QueryWrapper<InvoicePurchase>().
                eq("purchase_contract_no", purchaseLedger.getPurchaseContractNumber()));
        if (invoicePurchases == null || invoicePurchases.size() == 0) {
        TicketRegistration tr = ticketRegistrationMapper.selectOne(new LambdaQueryWrapper<TicketRegistration>().eq(TicketRegistration::getId, paymentRegistration.getTicketRegistrationId()));
        if (tr == null) {
            throw new RuntimeException("关联发票不存在");
        }
        paymentRegistration.setInvoicePurchaseId(invoicePurchases.get(0).getId());
        List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper.selectList(new QueryWrapper<PaymentRegistration>()
                .eq("invoice_purchase_id", invoicePurchases.get(0).getId()));
                .eq("ticket_registration_id", tr.getId()));
        BigDecimal total = paymentRegistrations.stream().map(PaymentRegistration::getCurrentPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (total.add(paymentRegistration.getCurrentPaymentAmount()).compareTo(invoicePurchases.get(0).getInvoiceAmount()) > 0) {
        if (total.add(paymentRegistration.getCurrentPaymentAmount()).compareTo(tr.getInvoiceAmount()) > 0) {
            throw new RuntimeException("付款金额超出发票金额");
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Integer tenantId = loginUser.getTenantId();
        paymentRegistration.setTenantId(tenantId.longValue());
        paymentRegistration.setRegistrantId(loginUser.getUserId());
        paymentRegistration.setCreateTime(DateUtils.getNowDate());
        paymentRegistration.setUpdateTime(DateUtils.getNowDate());
        return paymentRegistrationMapper.insert(paymentRegistration);
@@ -135,13 +137,13 @@
     */
    @Override
    public int updatePaymentRegistration(PaymentRegistration paymentRegistration) {
        InvoicePurchase invoicePurchase = invoicePurchaseMapper.selectById(paymentRegistration.getInvoicePurchaseId());
        TicketRegistration ticketRegistration = ticketRegistrationMapper.selectById(paymentRegistration.getTicketRegistrationId());
        List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper.selectList(new QueryWrapper<PaymentRegistration>()
                .eq("invoice_purchase_id", paymentRegistration.getInvoicePurchaseId()).ne("id", paymentRegistration.getId()));
                .eq("ticket_registration_id", paymentRegistration.getTicketRegistrationId()).ne("id", paymentRegistration.getId()));
        BigDecimal total = paymentRegistrations.stream().map(PaymentRegistration::getCurrentPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (total.add(paymentRegistration.getCurrentPaymentAmount()).compareTo(invoicePurchase.getInvoiceAmount()) > 0) {
        if (total.add(paymentRegistration.getCurrentPaymentAmount()).compareTo(ticketRegistration.getInvoiceAmount()) > 0) {
            throw new RuntimeException("付款金额超出发票金额");
        }
@@ -168,19 +170,21 @@
        paymentRegistrationDto.setSupplierName(purchaseLedger.getSupplierName());
        paymentRegistrationDto.setSupplierId(purchaseLedger.getSupplierId());
        List<InvoicePurchase> invoicePurchaseList = invoicePurchaseMapper.selectList(new QueryWrapper<InvoicePurchase>()
                .eq("purchase_contract_no", purchaseLedger.getPurchaseContractNumber()));
        if (invoicePurchaseList != null && invoicePurchaseList.size() > 0) {
            paymentRegistrationDto.setInvoiceNumber(invoicePurchaseList.get(0).getInvoiceNumber());
            paymentRegistrationDto.setInvoiceAmount(invoicePurchaseList.get(0).getInvoiceAmount());
            paymentRegistrationDto.setTaxRate(invoicePurchaseList.get(0).getTaxRate());
        List<TicketRegistration> ticketRegistrations = ticketRegistrationMapper.selectList(new QueryWrapper<TicketRegistration>()
                .eq("purchase_contract_number", purchaseLedger.getPurchaseContractNumber()));
        if (ticketRegistrations != null && ticketRegistrations.size() > 0) {
            paymentRegistrationDto.setInvoiceNumber(ticketRegistrations.get(0).getInvoiceNumber());
            paymentRegistrationDto.setInvoiceAmount(ticketRegistrations.get(0).getInvoiceAmount());
        }
        return paymentRegistrationDto;
    }
    @Override
    public List<Map<String, Object>> selectPaymentLedgerList(PaymentLedgerDto paymentLedgerDto) {
        List<Map<String, Object>> result = new ArrayList<>();
    public IPage<Map<String, Object>> selectPaymentLedgerList(
            PaymentLedgerDto paymentLedgerDto,
            Page page,
            Integer detailPageNum,
            Integer detailPageSize) {
        LambdaQueryWrapper<SupplierManage> queryWrapper = new LambdaQueryWrapper<>();
        Optional.ofNullable(paymentLedgerDto)
                .ifPresent(dto -> {
@@ -189,58 +193,223 @@
                    }
                });
        List<SupplierManage> supplierManages = supplierManageMapper.selectList(queryWrapper);
        IPage<SupplierManage> supplierPage = supplierManageMapper.selectPage(page, queryWrapper);
        List<SupplierManage> supplierManages = supplierPage.getRecords();
        IPage<Map<String, Object>> resultPage = new Page<>(page.getCurrent(), page.getSize(), supplierPage.getTotal());
        List<Map<String, Object>> result = new ArrayList<>();
        for (SupplierManage supplierManage : supplierManages) {
            Map<String, Object> res = new HashMap<>();
            res.put("supplierName", supplierManage.getSupplierName());
            // åº”付金额
            // åº”付金额计算
            BigDecimal payableAmount = BigDecimal.ZERO;
            List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(new QueryWrapper<SalesLedger>().eq("customer_id", supplierManage.getId()));
            if (salesLedgers != null && salesLedgers.size() > 0) {
                List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new QueryWrapper<SalesLedgerProduct>()
                        .in("sales_ledger_id", salesLedgers.stream().map(SalesLedger::getId).collect(Collectors.toList())));
                // åº”付金额
                payableAmount = salesLedgerProducts.stream().map(SalesLedgerProduct::getTaxInclusiveTotalPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            List<PurchaseLedger> purchaseLedgers = purchaseLedgerMapper.selectList(
                    new QueryWrapper<PurchaseLedger>().eq("supplier_id", supplierManage.getId())
            );
            List<SalesLedgerProduct> salesLedgerProducts = purchaseLedgers.stream()
                    .filter(Objects::nonNull)
                    .map(PurchaseLedger::getId)
                    .filter(Objects::nonNull)
                    .flatMap(id -> salesLedgerProductMapper.selectList(
                            new QueryWrapper<SalesLedgerProduct>().eq("sales_ledger_id", id)
                    ).stream())
                    .collect(Collectors.toList());
            payableAmount = salesLedgerProducts.stream()
                    .map(SalesLedgerProduct::getTaxInclusiveTotalPrice)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            // æ¥ç¥¨é‡‘额计算
            List<TicketRegistration> ticketRegistrations = purchaseLedgers.stream()
                    .map(PurchaseLedger::getId)
                    .filter(Objects::nonNull)
                    .map(id -> ticketRegistrationMapper.selectList(
                            new LambdaQueryWrapper<TicketRegistration>().eq(TicketRegistration::getPurchaseLedgerId, id)
                    ))
                    .flatMap(Collection::stream)
                    .collect(Collectors.toList());
            BigDecimal invoiceAmount = ticketRegistrations.stream()
                    .map(TicketRegistration::getInvoiceAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // å¼€ç¥¨é‡‘额
            BigDecimal invoiceAmount = salesLedgers.stream().map(SalesLedger::getContractAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            // ä»˜æ¬¾è®°å½•及详情分页
            List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper.selectList(
                    new QueryWrapper<PaymentRegistration>().eq("supplier_id", supplierManage.getId())
            );
            BigDecimal paymentAmount = paymentRegistrations.stream()
                    .map(PaymentRegistration::getCurrentPaymentAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // ä»˜æ¬¾é‡‘额
            List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper.selectList(new QueryWrapper<PaymentRegistration>()
                    .eq("supplier_id", supplierManage.getId()));
            // è¯¦æƒ…分页处理
            detailPageNum = detailPageNum != null ? detailPageNum : 1;
            detailPageSize = detailPageSize != null ? detailPageSize : paymentRegistrations.size(); // é»˜è®¤æ˜¾ç¤ºå…¨éƒ¨
            int totalDetails = paymentRegistrations.size();
            int start = (detailPageNum - 1) * detailPageSize;
            int end = Math.min(start + detailPageSize, totalDetails);
            List<PaymentRegistration> pagedDetails = paymentRegistrations.subList(start, end);
            BigDecimal paymentAmount = BigDecimal.ZERO;
            if (paymentRegistrations != null && paymentRegistrations.size() > 0) {
                paymentAmount = paymentRegistrations.stream().map(PaymentRegistration::getCurrentPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            // æž„建详情列表
            List<Map<String, Object>> details = pagedDetails.stream()
                    .filter(Objects::nonNull)
                    .map(pr -> {
                        Map<String, Object> detail = new HashMap<>();
                        detail.put("paymentAmount", pr.getCurrentPaymentAmount());
                        // æ‰¹é‡æŸ¥è¯¢ TicketRegistration(避免 N+1)
                        TicketRegistration ticketRegistration = ticketRegistrationMapper.selectById(pr.getTicketRegistrationId());
                        if (ticketRegistration != null) {
                            detail.put("payableAmount", ticketRegistration.getInvoiceAmount());
                            BigDecimal voteCount = productRecordMapper.selectList(
                                            new LambdaQueryWrapper<ProductRecord>().eq(ProductRecord::getTicketRegistrationId, ticketRegistration.getId())
                                    ).stream()
                                    .map(ProductRecord::getTicketsNum)
                                    .map(BigDecimal::new)
                                    .filter(Objects::nonNull)
                                    .reduce(BigDecimal.ZERO, BigDecimal::add);
                            detail.put("voteCount", voteCount);
                        }
                        // æ—¥æœŸæ ¼å¼åŒ–(建议使用 LocalDateTime)
                        if (pr.getPaymentDate() != null) {
                            detail.put("paymentDate", new SimpleDateFormat("yyyy-MM-dd").format(pr.getPaymentDate()));
                        }
                        return detail;
                    })
                    .collect(Collectors.toList());
            // å°è£…详情分页元数据
            Map<String, Object> detailPagination = new HashMap<>();
            detailPagination.put("total", totalDetails);
            detailPagination.put("pageNum", detailPageNum);
            detailPagination.put("pageSize", detailPageSize);
            detailPagination.put("pages", (int) Math.ceil((double) totalDetails / detailPageSize));
            res.put("invoiceAmount", invoiceAmount);
            res.put("payableAmount", payableAmount);
            res.put("paymentAmount", paymentAmount);
            // è¯¦æƒ…
            List<Map<String, Object>> details = new ArrayList<>();
            for (PaymentRegistration paymentRegistration : paymentRegistrations) {
                Map<String, Object> detail = new HashMap<>();
                detail.put("voteCount", 1); // ç¥¨æ•°ï¼ŒæœªçŸ¥æ•°æ®æºï¼Œæš‚时用1
                detail.put("paymentAmount", paymentRegistration.getCurrentPaymentAmount()); // ä»˜æ¬¾é‡‘额
                InvoicePurchase  invoicePurchase = invoicePurchaseMapper.selectById(paymentRegistration.getInvoicePurchaseId());
                detail.put("payableAmount", invoicePurchase.getInvoiceAmount()); // åº”付金额
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String formattedDate = sdf.format(paymentRegistration.getPaymentDate());
                detail.put("createTime", formattedDate); // å‘生时间
                details.add(detail);
            }
            res.put("details", paymentRegistrations);
            res.put("details", details);
            res.put("detailPagination", detailPagination); // æ·»åŠ è¯¦æƒ…åˆ†é¡µä¿¡æ¯
            result.add(res);
        }
        resultPage.setRecords(result);
        return resultPage;
    }
    @Override
    public Map<String, BigDecimal> paymentMonthList() {
        // æŸ¥è¯¢ä¾›åº”商列表
        List<SupplierManage> suppliers = supplierManageMapper.selectList(null);
        if (CollectionUtils.isEmpty(suppliers)) {
            Map<String, BigDecimal> result = new HashMap<>();
            result.put("payableAmount", BigDecimal.ZERO);
            result.put("paymentAmount", BigDecimal.ZERO);
            return result;
        }
        // æå–所有供应商ID
        List<Long> supplierIds = suppliers.stream()
                .map(SupplierManage::getId) // å…ˆèŽ·å–Integer类型的ID
                .filter(Objects::nonNull)    // è¿‡æ»¤æŽ‰å¯èƒ½çš„null值
                .map(Integer::longValue)    // å°†Integer转换为Long
                .collect(Collectors.toList());
        // èŽ·å–å½“æœˆçš„å¼€å§‹å’Œç»“æŸæ—¥æœŸ
        YearMonth currentMonth = YearMonth.now();
        LocalDate startDate = currentMonth.atDay(1);
        LocalDate endDate = currentMonth.atEndOfMonth();
        // æ‰¹é‡æŸ¥è¯¢é‡‡è´­å°è´¦ï¼ˆå½“月)
        Map<Long, List<PurchaseLedger>> purchaseLedgerMap = batchQueryPurchaseLedgers(supplierIds, startDate, endDate);
        // æ‰¹é‡æŸ¥è¯¢é”€å”®å°è´¦äº§å“
        Map<Long, List<SalesLedgerProduct>> salesLedgerProductMap = batchQuerySalesLedgerProducts(purchaseLedgerMap);
        // æ‰¹é‡æŸ¥è¯¢ä»˜æ¬¾è®°å½•(当月)
        Map<Long, List<PaymentRegistration>> paymentRegistrationMap = batchQueryPaymentRegistrations(supplierIds, startDate, endDate);
        // è®¡ç®—应付金额和付款金额
        BigDecimal totalPayableAmount = calculateTotalPayableAmount(purchaseLedgerMap, salesLedgerProductMap);
        BigDecimal totalPaymentAmount = calculateTotalPaymentAmount(paymentRegistrationMap);
        // æž„建结果
        Map<String, BigDecimal> result = new HashMap<>();
        result.put("payableAmount", totalPayableAmount);
        result.put("paymentAmount", totalPaymentAmount);
        return result;
    }
    // æ‰¹é‡æŸ¥è¯¢é‡‡è´­å°è´¦ï¼ˆå½“月)
    private Map<Long, List<PurchaseLedger>> batchQueryPurchaseLedgers(List<Long> supplierIds, LocalDate startDate, LocalDate endDate) {
        LambdaQueryWrapper<PurchaseLedger> query = new LambdaQueryWrapper<>();
        query.in(PurchaseLedger::getSupplierId, supplierIds)
                .ge(PurchaseLedger::getCreatedAt, startDate)
                .le(PurchaseLedger::getCreatedAt, endDate);
        List<PurchaseLedger> purchaseLedgers = purchaseLedgerMapper.selectList(query);
        return purchaseLedgers.stream()
                .filter(pl -> pl.getSupplierId() != null)
                .collect(Collectors.groupingBy(PurchaseLedger::getSupplierId));
    }
    // æ‰¹é‡æŸ¥è¯¢é”€å”®å°è´¦äº§å“
    private Map<Long, List<SalesLedgerProduct>> batchQuerySalesLedgerProducts(Map<Long, List<PurchaseLedger>> purchaseLedgerMap) {
        // æå–所有采购台账ID
        List<Long> purchaseLedgerIds = purchaseLedgerMap.values().stream()
                .flatMap(Collection::stream)
                .map(PurchaseLedger::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (purchaseLedgerIds.isEmpty()) {
            return Collections.emptyMap();
        }
        LambdaQueryWrapper<SalesLedgerProduct> query = new LambdaQueryWrapper<>();
        query.in(SalesLedgerProduct::getSalesLedgerId, purchaseLedgerIds);
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(query);
        return products.stream()
                .filter(slp -> slp.getSalesLedgerId() != null)
                .collect(Collectors.groupingBy(SalesLedgerProduct::getSalesLedgerId));
    }
    // æ‰¹é‡æŸ¥è¯¢ä»˜æ¬¾è®°å½•(当月)
    private Map<Long, List<PaymentRegistration>> batchQueryPaymentRegistrations(List<Long> supplierIds, LocalDate startDate, LocalDate endDate) {
        LambdaQueryWrapper<PaymentRegistration> query = new LambdaQueryWrapper<>();
        query.in(PaymentRegistration::getSupplierId, supplierIds)
                .ge(PaymentRegistration::getPaymentDate, startDate)
                .le(PaymentRegistration::getPaymentDate, endDate);
        List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper.selectList(query);
        return paymentRegistrations.stream()
                .filter(pr -> pr.getSupplierId() != null)
                .collect(Collectors.groupingBy(PaymentRegistration::getSupplierId));
    }
    // è®¡ç®—总应付金额
    private BigDecimal calculateTotalPayableAmount(Map<Long, List<PurchaseLedger>> purchaseLedgerMap,
                                                   Map<Long, List<SalesLedgerProduct>> salesLedgerProductMap) {
        return purchaseLedgerMap.values().stream()
                .flatMap(Collection::stream)
                .map(pl -> salesLedgerProductMap.getOrDefault(pl.getId(), Collections.emptyList()))
                .flatMap(Collection::stream)
                .map(SalesLedgerProduct::getTaxInclusiveTotalPrice)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    // è®¡ç®—总付款金额
    private BigDecimal calculateTotalPaymentAmount(Map<Long, List<PaymentRegistration>> paymentRegistrationMap) {
        return paymentRegistrationMap.values().stream()
                .flatMap(Collection::stream)
                .map(PaymentRegistration::getCurrentPaymentAmount)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}
src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
package com.ruoyi.purchase.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.purchase.dto.TicketRegistrationDto;
import com.ruoyi.purchase.mapper.ProductRecordMapper;
import com.ruoyi.purchase.pojo.ProductRecord;
import com.ruoyi.purchase.service.IProductRecordService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
 * é‡‡è´­å°è´¦äº§å“å¼€ç¥¨è®°å½•Service业务层处理
 *
 * @author ruoyi
 * @date 2025-05-23
 */
@Service
@AllArgsConstructor
public class ProductRecordServiceImpl extends ServiceImpl<ProductRecordMapper, ProductRecord> implements IProductRecordService {
    private ProductRecordMapper productRecordMapper;
    /**
     * æŸ¥è¯¢é‡‡è´­å°è´¦äº§å“å¼€ç¥¨è®°å½•
     *
     * @param ticketRegistrationDto é‡‡è´­å°è´¦äº§å“å¼€ç¥¨è®°å½•主键
     * @return é‡‡è´­å°è´¦äº§å“å¼€ç¥¨è®°å½•
     */
    @Override
    public List<ProductRecord> selectProductRecordList(TicketRegistrationDto ticketRegistrationDto) {
        return productRecordMapper.selectList(new LambdaQueryWrapper<ProductRecord>().eq(ProductRecord::getTicketRegistrationId, ticketRegistrationDto.getId())
                .eq(ProductRecord::getType, "2"));
    }
}
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -17,8 +17,12 @@
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.ProductRecordMapper;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.mapper.TicketRegistrationMapper;
import com.ruoyi.purchase.pojo.ProductRecord;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.purchase.pojo.TicketRegistration;
import com.ruoyi.purchase.service.IPurchaseLedgerService;
import com.ruoyi.sales.mapper.CommonFileMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
@@ -73,6 +77,10 @@
    private final ProductModelMapper productModelMapper;
    private final TicketRegistrationMapper ticketRegistrationMapper;
    private final ProductRecordMapper productRecordMapper;
    @Value("${file.upload-dir}")
    private String uploadDir;
@@ -118,7 +126,7 @@
        // 4. å¤„理子表数据
        List<SalesLedgerProduct> productList = purchaseLedgerDto.getProductData();
        if (productList != null && !productList.isEmpty()) {
            handleSalesLedgerProducts(purchaseLedger.getId(), purchaseLedgerDto.getProductId(), purchaseLedgerDto.getProductModelId(), productList, purchaseLedgerDto.getType());
            handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType());
        }
        // 5. è¿ç§»ä¸´æ—¶æ–‡ä»¶åˆ°æ­£å¼ç›®å½•
@@ -129,19 +137,52 @@
        return 1;
    }
    private void handleSalesLedgerProducts(Long salesLedgerId, Long productId, Long productModelId, List<SalesLedgerProduct> products, Integer type) {
        Product pro = productMapper.selectById(productId);
        ProductModel productModel = productModelMapper.selectById(productModelId);
    private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type) {
        if (products == null || products.isEmpty()) {
            throw new BaseException("产品信息不存在");
        }
        // æŒ‰ID分组,区分新增和更新的记录
        // æå‰æ”¶é›†æ‰€æœ‰éœ€è¦æŸ¥è¯¢çš„ID
        Set<Long> productIds = products.stream()
                .map(SalesLedgerProduct::getProductId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Set<Long> modelIds = products.stream()
                .map(SalesLedgerProduct::getProductModelId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        // ä¸€æ¬¡æ€§æŸ¥è¯¢äº§å“å’Œåž‹å·ä¿¡æ¯
        Map<Long, String> productMap = new HashMap<>();
        if (!productIds.isEmpty()) {
            List<Product> productList = productMapper.selectBatchIds(productIds);
            productList.forEach(p -> productMap.put(p.getId(), p.getProductName()));
        }
        Map<Long, String> modelMap = new HashMap<>();
        if (!modelIds.isEmpty()) {
            List<ProductModel> modelList = productModelMapper.selectBatchIds(modelIds);
            modelList.forEach(m -> modelMap.put(m.getId(), m.getModel()));
        }
        // è®¾ç½®å­—段
        for (SalesLedgerProduct product : products) {
            product.setSalesLedgerId(salesLedgerId);
            Long productId = product.getProductId();
            if (productId != null && productMap.containsKey(productId)) {
                product.setProductCategory(productMap.get(productId));
            }
            Long productModelId = product.getProductModelId();
            if (productModelId != null && modelMap.containsKey(productModelId)) {
                product.setSpecificationModel(modelMap.get(productModelId));
            }
        }
        // åˆ†ç»„处理
        Map<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream()
                .peek(p -> {
                    p.setSalesLedgerId(salesLedgerId);
                    p.setProductId(productId);
                    p.setProductCategory(pro.getProductName());
                    p.setProductModelId(productModelId);
                    p.setSpecificationModel(productModel.getModel());
                })
                .collect(Collectors.partitioningBy(p -> p.getId() != null));
        List<SalesLedgerProduct> updateList = partitionedProducts.get(true);
@@ -248,6 +289,23 @@
    @Override
    public int deletePurchaseLedgerByIds(Long[] ids) {
        if (ids == null || ids.length == 0) {
           throw new BaseException("请选中至少一条数据");
        }
        // æ‰¹é‡åˆ é™¤å…³è”的采购台账产品
        LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SalesLedgerProduct::getSalesLedgerId, ids)
                .eq(SalesLedgerProduct::getType, "2");
        salesLedgerProductMapper.delete(queryWrapper);
        // æ‰¹é‡åˆ é™¤å…³è”的采购台账的来票登记
        LambdaQueryWrapper<TicketRegistration> ticketRegistrationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        ticketRegistrationLambdaQueryWrapper.in(TicketRegistration::getSalesLedgerId,ids);
        ticketRegistrationMapper.delete(ticketRegistrationLambdaQueryWrapper);
        // æ‰¹é‡åˆ é™¤å…³è”的采购台账的来票登记记录
        LambdaQueryWrapper<ProductRecord> productRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        productRecordLambdaQueryWrapper.in(ProductRecord::getPurchaseLedgerId,ids);
        productRecordMapper.delete(productRecordLambdaQueryWrapper);
        // æ‰¹é‡åˆ é™¤é‡‡è´­å°è´¦
        return purchaseLedgerMapper.deleteBatchIds(Arrays.asList(ids));
    }
@@ -315,8 +373,13 @@
        queryWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId())
                .eq(SalesLedgerProduct::getType, 2);
        List<SalesLedgerProduct> productList = salesLedgerProductMapper.selectList(queryWrapper);
        productList.forEach(product -> {
            product.setFutureTickets(product.getFutureTickets() != null ? product.getFutureTickets() : product.getQuantity().longValue());
            product.setFutureTicketsAmount(product.getFutureTicketsAmount() != null ? product.getFutureTicketsAmount() : product.getTaxInclusiveTotalPrice());
            product.setTicketsNum(null);
            product.setTicketsAmount(null);
        });
        resultDto.setProductData(productList);
        return resultDto;
    }
@@ -336,6 +399,20 @@
        ).collect(Collectors.toList());
    }
    @Override
    public PurchaseLedgerDto getPurchaseNoById(Long id) {
        PurchaseLedgerDto purchaseLedgerDto = new PurchaseLedgerDto();
        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id);
        BeanUtils.copyProperties(purchaseLedger, purchaseLedgerDto);
//        TicketRegistration ticketRegistration = ticketRegistrationMapper.selectOne(new LambdaQueryWrapper<TicketRegistration>().eq(TicketRegistration::getPurchaseLedgerId, id));
//        if (ticketRegistration != null) {
//            purchaseLedgerDto.setInvoiceNumber(ticketRegistration.getInvoiceNumber());
//            purchaseLedgerDto.setInvoiceAmount(ticketRegistration.getInvoiceAmount());
//            purchaseLedgerDto.setTicketRegistrationId(ticketRegistration.getId());
//        }
        return purchaseLedgerDto;
    }
    /**
     * ä¸‹åˆ’线命名转驼峰命名
     */
src/main/java/com/ruoyi/purchase/service/impl/TicketRegistrationServiceImpl.java
@@ -4,13 +4,16 @@
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.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.other.pojo.TempFile;
import com.ruoyi.purchase.dto.TicketRegistrationDto;
import com.ruoyi.purchase.mapper.ProductRecordMapper;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.mapper.TicketRegistrationMapper;
import com.ruoyi.purchase.pojo.ProductRecord;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.purchase.pojo.TicketRegistration;
import com.ruoyi.purchase.service.ITicketRegistrationService;
@@ -23,6 +26,7 @@
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.math.BigDecimal;
@@ -35,6 +39,7 @@
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;
@@ -59,6 +64,8 @@
    private final TempFileMapper tempFileMapper;
    private final ProductRecordMapper productRecordMapper;
    @Value("${file.upload-dir}")
    private String uploadDir;
@@ -67,38 +74,59 @@
    public List<TicketRegistration> selectTicketRegistrationList(TicketRegistration ticketRegistration) {
        LambdaQueryWrapper<TicketRegistration> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(ticketRegistration.getPurchaseContractNumber())) {
            queryWrapper.like(TicketRegistration::getPurchaseContractNumber, ticketRegistration.getPurchaseContractNumber());
            queryWrapper.like(TicketRegistration::getPurchaseContractNumber, ticketRegistration.getPurchaseContractNumber())
                    .like(TicketRegistration::getSupplierName, ticketRegistration.getSupplierName())
                    .eq(TicketRegistration::getIssueDate, ticketRegistration.getIssueDate());
        }
        return ticketRegistrationMapper.selectList(queryWrapper);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addOrUpdateRegistration(TicketRegistrationDto ticketRegistrationDto) throws IOException {
        // 1. æŸ¥è¯¢é‡‡è´­å°è´¦è®°å½•
        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(ticketRegistrationDto.getPurchaseLedgerId());
        if (purchaseLedger == null) {
            // å¤„理采购台账不存在的情况,例如抛出异常或返回错误
            throw new IllegalArgumentException("采购台账记录不存在,ID: " + ticketRegistrationDto.getPurchaseLedgerId());
        }
        // 3. åˆ›å»ºæˆ–更新票据登记实体
        TicketRegistration ticketRegistration = new TicketRegistration();
        BeanUtils.copyProperties(ticketRegistrationDto, ticketRegistration);
        ticketRegistration.setPurchaseContractNumber(purchaseLedger.getPurchaseContractNumber());
        ticketRegistration.setTenantId(purchaseLedger.getTenantId());
        ticketRegistration.setContractAmount(purchaseLedger.getContractAmount());
        // å¤„理子表数据
        ticketRegistration.setSalesLedgerId(purchaseLedger.getSalesLedgerId());
        // 4. å¤„理子表数据
        List<SalesLedgerProduct> productData = ticketRegistrationDto.getProductData();
        if (productData != null && !productData.isEmpty()) {
        if (CollectionUtils.isNotEmpty(productData)) {
            handleSalesLedgerProducts(purchaseLedger.getId(), productData, 2);
        }
        // æ‰§è¡Œæ’入或更新操作
        int i;
        if (ticketRegistrationDto.getId() == null) {
            i = ticketRegistrationMapper.insert(ticketRegistration);
        } else {
            i = ticketRegistrationMapper.updateById(ticketRegistration);
        }
        // 5. æ‰§è¡Œæ’入或更新操作
        int rowsAffected = ticketRegistrationMapper.insert(ticketRegistration);
        // 6. å¢žåŠ é‡‡è´­å°è´¦äº§å“å¼€ç¥¨è®°å½•
        List<SalesLedgerProduct> salesLedgerProducts = ticketRegistrationDto.getProductData();
        if (CollectionUtils.isNotEmpty(salesLedgerProducts)){
            for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
                ProductRecord productRecord = new ProductRecord();
                productRecord.setTicketRegistrationId(ticketRegistration.getId());
                productRecord.setPurchaseLedgerId(ticketRegistrationDto.getPurchaseLedgerId());
                productRecord.setCreatedAt(DateUtils.getNowDate());
                BeanUtils.copyProperties(salesLedgerProduct,productRecord);
                productRecord.setId(null);
                productRecord.setType("2");
                productRecordMapper.insert(productRecord);
            }
        }
        // è¿ç§»ä¸´æ—¶æ–‡ä»¶åˆ°æ­£å¼ç›®å½•
        if (ticketRegistrationDto.getTempFileIds() != null && !ticketRegistrationDto.getTempFileIds().isEmpty()) {
            migrateTempFilesToFormal(ticketRegistration.getId(), ticketRegistrationDto.getTempFileIds());
        }
        return i;
        return rowsAffected;
    }
@@ -195,8 +223,21 @@
                .eq(SalesLedgerProduct::getType, 2);
        List<SalesLedgerProduct> productList = salesLedgerProductMapper.selectList(queryWrapper);
        resultDto.setProductData(productList);
        return resultDto;
    }
    @Override
    public List getTicketNo(TicketRegistrationDto ticketRegistrationDto) {
        LambdaQueryWrapper<TicketRegistration> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(TicketRegistration::getId,TicketRegistration::getInvoiceNumber,TicketRegistration::getInvoiceAmount)
                .eq(TicketRegistration::getPurchaseLedgerId,ticketRegistrationDto.getId());
        List<Map<String, Object>> result = ticketRegistrationMapper.selectMaps(queryWrapper);
        // å°†ä¸‹åˆ’线命名转换为驼峰命名
        return result.stream().map(map -> map.entrySet().stream()
                .collect(Collectors.toMap(
                        entry -> underlineToCamel(entry.getKey()),
                        Map.Entry::getValue))
        ).collect(Collectors.toList());
    }
    private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type) {
@@ -216,11 +257,57 @@
        // æ‰¹é‡æ›´æ–°ï¼ˆéœ€è¦ MyBatis æä¾›æ‰¹é‡æ›´æ–°æ–¹æ³•)
        if (!updateList.isEmpty()) {
            updateList.forEach(product -> {
                product.setFutureTickets(product.getQuantity().subtract(new BigDecimal(product.getTicketsNum())).longValue());
                product.setFutureTicketsAmount(product.getTaxExclusiveTotalPrice().subtract(product.getTicketsAmount()));
                // éžç©ºæ ¡éªŒï¼Œä»»ä¸€å­—段为空则抛出异常
                if (product.getQuantity() == null) {
                    throw new BaseException("数量不能为空");
                }
                if (product.getTicketsNum() == null) {
                    throw new BaseException("已开票数量不能为空");
                }
                if (product.getTaxInclusiveTotalPrice() == null) {
                    throw new BaseException("含税总价不能为空");
                }
                if (product.getTicketsAmount() == null) {
                    throw new BaseException("本次来票金额(元)不能为空");
                }
                // è®¡ç®— futureTickets(直接使用 BigDecimal è®¡ç®—,避免精度丢失)
                product.setFutureTickets(
                        product.getQuantity()
                                .subtract(BigDecimal.valueOf(product.getTicketsNum()))
                                .longValueExact() // ä½¿ç”¨ exact æ–¹æ³•确保无小数部分
                );
                // è®¡ç®— futureTicketsAmount
                product.setFutureTicketsAmount(
                        product.getTaxInclusiveTotalPrice()
                                .subtract(product.getTicketsAmount())
                );
                product.setType(type);
                salesLedgerProductMapper.updateById(product);
            });
        }
    }
    /**
     * ä¸‹åˆ’线命名转驼峰命名
     */
    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();
    }
}
src/main/java/com/ruoyi/sales/controller/ReceiptPaymentController.java
@@ -76,10 +76,39 @@
    @GetMapping("/getReceiptAmount")
    public AjaxResult getReceiptAmount() {
        try {
            BigDecimal amount = receiptPaymentService.getReceiptAmount();
            return AjaxResult.success(amount != null ? amount : BigDecimal.ZERO);
            BigDecimal receiptAmount = receiptPaymentService.getReceiptAmount();
            return AjaxResult.success(receiptAmount != null ? receiptAmount : BigDecimal.ZERO);
        } catch (Exception e) {
            return AjaxResult.error("获取合同金额失败:" + e.getMessage());
            return AjaxResult.error("获取回款金额失败:" + e.getMessage());
        }
    }
    /**
     * æŸ¥è¯¢å·²ç»ç»‘定发票的开票台账
     * @param page
     * @param receiptPaymentDto
     * @return
     */
    @GetMapping("/bindInvoiceNoRegPage")
    public AjaxResult bindInvoiceNoRegPage(Page page, ReceiptPaymentDto receiptPaymentDto) {
        return AjaxResult.success(receiptPaymentService.bindInvoiceNoRegPage(page,receiptPaymentDto));
    }
    /**
     * å¼€ç¥¨å°è´¦è¯¦æƒ…
     * @param id
     * @return
     */
    @GetMapping("/invoiceInfo")
    public AjaxResult invoiceInfo (Integer id) {
        return AjaxResult.success(receiptPaymentService.invoiceInfo(id));
    }
    /**
     * æœ¬æœˆåº”æ”¶,回款金额
     */
    @GetMapping("/getAmountMouth")
    public AjaxResult getAmountMouth() {
        return  AjaxResult.success(receiptPaymentService.getAmountMouth());
    }
}
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
@@ -6,16 +6,21 @@
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.sales.dto.InvoiceLedgerDto;
import com.ruoyi.sales.dto.SalesLedgerDto;
import com.ruoyi.sales.mapper.InvoiceLedgerMapper;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.service.ICommonFileService;
import com.ruoyi.sales.service.ISalesLedgerService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;
/**
 * é”€å”®å°è´¦Controller
@@ -32,6 +37,9 @@
    private ICommonFileService commonFileService;
    @Autowired
    private InvoiceLedgerMapper invoiceLedgerMapper;
    /**
     * æŸ¥è¯¢é”€å”®å°è´¦åˆ—表
     */
@@ -39,6 +47,23 @@
    public TableDataInfo list(SalesLedgerDto salesLedgerDto) {
        startPage();
        List<SalesLedger> list = salesLedgerService.selectSalesLedgerList(salesLedgerDto);
        // è®¡ç®—已开票金额/未开票金额(已填写发票金额为准)
        if(CollectionUtils.isEmpty(list)){
            return getDataTable(list);
        }
        List<Long> salesLedgerIds = list.stream().map(SalesLedger::getId).collect(Collectors.toList());
        List<InvoiceLedgerDto> invoiceLedgerDtoList = invoiceLedgerMapper.invoicedTotal(salesLedgerIds);
        if(CollectionUtils.isEmpty(invoiceLedgerDtoList)){
            return getDataTable(list);
        }
        for (SalesLedger salesLedger : list) {
            for (InvoiceLedgerDto invoiceLedgerDto : invoiceLedgerDtoList) {
                if (salesLedger.getId().intValue() == invoiceLedgerDto.getSalesLedgerId()) {
                    BigDecimal noInvoiceAmountTotal = salesLedger.getContractAmount().subtract(invoiceLedgerDto.getInvoiceTotal());
                    salesLedger.setNoInvoiceAmountTotal(noInvoiceAmountTotal);
                }
            }
        }
        return getDataTable(list);
    }
@@ -112,8 +137,8 @@
    @GetMapping("/getContractAmount")
    public AjaxResult getContractAmount() {
        try {
            BigDecimal amount = salesLedgerService.getContractAmount();
            return AjaxResult.success(amount != null ? amount : BigDecimal.ZERO);
            BigDecimal contractAmount = salesLedgerService.getContractAmount();
            return AjaxResult.success(contractAmount != null ? contractAmount : BigDecimal.ZERO);
        } catch (Exception e) {
            return AjaxResult.error("获取合同金额失败:" + e.getMessage());
        }
@@ -126,4 +151,12 @@
    public AjaxResult getTopFiveList() {
        return AjaxResult.success(salesLedgerService.getTopFiveList());
    }
    /**
     * è¿‘半年开票,回款金额
     */
    @GetMapping("/getAmountHalfYear")
    public AjaxResult getAmountHalfYear() {
        return AjaxResult.success(salesLedgerService.getAmountHalfYear());
    }
}
src/main/java/com/ruoyi/sales/dto/InvoiceLedgerDto.java
@@ -33,4 +33,13 @@
    @ApiModelProperty(value = "未回款金额")
    private BigDecimal unReceiptPaymentAmount;
    @ApiModelProperty(value = "税率")
    private BigDecimal taxRate;
    @ApiModelProperty(value = "销售合同号")
    private String salesContractNo;
    @ApiModelProperty(value = "销售合同ID")
    private Integer salesLedgerId;
}
src/main/java/com/ruoyi/sales/dto/MonthlyAmountDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package com.ruoyi.sales.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class MonthlyAmountDto {
    private String month;
    private BigDecimal invoiceAmount; // å¼€ç¥¨é‡‘额
    private BigDecimal receiptAmount; // å›žæ¬¾é‡‘额
}
src/main/java/com/ruoyi/sales/dto/ReceiptPaymentDto.java
@@ -4,6 +4,8 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class ReceiptPaymentDto extends ReceiptPayment {
@@ -16,4 +18,31 @@
    @ApiModelProperty(value = "查询文本")
    private String searchText;
    @ApiModelProperty(value = "销售台账sales_ledger")
    private Integer salesLedgerId;
    @ApiModelProperty(value = "销售合同号")
    private String salesContractNo;
    @ApiModelProperty(value = "客户名称ID")
    private Integer customerId;
    @ApiModelProperty(value = "发票号")
    private String invoiceNo;
    @ApiModelProperty(value = "发票金额")
    private BigDecimal invoiceTotal;
    @ApiModelProperty(value = "税率")
    private BigDecimal taxRate;
    @ApiModelProperty(value = "产品大类")
    private String productCategory;
    @ApiModelProperty(value = "回款金额")
    private BigDecimal receiptPaymentAmountTotal;
    @ApiModelProperty(value = "待回款金额")
    private BigDecimal noReceiptAmount;
}
src/main/java/com/ruoyi/sales/mapper/InvoiceLedgerMapper.java
@@ -41,7 +41,7 @@
     * @param invoiceLedgerDto
     * @return
     */
    IPage<InvoiceLedgerDto> invoiceLedgerSalesAccount(Page page, InvoiceLedgerDto invoiceLedgerDto);
    IPage<InvoiceLedgerDto> invoiceLedgerSalesAccount(Page page,@Param("invoiceLedgerDto") InvoiceLedgerDto invoiceLedgerDto);
    /**
     * äº§å“å¼€ç¥¨å°è´¦è¯¦æƒ…
@@ -50,4 +50,11 @@
     */
    InvoiceRegistrationProductDto invoiceLedgerProductInfo(Integer id);
    /**
     * æ ¹æ®é”€å”®åˆåŒè®¡ç®—已开票金额
     * @param salesLedgerIds
     * @return
     */
    List<InvoiceLedgerDto> invoicedTotal(List<Long> salesLedgerIds);
}
src/main/java/com/ruoyi/sales/mapper/ReceiptPaymentMapper.java
@@ -3,13 +3,40 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.sales.dto.InvoiceLedgerDto;
import com.ruoyi.sales.dto.ReceiptPaymentDto;
import com.ruoyi.sales.pojo.ReceiptPayment;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
public interface ReceiptPaymentMapper extends BaseMapper<ReceiptPayment> {
    IPage<ReceiptPaymentDto> receiptPaymentListPage(Page page, @Param("receiptPaymentDto") ReceiptPaymentDto receiptPaymentDto);
    ReceiptPaymentDto receiptPaymentInfo(Integer id);
    /**
     * æŸ¥è¯¢å·²ç»ç»‘定发票的开票台账
     * @param page
     * @param receiptPaymentDto
     * @return
     */
    IPage<ReceiptPaymentDto> bindInvoiceNoRegPage(Page page, ReceiptPaymentDto receiptPaymentDto);
    /**
     * å¼€ç¥¨å°è´¦è¯¦æƒ…
     * @param id
     * @return
     */
    InvoiceLedgerDto invoiceInfo(Integer id);
    /**
     * è®¡ç®—前多少条数据回款金额综合
     * @param customerId
     * @param total
     * @return
     */
    BigDecimal getReceiptAmount(@Param("customerId") Integer customerId, @Param("total") long total);
}
src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
@@ -1,9 +1,13 @@
package com.ruoyi.sales.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.ruoyi.sales.pojo.SalesLedger;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List;
/**
@@ -21,4 +25,6 @@
    List<Integer> selectSequencesByDate(@Param("datePart") String datePart);
    List getSalesNo();
    <T> BigDecimal selectSum(LambdaQueryWrapper<T> wrapper, SFunction<T, BigDecimal> column);
}
src/main/java/com/ruoyi/sales/pojo/ReceiptPayment.java
@@ -22,24 +22,6 @@
    @TableId(type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty(value = "销售台账sales_ledger")
    private Integer salesLedgerId;
    @ApiModelProperty(value = "销售合同号")
    private String salesContractNo;
    @ApiModelProperty(value = "客户名称ID")
    private Integer customerId;
    @ApiModelProperty(value = "发票号")
    private String invoiceNo;
    @ApiModelProperty(value = "发票金额")
    private BigDecimal invoiceAmount;
    @ApiModelProperty(value = "税率")
    private BigDecimal taxRate;
    @ApiModelProperty(value = "回款形式 0电汇1承兑")
    private String receiptPaymentType;
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
@@ -6,6 +6,7 @@
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
@@ -93,5 +94,9 @@
     */
    @Excel(name = "合同金额")
    private BigDecimal contractAmount;
    @TableField(exist = false)
    @ApiModelProperty(value = "未开票金额(元)")
    private BigDecimal noInvoiceAmountTotal;
}
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -141,4 +141,8 @@
     * äº§å“è§„æ ¼id
     */
    private Long productModelId;
    @ApiModelProperty(value = "初始未开票数")
    @TableField(exist = false)
    private Integer originalNoInvoiceNum;
}
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
@@ -1,6 +1,7 @@
package com.ruoyi.sales.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.sales.dto.MonthlyAmountDto;
import com.ruoyi.sales.dto.SalesLedgerDto;
import com.ruoyi.sales.pojo.SalesLedger;
@@ -28,4 +29,6 @@
    BigDecimal getContractAmount();
    List getTopFiveList();
    List<MonthlyAmountDto> getAmountHalfYear();
}
src/main/java/com/ruoyi/sales/service/ReceiptPaymentService.java
@@ -2,11 +2,13 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.sales.dto.InvoiceLedgerDto;
import com.ruoyi.sales.dto.ReceiptPaymentDto;
import com.ruoyi.sales.pojo.ReceiptPayment;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
public interface ReceiptPaymentService {
@@ -47,4 +49,21 @@
    ReceiptPaymentDto receiptPaymentInfo(Integer id);
    BigDecimal getReceiptAmount();
    /**
     * æŸ¥è¯¢å·²ç»ç»‘定发票的开票台账
     * @param page
     * @param receiptPaymentDto
     * @return
     */
    IPage<ReceiptPaymentDto> bindInvoiceNoRegPage(Page page, ReceiptPaymentDto receiptPaymentDto);
    /**
     * å¼€ç¥¨å°è´¦è¯¦æƒ…
     * @param id
     * @return
     */
    InvoiceLedgerDto invoiceInfo(Integer id);
    Map<String,BigDecimal> getAmountMouth();
}
src/main/java/com/ruoyi/sales/service/impl/InvoiceLedgerServiceImpl.java
@@ -13,11 +13,8 @@
import com.ruoyi.sales.mapper.InvoiceLedgerFileMapper;
import com.ruoyi.sales.mapper.InvoiceLedgerMapper;
import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper;
import com.ruoyi.sales.mapper.ReceiptPaymentMapper;
import com.ruoyi.sales.pojo.InvoiceLedger;
import com.ruoyi.sales.pojo.InvoiceLedgerFile;
import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
import com.ruoyi.sales.pojo.ReceiptPayment;
import com.ruoyi.sales.service.InvoiceLedgerService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
@@ -33,7 +30,6 @@
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
@@ -214,11 +210,17 @@
        if(CollectionUtils.isEmpty(invoiceLedgerDto.getFileList())){
            throw new RuntimeException("缺少文件信息");
        }
        QueryWrapper<InvoiceLedger> ledgerQueryWrapper = new QueryWrapper<>();
        ledgerQueryWrapper.eq("invoice_registration_product_id", invoiceLedgerDto.getId());
        InvoiceLedger invoiceLedger = invoiceLedgerMapper.selectOne(ledgerQueryWrapper);
        if(ObjectUtils.isEmpty(invoiceLedger)){
            throw new RuntimeException("开票台账未登记");
        }
        List<FileVo> fileList = invoiceLedgerDto.getFileList();
        fileList.forEach(fileVo -> {
            InvoiceLedgerFile invoiceLedgerFile = new InvoiceLedgerFile();
            BeanUtils.copyProperties(fileVo, invoiceLedgerFile);
            invoiceLedgerFile.setInvoiceLedgerId(invoiceLedgerDto.getId());
            invoiceLedgerFile.setInvoiceLedgerId(invoiceLedger.getId());
            invoiceLedgerFileMapper.insert(invoiceLedgerFile);
        });
    }
@@ -242,20 +244,6 @@
    @Override
    public IPage<InvoiceLedgerDto> invoiceLedgerSalesAccount(Page page, InvoiceLedgerDto invoiceLedgerDto) {
        IPage<InvoiceLedgerDto> invoiceLedgerDtoIPage = invoiceLedgerMapper.invoiceLedgerSalesAccount(page, invoiceLedgerDto);
//        for (InvoiceLedgerDto record : invoiceLedgerDtoIPage.getRecords()) {
//            QueryWrapper<ReceiptPayment> queryWrapper = new QueryWrapper<>();
//            queryWrapper.eq("customer_id", record.getCustomerId());
//            List<ReceiptPayment> receiptPaymentList = receiptPaymentMapper.selectList(queryWrapper);
//            BigDecimal totalAmount = BigDecimal.ZERO;
//            if(!CollectionUtils.isEmpty(receiptPaymentList)){
//                for (ReceiptPayment receiptPayment : receiptPaymentList) {
//                    totalAmount = totalAmount.add(receiptPayment.getInvoiceAmount());
//                }
//            }
//            BigDecimal unReceiptPaymentAmount = record.getInvoiceAmount().subtract(totalAmount);
//            record.setReceiptPaymentAmount(totalAmount);
//            record.setUnReceiptPaymentAmount(unReceiptPaymentAmount);
//        }
        return invoiceLedgerDtoIPage;
    }
@@ -272,13 +260,12 @@
        // æ‰§è¡ŒæŸ¥è¯¢å¹¶è®¡ç®—总和
        List<InvoiceLedger> invoiceLedgers = invoiceLedgerMapper.selectList(queryWrapper);
//        BigDecimal totalContractAmount = invoiceLedgers.stream()
//                .map(InvoiceLedger::getInvoiceAmount)
//                .filter(Objects::nonNull)
//                .reduce(BigDecimal.ZERO, BigDecimal::add);
//
//        return totalContractAmount;
        return null;
        BigDecimal totalContractAmount = invoiceLedgers.stream()
                .map(InvoiceLedger::getInvoiceTotal)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        return totalContractAmount;
    }
    /**
src/main/java/com/ruoyi/sales/service/impl/ReceiptPaymentServiceImpl.java
@@ -4,17 +4,24 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.sales.dto.InvoiceLedgerDto;
import com.ruoyi.sales.dto.ReceiptPaymentDto;
import com.ruoyi.sales.mapper.ReceiptPaymentMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.pojo.ReceiptPayment;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.service.ReceiptPaymentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Service
@@ -22,6 +29,9 @@
    @Autowired
    private ReceiptPaymentMapper receiptPaymentMapper;
    @Autowired
    private SalesLedgerMapper salesLedgerMapper;
    /**
     * å›žæ¬¾ç™»è®°æ–°å¢ž
@@ -67,7 +77,23 @@
     */
    @Override
    public IPage<ReceiptPaymentDto> receiptPaymentListPage(Page page, ReceiptPaymentDto receiptPaymentDto) {
        return receiptPaymentMapper.receiptPaymentListPage(page, receiptPaymentDto);
        // è®¡ç®—分页前page.current-1 * limit条数的综合计算已经收回的回款金额
        // è®¡ç®—已经分页的条数
        long total = (page.getCurrent() - 1) * page.getSize();
        BigDecimal receiptAmount = receiptPaymentMapper.getReceiptAmount(receiptPaymentDto.getCustomerId(), total);
        if(ObjectUtils.isEmpty(receiptAmount)){
            receiptAmount = BigDecimal.ZERO;
        }
        IPage<ReceiptPaymentDto> iPage = receiptPaymentMapper.receiptPaymentListPage(page, receiptPaymentDto);
        // å¼€ç¥¨æ€»é‡‘额
        BigDecimal invoiceTotal = CollectionUtils.isEmpty(iPage.getRecords()) ? BigDecimal.ZERO : iPage.getRecords().get(0).getInvoiceTotal();
        // å½“前应收金额
        BigDecimal currentUnReceiptAmount = invoiceTotal.subtract(receiptAmount);
        for (ReceiptPaymentDto record : iPage.getRecords()) {
            currentUnReceiptAmount = currentUnReceiptAmount.subtract(record.getReceiptPaymentAmount());
            record.setNoReceiptAmount(currentUnReceiptAmount);
        }
        return iPage;
    }
    /**
@@ -100,4 +126,55 @@
        return totalContractAmount;
    }
    /**
     * æŸ¥è¯¢å·²ç»ç»‘定发票的开票台账
     * @param page
     * @param receiptPaymentDto
     * @return
     */
    @Override
    public IPage<ReceiptPaymentDto> bindInvoiceNoRegPage(Page page, ReceiptPaymentDto receiptPaymentDto) {
        return receiptPaymentMapper.bindInvoiceNoRegPage(page, receiptPaymentDto);
    }
    /**
     * å¼€ç¥¨å°è´¦è¯¦æƒ…
     * @param id
     * @return
     */
    @Override
    public InvoiceLedgerDto invoiceInfo(Integer id) {
        return receiptPaymentMapper.invoiceInfo(id);
    }
    @Override
    public Map<String,BigDecimal> getAmountMouth() {
        List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(null);
        BigDecimal contractAmount = salesLedgers.stream().map(SalesLedger::getContractAmount)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        LocalDate now = LocalDate.now();
        YearMonth currentMonth = YearMonth.from(now);
        // åˆ›å»ºLambdaQueryWrapper
        LambdaQueryWrapper<ReceiptPayment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ge(ReceiptPayment::getReceiptPaymentDate, currentMonth.atDay(1).atStartOfDay())  // å¤§äºŽç­‰äºŽæœ¬æœˆç¬¬ä¸€å¤©
                .lt(ReceiptPayment::getReceiptPaymentDate, currentMonth.plusMonths(1).atDay(1).atStartOfDay()); // å°äºŽä¸‹æœˆç¬¬ä¸€å¤©
        // æ‰§è¡ŒæŸ¥è¯¢å¹¶è®¡ç®—总和
        List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(queryWrapper);
        BigDecimal receiveAmount = receiptPayments.stream()
                .map(ReceiptPayment::getReceiptPaymentAmount)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // æž„建结果
        Map<String, BigDecimal> result = new HashMap<>();
        result.put("receiveAmount", receiveAmount);
        result.put("contractAmount", contractAmount);
        return result;
    }
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -1,25 +1,28 @@
package com.ruoyi.sales.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.dto.InvoiceRegistrationProductDto;
import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.service.ISalesLedgerProductService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -39,6 +42,9 @@
    private PurchaseLedgerMapper purchaseLedgerMapper;
    @Autowired
    private InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
    @Override
    public SalesLedgerProduct selectSalesLedgerProductById(Long id) {
        return salesLedgerProductMapper.selectById(id);
@@ -49,7 +55,29 @@
        LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerProduct.getSalesLedgerId())
                .eq(SalesLedgerProduct::getType, salesLedgerProduct.getType());
        return salesLedgerProductMapper.selectList(queryWrapper);
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(queryWrapper);
        if(!CollectionUtils.isEmpty(salesLedgerProducts)){
            InvoiceRegistrationProductDto invoiceRegistrationProductDto = new InvoiceRegistrationProductDto();
            invoiceRegistrationProductDto.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId().intValue());
            List<InvoiceRegistrationProductDto> invoiceRegistrationProductDtoList = invoiceRegistrationProductMapper.invoiceRegistrationProductList(invoiceRegistrationProductDto);
            // ç»Ÿè®¡å¼€ç¥¨ç™»è®°äº§å“çš„已开票数/已开票金额
            if(!CollectionUtils.isEmpty(invoiceRegistrationProductDtoList)){
                for (SalesLedgerProduct ledgerProduct : salesLedgerProducts) {
                    int invoiceNum = 0;
                    BigDecimal invoiceAmount = BigDecimal.ZERO;
                    for (InvoiceRegistrationProductDto registrationProductDto : invoiceRegistrationProductDtoList) {
                        if(ledgerProduct.getId().intValue() == registrationProductDto.getSalesLedgerProductId()){
                            invoiceNum += registrationProductDto.getInvoiceNum();
                            invoiceAmount = invoiceAmount.add(registrationProductDto.getInvoiceAmount());
                        }
                    }
                    ledgerProduct.setInvoiceNum(invoiceNum);
                    ledgerProduct.setInvoiceAmount(invoiceAmount);
                }
            }
        }
        return salesLedgerProducts;
    }
    @Override
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -1,7 +1,6 @@
package com.ruoyi.sales.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -12,15 +11,10 @@
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.other.pojo.TempFile;
import com.ruoyi.sales.dto.MonthlyAmountDto;
import com.ruoyi.sales.dto.SalesLedgerDto;
import com.ruoyi.sales.mapper.CommonFileMapper;
import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.CommonFile;
import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.mapper.*;
import com.ruoyi.sales.pojo.*;
import com.ruoyi.sales.service.ISalesLedgerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -32,7 +26,6 @@
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import java.io.IOException;
import java.lang.reflect.Field;
@@ -71,6 +64,10 @@
    private final TempFileMapper tempFileMapper;
    private final ReceiptPaymentMapper receiptPaymentMapper;
    private final InvoiceLedgerMapper invoiceLedgerMapper;
    @Autowired
    private InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
@@ -103,6 +100,9 @@
        LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>();
        productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId());
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
        for (SalesLedgerProduct product : products) {
            product.setOriginalNoInvoiceNum(product.getNoInvoiceNum());
        }
        // 3.查询上传文件
        LambdaQueryWrapper<CommonFile> salesLedgerFileWrapper = new LambdaQueryWrapper<>();
@@ -159,8 +159,114 @@
    @Override
    public List getTopFiveList() {
        return null;
        // æŸ¥è¯¢åŽŸå§‹æ•°æ®
        LambdaQueryWrapper<SalesLedger> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(SalesLedger::getCustomerId,
                        SalesLedger::getCustomerName,
                        SalesLedger::getContractAmount)
                .orderByDesc(SalesLedger::getContractAmount);
        List<SalesLedger> records = salesLedgerMapper.selectList(queryWrapper);
        // æŒ‰å®¢æˆ·ID分组并聚合金额
        Map<Long, GroupedCustomer> groupedMap = new LinkedHashMap<>(); // ä½¿ç”¨LinkedHashMap保持排序
        for (SalesLedger record : records) {
            groupedMap.computeIfAbsent(record.getCustomerId(),
                            k -> new GroupedCustomer(record.getCustomerId(), record.getCustomerName()))
                    .addAmount(record.getContractAmount());
        }
        // è½¬æ¢ä¸ºç»“果列表并取前5
        return groupedMap.values().stream()
                .sorted(Comparator.comparing(GroupedCustomer::getTotalAmount).reversed())
                .limit(5)
                .map(customer -> {
                    Map<String, Object> result = new HashMap<>();
                    result.put("customerId", customer.getCustomerId());
                    result.put("customerName", customer.getCustomerName());
                    result.put("totalAmount", customer.getTotalAmount());
                    return result;
                })
                .collect(Collectors.toList());
    }
    @Override
    public List<MonthlyAmountDto> getAmountHalfYear() {
        LocalDate now = LocalDate.now();
        YearMonth currentMonth = YearMonth.from(now);
        List<MonthlyAmountDto> monthlyAmounts = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            YearMonth targetMonth = currentMonth.minusMonths(i);
            LocalDate firstDayOfMonth = targetMonth.atDay(1);
            LocalDate firstDayOfNextMonth = targetMonth.plusMonths(1).atDay(1);
            LocalDateTime startOfMonth = firstDayOfMonth.atStartOfDay();
            LocalDateTime startOfNextMonth = firstDayOfNextMonth.atStartOfDay();
            LambdaQueryWrapper<ReceiptPayment> receiptPaymentLambdaQueryWrapper = new LambdaQueryWrapper<>();
            receiptPaymentLambdaQueryWrapper.ge(ReceiptPayment::getCreateTime, startOfMonth)
                    .lt(ReceiptPayment::getCreateTime, startOfNextMonth);
            LambdaQueryWrapper<InvoiceLedger> invoiceLedgerLambdaQueryWrapper = new LambdaQueryWrapper<>();
            invoiceLedgerLambdaQueryWrapper.ge(InvoiceLedger::getCreateTime, startOfMonth)
                    .lt(InvoiceLedger::getCreateTime, startOfNextMonth);
            // èŽ·å–å›žæ¬¾é‡‘é¢
            List<ReceiptPayment> receiptPaymentList = receiptPaymentMapper.selectList(receiptPaymentLambdaQueryWrapper);
            //开票金额
            List<InvoiceLedger> invoiceLedgerList = invoiceLedgerMapper.selectList(invoiceLedgerLambdaQueryWrapper);
            // ä½¿ç”¨ Stream æ±‚å’Œ
            BigDecimal invoiceAmount = invoiceLedgerList.stream()
                    .map(InvoiceLedger::getInvoiceTotal)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal receiptAmount = receiptPaymentList.stream()
                    .map(ReceiptPayment::getReceiptPaymentAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            MonthlyAmountDto monthlyAmount = new MonthlyAmountDto();
            monthlyAmount.setMonth(targetMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")));
            monthlyAmount.setInvoiceAmount(invoiceAmount);
            monthlyAmount.setReceiptAmount(receiptAmount);
            monthlyAmounts.add(monthlyAmount);
        }
        Collections.reverse(monthlyAmounts);
        return monthlyAmounts;
    }
    // å†…部类用于存储聚合结果
    private static class GroupedCustomer {
        private final Long customerId;
        private final String customerName;
        private BigDecimal totalAmount = BigDecimal.ZERO;
        public GroupedCustomer(Long customerId, String customerName) {
            this.customerId = customerId;
            this.customerName = customerName;
        }
        public void addAmount(BigDecimal amount) {
            if (amount != null) {
                this.totalAmount = this.totalAmount.add(amount);
            }
        }
        public Long getCustomerId() {
            return customerId;
        }
        public String getCustomerName() {
            return customerName;
        }
        public BigDecimal getTotalAmount() {
            return totalAmount;
        }
    }
    /**
src/main/resources/application-druid.yml
@@ -62,5 +62,8 @@
                        multi-statement-allow: true
file:
    temp-dir: D:/ruoyi/temp/uploads   # ä¸´æ—¶ç›®å½•
    upload-dir: D:/ruoyi/prod/uploads # æ­£å¼ç›®å½•
#    temp-dir: D:/ruoyi/temp/uploads   # ä¸´æ—¶ç›®å½•
#    upload-dir: D:/ruoyi/prod/uploads # æ­£å¼ç›®å½•
    temp-dir: /javaWork/product-inventory-management/file/temp/uploads
    upload-dir: /javaWork/product-inventory-management/file/prod/uploads
src/main/resources/application.yml
@@ -16,7 +16,7 @@
# å¼€å‘环境配置
server:
  # æœåŠ¡å™¨çš„HTTP端口,默认为8080
  port: 8080
  port: 7003
  servlet:
    # åº”用的访问路径
    context-path: /
@@ -34,7 +34,7 @@
# æ—¥å¿—配置
logging:
  level:
    com.ruoyi: debug
    com.ruoyi: warn
    org.springframework: warn
# ç”¨æˆ·é…ç½®
@@ -68,13 +68,13 @@
  # redis é…ç½®
  redis:
    # åœ°å€
    host: localhost
    host: 127.0.0.1
    # ç«¯å£ï¼Œé»˜è®¤ä¸º6379
    port: 6379
    # æ•°æ®åº“索引
    database: 0
    # å¯†ç 
    password:
    password: root2022!
    # è¿žæŽ¥è¶…æ—¶æ—¶é—´
    timeout: 10s
    lettuce:
src/main/resources/mapper/purchase/PaymentRegistrationMapper.xml
@@ -9,7 +9,7 @@
        <result property="saleLedgerId" column="sale_ledger_id"/>
        <result property="purchaseLedgerId" column="purchase_ledger_id"/>
        <result property="supplierId" column="supplier_id"/>
        <result property="invoicePurchaseId" column="invoice_purchase_id"/>
        <result property="ticketRegistrationId" column="ticket_registration_id"/>
        <result property="currentPaymentAmount" column="current_payment_amount"/>
        <result property="paymentMethod" column="payment_method"/>
        <result property="registrantId" column="registrant_id"/>
@@ -17,6 +17,7 @@
        <result property="createTime" column="create_time"/>
        <result property="updateTime" column="update_time"/>
        <result property="tenantId" column="tenant_id"/>
        <result property="registrationtDate" column="registrationt_date"/>
    </resultMap>
    <resultMap type="com.ruoyi.purchase.dto.PaymentRegistrationDto" id="PaymentRegistrationDtoResult">
@@ -24,7 +25,7 @@
        <result property="saleLedgerId" column="sale_ledger_id"/>
        <result property="purchaseLedgerId" column="purchase_ledger_id"/>
        <result property="supplierId" column="supplier_id"/>
        <result property="invoicePurchaseId" column="invoice_purchase_id"/>
        <result property="ticketRegistrationId" column="ticket_registration_id"/>
        <result property="currentPaymentAmount" column="current_payment_amount"/>
        <result property="paymentMethod" column="payment_method"/>
        <result property="registrantId" column="registrant_id"/>
@@ -38,6 +39,7 @@
        <result property="taxRate" column="tax_rate"/>
        <result property="invoiceAmount" column="invoice_amount"/>
        <result property="tenantId" column="tenant_id"/>
        <result property="registrationtDate" column="registrationt_date"/>
    </resultMap>
    <sql id="selectPaymentRegistrationVo">
@@ -45,7 +47,7 @@
               pr.sale_ledger_id,
               pr.purchase_ledger_id,
               pr.supplier_id,
               pr.invoice_purchase_id,
               pr.ticket_registration_id,
               pr.current_payment_amount,
               pr.payment_method,
               pr.registrant_id,
@@ -57,13 +59,15 @@
               pl.purchase_contract_number as purchase_contract_number,
               sm.supplier_name as supplier_name,
               ip.invoice_number as invoice_number,
               ip.tax_rate as tax_rate,
               ip.invoice_amount as invoice_amount
               ip.invoice_amount as invoice_amount,
               pr.tax_rate,
               pr.registrationt_date,
               su.nick_name as registrant
        from payment_registration pr
                 left join sales_ledger sl on pr.sale_ledger_id = sl.id
                 left join purchase_ledger pl on pr.purchase_ledger_id = pl.id
                 left join supplier_manage sm on pr.supplier_id = sm.id
                 left join invoice_purchase ip on pr.invoice_purchase_id = ip.id
                 left join ticket_registration ip on pr.ticket_registration_id = ip.id
                 left join sys_user su on pr.registrant_id = su.user_id
    </sql>
src/main/resources/mapper/sales/InvoiceLedgerMapper.xml
@@ -111,15 +111,22 @@
    <select id="invoiceLedgerSalesAccount" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto">
        SELECT
            customer_id,
            T2.customer_name,
            SUM( invoice_amount ) invoiceAmount
            T4.id,T4.customer_name ,
            SUM(invoice_total) AS invoice_total,
            IFNULL( T5.receipt_payment_amount , 0 ) AS receipt_payment_amount,
            (invoice_total - receipt_payment_amount) AS unReceipt_payment_amount
        FROM
            invoice_ledger T1
                LEFT JOIN customer T2 ON T1.customer_id = T2.id
        GROUP BY
            customer_id,
            T2.customer_name;
                LEFT JOIN invoice_registration_product T2 ON T1.invoice_registration_product_id = T2.id
                LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id
                LEFT JOIN customer T4 ON T4.id = T3.customer_id
                LEFT JOIN ( SELECT invoice_ledger_id, SUM( receipt_payment_amount ) AS receipt_payment_amount FROM receipt_payment GROUP BY invoice_ledger_id ) T5 ON T5.invoice_ledger_id = T1.id
        <where>
            <if test="invoiceLedgerDto.searchText != null and invoiceLedgerDto.searchText != '' ">
                T4.customer_name LIKE CONCAT ('%',#{invoiceLedgerDto.searchText},'%')
            </if>
        </where>
        GROUP BY T4.id,T4.customer_name
    </select>
    <select id="invoiceLedgerProductInfo" resultType="com.ruoyi.sales.dto.InvoiceRegistrationProductDto">
@@ -160,5 +167,22 @@
        WHERE T1.id = #{id}
    </select>
    <select id="invoicedTotal" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto">
        SELECT
            IFNULL(SUM(T1.invoice_total),0) AS invoice_total,
            T2.sales_ledger_id
        FROM
            invoice_ledger T1
                LEFT JOIN invoice_registration_product T2 ON T1.invoice_registration_product_id = T2.id
        <where>
            AND T2.sales_ledger_id IN
            <foreach collection="salesLedgerIds" item="item" open="(" close=")" separator=",">
                #{item}
            </foreach>
        </where>
        GROUP BY
            T2.sales_ledger_id
    </select>
</mapper>
src/main/resources/mapper/sales/InvoiceRegistrationProductMapper.xml
@@ -33,6 +33,9 @@
            <if test="invoiceRegistrationProductDto.invoiceRegistrationId != null">
                invoice_registration_id = #{invoiceRegistrationProductDto.invoiceRegistrationId}
            </if>
            <if test="invoiceRegistrationProductDto.salesLedgerId != null">
                sales_ledger_id = #{invoiceRegistrationProductDto.salesLedgerId}
            </if>
        </where>
    </select>
src/main/resources/mapper/sales/ReceiptPaymentMapper.xml
@@ -5,39 +5,31 @@
<mapper namespace="com.ruoyi.sales.mapper.ReceiptPaymentMapper">
    <select id="receiptPaymentListPage" resultType="com.ruoyi.sales.dto.ReceiptPaymentDto">
        SELECT
            T1.id                 ,
            T1.sales_ledger_id        ,
            T1.sales_contract_no      ,
            T1.customer_id            ,
            T1.invoice_no             ,
            T1.invoice_amount         ,
            T1.tax_rate               ,
            T1.receipt_payment_type   ,
            T1.receipt_payment_amount ,
            T1.registrant             ,
            T1.receipt_payment_date   ,
            T1.create_time            ,
            T1.create_user            ,
            T1.update_time            ,
            T1.update_user            ,
            T1.tenant_id,
            T3.customer_contract_no,
            T2.customer_name
        FROM receipt_payment T1
        LEFT JOIN customer T2 ON T1.customer_id = T2.id
        LEFT JOIN sales_ledger T3 ON T1.sales_ledger_id = T3.id
            T4.customer_id,
            IFNULL(T5.invoice_total,0) AS invoice_total,
            T1.receipt_payment_amount,
            T1.receipt_payment_date
        FROM
            receipt_payment T1
        LEFT JOIN invoice_ledger T2 ON T1.invoice_ledger_id = T2.id
        LEFT JOIN invoice_registration_product T3 ON T2.invoice_registration_product_id = T3.id
        LEFT JOIN sales_ledger T4 ON T4.id = T3.sales_ledger_id
        LEFT JOIN (
            SELECT
                T3.customer_id,
                SUM( invoice_total ) AS invoice_total
            FROM
                invoice_ledger T1
            LEFT JOIN invoice_registration_product T2 ON T1.invoice_registration_product_id = T2.id
            LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id
            GROUP BY T3.customer_id
        ) T5 ON T5.customer_id = T4.customer_id
        <where>
            <if test="receiptPaymentDto.searchText != null and receiptPaymentDto.searchText != ''">
                AND (
                T2.customer_name LIKE CONCAT('%',#{receiptPaymentDto.searchText},'%')
                OR T1.sales_contract_no LIKE CONCAT('%',#{receiptPaymentDto.searchText},'%')
                )
            </if>
            <if test="receiptPaymentDto.customerId != null">
                AND T1.customer_id = #{receiptPaymentDto.customerId}
                AND T4.customer_id = #{receiptPaymentDto.customerId}
            </if>
        </where>
        ORDER BY  T1.receipt_payment_date ASC
        ORDER BY T1.create_time ASC
    </select>
    <select id="receiptPaymentInfo" resultType="com.ruoyi.sales.dto.ReceiptPaymentDto">
@@ -67,4 +59,87 @@
        WHERE T1.id = #{id}
    </select>
    <select id="bindInvoiceNoRegPage" resultType="com.ruoyi.sales.dto.ReceiptPaymentDto">
        SELECT
            T1.id                ,
            T1.invoice_no        ,
            T1.invoice_total    ,
            T1.invoice_person    ,
            T1.invoice_date      ,
            T1.create_time       ,
            T1.create_user       ,
            T1.update_time       ,
            T1.update_user       ,
            T1.tenant_id         ,
            T2.tax_rate,
            T3.sales_contract_no,
            T3.customer_contract_no,
            T3.customer_name,
            T4.invoiceFileName,
            T5.product_category,
            IFNULL(T6.receipt_payment_amount_total ,0) AS receipt_payment_amount_total,
            (T1.invoice_total  - IFNULL(T6.receipt_payment_amount_total ,0)) AS no_receipt_amount
        FROM invoice_ledger T1
                 LEFT JOIN invoice_registration_product T2 ON T2.id = T1.invoice_registration_product_id
                 LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id
                 LEFT JOIN (
            SELECT
                invoice_ledger_id,
                GROUP_CONCAT( name ORDER BY id ASC SEPARATOR ' | ') AS invoiceFileName
            FROM invoice_ledger_file GROUP BY invoice_ledger_id
        ) T4 ON T4.invoice_ledger_id = T1.id
                 LEFT JOIN sales_ledger_product T5 ON T2.sales_ledger_product_id = T5.id
                 LEFT JOIN (
            SELECT SUM(receipt_payment_amount) AS receipt_payment_amount_total,invoice_ledger_id FROM receipt_payment GROUP BY invoice_ledger_id
        )  T6 ON T1.id = T6.invoice_ledger_id
        ORDER BY T2.create_time DESC
    </select>
    <select id="invoiceInfo" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto">
        SELECT
            T1.id,
            T1.invoice_no,
            T1.invoice_total ,
            T2.tax_rate,
            T3.customer_name,
            T3.sales_contract_no
        FROM
            invoice_ledger T1
                LEFT JOIN
            invoice_registration_product T2 ON T1.invoice_registration_product_id = T2.id
                LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id
        WHERE T1.id = #{id}
    </select>
    <select id="getReceiptAmount" resultType="java.math.BigDecimal">
        SELECT
            SUM( receipt_payment_amount ) AS total_amount
        FROM
            (
                SELECT
                    T1.receipt_payment_amount
                FROM
                    receipt_payment T1
                        LEFT JOIN invoice_ledger T2 ON T1.invoice_ledger_id = T2.id
                        LEFT JOIN invoice_registration_product T3 ON T2.invoice_registration_product_id = T3.id
                        LEFT JOIN sales_ledger T4 ON T4.id = T3.sales_ledger_id
                        LEFT JOIN (
                        SELECT
                            T3.customer_id,
                            SUM( invoice_total ) AS invoice_total
                        FROM
                            invoice_ledger T1
                                LEFT JOIN invoice_registration_product T2 ON T1.invoice_registration_product_id = T2.id
                                LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id
                        GROUP BY
                            T3.customer_id
                    ) T5 ON T5.customer_id = T4.customer_id
                WHERE
                    T4.customer_id = #{customerId}
                ORDER BY
                    T1.create_time ASC
                    LIMIT #{total} ) AS limited_rows
    </select>
</mapper>
src/main/resources/mapper/system/SysDeptMapper.xml
@@ -156,4 +156,23 @@
        update sys_dept set del_flag = '2' where dept_id = #{deptId}
    </delete>
    <select id="maxLevelDeptId">
        WITH RECURSIVE DepartmentHierarchy AS (
            SELECT dept_id, parent_id
            FROM sys_dept
            WHERE dept_id = #{deptId}
            UNION ALL
            -- é€’归情况:加入当前部门的父级部门
            SELECT d.dept_id, d.parent_id
            FROM sys_dept d
                     INNER JOIN DepartmentHierarchy dh ON d.dept_id = dh.parent_id
        )
        -- æŸ¥è¯¢æœ€é¡¶çº§çš„父级部门ID
        SELECT dept_id as top_level_department_id
        FROM DepartmentHierarchy
        WHERE parent_id = 100;
    </select>
</mapper> 
src/main/resources/mapper/system/SysUserMapper.xml
@@ -157,6 +157,7 @@
             <if test="status != null and status != ''">status,</if>
             <if test="createBy != null and createBy != ''">create_by,</if>
             <if test="remark != null and remark != ''">remark,</if>
            <if test="tenantId != null ">tenant_id,</if>
             create_time
         )values(
             <if test="userId != null and userId != ''">#{userId},</if>
@@ -171,6 +172,7 @@
             <if test="status != null and status != ''">#{status},</if>
             <if test="createBy != null and createBy != ''">#{createBy},</if>
             <if test="remark != null and remark != ''">#{remark},</if>
            <if test="tenantId != null ">#{tenantId},</if>
             sysdate()
         )
    </insert>