package com.jsowell.adapay.service; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.TypeReference; import com.google.common.collect.ImmutableMap; 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.common.CreateAdaPaymentParam; import com.jsowell.adapay.common.DivMember; import com.jsowell.adapay.config.AbstractAdapayConfig; import com.jsowell.adapay.dto.*; import com.jsowell.adapay.factory.AdapayConfigFactory; import com.jsowell.adapay.response.*; import com.jsowell.adapay.vo.*; import com.jsowell.common.constant.CacheConstants; import com.jsowell.common.constant.Constants; import com.jsowell.common.core.redis.RedisCache; import com.jsowell.common.enums.DelFlagEnum; import com.jsowell.common.enums.adapay.AdapayStatusEnum; import com.jsowell.common.enums.ykc.ReturnCodeEnum; import com.jsowell.common.enums.ykc.ScenarioEnum; 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.ClearingBillInfo; import com.jsowell.pile.domain.ClearingWithdrawInfo; import com.jsowell.pile.domain.MemberBasicInfo; import com.jsowell.pile.dto.PayOrderDTO; import com.jsowell.pile.service.*; 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.cglib.beans.BeanMap; 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; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Slf4j @Service public class AdapayService { @Autowired private RedisCache redisCache; @Value("${adapay.callback}") private String ADAPAY_CALLBACK_URL; @Autowired private IAdapayMemberAccountService adapayMemberAccountService; @Autowired private ClearingWithdrawInfoService clearingWithdrawInfoService; @Autowired private ClearingBillInfoService clearingBillInfoService; @Autowired private IPileMerchantInfoService pileMerchantInfoService; @Autowired private IMemberBasicInfoService memberBasicInfoService; /** * 获取支付参数 */ public Map createPayment(PayOrderDTO dto) { log.info("===============使用汇付支付-获取支付参数"); // 相同参数重复请求,返回同一个支付对象 String redisKey = CacheConstants.ADAPAY_ORDER_PARAM + dto.getOrderCode(); Map cacheObject = redisCache.getCacheObject(redisKey); if (cacheObject != null) { // 表示已经获取到支付参数了,后续再有支付请求就拒绝 return cacheObject; } // 获取支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(dto.getWechatAppId()); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } // 获取openId MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMemberId(dto.getMemberId()); if (memberBasicInfo == null) { throw new BusinessException(ReturnCodeEnum.CODE_GET_OPEN_ID_BY_CODE_ERROR); } String openId =memberBasicInfo.getOpenId(); // String openId = wxAppletRemoteService.getOpenIdByCode(dto.getCode()); // if (StringUtils.isBlank(openId)) { // throw new BusinessException(ReturnCodeEnum.CODE_GET_OPEN_ID_BY_CODE_ERROR); // } // 封装对象 String amount = AdapayUtil.formatAmount(dto.getPayAmount()); // 用户支付金额 String payMode = Constants.ADAPAY_PAY_MODE_DELAY; // 汇付延时分账 CreateAdaPaymentParam createAdaPaymentParam = new CreateAdaPaymentParam(); createAdaPaymentParam.setOrder_no(dto.getOrderCode()); createAdaPaymentParam.setPay_amt(amount); createAdaPaymentParam.setApp_id(config.getAdapayAppId()); createAdaPaymentParam.setPay_channel("wx_lite"); // todo 如果以后有支付宝等别的渠道,这里需要做修改,判断是什么渠道的请求 createAdaPaymentParam.setGoods_title(dto.getGoodsTitle()); createAdaPaymentParam.setGoods_desc(dto.getGoodsDesc()); // 这个字段是微信支付凭证的商品名 Map map = Maps.newHashMap(); map.put("type", ScenarioEnum.ORDER.getValue()); map.put("orderCode", dto.getOrderCode()); map.put("payMode", payMode); map.put("memberId", dto.getMemberId()); createAdaPaymentParam.setDescription(JSON.toJSONString(map)); // 异步通知地址,url为http/https路径,服务器POST回调,URL 上请勿附带参数 createAdaPaymentParam.setNotify_url(ADAPAY_CALLBACK_URL); createAdaPaymentParam.setExpend(JSONObject.toJSONString(ImmutableMap.of("open_id", openId))); // 延时分账 createAdaPaymentParam.setPay_mode(payMode); try { log.info("创建汇付支付参数:{}", JSONObject.toJSONString(createAdaPaymentParam)); Map response = Payment.create(BeanMap.create(createAdaPaymentParam), config.getWechatAppId()); if (response != null && !response.isEmpty()) { JSONObject expend = JSONObject.parseObject(response.get("expend").toString()); JSONObject pay_info = expend.getJSONObject("pay_info"); Map resultMap = JSONObject.parseObject(pay_info.toJSONString(), new TypeReference>() {}); if (resultMap != null) { // 请求参数放入缓存,15分钟以内返回同一个支付参数 redisCache.setCacheObject(redisKey, resultMap, 15, TimeUnit.MINUTES); } return resultMap; } } catch (BaseAdaPayException e) { log.error("汇付-获取支付对象发生异常", e); } return null; } /** * 创建结算账户 * * @param dto * @throws BaseAdaPayException * @throws BusinessException */ public void createSettleAccount(SettleAccountDTO dto) throws BaseAdaPayException, BusinessException { String bankAcctType = dto.getBankAcctType(); // 设置wechatAppId String wechatAppId = pileMerchantInfoService.queryAppIdByMerchantId(dto.getMerchantId()); dto.setWechatAppId(wechatAppId); 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 { // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(dto.getWechatAppId()); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } // 查询汇付会员关系 AdapayMemberAccount adapayMemberAccount = adapayMemberAccountService.selectByMerchantId(dto.getMerchantId()); if (adapayMemberAccount != null) { log.error("通过merchantId:{}, 查询到结算账户配置:{}", dto.getMerchantId(), JSON.toJSONString(adapayMemberAccount)); 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", config.getAdapayAppId()); 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, config.getWechatAppId()); 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", config.getAdapayAppId()); // channel String Y 目前仅支持:bank_account(银行卡) settleCountParams.put("channel", "bank_account"); settleCountParams.put("account_info", accountInfo); log.info("创建汇付结算账户param:{}", settleCountParams); Map settleCount = SettleAccount.create(settleCountParams, config.getWechatAppId()); log.info("创建汇付结算账户result:{}", settleCount);*/ Map 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 = 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; } // 通过merchantId获取appId String wechatAppId = pileMerchantInfoService.queryAppIdByMerchantId(merchantId); 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, wechatAppId); if (adapayMemberInfoVO != null) { adapayMemberInfoVO.setMerchantId(merchantId); } AdapaySettleAccountVO adapaySettleAccountVO = queryAdapaySettleAccount(adapayMemberId, adapayMemberAccount.getSettleAccountId(), wechatAppId); 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, wechatAppId); } map.put("bankAcctType", bankAcctType); map.put("adapayMember", adapayMemberInfoVO); map.put("settleAccountList", list); map.put("adapayCorpMember", adapayCorpMemberVO); return map; } /** * 查询汇付会员信息 */ public AdapayMemberInfoVO queryAdapayMemberInfo(String adapayMemberId, String wechatAppId) throws BaseAdaPayException { // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } if (StringUtils.isBlank(adapayMemberId)) { return null; } Map memberParams = Maps.newHashMap(); memberParams.put("member_id", adapayMemberId); memberParams.put("app_id", config.getAdapayAppId()); Map member = Member.query(memberParams, config.getWechatAppId()); 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, String wechatAppId) throws BaseAdaPayException { // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } Map memberParams = Maps.newHashMap(); memberParams.put("member_id", adapayMemberId); memberParams.put("app_id", config.getAdapayAppId()); Map member = CorpMember.query(memberParams, config.getWechatAppId()); 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, config.getWechatAppId()); if (adapaySettleAccountVO != null) { corpMemberVO.setBankCode(adapaySettleAccountVO.getBankCode()); corpMemberVO.setCardName(adapaySettleAccountVO.getCardName()); corpMemberVO.setCardNo(adapaySettleAccountVO.getCardId()); } } } return corpMemberVO; } /** * 创建结算账户请求 */ public Map createSettleAccountRequest(SettleAccountDTO dto, String adapayMemberId, String wechatAppId) throws BaseAdaPayException { // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } // 创建结算账户 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", config.getAdapayAppId()); // channel String Y 目前仅支持:bank_account(银行卡) settleCountParams.put("channel", "bank_account"); settleCountParams.put("account_info", accountInfo); Map settleCount = SettleAccount.create(settleCountParams, config.getWechatAppId()); log.info("创建汇付结算账户param:{}, result:{}", JSON.toJSONString(settleCountParams), JSON.toJSONString(settleCount)); return settleCount; } /** * 删除结算账户对象/创建删除结算账户请求 * 企业用户更新银行卡信息时调用,先删除后新建 */ public void createDeleteSettleAccountRequest(String adapayMemberId, String settleAccountId, String wechatAppId) throws BaseAdaPayException { // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } Map settleCountParams = Maps.newHashMap(); settleCountParams.put("settle_account_id", settleAccountId); settleCountParams.put("member_id", adapayMemberId); settleCountParams.put("app_id", config.getAdapayAppId()); Map settleCount = SettleAccount.delete(settleCountParams, wechatAppId); log.info("创建删除结算账户请求param:{}, result:{}", JSON.toJSONString(settleCountParams), JSON.toJSONString(settleCount)); } /** * 查询汇付结算账户信息 */ public AdapaySettleAccountVO queryAdapaySettleAccount(String adapayMemberId, String settleAccountId, String wechatAppId) throws BaseAdaPayException { // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } 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", config.getAdapayAppId()); Map settleAccount = SettleAccount.query(settleCountParams, config.getWechatAppId()); 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 { String wechatAppId = pileMerchantInfoService.queryAppIdByMerchantId(merchantId); // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } 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", config.getAdapayAppId()); Map settleCount = SettleAccount.balance(queryParams, config.getWechatAppId()); 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 { String wechatAppId = pileMerchantInfoService.queryAppIdByMerchantId(dto.getMerchantId()); // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } // 通过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", config.getAdapayAppId()); 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); log.info("更新结算账户设置 param:{}, result:{}", JSON.toJSONString(params), JSON.toJSONString(settleCount)); } /** * 创建企业用户 */ public void createCorpMember(SettleAccountDTO dto) throws BaseAdaPayException, BusinessException { // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(dto.getWechatAppId()); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } Map memberParams = Maps.newHashMap(); String adapayMemberId = Constants.ADAPAY_CORP_MEMBER_PREFIX + IdUtils.getMemberId(); memberParams.put("member_id", adapayMemberId); memberParams.put("app_id", config.getAdapayAppId()); 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()); Map member = CorpMember.create(memberParams, file, config.getWechatAppId()); log.info("创建企业账户param:{}, result:{}", JSON.toJSONString(memberParams), JSON.toJSONString(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); } // 取消自动创建结算账户,手动创建结算账户 Map 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 adapayMemberAccount = new AdapayMemberAccount(); adapayMemberAccount.setMerchantId(dto.getMerchantId()); adapayMemberAccount.setAdapayMemberId(adapayMemberId); adapayMemberAccount.setSettleAccountId(settleAccountId); adapayMemberAccount.setStatus(Constants.ZERO); adapayMemberAccountService.insertAdapayMemberAccount(adapayMemberAccount); } /** * 提现逻辑/创建取现对象 * * @param dto * @throws BaseAdaPayException */ public void drawCash(WithdrawDTO dto) throws BaseAdaPayException { String wechatAppId = pileMerchantInfoService.queryAppIdByMerchantId(dto.getMerchantId()); // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } // 查询余额 AdapayAccountBalanceVO adapayAccountBalanceVO = queryAdapayAccountBalance(dto.getMerchantId()); if (adapayAccountBalanceVO == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_MEMBER_IS_NULL_ERROR); } // 提现手续费 每笔固定5元 BigDecimal feeAmt = new BigDecimal("5"); // 实际提现到账金额 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(); String orderNo = "drawcash_" + dto.getMerchantId() + "_" +System.currentTimeMillis(); settleCountParams.put("order_no", orderNo); settleCountParams.put("cash_amt", AdapayUtil.formatAmount(cashAmt)); settleCountParams.put("member_id", adapayAccountBalanceVO.getAdapayMemberId()); settleCountParams.put("app_id", config.getAdapayAppId()); settleCountParams.put("settle_account_id", adapayAccountBalanceVO.getSettleAccountId()); settleCountParams.put("cash_type", "T1"); settleCountParams.put("notify_url", ADAPAY_CALLBACK_URL); Map settleCount = Drawcash.create(settleCountParams, config.getWechatAppId()); log.info("申请取现接口,请求参数:{}, 返回参数:{}", JSON.toJSONString(settleCountParams), JSON.toJSONString(settleCount)); if (settleCount == null) { throw new BusinessException("", "申请取现接口发生异常"); } if (AdapayStatusEnum.FAILED.getValue().equals(settleCount.get("status"))) { throw new BusinessException((String) settleCount.get("error_code"), (String) settleCount.get("error_msg")); } String id = (String) settleCount.get("id"); // 发起支付手续费请求 inMemberId为0表示本商户 createBalancePaymentRequest(adapayAccountBalanceVO.getAdapayMemberId(), Constants.ZERO, feeAmt.toString(), "提现手续费", "提现单号:" + id, config.getWechatAppId()); // 保存提现记录 ClearingWithdrawInfo record = new ClearingWithdrawInfo(); record.setMerchantId(dto.getMerchantId()); record.setWithdrawCode(id); record.setOrderNo(orderNo); record.setWithdrawStatus(Constants.ZERO); Date now = new Date(); record.setApplicationTime(now); record.setCreateTime(now); record.setDelFlag(DelFlagEnum.NORMAL.getValue()); clearingWithdrawInfoService.insertSelective(record); // 修改清分账单为提现中 List list = clearingBillInfoService.selectByMerchantId(dto.getMerchantId(), "2"); List clearingBillIds = list.stream().map(ClearingBillInfo::getId).collect(Collectors.toList()); String billStatus = "3"; clearingBillInfoService.updateStatus(clearingBillIds, billStatus); } /** * 查询取现对象 * @param orderNo 请求订单号 */ public DrawCashDetailVO queryDrawCashDetail(String orderNo, String wechatAppId) throws BaseAdaPayException { Map queryCashParam = Maps.newHashMap(); queryCashParam.put("order_no", orderNo); Map response = Drawcash.query(queryCashParam, wechatAppId); log.info("查询取现对象param:{}, result:{}", JSON.toJSONString(queryCashParam), JSON.toJSONString(response)); if (response != null) { QueryDrawCashResponse queryDrawCashResponse = JSON.parseObject(JSON.toJSONString(response), QueryDrawCashResponse.class); if (queryDrawCashResponse == null || queryDrawCashResponse.isNotSuccess()) { return null; } QueryDrawCashResponse.Cash cash = queryDrawCashResponse.getCashList().get(0); DrawCashDetailVO vo = new DrawCashDetailVO(); vo.setCashId(cash.getCashId()); vo.setCashAmt(cash.getCashAmt()); vo.setTransStat(cash.getTransStat()); vo.setStatusDesc(cash.getTransStatusDesc()); return vo; } return null; } /** * 更新汇付会员信息 * * @param dto * @return * @throws BaseAdaPayException */ public Map updateAdapayMember(SettleAccountDTO dto) throws BaseAdaPayException { String wechatAppId = pileMerchantInfoService.queryAppIdByMerchantId(dto.getMerchantId()); // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } 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", config.getAdapayAppId()); 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()); Map member = AdapayCommon.requestAdapayFile(memberParams, file, config.getWechatAppId()); log.info("更新企业账户param:{}, result:{}", JSON.toJSONString(memberParams), JSON.toJSONString(member)); if (AdapayStatusEnum.FAILED.getValue().equals((String) member.get("status"))) { throw new BusinessException("", (String) member.get("error_msg")); } return null; } /** * 创建交易确认请求/创建分账请求 * 这个方法只适用于给一个用户分账 * * @param paymentId 支付对象id * @param adapayMemberAccount 收到该张的汇付会员信息 * @param confirmAmt 确认的金额 * @param orderCode 订单编号 */ public PaymentConfirmResponse createPaymentConfirmRequest(String paymentId, AdapayMemberAccount adapayMemberAccount, BigDecimal confirmAmt, String orderCode, String wechatAppId) { // 调汇付的分账接口 确认交易 Map confirmParams = Maps.newHashMap(); // Adapay生成的支付对象id confirmParams.put("payment_id", paymentId); // 请求订单号,只能为英文、数字或者下划线的一种或多种组合,保证在app_id下唯一 confirmParams.put("order_no", "PC" + System.currentTimeMillis()); // 确认金额,必须大于0,保留两位小数点,如0.10、100.05等。必须小于等于原支付金额-已确认金额-已撤销金额。 confirmParams.put("confirm_amt", AdapayUtil.formatAmount(confirmAmt)); // 附加说明 JSONObject jsonObject = new JSONObject(); jsonObject.put("orderCode", orderCode); jsonObject.put("adapayMemberId", adapayMemberAccount.getAdapayMemberId()); confirmParams.put("description", jsonObject.toJSONString()); // 分账对象信息 一次最多7个 DivMember divMember = new DivMember(); divMember.setMember_id(adapayMemberAccount.getAdapayMemberId()); divMember.setAmount(AdapayUtil.formatAmount(confirmAmt)); divMember.setFee_flag(Constants.Y); confirmParams.put("div_members", Lists.newArrayList(divMember)); Map paymentConfirm = null; try { paymentConfirm = PaymentConfirm.create(confirmParams, wechatAppId); } catch (BaseAdaPayException e) { log.error("创建交易确认请求error", e); } String jsonString = JSON.toJSONString(paymentConfirm); log.info("调分账接口param:{}, result:{}", JSON.toJSONString(confirmParams), jsonString); return JSONObject.parseObject(jsonString, PaymentConfirmResponse.class); } /** * 创建余额支付请求 * * @param outMemberId 出账用户的member_id, 若为商户本身时,请传入0 * @param inMemberId 入账用户的member_id, 若为商户本身时,请传入0 * @param transAmt 交易金额, 必须大于0,保留两位小数点,如0.10、100.05等 * @param title 标题 * @param desc 描述信息 */ public BalancePaymentResponse createBalancePaymentRequest(String outMemberId, String inMemberId, String transAmt, String title, String desc, String wechatAppId) { // 获取汇付支付配置 AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } Map balanceParam = Maps.newHashMap(); balanceParam.put("app_id", config.getAdapayAppId()); 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", title); balanceParam.put("goods_desc", desc); Map paymentResult = null; try { paymentResult = AdapayCommon.requestAdapay(balanceParam, config.getWechatAppId()); } catch (BaseAdaPayException e) { log.error("创建余额支付请求error", e); } String jsonString = JSON.toJSONString(paymentResult); log.info("创建余额支付param:{}, result:{}", JSON.toJSONString(balanceParam), jsonString); return JSONObject.parseObject(jsonString, BalancePaymentResponse.class); } /** * 创建支付确认撤销 */ public void createConfirmReverse(String paymentConfirmId) throws BaseAdaPayException { Map confirmReverseParams = Maps.newHashMap(); confirmReverseParams.put("adapay_func_code", "payments.confirm.reverse"); confirmReverseParams.put("payment_confirm_id", paymentConfirmId); confirmReverseParams.put("reason", "支付确认撤销"); confirmReverseParams.put("order_no", IdUtils.fastSimpleUUID()); Map confirmReverseResult = AdapayCommon.requestAdapay(confirmReverseParams); log.info("创建支付确认撤销param:{}, result:{}", JSON.toJSONString(confirmReverseParams), JSON.toJSONString(confirmReverseResult)); } /** * 创建退款请求 */ public RefundResponse createRefundRequest(String paymentId, BigDecimal refundAmt) { // 延迟分账确认的调退款接口 Map refundParams = Maps.newHashMap(); refundParams.put("refund_amt", AdapayUtil.formatAmount(refundAmt)); refundParams.put("refund_order_no", IdUtils.fastSimpleUUID()); refundParams.put("notify_url", ADAPAY_CALLBACK_URL); Map resultResponse = null; try { resultResponse = Refund.create(paymentId, refundParams); } catch (BaseAdaPayException e) { log.error("汇付支付创建退款对象error", e); } String jsonString = JSON.toJSONString(resultResponse); log.info("汇付支付创建退款对象param:{}, result:{}", JSON.toJSONString(refundParams), JSON.toJSONString(jsonString)); return JSONObject.parseObject(jsonString, RefundResponse.class); } /** * 创建交易撤销请求 * 延迟分账未确认, 调交易撤销接口退款 * @param wechatAppId 微信小程序appId */ public PaymentReverseResponse createPaymentReverseRequest(String paymentId, BigDecimal reverseAmt, String wechatAppId, String memberId, String scenarioType, String orderCode) { PaymentReverseResponse response; AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } // 延迟分账未确认调撤销调撤销接口退款 Map reverseParams = Maps.newHashMap(); reverseParams.put("app_id", config.getAdapayAppId()); reverseParams.put("payment_id", paymentId); reverseParams.put("reverse_amt", AdapayUtil.formatAmount(reverseAmt)); reverseParams.put("order_no", IdUtils.fastSimpleUUID()); reverseParams.put("notify_url", ADAPAY_CALLBACK_URL); // expand 为扩展域 Map expendMap = Maps.newHashMap(); expendMap.put("memberId", memberId); expendMap.put("scenarioType", scenarioType); if (StringUtils.isNotBlank(orderCode)) { expendMap.put("orderCode", orderCode); } reverseParams.put("expand", expendMap); reverseParams.put("reason", expendMap); Map paymentReverse = null; try { paymentReverse = PaymentReverse.create(reverseParams, config.getWechatAppId()); } catch (BaseAdaPayException e) { log.error("汇付支付创建交易撤销对象error", e); } String jsonString = JSON.toJSONString(paymentReverse); log.info("汇付支付创建交易撤销对象param:{}, result:{}", JSON.toJSONString(reverseParams), jsonString); return JSONObject.parseObject(jsonString, PaymentReverseResponse.class); } /** * 查询支付撤销对象 * * @return */ public List queryPaymentReverse(String paymentId, String wechatAppId) throws BaseAdaPayException { AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } Map reverse = Maps.newHashMap(); reverse.put("payment_id", paymentId); reverse.put("app_id", config.getAdapayAppId()); Map response = PaymentReverse.queryList(reverse, config.getWechatAppId()); JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(response)); List payment_reverses = jsonObject.getList("payment_reverses", PaymentReverseResponse.class); return payment_reverses; } /** * 查询支付确认对象列表 */ public QueryPaymentConfirmDetailResponse queryPaymentConfirmList(QueryPaymentConfirmDTO dto) { AbstractAdapayConfig config = AdapayConfigFactory.getConfig(dto.getWechatAppId()); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } Map param = Maps.newHashMap(); param.put("payment_id", dto.getPaymentId()); param.put("app_id", config.getAdapayAppId()); QueryPaymentConfirmDetailResponse queryPaymentConfirmDetailResponse = null; try { Map map = PaymentConfirm.queryList(param, config.getWechatAppId()); queryPaymentConfirmDetailResponse = JSON.parseObject(JSON.toJSONString(map), QueryPaymentConfirmDetailResponse.class); // log.info("queryPaymentConfirmDetailResponse:{}", JSON.toJSONString(queryPaymentConfirmDetailResponse)); } catch (BaseAdaPayException e) { log.error("查询支付确认对象列表error", e); } return queryPaymentConfirmDetailResponse; } /** * 查询账务流水 */ public void queryAcctFlowList(QueryAcctFlowDTO dto) throws BaseAdaPayException { AbstractAdapayConfig config = AdapayConfigFactory.getConfig(dto.getWechatAppId()); if (config == null) { throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); } Map acctFlowParams = Maps.newHashMap(); acctFlowParams.put("adapay_func_code", "acct.flow.list"); acctFlowParams.put("app_id", config.getAdapayAppId()); acctFlowParams.put("member_id", dto.getAdapayMemberId()); acctFlowParams.put("acct_type", dto.getAcctType()); acctFlowParams.put("page_index", dto.getPageNo()); acctFlowParams.put("page_size", dto.getPageSize()); acctFlowParams.put("begin_date", dto.getBeginDate()); acctFlowParams.put("end_date", dto.getEndDate()); Map acctFlowList = AdapayCommon.queryAdapay(acctFlowParams, config.getWechatAppId()); log.info("查询账务流水param:{}, result:{}", JSON.toJSONString(dto), JSON.toJSONString(acctFlowList)); } }