登记收款选择账单直接核销,附件上传支持拖动上传

This commit is contained in:
wuweihua
2026-10-09 10:09:50 +08:00
parent c95a9861cc
commit 95df65b4f6
14 changed files with 800 additions and 20 deletions
@@ -26,6 +26,10 @@ import com.bms.ar.mapper.ArBillMapper;
import com.bms.ar.service.IArBalanceWriteoffService;
import com.bms.ar.service.IArBillLogService;
import com.bms.common.exception.ServiceException;
import com.bms.customer.customermoney.domain.CustomerReceipt;
import com.bms.customer.customermoney.domain.ReceiptWriteoffPlan;
import com.bms.customer.customermoney.mapper.CustomerMoneyMapper;
import com.bms.customer.customermoney.mapper.ReceiptWriteoffPlanMapper;
import com.bms.common.utils.SecurityUtils;
import com.bms.common.utils.uuid.IdUtils;
@@ -49,6 +53,12 @@ public class ArBalanceWriteoffServiceImpl implements IArBalanceWriteoffService {
@Autowired
private IArBillLogService logService;
@Autowired
private ReceiptWriteoffPlanMapper receiptWriteoffPlanMapper;
@Autowired
private CustomerMoneyMapper customerMoneyMapper;
/**
* 按客户查询允许余额核销的未结清账单。
*/
@@ -117,6 +127,7 @@ public class ArBalanceWriteoffServiceImpl implements IArBalanceWriteoffService {
writeoff.setArBillId(bill.getArBillId());
writeoff.setBillNo(bill.getBillNo());
writeoff.setCustomerId(bill.getCustomerId());
writeoff.setReceiptId(cmd.getReceiptId());
writeoff.setCurrency(currency);
writeoff.setWriteoffAmount(amount);
writeoff.setWriteoffDate(writeoffDate);
@@ -191,6 +202,66 @@ public class ArBalanceWriteoffServiceImpl implements IArBalanceWriteoffService {
recordLog(bill.getArBillId(), writeoffId, ArLogOperationType.CANCEL_BALANCE_WRITEOFF,
"反核销取消核销:" + cancelRemark,
fromStatus, nextStatus, operator, requestId);
// 4. 若该核销单由收款审核联动产生(receipt_id 非空):计划置 REVERSED、
// 收款单已分配CNY回退为未分配;全程不回补余额、不动额度(收款审核时已全额入账)。
if (writeoff.getReceiptId() != null) {
reverseReceiptLink(writeoff, operator, cancelRemark);
}
}
/**
* 反核销收款联动核销单时的单据回写(与反核销同一事务):
* 计划 EFFECTIVE -> REVERSED;收款单 allocated_amount 减回、unallocated_amount 回补并重算类型。
* 不触碰客户余额与授信额度。
*/
private void reverseReceiptLink(ArBalanceWriteoff writeoff, String operator, String cancelRemark) {
ReceiptWriteoffPlan plan = receiptWriteoffPlanMapper
.selectEffectiveByWriteoffId(writeoff.getWriteoffId());
if (plan == null) {
// 无 EFFECTIVE 计划:手工余额核销(无计划)或计划已被处理,不做收款单联动
return;
}
if (receiptWriteoffPlanMapper.updateReversedByWriteoffId(writeoff.getWriteoffId(), operator) != 1) {
throw new ServiceException("收款核销计划状态已变化,请刷新后重试");
}
CustomerReceipt receipt = customerMoneyMapper.selectReceiptById(writeoff.getReceiptId());
if (receipt == null || !CustomerReceipt.STATUS_CONFIRMED.equals(receipt.getStatus())) {
throw new ServiceException("关联收款单不存在或不是已确认状态,无法联动反核销");
}
BigDecimal amount = nvl(writeoff.getWriteoffAmount());
BigDecimal base = nvl(receipt.getBaseAmount());
BigDecimal newAllocated = nvl(receipt.getAllocatedAmount()).subtract(amount);
if (newAllocated.compareTo(BigDecimal.ZERO) < 0) {
newAllocated = BigDecimal.ZERO;
}
BigDecimal newUnallocated = base.subtract(newAllocated);
if (newUnallocated.compareTo(BigDecimal.ZERO) < 0) {
newUnallocated = BigDecimal.ZERO;
}
String receiptType;
if (newAllocated.compareTo(BigDecimal.ZERO) == 0) {
receiptType = CustomerReceipt.TYPE_PREPAY;
} else if (newAllocated.compareTo(base) >= 0) {
receiptType = CustomerReceipt.TYPE_REPAY;
} else {
receiptType = CustomerReceipt.TYPE_MIXED;
}
CustomerReceipt update = new CustomerReceipt();
update.setId(receipt.getId());
update.setAllocatedAmount(newAllocated);
update.setUnallocatedAmount(newUnallocated);
update.setReceiptType(receiptType);
update.setUpdateBy(operator);
if (customerMoneyMapper.updateReceiptAllocation(update) != 1) {
throw new ServiceException("关联收款单状态已变化,请刷新后重试");
}
recordLog(plan.getArBillId(), writeoff.getWriteoffId(), ArLogOperationType.CANCEL_BALANCE_WRITEOFF,
"收款单联动核销反核销,回退收款单分配金额 " + amount.toPlainString()
+ " CNY(" + receipt.getReceiptNo() + ",原因:" + cancelRemark + ")",
null, null, operator, IdUtils.fastSimpleUUID());
}
/**