额度限制去除,计费后额度允许为负
This commit is contained in:
+33
-3
@@ -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源币种=?目标币种) */
|
||||
|
||||
+11
-8
@@ -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 "即期汇率";
|
||||
}
|
||||
|
||||
@@ -295,13 +295,14 @@
|
||||
<el-table-column label="时间" align="center" prop="createTime" width="160">
|
||||
<template #default="scope">{{ formatDateTime(scope.row.createTime) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="额度类型" align="center" prop="creditType" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.creditType === 'TEMP' ? 'warning' : ''">
|
||||
{{ formatOption(creditTypeOptions, scope.row.creditType) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="额度类型" align="center" prop="creditType" width="100">-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <el-tag :type="scope.row.creditType === 'TEMP' ? 'warning' : ''">-->
|
||||
<!-- {{ formatOption(creditTypeOptions, scope.row.creditType) }}-->
|
||||
<!-- </el-tag>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<el-table-column label="业务单号" align="center" prop="bizNo" width="190" />
|
||||
<el-table-column label="变动类型" align="center" prop="changeType" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="creditChangeTag(scope.row.changeType)">
|
||||
|
||||
@@ -22,11 +22,6 @@
|
||||
<el-option v-for="c in currencyOptions" :key="c" :label="c" :value="c" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="汇率类型">
|
||||
<el-select v-model="calc.rateType" style="width: 110px;">
|
||||
<el-option v-for="d in rateTypeOptions" :key="d.value" :label="d.label" :value="d.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="业务日期">
|
||||
<el-date-picker v-model="calc.bizDate" type="date" value-format="YYYY-MM-DD" placeholder="默认今天" style="width: 150px;" />
|
||||
</el-form-item>
|
||||
@@ -43,7 +38,7 @@
|
||||
<el-divider direction="vertical" />
|
||||
<span style="font-size: 12px; color: #909399;">
|
||||
汇率 1 {{ calcResult.fromCurrency }} = {{ calcResult.rate }} {{ calcResult.toCurrency }}
|
||||
({{ ratePathText(calcResult.ratePath) }},{{ rateTypeText(calcResult.rateType) }},{{ calcResult.bizDate }})
|
||||
({{ ratePathText(calcResult.ratePath) }},即期汇率,{{ calcResult.bizDate }})
|
||||
</span>
|
||||
</template>
|
||||
</el-alert>
|
||||
@@ -61,11 +56,6 @@
|
||||
<el-option v-for="c in currencyOptions" :key="c" :label="c" :value="c" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="汇率类型" prop="rateType">
|
||||
<el-select v-model="queryParams.rateType" clearable style="width: 120px;" placeholder="全部">
|
||||
<el-option v-for="d in rateTypeOptions" :key="d.value" :label="d.label" :value="d.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="来源" prop="source">
|
||||
<el-input v-model="queryParams.source" placeholder="汇率来源" clearable style="width: 140px;" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
@@ -97,11 +87,6 @@
|
||||
<el-tag size="small" type="success">{{ scope.row.toCurrency }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" align="center" prop="rateType" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="rateTypeTag(scope.row.rateType)">{{ rateTypeText(scope.row.rateType) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="汇率值(1源=?目标)" align="center" prop="exchangeRate" width="170">
|
||||
<template #default="scope">
|
||||
<span class="rate-value">{{ formatRate(scope.row.exchangeRate) }}</span>
|
||||
@@ -149,10 +134,9 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="汇率类型" prop="rateType">
|
||||
<el-select v-model="form.rateType" style="width: 100%;">
|
||||
<el-option v-for="d in rateTypeOptions" :key="d.value" :label="d.label" :value="d.value" />
|
||||
</el-select>
|
||||
<el-form-item label="汇率类型">
|
||||
<el-tag type="danger">即期汇率</el-tag>
|
||||
<span style="margin-left: 8px; font-size: 12px; color: #909399;">当前仅支持即期</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@@ -213,13 +197,8 @@ const title = ref('')
|
||||
const open = ref(false)
|
||||
const calcResult = ref(null)
|
||||
|
||||
const rateTypeOptions = [
|
||||
{ value: '0', label: '即期汇率' }
|
||||
// ,
|
||||
// { value: '1', label: '月初汇率' },
|
||||
// { value: '2', label: '月末汇率' },
|
||||
// { value: '3', label: '固定汇率' }
|
||||
]
|
||||
// 当前系统仅启用即期汇率(rateType 固定 '0'),不再维护类型字典;
|
||||
// 后续启用月初/月末/固定汇率时,再恢复 rateTypeOptions 及各处类型选择器。
|
||||
|
||||
/** 常用币种兜底 + 从国家资料(币种)去重加载 */
|
||||
const currencyOptions = ref(['CNY', 'USD', 'EUR', 'GBP', 'HKD', 'JPY'])
|
||||
@@ -237,7 +216,6 @@ const queryParams = reactive({
|
||||
pageSize: 10,
|
||||
fromCurrency: '',
|
||||
toCurrency: '',
|
||||
rateType: '',
|
||||
source: ''
|
||||
})
|
||||
|
||||
@@ -245,7 +223,6 @@ const calc = reactive({
|
||||
amount: 100,
|
||||
fromCurrency: 'USD',
|
||||
toCurrency: 'CNY',
|
||||
rateType: '0',
|
||||
bizDate: ''
|
||||
})
|
||||
|
||||
@@ -253,18 +230,10 @@ const form = ref({})
|
||||
const rules = {
|
||||
fromCurrency: [{ required: true, message: '源币种不能为空', trigger: 'change' }],
|
||||
toCurrency: [{ required: true, message: '目标币种不能为空', trigger: 'change' }],
|
||||
rateType: [{ required: true, message: '请选择汇率类型', trigger: 'change' }],
|
||||
exchangeRate: [{ required: true, message: '汇率值不能为空', trigger: 'blur' }],
|
||||
effectiveDate: [{ required: true, message: '生效日期不能为空', trigger: 'change' }]
|
||||
}
|
||||
|
||||
function rateTypeText(v) {
|
||||
const o = rateTypeOptions.find(d => d.value === String(v))
|
||||
return o ? o.label : v
|
||||
}
|
||||
function rateTypeTag(v) {
|
||||
return { '0': 'danger', '1': 'warning', '2': '', '3': 'success' }[v] || 'info'
|
||||
}
|
||||
function formatRate(v) {
|
||||
const num = Number(v)
|
||||
return isNaN(num) ? '-' : num.toFixed(8).replace(/0+$/, '').replace(/\.$/, '')
|
||||
@@ -348,7 +317,7 @@ function submitForm() {
|
||||
}
|
||||
|
||||
function handleDelete(row) {
|
||||
proxy.$modal.confirm('是否确认删除汇率【' + row.fromCurrency + ' → ' + row.toCurrency + ' / ' + rateTypeText(row.rateType) + '】?').then(() => {
|
||||
proxy.$modal.confirm('是否确认删除汇率【' + row.fromCurrency + ' → ' + row.toCurrency + '(即期)】?').then(() => {
|
||||
return delExchangeRate(row.rateId)
|
||||
}).then(() => {
|
||||
getList()
|
||||
@@ -369,7 +338,6 @@ function handleConvert() {
|
||||
amount: calc.amount,
|
||||
fromCurrency: calc.fromCurrency,
|
||||
toCurrency: calc.toCurrency,
|
||||
rateType: calc.rateType,
|
||||
bizDate: calc.bizDate || undefined
|
||||
}).then(res => {
|
||||
calcResult.value = res.data
|
||||
@@ -384,7 +352,6 @@ function handleToBase() {
|
||||
convertToBase({
|
||||
amount: calc.amount,
|
||||
currency: calc.fromCurrency,
|
||||
rateType: calc.rateType,
|
||||
bizDate: calc.bizDate || undefined
|
||||
}).then(res => {
|
||||
calcResult.value = res.data
|
||||
|
||||
Reference in New Issue
Block a user