登记收款加银行账户,允许额度欠费。
This commit is contained in:
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package com.ruoyi.web.controller.ar;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.ruoyi.ar.domain.ArBankAccount;
|
||||||
|
import com.ruoyi.ar.mapper.ArBankAccountMapper;
|
||||||
|
import com.ruoyi.common.core.controller.BaseController;
|
||||||
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公司收款银行账户(下拉选项,供登记收款等场景选择)。
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ar/bank-account")
|
||||||
|
public class ArBankAccountController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ArBankAccountMapper arBankAccountMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用账户列表;可按币种过滤,默认账户优先。
|
||||||
|
*/
|
||||||
|
@GetMapping("/options")
|
||||||
|
public AjaxResult options(@RequestParam(value = "currency", required = false) String currency) {
|
||||||
|
List<ArBankAccount> list = arBankAccountMapper.selectEnabledList(currency);
|
||||||
|
return AjaxResult.success(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,16 @@
|
|||||||
package com.ruoyi.ar.mapper;
|
package com.ruoyi.ar.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import com.ruoyi.ar.domain.ArBankAccount;
|
import com.ruoyi.ar.domain.ArBankAccount;
|
||||||
|
|
||||||
public interface ArBankAccountMapper {
|
public interface ArBankAccountMapper {
|
||||||
ArBankAccount selectDefaultByCurrency(@Param("currency") String currency);
|
ArBankAccount selectDefaultByCurrency(@Param("currency") String currency);
|
||||||
|
|
||||||
|
/** 按主键查启用账户 */
|
||||||
|
ArBankAccount selectEnabledById(@Param("bankAccountId") Long bankAccountId);
|
||||||
|
|
||||||
|
/** 启用账户下拉(currency 为空时查全部),默认账户优先 */
|
||||||
|
List<ArBankAccount> selectEnabledList(@Param("currency") String currency);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -115,8 +115,8 @@ public class BmsCustomerCompany extends BaseEntity
|
|||||||
/** 注册详细地址 */
|
/** 注册详细地址 */
|
||||||
private String registeredAddressDetail;
|
private String registeredAddressDetail;
|
||||||
|
|
||||||
/** 营业执照 oss_id */
|
/** 营业执照图片URL(当前存服务器本地相对路径,后续可切换对象存储) */
|
||||||
private Long businessLicenseOssId;
|
private String businessLicenseUrl;
|
||||||
|
|
||||||
/** 其他附件 oss_id 逗号分隔 */
|
/** 其他附件 oss_id 逗号分隔 */
|
||||||
private String attachmentIds;
|
private String attachmentIds;
|
||||||
|
|||||||
+3
-4
@@ -51,10 +51,9 @@ public class CreditUsageCommand
|
|||||||
private String reason;
|
private String reason;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 占用时是否校验可用额度(授信总额-已用 >= 本次占用额)。
|
* 字段保留兼容历史调用,当前计费策略(2026-09-20 起)已不再硬拦截:
|
||||||
* true=余额/额度不足直接抛异常(计费开单等新业务场景默认值);
|
* 超额客户计费继续占用信用额度,允许可用额度为负,后续改由超额提醒机制处理。
|
||||||
* false=允许超出总额度占用(兼容历史账单确认口径)。
|
|
||||||
* 释放场景该参数无意义。
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
private Boolean checkAvailable = Boolean.TRUE;
|
private Boolean checkAvailable = Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ public interface ICustomerAccountApi
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 占用授信额度:used_credit += amount,写 OCCUPY 额度流水(关联来源单据)。
|
* 占用授信额度:used_credit += amount,写 OCCUPY 额度流水(关联来源单据)。
|
||||||
* 命令中 customerId 与 customerCode 二选一;checkAvailable=true 时可用额度不足抛 ServiceException;
|
* 命令中 customerId 与 customerCode 二选一;超额不拦截,允许可用额度(总额度-已占用)为负;
|
||||||
* CNY账户不存在自动初始化,外币账户不存在时静默跳过(返回null,兼容历史口径)。
|
* CNY账户不存在自动初始化,外币账户不存在时静默跳过(返回null,兼容历史口径)。
|
||||||
*
|
*
|
||||||
* @return 已落库的额度流水(含ID);账户不存在跳过场景返回null
|
* @return 已落库的额度流水(含ID);账户不存在跳过场景返回null
|
||||||
|
|||||||
+5
-20
@@ -303,23 +303,8 @@ public class CustomerAccountApiImpl implements ICustomerAccountApi
|
|||||||
}
|
}
|
||||||
BigDecimal amount = money(command.getAmount());
|
BigDecimal amount = money(command.getAmount());
|
||||||
BigDecimal beforeUsed = nz(account.getUsedCredit());
|
BigDecimal beforeUsed = nz(account.getUsedCredit());
|
||||||
BigDecimal totalAvailable = nz(account.getTotalCredit()).add(nz(account.getExtraCredit()))
|
// 计费策略(2026-09-20 调整):超额客户不拦截计费,继续占用信用额度,
|
||||||
.subtract(beforeUsed);
|
// 允许可用额度(总额度-已占用)为负;后续基于负额度做超额提醒,不做硬拦截。
|
||||||
if (Boolean.TRUE.equals(command.getCheckAvailable()))
|
|
||||||
{
|
|
||||||
// 已处于超额(欠费)状态:可用额度已为负,任何新增计费一律拦截
|
|
||||||
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);
|
BigDecimal afterUsed = beforeUsed.add(amount).setScale(MONEY_SCALE, RoundingMode.HALF_UP);
|
||||||
account.setUsedCredit(afterUsed);
|
account.setUsedCredit(afterUsed);
|
||||||
account.setUpdateBy(username);
|
account.setUpdateBy(username);
|
||||||
@@ -742,17 +727,17 @@ public class CustomerAccountApiImpl implements ICustomerAccountApi
|
|||||||
if (disabled && overdue)
|
if (disabled && overdue)
|
||||||
{
|
{
|
||||||
vo.setAccountStatus(CustomerAccountStatusVO.STATUS_DISABLED_AND_OVERDUE);
|
vo.setAccountStatus(CustomerAccountStatusVO.STATUS_DISABLED_AND_OVERDUE);
|
||||||
vo.setAccountStatusDesc("客户已停用且可用额度不足(欠费),不可新下单");
|
vo.setAccountStatusDesc("客户已停用且已超额(欠费),停用客户不可新计费");
|
||||||
}
|
}
|
||||||
else if (disabled)
|
else if (disabled)
|
||||||
{
|
{
|
||||||
vo.setAccountStatus(CustomerAccountStatusVO.STATUS_DISABLED);
|
vo.setAccountStatus(CustomerAccountStatusVO.STATUS_DISABLED);
|
||||||
vo.setAccountStatusDesc("客户已停用,不可新下单");
|
vo.setAccountStatusDesc("客户已停用,不可新计费");
|
||||||
}
|
}
|
||||||
else if (overdue)
|
else if (overdue)
|
||||||
{
|
{
|
||||||
vo.setAccountStatus(CustomerAccountStatusVO.STATUS_OVERDUE);
|
vo.setAccountStatus(CustomerAccountStatusVO.STATUS_OVERDUE);
|
||||||
vo.setAccountStatusDesc("客户可用额度不足(欠费),需先回款核销恢复额度");
|
vo.setAccountStatusDesc("客户已超额(欠费),可继续计费占用额度,请及时催收回款");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+12
@@ -84,6 +84,18 @@ public class CustomerReceipt extends BaseEntity
|
|||||||
/** 收款方式:BANK_TRANSFER/ALIPAY/WECHAT/CASH/OTHER */
|
/** 收款方式:BANK_TRANSFER/ALIPAY/WECHAT/CASH/OTHER */
|
||||||
private String payMethod;
|
private String payMethod;
|
||||||
|
|
||||||
|
/** 收款银行账户ID(ar_bank_account) */
|
||||||
|
private Long bankAccountId;
|
||||||
|
|
||||||
|
/** 收款账户户名(登记时快照) */
|
||||||
|
private String bankAccountName;
|
||||||
|
|
||||||
|
/** 收款银行账号(登记时快照) */
|
||||||
|
private String bankAccountNo;
|
||||||
|
|
||||||
|
/** 开户行名称(登记时快照) */
|
||||||
|
private String bankName;
|
||||||
|
|
||||||
/** 银行流水号/支付平台流水号 */
|
/** 银行流水号/支付平台流水号 */
|
||||||
private String bankTransactionNo;
|
private String bankTransactionNo;
|
||||||
|
|
||||||
|
|||||||
+25
@@ -15,6 +15,8 @@ import org.springframework.util.CollectionUtils;
|
|||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.ar.domain.ArBankAccount;
|
||||||
|
import com.ruoyi.ar.mapper.ArBankAccountMapper;
|
||||||
import com.ruoyi.customer.customerinfo.domain.BmsCustomer;
|
import com.ruoyi.customer.customerinfo.domain.BmsCustomer;
|
||||||
import com.ruoyi.customer.customerinfo.domain.BmsCustomerAttachment;
|
import com.ruoyi.customer.customerinfo.domain.BmsCustomerAttachment;
|
||||||
import com.ruoyi.customer.customerinfo.mapper.BmsCustomerMapper;
|
import com.ruoyi.customer.customerinfo.mapper.BmsCustomerMapper;
|
||||||
@@ -69,6 +71,10 @@ public class CustomerMoneyServiceImpl implements ICustomerMoneyService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ICreditQuotaService creditQuotaService;
|
private ICreditQuotaService creditQuotaService;
|
||||||
|
|
||||||
|
/** 公司收款银行账户(登记收款选择并快照) */
|
||||||
|
@Autowired
|
||||||
|
private ArBankAccountMapper arBankAccountMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public List<CustomerAccount> selectAccountList(Long customerId)
|
public List<CustomerAccount> selectAccountList(Long customerId)
|
||||||
@@ -136,6 +142,25 @@ public class CustomerMoneyServiceImpl implements ICustomerMoneyService
|
|||||||
{
|
{
|
||||||
receipt.setCurrency(receipt.getCurrency().trim().toUpperCase());
|
receipt.setCurrency(receipt.getCurrency().trim().toUpperCase());
|
||||||
}
|
}
|
||||||
|
// 收款银行账户:以库中启用账户为准回填快照(不信任前端传入的户名/账号/开户行文本),
|
||||||
|
// 账户后续停用或修改不影响历史单据展示。
|
||||||
|
if (receipt.getBankAccountId() != null)
|
||||||
|
{
|
||||||
|
ArBankAccount bankAccount = arBankAccountMapper.selectEnabledById(receipt.getBankAccountId());
|
||||||
|
if (bankAccount == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException("收款银行账户不存在或已停用,请重新选择");
|
||||||
|
}
|
||||||
|
receipt.setBankAccountName(bankAccount.getAccountName());
|
||||||
|
receipt.setBankAccountNo(bankAccount.getAccountNo());
|
||||||
|
receipt.setBankName(bankAccount.getBankName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
receipt.setBankAccountName(null);
|
||||||
|
receipt.setBankAccountNo(null);
|
||||||
|
receipt.setBankName(null);
|
||||||
|
}
|
||||||
// 汇率与本位币金额:CNY 固定 1:1;外币以收款日即期汇率表为基准,允许页面手工修改。
|
// 汇率与本位币金额:CNY 固定 1:1;外币以收款日即期汇率表为基准,允许页面手工修改。
|
||||||
// 汇率来源由后端权威判定(不信任前端标记):与汇率表一致=RATE_TABLE,不一致/表未配置=MANUAL。
|
// 汇率来源由后端权威判定(不信任前端标记):与汇率表一致=RATE_TABLE,不一致/表未配置=MANUAL。
|
||||||
BigDecimal rate = receipt.getExchangeRate();
|
BigDecimal rate = receipt.getExchangeRate();
|
||||||
|
|||||||
@@ -36,4 +36,34 @@
|
|||||||
and status = '0'
|
and status = '0'
|
||||||
order by is_default desc, bank_account_id limit 1
|
order by is_default desc, bank_account_id limit 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<sql id="enabledColumns">
|
||||||
|
select bank_account_id,
|
||||||
|
account_name,
|
||||||
|
account_no,
|
||||||
|
bank_name,
|
||||||
|
currency,
|
||||||
|
is_default,
|
||||||
|
status,
|
||||||
|
remark,
|
||||||
|
create_by,
|
||||||
|
create_time,
|
||||||
|
update_by,
|
||||||
|
update_time
|
||||||
|
from ar_bank_account
|
||||||
|
where status = '0'
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectEnabledById" resultMap="ArBankAccountResult">
|
||||||
|
<include refid="enabledColumns"/>
|
||||||
|
and bank_account_id = #{bankAccountId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectEnabledList" resultMap="ArBankAccountResult">
|
||||||
|
<include refid="enabledColumns"/>
|
||||||
|
<if test="currency != null and currency != ''">
|
||||||
|
and currency = #{currency}
|
||||||
|
</if>
|
||||||
|
order by is_default desc, currency asc, bank_account_id asc
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -363,7 +363,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="registeredCity" column="registered_city" />
|
<result property="registeredCity" column="registered_city" />
|
||||||
<result property="registeredDistrict" column="registered_district" />
|
<result property="registeredDistrict" column="registered_district" />
|
||||||
<result property="registeredAddressDetail" column="registered_address_detail" />
|
<result property="registeredAddressDetail" column="registered_address_detail" />
|
||||||
<result property="businessLicenseOssId" column="business_license_oss_id" />
|
<result property="businessLicenseUrl" column="business_license_url" />
|
||||||
<result property="attachmentIds" column="attachment_ids" />
|
<result property="attachmentIds" column="attachment_ids" />
|
||||||
<result property="remark" column="remark" />
|
<result property="remark" column="remark" />
|
||||||
<result property="createBy" column="create_by" />
|
<result property="createBy" column="create_by" />
|
||||||
@@ -374,7 +374,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectBmsCustomerCompanyVo">
|
<sql id="selectBmsCustomerCompanyVo">
|
||||||
select company_id, customer_id, company_name_full, english_name, credit_code, legal_person, legal_person_phone, legal_person_id_card, registered_capital, capital_currency, paid_in_capital, establish_date, business_term_start, business_term_end, business_term_permanent, registration_authority, registration_number, operating_status, business_scope, shareholders, employee_count, company_phone, company_fax, company_website, company_email, registered_province, registered_city, registered_district, registered_address_detail, business_license_oss_id, attachment_ids, remark, create_by, create_time, update_by, update_time, del_flag from bms_customer_company
|
select company_id, customer_id, company_name_full, english_name, credit_code, legal_person, legal_person_phone, legal_person_id_card, registered_capital, capital_currency, paid_in_capital, establish_date, business_term_start, business_term_end, business_term_permanent, registration_authority, registration_number, operating_status, business_scope, shareholders, employee_count, company_phone, company_fax, company_website, company_email, registered_province, registered_city, registered_district, registered_address_detail, business_license_url, attachment_ids, remark, create_by, create_time, update_by, update_time, del_flag from bms_customer_company
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="selectBmsCustomerCompanyList" parameterType="com.ruoyi.customer.customerinfo.domain.BmsCustomerCompany" resultMap="BmsCustomerCompanyResult">
|
<select id="selectBmsCustomerCompanyList" parameterType="com.ruoyi.customer.customerinfo.domain.BmsCustomerCompany" resultMap="BmsCustomerCompanyResult">
|
||||||
@@ -426,7 +426,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="registeredCity != null">registered_city,</if>
|
<if test="registeredCity != null">registered_city,</if>
|
||||||
<if test="registeredDistrict != null">registered_district,</if>
|
<if test="registeredDistrict != null">registered_district,</if>
|
||||||
<if test="registeredAddressDetail != null">registered_address_detail,</if>
|
<if test="registeredAddressDetail != null">registered_address_detail,</if>
|
||||||
<if test="businessLicenseOssId != null">business_license_oss_id,</if>
|
<if test="businessLicenseUrl != null">business_license_url,</if>
|
||||||
<if test="attachmentIds != null">attachment_ids,</if>
|
<if test="attachmentIds != null">attachment_ids,</if>
|
||||||
<if test="remark != null">remark,</if>
|
<if test="remark != null">remark,</if>
|
||||||
<if test="createBy != null">create_by,</if>
|
<if test="createBy != null">create_by,</if>
|
||||||
@@ -462,7 +462,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="registeredCity != null">#{registeredCity},</if>
|
<if test="registeredCity != null">#{registeredCity},</if>
|
||||||
<if test="registeredDistrict != null">#{registeredDistrict},</if>
|
<if test="registeredDistrict != null">#{registeredDistrict},</if>
|
||||||
<if test="registeredAddressDetail != null">#{registeredAddressDetail},</if>
|
<if test="registeredAddressDetail != null">#{registeredAddressDetail},</if>
|
||||||
<if test="businessLicenseOssId != null">#{businessLicenseOssId},</if>
|
<if test="businessLicenseUrl != null">#{businessLicenseUrl},</if>
|
||||||
<if test="attachmentIds != null">#{attachmentIds},</if>
|
<if test="attachmentIds != null">#{attachmentIds},</if>
|
||||||
<if test="remark != null">#{remark},</if>
|
<if test="remark != null">#{remark},</if>
|
||||||
<if test="createBy != null">#{createBy},</if>
|
<if test="createBy != null">#{createBy},</if>
|
||||||
@@ -502,7 +502,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="registeredCity != null">registered_city = #{registeredCity},</if>
|
<if test="registeredCity != null">registered_city = #{registeredCity},</if>
|
||||||
<if test="registeredDistrict != null">registered_district = #{registeredDistrict},</if>
|
<if test="registeredDistrict != null">registered_district = #{registeredDistrict},</if>
|
||||||
<if test="registeredAddressDetail != null">registered_address_detail = #{registeredAddressDetail},</if>
|
<if test="registeredAddressDetail != null">registered_address_detail = #{registeredAddressDetail},</if>
|
||||||
<if test="businessLicenseOssId != null">business_license_oss_id = #{businessLicenseOssId},</if>
|
<if test="businessLicenseUrl != null">business_license_url = #{businessLicenseUrl},</if>
|
||||||
<if test="attachmentIds != null">attachment_ids = #{attachmentIds},</if>
|
<if test="attachmentIds != null">attachment_ids = #{attachmentIds},</if>
|
||||||
<if test="remark != null">remark = #{remark},</if>
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
<if test="updateBy != null">update_by = #{updateBy},</if>
|
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||||
|
|||||||
@@ -247,6 +247,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="rateSourceDesc" column="rate_source_desc" />
|
<result property="rateSourceDesc" column="rate_source_desc" />
|
||||||
<result property="baseAmount" column="base_amount" />
|
<result property="baseAmount" column="base_amount" />
|
||||||
<result property="payMethod" column="pay_method" />
|
<result property="payMethod" column="pay_method" />
|
||||||
|
<result property="bankAccountId" column="bank_account_id" />
|
||||||
|
<result property="bankAccountName" column="bank_account_name" />
|
||||||
|
<result property="bankAccountNo" column="bank_account_no" />
|
||||||
|
<result property="bankName" column="bank_name" />
|
||||||
<result property="bankTransactionNo" column="bank_transaction_no" />
|
<result property="bankTransactionNo" column="bank_transaction_no" />
|
||||||
<result property="receivedAt" column="received_at" />
|
<result property="receivedAt" column="received_at" />
|
||||||
<result property="status" column="status" />
|
<result property="status" column="status" />
|
||||||
@@ -266,7 +270,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<sql id="selectCustomerReceiptVo">
|
<sql id="selectCustomerReceiptVo">
|
||||||
select r.id, r.receipt_no, r.customer_id, r.account_id, r.receipt_type, r.amount, r.allocated_amount,
|
select r.id, r.receipt_no, r.customer_id, r.account_id, r.receipt_type, r.amount, r.allocated_amount,
|
||||||
r.unallocated_amount, r.currency, r.exchange_rate, r.rate_source, r.rate_source_desc,
|
r.unallocated_amount, r.currency, r.exchange_rate, r.rate_source, r.rate_source_desc,
|
||||||
r.base_amount, r.pay_method, r.bank_transaction_no,
|
r.base_amount, r.pay_method, r.bank_account_id, r.bank_account_name,
|
||||||
|
r.bank_account_no, r.bank_name, r.bank_transaction_no,
|
||||||
r.received_at, r.status,
|
r.received_at, r.status,
|
||||||
r.confirmed_at, r.confirmed_by, r.invoice_status, r.version, r.create_by, r.create_time,
|
r.confirmed_at, r.confirmed_by, r.invoice_status, r.version, r.create_by, r.create_time,
|
||||||
r.update_by, r.update_time, r.remark, r.del_flag,
|
r.update_by, r.update_time, r.remark, r.del_flag,
|
||||||
@@ -322,6 +327,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="rateSourceDesc != null">rate_source_desc,</if>
|
<if test="rateSourceDesc != null">rate_source_desc,</if>
|
||||||
<if test="baseAmount != null">base_amount,</if>
|
<if test="baseAmount != null">base_amount,</if>
|
||||||
<if test="payMethod != null">pay_method,</if>
|
<if test="payMethod != null">pay_method,</if>
|
||||||
|
<if test="bankAccountId != null">bank_account_id,</if>
|
||||||
|
<if test="bankAccountName != null">bank_account_name,</if>
|
||||||
|
<if test="bankAccountNo != null">bank_account_no,</if>
|
||||||
|
<if test="bankName != null">bank_name,</if>
|
||||||
<if test="bankTransactionNo != null">bank_transaction_no,</if>
|
<if test="bankTransactionNo != null">bank_transaction_no,</if>
|
||||||
<if test="receivedAt != null">received_at,</if>
|
<if test="receivedAt != null">received_at,</if>
|
||||||
<if test="status != null">status,</if>
|
<if test="status != null">status,</if>
|
||||||
@@ -347,6 +356,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="rateSourceDesc != null">#{rateSourceDesc},</if>
|
<if test="rateSourceDesc != null">#{rateSourceDesc},</if>
|
||||||
<if test="baseAmount != null">#{baseAmount},</if>
|
<if test="baseAmount != null">#{baseAmount},</if>
|
||||||
<if test="payMethod != null">#{payMethod},</if>
|
<if test="payMethod != null">#{payMethod},</if>
|
||||||
|
<if test="bankAccountId != null">#{bankAccountId},</if>
|
||||||
|
<if test="bankAccountName != null">#{bankAccountName},</if>
|
||||||
|
<if test="bankAccountNo != null">#{bankAccountNo},</if>
|
||||||
|
<if test="bankName != null">#{bankName},</if>
|
||||||
<if test="bankTransactionNo != null">#{bankTransactionNo},</if>
|
<if test="bankTransactionNo != null">#{bankTransactionNo},</if>
|
||||||
<if test="receivedAt != null">#{receivedAt},</if>
|
<if test="receivedAt != null">#{receivedAt},</if>
|
||||||
<if test="status != null">#{status},</if>
|
<if test="status != null">#{status},</if>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-- =============================================================
|
||||||
|
-- 1) 客户公司主体营业执照:bigint oss_id 改为 URL 字符串
|
||||||
|
-- 先按服务器本地存储(/common/upload 返回相对路径),后续可平滑切换对象存储
|
||||||
|
-- 2) 客户收款登记:增加收款银行账户(ar_bank_account 关联 + 冗余快照,防账户后续变更)
|
||||||
|
-- 2026-09-20
|
||||||
|
-- =============================================================
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
-- ---------- bms_customer_company ----------
|
||||||
|
ALTER TABLE `bms_customer_company`
|
||||||
|
CHANGE COLUMN `business_license_oss_id` `business_license_url` VARCHAR(500)
|
||||||
|
DEFAULT NULL COMMENT '营业执照图片URL(服务器本地存储,后续可切换对象存储)';
|
||||||
|
|
||||||
|
-- ---------- customer_receipt ----------
|
||||||
|
ALTER TABLE `customer_receipt`
|
||||||
|
ADD COLUMN `bank_account_id` BIGINT(20) DEFAULT NULL COMMENT '收款银行账户ID(ar_bank_account)' AFTER `pay_method`,
|
||||||
|
ADD COLUMN `bank_account_name` VARCHAR(100) DEFAULT NULL COMMENT '收款账户户名(登记时快照)' AFTER `bank_account_id`,
|
||||||
|
ADD COLUMN `bank_account_no` VARCHAR(128) DEFAULT NULL COMMENT '收款银行账号(登记时快照)' AFTER `bank_account_name`,
|
||||||
|
ADD COLUMN `bank_name` VARCHAR(100) DEFAULT NULL COMMENT '开户行名称(登记时快照)' AFTER `bank_account_no`;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 公司收款银行账户(登记收款下拉选择)
|
||||||
|
export function listBankAccountOptions(currency) {
|
||||||
|
return request({
|
||||||
|
url: '/ar/bank-account/options',
|
||||||
|
method: 'get',
|
||||||
|
params: currency ? { currency } : {}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -506,8 +506,8 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="营业执照" prop="businessLicenseOssId">
|
<el-form-item label="营业执照" prop="businessLicenseUrl">
|
||||||
<image-upload v-model="companyForm.businessLicenseOssId" :limit="1" :size="5" />
|
<image-upload v-model="companyForm.businessLicenseUrl" :limit="1" :size="5" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
@@ -1029,7 +1029,7 @@ function resetCompanyForm() {
|
|||||||
registeredCity: '',
|
registeredCity: '',
|
||||||
registeredDistrict: '',
|
registeredDistrict: '',
|
||||||
registeredAddressDetail: '',
|
registeredAddressDetail: '',
|
||||||
businessLicenseOssId: null,
|
businessLicenseUrl: '',
|
||||||
attachmentIds: '',
|
attachmentIds: '',
|
||||||
remark: ''
|
remark: ''
|
||||||
}
|
}
|
||||||
|
|||||||
+67
-4
@@ -73,7 +73,7 @@
|
|||||||
<div class="balance-label">可用额度</div>
|
<div class="balance-label">可用额度</div>
|
||||||
<div class="balance-value" :class="availableOverLimit ? 'danger' : 'success'">{{ availableCredit }}</div>
|
<div class="balance-value" :class="availableOverLimit ? 'danger' : 'success'">{{ availableCredit }}</div>
|
||||||
<div class="balance-sub" v-if="availableOverLimit" style="color: var(--el-color-danger);">
|
<div class="balance-sub" v-if="availableOverLimit" style="color: var(--el-color-danger);">
|
||||||
已超额,回款核销后恢复
|
已超额,可继续计费,请及时催收回款
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -152,6 +152,14 @@
|
|||||||
<el-table-column label="收款方式" align="center" prop="payMethod" width="110">
|
<el-table-column label="收款方式" align="center" prop="payMethod" width="110">
|
||||||
<template #default="scope">{{ formatOption(payMethodOptions, scope.row.payMethod) }}</template>
|
<template #default="scope">{{ formatOption(payMethodOptions, scope.row.payMethod) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="收款银行账户" align="center" width="220" show-overflow-tooltip>
|
||||||
|
<template #default="scope">
|
||||||
|
<span v-if="scope.row.bankAccountId">
|
||||||
|
{{ scope.row.bankName || '-' }} {{ scope.row.bankAccountNo || '' }}
|
||||||
|
</span>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="银行/平台流水号" align="center" prop="bankTransactionNo" width="170" show-overflow-tooltip />
|
<el-table-column label="银行/平台流水号" align="center" prop="bankTransactionNo" width="170" show-overflow-tooltip />
|
||||||
<el-table-column label="状态" align="center" prop="status" width="90">
|
<el-table-column label="状态" align="center" prop="status" width="90">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@@ -637,6 +645,26 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="收款银行账户" prop="bankAccountId">
|
||||||
|
<el-select
|
||||||
|
v-model="receiptDialog.form.bankAccountId"
|
||||||
|
placeholder="请选择收款银行账户"
|
||||||
|
style="width: 100%;"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
:loading="bankAccountLoading"
|
||||||
|
@change="handleBankAccountChange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="acc in bankAccountOptions"
|
||||||
|
:key="acc.bankAccountId"
|
||||||
|
:label="`${acc.bankName} ${acc.accountNo}(${acc.accountName})`"
|
||||||
|
:value="acc.bankAccountId"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="流水号" prop="bankTransactionNo">
|
<el-form-item label="流水号" prop="bankTransactionNo">
|
||||||
<el-input v-model="receiptDialog.form.bankTransactionNo" placeholder="银行/支付平台流水号" />
|
<el-input v-model="receiptDialog.form.bankTransactionNo" placeholder="银行/支付平台流水号" />
|
||||||
@@ -715,6 +743,13 @@
|
|||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="待核销金额">CNY {{ formatMoney(viewDialog.data.unallocatedAmount) }}</el-descriptions-item>
|
<el-descriptions-item label="待核销金额">CNY {{ formatMoney(viewDialog.data.unallocatedAmount) }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="收款方式">{{ formatOption(payMethodOptions, viewDialog.data.payMethod) }}</el-descriptions-item>
|
<el-descriptions-item label="收款方式">{{ formatOption(payMethodOptions, viewDialog.data.payMethod) }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="收款银行账户">
|
||||||
|
<span v-if="viewDialog.data.bankAccountId">
|
||||||
|
{{ viewDialog.data.bankName || '-' }} {{ viewDialog.data.bankAccountNo || '' }}
|
||||||
|
<span v-if="viewDialog.data.bankAccountName">({{ viewDialog.data.bankAccountName }})</span>
|
||||||
|
</span>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="银行流水号">{{ viewDialog.data.bankTransactionNo || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="银行流水号">{{ viewDialog.data.bankTransactionNo || '-' }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="确认时间">{{ formatDateTime(viewDialog.data.confirmedAt) }}</el-descriptions-item>
|
<el-descriptions-item label="确认时间">{{ formatDateTime(viewDialog.data.confirmedAt) }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="登记人">{{ viewDialog.data.createBy || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="登记人">{{ viewDialog.data.createBy || '-' }}</el-descriptions-item>
|
||||||
@@ -822,7 +857,7 @@
|
|||||||
<div class="rate-tip">
|
<div class="rate-tip">
|
||||||
{{ creditDialog.form.creditType === 'TEMP'
|
{{ creditDialog.form.creditType === 'TEMP'
|
||||||
? '失效日当天仍有效,次日访问账户时自动清零并记到期流水'
|
? '失效日当天仍有效,次日访问账户时自动清零并记到期流水'
|
||||||
: '信用额度失效日期必填;失效日当天仍有效,次日自动清零,已用额度未回款时将形成欠费拦截' }}
|
: '信用额度失效日期必填;失效日当天仍有效,次日自动清零,已用额度未回款时将形成超额欠费(可继续计费,请及时催收)' }}
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -970,6 +1005,7 @@ import { getCustomer } from "@/api/customersuppliermanagement/customerinfo/custo
|
|||||||
import { listAccount, listReceipt, getReceipt, addReceipt, confirmReceipt, cancelReceipt, listFlow, listCreditFlow, applyCreditAdjust, listCreditApply, approveCreditApply, rejectCreditApply, cancelCreditApply, listMyCreditPools } from "@/api/customersuppliermanagement/customermoney/customermoney.js"
|
import { listAccount, listReceipt, getReceipt, addReceipt, confirmReceipt, cancelReceipt, listFlow, listCreditFlow, applyCreditAdjust, listCreditApply, approveCreditApply, rejectCreditApply, cancelCreditApply, listMyCreditPools } from "@/api/customersuppliermanagement/customermoney/customermoney.js"
|
||||||
import { listUnsettledBill, listBalanceWriteoff, balanceWriteoff, cancelBalanceWriteoff } from "@/api/customersuppliermanagement/customermoney/customerbill.js"
|
import { listUnsettledBill, listBalanceWriteoff, balanceWriteoff, cancelBalanceWriteoff } from "@/api/customersuppliermanagement/customermoney/customerbill.js"
|
||||||
import { convertToBase } from "@/api/data/exchangeRate"
|
import { convertToBase } from "@/api/data/exchangeRate"
|
||||||
|
import { listBankAccountOptions } from "@/api/ar/bankAccount"
|
||||||
import { getToken } from "@/utils/auth"
|
import { getToken } from "@/utils/auth"
|
||||||
import { AR_BALANCE_WRITEOFF_STATUS, AR_BALANCE_WRITEOFF_STATUS_OPTIONS, AR_BALANCE_WRITEOFF_STATUS_TYPES, AR_BILL_STATUS_OPTIONS, AR_BILL_STATUS_TYPES, arEnumLabel } from '@/constants/ar/enums'
|
import { AR_BALANCE_WRITEOFF_STATUS, AR_BALANCE_WRITEOFF_STATUS_OPTIONS, AR_BALANCE_WRITEOFF_STATUS_TYPES, AR_BILL_STATUS_OPTIONS, AR_BILL_STATUS_TYPES, arEnumLabel } from '@/constants/ar/enums'
|
||||||
|
|
||||||
@@ -1107,7 +1143,7 @@ const availableCreditValue = computed(() => {
|
|||||||
})
|
})
|
||||||
/** 可用额度展示文本 */
|
/** 可用额度展示文本 */
|
||||||
const availableCredit = computed(() => formatMoney(availableCreditValue.value))
|
const availableCredit = computed(() => formatMoney(availableCreditValue.value))
|
||||||
/** 是否处于超额状态(已用额度超过授信总额,新计费开单将被拦截,需先回款核销) */
|
/** 是否处于超额状态(已用额度超过授信总额,可用为负;不拦截计费,后续做超额提醒) */
|
||||||
const availableOverLimit = computed(() => availableCreditValue.value < 0)
|
const availableOverLimit = computed(() => availableCreditValue.value < 0)
|
||||||
|
|
||||||
/** 临时额度有效期文案 */
|
/** 临时额度有效期文案 */
|
||||||
@@ -1360,6 +1396,30 @@ const receiptDialog = reactive({
|
|||||||
visible: false,
|
visible: false,
|
||||||
form: {}
|
form: {}
|
||||||
})
|
})
|
||||||
|
/** 收款银行账户下拉(按币种过滤,默认账户优先) */
|
||||||
|
const bankAccountOptions = ref([])
|
||||||
|
const bankAccountLoading = ref(false)
|
||||||
|
|
||||||
|
function loadBankAccountOptions(currency, { autoPick = true } = {}) {
|
||||||
|
bankAccountLoading.value = true
|
||||||
|
listBankAccountOptions(currency || 'CNY').then(res => {
|
||||||
|
bankAccountOptions.value = res.data || []
|
||||||
|
if (!autoPick) return
|
||||||
|
// 当前已选账户在新列表中仍存在则保留;否则默认选中默认账户(无默认取第一个)
|
||||||
|
const cur = receiptDialog.form.bankAccountId
|
||||||
|
const stillExists = cur && bankAccountOptions.value.some(a => a.bankAccountId === cur)
|
||||||
|
if (!stillExists) {
|
||||||
|
const def = bankAccountOptions.value.find(a => a.isDefault === '1') || bankAccountOptions.value[0]
|
||||||
|
receiptDialog.form.bankAccountId = def ? def.bankAccountId : null
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
bankAccountLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBankAccountChange() {
|
||||||
|
// 选项清空时无需额外处理;快照(户名/账号/开户行)由后端登记时回填
|
||||||
|
}
|
||||||
const receiptRules = {
|
const receiptRules = {
|
||||||
receivedAt: [{ required: true, message: '收款日期不能为空', trigger: 'change' }],
|
receivedAt: [{ required: true, message: '收款日期不能为空', trigger: 'change' }],
|
||||||
amount: [{ required: true, message: '收款金额不能为空', trigger: 'blur' }],
|
amount: [{ required: true, message: '收款金额不能为空', trigger: 'blur' }],
|
||||||
@@ -1378,6 +1438,7 @@ function resetReceiptForm() {
|
|||||||
currency: 'CNY',
|
currency: 'CNY',
|
||||||
exchangeRate: 1,
|
exchangeRate: 1,
|
||||||
payMethod: 'BANK_TRANSFER',
|
payMethod: 'BANK_TRANSFER',
|
||||||
|
bankAccountId: null,
|
||||||
bankTransactionNo: '',
|
bankTransactionNo: '',
|
||||||
remark: '',
|
remark: '',
|
||||||
attachmentList: []
|
attachmentList: []
|
||||||
@@ -1387,6 +1448,7 @@ function resetReceiptForm() {
|
|||||||
|
|
||||||
function handleAddReceipt() {
|
function handleAddReceipt() {
|
||||||
resetReceiptForm()
|
resetReceiptForm()
|
||||||
|
loadBankAccountOptions(receiptDialog.form.currency)
|
||||||
receiptDialog.visible = true
|
receiptDialog.visible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1422,11 +1484,12 @@ function fetchDefaultRate() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 切换币种:重置手工标记并重新取默认汇率 */
|
/** 切换币种:重置手工标记并重新取默认汇率、刷新收款银行账户下拉 */
|
||||||
function handleCurrencyChange() {
|
function handleCurrencyChange() {
|
||||||
rateEdited.value = false
|
rateEdited.value = false
|
||||||
rateSourceInfo.value = { source: '', ratePath: '' }
|
rateSourceInfo.value = { source: '', ratePath: '' }
|
||||||
fetchDefaultRate()
|
fetchDefaultRate()
|
||||||
|
loadBankAccountOptions(receiptDialog.form.currency)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 手工修改汇率 */
|
/** 手工修改汇率 */
|
||||||
|
|||||||
Reference in New Issue
Block a user