add 汇付开户支持一次提交同时创建会员与结算账户

个人开户成功后自动创建结算账户;企业开户上送银行字段,审核通过后由汇付自动创建结算账户。
This commit is contained in:
jsowell
2026-08-13 09:50:45 +08:00
parent dddee6668f
commit c4bfb67d11
4 changed files with 103 additions and 14 deletions

View File

@@ -231,3 +231,18 @@
- 保留,作为 A / B 决策历史
- 本文档
- 用于记录当前已落地的“新页面重做”方向与实现边界
## 一站式开户(后续优化)
首次创建时,`accountUserInfo.vue` 开户弹窗改为同一窗口同时采集:
- 会员资料(个人 / 企业)
- 结算账户资料
提交行为:
- 个人用户:后端 `createAdapayMember` 先创建会员,再自动创建结算账户
- 企业用户:后端 `createCorpMember` 在企业开户请求中上送银行字段,审核通过后由汇付自动创建结算账户
仍保留独立的“创建结算账户”入口,用于历史“已开户无结算账户”状态补建。

View File

@@ -26,4 +26,18 @@ public class CreateCorpMemberDTO {
private String telphone;
private String email;
private List<String> imgList;
/**
* 首次开户时一并提交的结算账户信息。
* 企业用户审核通过后,汇付会按这些银行字段自动创建结算账户。
*/
private String bankAcctType;
private String cardId;
private String cardNo;
private String cardName;
private String bankCode;
private String bankName;
private String telNo;
private String certId;
private String certType;
}

View File

@@ -13,4 +13,19 @@ public class CreatePersonalMemberDTO {
private String email;
private String gender;
private String nickname;
/**
* 首次开户时一并提交的结算账户信息;有值时创建会员成功后自动创建结算账户。
*/
private String bankAcctType;
private String cardId;
private String cardNo;
private String cardName;
private String certId;
private String certType;
private String telNo;
private String bankCode;
private String bankName;
private String provCode;
private String areaCode;
}

View File

