demand: TMS系统财务销账优化

committer: heyu
This commit is contained in:
aike 2025-09-17 15:18:46 +08:00
parent b227e790bb
commit 1b5f7b5730
2 changed files with 163 additions and 76 deletions

View File

@ -385,7 +385,7 @@ public class EmisWriteoffApplyController extends EmisBaseController {
/**
* 根据运单号查询运单、结算账单、结算子账单信息(返回EmisWriteoffApplyDetail列表)
*/
// @PreAuthorize("@ss.hasPermi('emis:writeoffApply:queryByBillCodes')")
// @PreAuthorize("@ss.hasPermi('emis:writeoffApply:queryByBillCodes')")
@GetMapping("/queryByBillCodes")
public AjaxResult queryByBillCodes(EmisWriteoffApply emisWriteoffApply) {
try {

View File

@ -121,24 +121,23 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
}
totalApplyAmount = totalApplyAmount.add(detail.getApplyMoney());
// 查询运单信息
EmisWaybill waybill = emisWaybillMapper.selectEmisWaybillByBillCode(detail.getBillCode());
if (waybill == null) {
throw new EmisBizError("运单号 " + detail.getBillCode() + " 不存在");
// 直接使用明细中的运单信息,无需额外查询
if (detail.getEmisWaybill() == null) {
throw new EmisBizError("运单号 " + detail.getBillCode() + " 的运单信息为空");
}
// 查询已收金额
BigDecimal receivedAmount = detail.getEmisSettleSubBill().getRecedMoney();
if (receivedAmount == null) {
receivedAmount = BigDecimal.ZERO;
}
BigDecimal receivedAmount = detail.getEmisSettleSubBill() != null
&& detail.getEmisSettleSubBill().getRecedMoney() != null
? detail.getEmisSettleSubBill().getRecedMoney()
: BigDecimal.ZERO;
// 验证:申请金额 + 已收金额 <= 运单应收金额
BigDecimal totalAmount = detail.getApplyMoney().add(receivedAmount);
if (totalAmount.compareTo(waybill.getFreight()) > 0) {
if (totalAmount.compareTo(detail.getEmisWaybill().getFreight()) > 0) {
throw new EmisBizError("运单号 " + detail.getBillCode() + " 的申请金额(" +
detail.getApplyMoney() + ") + 已收金额(" + receivedAmount + ") = " +
totalAmount + " 超过运单应收金额(" + waybill.getFreight() + ")");
totalAmount + " 超过运单应收金额(" + detail.getEmisWaybill().getFreight() + ")");
}
}
@ -354,6 +353,9 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
// 更新相关业务数据
List<EmisWriteoffApplyDetail> detailList = updateRelatedBusinessData(existingApply, true);
// 更新运单的付款状态
updateWaybillPaymentStatus(existingApply, detailList, true);
// 重算并更新月结客户额度和现金客户额度
updateCreditLimits(existingApply, detailList);
@ -493,11 +495,15 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
// 回退相关业务数据
List<EmisWriteoffApplyDetail> detailList = rollbackRelatedBusinessData(existingApply);
// 更新运单的付款状态
updateWaybillPaymentStatus(existingApply, detailList, false);
// 重算并更新月结客户额度和现金客户额度
updateCreditLimits(existingApply, detailList);
// 发送通知给申请人和财务中心审批人员
sendWriteoffApplyNotification(existingApply, "headquartersReject", emisWriteoffApply.getHeadquartersRejectReason());
sendWriteoffApplyNotification(existingApply, "headquartersReject",
emisWriteoffApply.getHeadquartersRejectReason());
return result;
} catch (Exception e) {
@ -604,7 +610,7 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
/**
* 更新相关业务数据
*
*
* @return 申请明细列表
*/
private List<EmisWriteoffApplyDetail> updateRelatedBusinessData(EmisWriteoffApply apply, boolean isPass)
@ -663,14 +669,14 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
return;
}
// 获取运单信息
EmisWaybill waybill = emisWaybillMapper.selectEmisWaybillByBillCode(billCode);
if (waybill == null) {
throw new EmisBizError("运单不存在:" + billCode);
// 直接使用明细中的运单信息,无需额外查询
if (detail.getEmisWaybill() == null) {
log.warn("运单信息为空,运单号: {}", billCode);
return;
}
// 验证申请金额
BigDecimal waybillAmount = waybill.getFreight(); // 运单应收金额
BigDecimal waybillAmount = detail.getEmisWaybill().getFreight(); // 运单应收金额
BigDecimal applyAmount = detail.getApplyMoney(); // 申请销账金额(从明细获取)
BigDecimal receivedAmount = detail.getEmisSettleSubBill().getRecedMoney() != null
? detail.getEmisSettleSubBill().getRecedMoney()
@ -682,18 +688,14 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
throw new EmisBizError("申请金额+已收金额(" + totalAmount + ")超过运单应收金额(" + waybillAmount + ")");
}
// 获取运单对应的子账单
List<EmisSettleSubBill> subBillList = emisSettleSubBillMapper.selectSettleSubBillListByBillCode(billCode);
if (CollectionUtils.isEmpty(subBillList)) {
log.warn("运单{}没有对应的子账单", billCode);
// 直接使用明细中的子账单信息,无需额外查询
if (detail.getEmisSettleSubBill() == null) {
log.warn("子账单信息为空,运单号: {}", billCode);
return;
}
// 更新子账单
for (EmisSettleSubBill subBill : subBillList) {
updateSubBillForWriteoff(subBill, detail, isPass);
}
updateSubBillForWriteoff(detail.getEmisSettleSubBill(), detail, isPass);
}
/**
@ -821,7 +823,7 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
/**
* 回退相关业务数据
*
*
* @return 申请明细列表
*/
private List<EmisWriteoffApplyDetail> rollbackRelatedBusinessData(EmisWriteoffApply apply) throws EmisBizError {
@ -927,24 +929,14 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
return;
}
// 获取运单信息
EmisWaybill waybill = emisWaybillMapper.selectEmisWaybillByBillCode(billCode);
if (waybill == null) {
log.warn("运单不存在,运单号: {}", billCode);
return;
}
// 获取运单对应的子账单
List<EmisSettleSubBill> subBillList = emisSettleSubBillMapper.selectSettleSubBillListByBillCode(billCode);
if (CollectionUtils.isEmpty(subBillList)) {
log.warn("运单{}没有对应的子账单", billCode);
// 直接使用明细中的子账单信息,无需额外查询
if (detail.getEmisSettleSubBill() == null) {
log.warn("子账单信息为空,运单号: {}", billCode);
return;
}
// 回退子账单
for (EmisSettleSubBill subBill : subBillList) {
rollbackSubBillForWriteoff(subBill, detail);
}
rollbackSubBillForWriteoff(detail.getEmisSettleSubBill(), detail);
}
/**
@ -1015,7 +1007,7 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
/**
* 重算并更新月结客户额度和现金客户额度
*
*
* @param apply 销账申请
* @param detailList 申请明细列表
*/
@ -1030,7 +1022,7 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
// 收集需要更新额度的客户和销售员信息
Set<String> customerCodes = new HashSet<>();
Set<String> salesmenCodes = new HashSet<>();
Set<String> salesmenNames = new HashSet<>();
// 遍历明细,获取运单信息
for (EmisWriteoffApplyDetail detail : detailList) {
@ -1044,7 +1036,7 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
}
// 收集销售员代码
if (StringUtil.isNotBlank(waybill.getSalesmen())) {
salesmenCodes.add(waybill.getSalesmen());
salesmenNames.add(waybill.getSalesmen());
}
}
}
@ -1060,11 +1052,11 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
}
// 更新销售员信用额度
for (String salesmenCode : salesmenCodes) {
for (String salesmen : salesmenNames) {
try {
updateSalesmenCreditLimit(salesmenCode);
updateSalesmenCreditLimit(salesmen);
} catch (Exception e) {
log.error("更新销售员信用额度失败,销售员代码: {}", salesmenCode, e);
log.error("更新销售员信用额度失败,销售员: {}", salesmen, e);
}
}
@ -1076,7 +1068,7 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
/**
* 更新客户信用额度
*
*
* @param customerCode 客户代码
*/
private void updateCustomerCreditLimit(String customerCode) throws EmisBizError {
@ -1099,32 +1091,32 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
/**
* 更新销售员信用额度
*
* @param salesmenCode 销售员代码
*
* @param salesmen 销售员代码
*/
private void updateSalesmenCreditLimit(String salesmenCode) throws EmisBizError {
private void updateSalesmenCreditLimit(String salesmen) throws EmisBizError {
try {
// 查询销售员信用额度信息
EmisCreditSalesmen query = new EmisCreditSalesmen();
query.setAccCode(salesmenCode);
query.setSalesmen(salesmen);
List<EmisCreditSalesmen> creditList = emisCreditSalesmenService.selectEmisCreditSalesmenList(query);
for (EmisCreditSalesmen credit : creditList) {
// 调用更新方法,这会触发额度重算
emisCreditSalesmenService.updateEmisCreditSalesmen(credit);
log.info("销售员信用额度更新成功,销售员代码: {}", salesmenCode);
log.info("销售员信用额度更新成功,销售员: {}", salesmen);
}
} catch (Exception e) {
log.error("更新销售员信用额度失败,销售员代码: {}", salesmenCode, e);
log.error("更新销售员信用额度失败,销售员: {}", salesmen, e);
throw e;
}
}
/**
* 发送销账申请通知
*
* @param apply 销账申请
* @param actionType 操作类型:centerPass-财务中心通过,centerReject-财务中心驳回,headquartersReject-总部驳回
*
* @param apply 销账申请
* @param actionType 操作类型:centerPass-财务中心通过,centerReject-财务中心驳回,headquartersReject-总部驳回
* @param rejectReason 驳回原因(驳回时使用)
*/
private void sendWriteoffApplyNotification(EmisWriteoffApply apply, String actionType, String rejectReason) {
@ -1139,35 +1131,33 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
String clickPath = "/d24/financialManagement/WriteoffApplyList";
// 获取申请人姓名
String applyManName = StringUtils.hasText(apply.getApplyManName()) ?
apply.getApplyManName() : apply.getApplyManCode();
String applyManName = StringUtils.hasText(apply.getApplyManName()) ? apply.getApplyManName()
: apply.getApplyManCode();
// 获取操作人姓名
String operatorName = "";
if ("centerPass".equals(actionType) || "centerReject".equals(actionType)) {
operatorName = StringUtils.hasText(apply.getCenterConfirmManName()) ?
apply.getCenterConfirmManName() : apply.getCenterConfirmManCode();
operatorName = StringUtils.hasText(apply.getCenterConfirmManName()) ? apply.getCenterConfirmManName()
: apply.getCenterConfirmManCode();
} else if ("headquartersReject".equals(actionType)) {
operatorName = StringUtils.hasText(apply.getHeadquartersConfirmManName()) ?
apply.getHeadquartersConfirmManName() : apply.getHeadquartersConfirmManCode();
operatorName = StringUtils.hasText(apply.getHeadquartersConfirmManName())
? apply.getHeadquartersConfirmManName()
: apply.getHeadquartersConfirmManCode();
}
// 构建通知内容
switch (actionType) {
case "centerPass":
title = "销账申请已通过,申请编号【" + apply.getApplyNo() + "】";
message = operatorName + "已通过您的销账申请,申请编号:" + apply.getApplyNo() +
",销账金额:" + apply.getWriteoffAmount();
title = operatorName + "已通过您的销账申请,申请编号:" + apply.getApplyNo() +
",销账金额:" + apply.getWriteoffAmount();
break;
case "centerReject":
title = "销账申请被驳回,申请编号【" + apply.getApplyNo() + "】";
message = operatorName + "驳回了您的销账申请,申请编号:" + apply.getApplyNo() +
",驳回原因:" + (StringUtils.hasText(rejectReason) ? rejectReason : "无");
title = operatorName + "驳回了您的销账申请,申请编号:" + apply.getApplyNo() +
",驳回原因:" + (StringUtils.hasText(rejectReason) ? rejectReason : "无");
break;
case "headquartersReject":
title = "销账申请被总部驳回,申请编号【" + apply.getApplyNo() + "】";
message = operatorName + "驳回了您的销账申请,申请编号:" + apply.getApplyNo() +
",驳回原因:" + (StringUtils.hasText(rejectReason) ? rejectReason : "无");
title = operatorName + "驳回了您的销账申请,申请编号:" + apply.getApplyNo() +
",驳回原因:" + (StringUtils.hasText(rejectReason) ? rejectReason : "无");
break;
default:
log.warn("未知的操作类型:{}", actionType);
@ -1179,10 +1169,9 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
// 如果是总部驳回,还需要通知财务中心审批人员
if ("headquartersReject".equals(actionType) && StringUtils.hasText(apply.getCenterConfirmManCode())) {
String centerTitle = "您审核的销账申请被总部驳回,申请编号【" + apply.getApplyNo() + "】";
String centerMessage = "您审核通过的销账申请被" + operatorName + "驳回,申请编号:" + apply.getApplyNo() +
",驳回原因:" + (StringUtils.hasText(rejectReason) ? rejectReason : "无");
sendNoticeToEmpUser(apply.getCenterConfirmManCode(), centerTitle, centerMessage, clickPath);
String centerTitle = "您审核通过的销账申请被" + operatorName + "驳回,申请编号:" + apply.getApplyNo() +
",驳回原因:" + (StringUtils.hasText(rejectReason) ? rejectReason : "无");
sendNoticeToEmpUser(apply.getCenterConfirmManCode(), centerTitle, "", clickPath);
}
log.info("销账申请通知发送成功,申请编号:{},操作类型:{}", apply.getApplyNo(), actionType);
@ -1190,4 +1179,102 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm
log.error("发送销账申请通知失败,申请编号:{},操作类型:{}", apply.getApplyNo(), actionType, e);
}
}
/**
* 更新运单的付款状态
*
* @param apply 销账申请
* @param detailList 申请明细列表
* @param isPass 是否审核通过
*/
private void updateWaybillPaymentStatus(EmisWriteoffApply apply, List<EmisWriteoffApplyDetail> detailList,
boolean isPass) {
try {
if (CollectionUtils.isEmpty(detailList)) {
log.warn("申请明细为空,无法更新运单付款状态,申请ID: {}", apply.getId());
return;
}
log.info("开始更新运单付款状态,申请ID: {}, 是否通过: {}", apply.getId(), isPass);
// 按运单号分组处理,避免重复更新同一运单
Map<String, List<EmisWriteoffApplyDetail>> waybillGroups = detailList.stream()
.filter(detail -> StringUtil.isNotBlank(detail.getBillCode()))
.collect(java.util.stream.Collectors.groupingBy(EmisWriteoffApplyDetail::getBillCode));
for (Map.Entry<String, List<EmisWriteoffApplyDetail>> entry : waybillGroups.entrySet()) {
String billCode = entry.getKey();
List<EmisWriteoffApplyDetail> waybillDetails = entry.getValue();
try {
// 直接使用明细中的运单信息,无需额外查询
EmisWriteoffApplyDetail firstDetail = waybillDetails.get(0);
if (firstDetail.getEmisWaybill() == null) {
log.warn("运单信息为空,无法更新付款状态,运单号: {}", billCode);
continue;
}
// 计算该运单的总申请金额
BigDecimal totalApplyMoney = waybillDetails.stream()
.map(detail -> detail.getApplyMoney() != null ? detail.getApplyMoney() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 计算该运单的总已收金额
BigDecimal totalReceivedMoney = waybillDetails.stream()
.map(detail -> detail.getEmisSettleSubBill() != null
&& detail.getEmisSettleSubBill().getRecedMoney() != null
? detail.getEmisSettleSubBill().getRecedMoney()
: BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 获取运单运费
BigDecimal waybillFreight = firstDetail.getEmisWaybill().getFreight() != null
? firstDetail.getEmisWaybill().getFreight()
: BigDecimal.ZERO;
// 更新运单付款状态
EmisWaybill updateWaybill = new EmisWaybill();
updateWaybill.setBillCode(billCode);
if (isPass) {
// 审核通过:申请金额 + 已收金额 与运单金额比较
BigDecimal totalAmount = totalApplyMoney.add(totalReceivedMoney);
if (totalAmount.compareTo(BigDecimal.ZERO) == 0) {
updateWaybill.setPaymentStatus("0"); // 未付款
} else if (totalAmount.compareTo(waybillFreight) >= 0) {
updateWaybill.setPaymentStatus("1"); // 已付款
} else {
updateWaybill.setPaymentStatus("2"); // 部分付款
}
} else {
// 审核驳回:申请金额 + 已收金额 与运单金额比较
BigDecimal totalAmount = totalReceivedMoney; // 驳回时只考虑已收金额
if (totalAmount.compareTo(BigDecimal.ZERO) == 0) {
updateWaybill.setPaymentStatus("0"); // 未付款
} else if (totalAmount.compareTo(waybillFreight) >= 0) {
updateWaybill.setPaymentStatus("1"); // 已付款
} else {
updateWaybill.setPaymentStatus("2"); // 部分付款
}
}
// 更新运单付款状态
emisWaybillMapper.updatePayedStatus(updateWaybill);
log.info("运单付款状态更新成功,运单号: {}, 付款状态: {}, 申请金额: {}, 已收金额: {}, 运单运费: {}",
billCode, updateWaybill.getPaymentStatus(), totalApplyMoney, totalReceivedMoney,
waybillFreight);
} catch (Exception e) {
log.error("更新运单付款状态失败,运单号: {}", billCode, e);
// 继续处理其他运单,不抛出异常
}
}
log.info("运单付款状态更新完成,申请ID: {}", apply.getId());
} catch (Exception e) {
log.error("更新运单付款状态失败,申请ID: {}", apply.getId(), e);
// 不抛出异常,避免影响主流程
}
}
}