package com.jsowell.adapay.service; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.huifu.adapay.core.exception.BaseAdaPayException; import com.huifu.adapay.model.*; import com.jsowell.adapay.dto.SettleAccountDTO; import com.jsowell.adapay.dto.UpdateAccountConfigDTO; import com.jsowell.adapay.dto.WithdrawDTO; import com.jsowell.adapay.response.QueryCorpMemberResponse; import com.jsowell.adapay.response.QueryMemberResponse; import com.jsowell.adapay.vo.AdapayAccountBalanceVO; import com.jsowell.adapay.vo.AdapayCorpMemberVO; import com.jsowell.adapay.vo.AdapayMemberInfoVO; import com.jsowell.adapay.vo.AdapaySettleAccountVO; import com.jsowell.common.constant.Constants; import com.jsowell.common.enums.DelFlagEnum; import com.jsowell.common.enums.ykc.ReturnCodeEnum; import com.jsowell.common.exception.BusinessException; import com.jsowell.common.util.AdapayUtil; import com.jsowell.common.util.StringUtils; import com.jsowell.common.util.ZipUtil; import com.jsowell.common.util.id.IdUtils; import com.jsowell.pile.domain.AdapayMemberAccount; import com.jsowell.pile.domain.ClearingWithdrawInfo; import com.jsowell.pile.service.ClearingWithdrawInfoService; import com.jsowell.pile.service.IAdapayMemberAccountService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.io.File; import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Map; @Slf4j @Service public class AdapayMemberService { @Value("${adapay.appId}") private String ADAPAY_APP_ID; // private final String CALLBACK_URL = "https://api.jsowellcloud.com/uniapp/pay/callbackAdapay"; @Value("${adapay.callback}") private String ADAPAY_CALLBACK_URL; @Autowired private IAdapayMemberAccountService adapayMemberAccountService; @Autowired private ClearingWithdrawInfoService clearingWithdrawInfoService; public void createSettleAccount(SettleAccountDTO dto) throws BaseAdaPayException, BusinessException { String bankAcctType = dto.getBankAcctType(); if (StringUtils.equals(bankAcctType, Constants.ONE)) { createCorpMember(dto); } else if (StringUtils.equals(bankAcctType, Constants.TWO)) { createMember(dto); } } /** * 创建汇付会员 * * @param dto * @throws Exception */ @Transactional(readOnly = false, propagation = Propagation.REQUIRED) public void createMember(SettleAccountDTO dto) throws BaseAdaPayException, BusinessException { AdapayMemberAccount adapayMemberAccount = adapayMemberAccountService.selectByMerchantId(dto.getMerchantId()); if (adapayMemberAccount != null) { log.error("通过merchantId:{}, 没有查询到结算账户配置", dto.getMerchantId()); return; } log.info("=======execute CreateMember begin======="); Map memberParams = Maps.newHashMap(); String adapayMemberId = Constants.ADAPAY_MEMBER_PREFIX + IdUtils.getMemberId(); memberParams.put("member_id", adapayMemberId); memberParams.put("app_id", ADAPAY_APP_ID); memberParams.put("location", dto.getLocation()); memberParams.put("email", dto.getEmail()); memberParams.put("gender", dto.getGender()); memberParams.put("nickname", dto.getNickname()); log.info("创建用户,请求参数:" + JSON.toJSONString(memberParams)); Map member = Member.create(memberParams); log.info("创建用户,返回参数:" + JSON.toJSONString(member)); log.info("=======execute CreateMember end======="); if (member == null || StringUtils.equals((String) member.get("status"), "failed")) { String errorMsg = member == null ? "创建汇付用户失败" : (String) member.get("error_msg"); throw new BusinessException("00500001", errorMsg); } // 创建结算账户 Map accountInfo = Maps.newHashMap(); // 银行卡号 accountInfo.put("card_id", dto.getCardId()); // 银行卡对应的户名 accountInfo.put("card_name", dto.getCardName()); // 证件号,银行账户类型为对私时,必填 if (StringUtils.isNotBlank(dto.getCertId())) { accountInfo.put("cert_id", dto.getCertId()); } // 证件类型,仅支持:00-身份证,银行账户类型为对私时,必填 accountInfo.put("cert_type", "00"); // 手机号 accountInfo.put("tel_no", dto.getTelNo()); // 银行编码,详见附录 银行代码,银行账户类型对公时,必填 if (StringUtils.isNotBlank(dto.getBankCode())) { accountInfo.put("bank_code", dto.getBankCode()); } // 银行账户类型:1-对公;2-对私 accountInfo.put("bank_acct_type", dto.getBankAcctType()); // 银行账户开户银行所在省份编码 (省市编码),银行账户类型为对公时,必填 if (StringUtils.isNotBlank(dto.getProvCode())) { accountInfo.put("prov_code", dto.getProvCode()); } // 银行账户开户银行所在地区编码(省市编码),银行账户类型为对公时,必填 if (StringUtils.isNotBlank(dto.getAreaCode())) { accountInfo.put("area_code", dto.getAreaCode()); } Map settleCountParams = Maps.newHashMap(); settleCountParams.put("member_id", adapayMemberId); settleCountParams.put("app_id", ADAPAY_APP_ID); // channel String Y 目前仅支持:bank_account(银行卡) settleCountParams.put("channel", "bank_account"); settleCountParams.put("account_info", accountInfo); log.info("创建汇付结算账户param:{}", settleCountParams); Map settleCount = SettleAccount.create(settleCountParams); log.info("创建汇付结算账户result:{}", settleCount); 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 = new AdapayMemberAccount(); adapayMemberAccount.setMerchantId(dto.getMerchantId()); adapayMemberAccount.setAdapayMemberId(adapayMemberId); adapayMemberAccount.setSettleAccountId(settleAccountId); adapayMemberAccount.setStatus(Constants.ONE); adapayMemberAccountService.insertAdapayMemberAccount(adapayMemberAccount); } /** * 查询汇付会员信息 * * @param merchantId * @return */ public Map selectAdapayMember(String merchantId) throws BaseAdaPayException { Map map = Maps.newHashMap(); AdapayMemberAccount adapayMemberAccount = adapayMemberAccountService.selectByMerchantId(merchantId); if (adapayMemberAccount == null) { log.error("通过merchantId:{}, 没有查询到结算账户配置", merchantId); return null; } String adapayMemberId = adapayMemberAccount.getAdapayMemberId(); String bankAcctType; AdapayMemberInfoVO adapayMemberInfoVO = null; List list = null; AdapayCorpMemberVO adapayCorpMemberVO = null; if (StringUtils.startsWith(adapayMemberId, Constants.ADAPAY_MEMBER_PREFIX)) { bankAcctType = Constants.TWO; // 查询个人用户 adapayMemberInfoVO = queryAdapayMemberInfo(adapayMemberId); if (adapayMemberInfoVO != null) { adapayMemberInfoVO.setMerchantId(merchantId); } AdapaySettleAccountVO adapaySettleAccountVO = queryAdapaySettleAccount(adapayMemberId, adapayMemberAccount.getSettleAccountId()); if (adapaySettleAccountVO != null) { adapaySettleAccountVO.setMerchantId(merchantId); } map.put("adapayMember", adapayMemberInfoVO); list = Lists.newArrayList(adapaySettleAccountVO); map.put("settleAccountList", list); } else { bankAcctType = Constants.ONE; // 查询企业用户 adapayCorpMemberVO = queryCorpAdapayMemberInfo(adapayMemberId); } map.put("bankAcctType", bankAcctType); map.put("adapayMember", adapayMemberInfoVO); map.put("settleAccountList", list); map.put("adapayCorpMember", adapayCorpMemberVO); return map; } /** * 查询汇付会员信息 */ public AdapayMemberInfoVO queryAdapayMemberInfo(String adapayMemberId) throws BaseAdaPayException { if (StringUtils.isBlank(adapayMemberId)) { return null; } Map memberParams = Maps.newHashMap(); memberParams.put("member_id", adapayMemberId); memberParams.put("app_id", ADAPAY_APP_ID); Map member = Member.query(memberParams); log.info("==查询个人用户,请求参数:{},返回参数:{}", JSON.toJSONString(memberParams), JSON.toJSONString(member)); if (member == null || member.isEmpty() || !"succeeded".equals(member.get("status"))) { return null; } QueryMemberResponse queryMemberResponse = JSON.parseObject(JSON.toJSONString(member), QueryMemberResponse.class); AdapayMemberInfoVO resultVO = AdapayMemberInfoVO.builder() .nickname(queryMemberResponse.getNickname()) .gender(queryMemberResponse.getGender()) .email(queryMemberResponse.getEmail()) .location(queryMemberResponse.getLocation()) .build(); return resultVO; } /** * 查询企业用户信息 */ public AdapayCorpMemberVO queryCorpAdapayMemberInfo(String adapayMemberId) throws BaseAdaPayException { Map memberParams = Maps.newHashMap(); memberParams.put("member_id", adapayMemberId); memberParams.put("app_id", ADAPAY_APP_ID); Map member = CorpMember.query(memberParams); log.info("==查询企业用户信息 param:{}, result:{}", JSON.toJSONString(memberParams), JSON.toJSONString(member)); if (member == null || member.isEmpty() || !"succeeded".equals(member.get("status"))) { return null; } QueryCorpMemberResponse response = JSONObject.parseObject(JSON.toJSONString(member), QueryCorpMemberResponse.class); AdapayCorpMemberVO corpMemberVO = AdapayCorpMemberVO.builder() .memberId(adapayMemberId) .address(response.getAddress()) .name(response.getName()) .areaCode(response.getArea_code()) .provCode(response.getProv_code()) .auditDesc(response.getAudit_desc()) .auditState(response.getAudit_state()) .legalCertIdExpires(response.getLegal_cert_id_expires()) .businessScope(response.getBusiness_scope()) .legalMp(response.getLegal_mp()) .legalPerson(response.getLegal_person()) .legalCertId(response.getLegal_cert_id()) .telphone(response.getTelphone()) .zipCode(response.getZip_code()) .email(response.getEmail()) .socialCreditCode(response.getSocial_credit_code()) .socialCreditCodeExpires(response.getSocial_credit_code_expires()) // .bankCode(response.getBank_code()) // .cardName(response.getCard_name()) // .cardNo(response.getCard_no()) .build(); if (StringUtils.isNotBlank(response.getSettle_accounts())) { JSONObject jsonObject = JSON.parseObject(response.getSettle_accounts()); String settleAccountId = jsonObject.getString("id"); if (StringUtils.isNotEmpty(settleAccountId)) { AdapaySettleAccountVO adapaySettleAccountVO = queryAdapaySettleAccount(adapayMemberId, settleAccountId); if (adapaySettleAccountVO != null) { corpMemberVO.setBankCode(adapaySettleAccountVO.getBankCode()); corpMemberVO.setCardName(adapaySettleAccountVO.getCardName()); corpMemberVO.setCardNo(adapaySettleAccountVO.getCardId()); } } } return corpMemberVO; } /** * 查询汇付结算账户信息 */ public AdapaySettleAccountVO queryAdapaySettleAccount(String adapayMemberId, String settleAccountId) throws BaseAdaPayException { if (StringUtils.isBlank(adapayMemberId) || StringUtils.isBlank(settleAccountId)) { return null; } Map settleCountParams = Maps.newHashMap(); settleCountParams.put("settle_account_id", settleAccountId); settleCountParams.put("member_id", adapayMemberId); settleCountParams.put("app_id", ADAPAY_APP_ID); Map settleAccount = SettleAccount.query(settleCountParams); log.info("==查询汇付结算账户信息param:{}, result:{}", JSON.toJSONString(settleCountParams), JSON.toJSONString(settleAccount)); if (settleAccount == null || settleAccount.isEmpty() || !"succeeded".equals(settleAccount.get("status"))) { return null; } QueryMemberResponse.SettleAccount settleAccountInfo = JSON.parseObject(JSON.toJSONString(settleAccount), QueryMemberResponse.SettleAccount.class); QueryMemberResponse.AccountInfo accountInfo = settleAccountInfo.getAccount_info(); AdapaySettleAccountVO resultVO = AdapaySettleAccountVO.builder() .adapayMemberId(settleAccountInfo.getMember_id()) .settleAccountId(settleAccountInfo.getId()) .cardId(accountInfo.getCard_id()) .cardName(accountInfo.getCard_name()) .certId(accountInfo.getCert_id()) .certType(accountInfo.getCert_type()) .telNo(accountInfo.getTel_no()) .bankName(accountInfo.getBank_name()) .bankCode(accountInfo.getBank_code()) .bankAcctType(accountInfo.getBank_acct_type()) .provCode(accountInfo.getProv_code()) .areaCode(accountInfo.getArea_code()) .build(); return resultVO; } /** * 查询汇付会员账户余额 */ public AdapayAccountBalanceVO queryAdapayAccountBalance(String merchantId) throws BaseAdaPayException { AdapayAccountBalanceVO vo = AdapayAccountBalanceVO.builder().build(); // 通过merchantId 查询出汇付会员id 和 结算账户id,用来查询余额 AdapayMemberAccount adapayMemberAccount = adapayMemberAccountService.selectByMerchantId(merchantId); if (adapayMemberAccount == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_MEMBER_IS_NULL_ERROR); } String settle_account_id = adapayMemberAccount.getSettleAccountId(); String member_id = adapayMemberAccount.getAdapayMemberId(); Map queryParams = Maps.newHashMap(); queryParams.put("settle_account_id", settle_account_id); queryParams.put("member_id", member_id); queryParams.put("app_id", ADAPAY_APP_ID); Map settleCount = SettleAccount.balance(queryParams); if (settleCount == null || settleCount.isEmpty() || !"succeeded".equals(settleCount.get("status"))) { return vo; } vo.setFrzBalance(new BigDecimal((String) settleCount.get("frz_balance"))); vo.setAcctBalance(new BigDecimal((String) settleCount.get("acct_balance"))); vo.setAvlBalance(new BigDecimal((String) settleCount.get("avl_balance"))); vo.setLastAvlBalance(new BigDecimal((String) settleCount.get("last_avl_balance"))); vo.setAdapayMemberId(adapayMemberAccount.getAdapayMemberId()); vo.setSettleAccountId(adapayMemberAccount.getSettleAccountId()); return vo; } /** * 更新结算账户设置 * * @param dto * @throws BaseAdaPayException */ public void updateSettleAccountConfig(UpdateAccountConfigDTO dto) throws BaseAdaPayException { // 通过merchantId 查询出汇付会员id 和 结算账户id,用来查询余额 AdapayMemberAccount adapayMemberAccount = adapayMemberAccountService.selectByMerchantId(dto.getMerchantId()); if (adapayMemberAccount == null) { log.error("通过merchantId:{}, 没有查询到结算账户配置", dto.getMerchantId()); return; } // 修改账户配置 Map params = Maps.newHashMap(); params.put("app_id", ADAPAY_APP_ID); params.put("member_id", adapayMemberAccount.getAdapayMemberId()); params.put("settle_account_id", adapayMemberAccount.getSettleAccountId()); if (StringUtils.isNotBlank(dto.getMinAmt())) { params.put("min_amt", dto.getMinAmt()); } if (StringUtils.isNotBlank(dto.getRemainedAmt())) { params.put("remained_amt", dto.getRemainedAmt()); } if (StringUtils.isNotBlank(dto.getChannelRemark())) { params.put("channel_remark", dto.getChannelRemark()); } Map settleCount = SettleAccount.update(params); } /** * 创建企业用户 */ public void createCorpMember(SettleAccountDTO dto) throws BaseAdaPayException, BusinessException { Map memberParams = Maps.newHashMap(); String adapayMemberId = Constants.ADAPAY_CORP_MEMBER_PREFIX + IdUtils.getMemberId(); memberParams.put("member_id", adapayMemberId); memberParams.put("app_id", ADAPAY_APP_ID); memberParams.put("order_no", "jsdk_order" + System.currentTimeMillis()); memberParams.put("social_credit_code_expires", dto.getSocialCreditCodeExpires()); memberParams.put("business_scope", dto.getBusinessScope()); memberParams.put("name", dto.getBusinessName()); memberParams.put("prov_code", dto.getProvCode()); memberParams.put("area_code", dto.getAreaCode()); memberParams.put("social_credit_code", dto.getSocialCreditCode()); memberParams.put("legal_person", dto.getLegalPerson()); memberParams.put("legal_cert_id", dto.getLegalCertId()); memberParams.put("legal_cert_id_expires", dto.getLegalCertIdExpires()); memberParams.put("legal_mp", dto.getLegalMp()); memberParams.put("address", dto.getAddress()); memberParams.put("zip_code", dto.getZipCode()); memberParams.put("telphone", dto.getTelphone()); memberParams.put("email", dto.getEmail()); memberParams.put("bank_code", dto.getBankCode()); memberParams.put("bank_acct_type", dto.getBankAcctType()); memberParams.put("card_no", dto.getCardNo()); memberParams.put("card_name", dto.getCardName()); memberParams.put("notify_url", ADAPAY_CALLBACK_URL); File file = ZipUtil.createZipFileFromImages(dto.getImgList()); log.info("创建企业账户param:{}", memberParams); Map member = CorpMember.create(memberParams, file); log.info("创建企业账户result:{}", member); if (StringUtils.equals((String) member.get("status"), "failed")) { throw new BusinessException("", (String) member.get("error_msg")); } // 逻辑删除原来审核不通过的记录 List accountList = adapayMemberAccountService.selectAdapayMemberAccountList(dto.getMerchantId()); if (CollectionUtils.isNotEmpty(accountList)) { Long[] ids = accountList.stream() .map(AdapayMemberAccount::getId) .toArray(Long[]::new); adapayMemberAccountService.deleteAdapayMemberAccountByIds(ids); } // 保存到数据库 AdapayMemberAccount adapayMemberAccount = new AdapayMemberAccount(); adapayMemberAccount.setMerchantId(dto.getMerchantId()); adapayMemberAccount.setAdapayMemberId(adapayMemberId); adapayMemberAccount.setStatus(Constants.ZERO); adapayMemberAccountService.insertAdapayMemberAccount(adapayMemberAccount); } /** * 提现逻辑 * @param dto * @throws BaseAdaPayException */ public void drawCash(WithdrawDTO dto) throws BaseAdaPayException { // 查询余额 AdapayAccountBalanceVO adapayAccountBalanceVO = queryAdapayAccountBalance(dto.getMerchantId()); if (adapayAccountBalanceVO == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_MEMBER_IS_NULL_ERROR); } // 提现手续费 每笔固定10元 BigDecimal feeAmt = new BigDecimal("10"); // 实际提现到账金额 BigDecimal cashAmt = adapayAccountBalanceVO.getAvlBalance().subtract(feeAmt); // 可提现金额减去手续费后需大于0 if (cashAmt.compareTo(BigDecimal.ZERO) < 0) { throw new BusinessException(ReturnCodeEnum.CODE_INSUFFICIENT_BALANCE_ERROR); } // 发送提现申请 Map settleCountParams = Maps.newHashMap(); settleCountParams.put("order_no", "drawcash_" + System.currentTimeMillis()); settleCountParams.put("cash_amt", AdapayUtil.formatAmount(cashAmt)); settleCountParams.put("member_id", adapayAccountBalanceVO.getAdapayMemberId()); settleCountParams.put("app_id", ADAPAY_APP_ID); settleCountParams.put("settle_account_id", adapayAccountBalanceVO.getSettleAccountId()); settleCountParams.put("cash_type", "T1"); settleCountParams.put("notify_url", ADAPAY_CALLBACK_URL); log.info("申请取现接口,请求参数:{}", JSON.toJSONString(settleCountParams)); Map settleCount = Drawcash.create(settleCountParams); log.info("申请取现接口,返回参数:{}", JSON.toJSONString(settleCount)); if (settleCount == null) { throw new BusinessException("", "申请取现接口发生异常"); } String id = (String) settleCount.get("id"); // 发起支付手续费请求 inMemberId为0表示本商户 createBalancePaymentRequest(adapayAccountBalanceVO.getAdapayMemberId(), Constants.ZERO, feeAmt.toString()); // 保存提现记录 ClearingWithdrawInfo record = new ClearingWithdrawInfo(); record.setWithdrawCode(id); record.setWithdrawStatus(Constants.ZERO); Date now = new Date(); record.setApplicationTime(now); record.setCreateTime(now); record.setDelFlag(DelFlagEnum.NORMAL.getValue()); clearingWithdrawInfoService.insertOrUpdate(record); } /** * 更新汇付会员信息 * @param dto * @return * @throws BaseAdaPayException */ public Map updateAdapayMember(SettleAccountDTO dto) throws BaseAdaPayException { AdapayMemberAccount adapayMemberAccount = adapayMemberAccountService.selectByMerchantId(dto.getMerchantId()); if (adapayMemberAccount == null) { log.error("通过merchantId:{}, 没有查询到结算账户配置", dto.getMerchantId()); return null; } Map memberParams = Maps.newHashMap(); memberParams.put("adapay_func_code", "corp_members.update"); memberParams.put("member_id", adapayMemberAccount.getAdapayMemberId()); memberParams.put("app_id", ADAPAY_APP_ID); memberParams.put("order_no", "jsdk_order_" + System.currentTimeMillis()); memberParams.put("social_credit_code_expires", dto.getSocialCreditCodeExpires()); memberParams.put("business_scope", dto.getBusinessScope()); memberParams.put("name", dto.getNickname()); memberParams.put("prov_code", dto.getProvCode()); memberParams.put("area_code", dto.getAreaCode()); memberParams.put("legal_person", dto.getLegalPerson()); memberParams.put("legal_cert_id", dto.getLegalCertId()); memberParams.put("legal_cert_id_expires", dto.getLegalCertIdExpires()); memberParams.put("legal_mp", dto.getLegalMp()); memberParams.put("address", dto.getAddress()); memberParams.put("zip_code", dto.getZipCode()); memberParams.put("telphone", dto.getTelphone()); memberParams.put("email", dto.getEmail()); File file = ZipUtil.createZipFileFromImages(dto.getImgList()); log.info("更新企业账户param:{}", memberParams); Map member = AdapayCommon.requestAdapayFile(memberParams, file); log.info("更新企业账户result:{}", JSON.toJSONString(member)); if (StringUtils.equals((String) member.get("status"), "failed")) { throw new BusinessException("", (String) member.get("error_msg")); } return null; } /** * 创建余额支付请求 * @param outMemberId 出账用户的member_id, 若为商户本身时,请传入0 * @param inMemberId 入账用户的member_id, 若为商户本身时,请传入0 * @param transAmt 交易金额, 必须大于0,保留两位小数点,如0.10、100.05等 */ public void createBalancePaymentRequest(String outMemberId, String inMemberId, String transAmt) throws BaseAdaPayException { Map balanceParam = Maps.newHashMap(); balanceParam.put("app_id", ADAPAY_APP_ID); balanceParam.put("adapay_func_code", "settle_accounts.balancePay"); balanceParam.put("order_no", IdUtils.fastSimpleUUID()); balanceParam.put("out_member_id", outMemberId); balanceParam.put("in_member_id", inMemberId); balanceParam.put("trans_amt", AdapayUtil.formatAmount(transAmt)); balanceParam.put("goods_title", "测试余额支付"); balanceParam.put("goods_desc", "该商品信息用于测试余额支付"); Map paymentResult = AdapayCommon.requestAdapay(balanceParam); log.info("创建余额支付param:{}, result:{}", JSON.toJSONString(balanceParam), JSON.toJSONString(paymentResult)); } }