额度限制去除,计费后额度允许为负

This commit is contained in:
luojiaquan
2026-09-18 18:14:41 +08:00
parent 9a26ba373a
commit f529067ae3
5 changed files with 69 additions and 67 deletions
@@ -249,6 +249,9 @@ public class CustomerAccountApiImpl implements ICustomerAccountApi
String currency = resolveCurrency(command.getCurrency());
String username = currentUsername();
Long userId = currentUserId();
// 计费开单准入:客户被停用(含删除)时直接拦截,与账户状态接口口径保持一致。
// 仅占用(新增计费)校验;释放/核销等清欠动作不受限,避免客户被停用后无法平账。
assertCustomerActive(customerId);
CustomerAccount account = lockAccountForUsage(customerId, currency, username);
if (account == null)
{
@@ -259,10 +262,20 @@ public class CustomerAccountApiImpl implements ICustomerAccountApi
BigDecimal beforeUsed = nz(account.getUsedCredit());
BigDecimal totalAvailable = nz(account.getTotalCredit()).add(nz(account.getExtraCredit()))
.subtract(beforeUsed);
if (Boolean.TRUE.equals(command.getCheckAvailable()) && totalAvailable.compareTo(amount) < 0)
if (Boolean.TRUE.equals(command.getCheckAvailable()))
{
throw new ServiceException("客户可用额度不足,当前可用额度:" + totalAvailable.toPlainString()
+ " " + currency + ",本次需占用:" + amount.toPlainString());
// 已处于超额(欠费)状态:可用额度已为负,任何新增计费一律拦截
if (totalAvailable.compareTo(BigDecimal.ZERO) < 0)
{
throw new ServiceException("客户已超额(欠费),当前可用额度:" + totalAvailable.toPlainString()
+ " " + currency + ",请先回款核销恢复额度后再计费开单");
}
if (totalAvailable.compareTo(amount) < 0)
{
throw new ServiceException("客户可用额度不足,当前可用额度:" + totalAvailable.toPlainString()
+ " " + currency + ",本次需占用:" + amount.toPlainString()
+ ",请回款核销或申请调整额度");
}
}
BigDecimal afterUsed = beforeUsed.add(amount).setScale(MONEY_SCALE, RoundingMode.HALF_UP);
account.setUsedCredit(afterUsed);
@@ -558,6 +571,23 @@ public class CustomerAccountApiImpl implements ICustomerAccountApi
customerMoneyMapper.insertCreditFlow(flow);
}
/**
* 计费开单准入:客户档案必须存在且为启用状态(is_enable='0')。
* 删除(del_flag='1',查询返回null)或停用(is_enable='1')均拒绝新增授信占用。
*/
private void assertCustomerActive(Long customerId)
{
BmsCustomer customer = bmsCustomerMapper.selectBmsCustomerByCustomerId(customerId);
if (customer == null)
{
throw new ServiceException("客户不存在或已删除,不可计费开单(客户ID:" + customerId + ")");
}
if ("1".equals(customer.getIsEnable()))
{
throw new ServiceException("客户【" + customer.getCustomerName() + "】已停用,不可计费开单");
}
}
private void validateUsageCommand(CreditUsageCommand command)
{
if (command == null || (command.getCustomerId() == null && !StringUtils.hasText(command.getCustomerCode())))
@@ -22,14 +22,15 @@ public class BmsExchangeRate extends BaseEntity
/** 系统本位币 */
public static final String BASE_CURRENCY = "CNY";
/** 汇率类型:即期汇率 */
/** 汇率类型:即期汇率(当前系统仅启用即期汇率) */
public static final String RATE_TYPE_SPOT = "0";
/** 汇率类型:月初汇率 */
public static final String RATE_TYPE_MONTH_BEGIN = "1";
/** 汇率类型:月末汇率 */
public static final String RATE_TYPE_MONTH_END = "2";
/** 汇率类型:固定汇率 */
public static final String RATE_TYPE_FIXED = "3";
// 月初/月末/固定汇率暂不启用,先只做即期,后续需要时再恢复:
// /** 汇率类型:月初汇率 */
// public static final String RATE_TYPE_MONTH_BEGIN = "1";
// /** 汇率类型:月末汇率 */
// public static final String RATE_TYPE_MONTH_END = "2";
// /** 汇率类型:固定汇率 */
// public static final String RATE_TYPE_FIXED = "3";
/** 汇率ID */
private Long rateId;
@@ -42,8 +43,8 @@ public class BmsExchangeRate extends BaseEntity
@Excel(name = "目标币种")
private String toCurrency;
/** 汇率类型(0即期 1月初 2月末 3固定) */
@Excel(name = "汇率类型", readConverterExp = "0=即期汇率,1=月初汇率,2=月末汇率,3=固定汇率")
/** 汇率类型(当前仅 0即期;月初/月末/固定暂不启用) */
@Excel(name = "汇率类型", readConverterExp = "0=即期汇率")
private String rateType;
/** 汇率值(1源币种=?目标币种) */
@@ -31,6 +31,8 @@ public class BmsExchangeRateServiceImpl implements IBmsExchangeRateService
@Override
public List<BmsExchangeRate> selectExchangeRateList(BmsExchangeRate exchangeRate)
{
// 当前仅启用即期汇率:列表/导出只展示即期配置
exchangeRate.setRateType(BmsExchangeRate.RATE_TYPE_SPOT);
return exchangeRateMapper.selectExchangeRateList(exchangeRate);
}
@@ -77,7 +79,9 @@ public class BmsExchangeRateServiceImpl implements IBmsExchangeRateService
{
String from = normalizeCurrency(fromCurrency);
String to = normalizeCurrency(toCurrency);
String type = StringUtils.isNotEmpty(rateType) ? rateType : BmsExchangeRate.RATE_TYPE_SPOT;
// 当前系统只启用即期汇率:忽略外部传入的 rateType,统一按即期处理。
// 后续启用月初/月末/固定汇率时,恢复为:StringUtils.isNotEmpty(rateType) ? rateType : RATE_TYPE_SPOT
String type = BmsExchangeRate.RATE_TYPE_SPOT;
Date date = truncateToDay(bizDate != null ? bizDate : DateUtils.getNowDate());
// 同币种
@@ -212,10 +216,8 @@ public class BmsExchangeRateServiceImpl implements IBmsExchangeRateService
{
rate.setFromCurrency(normalizeCurrency(rate.getFromCurrency()));
rate.setToCurrency(normalizeCurrency(rate.getToCurrency()));
if (StringUtils.isEmpty(rate.getRateType()))
{
rate.setRateType(BmsExchangeRate.RATE_TYPE_SPOT);
}
// 当前仅启用即期汇率,新增/编辑统一落即期(月初/月末/固定暂不启用)
rate.setRateType(BmsExchangeRate.RATE_TYPE_SPOT);
if (StringUtils.isEmpty(rate.getSource()))
{
rate.setSource("手工录入");
@@ -273,9 +275,10 @@ public class BmsExchangeRateServiceImpl implements IBmsExchangeRateService
{
switch (type)
{
case BmsExchangeRate.RATE_TYPE_MONTH_BEGIN: return "月初汇率";
case BmsExchangeRate.RATE_TYPE_MONTH_END: return "月末汇率";
case BmsExchangeRate.RATE_TYPE_FIXED: return "固定汇率";
// 月初/月末/固定汇率暂不启用,先只做即期:
// case BmsExchangeRate.RATE_TYPE_MONTH_BEGIN: return "月初汇率";
// case BmsExchangeRate.RATE_TYPE_MONTH_END: return "月末汇率";
// case BmsExchangeRate.RATE_TYPE_FIXED: return "固定汇率";
case BmsExchangeRate.RATE_TYPE_SPOT:
default: return "即期汇率";
}