demand: TMS系统 - 客户账单管理 - 财务开票处理 - 已开票 - 发票收款 - 界面功能调整

committer: heyu
This commit is contained in:
aike 2025-09-27 16:51:43 +08:00
parent 2f0c98c223
commit b0835ba22b
4 changed files with 362 additions and 51 deletions

View File

@ -23,16 +23,14 @@ import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
/**
* @ClassName EmisSettleInvoiceRel
* @Description 开票子账单关联表
* @author linfso
* @date 2024-07-21 13:31:27
*/
@Data
public class EmisSettleInvoiceRel extends BaseEntity
{
@Data
public class EmisSettleInvoiceRel extends BaseEntity {
private static final long serialVersionUID = 1L;
/* id */
@ -46,8 +44,10 @@ public class EmisSettleInvoiceRel extends BaseEntity
private String billNo;
/* 申请开票金额 */
private BigDecimal money;
/* 已收金额 */
private BigDecimal recedMoney;
// 扩展参数
// 扩展参数
private EmisWaybill waybillDetail;
}

View File

@ -1,12 +1,12 @@
/**
* @Project: emis
* @Title: EmisSettlePayRecordServiceImpl.java
* @author linfso
* @date 2024-07-21 13:31:24
* @Copyright: ShangHai Duta 2022 All rights reserved.
* @version v1.0
* @Description: <p> 账单收退款记录 实体类 </p>
*/
/**
* @Project: emis
* @Title: EmisSettlePayRecordServiceImpl.java
* @author linfso
* @date 2024-07-21 13:31:24
* @Copyright: ShangHai Duta 2022 All rights reserved.
* @version v1.0
* @Description: <p> 账单收退款记录 实体类 </p>
*/
package com.xdadan.erp.emis.service.impl;
@ -15,8 +15,11 @@ import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -75,6 +78,12 @@ public class EmisSettlePayRecordServiceImpl extends EmisBaseService implements I
@Autowired
private EmisSettlePayInvoiceRelMapper emisSettlePayInvoiceRelMapper;
@Autowired
private EmisSettleSubBillMapper emisSettleSubBillMapper;
@Autowired
private EmisWaybillMapper emisWaybillMapper;
/**
* 查询账单收退款记录
*
@ -82,8 +91,7 @@ public class EmisSettlePayRecordServiceImpl extends EmisBaseService implements I
* @return 账单收退款记录
*/
@Override
public EmisSettlePayRecord selectEmisSettlePayRecordById(Long id)
{
public EmisSettlePayRecord selectEmisSettlePayRecordById(Long id) {
return emisSettlePayRecordMapper.selectEmisSettlePayRecordById(id);
}
@ -446,7 +454,8 @@ public class EmisSettlePayRecordServiceImpl extends EmisBaseService implements I
emisSettlePayRecord.setSettleBillNo(WaybillHelper.formatQueryValue(emisSettlePayRecord.getSettleBillNo()));
// 多账单合并收款
List<String> settleBillNoArr = Arrays.stream(emisSettlePayRecord.getSettleBillNo().split(",")).distinct().collect(Collectors.toList());
List<String> settleBillNoArr = Arrays.stream(emisSettlePayRecord.getSettleBillNo().split(",")).distinct()
.collect(Collectors.toList());
for (int i = 0; i < settleBillNoArr.size(); i++) {
String settleBillNo = settleBillNoArr.get(i);
@ -514,13 +523,17 @@ public class EmisSettlePayRecordServiceImpl extends EmisBaseService implements I
// 插入数据
emisSettlePayRecordMapper.insertEmisSettlePayRecord(emisSettlePayRecord);
// 重新计算账单收款信息
for (int i = 0; i < settleBillNoArr.size(); i++) {
String settleBillNo = settleBillNoArr.get(i);
if (!StringUtils.isEmpty(settleBillNo)) {
emisSettleBillService.reCalcSettleBillPayStatus(settleBillNo);
}
}
// // 重新计算账单收款信息
// for (int i = 0; i < settleBillNoArr.size(); i++) {
// String settleBillNo = settleBillNoArr.get(i);
// if (!StringUtils.isEmpty(settleBillNo)) {
// emisSettleBillService.reCalcSettleBillPayStatus(settleBillNo);
// }
// }
// 处理部分收款逻辑 - 更新各个维度的收款状态
updatePartialPaymentStatus(emisSettlePayRecord, settleBillNoArr);
return 1;
}
@ -661,4 +674,288 @@ public class EmisSettlePayRecordServiceImpl extends EmisBaseService implements I
}
}
/**
* 更新部分收款状态
* 根据emis_settle_sub_bill的已收金额和本次运单的申请金额加起来与运费比较
* 更新emis_settle_sub_bill、emis_waybill的收款状态、已收金额
* 从账单维度更新emis_settle_bill、从发票维度更新emis_settle_invoice_record的对应字段
*
* @param emisSettlePayRecord 收款记录
* @param settleBillNoArr 账单号数组
*/
private void updatePartialPaymentStatus(EmisSettlePayRecord emisSettlePayRecord, List<String> settleBillNoArr) {
try {
// 处理运单收款关联
List<EmisSettlePayRel> payRelList = emisSettlePayRecord.getPayRelList();
if (!CollectionUtils.isEmpty(payRelList)) {
for (EmisSettlePayRel payRel : payRelList) {
updateWaybillPaymentStatus(payRel);
}
}
// 处理发票收款关联
List<EmisSettlePayInvoiceRel> payInvoiceRelList = emisSettlePayRecord.getPayInvoiceRelList();
if (!CollectionUtils.isEmpty(payInvoiceRelList)) {
for (EmisSettlePayInvoiceRel payInvoiceRel : payInvoiceRelList) {
updateInvoicePaymentStatus(payInvoiceRel, payRelList);
}
}
// 处理账单收款状态
for (String settleBillNo : settleBillNoArr) {
if (!StringUtils.isEmpty(settleBillNo)) {
updateSettleBillPaymentStatus(settleBillNo);
}
}
} catch (Exception e) {
log.error("更新部分收款状态失败", e);
throw new RuntimeException("更新收款状态失败:" + e.getMessage());
}
}
/**
* 更新运单收款状态
*
* @param payRel 运单收款关联
*/
private void updateWaybillPaymentStatus(EmisSettlePayRel payRel) {
try {
String billCode = payRel.getBillNo();
if (StringUtils.isEmpty(billCode)) {
return;
}
// 获取子账单信息
List<EmisSettleSubBill> subBillList = emisSettleSubBillMapper.selectSettleSubBillListByBillCode(billCode);
if (CollectionUtils.isEmpty(subBillList)) {
log.warn("未找到运单号 {} 对应的子账单", billCode);
return;
}
// 获取运单信息
EmisWaybill waybill = emisWaybillMapper.selectEmisWaybillByBillCode(billCode);
if (waybill == null) {
log.warn("未找到运单号 {} 对应的运单信息", billCode);
return;
}
// 计算本次收款金额
BigDecimal currentPayMoney = payRel.getPayMoney() != null ? payRel.getPayMoney() : BigDecimal.ZERO;
// 获取唯一的子账单(一个运单只对应一个子账单)
EmisSettleSubBill subBill = subBillList.get(0);
// 获取子账单的已收金额
BigDecimal currentRecedMoney = subBill.getRecedMoney() != null ? subBill.getRecedMoney()
: BigDecimal.ZERO;
// 计算新的已收金额
BigDecimal newRecedMoney = currentRecedMoney.add(currentPayMoney);
// 获取子账单的运费
BigDecimal billFee = subBill.getBillFee() != null ? subBill.getBillFee() : BigDecimal.ZERO;
// 根据已收金额和运费比较,确定收款状态
String paymentStatus;
if (newRecedMoney.compareTo(BigDecimal.ZERO) == 0) {
paymentStatus = "0"; // 未付款
} else if (newRecedMoney.compareTo(billFee) >= 0) {
paymentStatus = "1"; // 已付款
} else {
paymentStatus = "2"; // 部分付款
}
// 更新子账单收款状态和已收金额
EmisSettleSubBill updateSubBill = new EmisSettleSubBill();
updateSubBill.setBillCode(subBill.getBillCode());
updateSubBill.setPaymentStatus(paymentStatus);
updateSubBill.setRecedMoney(newRecedMoney);
emisSettleSubBillMapper.updatePayedStatus(updateSubBill);
// 更新运单收款状态
EmisWaybill updateWaybill = new EmisWaybill();
updateWaybill.setBillCode(billCode);
updateWaybill.setPaymentStatus(paymentStatus);
emisWaybillMapper.updatePayedStatus(updateWaybill);
log.info("更新运单收款状态成功,运单号: {}, 子账单号: {}, 收款状态: {}, 已收金额: {}, 运费: {}",
billCode, subBill.getBillNo(), paymentStatus, newRecedMoney, billFee);
} catch (Exception e) {
log.error("更新运单收款状态失败,运单号: {}", payRel.getBillNo(), e);
throw e;
}
}
/**
* 更新发票收款状态
*
* @param payInvoiceRel 发票收款关联
* @param payRelList 收款关联列表
*/
private void updateInvoicePaymentStatus(EmisSettlePayInvoiceRel payInvoiceRel, List<EmisSettlePayRel> payRelList) {
try {
String applySeqNo = payInvoiceRel.getApplySeqNo();
if (StringUtils.isEmpty(applySeqNo)) {
return;
}
// 获取发票记录
EmisSettleInvoiceRecord invoiceRecord = emisSettleInvoiceRecordMapper
.selectInvoiceRecordByApplySeqNo(applySeqNo);
if (invoiceRecord == null) {
log.warn("未找到申请序号 {} 对应的发票记录", applySeqNo);
return;
}
BigDecimal money = invoiceRecord.getApplyMoney() != null ? invoiceRecord.getApplyMoney()
: BigDecimal.ZERO;
// 获取发票之前的收款金额
BigDecimal previousRecedMoney = invoiceRecord.getRecedMoney() != null ? invoiceRecord.getRecedMoney()
: BigDecimal.ZERO;
// 计算当前收款记录中与该发票相关的运单收款金额
BigDecimal currentInvoicePayMoney = calculateCurrentInvoicePayment(invoiceRecord, payRelList);
// 计算新的总收款金额 = 之前的收款金额 + 当前收款金额
BigDecimal totalRecedMoney = previousRecedMoney.add(currentInvoicePayMoney);
String paymentStatus;
if (totalRecedMoney.compareTo(BigDecimal.ZERO) == 0) {
paymentStatus = "0"; // 未付款
} else if (totalRecedMoney.compareTo(money) >= 0) {
paymentStatus = "1"; // 已付款
} else {
paymentStatus = "2"; // 部分付款
}
// 更新发票记录收款状态
EmisSettleInvoiceRecord updateInvoiceRecord = new EmisSettleInvoiceRecord();
updateInvoiceRecord.setId(invoiceRecord.getId());
updateInvoiceRecord.setPaymentStatus(paymentStatus);
updateInvoiceRecord.setRecedMoney(totalRecedMoney);
emisSettleInvoiceRecordMapper.updateEmisSettleInvoiceRecord(updateInvoiceRecord);
log.info("更新发票收款状态成功,申请序号: {}, 收款状态: {}, 总收款金额: {}, 当前收款金额: {}, 申请金额: {}",
applySeqNo, paymentStatus, totalRecedMoney, currentInvoicePayMoney, money);
} catch (Exception e) {
log.error("更新发票收款状态失败,申请序号: {}", payInvoiceRel.getApplySeqNo(), e);
throw e;
}
}
/**
* 计算当前收款记录中与该发票相关的运单收款金额
*
* @param invoiceRecord 发票记录
* @param payRelList 当前收款记录中的运单收款列表
* @return 当前收款金额
*/
private BigDecimal calculateCurrentInvoicePayment(EmisSettleInvoiceRecord invoiceRecord,
List<EmisSettlePayRel> payRelList) {
try {
String settleBillNo = invoiceRecord.getSettleBillNo();
if (StringUtils.isEmpty(settleBillNo)) {
return BigDecimal.ZERO;
}
// 处理多个账单号的情况(用逗号分隔)
String[] settleBillNos = settleBillNo.split(",");
Set<String> allBillCodes = new HashSet<>();
for (String billNo : settleBillNos) {
String trimmedBillNo = billNo.trim();
if (StringUtils.isNotEmpty(trimmedBillNo)) {
// 通过账单号找到该账单下的所有运单
List<EmisSettleSubBill> subBillList = emisSettleSubBillMapper
.selectSubBillListBySettleBillNo(trimmedBillNo);
if (CollectionUtils.isNotEmpty(subBillList)) {
// 收集该账单下的所有运单号
Set<String> billCodes = subBillList.stream()
.map(EmisSettleSubBill::getBillCode)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
allBillCodes.addAll(billCodes);
}
}
}
if (allBillCodes.isEmpty()) {
return BigDecimal.ZERO;
}
// 计算当前收款记录中属于该发票相关运单的收款金额
BigDecimal currentPayment = BigDecimal.ZERO;
for (EmisSettlePayRel payRel : payRelList) {
if (payRel.getBillNo() != null && allBillCodes.contains(payRel.getBillNo())
&& payRel.getPayMoney() != null) {
currentPayment = currentPayment.add(payRel.getPayMoney());
}
}
return currentPayment;
} catch (Exception e) {
log.error("计算当前发票收款金额失败,申请序号: {}", invoiceRecord.getApplySeqNo(), e);
return BigDecimal.ZERO;
}
}
/**
* 更新账单收款状态
*
* @param settleBillNo 账单号
*/
private void updateSettleBillPaymentStatus(String settleBillNo) {
try {
// 获取账单信息
EmisSettleBill settleBill = emisSettleBillMapper.selectSettleBillBySettleBillNo(settleBillNo);
if (settleBill == null) {
log.warn("未找到账单号 {} 对应的账单信息", settleBillNo);
return;
}
// 获取账单下的所有子账单
List<EmisSettleSubBill> subBillList = emisSettleSubBillMapper.selectSubBillListBySettleBillNo(settleBillNo);
if (CollectionUtils.isEmpty(subBillList)) {
log.warn("账单号 {} 下没有子账单", settleBillNo);
return;
}
// 计算总已收金额
BigDecimal totalRecedMoney = BigDecimal.ZERO;
for (EmisSettleSubBill subBill : subBillList) {
BigDecimal recedMoney = subBill.getRecedMoney() != null ? subBill.getRecedMoney() : BigDecimal.ZERO;
totalRecedMoney = totalRecedMoney.add(recedMoney);
}
// 根据已收金额和应收金额比较,确定收款状态
BigDecimal recMoney = settleBill.getRecMoney() != null ? settleBill.getRecMoney() : BigDecimal.ZERO;
String paymentStatus;
if (totalRecedMoney.compareTo(BigDecimal.ZERO) == 0) {
paymentStatus = "0"; // 未付款
} else if (totalRecedMoney.compareTo(recMoney) >= 0) {
paymentStatus = "1"; // 已付款
} else {
paymentStatus = "2"; // 部分付款
}
// 更新账单收款状态和已收金额
EmisSettleBill updateSettleBill = new EmisSettleBill();
updateSettleBill.setId(settleBill.getId());
updateSettleBill.setPaymentStatus(paymentStatus);
updateSettleBill.setRecedMoney(totalRecedMoney);
emisSettleBillMapper.updateEmisSettleBill(updateSettleBill);
log.info("更新账单收款状态成功,账单号: {}, 收款状态: {}, 已收金额: {}, 应收金额: {}",
settleBillNo, paymentStatus, totalRecedMoney, recMoney);
} catch (Exception e) {
log.error("更新账单收款状态失败,账单号: {}", settleBillNo, e);
throw e;
}
}
}