@@ -272,7 +272,8 @@ public class AdapayService {
}
/**
* 创建个人用户
* 创建个人用户
* 若同时提交结算账户字段,则在会员创建成功后自动创建结算账户,实现一次填写完成开户。
*/
public void createAdapayMember(CreatePersonalMemberDTO dto) throws BaseAdaPayException, BusinessException {
assertActionAllowed(dto.getMerchantId(), AdapayOpenActionEnum.CREATE_PERSONAL_MEMBER);
@@ -285,10 +286,37 @@ public class AdapayService {
.wechatAppId(pileMerchantInfoService.queryAppIdByMerchantId(dto.getMerchantId()))
.build();
createMember(request);
if (hasSettleAccountPayload(dto.getBankAcctType(), dto.getCardId(), dto.getCardNo(), dto.getCardName())) {
try {
CreateSettleAccountDTO settleRequest = CreateSettleAccountDTO.builder()
.merchantId(dto.getMerchantId())
.bankAcctType(dto.getBankAcctType())
.cardId(dto.getCardId())
.cardNo(dto.getCardNo())
.cardName(dto.getCardName())
.certId(dto.getCertId())
.certType(dto.getCertType())
.telNo(dto.getTelNo())
.bankCode(dto.getBankCode())
.bankName(dto.getBankName())
.provCode(dto.getProvCode())
.areaCode(dto.getAreaCode())
.build();
createSettleAccount(settleRequest);
} catch (BusinessException e) {
throw new BusinessException(StringUtils.isNotBlank(e.getCode()) ? e.getCode() : "",
"个人用户已创建,但结算账户创建失败:" + e.getMessage() + "。请在结算账户区域重试创建。");
} catch (BaseAdaPayException e) {
throw new BusinessException("",
"个人用户已创建,但结算账户创建失败:" + e.getMessage() + "。请在结算账户区域重试创建。");
}
}
}
/**
* 创建企业用户
* 创建企业用户
* 若同时提交银行账户字段,审核通过后汇付会自动创建结算账户,实现一次填写完成开户。
*/
public void createCorpMember(CreateCorpMemberDTO dto) throws BaseAdaPayException, BusinessException {
assertActionAllowed(dto.getMerchantId(), AdapayOpenActionEnum.CREATE_CORP_MEMBER);
@@ -310,6 +338,15 @@ public class AdapayService {
.telphone(dto.getTelphone())
.email(dto.getEmail())
.imgList(dto.getImgList())
.bankAcctType(dto.getBankAcctType())
.cardId(dto.getCardId())
.cardNo(dto.getCardNo())
.cardName(dto.getCardName())
.bankCode(dto.getBankCode())
.bankName(dto.getBankName())
.telNo(dto.getTelNo())
.certId(dto.getCertId())
.certType(dto.getCertType())
.build();
createCorpMember(request);
}
@@ -904,6 +941,18 @@ public class AdapayService {
memberParams.put("telphone", dto.getTelphone());
memberParams.put("email", dto.getEmail());
memberParams.put("notify_url", ADAPAY_CALLBACK_URL);
// 首次开户若一并提交银行字段,审核通过后由汇付自动创建结算账户
String autoCardNo = StringUtils.isNotBlank(dto.getCardNo()) ? dto.getCardNo() : dto.getCardId();
if (hasSettleAccountPayload(dto.getBankAcctType(), dto.getCardId(), dto.getCardNo(), dto.getCardName())
&& StringUtils.isNotBlank(dto.getBankCode())
&& StringUtils.isNotBlank(autoCardNo)) {
memberParams.put("bank_code", dto.getBankCode());
memberParams.put("bank_acct_type", dto.getBankAcctType());
memberParams.put("card_no", autoCardNo);
memberParams.put("card_name", dto.getCardName());
}
Map<String, Object> member;
try {
File file = ZipUtil.createZipFileFromImages(dto.getImgList());
@@ -926,18 +975,6 @@ public class AdapayService {
markCorpMemberCreateFailed(adapayMemberAccount, error_msg);
throw new BusinessException("", error_msg);
}
// 取消自动创建结算账户,手动创建结算账户
// Map<String, Object> settleCount = createSettleAccountRequest(dto, adapayMemberId, dto.getWechatAppId());
//
// if (settleCount == null || StringUtils.equals((String) settleCount.get("status"), "failed")) {
// String errorMsg = settleCount == null ? "创建汇付结算账户失败" : (String) settleCount.get("error_msg");
// throw new BusinessException("00500001", errorMsg);
// }
// String settleAccountId = (String) settleCount.get("id");
// // 更新数据库
// adapayMemberAccount.setSettleAccountId(settleAccountId);
// adapayMemberAccountService.updateAdapayMemberAccount(adapayMemberAccount);
}
/**
@@ -2085,6 +2122,7 @@ public class AdapayService {
switch (status) {
case CORP_AUDITING:
tips.add("企业开户已提交,请耐心等待汇付审核结果,可点击刷新查看最新状态");
tips.add("若首次开户已填写结算账户信息,审核通过后汇付将自动创建结算账户");
break;
case CORP_FAILED:
if (StringUtils.isNotBlank(auditDesc)) {
@@ -2133,6 +2171,13 @@ public class AdapayService {
return StringUtils.startsWith(adapayMemberId, Constants.ADAPAY_CORP_MEMBER_PREFIX);
}
private boolean hasSettleAccountPayload(String bankAcctType, String cardId, String cardNo, String cardName) {
return StringUtils.isNotBlank(bankAcctType)
&& StringUtils.isNotBlank(cardName)
&& (StringUtils.isNotBlank(cardId) || StringUtils.isNotBlank(cardNo));
}
private SettleAccountDTO buildSettleAccountDTO(CreateSettleAccountDTO dto) {
SettleAccountDTO request = SettleAccountDTO.builder()
.merchantId(dto.getMerchantId())