api/src/main/java/com/ruoyi/api/third/controller/ReceivableBillApiController.java
New file @@ -0,0 +1,550 @@ package com.ruoyi.api.third.controller; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.cwgl.domain.PayableBillManagement; import com.ruoyi.cwgl.domain.PayableFeeDetail; import com.ruoyi.cwgl.domain.PayableFeeManagement; import com.ruoyi.cwgl.domain.ReceivableBillManagement; import com.ruoyi.cwgl.domain.ReceivableFeeDetail; import com.ruoyi.cwgl.domain.ReceivableFeeManagement; import com.ruoyi.cwgl.domain.dto.PayableBillApiDto; import com.ruoyi.cwgl.domain.dto.ReceivableBillApiDto; import com.ruoyi.cwgl.service.IPayableBillManagementService; import com.ruoyi.cwgl.service.IPayableFeeDetailService; import com.ruoyi.cwgl.service.IPayableFeeManagementService; import com.ruoyi.cwgl.service.IReceivableBillManagementService; import com.ruoyi.cwgl.service.IReceivableFeeDetailService; import com.ruoyi.cwgl.service.IReceivableFeeManagementService; import com.ruoyi.system.service.ISystemDataNoService; import com.ruoyi.common.enums.SystemDataNoEnum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.math.BigDecimal; import java.util.*; /** * 应收账单API接口 * @author wjw */ @RestController @RequestMapping("/api/third/receivable") public class ReceivableBillApiController { private static Logger logger = LoggerFactory.getLogger(ReceivableBillApiController.class); @Autowired private IReceivableBillManagementService receivableBillManagementService; @Autowired private IReceivableFeeManagementService receivableFeeManagementService; @Autowired private IReceivableFeeDetailService receivableFeeDetailService; @Autowired private IPayableBillManagementService payableBillManagementService; @Autowired private IPayableFeeManagementService payableFeeManagementService; @Autowired private IPayableFeeDetailService payableFeeDetailService; @Autowired private ISystemDataNoService systemDataNoService; /** * 添加应收账单接口 * 其他系统调用此接口添加应收账单、应收账单明细、应收账单费用 * @param receivableBillApiDto 应收账单API数据传输对象 * @return 操作结果 */ @PostMapping("/addBill") public Map<String, String> addReceivableBill(@Valid @RequestBody ReceivableBillApiDto receivableBillApiDto) { logger.info("接收应收账单添加请求:{}", receivableBillApiDto); Map<String, String> result = new HashMap<>(); try { // 1. 验证数据 // validateReceivableBillData(receivableBillApiDto); // 2. 保存应收账单管理信息 ReceivableBillManagement billManagement = saveReceivableBillManagement(receivableBillApiDto.getBill()); // 3. 保存应收费用管理信息和明细 saveReceivableFeeManagementAndDetails(receivableBillApiDto.getFees(), billManagement.getSystemNo()); result.put("status", "0000"); result.put("message", "应收账单添加成功"); result.put("billNo", billManagement.getSystemNo()); logger.info("应收账单添加成功,账单编号:{}", billManagement.getSystemNo()); } catch (Exception e) { logger.error("应收账单添加失败:", e); result.put("status", "9999"); result.put("message", "应收账单添加失败:" + e.getMessage()); } return result; } /** * 验证应收账单数据 */ private void validateReceivableBillData(ReceivableBillApiDto receivableBillApiDto) { if (receivableBillApiDto == null) { throw new IllegalArgumentException("请求数据不能为空"); } if (receivableBillApiDto.getBill() == null) { throw new IllegalArgumentException("应收账单信息不能为空"); } if (receivableBillApiDto.getFees() == null || receivableBillApiDto.getFees().isEmpty()) { throw new IllegalArgumentException("应收费用信息不能为空"); } // 验证总金额与费用明细金额是否匹配 BigDecimal totalAmount = receivableBillApiDto.getBill().getTotalAmount(); BigDecimal feeTotalAmount = BigDecimal.ZERO; for (ReceivableBillApiDto.ReceivableFeeDto fee : receivableBillApiDto.getFees()) { feeTotalAmount = feeTotalAmount.add(fee.getReceivableAmount()); // 验证费用明细 if (fee.getFeeDetails() != null) { BigDecimal detailTotalAmount = BigDecimal.ZERO; for (ReceivableBillApiDto.ReceivableFeeDetailDto detail : fee.getFeeDetails()) { detailTotalAmount = detailTotalAmount.add(detail.getBillingAmount()); } if (fee.getReceivableAmount().compareTo(detailTotalAmount) != 0) { throw new IllegalArgumentException("费用金额与明细金额不匹配,费用金额:" + fee.getReceivableAmount() + ",明细金额:" + detailTotalAmount); } } } if (totalAmount.compareTo(feeTotalAmount) != 0) { throw new IllegalArgumentException("账单总金额与费用总金额不匹配,账单金额:" + totalAmount + ",费用金额:" + feeTotalAmount); } } /** * 保存应收账单管理信息 */ private ReceivableBillManagement saveReceivableBillManagement(ReceivableBillApiDto.ReceivableBillDto billDto) { ReceivableBillManagement billManagement = new ReceivableBillManagement(); // 生成系统编号 String systemNo = systemDataNoService.getNoByKey(SystemDataNoEnum.YSZD); // 设置基本信息 billManagement.setSystemNo(systemNo); billManagement.setBillName(billDto.getBillName()); billManagement.setCustomerName(billDto.getCustomerName()); billManagement.setPayee(billDto.getPayee()); billManagement.setResponsiblePerson(billDto.getResponsiblePerson()); billManagement.setResponsibleLeader(billDto.getResponsibleLeader()); billManagement.setSettlementMethod(billDto.getSettlementMethod()); billManagement.setBusinessType(billDto.getBusinessType()); billManagement.setPromotionRequirement(billDto.getPromotionRequirement()); billManagement.setIsInternalSettlement(billDto.getIsInternalSettlement()); billManagement.setInternalSettlementUnit(billDto.getInternalSettlementUnit()); // 设置金额信息 billManagement.setDocumentCount(billDto.getDocumentCount()); billManagement.setTotalAmount(billDto.getTotalAmount()); billManagement.setCurrency(billDto.getCurrency()); billManagement.setDiscountAmount(billDto.getDiscountAmount()); billManagement.setReceivedAmount(billDto.getReceivedAmount() != null ? billDto.getReceivedAmount() : BigDecimal.ZERO); billManagement.setPendingAmount(billDto.getPendingAmount() != null ? billDto.getPendingAmount() : billDto.getTotalAmount()); billManagement.setExchangeRate(billDto.getExchangeRate()); billManagement.setCnyAmount(billDto.getCnyAmount()); // 设置日期信息 billManagement.setPeriodType(billDto.getPeriodType()); billManagement.setBusinessStartDate(billDto.getBusinessStartDate()); billManagement.setBusinessEndDate(billDto.getBusinessEndDate()); billManagement.setBillingStartDate(billDto.getBillingStartDate()); billManagement.setBillingEndDate(billDto.getBillingEndDate()); billManagement.setBillGenerateDate(billDto.getBillGenerateDate()); billManagement.setBillSendDate(billDto.getBillSendDate()); billManagement.setBillDueDate(billDto.getBillDueDate()); // 设置其他信息 billManagement.setSettlementCategory(billDto.getSettlementCategory()); billManagement.setSettlementPeriod(billDto.getSettlementPeriod()); billManagement.setStatus(billDto.getStatus() != null ? billDto.getStatus() : "draft"); billManagement.setRemark(billDto.getRemark()); billManagement.setCreateTime(DateUtils.getNowDate()); billManagement.setCreateBy("api_system"); // 保存账单管理信息 int rows = receivableBillManagementService.insertReceivableBillManagement(billManagement); if (rows <= 0) { throw new RuntimeException("保存应收账单管理信息失败"); } return billManagement; } /** * 保存应收费用管理信息和明细 */ private void saveReceivableFeeManagementAndDetails(List<ReceivableBillApiDto.ReceivableFeeDto> fees, String billSystemNo) { List<ReceivableFeeManagement> feeManagementList = new ArrayList<>(); List<ReceivableFeeDetail> feeDetailList = new ArrayList<>(); for (ReceivableBillApiDto.ReceivableFeeDto feeDto : fees) { // 生成费用管理记录 ReceivableFeeManagement feeManagement = new ReceivableFeeManagement(); // 生成系统编号 String feeSystemNo = systemDataNoService.getNoByKey(SystemDataNoEnum.YS); // 设置费用管理信息 feeManagement.setSystemNo(feeSystemNo); feeManagement.setSerialNumber(feeDto.getSerialNumber()); feeManagement.setRelatedBillNo(billSystemNo); feeManagement.setSourceSystem(feeDto.getSourceSystem()); feeManagement.setBusinessSector(feeDto.getBusinessSector()); feeManagement.setDocumentType(feeDto.getDocumentType()); feeManagement.setDocumentNo(feeDto.getDocumentNo()); feeManagement.setIsInternalSettlement(feeDto.getIsInternalSettlement()); feeManagement.setInternalSettlementUnit(feeDto.getInternalSettlementUnit()); feeManagement.setCustomerName(feeDto.getCustomerName()); feeManagement.setProjectName(feeDto.getProjectName()); feeManagement.setBusinessTime(feeDto.getBusinessTime()); feeManagement.setReceivableConfirmTime(feeDto.getReceivableConfirmTime()); feeManagement.setReceivableAmount(feeDto.getReceivableAmount()); feeManagement.setReceivableAmountStr(feeDto.getReceivableAmountStr()); feeManagement.setStatus(feeDto.getStatus() != null ? feeDto.getStatus() : "confirmed"); feeManagement.setRemark(feeDto.getRemark()); feeManagement.setCreateTime(DateUtils.getNowDate()); feeManagement.setCreateBy("api_system"); feeManagementList.add(feeManagement); // 保存费用明细 if (feeDto.getFeeDetails() != null && !feeDto.getFeeDetails().isEmpty()) { for (ReceivableBillApiDto.ReceivableFeeDetailDto detailDto : feeDto.getFeeDetails()) { ReceivableFeeDetail feeDetail = new ReceivableFeeDetail(); feeDetail.setSerialNumber(detailDto.getSerialNumber()); feeDetail.setFeeType(detailDto.getFeeType()); feeDetail.setFeeName(detailDto.getFeeName()); feeDetail.setBillingUnit(detailDto.getBillingUnit()); feeDetail.setUnitPrice(detailDto.getUnitPrice()); feeDetail.setBillingQuantity(detailDto.getBillingQuantity()); feeDetail.setBillingAmount(detailDto.getBillingAmount()); feeDetail.setActualAmount(detailDto.getActualAmount() != null ? detailDto.getActualAmount() : BigDecimal.ZERO); feeDetail.setCurrency(detailDto.getCurrency()); feeDetail.setFeeRegTime(detailDto.getFeeRegTime()); feeDetail.setRemark(detailDto.getRemark()); feeDetail.setCreateTime(DateUtils.getNowDate()); feeDetail.setCreateBy("api_system"); // 注意:这里需要先保存feeManagement获取ID,然后再设置关联关系 // 由于是批量保存,这里先收集,后续再处理关联关系 feeDetailList.add(feeDetail); } } } // 批量保存费用管理信息 int feeRows = receivableFeeManagementService.insertReceivableFeeManagementBatch(feeManagementList); if (feeRows <= 0) { throw new RuntimeException("保存应收费用管理信息失败"); } // 处理费用明细的关联关系并保存 if (!feeDetailList.isEmpty()) { // 使用Map存储系统编号和ID的映射关系 Map<String, Integer> systemNoToIdMap = new HashMap<>(); for (ReceivableFeeManagement feeManagement : feeManagementList) { // 假设插入后可以通过某种方式获取ID,这里简化处理 // 实际项目中可能需要根据业务逻辑获取ID systemNoToIdMap.put(feeManagement.getSystemNo(), feeManagement.getId()); } // 设置费用明细的关联ID List<ReceivableFeeDetail> finalFeeDetailList = new ArrayList<>(); for (int i = 0; i < feeManagementList.size(); i++) { ReceivableFeeManagement feeManagement = feeManagementList.get(i); Integer feeId = systemNoToIdMap.get(feeManagement.getSystemNo()); if (feeId != null && i < feeDetailList.size()) { ReceivableFeeDetail feeDetail = feeDetailList.get(i); feeDetail.setReceivableFeeId(feeId); finalFeeDetailList.add(feeDetail); } } // 批量保存费用明细 int detailRows = receivableFeeDetailService.insertReceivableFeeDetailBatch(finalFeeDetailList); if (detailRows <= 0) { throw new RuntimeException("保存应收费用明细信息失败"); } } } /** * 添加应付账单接口 * 其他系统调用此接口添加应付账单、应付账单明细、应付账单费用 * @param payableBillApiDto 应付账单API数据传输对象 * @return 操作结果 */ @PostMapping("/addPayableBill") public Map<String, String> addPayableBill(@Valid @RequestBody PayableBillApiDto payableBillApiDto) { logger.info("接收应付账单添加请求:{}", payableBillApiDto); Map<String, String> result = new HashMap<>(); try { // 1. 验证数据 // validatePayableBillData(payableBillApiDto); // 2. 保存应付账单管理信息 PayableBillManagement billManagement = savePayableBillManagement(payableBillApiDto.getBill()); // 3. 保存应付费用管理信息和明细 savePayableFeeManagementAndDetails(payableBillApiDto.getFees(), billManagement.getSystemNo()); result.put("status", "0000"); result.put("message", "应付账单添加成功"); result.put("billNo", billManagement.getSystemNo()); logger.info("应付账单添加成功,账单编号:{}", billManagement.getSystemNo()); } catch (Exception e) { logger.error("应付账单添加失败:", e); result.put("status", "9999"); result.put("message", "应付账单添加失败:" + e.getMessage()); } return result; } /** * 验证应付账单数据 */ private void validatePayableBillData(PayableBillApiDto payableBillApiDto) { if (payableBillApiDto == null) { throw new IllegalArgumentException("请求数据不能为空"); } if (payableBillApiDto.getBill() == null) { throw new IllegalArgumentException("应付账单信息不能为空"); } if (payableBillApiDto.getFees() == null || payableBillApiDto.getFees().isEmpty()) { throw new IllegalArgumentException("应付费用信息不能为空"); } // 验证总金额与费用明细金额是否匹配 BigDecimal totalAmount = payableBillApiDto.getBill().getTotalAmount(); BigDecimal feeTotalAmount = BigDecimal.ZERO; for (PayableBillApiDto.PayableFeeDto fee : payableBillApiDto.getFees()) { feeTotalAmount = feeTotalAmount.add(fee.getPayableAmount()); // 验证费用明细 if (fee.getFeeDetails() != null) { BigDecimal detailTotalAmount = BigDecimal.ZERO; for (PayableBillApiDto.PayableFeeDetailDto detail : fee.getFeeDetails()) { detailTotalAmount = detailTotalAmount.add(detail.getBillingAmount()); } if (fee.getPayableAmount().compareTo(detailTotalAmount) != 0) { throw new IllegalArgumentException("费用金额与明细金额不匹配,费用金额:" + fee.getPayableAmount() + ",明细金额:" + detailTotalAmount); } } } if (totalAmount.compareTo(feeTotalAmount) != 0) { throw new IllegalArgumentException("账单总金额与费用总金额不匹配,账单金额:" + totalAmount + ",费用金额:" + feeTotalAmount); } } /** * 保存应付账单管理信息 */ private PayableBillManagement savePayableBillManagement(PayableBillApiDto.PayableBillDto billDto) { PayableBillManagement billManagement = new PayableBillManagement(); // 生成系统编号 String systemNo = systemDataNoService.getNoByKey(SystemDataNoEnum.YFZD); // 设置基本信息 billManagement.setSystemNo(systemNo); billManagement.setBillName(billDto.getBillName()); billManagement.setSupplierName(billDto.getSupplierName()); billManagement.setIsInternalSettlement(billDto.getIsInternalSettlement()); billManagement.setInternalSettlementUnit(billDto.getInternalSettlementUnit()); // 设置金额信息 billManagement.setDocumentCount(billDto.getDocumentCount()); billManagement.setTotalAmount(billDto.getTotalAmount()); billManagement.setCurrency(billDto.getCurrency()); billManagement.setDiscountAmount(billDto.getDiscountAmount()); billManagement.setPaidAmount(billDto.getPaidAmount() != null ? billDto.getPaidAmount() : BigDecimal.ZERO); billManagement.setPendingAmount(billDto.getPendingAmount() != null ? billDto.getPendingAmount() : billDto.getTotalAmount()); billManagement.setExchangeRate(billDto.getExchangeRate()); billManagement.setCnyAmount(billDto.getCnyAmount()); // 设置日期信息 billManagement.setPeriodType(billDto.getPeriodType()); billManagement.setBusinessStartDate(billDto.getBusinessStartDate()); billManagement.setBusinessEndDate(billDto.getBusinessEndDate()); billManagement.setBillingStartDate(billDto.getBillingStartDate()); billManagement.setBillingEndDate(billDto.getBillingEndDate()); billManagement.setBillGenerateDate(billDto.getBillGenerateDate()); billManagement.setBillSendDate(billDto.getBillSendDate()); billManagement.setBillDueDate(billDto.getBillDueDate()); // 设置其他信息 billManagement.setStatus(billDto.getStatus() != null ? billDto.getStatus() : "draft"); billManagement.setRemark(billDto.getRemark()); billManagement.setCreateTime(DateUtils.getNowDate()); billManagement.setCreateBy("api_system"); // 保存账单管理信息 int rows = payableBillManagementService.insertPayableBillManagement(billManagement); if (rows <= 0) { throw new RuntimeException("保存应付账单管理信息失败"); } return billManagement; } /** * 保存应付费用管理信息和明细 */ private void savePayableFeeManagementAndDetails(List<PayableBillApiDto.PayableFeeDto> fees, String billSystemNo) { List<PayableFeeManagement> feeManagementList = new ArrayList<>(); List<PayableFeeDetail> feeDetailList = new ArrayList<>(); for (PayableBillApiDto.PayableFeeDto feeDto : fees) { // 生成费用管理记录 PayableFeeManagement feeManagement = new PayableFeeManagement(); // 生成系统编号 String feeSystemNo = systemDataNoService.getNoByKey(SystemDataNoEnum.YF); // 设置费用管理信息 feeManagement.setSystemNo(feeSystemNo); feeManagement.setRelatedBillNo(billSystemNo); feeManagement.setSourceSystem(feeDto.getSourceSystem()); feeManagement.setBusinessSector(feeDto.getBusinessSector()); feeManagement.setDocumentType(feeDto.getDocumentType()); feeManagement.setDocumentNo(feeDto.getDocumentNo()); feeManagement.setIsInternalSettlement(feeDto.getIsInternalSettlement()); feeManagement.setInternalSettlementUnit(feeDto.getInternalSettlementUnit()); feeManagement.setSupplierName(feeDto.getSupplierName()); feeManagement.setProjectName(feeDto.getProjectName()); feeManagement.setBusinessTime(feeDto.getBusinessTime()); feeManagement.setPayableConfirmTime(feeDto.getPayableConfirmTime()); feeManagement.setPayableAmount(feeDto.getPayableAmount()); feeManagement.setPayableAmountStr(feeDto.getPayableAmountStr()); feeManagement.setStatus(feeDto.getStatus() != null ? feeDto.getStatus() : "confirmed"); feeManagement.setRemark(feeDto.getRemark()); feeManagement.setCreateTime(DateUtils.getNowDate()); feeManagement.setCreateBy("api_system"); feeManagementList.add(feeManagement); // 保存费用明细 if (feeDto.getFeeDetails() != null && !feeDto.getFeeDetails().isEmpty()) { for (PayableBillApiDto.PayableFeeDetailDto detailDto : feeDto.getFeeDetails()) { PayableFeeDetail feeDetail = new PayableFeeDetail(); feeDetail.setFeeType(detailDto.getFeeType()); feeDetail.setFeeName(detailDto.getFeeName()); feeDetail.setBillingUnit(detailDto.getBillingUnit()); feeDetail.setUnitPrice(detailDto.getUnitPrice()); feeDetail.setBillingQuantity(detailDto.getBillingQuantity()); feeDetail.setBillingAmount(detailDto.getBillingAmount()); feeDetail.setActualAmount(detailDto.getActualAmount() != null ? detailDto.getActualAmount() : BigDecimal.ZERO); feeDetail.setCurrency(detailDto.getCurrency()); feeDetail.setFeeRegTime(detailDto.getFeeRegTime()); feeDetail.setRemark(detailDto.getRemark()); feeDetail.setCreateTime(DateUtils.getNowDate()); feeDetail.setCreateBy("api_system"); // 注意:这里需要先保存feeManagement获取ID,然后再设置关联关系 // 由于是批量保存,这里先收集,后续再处理关联关系 feeDetailList.add(feeDetail); } } } // 批量保存费用管理信息 int feeRows = payableFeeManagementService.insertPayableFeeManagementBatch(feeManagementList); if (feeRows <= 0) { throw new RuntimeException("保存应付费用管理信息失败"); } // 处理费用明细的关联关系并保存 if (!feeDetailList.isEmpty()) { // 使用Map存储系统编号和ID的映射关系 Map<String, Integer> systemNoToIdMap = new HashMap<>(); // 批量保存费用管理信息并获取ID for (PayableFeeManagement feeManagement : feeManagementList) { // 假设插入后可以通过某种方式获取ID,这里简化处理 // 实际项目中可能需要根据业务逻辑获取ID systemNoToIdMap.put(feeManagement.getSystemNo(), feeManagement.getId()); } // 设置费用明细的关联ID List<PayableFeeDetail> finalFeeDetailList = new ArrayList<>(); for (int i = 0; i < feeManagementList.size(); i++) { PayableFeeManagement feeManagement = feeManagementList.get(i); Integer feeId = systemNoToIdMap.get(feeManagement.getSystemNo()); if (feeId != null && i < feeDetailList.size()) { PayableFeeDetail feeDetail = feeDetailList.get(i); feeDetail.setPayableFeeId(feeId); finalFeeDetailList.add(feeDetail); } } // 批量保存费用明细 int detailRows = payableFeeDetailService.insertPayableFeeDetailBatch(finalFeeDetailList); if (detailRows <= 0) { throw new RuntimeException("保存应付费用明细信息失败"); } } } /** * 健康检查接口 * @return 健康状态 */ @GetMapping("/health") public Map<String, String> healthCheck() { Map<String, String> result = new HashMap<>(); result.put("status", "0000"); result.put("message", "应收应付账单API服务正常运行"); result.put("timestamp", DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date())); return result; } } service/src/main/java/com/ruoyi/cwgl/domain/dto/PayableBillApiDto.java
New file @@ -0,0 +1,221 @@ package com.ruoyi.cwgl.domain.dto; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.Date; import java.util.List; /** * 应付账单API接口数据传输对象 */ @Data public class PayableBillApiDto { /** * 应付账单管理信息 */ @NotNull(message = "应付账单信息不能为空") private PayableBillDto bill; /** * 应付费用管理信息 */ @NotNull(message = "应付费用信息不能为空") private List<PayableFeeDto> fees; /** * 应付账单数据传输对象 */ @Data public static class PayableBillDto { /** 账单名称 */ @NotBlank(message = "账单名称不能为空") private String billName; /** 供应商名称 */ @NotBlank(message = "供应商名称不能为空") private String supplierName; /** 是否内部结算 */ private String isInternalSettlement; /** 内部结算单位 */ private String internalSettlementUnit; /** 单据数量 */ private Integer documentCount; /** 应结算金额 */ @NotNull(message = "应结算金额不能为空") private BigDecimal totalAmount; /** 币制 */ @NotBlank(message = "币制不能为空") private String currency; /** 减免金额 */ private BigDecimal discountAmount; /** 已付金额 */ private BigDecimal paidAmount; /** 待付金额 */ private BigDecimal pendingAmount; /** 汇率(港币兑人民币) */ private BigDecimal exchangeRate; /** 人民币金额 */ private BigDecimal cnyAmount; /** 周期类型 */ private String periodType; /** 业务期间开始日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date businessStartDate; /** 业务期间结束日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date businessEndDate; /** 账期开始日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date billingStartDate; /** 账期结束日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date billingEndDate; /** 账单生成日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date billGenerateDate; /** 账单发送日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date billSendDate; /** 账单到期日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date billDueDate; /** 状态(draft:草稿;generated:已生成;sent:已发送;partial_paid:部分付款;paid:已付款;cancelled:已取消) */ private String status; /** 备注 */ private String remark; } /** * 应付费用数据传输对象 */ @Data public static class PayableFeeDto { /** 序号(用于与明细表关联) */ private String serialNumber; /** 关联账单编号 */ private String relatedBillNo; /** 来源系统 */ @NotBlank(message = "来源系统不能为空") private String sourceSystem; /** 业务板块 */ private String businessSector; /** 单据类型 */ private String documentType; /** 单据编号 */ @NotBlank(message = "单据编号不能为空") private String documentNo; /** 是否内部结算 */ private String isInternalSettlement; /** 内部结算单位 */ private String internalSettlementUnit; /** 供应商名称 */ @NotBlank(message = "供应商名称不能为空") private String supplierName; /** 项目名称 */ private String projectName; /** 业务发生时间 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date businessTime; /** 应付确认时间 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date payableConfirmTime; /** 应付金额 */ @NotNull(message = "应付金额不能为空") private BigDecimal payableAmount; private String payableAmountStr; /** 状态 */ private String status; /** 备注 */ private String remark; /** 应付费用明细列表 */ private List<PayableFeeDetailDto> feeDetails; } /** * 应付费用明细数据传输对象 */ @Data public static class PayableFeeDetailDto { /** 序号(用于与主表关联) */ private String serialNumber; /** 费用类型 */ @NotBlank(message = "费用类型不能为空") private String feeType; /** 费用名称 */ @NotBlank(message = "费用名称不能为空") private String feeName; /** 计费单位 */ private String billingUnit; /** 计费单价 */ @NotNull(message = "计费单价不能为空") private BigDecimal unitPrice; /** 计费数量 */ @NotNull(message = "计费数量不能为空") private BigDecimal billingQuantity; /** 计费金额 */ @NotNull(message = "计费金额不能为空") private BigDecimal billingAmount; /** 实付金额 */ private BigDecimal actualAmount; /** 币制 */ private String currency; /** 费用登记时间 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date feeRegTime; /** 备注 */ private String remark; } } service/src/main/java/com/ruoyi/cwgl/domain/dto/ReceivableBillApiDto.java
New file @@ -0,0 +1,245 @@ package com.ruoyi.cwgl.domain.dto; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.Date; import java.util.List; /** * 应收账单API接口数据传输对象 */ @Data public class ReceivableBillApiDto { /** * 应收账单管理信息 */ @NotNull(message = "应收账单信息不能为空") private ReceivableBillDto bill; /** * 应收费用管理信息 */ @NotNull(message = "应收费用信息不能为空") private List<ReceivableFeeDto> fees; /** * 应收账单数据传输对象 */ @Data public static class ReceivableBillDto { /** 账单名称 */ @NotBlank(message = "账单名称不能为空") private String billName; /** 客户名称 */ @NotBlank(message = "客户名称不能为空") private String customerName; /** 收款人 */ private String payee; /** 责任人 */ private String responsiblePerson; /** 责任领导 */ private String responsibleLeader; /** 结算方式 */ private String settlementMethod; /** 业务类型 */ private String businessType; /** 推进要求 */ private String promotionRequirement; /** 是否内部结算 */ private String isInternalSettlement; /** 内部结算单位 */ private String internalSettlementUnit; /** 单据数量 */ private Integer documentCount; /** 应结算金额 */ @NotNull(message = "应结算金额不能为空") private BigDecimal totalAmount; /** 币制 */ @NotBlank(message = "币制不能为空") private String currency; /** 减免金额 */ private BigDecimal discountAmount; /** 已收金额 */ private BigDecimal receivedAmount; /** 待收金额 */ private BigDecimal pendingAmount; /** 汇率(港币兑人民币) */ private BigDecimal exchangeRate; /** 人民币金额 */ private BigDecimal cnyAmount; /** 周期类型 */ private String periodType; /** 业务期间开始日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date businessStartDate; /** 业务期间结束日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date businessEndDate; /** 账期开始日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date billingStartDate; /** 账期结束日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date billingEndDate; /** 账单生成日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date billGenerateDate; /** 账单发送日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date billSendDate; /** 账单到期日期 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date billDueDate; /** 结算种类 */ private String settlementCategory; /** 结算期 */ private String settlementPeriod; /** 状态(draft:草稿;generated:已生成;sent:已发送;partial_paid:部分收款;paid:已收款;cancelled:已取消) */ private String status; /** 备注 */ private String remark; } /** * 应收费用数据传输对象 */ @Data public static class ReceivableFeeDto { /** 序号(用于与明细表关联) */ private String serialNumber; /** 关联账单编号 */ private String relatedBillNo; /** 来源系统 */ @NotBlank(message = "来源系统不能为空") private String sourceSystem; /** 业务板块 */ private String businessSector; /** 单据类型 */ private String documentType; /** 单据编号 */ @NotBlank(message = "单据编号不能为空") private String documentNo; /** 是否内部结算 */ private String isInternalSettlement; /** 内部结算单位 */ private String internalSettlementUnit; /** 客户名称 */ @NotBlank(message = "客户名称不能为空") private String customerName; /** 项目名称 */ private String projectName; /** 业务发生时间 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date businessTime; /** 应收确认时间 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date receivableConfirmTime; /** 应收金额 */ @NotNull(message = "应收金额不能为空") private BigDecimal receivableAmount; private String receivableAmountStr; /** 状态 */ private String status; /** 备注 */ private String remark; /** 应收费用明细列表 */ private List<ReceivableFeeDetailDto> feeDetails; } /** * 应收费用明细数据传输对象 */ @Data public static class ReceivableFeeDetailDto { /** 序号(用于与主表关联) */ private String serialNumber; /** 费用类型 */ @NotBlank(message = "费用类型不能为空") private String feeType; /** 费用名称 */ @NotBlank(message = "费用名称不能为空") private String feeName; /** 计费单位 */ private String billingUnit; /** 计费单价 */ @NotNull(message = "计费单价不能为空") private BigDecimal unitPrice; /** 计费数量 */ @NotNull(message = "计费数量不能为空") private BigDecimal billingQuantity; /** 计费金额 */ @NotNull(message = "计费金额不能为空") private BigDecimal billingAmount; /** 实收金额 */ private BigDecimal actualAmount; /** 币制 */ private String currency; /** 费用登记时间 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date feeRegTime; /** 备注 */ private String remark; } } service/src/main/resources/mapper/cwgl/PayableFeeManagementMapper.xml
@@ -129,11 +129,11 @@ <insert id="insertPayableFeeManagementBatch" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id"> insert into payable_fee_management <trim prefix="(" suffix=") values" suffixOverrides=","> id,system_no,related_bill_no,source_system,business_sector,document_type,document_no,is_internal_settlement,internal_settlement_unit,supplier_name,project_name,business_time,payable_confirm_time,payable_amount,payable_amount_str,status,remark,create_by,create_time,update_by,update_time,deleted, system_no,related_bill_no,source_system,business_sector,document_type,document_no,is_internal_settlement,internal_settlement_unit,supplier_name,project_name,business_time,payable_confirm_time,payable_amount,payable_amount_str,status,remark,create_by,create_time,update_by,update_time,deleted, </trim> <foreach item="item" index="index" collection="list" separator=","> <trim prefix="(" suffix=") " suffixOverrides=","> #{item.id},#{item.systemNo},#{item.relatedBillNo},#{item.sourceSystem},#{item.businessSector},#{item.documentType},#{item.documentNo},#{item.isInternalSettlement},#{item.internalSettlementUnit},#{item.supplierName},#{item.projectName},#{item.businessTime},#{item.payableConfirmTime},#{item.payableAmount},#{item.payableAmountStr},#{item.status},#{item.remark},#{item.createBy},#{item.createTime},#{item.updateBy},#{item.updateTime},#{item.deleted}, #{item.systemNo},#{item.relatedBillNo},#{item.sourceSystem},#{item.businessSector},#{item.documentType},#{item.documentNo},#{item.isInternalSettlement},#{item.internalSettlementUnit},#{item.supplierName},#{item.projectName},#{item.businessTime},#{item.payableConfirmTime},#{item.payableAmount},#{item.payableAmountStr},#{item.status},#{item.remark},#{item.createBy},#{item.createTime},#{item.updateBy},#{item.updateTime},#{item.deleted}, </trim> </foreach> </insert> service/src/main/resources/mapper/cwgl/ReceivableFeeManagementMapper.xml
@@ -133,11 +133,11 @@ <insert id="insertReceivableFeeManagementBatch" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id"> insert into receivable_fee_management <trim prefix="(" suffix=") values" suffixOverrides=","> id,system_no,related_bill_no,source_system,business_sector,document_type,document_no,is_internal_settlement,internal_settlement_unit,customer_name,project_name,business_time,receivable_confirm_time,receivable_amount,receivable_amount_str,status,remark,create_by,create_time,update_by,update_time,deleted,customer_id, system_no,related_bill_no,source_system,business_sector,document_type,document_no,is_internal_settlement,internal_settlement_unit,customer_name,project_name,business_time,receivable_confirm_time,receivable_amount,receivable_amount_str,status,remark,create_by,create_time,update_by,update_time,deleted,customer_id, </trim> <foreach item="item" index="index" collection="list" separator=","> <trim prefix="(" suffix=") " suffixOverrides=","> #{item.id},#{item.systemNo},#{item.relatedBillNo},#{item.sourceSystem},#{item.businessSector},#{item.documentType},#{item.documentNo},#{item.isInternalSettlement},#{item.internalSettlementUnit},#{item.customerName},#{item.projectName},#{item.businessTime},#{item.receivableConfirmTime},#{item.receivableAmount},#{item.receivableAmountStr},#{item.status},#{item.remark},#{item.createBy},#{item.createTime},#{item.updateBy},#{item.updateTime},#{item.deleted},#{item.customerId}, #{item.systemNo},#{item.relatedBillNo},#{item.sourceSystem},#{item.businessSector},#{item.documentType},#{item.documentNo},#{item.isInternalSettlement},#{item.internalSettlementUnit},#{item.customerName},#{item.projectName},#{item.businessTime},#{item.receivableConfirmTime},#{item.receivableAmount},#{item.receivableAmountStr},#{item.status},#{item.remark},#{item.createBy},#{item.createTime},#{item.updateBy},#{item.updateTime},#{item.deleted},#{item.customerId}, </trim> </foreach> </insert> ui/admin-ui3/src/api/cwgl/analysisManagement.ts
@@ -23,7 +23,14 @@ download('/cwgl/receivableBillManagement/customerSummary/export',query); }) } /** * 账龄分析列表导出 */ export const exportAgingAnalysis:requestType = (query) => { return new Promise<any>(()=>{ download('/cwgl/receivableBillManagement/customerSummary/export',query); }) } export const agingAnalysisList:requestType = (query) => { return request({ url: '/cwgl/receivableBillManagement/agingAnalysis', ui/admin-ui3/src/layout/index.vue
@@ -7,7 +7,7 @@ <navbar @setLayout="setLayout" /> <tags-view v-if="needTagsView" /> </div> <el-watermark :content="watermarkContent" zIndex="99999"> <el-watermark :content="watermarkContent" :zIndex="99999"> <app-main /> </el-watermark> <settings ref="settingRef" /> ui/admin-ui3/src/main.ts
@@ -15,7 +15,6 @@ import 'default-passive-events' import elementIcons from '@/components/SvgIcon/svgicon' import directive from "@/directive"; // pinia store @@ -40,6 +39,7 @@ app.component('XlsFileImport', XlsFileImport); app.component('flowLog', flowLog) app.component('svg-icon', SvgIcon) app.use(plugins) ui/admin-ui3/src/views/cwgl/accountAnalysisDetail/index.vue
@@ -1,7 +1,7 @@ <template> <basicContainer> <div class="account-analysis-detail"> <avue-crud ref="crudRef" v-model="form" v-model:search="searchForm" v-model:page="page" :option="option" <avue-crud ref="crudRef" v-model="form" v-model:search="searchForm" :page="page" :option="option" :data="tableData" :table-loading="loading" :row-class-name="rowClassName" @on-load="onLoad" @search-change="searchChange" @search-reset="searchReset" @refresh-change="refreshChange" @current-change="currentChange" @size-change="sizeChange"> @@ -23,7 +23,7 @@ <el-button type="primary" link underline="never" icon="View" @click="crudRef.rowView(row)">查看</el-button> <el-link type="primary" icon="el-icon-document" v-hasPermi="['cwgl:receivableBillManagement:log']" :underline="false" @click="handleFlow(row)" style="margin-left: 12px;">日志</el-link> underline="never" @click="handleFlow(row)" style="margin-left: 12px;">日志</el-link> </template> </avue-crud> </div> @@ -99,7 +99,7 @@ import { agingAnalysisList, listAccountLog, updateAccountAnalysis, receivableBillManagementAccountAnalysis } from "@/api/cwgl/analysisManagement"; import useCurrentInstance from "@/utils/useCurrentInstance"; import OperationLogModal from '@/components/OperationLogModal/index.vue'; import { download } from "@/utils/request"; const { proxy } = useCurrentInstance(); const { sys_account_business } = proxy.useDict('sys_account_business'); @@ -151,8 +151,8 @@ // --- Avue 配置 --- const option = computed(() => ({ height: 'auto', calcHeight: 30, // height: 'auto', // calcHeight: 30, searchShow: true, searchMenuSpan: 6, border: true, @@ -160,11 +160,15 @@ editBtn: false, delBtn: false, viewBtn: false, showSummary: true, dicCache: true, menuWidth: 220, labelWidth: 150, page: true, pagination: true, searchLabelWidth: 120, showSummary: true, // 强制指定合计文案(如果 method 返回空,它作为保底) sumText: '合计', sumColumnList: [ { name: 'repaymentAmount', type: 'sum' }, { name: 'ncSettlementAmount', type: 'sum' }, @@ -182,8 +186,8 @@ detail: true, formatter: (row: any, value: any) => dictFormat(sys_account_business, value) }, { label: '账单系统编号', prop: 'systemNo', search: true, width: 140 }, { label: '结算期', prop: 'settlementPeriod', width: 100 }, { label: '账单系统编号', prop: 'systemNo', search: true, width: 180 }, { label: '结算期', prop: 'settlementPeriod', width: 200 }, { label: 'NC账面结算', children: [ @@ -250,13 +254,6 @@ tableData.value = res.rows || []; page.total = res.total || 0; loading.value = false; if (highlightSystemNo.value) { nextTick(() => { const target = document.querySelector('.highlight-row'); target?.scrollIntoView({ behavior: 'smooth', block: 'center' }); }); } }).catch(() => { loading.value = false; }); @@ -382,8 +379,8 @@ }; /* 导出按钮 */ function handleExport() { proxy.download( '/wmswh/reportStockcwgl/receivableBillManagement/accountAnalysis/export', download( '/cwgl/receivableBillManagement/accountAnalysis/export', { ...form.value, }, @@ -430,4 +427,19 @@ .edit-form { padding: 10px 20px; } /* 强制在合计行的第一个非复选框单元格(责任人列)显示文案 */ :deep(.el-table__footer-wrapper .el-table__cell.avue-crud__color .cell), :deep(.el-table__footer-wrapper .el-table__cell:nth-child(2) .cell) { visibility: visible !important; } /* 如果是多选框列导致的遮挡,通过伪元素强行在第二列注入 */ :deep(.el-table__footer-wrapper tr td:nth-child(2) .cell::before) { content: '合计'; font-weight: bold; color: #333; } </style> ui/admin-ui3/src/views/cwgl/ageAnalysis/index.vue
@@ -75,7 +75,7 @@ </el-row> <el-row> <el-col :span="24"> <el-form-item label="备注"><el-input v-model="editForm.remark" /></el-form-item> <el-form-item label="备注"><el-input v-model="editForm.accountRemark" /></el-form-item> </el-col> </el-row> <el-row> @@ -139,7 +139,7 @@ </template> <script setup name="AgeAnalysis" lang="ts"> import { ref, reactive, onMounted } from 'vue'; import { ref, reactive, onMounted, watch } from 'vue'; import { useRoute } from 'vue-router'; import router from "@/router"; import { agingAnalysisList, addPaymentFeedback, listPaymentFeedback, listAgingLog, receivableBillManagementAging } from "@/api/cwgl/analysisManagement"; @@ -177,34 +177,30 @@ * Avue 配置项 */ const option = ref({ align: 'center', headerAlign: 'center', searchShow: true, searchMenuSpan: 6, border: true, addBtn: false, editBtn: false, delBtn: false, viewBtn: false, menu: true, stripe: true, columnBtn: true, searchIndex: 1, searchMenuSpan: 4, searchSpan: 5, height: 'auto', menuWidth: 180, dicCache: true, menuWidth: 220, labelWidth: 150, page: true, pagination: true, searchLabelWidth: 120, menuFixed: 'right', showSummary: true, // --- 合计行配置 --- // showSummary: true, // sumText: '合计', // sumColumnList: [ // { name: 'estimateAmount', type: 'sum' }, // { name: 'confirmedAmount', type: 'sum' }, // { name: 'balanceAmount', type: 'sum' }, // { name: 'overdueAmount', type: 'sum' }, // { name: 'unInvoicedAmount', type: 'sum' } // ], // 强制指定合计文案(如果 method 返回空,它作为保底) sumText: '合计', sumColumnList: [ // { label: '合计:', name: 'responsiblePerson', type: 'sum', }, { name: 'totalAmount', type: 'sum' }, { name: 'pendingAmount', type: 'sum' }, { name: 'overdueAmount', type: 'sum' }, { name: 'unInvoicedAmount', type: 'sum' }, ], column: [ { label: '责任人', prop: 'responsiblePerson', width: 100 }, @@ -226,9 +222,7 @@ detail: true, formatter: (row: any, value: any) => dictFormat(sys_account_business, value) }, { label: '账单系统编号', prop: 'systemNo', width: 200, search: true }, // 金额列 { label: '含暂估应收账款余额', prop: 'totalAmount', width: 160, type: 'number' }, { label: '已确认应收账款金额', prop: 'totalAmount', width: 160, type: 'number' }, @@ -244,11 +238,18 @@ { label: '逾期1年以上', prop: 'overdueOver1Year', width: 130 }, { label: '推进要求', prop: 'promotionRequirement', width: 250, overHidden: true }, { label: '备注', prop: 'remark', width: 150 }, { label: '逾期金额所属期', prop: 'overduePeriod', width: 150 }, { label: '账单是否确认', prop: 'isConfirmed', width: 120 }, { label: '备注', prop: 'accountRemark', width: 150 }, { label: '逾期金额所属期', width: 200, formatter: (row) => { if (row.billingStartDate && row.billingEndDate) { return `${row.billingStartDate} 至 ${row.billingEndDate}`; } return row.periodType || '-'; } }, { label: '开票日期', prop: 'invoiceDate', width: 120 }, { label: '未开票金额', prop: 'unInvoicedAmount', width: 120 } { label: '未开票金额', prop: 'pendingAmount', width: 120 } ] }); @@ -385,8 +386,8 @@ onLoad(); }; // 修改 goReturn 方法 const goReturn = () => router.push('/basic/analysisManagement'); // --- 弹窗逻辑 --- const editVisible = ref(false); const editForm = ref<any>({}); @@ -510,11 +511,26 @@ padding-left: 10px; border-left: 4px solid #409eff; } /* 操作列按钮间距 */ .menu-btn-container .el-link { margin-right: 12px; } .menu-btn-container .el-link:last-child { margin-right: 0; } /* 强制在合计行的第一个非复选框单元格(责任人列)显示文案 */ :deep(.el-table__footer-wrapper .el-table__cell.avue-crud__color .cell), :deep(.el-table__footer-wrapper .el-table__cell:nth-child(2) .cell) { visibility: visible !important; } /* 如果是多选框列导致的遮挡,通过伪元素强行在第二列注入 */ :deep(.el-table__footer-wrapper tr td:nth-child(2) .cell::before) { content: '合计'; font-weight: bold; color: #333; } </style> ui/admin-ui3/src/views/cwgl/analysisManagement/index.vue
@@ -140,7 +140,6 @@ */ const handleAgeAnalysis = (row: any) => { // 可使用 router.push 进行跳转 console.log(row.customerName); router.push('/basic/ageAnalysis?customerName='+row.customerName) };