View File

@ -223,7 +223,7 @@
</select>
<select id="selectInvoiceRecordByApplySeqNo" parameterType="String" resultMap="EmisSettleInvoiceRecordResult">
select id, apply_seq_no, apply_date, apply_man_code, apply_site_code, customer_code, customer_name, settle_bill_no, settle_bill_name, apply_money, invoice_type, company_name, company_tax_no, company_tel, company_address, bank_name, bank_acc_no, contact, phone, real_tax_type, open_money_max, open_money, invoice_no, invoice_status, invoice_status_desc, recieve_address, email, file_path, remark, bl_audit, audit_date, audit_man_code, audit_site_code, audit_note, op_man_code, op_date, op_site_code, open_ch_id, open_ch_status, open_ch_status_desc, open_com_code, del_flag, create_by, create_time, update_by, update_time, create_site, update_site
select id, apply_seq_no, apply_date, apply_man_code, apply_site_code, customer_code, customer_name, settle_bill_no, settle_bill_name, apply_money, invoice_type, company_name, company_tax_no, company_tel, company_address, bank_name, bank_acc_no, contact, phone, real_tax_type, open_money_max, open_money,reced_money, invoice_no, invoice_status, invoice_status_desc, recieve_address, email, file_path, remark, bl_audit, audit_date, audit_man_code, audit_site_code, audit_note, op_man_code, op_date, op_site_code, open_ch_id, open_ch_status, open_ch_status_desc, open_com_code, del_flag, create_by, create_time, update_by, update_time, create_site, update_site
from emis_settle_invoice_record a
where a.apply_seq_no = #{applySeqNo}
</select>

