去掉应收登记收款功能逻辑
This commit is contained in:
@@ -10,8 +10,8 @@ import lombok.EqualsAndHashCode;
|
||||
/**
|
||||
* 应收账单余额核销 ar_balance_writeoff
|
||||
*
|
||||
* <p>用客户账户余额核销应收账单,与 ar_receipt_writeoff(收款核销)并列,
|
||||
* 两者共享 ar_bill.written_off_amount / unwritten_amount 缓存。</p>
|
||||
* <p>用客户账户余额核销应收账单,和客户账户余额流水联动,
|
||||
* 共享 ar_bill.written_off_amount / unwritten_amount 缓存。</p>
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-09-16
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.ruoyi.ar.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/** 应收真实收款。 */
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ArReceipt extends BaseEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long receiptId;
|
||||
private String receiptNo;
|
||||
private Long customerId;
|
||||
/** 客户名称,仅用于列表展示。 */
|
||||
private String customerName;
|
||||
/** 客户编码,仅用于列表展示。 */
|
||||
private String customerCode;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date receiptDate;
|
||||
private String currency;
|
||||
private BigDecimal receiptAmount;
|
||||
private BigDecimal unallocatedAmount;
|
||||
private String paymentMethod;
|
||||
private String bankReference;
|
||||
private String status;
|
||||
private String remark;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.ruoyi.ar.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
/** 收款与账单的核销关系。 */
|
||||
@Data
|
||||
public class ArReceiptWriteoff implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long writeoffId;
|
||||
private Long receiptId;
|
||||
private Long arBillId;
|
||||
/** 关联账单号,仅用于核销记录展示。 */
|
||||
private String billNo;
|
||||
/** 关联收款单号,仅用于核销记录展示。 */
|
||||
private String receiptNo;
|
||||
private String writeoffNo;
|
||||
private BigDecimal writeoffAmount;
|
||||
private String currency;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date writeoffDate;
|
||||
private String status;
|
||||
private String remark;
|
||||
private String createBy;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
private String cancelBy;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date cancelTime;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.ruoyi.ar.domain.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import com.ruoyi.ar.domain.ArReceipt;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/** 收款查询参数。 */
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ArReceiptQuery extends ArReceipt
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private Date receiptDateStart;
|
||||
private Date receiptDateEnd;
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
package com.ruoyi.ar.domain.vo;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/** 批量收款核销参数。 */
|
||||
@Data
|
||||
public class ArReceiptWriteoffRequest
|
||||
{
|
||||
@NotNull(message = "收款ID不能为空")
|
||||
private Long receiptId;
|
||||
@NotEmpty(message = "至少选择一张账单")
|
||||
@Valid
|
||||
private List<Allocation> allocations;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date writeoffDate;
|
||||
private String currency;
|
||||
private String remark;
|
||||
private String requestId;
|
||||
|
||||
@Data
|
||||
public static class Allocation
|
||||
{
|
||||
@NotNull(message = "账单ID不能为空")
|
||||
private Long arBillId;
|
||||
@NotNull(message = "核销金额不能为空")
|
||||
private BigDecimal amount;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.ruoyi.ar.enums;
|
||||
|
||||
/** 应收收款状态。 */
|
||||
public enum ArReceiptStatus
|
||||
{
|
||||
REGISTERED("REGISTERED"),
|
||||
PARTIAL_WRITTEN_OFF("PARTIAL_WRITTEN_OFF"),
|
||||
WRITTEN_OFF("WRITTEN_OFF"),
|
||||
CANCELLED("CANCELLED");
|
||||
|
||||
private final String code;
|
||||
|
||||
ArReceiptStatus(String code)
|
||||
{
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.ruoyi.ar.enums;
|
||||
|
||||
/** 收款核销状态。 */
|
||||
public enum ArWriteoffStatus
|
||||
{
|
||||
EFFECTIVE("EFFECTIVE"),
|
||||
CANCELLED("CANCELLED");
|
||||
|
||||
private final String code;
|
||||
|
||||
ArWriteoffStatus(String code)
|
||||
{
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.ruoyi.ar.mapper;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.ruoyi.ar.domain.ArReceipt;
|
||||
import com.ruoyi.ar.domain.vo.ArReceiptQuery;
|
||||
|
||||
public interface ArReceiptMapper
|
||||
{
|
||||
List<ArReceipt> selectArReceiptList(ArReceiptQuery query);
|
||||
|
||||
ArReceipt selectArReceiptById(Long receiptId);
|
||||
|
||||
ArReceipt selectArReceiptByIdForUpdate(Long receiptId);
|
||||
|
||||
ArReceipt selectArReceiptByNo(String receiptNo);
|
||||
|
||||
ArReceipt selectArReceiptByReference(@Param("paymentMethod") String paymentMethod,
|
||||
@Param("bankReference") String bankReference);
|
||||
|
||||
int insertArReceipt(ArReceipt receipt);
|
||||
|
||||
int updateBalanceAndStatus(@Param("receiptId") Long receiptId,
|
||||
@Param("unallocatedAmount") BigDecimal unallocatedAmount,
|
||||
@Param("status") String status, @Param("operator") String operator);
|
||||
|
||||
int updateCancelled(@Param("receiptId") Long receiptId, @Param("operator") String operator,
|
||||
@Param("remark") String remark);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.ruoyi.ar.mapper;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.ruoyi.ar.domain.ArReceiptWriteoff;
|
||||
|
||||
public interface ArReceiptWriteoffMapper
|
||||
{
|
||||
List<ArReceiptWriteoff> selectByBillId(Long arBillId);
|
||||
|
||||
List<ArReceiptWriteoff> selectByReceiptId(Long receiptId);
|
||||
|
||||
ArReceiptWriteoff selectById(Long writeoffId);
|
||||
|
||||
ArReceiptWriteoff selectByIdForUpdate(Long writeoffId);
|
||||
|
||||
int insert(ArReceiptWriteoff writeoff);
|
||||
|
||||
int updateCancelled(@Param("writeoffId") Long writeoffId, @Param("cancelBy") String cancelBy,
|
||||
@Param("remark") String remark);
|
||||
|
||||
BigDecimal sumEffectiveByBillId(Long arBillId);
|
||||
|
||||
BigDecimal sumEffectiveByReceiptId(Long receiptId);
|
||||
}
|
||||
+1
-2
@@ -7,8 +7,7 @@ import com.ruoyi.ar.domain.ArBill;
|
||||
/**
|
||||
* 应收账单余额核销 Service接口
|
||||
*
|
||||
* <p>资金来源为客户账户余额(customer_account.balance),与收款核销
|
||||
* (ar_receipt_writeoff)并列;核销时三方联动:账户余额扣减、已用额度释放、
|
||||
* <p>资金来源为客户账户余额(customer_account.balance);核销时三方联动:账户余额扣减、已用额度释放、
|
||||
* 账单已核销/未核销金额及状态更新。</p>
|
||||
*
|
||||
* @author ruoyi
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.ruoyi.ar.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.ruoyi.ar.domain.ArReceipt;
|
||||
import com.ruoyi.ar.domain.ArReceiptWriteoff;
|
||||
import com.ruoyi.ar.domain.vo.ArReceiptQuery;
|
||||
import com.ruoyi.ar.domain.vo.ArReceiptWriteoffRequest;
|
||||
|
||||
public interface IArReceiptService
|
||||
{
|
||||
List<ArReceipt> selectReceiptList(ArReceiptQuery query);
|
||||
|
||||
List<ArReceiptWriteoff> selectWriteoffs(Long receiptId);
|
||||
|
||||
ArReceipt registerReceipt(ArReceipt receipt, String operator, String requestId);
|
||||
|
||||
void cancelReceipt(Long receiptId, String remark, String operator, String requestId);
|
||||
|
||||
List<ArReceiptWriteoff> writeoff(ArReceiptWriteoffRequest request, String operator, String requestId);
|
||||
|
||||
void cancelWriteoff(Long writeoffId, String remark, String operator, String requestId);
|
||||
}
|
||||
-275
@@ -1,275 +0,0 @@
|
||||
package com.ruoyi.ar.service.impl;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.ruoyi.ar.domain.ArBill;
|
||||
import com.ruoyi.ar.domain.ArBillLog;
|
||||
import com.ruoyi.ar.domain.ArReceipt;
|
||||
import com.ruoyi.ar.domain.ArReceiptWriteoff;
|
||||
import com.ruoyi.ar.domain.vo.ArReceiptQuery;
|
||||
import com.ruoyi.ar.domain.vo.ArReceiptWriteoffRequest;
|
||||
import com.ruoyi.ar.enums.ArBillStatus;
|
||||
import com.ruoyi.ar.enums.ArLogResult;
|
||||
import com.ruoyi.ar.enums.ArReceiptStatus;
|
||||
import com.ruoyi.ar.enums.ArWriteoffStatus;
|
||||
import com.ruoyi.ar.mapper.ArBillMapper;
|
||||
import com.ruoyi.ar.mapper.ArBillLogMapper;
|
||||
import com.ruoyi.ar.mapper.ArReceiptMapper;
|
||||
import com.ruoyi.ar.mapper.ArReceiptWriteoffMapper;
|
||||
import com.ruoyi.ar.service.IArBillLogService;
|
||||
import com.ruoyi.ar.service.IArReceiptService;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.uuid.IdUtils;
|
||||
|
||||
@Service
|
||||
public class ArReceiptServiceImpl implements IArReceiptService
|
||||
{
|
||||
@Autowired private ArReceiptMapper receiptMapper;
|
||||
@Autowired private ArReceiptWriteoffMapper writeoffMapper;
|
||||
@Autowired private ArBillMapper billMapper;
|
||||
@Autowired private ArBillLogMapper logMapper;
|
||||
@Autowired private IArBillLogService logService;
|
||||
|
||||
@Override
|
||||
public List<ArReceipt> selectReceiptList(ArReceiptQuery query)
|
||||
{
|
||||
return receiptMapper.selectArReceiptList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArReceiptWriteoff> selectWriteoffs(Long receiptId)
|
||||
{
|
||||
return writeoffMapper.selectByReceiptId(receiptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ArReceipt registerReceipt(ArReceipt receipt, String operator, String requestId)
|
||||
{
|
||||
if (receipt == null || receipt.getCustomerId() == null || receipt.getReceiptDate() == null
|
||||
|| receipt.getReceiptAmount() == null || receipt.getReceiptAmount().compareTo(BigDecimal.ZERO) <= 0)
|
||||
{
|
||||
throw failure(null, "RECEIPT", "REGISTER", "收款客户、日期和正数金额不能为空", operator, requestId);
|
||||
}
|
||||
if (StringUtils.isEmpty(receipt.getReceiptNo()))
|
||||
{
|
||||
receipt.setReceiptNo("RC" + DateUtils.dateTimeNow("yyyyMMddHHmmss") + IdUtils.fastSimpleUUID().substring(0, 6).toUpperCase());
|
||||
}
|
||||
if (StringUtils.isEmpty(receipt.getCurrency())) receipt.setCurrency("CNY");
|
||||
if (StringUtils.isEmpty(receipt.getPaymentMethod())) receipt.setPaymentMethod("BANK");
|
||||
ArBillLog previous = logMapper.selectSuccessByRequestId(requestId, "RECEIPT");
|
||||
if (previous != null && isNumber(previous.getObjectId()))
|
||||
{
|
||||
ArReceipt existed = receiptMapper.selectArReceiptById(Long.valueOf(previous.getObjectId()));
|
||||
if (existed != null) return existed;
|
||||
}
|
||||
if (receiptMapper.selectArReceiptByNo(receipt.getReceiptNo()) != null)
|
||||
{
|
||||
throw failure(null, "RECEIPT", receipt.getReceiptNo(), "收款单号已存在", operator, requestId);
|
||||
}
|
||||
if (!StringUtils.isEmpty(receipt.getBankReference())
|
||||
&& receiptMapper.selectArReceiptByReference(receipt.getPaymentMethod(), receipt.getBankReference()) != null)
|
||||
{
|
||||
throw failure(null, "RECEIPT", receipt.getReceiptNo(), "银行流水号已存在", operator, requestId);
|
||||
}
|
||||
receipt.setUnallocatedAmount(receipt.getReceiptAmount());
|
||||
receipt.setStatus(ArReceiptStatus.REGISTERED.getCode());
|
||||
receipt.setCreateBy(operator);
|
||||
receipt.setUpdateBy(operator);
|
||||
try
|
||||
{
|
||||
receiptMapper.insertArReceipt(receipt);
|
||||
}
|
||||
catch (DuplicateKeyException e)
|
||||
{
|
||||
ArReceipt existed = receiptMapper.selectArReceiptByNo(receipt.getReceiptNo());
|
||||
if (existed != null) return existed;
|
||||
throw e;
|
||||
}
|
||||
ArBillLog log = new ArBillLog();
|
||||
log.setObjectType("RECEIPT"); log.setObjectId(String.valueOf(receipt.getReceiptId()));
|
||||
log.setOperationType("RECEIPT"); log.setOperationDesc("登记应收收款");
|
||||
log.setOperatorId(operator); log.setOperatorName(operator); log.setOperationSource("WEB");
|
||||
log.setRequestId(requestId); log.setResult(ArLogResult.SUCCESS.getCode()); logService.record(log);
|
||||
return receipt;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void cancelReceipt(Long receiptId, String remark, String operator, String requestId)
|
||||
{
|
||||
ArBillLog previous = logMapper.selectSuccessByRequestId(requestId, "RECEIPT");
|
||||
if (previous != null && "CANCEL_RECEIPT".equals(previous.getOperationType())) return;
|
||||
ArReceipt receipt = receiptMapper.selectArReceiptByIdForUpdate(receiptId);
|
||||
if (receipt == null) throw failure(null, "RECEIPT", String.valueOf(receiptId), "收款不存在", operator, requestId);
|
||||
if (!ArReceiptStatus.REGISTERED.getCode().equals(receipt.getStatus())
|
||||
|| nvl(receipt.getUnallocatedAmount()).compareTo(nvl(receipt.getReceiptAmount())) != 0)
|
||||
{
|
||||
throw failure(null, "RECEIPT", String.valueOf(receiptId), "收款已发生核销,不能直接取消", operator, requestId);
|
||||
}
|
||||
receiptMapper.updateCancelled(receiptId, operator, StringUtils.isEmpty(remark) ? "取消收款" : remark);
|
||||
ArBillLog log = new ArBillLog();
|
||||
log.setObjectType("RECEIPT"); log.setObjectId(String.valueOf(receiptId)); log.setOperationType("CANCEL_RECEIPT");
|
||||
log.setOperationDesc(StringUtils.isEmpty(remark) ? "取消收款" : remark); log.setFromStatus(ArReceiptStatus.REGISTERED.getCode());
|
||||
log.setToStatus(ArReceiptStatus.CANCELLED.getCode()); log.setOperatorId(operator); log.setOperatorName(operator);
|
||||
log.setOperationSource("WEB"); log.setRequestId(requestId); log.setResult(ArLogResult.SUCCESS.getCode()); logService.record(log);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<ArReceiptWriteoff> writeoff(ArReceiptWriteoffRequest request, String operator, String requestId)
|
||||
{
|
||||
if (request == null || request.getReceiptId() == null || request.getAllocations() == null || request.getAllocations().isEmpty())
|
||||
{
|
||||
throw failure(null, "WRITEOFF", "", "核销收款和账单不能为空", operator, requestId);
|
||||
}
|
||||
ArBillLog previous = logMapper.selectSuccessByRequestId(requestId, "WRITEOFF");
|
||||
if (previous != null && isNumber(previous.getObjectId()))
|
||||
{
|
||||
ArReceiptWriteoff existed = writeoffMapper.selectById(Long.valueOf(previous.getObjectId()));
|
||||
if (existed != null) return writeoffMapper.selectByReceiptId(existed.getReceiptId());
|
||||
}
|
||||
ArReceipt receipt = receiptMapper.selectArReceiptByIdForUpdate(request.getReceiptId());
|
||||
if (receipt == null) throw failure(null, "WRITEOFF", String.valueOf(request.getReceiptId()), "收款不存在", operator, requestId);
|
||||
if (ArReceiptStatus.CANCELLED.getCode().equals(receipt.getStatus()))
|
||||
{
|
||||
throw failure(null, "WRITEOFF", String.valueOf(request.getReceiptId()), "收款已取消,不允许核销", operator, requestId);
|
||||
}
|
||||
String currency = StringUtils.isEmpty(request.getCurrency()) ? receipt.getCurrency() : request.getCurrency();
|
||||
if (!currency.equalsIgnoreCase(receipt.getCurrency()))
|
||||
{
|
||||
throw failure(null, "WRITEOFF", String.valueOf(request.getReceiptId()), "收款与核销币种不一致", operator, requestId);
|
||||
}
|
||||
BigDecimal allocationTotal = BigDecimal.ZERO;
|
||||
for (ArReceiptWriteoffRequest.Allocation allocation : request.getAllocations())
|
||||
{
|
||||
if (allocation.getAmount() == null || allocation.getAmount().compareTo(BigDecimal.ZERO) <= 0)
|
||||
{
|
||||
throw failure(null, "WRITEOFF", String.valueOf(request.getReceiptId()), "核销金额必须大于零", operator, requestId);
|
||||
}
|
||||
allocationTotal = allocationTotal.add(allocation.getAmount());
|
||||
}
|
||||
if (allocationTotal.compareTo(nvl(receipt.getUnallocatedAmount())) > 0)
|
||||
{
|
||||
throw failure(null, "WRITEOFF", String.valueOf(request.getReceiptId()), "核销金额超过收款未分配余额", operator, requestId);
|
||||
}
|
||||
|
||||
List<ArReceiptWriteoff> result = new ArrayList<>();
|
||||
BigDecimal remainingReceipt = nvl(receipt.getUnallocatedAmount());
|
||||
Date writeoffDate = request.getWriteoffDate() == null ? new Date() : request.getWriteoffDate();
|
||||
for (ArReceiptWriteoffRequest.Allocation allocation : request.getAllocations())
|
||||
{
|
||||
ArBill bill = billMapper.selectArBillByIdForUpdate(allocation.getArBillId());
|
||||
if (bill == null) throw failure(null, "WRITEOFF", String.valueOf(allocation.getArBillId()), "账单不存在", operator, requestId);
|
||||
ArBillStatus billStatus = ArBillStatus.of(bill.getStatus());
|
||||
if (billStatus == ArBillStatus.VOID) throw failure(bill.getArBillId(), "WRITEOFF", String.valueOf(bill.getArBillId()), "账单已作废,不允许核销", operator, requestId);
|
||||
if (billStatus == null || !billStatus.canWriteOff())
|
||||
{
|
||||
throw failure(bill.getArBillId(), "WRITEOFF", String.valueOf(bill.getArBillId()), "账单尚未确认,不允许核销", operator, requestId);
|
||||
}
|
||||
if (!currency.equalsIgnoreCase(bill.getCurrency())) throw failure(bill.getArBillId(), "WRITEOFF", String.valueOf(bill.getArBillId()), "收款与账单币种不一致", operator, requestId);
|
||||
BigDecimal amount = allocation.getAmount();
|
||||
if (amount.compareTo(nvl(bill.getUnwrittenAmount())) > 0)
|
||||
{
|
||||
throw failure(bill.getArBillId(), "WRITEOFF", String.valueOf(bill.getArBillId()), "核销金额超过账单未核销余额", operator, requestId);
|
||||
}
|
||||
ArReceiptWriteoff writeoff = new ArReceiptWriteoff();
|
||||
writeoff.setReceiptId(receipt.getReceiptId()); writeoff.setArBillId(bill.getArBillId());
|
||||
writeoff.setWriteoffNo("WO" + DateUtils.dateTimeNow("yyyyMMddHHmmss") + IdUtils.fastSimpleUUID().substring(0, 6).toUpperCase());
|
||||
writeoff.setWriteoffAmount(amount); writeoff.setCurrency(currency); writeoff.setWriteoffDate(writeoffDate);
|
||||
writeoff.setStatus(ArWriteoffStatus.EFFECTIVE.getCode()); writeoff.setRemark(request.getRemark()); writeoff.setCreateBy(operator);
|
||||
writeoffMapper.insert(writeoff);
|
||||
remainingReceipt = remainingReceipt.subtract(amount);
|
||||
BigDecimal written = nvl(bill.getWrittenOffAmount()).add(amount);
|
||||
BigDecimal unwritten = nvl(bill.getUnwrittenAmount()).subtract(amount);
|
||||
String nextBillStatus = billStatus(written, nvl(bill.getTotalAmount()), bill.getStatus());
|
||||
if (billMapper.updateArBillAmounts(bill.getArBillId(), written, unwritten,
|
||||
nextBillStatus, operator, bill.getStatus()) != 1)
|
||||
{
|
||||
throw failure(bill.getArBillId(), "WRITEOFF", String.valueOf(bill.getArBillId()), "账单状态已发生变化,请刷新后重试", operator, requestId);
|
||||
}
|
||||
writeoffLog(writeoff, bill, operator, requestId);
|
||||
result.add(writeoff);
|
||||
}
|
||||
receiptMapper.updateBalanceAndStatus(receipt.getReceiptId(), remainingReceipt,
|
||||
remainingReceipt.compareTo(BigDecimal.ZERO) == 0 ? ArReceiptStatus.WRITTEN_OFF.getCode() : ArReceiptStatus.PARTIAL_WRITTEN_OFF.getCode(), operator);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void cancelWriteoff(Long writeoffId, String remark, String operator, String requestId)
|
||||
{
|
||||
ArBillLog previous = logMapper.selectSuccessByRequestId(requestId, "WRITEOFF");
|
||||
if (previous != null && "CANCEL_WRITEOFF".equals(previous.getOperationType())) return;
|
||||
ArReceiptWriteoff writeoff = writeoffMapper.selectByIdForUpdate(writeoffId);
|
||||
if (writeoff == null) throw failure(null, "WRITEOFF", String.valueOf(writeoffId), "核销记录不存在", operator, requestId);
|
||||
if (!ArWriteoffStatus.EFFECTIVE.getCode().equals(writeoff.getStatus())) throw failure(writeoff.getArBillId(), "WRITEOFF", String.valueOf(writeoffId), "只有有效核销可以取消", operator, requestId);
|
||||
ArReceipt receipt = receiptMapper.selectArReceiptByIdForUpdate(writeoff.getReceiptId());
|
||||
ArBill bill = billMapper.selectArBillByIdForUpdate(writeoff.getArBillId());
|
||||
if (receipt == null || bill == null) throw failure(writeoff.getArBillId(), "WRITEOFF", String.valueOf(writeoffId), "核销关联的收款或账单不存在", operator, requestId);
|
||||
writeoffMapper.updateCancelled(writeoffId, operator, StringUtils.isEmpty(remark) ? "取消核销" : remark);
|
||||
BigDecimal receiptUnallocated = nvl(receipt.getUnallocatedAmount()).add(writeoff.getWriteoffAmount());
|
||||
receiptMapper.updateBalanceAndStatus(receipt.getReceiptId(), receiptUnallocated,
|
||||
receiptUnallocated.compareTo(nvl(receipt.getReceiptAmount())) == 0 ? ArReceiptStatus.REGISTERED.getCode() : ArReceiptStatus.PARTIAL_WRITTEN_OFF.getCode(), operator);
|
||||
BigDecimal written = nvl(bill.getWrittenOffAmount()).subtract(writeoff.getWriteoffAmount());
|
||||
if (written.compareTo(BigDecimal.ZERO) < 0) written = BigDecimal.ZERO;
|
||||
BigDecimal unwritten = nvl(bill.getTotalAmount()).subtract(written);
|
||||
String nextBillStatus = billStatus(written, nvl(bill.getTotalAmount()), bill.getStatus());
|
||||
if (billMapper.updateArBillAmounts(bill.getArBillId(), written, unwritten,
|
||||
nextBillStatus, operator, bill.getStatus()) != 1)
|
||||
{
|
||||
throw failure(bill.getArBillId(), "WRITEOFF", String.valueOf(bill.getArBillId()), "账单状态已发生变化,请刷新后重试", operator, requestId);
|
||||
}
|
||||
ArBillLog log = new ArBillLog();
|
||||
log.setArBillId(bill.getArBillId()); log.setObjectType("WRITEOFF"); log.setObjectId(String.valueOf(writeoffId));
|
||||
log.setOperationType("CANCEL_WRITEOFF"); log.setOperationDesc(StringUtils.isEmpty(remark) ? "取消核销" : remark);
|
||||
log.setFromStatus(ArWriteoffStatus.EFFECTIVE.getCode()); log.setToStatus(ArWriteoffStatus.CANCELLED.getCode()); log.setOperatorId(operator); log.setOperatorName(operator);
|
||||
log.setOperationSource("WEB"); log.setRequestId(requestId); log.setResult(ArLogResult.SUCCESS.getCode()); logService.record(log);
|
||||
}
|
||||
|
||||
private void writeoffLog(ArReceiptWriteoff writeoff, ArBill bill, String operator, String requestId)
|
||||
{
|
||||
ArBillLog log = new ArBillLog();
|
||||
log.setArBillId(bill.getArBillId()); log.setObjectType("WRITEOFF"); log.setObjectId(String.valueOf(writeoff.getWriteoffId()));
|
||||
log.setOperationType("WRITEOFF"); log.setOperationDesc("收款核销到账单"); log.setFromStatus(bill.getStatus());
|
||||
log.setToStatus(billStatus(nvl(bill.getWrittenOffAmount()).add(writeoff.getWriteoffAmount()), nvl(bill.getTotalAmount()), bill.getStatus()));
|
||||
log.setOperatorId(operator); log.setOperatorName(operator); log.setOperationSource("WEB"); log.setRequestId(requestId); log.setResult(ArLogResult.SUCCESS.getCode());
|
||||
logService.record(log);
|
||||
}
|
||||
|
||||
private String billStatus(BigDecimal written, BigDecimal total, String current)
|
||||
{
|
||||
if (written.compareTo(BigDecimal.ZERO) == 0)
|
||||
{
|
||||
return ArBillStatus.DRAFT.getCode().equals(current)
|
||||
? ArBillStatus.DRAFT.getCode() : ArBillStatus.CONFIRMED.getCode();
|
||||
}
|
||||
return written.compareTo(total) >= 0
|
||||
? ArBillStatus.WRITTEN_OFF.getCode() : ArBillStatus.PARTIAL_WRITTEN_OFF.getCode();
|
||||
}
|
||||
|
||||
private ServiceException failure(Long billId, String objectType, String message, String operator, String requestId)
|
||||
{
|
||||
logService.recordFailure(billId, objectType, objectType, "RECEIPT", null, message, operator, requestId);
|
||||
return new ServiceException(message);
|
||||
}
|
||||
|
||||
private ServiceException failure(Long billId, String objectType, String objectId, String message, String operator, String requestId)
|
||||
{
|
||||
logService.recordFailure(billId, objectType, objectId,
|
||||
"RECEIPT".equals(objectType) ? "RECEIPT" : "WRITEOFF", null, message, operator, requestId);
|
||||
return new ServiceException(message);
|
||||
}
|
||||
|
||||
private BigDecimal nvl(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; }
|
||||
private boolean isNumber(String value) { if (StringUtils.isEmpty(value)) return false; try { Long.valueOf(value); return true; } catch (NumberFormatException e) { return false; } }
|
||||
}
|
||||
Reference in New Issue
Block a user