View File

@ -10,6 +10,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="payId" column="pay_id" />
<result property="billNo" column="bill_no" />
<result property="money" column="money" />
<result property="recedMoney" column="reced_money" />
</resultMap>
<resultMap id="EmisSettleInvoiceRelWithSubBillResult" type="EmisSettleInvoiceRel" extends="EmisSettleInvoiceRelResult" >
@ -21,29 +22,33 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectEmisSettleInvoiceRelVo">
select id, apply_seq_no, pay_id, bill_no, money, del_flag, create_by, create_time, update_by, update_time, create_site, update_site from emis_settle_invoice_rel
select r.id, r.apply_seq_no, r.pay_id, r.bill_no, r.money,
COALESCE(s.reced_money, 0) as reced_money,
r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.create_site, r.update_site
from emis_settle_invoice_rel r
left join emis_settle_sub_bill s on r.bill_no = s.bill_no and s.del_flag = '0'
</sql>
<select id="selectEmisSettleInvoiceRelList" parameterType="EmisSettleInvoiceRel" resultMap="EmisSettleInvoiceRelWithSubBillResult">
<include refid="selectEmisSettleInvoiceRelVo"/>
<where>
del_flag='0'
<if test="id != null "> and id = #{id}</if>
<if test="applySeqNo != null and applySeqNo != ''"> and FIND_IN_SET(apply_seq_no, #{applySeqNo} )</if>
<if test="payId != null and payId != ''"> and pay_id=#{payId}</if>
<if test="billNo != null and billNo != ''"> and bill_no like concat('%', #{billNo}, '%')</if>
<if test="money != null "> and money = #{money}</if>
<if test="delFlag != null and delFlag != ''"> and del_flag like concat('%', #{delFlag}, '%')</if>
<if test="createBy != null and createBy != ''"> and create_by like concat('%', #{createBy}, '%')</if>
<if test="createTime != null "> and create_time = #{createTime}</if>
<if test="updateBy != null and updateBy != ''"> and update_by like concat('%', #{updateBy}, '%')</if>
<if test="updateTime != null "> and update_time = #{updateTime}</if>
<if test="createSite != null and createSite != ''"> and create_site like concat('%', #{createSite}, '%')</if>
<if test="updateSite != null and updateSite != ''"> and update_site like concat('%', #{updateSite}, '%')</if>
r.del_flag='0'
<if test="id != null "> and r.id = #{id}</if>
<if test="applySeqNo != null and applySeqNo != ''"> and FIND_IN_SET(r.apply_seq_no, #{applySeqNo} )</if>
<if test="payId != null and payId != ''"> and r.pay_id=#{payId}</if>
<if test="billNo != null and billNo != ''"> and r.bill_no like concat('%', #{billNo}, '%')</if>
<if test="money != null "> and r.money = #{money}</if>
<if test="delFlag != null and delFlag != ''"> and r.del_flag like concat('%', #{delFlag}, '%')</if>
<if test="createBy != null and createBy != ''"> and r.create_by like concat('%', #{createBy}, '%')</if>
<if test="createTime != null "> and r.create_time = #{createTime}</if>
<if test="updateBy != null and updateBy != ''"> and r.update_by like concat('%', #{updateBy}, '%')</if>
<if test="updateTime != null "> and r.update_time = #{updateTime}</if>
<if test="createSite != null and createSite != ''"> and r.create_site like concat('%', #{createSite}, '%')</if>
<if test="updateSite != null and updateSite != ''"> and r.update_site like concat('%', #{updateSite}, '%')</if>
</where>
order by create_time desc
order by r.create_time desc
</select>
<select id="checkUnique" parameterType="EmisSettleInvoiceRel" resultType="int">
@ -66,22 +71,31 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectEmisSettleInvoiceRelById" parameterType="Long" resultMap="EmisSettleInvoiceRelResult">
select id, apply_seq_no, pay_id, bill_no, money, del_flag, create_by, create_time, update_by, update_time, create_site, update_site
from emis_settle_invoice_rel a
where a.id = #{id}
select r.id, r.apply_seq_no, r.pay_id, r.bill_no, r.money,
COALESCE(s.reced_money, 0) as reced_money,
r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.create_site, r.update_site
from emis_settle_invoice_rel r
left join emis_settle_sub_bill s on r.bill_no = s.bill_no and s.del_flag = '0'
where r.id = #{id}
</select>
<select id="selectListByApplySeqNo" parameterType="String" resultMap="EmisSettleInvoiceRelWithSubBillResult">
select id, apply_seq_no, pay_id, bill_no, money, del_flag, create_by, create_time, update_by, update_time, create_site, update_site
from emis_settle_invoice_rel a
where a.apply_seq_no = #{applySeqNo} and del_flag='0'
select r.id, r.apply_seq_no, r.pay_id, r.bill_no, r.money,
COALESCE(s.reced_money, 0) as reced_money,
r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.create_site, r.update_site
from emis_settle_invoice_rel r
left join emis_settle_sub_bill s on r.bill_no = s.bill_no and s.del_flag = '0'
where r.apply_seq_no = #{applySeqNo} and r.del_flag='0'
</select>
<select id="selectHasOpenListBySettleBillNo" parameterType="String" resultMap="EmisSettleInvoiceRelWithSubBillResult">
select id, apply_seq_no, pay_id, bill_no, money, del_flag, create_by, create_time, update_by, update_time, create_site, update_site
from emis_settle_invoice_rel a
where del_flag='0'
AND apply_seq_no IN (
select r.id, r.apply_seq_no, r.pay_id, r.bill_no, r.money,
COALESCE(s.reced_money, 0) as reced_money,
r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.create_site, r.update_site
from emis_settle_invoice_rel r
left join emis_settle_sub_bill s on r.bill_no = s.bill_no and s.del_flag = '0'
where r.del_flag='0'
AND r.apply_seq_no IN (
SELECT x1.apply_seq_no FROM
emis_settle_invoice_record x1,
emis_settle_bill x2
@ -91,7 +105,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND FIND_IN_SET( x2.settle_bill_no, x1.settle_bill_no )
AND FIND_IN_SET( x2.settle_bill_no, #{settleBillNo})
)
AND a.bill_no IN (
AND r.bill_no IN (
select essb.bill_no from emis_settle_sub_bill essb where essb.del_flag='0' and FIND_IN_SET( essb.settle_bill_no, #{settleBillNo})
)
</select>