GitBucket
4.23.0
Toggle navigation
Sign in
Files
Branches
1
Releases
Issues
Pull requests
Labels
Priorities
Milestones
Wiki
Forks
yn-bftl-byx
/
thirdparty
Browse code
测试
master
1 parent
0e08544
commit
06da987594cc6e3e97f2d0997c19dbc3745e157b
steven
authored
on 24 Oct
Patch
Showing
1 changed file
src/main/java/com/yn/bftl/thirdparty/modules/chinaums/service/impl/WalletServiceImpl.java
Ignore Space
Show notes
View
src/main/java/com/yn/bftl/thirdparty/modules/chinaums/service/impl/WalletServiceImpl.java
package com.yn.bftl.thirdparty.modules.chinaums.service.impl; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONObject; import com.yn.bftl.common.common.exception.YnceError; import com.yn.bftl.common.common.util.ByxRouteUtil; import com.yn.bftl.common.common.util.RSAEncryptorUtil; import com.yn.bftl.common.common.util.RouteUtil; import com.yn.bftl.common.modules.account.dto.*; import com.yn.bftl.common.modules.account.entity.*; import com.yn.bftl.common.modules.account.enums.AccountChangeType; import com.yn.bftl.common.modules.account.enums.AccountState; import com.yn.bftl.common.modules.account.enums.ChangeDirection; import com.yn.bftl.common.modules.account.enums.TransferState; import com.yn.bftl.common.modules.account.vo.AccountPaymentsVO; import com.yn.bftl.common.modules.account.vo.BalanceAcctsVO; import com.yn.bftl.common.modules.account.vo.BalanceTransactionsPageVO; import com.yn.bftl.common.modules.account.vo.WithdrawalsVO; import com.yn.bftl.common.modules.company.entity.Brand; import com.yn.bftl.common.modules.company.entity.ChinaumsAuthInfo; import com.yn.bftl.common.modules.company.entity.Company; import com.yn.bftl.common.modules.company.enums.ApplicationStatus; import com.yn.bftl.common.modules.configuration.entity.ThirdPartyPaySet; import com.yn.bftl.common.modules.order.dto.SubaccountRefundDTO; import com.yn.bftl.common.modules.order.dto.WalletRefundDTO; import com.yn.bftl.common.modules.order.entity.*; import com.yn.bftl.common.modules.order.enums.*; import com.yn.bftl.common.modules.order.vo.OrderOnlinePayVO; import com.yn.bftl.common.modules.order.vo.RefundVO; import com.yn.bftl.common.modules.order.vo.SubaccountRefundVO; import com.yn.bftl.common.modules.subaccount.entity.AllinpayMutual; import com.yn.bftl.common.modules.subaccount.entity.ChinaumsPayment; import com.yn.bftl.common.modules.subaccount.entity.ChinaumsRefund; import com.yn.bftl.common.modules.subaccount.entity.SubaccountRefund; import com.yn.bftl.common.modules.subaccount.enums.DealStatus; import com.yn.bftl.common.modules.subaccount.enums.SubaccountState; import com.yn.bftl.common.modules.subaccount.enums.SubaccountType; import com.yn.bftl.thirdparty.common.constants.Constant; import com.yn.bftl.thirdparty.common.exception.YnceErrorException; import com.yn.bftl.thirdparty.common.repository.*; import com.yn.bftl.thirdparty.common.service.BaseMemberService; import com.yn.bftl.thirdparty.common.service.ByxTradeWayService; import com.yn.bftl.thirdparty.common.util.DateTimeUtils; import com.yn.bftl.thirdparty.common.util.HttpClientUtil; import com.yn.bftl.thirdparty.common.util.SequenceUtil; import com.yn.bftl.thirdparty.common.repository.RefundRepository; import com.yn.bftl.thirdparty.modules.business.dto.RefundSubaccountDTO; import com.yn.bftl.thirdparty.modules.business.repository.ChinaumsPaymentRepository; import com.yn.bftl.thirdparty.modules.business.repository.ChinaumsRefundRepository; import com.yn.bftl.thirdparty.modules.business.repository.SubaccountRefundRepository; import com.yn.bftl.thirdparty.modules.business.service.RefundService; import com.yn.bftl.thirdparty.modules.business.service.SubaccountService; import com.yn.bftl.thirdparty.modules.business.util.ThirdPartyConfigUtil; import com.yn.bftl.thirdparty.modules.chinaums.dto.TradeResultDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.WalletCreateByCompanyDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.WalletOrderPayDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.byx.*; import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.*; import com.yn.bftl.thirdparty.modules.chinaums.enums.OrderPayStatusEnum; import com.yn.bftl.thirdparty.modules.chinaums.enums.OrderPaymentStatusEnum; import com.yn.bftl.thirdparty.modules.chinaums.repository.ChinaumsAuthInfoRepository; import com.yn.bftl.thirdparty.modules.chinaums.service.AuthService; import com.yn.bftl.thirdparty.modules.chinaums.service.WalletService; import com.yn.bftl.thirdparty.modules.chinaums.util.ByxChinaumsUtil; import com.yn.bftl.thirdparty.modules.chinaums.util.ChinaumsUtil; import com.yn.bftl.thirdparty.modules.chinaums.vo.ChinaumsRechargeAccountVO; import com.yn.bftl.thirdparty.modules.chinaums.vo.ElectronicReceiptVO; import com.yn.bftl.thirdparty.modules.chinaums.vo.byx.*; import com.yn.bftl.thirdparty.modules.chinaums.vo.chinaums.*; import com.yn.bftl.thirdparty.modules.log.service.LoggerService; import com.yn.bftl.thirdparty.modules.secret.service.RandomKeyService; import com.yn.bftl.thirdparty.modules.unionpay.enums.UnionpayAppOrderType; import com.yn.bftl.thirdparty.modules.unionpay.repository.OrderFeeRatioRepository; import com.yn.bftl.thirdparty.modules.unionpay.repository.TopUpOrderRepository; import com.yn.bftl.thirdparty.modules.unionpay.service.UnionpayAccountService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.*; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * @author huabiao * @create 2022/12/5 20:25 **/ @Slf4j @Service public class WalletServiceImpl extends BaseMemberService implements WalletService { @Resource private ByxChinaumsUtil byxChinaumsUtil; @Resource private ChinaumsUtil chinaumsUtil; @Resource private ChinaumsAuthInfoRepository chinaumsAuthInfoRepository; @Resource private OrderRepository orderRepository; @Resource private SubaccountService subaccountService; @Resource private PaymentRepository paymentRepository; @Resource private BrandRepository brandRepository; @Resource private ChinaumsPaymentRepository chinaumsPaymentRepository; @Resource private OrderFeeRatioRepository orderFeeRatioRepository; @Resource private AccountChangeListRepository accountChangeListRepository; @Resource private AccountRepository accountRepository; @Resource private UnionpayAccountService unionpayAccountService; @Resource private WalletService walletService; @Resource private AllinpayMutualRepository allinpayMutualRepository; @Resource private TransferListRepository transferListRepository; @Resource private ChinaumsRefundRepository chinaumsRefundRepository; @Resource private TopUpOrderRepository topUpOrderRepository; @Resource private ThirdPartyConfigUtil thirdPartyConfigUtil; @Resource private StringRedisTemplate stringRedisTemplate; @Resource private SequenceUtil sequenceUtil; @Resource private LoggerService loggerService; @Resource private CompanyRepository companyRepository; @Resource private ReimbursementRecordRepository reimbursementRecordRepository; @Resource private SubaccountRefundRepository subaccountRefundRepository; @Resource private RefundService refundService; @Resource private RefundRepository refundRepository; @Resource private ThirdPartyPaySetRepository thirdPartyPaySetRepository; @Resource private AuthService authService; @Resource private RandomKeyService randomKeyService; @Resource private ByxTradeWayService byxTradeWayService; @Override public BalanceAcctsVO balanceAcctsQryByAcctId(String balanceAcctId) { Company company = getUser().getCompany(); ChinaumsAuthInfo chinaumsAuthInfo = company.getChinaumsAuthInfo(); if (StringUtils.isBlank(balanceAcctId)) { balanceAcctId = chinaumsAuthInfo.getBalanceAcctId(); } // Map<String, String> map = new HashMap<>(); // map.put("balanceAcctId", balanceAcctId); // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_BALANCE_ACCTS_QRY, (JSONObject) JSONObject.toJSON(map), BalanceAcctsVO.class); BalanceAcctsVO balanceAcctsVO = new BalanceAcctsVO(); ByxQueryAcctBalDTO byxQueryAcctBalDTO = new ByxQueryAcctBalDTO(); byxQueryAcctBalDTO.setWalletId(balanceAcctId); // byxTradeWayService.setCert(byxQueryAcctBalDTO, company.getWalletId()); ByxQueryAcctBalVO byxQueryAcctBalVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_BALANCE_ACCTS_QRY,(JSONObject) JSONObject.toJSON(byxQueryAcctBalDTO),ByxQueryAcctBalVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxQueryAcctBalVO.getRspCode())){ balanceAcctsVO.setBalanceAcctId(byxQueryAcctBalVO.getWalletId()); balanceAcctsVO.setRelAcctNo(chinaumsAuthInfo.getRelAcctNo()); balanceAcctsVO.setSettledAmount(Convert.toLong( byxQueryAcctBalVO.getAvlblAmt())); balanceAcctsVO.setFrozenSettledAmount(Convert.toLong(byxQueryAcctBalVO.getFrznAmt())); balanceAcctsVO.setPendingAmount(BigDecimal.ZERO.longValue()); ByxQueryAcctInfoDTO byxQueryAcctInfoDTO = new ByxQueryAcctInfoDTO(); byxQueryAcctInfoDTO.setWalletId(company.getWalletId()); ByxQueryAcctInfoVO byxQueryAcctInfoVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_QUERY_ACCOUNT_INFORMATION,(JSONObject) JSONObject.toJSON(byxQueryAcctInfoDTO),ByxQueryAcctInfoVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxQueryAcctInfoVO.getRspCode())){ if("2".equals(byxQueryAcctInfoVO.getAcctStatus())){ balanceAcctsVO.setIsFrozen(true); } else { balanceAcctsVO.setIsFrozen(false); } } } return balanceAcctsVO; } @Override public BalanceTransactionsPageVO balanceTransactions(String balanceAcctId,String transOrderNo, String startAt, String endAt) { // if (StringUtils.isBlank(balanceAcctId)) { // balanceAcctId = getUser().getCompany().getWalletId(); // } // Map<String, Object> map = new HashMap<>(); // map.put("balanceAcctId", balanceAcctId); // // 必须小于等于100 // map.put("size", 100); // if (StringUtils.isNotBlank(startAt)) { // map.put("startAt", startAt.replace(" ", "+")); // } // if (StringUtils.isNotBlank(endAt)) { // map.put("endAt", endAt.replace(" ", "+")); // } // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_BALANCE_TRANSACTIONS, (JSONObject) JSONObject.toJSON(map), BalanceTransactionsPageVO.class); BalanceTransactionsPageVO balanceTransactionsPageVO = new BalanceTransactionsPageVO(); ByxQueryTransListDTO byxQueryTransListDTO = new ByxQueryTransListDTO(); if (StringUtils.isBlank(balanceAcctId)) { balanceAcctId = getUser().getCompany().getWalletId(); } byxQueryTransListDTO.setWalletId(balanceAcctId); // 必须小于等于50 byxQueryTransListDTO.setPageSize("50"); byxQueryTransListDTO.setPageNo("1"); if (StrUtil.isBlank(startAt)) { startAt = DateUtil.now(); } if (StrUtil.isBlank(endAt)) { endAt = startAt; } byxQueryTransListDTO.setStartDate(DateUtil.format(Convert.toLocalDateTime(startAt), "yyyyMMdd") ); byxQueryTransListDTO.setEndDate(DateUtil.format(Convert.toLocalDateTime(endAt), "yyyyMMdd") ); if(null!=transOrderNo){ byxQueryTransListDTO.setTransOrderNo(transOrderNo); } //log.info("byxQueryTransListDTO:{}",byxQueryTransListDTO); // byxTradeWayService.setTradeWayInCert(byxQueryTransListDTO,balanceAcctId); ByxQueryTransListVO byxQueryTransListVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_BALANCE_TRANSACTIONS, (JSONObject) JSONObject.toJSON(byxQueryTransListDTO), ByxQueryTransListVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxQueryTransListVO.getRspCode())){ balanceTransactionsPageVO.setSize(Convert.toInt(byxQueryTransListVO.getPageSize()) ); balanceTransactionsPageVO.setPage(Convert.toInt(byxQueryTransListVO.getPageNo()) ); balanceTransactionsPageVO.setTotal(Convert.toInt(byxQueryTransListVO.getTotal()) ); List<BalanceTransactionsPageVO.BalanceTransactionsVO> data = new ArrayList<>(); if(ObjectUtil.isNotEmpty(byxQueryTransListVO.getRowList())){ for (ByxQueryTransListRowVO byxQueryTransListRowVO : byxQueryTransListVO.getRowList()) { BalanceTransactionsPageVO.BalanceTransactionsVO balanceTransactionsVO = new BalanceTransactionsPageVO.BalanceTransactionsVO(); balanceTransactionsVO.setBalanceAcctId(byxQueryTransListRowVO.getWalletId()); balanceTransactionsVO.setTradeId(byxQueryTransListRowVO.getTransOrderNo()); balanceTransactionsVO.setOutOrderNo(byxQueryTransListRowVO.getMctOrderNo()); balanceTransactionsVO.setAmtSymbol(byxQueryTransListRowVO.getAmtSymbol()); if("+".equals(byxQueryTransListRowVO.getAmtSymbol())){ // amtSymbol+表示入金,-表示出金 // tradeType 11 --> 转账入金 balanceTransactionsVO.setTradeType(11); } if("-".equals(byxQueryTransListRowVO.getAmtSymbol())){ // amtSymbol+表示入金,-表示出金 // tradeType 40 --> 消费(转账) balanceTransactionsVO.setTradeType(40); } balanceTransactionsVO.setSettledAmount(Convert.toLong(byxQueryTransListRowVO.getTransAmt()) ); balanceTransactionsVO.setRemark(byxQueryTransListRowVO.getRemark()); balanceTransactionsVO.setSucceededAt(DateTimeUtils.getDateTimeToRFC3339(byxQueryTransListRowVO.getProcTime())); data.add(balanceTransactionsVO); } } balanceTransactionsPageVO.setData(data); } return balanceTransactionsPageVO; } @Override public ChinaumsRechargeAccountVO getWalletRechargeAccount() { Company company = getUser().getCompany(); ChinaumsAuthInfo chinaumsAuthInfo = chinaumsAuthInfoRepository.findFirstByCompanyId(company.getId()); if (chinaumsAuthInfo == null) { throw new YnceErrorException(YnceError.YNCE_218009); } ChinaumsRechargeAccountVO chinaumsRechargeAccountVO = new ChinaumsRechargeAccountVO(); chinaumsRechargeAccountVO.setAccountName(chinaumsAuthInfo.getBindAcctName()); chinaumsRechargeAccountVO.setAccountNumber(chinaumsAuthInfo.getRelAcctNo()); return chinaumsRechargeAccountVO; } private Order getOrderAndCheck(WalletOrderPayDTO walletOrderPayDTO) { Order order = orderRepository.findById(walletOrderPayDTO.getOrderId()).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_204003); } if (!order.getApprovalStatus().equals(ApprovalStatus.APPROVE)) { throw new YnceErrorException(YnceError.YNCE_204016); } if (!order.getPaymentStatus().equals(PaymentStatus.UN_PAID)) { throw new YnceErrorException(YnceError.YNCE_204015); } return order; } /** * 电子账本 订单支付 * @Description step 1.根据订单ID查询预存款的支付单 * step 2.如果支付单不存在,则创建支付单号及费用明细,否则直接返回支付单的银联支付号 * step 3.调用银行下单及支付接口---调用下单返回银行订单号,通过银行订单号调用支付接口,返回银行交易单号 * step 4.如果支付成功则保存银行交易单号并更新支付状态, 否则保存失败状态 * step 5.根据订单对应的所有明细支付信息创建对应的银联支付单号并保存入库 * @param walletOrderPayDTO:订单支付DTO * @return String----银联支付单号 */ @Override public String orderPay(WalletOrderPayDTO walletOrderPayDTO) { if (walletOrderPayDTO.getOrderId() == null) { log.error("支付失败,订单号为空"); throw new YnceErrorException(YnceError.YNCE_204003); } if (StringUtils.isEmpty(walletOrderPayDTO.getPassword())) { log.error("密码不为空"); throw new YnceErrorException(YnceError.YNCE_204101); } if (StringUtils.isEmpty(walletOrderPayDTO.getPlugRandomKey())) { log.error("随机因子不为空"); throw new YnceErrorException(YnceError.YNCE_204101); } Order order = getOrderAndCheck(walletOrderPayDTO); // 获取预存款的支付单, 订单和支付单是1:1关系 Payment payment = paymentRepository.findFirstByOrderIdAndPaymentMethod(order.getId().toString(), PaymentMethod.DEPOSIT); if (payment != null && PayStatus.SUCC.equals(payment.getPayStatus())) { return payment.getExternalId(); } // 银联钱包的支付和下单是实时的,返回数据要么成功要么失败 // 校验 this.checkBalance(order, payment); // 平台支付单号 String paymentSn = ""; // 创建支付单 if (payment == null) { paymentSn = subaccountService.createPayment(order, null, UnionpayAppOrderType.DEPOSIT, null, null, null); } // 处理费用等 List<ChinaumsGuaranteePayParamsDTO> chinaumsGuaranteePayParamsDTOList = this.getChinaumsGuaranteePayParamsDTO(order); // 判断金额是否一致 BigDecimal totalAmount = new BigDecimal(chinaumsGuaranteePayParamsDTOList.stream().mapToInt(ChinaumsGuaranteePayParamsDTO::getAmount).sum()); if (totalAmount.compareTo(order.getAmount().multiply(new BigDecimal(100))) != 0) { log.error("银联请求参数总金额" + totalAmount + "与订单支付金额" + order.getAmount() + "不一致"); throw new YnceErrorException(YnceError.YNCE_218006); } // 发送 下单 String guaranteedOrderNo = this.sendChinaumsOrder(order); if (StringUtils.isEmpty(guaranteedOrderNo)) { throw new YnceErrorException("系统异常,支付失败"); } payment = paymentRepository.findFirstBySnOrderByIdDesc(paymentSn); payment.setExternalId(guaranteedOrderNo); paymentRepository.saveAndFlush(payment); // 发送 支付-------支付接口是实时返回成功或失败,判断条件是rspCode为00000 JSONObject jsonObject = this.sendChinaumsPay(order, paymentSn, guaranteedOrderNo, walletOrderPayDTO); if (jsonObject == null || jsonObject.get("rspCode") == null || jsonObject.get("transOrderNo") == null) { throw new YnceErrorException("系统异常,支付失败"); } log.info("支付成功:" + jsonObject.toJSONString()); // payment = paymentRepository.findFirstBySnOrderByIdDesc(paymentSn); // String transOrderNo = jsonObject.get("transOrderNo").toString(); // 支付成功 if (jsonObject.get("rspCode").equals("00000")) { // 修改支付单状态 payment.setPayStatus(PayStatus.SUCC); payment.setPaymentTime(LocalDateTime.now()); payment.setExternalId(guaranteedOrderNo); payment.setUnionpaySn(guaranteedOrderNo); paymentRepository.saveAndFlush(payment); // try { // // // 若订单未支付进行回调处理 // if (PaymentStatus.UN_PAID.equals(order.getPaymentStatus())) { // // 生成收款单以及后续业务操作 // OrderOnlinePayVO orderOnlinePayVO = new OrderOnlinePayVO(); // orderOnlinePayVO.setOrderId(Long.valueOf(payment.getOrderId())); // orderOnlinePayVO.setPaymentId(payment.getId()); // orderOnlinePayVO.setExternalId(payment.getExternalId()); // JSONObject result = HttpClientUtil.getInstance().sendPost(thirdPartyConfigUtil.getPlatform().getServiceUrl() + RouteUtil.ROUTE_RECEIPT_ONLINE_PAY, orderOnlinePayVO); // if (!"200".equals(result.get("code").toString())) { // log.error("预存款支付回调失败:请求收款失败"); // } // } this.handlePayStateSuccess(order, guaranteedOrderNo, chinaumsGuaranteePayParamsDTOList); // } catch (Exception e) { // log.error(e.getMessage()); // throw new YnceErrorException("支付处理失败"); // } return payment.getExternalId(); } // 当支付失败时,抛出异常 payment.setPayStatus(PayStatus.FAILED); payment.setExternalId(guaranteedOrderNo); paymentRepository.saveAndFlush(payment); throw new YnceErrorException(YnceError.YNCE_218033); } private void checkBalance(Order order, Payment payment) { // 获取电子账户余额 BigDecimal balance; try { BalanceAcctsVO balanceAcctsVO = this.balanceAcctsQryByAcctId(null); balance = new BigDecimal(balanceAcctsVO.getSettledAmount() + balanceAcctsVO.getPendingAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } catch (Exception exception) { throw new YnceErrorException(YnceError.YNCE_205010); } // 校验 this.checkCondition(order, payment, balance); } private String sendChinaumsOrder(Order order) { ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); String subject = order.getOrderItems().get(0).getGoodsName(); if (StringUtils.isNotEmpty(order.getInvoiceContent())) { subject = order.getRemark(); } else if (StringUtils.isNotEmpty(order.getRemark())) { subject = order.getRemark(); } ByxChinaumsGuaranteeOrderParamsDTO byxChinaumsGuaranteeOrderParamsDTO = ByxChinaumsGuaranteeOrderParamsDTO .builder() .mctOrderNo(order.getId()) .oprType(1) .buyerWalletId(order.getBuyerCompany().getWalletId()) .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .merWalletId(order.getSellerCompany().getWalletId()) .merName(order.getSellerCompany().getName()) .orderAmt(order.getAmount().multiply(new BigDecimal(100)).longValue()) .subject(subject) .payTimeoutExpress("1h") .notifyUrl(thirdPartyPaySet.getThirdPartyUrl() + "/chinaums/call_back/byx/result") .remark(order.getRemark()) .build(); JSONObject requestJsonObject = (JSONObject) JSONObject.toJSON(byxChinaumsGuaranteeOrderParamsDTO); try { log.info("===========================调用银联下单接口"); JSONObject jsonObject = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLECT_COMBINED_GUARANTEE_ORDER, requestJsonObject, JSONObject.class); if ("10004".equals(jsonObject.get("rspCode").toString())) { ByxChinaumsGuaranteePayVO byxChinaumsGuaranteePayVO = this.orderPaymentsByOutOrderNo(order.getId().toString(), thirdPartyPaySet.getChinaumsFeeBalanceAcctId()); return byxChinaumsGuaranteePayVO.getGuaranteedOrderNo(); } return jsonObject.get("guaranteedOrderNo").toString(); } catch (Exception exception) { log.error("银联请求合并消费担保下单失败:" + exception.getMessage()); } return null; } private JSONObject sendChinaumsPay(Order order, String paymentSn, String guaranteedOrderNo, WalletOrderPayDTO walletOrderPayDTO) { log.info("===========================调用银联支付接口"); // 参数准备 ByxChinaumsGuaranteePayParamsDTO byxChinaumsGuaranteePayParamsDTO = getByxChinaumsGuaranteePayParamsDTO(order, paymentSn, guaranteedOrderNo, walletOrderPayDTO); JSONObject requestJsonObject = (JSONObject) JSONObject.toJSON(byxChinaumsGuaranteePayParamsDTO); try { return byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS, requestJsonObject, JSONObject.class); } catch (Exception exception) { log.error("银联请求合并消费担保下单失败:" + exception.getMessage()); } return null; } private void handlePayStateSuccess(Order order, String guaranteedOrderNo, List<ChinaumsGuaranteePayParamsDTO> chinaumsGuaranteePayParamsDTOList) { // 保存担保消费子订单信息 for (ChinaumsGuaranteePayParamsDTO chinaumsGuaranteePayParamsDTO : chinaumsGuaranteePayParamsDTOList) { if (chinaumsGuaranteePayParamsDTO.getMetadata() != null) { // 没有合并数据的子订单 if (chinaumsGuaranteePayParamsDTO.getMetadata().getBrandFee() == null && CollectionUtils.isEmpty(chinaumsGuaranteePayParamsDTO.getMetadata().getBrandList())) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(chinaumsGuaranteePayParamsDTO, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(chinaumsGuaranteePayParamsDTO.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setGuaranteePaymentId(guaranteedOrderNo); chinaumsPayment.setSubaccountType(SubaccountType.valueOf(chinaumsGuaranteePayParamsDTO.getMetadata().getSubaccountType())); chinaumsPaymentRepository.save(chinaumsPayment); } else { // 品牌费处理 if (chinaumsGuaranteePayParamsDTO.getMetadata().getBrandFee() != null) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(chinaumsGuaranteePayParamsDTO, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(chinaumsGuaranteePayParamsDTO.getMetadata().getBrandFee()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setGuaranteePaymentId(guaranteedOrderNo); chinaumsPayment.setSubaccountType(SubaccountType.BRAND_FEE); chinaumsPaymentRepository.save(chinaumsPayment); } // 品牌授权费处理 if (CollectionUtils.isNotEmpty(chinaumsGuaranteePayParamsDTO.getMetadata().getBrandList())) { for (GuaranteePayMetaDataBrandDTO guaranteePayMetaDataBrand : chinaumsGuaranteePayParamsDTO.getMetadata().getBrandList()) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(chinaumsGuaranteePayParamsDTO, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(guaranteePayMetaDataBrand.getBrandAuthFee()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setGuaranteePaymentId(guaranteedOrderNo); chinaumsPayment.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); chinaumsPayment.setBrandId(Long.valueOf(guaranteePayMetaDataBrand.getBrandId())); chinaumsPaymentRepository.save(chinaumsPayment); } } } } else { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); chinaumsPayment.setRecvBalanceAcctId(chinaumsGuaranteePayParamsDTO.getRecvBalanceAcctId()); chinaumsPayment.setRemark(chinaumsGuaranteePayParamsDTO.getRemark()); chinaumsPayment.setOutOrderNo(chinaumsGuaranteePayParamsDTO.getOutOrderNo()); chinaumsPayment.setAmount(new BigDecimal(chinaumsGuaranteePayParamsDTO.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setGuaranteePaymentId(guaranteedOrderNo); chinaumsPaymentRepository.save(chinaumsPayment); } } } private void checkCondition(Order order, Payment payment, BigDecimal balance) { // 跟平台预存款余额比较,若不一致则抛出异常 Account depositAccount = accountRepository.findDepositAccount(order.getBuyerCompany().getId()); if (depositAccount.getBalance().compareTo(balance) != 0) { throw new YnceErrorException(YnceError.YNCE_205010); } // 判断余额是否充足 if (balance.compareTo(BigDecimal.ZERO) < 1 || balance.compareTo(order.getAmount()) == -1) { throw new YnceErrorException(YnceError.YNCE_205001); } // 获取处理中的预存款支付订单金额 BigDecimal progressPaymentAmount = paymentRepository.getProgressPaymentAmount(order.getBuyerCompany().getId()); if (progressPaymentAmount.compareTo(BigDecimal.ZERO) == 1) { // 若存在支付单,则预存款支付订单金额需减去该支付单金额 if (payment != null) { progressPaymentAmount = progressPaymentAmount.subtract(payment.getAmount()); } // 若存在处理中的,则判断余额是否足够 balance = balance.subtract(progressPaymentAmount); if (balance.compareTo(BigDecimal.ZERO) < 1 || balance.compareTo(order.getAmount()) == -1) { throw new YnceErrorException(YnceError.YNCE_205011); } } } private ByxChinaumsGuaranteePayParamsDTO getByxChinaumsGuaranteePayParamsDTO(Order order, String paymentSn, String guaranteedOrderNo, WalletOrderPayDTO walletOrderPayDTO) { ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); String subject = order.getOrderItems().get(0).getGoodsName(); if (StringUtils.isNotEmpty(order.getInvoiceContent())) { subject = order.getRemark(); } else if (StringUtils.isNotEmpty(order.getRemark())) { subject = order.getRemark(); } ByxChinaumsGuaranteePayParamsDTO byxChinaumsGuaranteePayParamsDTO = ByxChinaumsGuaranteePayParamsDTO .builder() .mctOrderNo(paymentSn) .guaranteedOrderNo(guaranteedOrderNo) .oprType(1) .payType("00") .buyerWalletId(order.getBuyerCompany().getWalletId()) .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .merWalletId(order.getSellerCompany().getWalletId()) .merName(order.getSellerCompany().getName()) .orderAmt(order.getAmount().multiply(new BigDecimal(100)).longValue()) .subject(subject) .payTimeoutExpress("1h") .notifyUrl(thirdPartyPaySet.getThirdPartyUrl() + "/chinaums/call_back/byx/result") .remark(order.getRemark()) .build(); byxChinaumsGuaranteePayParamsDTO.setEncryptPwd(walletOrderPayDTO.getPassword()); byxChinaumsGuaranteePayParamsDTO.setPlugRandomKey(walletOrderPayDTO.getPlugRandomKey()); // byxTradeWayService.setTradeWayInCert(byxChinaumsGuaranteePayParamsDTO, order.getBuyerCompany().getWalletId()); byxTradeWayService.setTradeWayByBPass(byxChinaumsGuaranteePayParamsDTO); return byxChinaumsGuaranteePayParamsDTO; } /** * 银联支付查询-通过平台单号 * * @param mctOrderNo 支付单号 * @return 银联合并消费担保下单VO * @author huabiao * @create 2023/10/17 15:07 */ @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) @Override public ByxChinaumsGuaranteePayVO orderPaymentsByOutOrderNo(String mctOrderNo, String platformWalletId) { ByxChinaumsGuaranteePayVO byxChinaumsGuaranteePayVO = new ByxChinaumsGuaranteePayVO(); try { JSONObject jsonObject = new JSONObject(); jsonObject.put("mctOrderNo", mctOrderNo); jsonObject.put("platformWalletId", platformWalletId); byxChinaumsGuaranteePayVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_QUERY_INFO, jsonObject, ByxChinaumsGuaranteePayVO.class); } catch (Exception exception) { byxChinaumsGuaranteePayVO.setRspMsg(exception.getMessage()); } return byxChinaumsGuaranteePayVO; } @Override @Transactional(rollbackFor = Exception.class) public AccountPaymentsVO payments(AccountPaymentsDTO accountPaymentsDTO) { ByxTransferDTO byxTransferDTO = new ByxTransferDTO(); AccountPaymentsVO accountPaymentsVO = new AccountPaymentsVO(); if (StringUtils.isBlank(accountPaymentsDTO.getPayBalanceAcctId())) { Company company = getUser().getCompany(); accountPaymentsDTO.setPayBalanceAcctId(company.getWalletId()); } byxTransferDTO.setMctOrderNo(accountPaymentsDTO.getOutOrderNo()); byxTransferDTO.setFromWalletId(accountPaymentsDTO.getPayBalanceAcctId()); byxTransferDTO.setIntoWalletId(accountPaymentsDTO.getRecvBalanceAcctId()); byxTransferDTO.setTransferAmt(Convert.toStr(accountPaymentsDTO.getAmount()) ); // byxTradeWayService.setTradeWayInCert(); // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_PAYMENTS, (JSONObject) JSONObject.toJSON(accountPaymentsDTO), AccountPaymentsVO.class); byxTransferDTO.setPlugRandomKey(accountPaymentsDTO.getPlugRandomKey()); byxTransferDTO.setEncryptPwd(accountPaymentsDTO.getPassword()); byxTradeWayService.setTradeWayByBPass(byxTransferDTO); ByxTransferVO byxTransferVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_PAYMENTS, (JSONObject) JSONObject.toJSON(byxTransferDTO), ByxTransferVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxTransferVO.getRspCode())){ accountPaymentsVO.setStatus( TransferState.SUCCESS.getValue()); } else { accountPaymentsVO.setStatus(TransferState.FAIL.getValue()); accountPaymentsVO.setReason(byxTransferVO.getRspResult()); } accountPaymentsVO.setPaymentId(byxTransferVO.getTransOrderNo()); accountPaymentsVO.setOutOrderNo(byxTransferVO.getTransOrderNo()); accountPaymentsVO.setTotalAmount(accountPaymentsDTO.getTotalAmount() ); accountPaymentsVO.setAmount(accountPaymentsDTO.getAmount() ); accountPaymentsVO.setDiscountAmount(accountPaymentsDTO.getDiscountAmount() ); accountPaymentsVO.setCreatedAt(accountPaymentsDTO.getSentAt() ); accountPaymentsVO.setFinishedAt(DateTimeUtils.getDateTimeToRFC3339(DateUtil.format(LocalDateTimeUtil.now(),"yyyyMMddHHmmss") ) ); accountPaymentsVO.setPayBalanceAcctId(accountPaymentsDTO.getPayBalanceAcctId()); accountPaymentsVO.setRecvBalanceAcctId(accountPaymentsDTO.getRecvBalanceAcctId()); ExternalIncomeDTO externalIncomeDTO = new ExternalIncomeDTO(); externalIncomeDTO.setAmount(accountPaymentsVO.getAmount()); externalIncomeDTO.setTradeId(accountPaymentsVO.getPaymentId()); externalIncomeDTO.setPayBalanceAcctId(accountPaymentsVO.getPayBalanceAcctId()); externalIncomeDTO.setBalanceAcctId(accountPaymentsVO.getRecvBalanceAcctId()); externalIncomeDTO.setTransactionNo(accountPaymentsVO.getPaymentId()); externalIncomeDTO.setTradeId(accountPaymentsVO.getPaymentId()); externalIncomeDTO.setRecordedAt(accountPaymentsVO.getFinishedAt()); externalIncomeDTO.setCreatedAt(accountPaymentsVO.getCreatedAt()); externalIncomeDTO.setBankMemo(accountPaymentsVO.getRemark()); externalIncomeDTO.setOrigOutOrderNo(accountPaymentsVO.getOutOrderNo()); paymentCallBack(externalIncomeDTO); return accountPaymentsVO; } /** * 分账退款 * @param byxChinaumsRefundDTO----byxChinaumsRefundDTO * @return ByxChinaumsRefundVO */ public ByxChinaumsRefundVO refundForProfitSharing(ByxChinaumsRefundDTO byxChinaumsRefundDTO) { if (StringUtils.isBlank(byxChinaumsRefundDTO.getPlatformWalletId())) { ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); byxChinaumsRefundDTO.setPlatformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()); } ByxChinaumsRefundVO byxChinaumsRefundVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_REFUND, (JSONObject) JSONObject.toJSON(byxChinaumsRefundDTO), ByxChinaumsRefundVO.class); if (byxChinaumsRefundVO == null) { log.error("系统异常,退款失败: ROUTE_WALLET_REFUND接口返回为空"); throw new YnceErrorException("系统异常,退款失败"); } return byxChinaumsRefundVO; } @Override public AccountPaymentsVO paymentsByOutOrderNo(String outOrderNo) { // Map<String, String> map = new HashMap<String, String>() {{ // put("outOrderNo", outOrderNo); // }}; // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_PAYMENTS_BY_OUT_ORDER_NO, (JSONObject) JSONObject.toJSON(byxQueryConsumePayOrderInfoDTO), AccountPaymentsVO.class); AccountPaymentsVO accountPaymentsVO = new AccountPaymentsVO(); ByxQueryConsumePayOrderInfoDTO byxQueryConsumePayOrderInfoDTO = new ByxQueryConsumePayOrderInfoDTO(); byxQueryConsumePayOrderInfoDTO.setGuaranteedOrderNo(outOrderNo); ByxQueryConsumePayOrderInfoVO byxQueryConsumePayOrderInfoVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_PAYMENTS_BY_OUT_ORDER_NO, (JSONObject) JSONObject.toJSON(byxQueryConsumePayOrderInfoDTO), ByxQueryConsumePayOrderInfoVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxQueryConsumePayOrderInfoVO.getRspCode())){ accountPaymentsVO.setPaymentId(byxQueryConsumePayOrderInfoVO.getMctOrderNo()); accountPaymentsVO.setOutOrderNo(byxQueryConsumePayOrderInfoVO.getGuaranteedOrderNo()); accountPaymentsVO.setAmount(Convert.toLong(byxQueryConsumePayOrderInfoVO.getActPayedAmt()) ); accountPaymentsVO.setTotalAmount(Convert.toLong(byxQueryConsumePayOrderInfoVO.getOrderAmt()) ); accountPaymentsVO.setRefundedAmount(Convert.toLong(byxQueryConsumePayOrderInfoVO.getRefundedAmt()) ); if(ObjectUtil.isNotEmpty(byxQueryConsumePayOrderInfoVO.getByxQueryOrderDetailPayRowVOList())){ ByxQueryOrderDetailPayRowVO byxQueryOrderDetailPayRowVO = byxQueryConsumePayOrderInfoVO.getByxQueryOrderDetailPayRowVOList().get(0); ByxQueryOrderDetailSettRowVO byxQueryOrderDetailSettRowVO = byxQueryConsumePayOrderInfoVO.getByxQueryOrderDetailSettRowVOList().get(0); if(OrderPayStatusEnum.PAYMENT_SUCCESSFUL.getValue().equals(byxQueryOrderDetailPayRowVO.getPayStatus())){ accountPaymentsVO.setStatus(OrderPaymentStatusEnum.SUCCEEDED.getValue()); } else if(OrderPayStatusEnum.SUBMITTED_PAYMENT.getValue().equals(byxQueryOrderDetailPayRowVO.getPayStatus())){ accountPaymentsVO.setStatus(OrderPaymentStatusEnum.PROCESSING.getValue()); } else if(OrderPayStatusEnum.PAYMENT_FAILED.getValue().equals(byxQueryOrderDetailPayRowVO.getPayStatus())){ accountPaymentsVO.setStatus(OrderPaymentStatusEnum.FAILED.getValue()); } // 类型为普通订单支付和合并支付时,返回订单金额。 类型为补充支付时,返回交易金额 if("02".equals(byxQueryOrderDetailPayRowVO.getType()) ){ accountPaymentsVO.setAmount(Convert.toLong(byxQueryOrderDetailPayRowVO.getPayAmt())); } else { accountPaymentsVO.setTotalAmount(Convert.toLong(byxQueryOrderDetailPayRowVO.getPayAmt())); } accountPaymentsVO.setFinishedAt(DateTimeUtils.getDateTimeToRFC3339(byxQueryOrderDetailSettRowVO.getSettTime())); } } else { accountPaymentsVO.setStatus(OrderPaymentStatusEnum.FAILED.getValue()); accountPaymentsVO.setReason(byxQueryConsumePayOrderInfoVO.getRspResult()); } return accountPaymentsVO; } @Override @Transactional(rollbackFor = Exception.class) public WithdrawalsVO withdrawals(WithdrawalsDTO withdrawalsDTO) { // Company company = getUser().getCompany(); // ByxAsyncWithdrawDTO byxAsyncWithdrawDTO = new ByxAsyncWithdrawDTO(); // if (StringUtils.isBlank(withdrawalsDTO.getBalanceAcctId())) { // withdrawalsDTO.setBalanceAcctId(company.getWalletId()); // } // withdrawalsDTO.setBusinessType("1"); // if (StringUtils.isBlank(withdrawalsDTO.getBankAcctNo())) { // ChinaumsAuthInfo chinaumsAuthInfo = chinaumsAuthInfoRepository.findFirstByCompanyId(company.getId()); // if (chinaumsAuthInfo == null) { // throw new YnceErrorException("获取银联认证信息失败"); // } // String publicKey = chinaumsUtil.getPublicKey(); // try { // withdrawalsDTO.setBankAcctNo(RSAEncryptorUtil.encryptByPublicKey(chinaumsAuthInfo.getSettleAcctBankAcctNo(), publicKey)); // } catch (Exception e) { // throw new RuntimeException(e); // } // } // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_WITHDRAWALS, (JSONObject) JSONObject.toJSON(withdrawalsDTO), WithdrawalsVO.class); // log.error("withdrawalsDTO:{}",withdrawalsDTO); WithdrawalsVO withdrawalsVO = new WithdrawalsVO(); Company company = getUser().getCompany(); ByxAsyncWithdrawDTO byxAsyncWithdrawDTO = new ByxAsyncWithdrawDTO(); if (StringUtils.isBlank(withdrawalsDTO.getBalanceAcctId())) { byxAsyncWithdrawDTO.setWalletId(company.getWalletId()); } else { byxAsyncWithdrawDTO.setWalletId(withdrawalsDTO.getBalanceAcctId()); } if (StringUtils.isBlank(withdrawalsDTO.getBankAcctNo())) { ChinaumsAuthInfo chinaumsAuthInfo = chinaumsAuthInfoRepository.findFirstByCompanyId(company.getId()); if (chinaumsAuthInfo == null) { throw new YnceErrorException("获取银联认证信息失败"); } } withdrawalsVO.setBusinessType("1"); withdrawalsVO.setBalanceAcctId(company.getWalletId()); withdrawalsVO.setAmount(Convert.toStr(withdrawalsDTO.getAmount()) ); withdrawalsVO.setOutOrderNo(withdrawalsDTO.getOutOrderNo()); withdrawalsVO.setCreatedAt(withdrawalsDTO.getSentAt()); withdrawalsVO.setServiceFee(Convert.toInt(withdrawalsDTO.getServiceFee()) ); // 提现金额 byxAsyncWithdrawDTO.setAmount(Convert.toStr(withdrawalsDTO.getAmount())); // 我们的订单号 byxAsyncWithdrawDTO.setMctOrderNo(withdrawalsDTO.getOutOrderNo()); byxAsyncWithdrawDTO.setPlugRandomKey(withdrawalsDTO.getPlugRandomKey()); byxAsyncWithdrawDTO.setEncryptPwd(withdrawalsDTO.getPassword()); byxTradeWayService.setTradeWayByBPass(byxAsyncWithdrawDTO); log.error("byxAsyncWithdrawDTO:{}",byxAsyncWithdrawDTO); ByxAsyncWithdrawVO byxAsyncWithdrawVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_WITHDRAWALS, (JSONObject) JSONObject.toJSON(byxAsyncWithdrawDTO), ByxAsyncWithdrawVO.class); // 20000:表示处理中。 通过调用查询交易结果查询最终交易状态。 if("20000".equals(byxAsyncWithdrawVO.getRspCode())){ withdrawalsVO.setStatus("processing"); withdrawalsVO.setWithdrawalId(byxAsyncWithdrawVO.getTransOrderNo()); // withdrawalsCallBack(withdrawalsVO.getOutOrderNo()); } else { withdrawalsVO.setStatus("failed"); withdrawalsVO.setReason(byxAsyncWithdrawVO.getRspResult()); } return withdrawalsVO; } @Override @Transactional(rollbackFor = Exception.class) public void withdrawalsCallBack(String outOrderNo) { AllinpayMutual allinpayMutual = allinpayMutualRepository.findFirstByBizOrderNo(outOrderNo); if (allinpayMutual == null) { log.error("未查询到提现记录!!!"); return; } if (DealStatus.DEALSTATUS_SUCC.equals(allinpayMutual.getDealStatus())) { log.warn("提现状态已更新!!!"); return; } WithdrawalsVO withdrawalsVO = withdrawalsByOutOrderNo(outOrderNo); if (withdrawalsVO == null) { log.error("【提现订单查询(平台订单号)】在银联未查询到记录!!!"); return; } if (!"processing".equals(withdrawalsVO.getStatus())) { Long companyId = allinpayMutual.getCompany().getId(); Account account = accountRepository.findDepositAccount(companyId); if (account == null) { throw new YnceErrorException("账户不存在"); } unionpayAccountService.withdrawalsHandle(account, withdrawalsVO); } } @Override @Transactional public WithdrawalsVO withdrawalsByOutOrderNo(String outOrderNo) { // Map<String, String> map = new HashMap<String, String>() {{ // put("outOrderNo", outOrderNo); // }}; // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_WITHDRAWALS_BY_OUT_ORDER_NO, (JSONObject) JSONObject.toJSON(map), WithdrawalsVO.class); WithdrawalsVO withdrawalsVO = new WithdrawalsVO(); AllinpayMutual allinpayMutual = allinpayMutualRepository.findFirstByBizOrderNo(outOrderNo); if(ObjectUtil.isNull(allinpayMutual)){ throw new YnceErrorException("未查询到提现记录!!!"); } // Company company = allinpayMutual.getCompany(); // if(ObjectUtil.isNull(company)){ // throw new YnceErrorException(YnceError.YNCE_201009); // } // ChinaumsAuthInfo chinaumsAuthInfo = company.getChinaumsAuthInfo(); // if( ObjectUtil.isNull(chinaumsAuthInfo)){ // throw new YnceErrorException(YnceError.YNCE_218009); // } ByxQueryTransResultDTO byxQueryTransResultDTO = new ByxQueryTransResultDTO(); byxQueryTransResultDTO.setWalletId(chinaumsAuthInfo.getBalanceAcctId()); byxQueryTransResultDTO.setMctOrderNo(allinpayMutual.getBizOrderNo()); // byxTradeWayService.setTradeWayInCert(byxQueryTransResultDTO,byxQueryTransResultDTO.getWalletId()); // log.info("提现回调查询:{}",byxQueryTransResultDTO); ByxQueryTransResultVO byxQueryTransResultVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_WITHDRAWALS_BY_OUT_ORDER_NO, (JSONObject) JSONObject.toJSON(byxQueryTransResultDTO), ByxQueryTransResultVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxQueryTransResultVO.getRspCode())){ if(ObjectUtil.isNotEmpty(byxQueryTransResultVO.getRowList())){ ByxQueryTransResultRowVO byxQueryTransResultRowVO = byxQueryTransResultVO.getRowList().get(0); withdrawalsVO.setWithdrawalId(allinpayMutual.getOriBizOrderNo()); withdrawalsVO.setOutOrderNo(outOrderNo); withdrawalsVO.setReason(byxQueryTransResultRowVO.getProcResultDscrb()); withdrawalsVO.setFinishedAt(DateTimeUtils.getDateTimeToRFC3339(byxQueryTransResultRowVO.getTransTime()) ); withdrawalsVO.setAmount(byxQueryTransResultRowVO.getSettAmt()); if("0".equals(byxQueryTransResultRowVO.getProcStatus()) || "5".equals(byxQueryTransResultRowVO.getProcStatus())){ withdrawalsVO.setStatus("processing"); } else if("1".equals(byxQueryTransResultRowVO.getProcStatus())){ withdrawalsVO.setStatus("succeeded"); } else { withdrawalsVO.setStatus("failed"); } } } return withdrawalsVO; } @Transactional(rollbackFor = Exception.class) @Override public boolean tradeResult(TradeResultDTO tradeResultDTO) { /* * 20: 支付充值; * 21: 充值退款; * 25: 可提现支付充值; * 30: 单笔提现/批量提现申请; * 40: 消费; * 41: 消费退款; * 51: 分账; * 52: 合并支付充值; * 53: 批量提现确认; * 60: 担保下单; * 62: 担保未确认退款; * 63: 担保已确认退款; * 64: 担保支付; * 66: 担保支付退款; * 67: 担保支付确认退款; * 73: 资金调拨; * 74: 提前入账 * 81: 收单通道验证打款 */ Integer tradeType = tradeResultDTO.getTradeType(); switch (tradeType) { // 支付充值 case 20: break; // 单笔提现/批量提现申请 case 30: AllinpayMutual allinpayMutual = allinpayMutualRepository.findFirstByBizOrderNo(tradeResultDTO.getOutOrderNo()); if (allinpayMutual == null) { log.error("未查询到提现记录!!!"); return false; } if (DealStatus.DEALSTATUS_SUCC.equals(allinpayMutual.getDealStatus())) { log.warn("提现状态已更新!!!"); return true; } WithdrawalsVO withdrawalsVO = walletService.withdrawalsByOutOrderNo(tradeResultDTO.getOutOrderNo()); if (withdrawalsVO == null) { log.error("【提现订单查询(平台订单号)】在银联未查询到记录!!!"); return false; } if (!"processing".equals(withdrawalsVO.getStatus())) { Long companyId = allinpayMutual.getCompany().getId(); Account account = accountRepository.findDepositAccount(companyId); if (account == null) { throw new YnceErrorException("账户不存在"); } unionpayAccountService.withdrawalsHandle(account, withdrawalsVO); } return true; // 消费(转账) case 40: //***** 分账退款转账 start *****// if (tradeResultDTO.getOutOrderNo().startsWith("FZTK-")) { // 查询分账退款单 SubaccountRefund subaccountRefund = subaccountRefundRepository.findFirstBySn(tradeResultDTO.getOutOrderNo()); if (subaccountRefund == null) { log.error("未查询到分账退款单"); return false; } if (subaccountRefund.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)) { log.info("分账退款单状态已更新"); return true; } // 通过退款单号查询订单 Refund refund = refundRepository.findFirstByRefundSn(subaccountRefund.getRefundSn()); if (refund == null) { log.error("未查询到退款单"); return false; } // 调用流水处理 subaccountRefund.setExternalId(tradeResultDTO.getTradeId()); subaccountRefund.setRefundTime(DateTimeUtils.getLocalDateTimeByRFC3339(tradeResultDTO.getFinishedAt())); subaccountRefund.setSubaccountState(SubaccountState.SEPARATE_SUCC); subaccountRefund.setOrders(refund.getOrders()); // 查询订单 subaccountRefundRepository.save(subaccountRefund); subaccountService.generateRefundSubaccount(subaccountRefund); // 处理退款单 RefundSubaccountDTO subaccountRefundDTO = RefundSubaccountDTO .builder() .refundAmount(subaccountRefund.getAmount()) .refundTime(subaccountRefund.getRefundTime()) .refundSn(subaccountRefund.getRefundSn()) .externalId(subaccountRefund.getExternalId()) .build(); refundService.handleSubaccountRefund(subaccountRefundDTO); return true; } //***** 分账退款转账 end *****// //***** 授信还款转账 start *****// if (tradeResultDTO.getOutOrderNo().startsWith("HK-")) { ReimbursementRecord record = reimbursementRecordRepository.findByOrderNo(tradeResultDTO.getOutOrderNo()); if (record != null) { if (TransferState.SUCCESS.equals(record.getState())) { log.warn("转账状态已更新!!!"); return true; } AccountPaymentsVO accountPaymentsVO = walletService.paymentsByOutOrderNo(tradeResultDTO.getOutOrderNo()); if (accountPaymentsVO == null) { log.error("【消费订单查询(平台订单号)】在银联未查询到记录!!!"); return false; } if (!"processing".equals(accountPaymentsVO.getStatus())) { PaymentDTO paymentDTO = new PaymentDTO(); paymentDTO.setId(record.getAccounts().getId()); paymentDTO.setPaymentAmount(record.getAmount()); paymentDTO.setRemarks(accountPaymentsVO.getRemark()); unionpayAccountService.unionpayCreditRefundHandle(paymentDTO, record.getReceiptCompany().getId(), accountPaymentsVO); } return true; } } //***** 授信还款转账 end *****// TransferList transferList = transferListRepository.findByTransOrderNo(tradeResultDTO.getOutOrderNo()); //***** 充值转账 start *****// if (transferList == null) { TopUpOrder topUpOrder = topUpOrderRepository.findByTransferSn(tradeResultDTO.getOutOrderNo()); if (topUpOrder == null) { log.error("未查询到转账记录!!!"); return false; } else { if (SyncState.SYNCED.equals(topUpOrder.getSyncState())) { log.warn("转账状态已更新!!!"); return true; } AccountPaymentsVO accountPaymentsVO = walletService.paymentsByOutOrderNo(tradeResultDTO.getOutOrderNo()); if (accountPaymentsVO == null) { log.error("【消费订单查询(平台订单号)】在银联未查询到记录!!!"); return false; } if ("succeeded".equals(accountPaymentsVO.getStatus())) { this.rechargeHandle(topUpOrder, accountPaymentsVO); } else if ("failed".equals(accountPaymentsVO.getStatus())) { // 转账失败,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); topUpOrderRepository.save(topUpOrder); } return true; } } //***** 充值转账 end *****// //***** 正常转账 start *****// if (TransferState.SUCCESS.equals(transferList.getState())) { log.warn("转账状态已更新!!!"); return true; } AccountPaymentsVO accountPaymentsVO = walletService.paymentsByOutOrderNo(tradeResultDTO.getOutOrderNo()); if (accountPaymentsVO == null) { log.error("【消费订单查询(平台订单号)】在银联未查询到记录!!!"); return false; } if (!"processing".equals(accountPaymentsVO.getStatus())) { Account outputAccount = accountRepository.findDepositAccount(transferList.getOutputCompany().getId()); Account inputAccount = accountRepository.findDepositAccount(transferList.getInputCompany().getId()); unionpayAccountService.transferHandle(transferList.getAmount(), inputAccount, outputAccount, accountPaymentsVO); } return true; //***** 正常转账 end *****// // 担保下单 case 60: return payCallback(tradeResultDTO); // 担保未确认退款 case 62: // 若断是否完成时间是否已超过30秒,若是则处理数据 LocalDateTime refundTime = DateTimeUtils.getLocalDateTimeByRFC3339(tradeResultDTO.getFinishedAt()); Duration duration = Duration.between(refundTime, LocalDateTime.now()); if (duration.toMillis() < 30000) { return false; } // 根据平台订单号获取银联退款单 ChinaumsRefund chinaumsRefund = chinaumsRefundRepository.findFirstByOutOrderNo(tradeResultDTO.getOutOrderNo()); if (chinaumsRefund == null) { log.error("未查询到银联退款单"); return false; } Refund refund = refundRepository.findById(chinaumsRefund.getPlatformRefundId()).orElse(null); if (refund == null) { log.error("未查询到退款单"); return false; } if ("failed".equals(tradeResultDTO.getStatus())) { chinaumsRefund.setStatus(tradeResultDTO.getStatus()); chinaumsRefundRepository.save(chinaumsRefund); return true; } else if ("succeeded".equals(tradeResultDTO.getStatus())) { // 当银联退款单状态为空或者处理中的时候,手动回写数据 if (StringUtils.isBlank(chinaumsRefund.getStatus()) || "processing".equals(chinaumsRefund.getStatus())) { // 注意:这里可能因为退款单存在多个银联退款单而导致同时更新同一个退库单而导致报错,故这里直接捕捉异常并抛出异常回滚 try { // 回写银联退款单 chinaumsRefund.setRefundId(tradeResultDTO.getTradeId()); chinaumsRefund.setStatus(tradeResultDTO.getStatus()); chinaumsRefundRepository.save(chinaumsRefund); // 获取退款单对应退款退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByPlatformRefundIdAndStatus(refund.getId(), "succeeded"); // 回写退款单 refund.setActualAmount(chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add)); refund.setRefundStatus(refund.getActualAmount().compareTo(refund.getAmount()) == 0 ? RefundStatus.REFUNDED : RefundStatus.PARTIAL_REFUNDED); refund.setRefundTime(DateTimeUtils.getLocalDateTimeByRFC3339(tradeResultDTO.getFinishedAt())); // 获取退款单号 String unionpayRefundSn = StringUtils.join(chinaumsRefundList.stream().map(ChinaumsRefund::getRefundId).collect(Collectors.toList()), ","); refund.setUnionpayRefundSn(unionpayRefundSn); refund.setThirdPartyAccount(unionpayRefundSn); refundRepository.save(refund); } catch (Exception exception) { log.error("处理银联退款单异常:" + exception.getMessage()); throw new YnceErrorException(YnceError.YNCE_000000); } } return true; } else { log.error("担保未确认退款回调状态异常"); return false; } default: throw new YnceErrorException("暂时不支持此交易类型"); } return true; } public boolean payCallback(TradeResultDTO tradeResultDTO) { // 获取支付单 Payment payment = paymentRepository.findFirstBySnOrderByIdDesc(tradeResultDTO.getOutOrderNo()); if (payment == null) { log.error("未查询到支付单"); return false; } // 支付失败 if ("03".equals(tradeResultDTO.getStatus())) { payment.setExternalId(tradeResultDTO.getTradeId()); payment.setPayStatus(PayStatus.FAILED); paymentRepository.saveAndFlush(payment); return true; } else if ("06".equals(tradeResultDTO.getStatus())) { // 获取订单 Order order = orderRepository.findById(Long.valueOf(payment.getOrderId())).orElse(null); if (order == null) { log.error("支付回调(MERGE_GUARANTEED_PAY)异常,订单不存在"); return false; } // 若订单未支付进行回调处理 if (PaymentStatus.UN_PAID.equals(order.getPaymentStatus())) { // 若订单未支付则判断是否支付时间已超过30秒,若是则手动回调 // LocalDateTime payTime = DateTimeUtils.getLocalDateTimeByRFC3339(tradeResultDTO.getFinishedAt()); // Duration duration = Duration.between(payTime, LocalDateTime.now()); // if (duration.toMillis() < 30000) { // return false; // } payment.setExternalId(tradeResultDTO.getTradeId()); payment.setPayStatus(PayStatus.SUCC); // payment.setPaymentTime(payTime); payment.setUnionpaySn(tradeResultDTO.getTradeId()); paymentRepository.saveAndFlush(payment); // 如果不存在银联支付单则生成 ---//TODO: 注释以下代码,未测试 // if (!chinaumsPaymentRepository.existsByOrdersId(order.getId())) { // handleChinaumsPayment(order); // } // 生成收款单以及后续业务操作 OrderOnlinePayVO orderOnlinePayVO = new OrderOnlinePayVO(); orderOnlinePayVO.setOrderId(Long.valueOf(payment.getOrderId())); orderOnlinePayVO.setPaymentId(payment.getId()); // orderOnlinePayVO.setPayTime(payTime); orderOnlinePayVO.setExternalId(payment.getExternalId()); ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); if (thirdPartyPaySet == null || StringUtils.isBlank(thirdPartyPaySet.getServiceUrl())) { log.error("预存款支付回调失败:未配置第三方请求地址"); return false; } JSONObject result = HttpClientUtil.getInstance().sendPost(thirdPartyPaySet.getServiceUrl() + RouteUtil.ROUTE_RECEIPT_ONLINE_PAY, orderOnlinePayVO); if (!"200".equals(result.get("code").toString())) { log.error("预存款支付回调失败:请求收款失败"); return false; } } return true; } else { log.error("担保下单回调状态异常"); return false; } } /** * POS充值后续处理 * * @param topUpOrder * @param accountPaymentsVO * @return */ private boolean rechargeHandle(TopUpOrder topUpOrder, AccountPaymentsVO accountPaymentsVO) { topUpOrder.setSyncState(SyncState.SYNCED); topUpOrder.setUnionpaySn(accountPaymentsVO.getPaymentId()); topUpOrderRepository.save(topUpOrder); AccountChangeList accountChangeList = accountChangeListRepository.findFirstBySourceNo(accountPaymentsVO.getPaymentId()); if (accountChangeList != null) { log.warn("{}充值转账入金已生成异动记录!!!", topUpOrder.getOrderType().getName()); return true; } RechargeDTO rechargeDTO = new RechargeDTO(); rechargeDTO.setCompanyId(topUpOrder.getTopUpCompany().getId()); rechargeDTO.setRechargeAmount(topUpOrder.getAmount()); rechargeDTO.setRemarks(topUpOrder.getOrderType().getName() + "充值"); rechargeDTO.setPaymentMethod(topUpOrder.getOrderType().getName() + "支付"); rechargeDTO.setFinishedDate(DateTimeUtils.getLocalDateTimeByRFC3339(accountPaymentsVO.getFinishedAt())); rechargeDTO.setSourceNo(accountPaymentsVO.getPaymentId()); return unionpayAccountService.rechargeMoney(rechargeDTO); } /** * <p>这里要根据根据订单区分计算分账金额</p> * <p>1.普通销售订单:货款、品牌公司、策划公司、服务费</p> * <p>2.OEM销售订单:货款、品牌公司、策划公司、服务费、品牌授权费</p> * * @param order 订单 * @return 银联担保支付参数DTO数组 * @description * @author huabiao * @create 2022/12/12 16:41 */ private List<ChinaumsGuaranteePayParamsDTO> getChinaumsGuaranteePayParamsDTO(Order order) { List<ChinaumsGuaranteePayParamsDTO> chinaumsGuaranteePayParamsDTOList = new ArrayList<>(); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 品牌授权费数组 List<ChinaumsGuaranteePayParamsDTO> brandAuthFeeChinaumsGuaranteePayParamsDTOList = new ArrayList<>(); // 计算货款 ChinaumsGuaranteePayParamsDTO goodsCost = new ChinaumsGuaranteePayParamsDTO(); if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { if (StringUtils.isBlank(order.getSellerCompany().getWalletId())) { log.error(order.getSn() + "货款公司暂未认证银联"); throw new YnceErrorException(YnceError.YNCE_218006); } // 剩余货款 BigDecimal residueGoodsPayment = order.getGoodsPayment(); // 计算货款平台服务费 BigDecimal goodsCostPlatformServiceFee = BigDecimal.ZERO; if (orderFeeRatio.getSellerServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { goodsCostPlatformServiceFee = order.getGoodsAmount().multiply(orderFeeRatio.getSellerServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); platformServiceFee = platformServiceFee.add(goodsCostPlatformServiceFee); residueGoodsPayment = residueGoodsPayment.subtract(goodsCostPlatformServiceFee); } // 计算品牌授权费(只有当剩余货款大于0的时候才计算品牌授权费) BigDecimal totalBrandAuthCost = BigDecimal.ZERO; if (residueGoodsPayment.compareTo(BigDecimal.ZERO) == 1 && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { // 通过订单项中的品牌ID分组 Map<Long, List<OrderItemFeeRatio>> brandIdOrderItemFeeRatioListMap = orderFeeRatio.getOrderItemFeeRatio().stream() .collect(Collectors.groupingBy(orderItemFeeRatio -> orderItemFeeRatio.getOrderItem().getBrandId())); int i = 1; for (Map.Entry<Long, List<OrderItemFeeRatio>> brandIdOrderItemFeeRatioListEntry : brandIdOrderItemFeeRatioListMap.entrySet()) { Long brandId = brandIdOrderItemFeeRatioListEntry.getKey(); List<OrderItemFeeRatio> orderItemFeeRatioList = brandIdOrderItemFeeRatioListEntry.getValue(); Brand brand = brandRepository.findById(brandId).orElse(null); if (brand == null || StringUtils.isBlank(brand.getCompany().getWalletId())) { continue; } // 获取订单项 List<OrderItem> orderItemList = orderItemFeeRatioList.stream().map(orderItemFeeRatio -> orderItemFeeRatio.getOrderItem()).collect(Collectors.toList()); BigDecimal orderAmount = orderItemList.stream().map(OrderItem::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 品牌授权费比例 BigDecimal brandAuthCostRatio = orderItemFeeRatioList.get(0).getBrandAuthCostRatio(); // 计算货款 BigDecimal brandGoodsPayment = orderItemList.stream().map(OrderItem::getGoodsPayment).reduce(BigDecimal.ZERO, BigDecimal::add); // 品牌授权费(采取四舍五入的计算方式) BigDecimal brandAuthCost = brandGoodsPayment.multiply(brandAuthCostRatio).setScale(2, BigDecimal.ROUND_HALF_UP); // 品牌授权费服务费比例 BigDecimal brandAuthCostServiceCostRatio = orderItemFeeRatioList.get(0).getBrandAuthCostServiceCostRatio(); // 计算平台服务费 BigDecimal brandAuthCostServiceFee = BigDecimal.ZERO; if (brandAuthCostServiceCostRatio.compareTo(BigDecimal.ZERO) == 1) { brandAuthCostServiceFee = brandAuthCost.multiply(brandAuthCostServiceCostRatio).setScale(2, BigDecimal.ROUND_UP); platformServiceFee = platformServiceFee.add(brandAuthCostServiceFee); brandAuthCost = brandAuthCost.subtract(brandAuthCostServiceFee); } // 品牌授权费 if (brandAuthCost.compareTo(BigDecimal.ZERO) == 1) { ChinaumsGuaranteePayParamsDTO brandAuthFee = new ChinaumsGuaranteePayParamsDTO(); brandAuthFee.setAmount(brandAuthCost.multiply(new BigDecimal(100)).intValue()); brandAuthFee.setRecvBalanceAcctId(brand.getCompany().getWalletId()); brandAuthFee.setOutOrderNo(order.getSn() + "-" + SubaccountType.BRAND_AUTH_FEE.getValue() + "-" + i); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO brandAuthExtraDTO = new ChinaumsGuaranteePayExtraDTO(); brandAuthExtraDTO.setProductInfos(this.handleProductInfo(orderItemList, order.getSn(), orderAmount, brandAuthCost)); brandAuthFee.setExtra(brandAuthExtraDTO); List<GuaranteePayMetaDataBrandDTO> brandList = Arrays.asList(GuaranteePayMetaDataBrandDTO.builder().brandId(brandId.toString()).brandAuthFee(brandAuthFee.getAmount()).build()); brandAuthFee.setMetadata(ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.BRAND_AUTH_FEE.getValue()).brandList(brandList).build()); brandAuthFeeChinaumsGuaranteePayParamsDTOList.add(brandAuthFee); i++; totalBrandAuthCost = totalBrandAuthCost.add(brandAuthCost).add(brandAuthCostServiceFee); } } } // 货款 = 初始货款 - 平台服务费 - 品牌授权费 BigDecimal goodsPayment = order.getGoodsPayment().subtract(goodsCostPlatformServiceFee).subtract(totalBrandAuthCost); if (goodsPayment.compareTo(BigDecimal.ZERO) == 1) { goodsCost.setAmount(goodsPayment.multiply(new BigDecimal(100)).intValue()); goodsCost.setRecvBalanceAcctId(order.getSellerCompany().getWalletId()); goodsCost.setOutOrderNo(order.getSn() + "-" + SubaccountType.GOODS_COST.getValue()); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfo(order.getOrderItems(), order.getSn(), order.getAmount(), goodsPayment)); goodsCost.setExtra(chinaumsGuaranteePayExtraDTO); goodsCost.setMetadata(ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.GOODS_COST.getValue()).build()); chinaumsGuaranteePayParamsDTOList.add(goodsCost); } } // 计算品牌费 ChinaumsGuaranteePayParamsDTO brandFee = new ChinaumsGuaranteePayParamsDTO(); if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { if (StringUtils.isBlank(order.getBrandCompany().getWalletId())) { log.error(order.getSn() + "品牌公司暂未认证银联"); throw new YnceErrorException(YnceError.YNCE_218006); } // 计算货款平台服务费 BigDecimal brandFeePlatformServiceFee = BigDecimal.ZERO; if (orderFeeRatio.getBrandServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { brandFeePlatformServiceFee = order.getBrandCost().multiply(orderFeeRatio.getBrandServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); platformServiceFee = platformServiceFee.add(brandFeePlatformServiceFee); } brandFee.setRecvBalanceAcctId(order.getBrandCompany().getWalletId()); brandFee.setOutOrderNo(order.getSn() + "-" + SubaccountType.BRAND_FEE.getValue()); // 品牌费 BigDecimal brandCost = order.getBrandCost().subtract(brandFeePlatformServiceFee); // 自定义参数 ChinaumsGuaranteePayMetaDataDTO metadata; if (CollectionUtils.isNotEmpty(brandAuthFeeChinaumsGuaranteePayParamsDTOList)) { BigDecimal originalBrandCost = brandCost; List<GuaranteePayMetaDataBrandDTO> brandList = new ArrayList<>(); for (ChinaumsGuaranteePayParamsDTO chinaumsGuaranteePayParamsDTO : brandAuthFeeChinaumsGuaranteePayParamsDTOList) { // 判断品牌授权费和品牌是否为同一家公司 if (!brandFee.getRecvBalanceAcctId().equals(chinaumsGuaranteePayParamsDTO.getRecvBalanceAcctId())) { log.error("品牌授权费和品牌费的所属公司不是一家"); throw new YnceErrorException(YnceError.YNCE_218006); } brandCost = brandCost.add(new BigDecimal(chinaumsGuaranteePayParamsDTO.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); brandList.addAll(chinaumsGuaranteePayParamsDTO.getMetadata().getBrandList()); } if (originalBrandCost.compareTo(BigDecimal.ZERO) == 1) { metadata = ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.BRAND_FEE.getValue()).brandFee(originalBrandCost.multiply(new BigDecimal(100)).intValue()).brandList(brandList).build(); } else { metadata = ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.BRAND_FEE.getValue()).brandList(brandList).build(); } } else { metadata = ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.BRAND_FEE.getValue()).brandFee(brandCost.multiply(new BigDecimal(100)).intValue()).build(); } if (brandCost.compareTo(BigDecimal.ZERO) == 1) { brandFee.setAmount(brandCost.multiply(new BigDecimal(100)).intValue()); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); List<JSONObject> productInfos = this.handleProductInfo(order.getOrderItems(), order.getSn(), order.getAmount(), brandCost); chinaumsGuaranteePayExtraDTO.setProductInfos(productInfos); brandFee.setExtra(chinaumsGuaranteePayExtraDTO); // 拼接自定义参数 brandFee.setMetadata(metadata); chinaumsGuaranteePayParamsDTOList.add(brandFee); } } else { // 不存在品牌费但是存在品牌授权费 if (CollectionUtils.isNotEmpty(brandAuthFeeChinaumsGuaranteePayParamsDTOList)) { brandFee.setRecvBalanceAcctId(brandAuthFeeChinaumsGuaranteePayParamsDTOList.get(0).getRecvBalanceAcctId()); brandFee.setOutOrderNo(order.getSn() + "-" + SubaccountType.BRAND_FEE.getValue()); BigDecimal brandAuthCost = BigDecimal.ZERO; ChinaumsGuaranteePayMetaDataDTO metadata; List<GuaranteePayMetaDataBrandDTO> brandList = new ArrayList<>(); for (ChinaumsGuaranteePayParamsDTO chinaumsGuaranteePayParamsDTO : brandAuthFeeChinaumsGuaranteePayParamsDTOList) { if (!brandFee.getRecvBalanceAcctId().equals(chinaumsGuaranteePayParamsDTO.getRecvBalanceAcctId())) { log.error("品牌授权费所属公司不是一家"); throw new YnceErrorException(YnceError.YNCE_218006); } brandAuthCost = brandAuthCost.add(new BigDecimal(chinaumsGuaranteePayParamsDTO.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); brandList.addAll(chinaumsGuaranteePayParamsDTO.getMetadata().getBrandList()); } brandFee.setAmount(brandAuthCost.multiply(new BigDecimal(100)).intValue()); metadata = ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.BRAND_FEE.getValue()).brandList(brandList).build(); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); List<JSONObject> productInfos = this.handleProductInfo(order.getOrderItems(), order.getSn(), order.getAmount(), brandAuthCost); chinaumsGuaranteePayExtraDTO.setProductInfos(productInfos); brandFee.setExtra(chinaumsGuaranteePayExtraDTO); // 拼接自定义参数 brandFee.setMetadata(metadata); chinaumsGuaranteePayParamsDTOList.add(brandFee); } } // 计算策划费 ChinaumsGuaranteePayParamsDTO deviseFee = new ChinaumsGuaranteePayParamsDTO(); if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { if (StringUtils.isBlank(order.getDeviseCompany().getWalletId())) { log.error(order.getSn() + "策划公司暂未认证银联"); throw new YnceErrorException(YnceError.YNCE_218006); } // 计算货款平台服务费 BigDecimal deviseFeePlatformServiceFee = BigDecimal.ZERO; if (orderFeeRatio.getDeviseServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { deviseFeePlatformServiceFee = order.getDeviseCost().multiply(orderFeeRatio.getDeviseServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); platformServiceFee = platformServiceFee.add(deviseFeePlatformServiceFee); } // 实际分账的策划费 BigDecimal deviseCost = order.getDeviseCost().subtract(deviseFeePlatformServiceFee); if (deviseCost.compareTo(BigDecimal.ZERO) == 1) { deviseFee.setAmount(deviseCost.multiply(new BigDecimal(100)).intValue()); deviseFee.setRecvBalanceAcctId(order.getDeviseCompany().getWalletId()); deviseFee.setOutOrderNo(order.getSn() + "-" + SubaccountType.DEVISE_FEE.getValue()); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfo(order.getOrderItems(), order.getSn(), order.getAmount(), deviseCost)); deviseFee.setExtra(chinaumsGuaranteePayExtraDTO); deviseFee.setMetadata(ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.DEVISE_FEE.getValue()).build()); chinaumsGuaranteePayParamsDTOList.add(deviseFee); } } // 平台服务费 if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId(); if (StringUtils.isBlank(balanceAcctId)) { log.error(order.getSn() + "平台公司暂未认证银联"); throw new YnceErrorException(YnceError.YNCE_218006); } ChinaumsGuaranteePayParamsDTO platformServiceFeeDTO = new ChinaumsGuaranteePayParamsDTO(); platformServiceFeeDTO.setAmount(platformServiceFee.multiply(new BigDecimal(100)).intValue()); platformServiceFeeDTO.setRecvBalanceAcctId(balanceAcctId); platformServiceFeeDTO.setOutOrderNo(order.getSn() + "-" + SubaccountType.SERVICE_FEE.getValue()); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfo(order.getOrderItems(), order.getSn(), order.getAmount(), platformServiceFee)); platformServiceFeeDTO.setExtra(chinaumsGuaranteePayExtraDTO); platformServiceFeeDTO.setMetadata(ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.SERVICE_FEE.getValue()).build()); chinaumsGuaranteePayParamsDTOList.add(platformServiceFeeDTO); } return chinaumsGuaranteePayParamsDTOList; } /** * 处理商品数据 * * @param orderItemList:订单项 * @param sn:订单号 * @param orderAmount:订单金额 * @param amount:分摊金额 * @return 处理完的银联JSON数据 * @author huabiao * @create 2022/12/15 14:08 */ private List<JSONObject> handleProductInfo(List<OrderItem> orderItemList, String sn, BigDecimal orderAmount, BigDecimal amount) { // 循环订单项 List<JSONObject> productInfos = new ArrayList<>(); BigDecimal allocatedAmount = BigDecimal.ZERO; for (int i = 0; i < orderItemList.size(); i++) { OrderItem orderItem = orderItemList.get(i); JSONObject jsonObject = new JSONObject(); jsonObject.put("orderNo", sn + "-" + orderItem.getId()); // 按比例计算,最后一项直接减完 if (i == (orderItemList.size() - 1)) { jsonObject.put("orderAmount", amount.subtract(allocatedAmount).multiply(new BigDecimal(100)).intValue()); } else { BigDecimal orderItemPlatformServiceFee = amount.multiply(orderItem.getAmount()).divide(orderAmount, 2, BigDecimal.ROUND_DOWN); // 当计算结果不大于0时,赋值0.01 if (orderItemPlatformServiceFee.compareTo(BigDecimal.ZERO) != 1) { orderItemPlatformServiceFee = new BigDecimal("0.01"); } jsonObject.put("orderAmount", orderItemPlatformServiceFee.multiply(new BigDecimal(100)).intValue()); allocatedAmount = allocatedAmount.add(orderItemPlatformServiceFee); } jsonObject.put("productName", orderItem.getGoodsName() + orderItem.getSkuName()); jsonObject.put("productCount", orderItem.getQuantity()); productInfos.add(jsonObject); } return productInfos; } @Transactional(propagation = Propagation.NOT_SUPPORTED) @Override public ChinaumsGuaranteePayConfirmsVO paySettlement(ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO) { ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS, (JSONObject) JSONObject.toJSON(chinaumsGuaranteePayConfirmsDTO), ChinaumsGuaranteePayConfirmsVO.class); return chinaumsGuaranteePayConfirmsVO; } @Override @Transactional(propagation = Propagation.NOT_SUPPORTED) public String paySettlementConfirms(ByxChinaumsGuaranteePayConfirmsDTO byxChinaumsGuaranteePayConfirmsDTO) { JSONObject result = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS, (JSONObject) JSONObject.toJSON(byxChinaumsGuaranteePayConfirmsDTO), JSONObject.class); // 返回数据为空,则表示异常 if (result == null || result.get("settOrderNo") == null) { return null; } JSONObject params = new JSONObject(); params.put("settOrderNo", result.get("settOrderNo")); // 循环5次,每次卡睡眠2秒,共10秒 for (int i = 0; i < 5; i++) { try { Thread.sleep(2000); } catch (InterruptedException e) { log.error("结算确认的调度睡眠异常:" + e.getMessage()); } JSONObject queryResult = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS_QUERY, params, JSONObject.class); if (queryResult == null || queryResult.get("settStatus") == null) { continue; } // 01: if ("00".equals(queryResult.get("settStatus").toString()) || "01".equals(queryResult.get("settStatus").toString()) || "03".equals(queryResult.get("settStatus").toString())) { continue; } break; } return result.get("settOrderNo").toString(); } @Override @Transactional(rollbackFor = Exception.class) public List<ChinaumsPayment> handleChinaumsPayment(Order order) { List<ChinaumsPayment> chinaumsPaymentList = new ArrayList<>(); // 获取支付单 List<Payment> paymentList = paymentRepository.findAllByOrderId(order.getId().toString()); if (CollectionUtils.isEmpty(paymentList)) { return chinaumsPaymentList; } Payment payment = paymentList.get(0); // 通过系统订单号查询合并消费担保下单数据 // ByxChinaumsGuaranteePayVO byxChinaumsGuaranteePayVO = walletService.orderPaymentsByOutOrderNo(payment.getExternalId()); List<ChinaumsGuaranteePayParamsDTO> chinaumsGuaranteePayParamsDTOList = this.getChinaumsGuaranteePayParamsDTO(order); // JSONObject jsonObject = new JSONObject(); // jsonObject.put("combinedGuaranteePaymentId", payment.getExternalId()); // ChinaumsGuaranteePayVO chinaumsGuaranteePayVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_BY_SYS_NO, jsonObject, ChinaumsGuaranteePayVO.class); // 保存担保消费子订单信息 for (ChinaumsGuaranteePayParamsDTO guaranteePaymentResult : chinaumsGuaranteePayParamsDTOList) { if (guaranteePaymentResult.getMetadata() != null) { // 没有合并数据的子订单 if (guaranteePaymentResult.getMetadata().getBrandFee() == null && CollectionUtils.isEmpty(guaranteePaymentResult.getMetadata().getBrandList())) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(guaranteePaymentResult, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(guaranteePaymentResult.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setSubaccountType(SubaccountType.valueOf(guaranteePaymentResult.getMetadata().getSubaccountType())); chinaumsPaymentRepository.save(chinaumsPayment); chinaumsPaymentList.add(chinaumsPayment); } else { // 品牌费处理 if (guaranteePaymentResult.getMetadata().getBrandFee() != null && guaranteePaymentResult.getMetadata().getBrandFee() > 0) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(guaranteePaymentResult, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(guaranteePaymentResult.getMetadata().getBrandFee()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setSubaccountType(SubaccountType.BRAND_FEE); chinaumsPaymentRepository.save(chinaumsPayment); chinaumsPaymentList.add(chinaumsPayment); } // 品牌授权费处理 if (CollectionUtils.isNotEmpty(guaranteePaymentResult.getMetadata().getBrandList())) { for (GuaranteePayMetaDataBrandDTO guaranteePayMetaDataBrand : guaranteePaymentResult.getMetadata().getBrandList()) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(guaranteePaymentResult, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(guaranteePayMetaDataBrand.getBrandAuthFee()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); chinaumsPayment.setBrandId(Long.valueOf(guaranteePayMetaDataBrand.getBrandId())); chinaumsPaymentRepository.save(chinaumsPayment); chinaumsPaymentList.add(chinaumsPayment); } } } } else { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(guaranteePaymentResult, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(guaranteePaymentResult.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPaymentRepository.save(chinaumsPayment); chinaumsPaymentList.add(chinaumsPayment); } } return chinaumsPaymentList; } @Transactional(rollbackFor = Exception.class) @Override public Boolean transferDeposit(ExternalIncomeDTO externalIncomeDTO) { /* * 10: 母户入金 * 11: 转账入金 * 13: 大额订单入金 * 33: 提现退汇 * 37: 虚户入金退回退汇 * 39: 大额订单入金退回退汇 * 79: 资金划扣退汇 * 84: 收单通道验证打款退汇 */ switch (externalIncomeDTO.getTradeType()) { // 母户入金 case "10": log.info("母户入金【{}】:{}", externalIncomeDTO.getBalanceAcctId(), externalIncomeDTO.getAmount()); break; case "94": // 在途金额已生成流水,所以这里在途金额到账不处理 log.info("在途金额到账【{}】:{}", externalIncomeDTO.getBalanceAcctId(), externalIncomeDTO.getAmount()); break; // 转账入金(用户通过手机银行充值) case "11": case "93": ChinaumsAuthInfo chinaumsAuthInfo = chinaumsAuthInfoRepository.findFirstByBalanceAcctId(externalIncomeDTO.getBalanceAcctId()); if (chinaumsAuthInfo == null) { throw new YnceErrorException("未查询到银联认证信息"); } AccountChangeList accountChangeList = accountChangeListRepository.findFirstBySourceNo(externalIncomeDTO.getTradeId()); if (accountChangeList != null) { log.warn("该入金已生成异动记录!!!"); return true; } Company company = chinaumsAuthInfo.getCompany(); // Account account = accountRepository.findDepositAccount(company.getId()); // TopUpList topUpList = topUpListRepository.findTopByAccountAndStateOrderByCreatedOnDesc(account, TopUpState.PAID); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss+08:00") .withZone(ZoneId.of("Asia/Shanghai")); // 可查90个自然日的交易,单次查询开始和结束时间间隔不大于7天 LocalDateTime dateTime = LocalDateTime.now().minusDays(1L); BalanceTransactionsPageVO balanceTransactionsPageVO = this.balanceTransactions(company.getWalletId(),externalIncomeDTO.getTradeId(), dateTime.toString(), LocalDateTime.now().toString()); if (balanceTransactionsPageVO.getTotal() <= 0) { log.warn("未查询到流水记录!!!"); return false; } // 标记查询的流水中是否有当前入金的回调 boolean flag = false; List<BalanceTransactionsPageVO.BalanceTransactionsVO> data = balanceTransactionsPageVO.getData(); for (BalanceTransactionsPageVO.BalanceTransactionsVO d : data) { // 只处理交易类型为入金的流水 if (d.getTradeType() != 11 && d.getTradeType() != 93) { continue; } if (externalIncomeDTO.getTradeId().equals(d.getTradeId())) { flag = true; RechargeDTO rechargeDTO = new RechargeDTO(); rechargeDTO.setCompanyId(company.getId()); BigDecimal rechargeAmount; if (d.getSettledAmount() > 0) { rechargeAmount = new BigDecimal(d.getSettledAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } else { rechargeAmount = new BigDecimal(d.getPendingAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } rechargeDTO.setRechargeAmount(rechargeAmount); if (StringUtils.isNotEmpty(d.getRemark())) { rechargeDTO.setRemarks(d.getRemark()); } else { rechargeDTO.setRemarks("银联钱包充值"); } rechargeDTO.setPaymentMethod("银联支付"); // rechargeDTO.setFinishedDate(LocalDateTime.parse(d.getSucceededAt(), DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSzzz"))); rechargeDTO.setFinishedDate(Convert.toLocalDateTime(d.getSucceededAt())); rechargeDTO.setSourceNo(d.getTradeId()); if(unionpayAccountService.rechargeMoney(rechargeDTO)){ log.info("【{}】生成充值记录成功",company.getName()); } else { log.error("【{}】生成充值记录失败",company.getName()); } break; } } return flag; default: throw new YnceErrorException("暂不支持此交易类型:{}", externalIncomeDTO.getTradeType()); } return true; } @Override public RefundVO refund(WalletRefundDTO walletRefundDTO) { Payment payment = paymentRepository.findFirstBySnOrderByIdDesc(walletRefundDTO.getPaymentNo()); if (payment == null) { throw new YnceErrorException(YnceError.YNCE_205007); } if (!payment.getPayStatus().equals(PayStatus.SUCC)) { throw new YnceErrorException(YnceError.YNCE_218013); } Order order = orderRepository.findById(walletRefundDTO.getOrderId()).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_211004); } if (order.getIsSeparateAccounts()) { throw new YnceErrorException(YnceError.YNCE_227001); } // 获取退款单已请求的所有银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByPlatformRefundId(walletRefundDTO.getRefundId()); // 获取银联支付单 List<ChinaumsPayment> chinaumsPaymentList = chinaumsPaymentRepository.findAllByOrdersId(walletRefundDTO.getOrderId()); if (CollectionUtils.isNotEmpty(chinaumsPaymentList)) { // 计算总银联支付金额 BigDecimal totalAmount = chinaumsPaymentList.stream().map(chinaumsPayment -> chinaumsPayment.getAmount()).reduce(BigDecimal.ZERO, BigDecimal::add); // 订单银联退款单(该订单下的所有银联退款单,不包含当前退款单) List<ChinaumsRefund> orderChinaumsRefundList = new ArrayList<>(); // 查询银联该合并消费担保订单的总退款金额 BigDecimal totalRefundAmount = BigDecimal.ZERO; // 查询所有银联退款单的总金额(不包含当前退款单) List<Long> orderRefundIdList = order.getRefunds().stream().filter(refund -> !refund.getId().equals(walletRefundDTO.getRefundId())).map(Refund::getId).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(orderRefundIdList)) { orderChinaumsRefundList = chinaumsRefundRepository.findAllByPlatformRefundIdIn(orderRefundIdList); // TODO 这里是否需要考虑退款成功与否 totalRefundAmount = orderChinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 判断是否最后一次退款【订单支付金额-总退款金额 = 本次退款金额】 Boolean isFinallyRefund = order.getPayAmount().subtract(totalRefundAmount).compareTo(walletRefundDTO.getAmount()) == 0; // 已处理退款金额 ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); BigDecimal handleAmount = BigDecimal.ZERO; for (int i = 0; i < chinaumsPaymentList.size(); i++) { Boolean isRequestRefund = false; ChinaumsPayment chinaumsPayment = chinaumsPaymentList.get(i); // 根据平台退款ID和原始系统订单号以及分账类型查询是否存在银联退款单(因为品牌费和品牌授权费是同一家公司收取,所以这里需要通过分账类型区分) ChinaumsRefund chinaumsRefund = chinaumsRefundList.stream().filter(filterChinaumsRefund -> filterChinaumsRefund.getPlatformRefundId().equals(walletRefundDTO.getRefundId()) && filterChinaumsRefund.getOrigTradeId().equals(chinaumsPayment.getGuaranteePaymentId()) && filterChinaumsRefund.getSubaccountType().equals(chinaumsPayment.getSubaccountType())).findFirst().orElse(null); if (chinaumsRefund != null) { handleAmount = handleAmount.add(chinaumsRefund.getAmount()); // 若状态为空则主动查询 if (StringUtils.isBlank(chinaumsRefund.getStatus())) { try { // 调用查询接口 JSONObject jsonObject = new JSONObject(); // jsonObject.put("outOrderNo", chinaumsRefund.getOutOrderNo()); jsonObject.put("transOrderNo", walletRefundDTO.getPaymentNo()); jsonObject.put("platformWalletId", thirdPartyPaySet.getChinaumsFeeBalanceAcctId()); ByxChinaumsRefundVO chinaumsRefundVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_REFUND_QUERY, (JSONObject) JSONObject.toJSON(jsonObject), ByxChinaumsRefundVO.class); chinaumsRefund.setRefundId(chinaumsRefundVO.getMctOrderNo()); chinaumsRefund.setStatus(chinaumsRefundVO.getRefundStatus()); chinaumsRefund.setReason(chinaumsRefundVO.getAbst()); chinaumsRefund.setRemark(chinaumsRefundVO.getRemark()); chinaumsRefundRepository.save(chinaumsRefund); } catch (Exception exception) { log.error("{}请求查询银联退款单失败:{}", chinaumsRefund.getOutOrderNo(), exception.getMessage()); if (StringUtils.isNotBlank(exception.getMessage()) && exception.getMessage().contains("请求的资源不存在")) { isRequestRefund = true; } else { continue; } } } } else { BigDecimal refundAmount; // 当为最后一次退款时,需要将子订单剩余金额退完 if (isFinallyRefund) { // 获取已退款金额 BigDecimal refundedAmount = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(orderChinaumsRefundList)) { // 根据原始系统订单号以及分账类型查询已退款金额(因为品牌费和品牌授权费是同一家公司收取,所以这里需要通过分账类型区分) refundedAmount = orderChinaumsRefundList.stream().filter(orderChinaumsRefund -> orderChinaumsRefund.getOrigTradeId().equals(chinaumsPayment.getGuaranteePaymentId()) && orderChinaumsRefund.getSubaccountType().equals(chinaumsPayment.getSubaccountType())) .collect(Collectors.toList()).stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } refundAmount = chinaumsPayment.getAmount().subtract(refundedAmount); } else { // 最后一个单时直接用剩余的金额计算 if (i == (chinaumsPaymentList.size() - 1)) { refundAmount = walletRefundDTO.getAmount().subtract(handleAmount); } else { refundAmount = walletRefundDTO.getAmount().multiply(chinaumsPayment.getAmount()).divide(totalAmount, 2, RoundingMode.DOWN); } } String outOrderNo = walletRefundDTO.getRefundNo() + chinaumsPayment.getId(); // 先保存银联退款单 chinaumsRefund = new ChinaumsRefund(); chinaumsRefund.setOutOrderNo(outOrderNo); chinaumsRefund.setAmount(refundAmount); chinaumsRefund.setOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); chinaumsRefund.setOrigOutOrderNo(chinaumsPayment.getOutOrderNo()); chinaumsRefund.setOrigPayBalanceAcctId(chinaumsPayment.getPayBalanceAcctId()); chinaumsRefund.setOrigRecvBalanceAcctId(chinaumsPayment.getRecvBalanceAcctId()); chinaumsRefund.setPlatformRefundId(walletRefundDTO.getRefundId()); chinaumsRefund.setSubaccountType(chinaumsPayment.getSubaccountType()); chinaumsRefundRepository.save(chinaumsRefund); chinaumsRefundList.add(chinaumsRefund); handleAmount = handleAmount.add(chinaumsRefund.getAmount()); isRequestRefund = true; } // 请求银联退款 if (isRequestRefund) { // ChinaumsRefundDTO chinaumsRefundDTO = ChinaumsRefundDTO // .builder() // .outOrderNo(chinaumsRefund.getOutOrderNo()) // .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) // .amount(chinaumsRefund.getAmount().multiply(new BigDecimal(100)).intValue()) // .origTradeId(chinaumsPayment.getGuaranteePaymentId()) // .build(); ByxChinaumsRefundDTO byxChinaumsRefundDTO = ByxChinaumsRefundDTO .builder() .mctOrderNo(chinaumsRefund.getOutOrderNo()) .refundAmt(chinaumsRefund.getAmount().multiply(new BigDecimal(100)).longValue()) .guaranteedOrderNo(chinaumsPayment.getGuaranteePaymentId()) .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .build(); try { // 发起退款请求-----实时 ByxChinaumsRefundVO byxChinaumsRefundVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_REFUND, (JSONObject) JSONObject.toJSON(byxChinaumsRefundDTO), ByxChinaumsRefundVO.class); // // processing:处理中 // succeeded:成功 // failed:失败 // chinaumsRefund.setStatus("succeeded"); if (!"00000".equals(byxChinaumsRefundVO.getRspCode())) { log.error("{}请求银联退款失败:{}", byxChinaumsRefundVO.getMctOrderNo(), byxChinaumsRefundVO.getRspResult()); chinaumsRefund.setStatus("failed"); throw new YnceErrorException("请求银联退款失败:" + byxChinaumsRefundVO.getRspResult()); } // 获取请求结果 chinaumsRefund.setRefundId(byxChinaumsRefundVO.getTransOrderNo()); chinaumsRefund.setReason(byxChinaumsRefundVO.getAbst()); chinaumsRefund.setRemark(byxChinaumsRefundVO.getRemark()); chinaumsRefundRepository.save(chinaumsRefund); // 更新账号余额 if (chinaumsRefund.getStatus().equals("succeeded")) { accountRepository.subBalanceForCompany(chinaumsRefund.getAmount(), Long.parseLong(chinaumsRefund.getOrigRecvBalanceAcctId())); } } catch (Exception exception) { log.error("{}请求银联退款失败:{}", byxChinaumsRefundDTO.getMctOrderNo(), exception.getMessage()); } } // 如果退款状态是处理中,则循环查询,时间不超过5秒 // if ("processing".equals(chinaumsRefund.getStatus())) { // try { // long currentTimeMillis = System.currentTimeMillis(); // while (true) { // // 调用查询接口 // JSONObject jsonObject = new JSONObject(); // jsonObject.put("refundId", chinaumsRefund.getRefundId()); // ChinaumsRefundVO chinaumsRefundVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_REFUND_BY_SYS_NO, (JSONObject) JSONObject.toJSON(jsonObject), ChinaumsRefundVO.class); // // 当请求成功或者时间超时时,结束循环 // if (!"processing".equals(chinaumsRefundVO.getStatus()) || System.currentTimeMillis() - currentTimeMillis > 5000) { // chinaumsRefund.setStatus(chinaumsRefundVO.getStatus()); // chinaumsRefund.setReason(chinaumsRefundVO.getReason()); // chinaumsRefund.setRemark(chinaumsRefundVO.getRemark()); // chinaumsRefundRepository.save(chinaumsRefund); // break; // } // } // } catch (Exception exception) { // log.error("{}请求银联退款状态失败:{}", chinaumsRefund.getOutOrderNo(), exception.getMessage()); // } // } } } RefundVO refundVO = new RefundVO(); if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { // 获取成功退款的单号 List<ChinaumsRefund> succeededChinaumsRefundList = chinaumsRefundList.stream().filter(chinaumsRefund -> "succeeded".equals(chinaumsRefund.getStatus())).collect(Collectors.toList()); refundVO.setRefundAmount(succeededChinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add)); refundVO.setRefundStatus(refundVO.getRefundAmount().compareTo(walletRefundDTO.getAmount()) == 0 ? RefundStatus.REFUNDED : RefundStatus.PARTIAL_REFUNDED); refundVO.setRefundTime(LocalDateTime.now()); // 获取退款单号 List<String> refundIdList = succeededChinaumsRefundList.stream().map(chinaumsRefund -> chinaumsRefund.getRefundId()).collect(Collectors.toList()); refundVO.setExternalId(StringUtils.join(refundIdList, ",")); } else { refundVO.setRefundStatus(RefundStatus.UN_REFUND); } return refundVO; } @Transactional(propagation = Propagation.NOT_SUPPORTED) @Override public ChinaumsAllocationsVO createSubaccount(ChinaumsAllocationsDTO chinaumsAllocationsDTO) { ChinaumsAllocationsVO chinaumsAllocationsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_UPAPI_ALLOCATIONS, (JSONObject) JSONObject.toJSON(chinaumsAllocationsDTO), ChinaumsAllocationsVO.class); return chinaumsAllocationsVO; } @Override public void posTransfer() { List<TopUpOrder> topUpOrders = topUpOrderRepository.findByOrderTypeAndPaymentStatusAndSyncStateInAndPayTimeLessThanAndRefundedIsFalseOrderByPayTime( TopUpOrderType.POS, PayStatus.SUCC, Arrays.asList(SyncState.SYNCEDERROR, SyncState.UNSYNCED), LocalDateTime.of(LocalDate.now(), LocalTime.MIN)); if (CollectionUtils.isEmpty(topUpOrders)) { log.warn("POS充值转账 - 待转账记录为空!"); return; } // 根据所属企业分组 Map<Company, List<TopUpOrder>> companyTopUpOrderList = topUpOrders.stream().collect(Collectors.groupingBy(TopUpOrder::getCompany)); // 循环分组数据 for (Map.Entry<Company, List<TopUpOrder>> companyTopUpOrderListEntry : companyTopUpOrderList.entrySet()) { // 所属企业id Long companyId = companyTopUpOrderListEntry.getKey().getId(); // 所属企业充值订单 List<TopUpOrder> topUpOrderList = companyTopUpOrderListEntry.getValue(); // 获取第三方企业配置 ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getCompany(companyId); if (thirdPartyPaySet == null || StringUtils.isEmpty(thirdPartyPaySet.getPosRechargeBalanceAcctId())) { loggerService.rechargeTransfer("POS充值收款电子账簿ID为空", null, WalletServiceImpl.class.getName(), "posTransfer", "verifyParam", companyRepository.findById(companyId).orElse(null)); continue; } // 加锁,避免并发请求 String balanceAcctIdLockKey = this.getBalanceAcctIdLockKey(thirdPartyPaySet.getPosRechargeBalanceAcctId()); Boolean balanceAcctIdLock = stringRedisTemplate.opsForValue().setIfAbsent(balanceAcctIdLockKey, balanceAcctIdLockKey); if (!balanceAcctIdLock) { throw new YnceErrorException(YnceError.YNCE_000000); } stringRedisTemplate.expire(balanceAcctIdLockKey, 3, TimeUnit.MINUTES); for (TopUpOrder topUpOrder : topUpOrderList) { Company inputCompany = companyRepository.findById(topUpOrder.getTopUpCompany().getId()).orElse(null); if (inputCompany == null || StringUtils.isEmpty(inputCompany.getWalletId())) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入企业未认证", null, WalletServiceImpl.class.getName(), "posTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } Account inputAccount = accountRepository.findDepositAccount(inputCompany.getId()); if (inputAccount == null) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入账户不存在", null, WalletServiceImpl.class.getName(), "posTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } if (!inputAccount.getState().equals(AccountState.ENABLED)) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入账户非启用状态", null, WalletServiceImpl.class.getName(), "posTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } // 如果充值订单已有转账订单号,但却是未同步状态,则尝试更新 if (StringUtils.isNotBlank(topUpOrder.getTransferSn())) { AccountPaymentsVO accountPaymentsVO = null; try { accountPaymentsVO = walletService.paymentsByOutOrderNo(topUpOrder.getTransferSn()); if (accountPaymentsVO == null) { log.warn("POS充值转账同步 -【消费订单查询(平台订单号):{}】在银联未查询到记录!!!", topUpOrder.getTransferSn()); // 说明在发起转账时银联那边并未接收到,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { if ("succeeded".equals(accountPaymentsVO.getStatus())) { this.rechargeHandle(topUpOrder, accountPaymentsVO); continue; } else if ("failed".equals(accountPaymentsVO.getStatus())) { // 转账失败,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { continue; } } } catch (Exception e) { if (e.getMessage().contains("请求的资源不存在")) { // 说明在发起转账时银联那边并未接收到,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",查询转账记录失败", accountPaymentsVO, WalletServiceImpl.class.getName(), "posTransfer", "queryTransferRecord", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } } } try { // 判断余额是否足够 Long amountPenny = topUpOrder.getAmount().multiply(new BigDecimal("100")).longValue(); BalanceAcctsVO balanceAcctsVO = this.balanceAcctsQryByAcctId(thirdPartyPaySet.getPosRechargeBalanceAcctId()); if (balanceAcctsVO.getSettledAmount() < amountPenny) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转出账簿id" + thirdPartyPaySet.getPosRechargeBalanceAcctId() + "余额不足,余额为" + balanceAcctsVO.getSettledAmount(), null, WalletServiceImpl.class.getName(), "posTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); break; } // 记录转账单号,后续成功再生成充值记录 String zz = sequenceUtil.getNextSequenceNumber("ZZ"); topUpOrder.setTransferSn(zz); topUpOrderRepository.saveAndFlush(topUpOrder); AccountPaymentsDTO accountTransfer = null; try { // 请求银联【电子账簿消费(转账)】 accountTransfer = new AccountPaymentsDTO(); accountTransfer.setAmount(amountPenny) .setPayBalanceAcctId(thirdPartyPaySet.getPosRechargeBalanceAcctId()) .setRecvBalanceAcctId(inputCompany.getWalletId()) // .setPassword(RSAEncryptorUtil.encryptByPublicKey(dto.getEncryptPwd(), thirdPartyPaySet.getChinaumsPublicKey())) .setOutOrderNo(zz) .setRemark(topUpOrder.getRemark()); Map<String, Object> productInfos = new HashMap<String, Object>() {{ put("orderNo", zz); put("orderAmount", amountPenny); put("productName", "POS充值转账"); put("productCount", 1); }}; Map<String, Object> extra = new HashMap<String, Object>() {{ put("productInfos", Collections.singletonList(productInfos)); }}; accountTransfer.setExtra(extra); this.payments(accountTransfer); } catch (Exception e) { log.error("转账出现异常 - ", e); loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转账出现异常:" + e.getMessage(), accountTransfer, WalletServiceImpl.class.getName(), "posTransfer", "transfer", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); } } catch (Exception e) { log.error("POS充值转账 - ", e); loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + "," + e.getMessage(), null, WalletServiceImpl.class.getName(), "posTransfer", "transfer", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); } } } } @Override public void scanTransfer() { List<TopUpOrder> topUpOrders = topUpOrderRepository.findByOrderTypeAndPaymentStatusAndSyncStateInAndPayTimeLessThanAndRefundedIsFalseOrderByPayTime( TopUpOrderType.SCAN, PayStatus.SUCC, Arrays.asList(SyncState.SYNCEDERROR, SyncState.UNSYNCED), LocalDateTime.of(LocalDate.now(), LocalTime.MIN)); if (CollectionUtils.isEmpty(topUpOrders)) { log.warn("扫码充值转账 - 待转账记录为空!"); return; } // 根据所属企业分组 Map<Company, List<TopUpOrder>> companyTopUpOrderList = topUpOrders.stream().collect(Collectors.groupingBy(TopUpOrder::getCompany)); // 循环分组数据 for (Map.Entry<Company, List<TopUpOrder>> companyTopUpOrderListEntry : companyTopUpOrderList.entrySet()) { // 所属企业Id Long companyId = companyTopUpOrderListEntry.getKey().getId(); // 所属企业充值订单 List<TopUpOrder> topUpOrderList = companyTopUpOrderListEntry.getValue(); // 获取第三方企业配置 ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getCompany(companyId); if (thirdPartyPaySet == null || StringUtils.isEmpty(thirdPartyPaySet.getScanRechargeBalanceAcctId())) { loggerService.rechargeTransfer("扫码充值收款电子账簿ID为空", null, WalletServiceImpl.class.getName(), "scanTransfer", "verifyParam", companyRepository.findById(companyId).orElse(null)); continue; } // 加锁,避免并发请求 String balanceAcctIdLockKey = this.getBalanceAcctIdLockKey(thirdPartyPaySet.getScanRechargeBalanceAcctId()); Boolean balanceAcctIdLock = stringRedisTemplate.opsForValue().setIfAbsent(balanceAcctIdLockKey, balanceAcctIdLockKey); if (!balanceAcctIdLock) { throw new YnceErrorException(YnceError.YNCE_000000); } stringRedisTemplate.expire(balanceAcctIdLockKey, 3, TimeUnit.MINUTES); for (TopUpOrder topUpOrder : topUpOrderList) { Company inputCompany = companyRepository.findById(topUpOrder.getTopUpCompany().getId()).orElse(null); if (inputCompany == null || StringUtils.isEmpty(inputCompany.getWalletId())) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入企业未认证", null, WalletServiceImpl.class.getName(), "scanTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } Account inputAccount = accountRepository.findDepositAccount(inputCompany.getId()); if (inputAccount == null) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入账户不存在", null, WalletServiceImpl.class.getName(), "scanTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } if (!inputAccount.getState().equals(AccountState.ENABLED)) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入账户非启用状态", null, WalletServiceImpl.class.getName(), "scanTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } // 如果充值订单已有转账订单号,但却是未同步状态,则尝试更新 if (StringUtils.isNotBlank(topUpOrder.getTransferSn())) { AccountPaymentsVO accountPaymentsVO = null; try { accountPaymentsVO = walletService.paymentsByOutOrderNo(topUpOrder.getTransferSn()); if (accountPaymentsVO == null) { log.warn("扫码充值转账同步 -【消费订单查询(平台订单号):{}】在银联未查询到记录!!!", topUpOrder.getTransferSn()); // 说明在发起转账时银联那边并未接收到,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { if ("succeeded".equals(accountPaymentsVO.getStatus())) { this.rechargeHandle(topUpOrder, accountPaymentsVO); continue; } else if ("failed".equals(accountPaymentsVO.getStatus())) { // 转账失败,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { continue; } } } catch (Exception e) { if (e.getMessage().contains("请求的资源不存在")) { // 说明在发起转账时银联那边并未接收到,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",查询转账记录失败", accountPaymentsVO, WalletServiceImpl.class.getName(), "scanTransfer", "queryTransferRecord", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } } } try { // 判断余额是否足够 Long amountPenny = topUpOrder.getAmount().multiply(new BigDecimal("100")).longValue(); BalanceAcctsVO balanceAcctsVO = this.balanceAcctsQryByAcctId(thirdPartyPaySet.getScanRechargeBalanceAcctId()); if (balanceAcctsVO.getSettledAmount() < amountPenny) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转出账簿id" + thirdPartyPaySet.getScanRechargeBalanceAcctId() + "余额不足,余额为" + balanceAcctsVO.getSettledAmount(), null, WalletServiceImpl.class.getName(), "scanTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); break; } // 记录转账单号,后续成功再生成充值记录 String zz = sequenceUtil.getNextSequenceNumber("ZZ"); topUpOrder.setTransferSn(zz); topUpOrderRepository.saveAndFlush(topUpOrder); AccountPaymentsDTO accountTransfer = null; try { // 请求银联【电子账簿消费(转账)】 accountTransfer = new AccountPaymentsDTO(); accountTransfer.setAmount(amountPenny) .setPayBalanceAcctId(thirdPartyPaySet.getScanRechargeBalanceAcctId()) .setRecvBalanceAcctId(inputCompany.getWalletId()) // .setPassword(RSAEncryptorUtil.encryptByPublicKey(dto.getEncryptPwd(), thirdPartyPaySet.getChinaumsPublicKey())) .setOutOrderNo(zz) .setRemark(topUpOrder.getRemark()); Map<String, Object> productInfos = new HashMap<String, Object>() {{ put("orderNo", zz); put("orderAmount", amountPenny); put("productName", "扫码充值转账"); put("productCount", 1); }}; Map<String, Object> extra = new HashMap<String, Object>() {{ put("productInfos", Collections.singletonList(productInfos)); }}; accountTransfer.setExtra(extra); this.payments(accountTransfer); } catch (Exception e) { log.error("转账出现异常 - ", e); loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转账出现异常:" + e.getMessage(), accountTransfer, WalletServiceImpl.class.getName(), "scanTransfer", "transfer", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); } } catch (Exception e) { log.error("扫码充值转账 - ", e); loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + "," + e.getMessage(), null, WalletServiceImpl.class.getName(), "scanTransfer", "transfer", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); } } } } @Override @Transactional(rollbackFor = Exception.class) public SubaccountRefundVO subaccountRefund(SubaccountRefundDTO subaccountRefundDTO) { Order order = orderRepository.findById(subaccountRefundDTO.getOrderId()).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_206012); } if (StringUtils.isBlank(order.getBuyerCompany().getWalletId())) { throw new YnceErrorException(YnceError.YNCE_204095, YnceError.YNCE_218009.getMsg()); } OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(subaccountRefundDTO.getOrderId()); if (orderFeeRatio == null) { throw new YnceErrorException(YnceError.YNCE_204095, "订单费用比例不存在"); } Refund refund = refundRepository.findFirstByRefundSn(subaccountRefundDTO.getRefundNo()); if (refund == null) { throw new YnceErrorException(YnceError.YNCE_204028); } // 分账退款单列表 List<SubaccountRefund> subaccountRefundList = new ArrayList<>(); // 计算品牌退款费用 BigDecimal brandCost = calBrandRefundCost(refund, subaccountRefundDTO, order, orderFeeRatio, subaccountRefundList); // 计算策划退款费用 BigDecimal deviseCost = calPlanningRefundCost(refund, subaccountRefundDTO, order, orderFeeRatio, subaccountRefundList); // 计算货款退款费用 calGoodsRefundCost(refund, subaccountRefundDTO, order, orderFeeRatio, subaccountRefundList, brandCost, deviseCost); return getSubaccountRefundVO(subaccountRefundDTO, subaccountRefundList); } private void calGoodsRefundCost(Refund refund, SubaccountRefundDTO subaccountRefundDTO, Order order, OrderFeeRatio orderFeeRatio, List<SubaccountRefund> subaccountRefundList, BigDecimal brandCost, BigDecimal deviseCost) { BigDecimal goodsPayment = subaccountRefundDTO.getAmount().subtract(brandCost).subtract(deviseCost); ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); if (goodsPayment.compareTo(BigDecimal.ZERO) > 0) { // 判断是否已生成分账退款单 SubaccountRefund subaccountRefund = subaccountRefundRepository.findFirstByRefundSnAndSubaccountType(subaccountRefundDTO.getRefundNo(), SubaccountType.GOODS_COST); // 转账结果 AccountPaymentsVO accountPaymentsVO = new AccountPaymentsVO(); if (subaccountRefund == null) { String sn = sequenceUtil.getNextSequenceNumber("FZTK"); // 拼接转账申请 ByxChinaumsRefundDTO byxChinaumsRefundDTO = ByxChinaumsRefundDTO.builder() .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .refundAmt(goodsPayment.multiply(BigDecimal.valueOf(100)).longValue()) .guaranteedOrderNo(refund.getThirdPartyAccount()) .build(); // 转账结果 ByxChinaumsRefundVO byxChinaumsRefundVO = null; try { byxChinaumsRefundVO = this.refundForProfitSharing(byxChinaumsRefundDTO); } catch (Exception exception) { log.error(subaccountRefundDTO.getRefundNo() + "请求分账退款失败:" + exception.getMessage()); } if (byxChinaumsRefundVO == null) { throw new YnceErrorException("系统异常,退款失败"); } // 保存分账退款单 subaccountRefund = new SubaccountRefund(); subaccountRefund.setSn(sn); subaccountRefund.setAmount(goodsPayment); subaccountRefund.setRefundCompany(order.getSellerCompany()); subaccountRefund.setReceiptCompany(order.getBuyerCompany()); subaccountRefund.setExternalId(byxChinaumsRefundVO.getTransOrderNo()); subaccountRefund.setSubaccountType(SubaccountType.GOODS_COST); subaccountRefund.setSubaccountCostRatio(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio())); subaccountRefund.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccountRefund.setRefundSn(subaccountRefundDTO.getRefundNo()); } subaccountRefundRepository.saveAndFlush(subaccountRefund); subaccountRefundList.add(subaccountRefund); } } private BigDecimal calPlanningRefundCost(Refund refund, SubaccountRefundDTO subaccountRefundDTO, Order order, OrderFeeRatio orderFeeRatio, List<SubaccountRefund> subaccountRefundList) { BigDecimal deviseCost = BigDecimal.ZERO; ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); if (orderFeeRatio.getDeviseCostRatio().compareTo(BigDecimal.ZERO) != 0) { // 判断是否已生成分账退款单 SubaccountRefund subaccountRefund = subaccountRefundRepository.findFirstByRefundSnAndSubaccountType(subaccountRefundDTO.getRefundNo(), SubaccountType.DEVISE_FEE); deviseCost = subaccountRefundDTO.getAmount().multiply(orderFeeRatio.getDeviseCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); if (subaccountRefund == null) { String sn = sequenceUtil.getNextSequenceNumber("FZTK"); // 拼接转账申请 ByxChinaumsRefundDTO byxChinaumsRefundDTO = ByxChinaumsRefundDTO.builder() .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .refundAmt(deviseCost.multiply(BigDecimal.valueOf(100)).longValue()) .guaranteedOrderNo(refund.getThirdPartyAccount()) .build(); // 转账结果 ByxChinaumsRefundVO byxChinaumsRefundVO = null; try { byxChinaumsRefundVO = this.refundForProfitSharing(byxChinaumsRefundDTO); } catch (Exception exception) { log.error(subaccountRefundDTO.getRefundNo() + "请求分账退款失败:" + exception.getMessage()); } if (byxChinaumsRefundVO == null) { throw new YnceErrorException("系统异常,退款失败"); } // 保存分账退款单 subaccountRefund = new SubaccountRefund(); subaccountRefund.setSn(sn); subaccountRefund.setAmount(deviseCost); subaccountRefund.setRefundCompany(order.getDeviseCompany()); subaccountRefund.setReceiptCompany(order.getBuyerCompany()); // subaccountRefund.setOrders(order); subaccountRefund.setExternalId(byxChinaumsRefundVO.getTransOrderNo()); subaccountRefund.setSubaccountType(SubaccountType.DEVISE_FEE); subaccountRefund.setSubaccountCostRatio(orderFeeRatio.getDeviseCostRatio()); subaccountRefund.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccountRefund.setRefundSn(subaccountRefundDTO.getRefundNo()); } subaccountRefundRepository.saveAndFlush(subaccountRefund); subaccountRefundList.add(subaccountRefund); } return deviseCost; } private BigDecimal calBrandRefundCost(Refund refund, SubaccountRefundDTO subaccountRefundDTO, Order order, OrderFeeRatio orderFeeRatio, List<SubaccountRefund> subaccountRefundList) { BigDecimal brandCost = BigDecimal.ZERO; ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); if (orderFeeRatio.getBrandCostRatio().compareTo(BigDecimal.ZERO) == 1) { // 判断是否已生成分账退款单 SubaccountRefund subaccountRefund = subaccountRefundRepository.findFirstByRefundSnAndSubaccountType(subaccountRefundDTO.getRefundNo(), SubaccountType.BRAND_FEE); brandCost = subaccountRefundDTO.getAmount().multiply(orderFeeRatio.getBrandCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); if (subaccountRefund == null) { String sn = sequenceUtil.getNextSequenceNumber("FZTK"); // 拼接转账申请 ByxChinaumsRefundDTO byxChinaumsRefundDTO = ByxChinaumsRefundDTO.builder() .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .refundAmt(brandCost.multiply(BigDecimal.valueOf(100)).longValue()) .guaranteedOrderNo(refund.getThirdPartyAccount()) .build(); // 转账结果 ByxChinaumsRefundVO byxChinaumsRefundVO = null; try { byxChinaumsRefundVO = this.refundForProfitSharing(byxChinaumsRefundDTO); } catch (Exception exception) { log.error(subaccountRefundDTO.getRefundNo() + "请求分账退款失败:" + exception.getMessage()); } if (byxChinaumsRefundVO == null) { throw new YnceErrorException("系统异常,退款失败"); } // 保存分账退款单 subaccountRefund = new SubaccountRefund(); subaccountRefund.setSn(sn); subaccountRefund.setAmount(brandCost); subaccountRefund.setRefundCompany(order.getBrandCompany()); subaccountRefund.setReceiptCompany(order.getBuyerCompany()); subaccountRefund.setExternalId(byxChinaumsRefundVO.getTransOrderNo()); subaccountRefund.setSubaccountType(SubaccountType.BRAND_FEE); subaccountRefund.setSubaccountCostRatio(orderFeeRatio.getBrandCostRatio()); subaccountRefund.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccountRefund.setRefundSn(subaccountRefundDTO.getRefundNo()); } subaccountRefundRepository.saveAndFlush(subaccountRefund); subaccountRefundList.add(subaccountRefund); } return brandCost; } private static SubaccountRefundVO getSubaccountRefundVO(SubaccountRefundDTO subaccountRefundDTO, List<SubaccountRefund> subaccountRefundList) { SubaccountRefundVO subaccountRefundVO = new SubaccountRefundVO(); if (CollectionUtils.isNotEmpty(subaccountRefundList)) { BigDecimal refundAmount = BigDecimal.ZERO; List<String> externalIdList = new ArrayList<>(); for (SubaccountRefund subaccountRefund : subaccountRefundList) { if (subaccountRefund.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)) { refundAmount = refundAmount.add(subaccountRefund.getAmount()); externalIdList.add(subaccountRefund.getExternalId()); } } if (refundAmount.compareTo(BigDecimal.ZERO) == 0) { subaccountRefundVO.setRefundStatus(RefundStatus.UN_REFUND); subaccountRefundVO.setRefundAmount(BigDecimal.ZERO); } else { if (refundAmount.compareTo(subaccountRefundDTO.getAmount()) == 0) { subaccountRefundVO.setRefundStatus(RefundStatus.REFUNDED); } else { subaccountRefundVO.setRefundStatus(RefundStatus.PARTIAL_REFUNDED); } subaccountRefundVO.setExternalId(StringUtils.join(externalIdList, ",")); subaccountRefundVO.setRefundTime(LocalDateTime.now()); subaccountRefundVO.setRefundAmount(refundAmount); } } else { subaccountRefundVO.setRefundStatus(RefundStatus.UN_REFUND); subaccountRefundVO.setRefundAmount(BigDecimal.ZERO); } return subaccountRefundVO; } @Override public ElectronicReceiptVO electronicReceipts(String tradeId) { Map<String, Object> map = new HashMap<>(); List<String> list = new ArrayList<>(); list.add(tradeId); map.put("list", list); JSONObject result = chinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_ELECTRONIC_RECEIPTS, (JSONObject) JSONObject.toJSON(map), JSONObject.class); if (result == null || result.get("downloadUrl") == null) { throw new YnceErrorException("查询电子回单失败"); } ElectronicReceiptVO vo = new ElectronicReceiptVO(); vo.setTradeId(tradeId); vo.setFileUrl(result.get("downloadUrl").toString()); vo.setOutOrderNo(result.get("mctOrderNo") == null ? null : result.get("mctOrderNo").toString()); return vo; } @Override @Transactional(rollbackFor = Exception.class) public void createWalletByCompany(WalletCreateByCompanyDTO walletCreateByCompanyDTO) { Company company = companyRepository.findById(walletCreateByCompanyDTO.getCompanyId()).orElse(null); if (company == null) { throw new YnceErrorException(YnceError.YNCE_218031, "企业不存在"); } if (StringUtils.isBlank(company.getWalletId())) { throw new YnceErrorException(YnceError.YNCE_218031, "企业暂未认证"); } if (!ApplicationStatus.REGISTER_SUCCESS.equals(company.getChinaumsAuthInfo().getApplicationStatus())) { throw new YnceErrorException(YnceError.YNCE_218031, "企业认证修改中"); } Company walletCompany = companyRepository.findById(walletCreateByCompanyDTO.getWalletCompanyId()).orElse(null); if (walletCompany == null) { throw new YnceErrorException(YnceError.YNCE_218031, "新电子账簿所属企业不存在"); } if (StringUtils.isNotBlank(walletCompany.getWalletId())) { throw new YnceErrorException(YnceError.YNCE_218031, "新电子账簿所属企业已认证"); } if (walletCompany.getChinaumsAuthInfo() != null && !ApplicationStatus.REGISTER_SUCCESS.equals(walletCompany.getChinaumsAuthInfo().getApplicationStatus())) { throw new YnceErrorException(YnceError.YNCE_218031, "新电子账簿所属企业认证修改中"); } // 拼接请求参数 ChinaumsCreateWalletDTO chinaumsCreateWalletDTO = ChinaumsCreateWalletDTO.builder() .cusId(company.getChinaumsAuthInfo().getCusId()) .mchId(company.getChinaumsAuthInfo().getMchId()) .password(chinaumsUtil.getDefaultPassword()) .build(); // 调用创建服务 ChinaumsCreateWalletVO chinaumsCreateWalletVO; try { chinaumsCreateWalletVO = this.createWallet(chinaumsCreateWalletDTO); } catch (Exception exception) { throw new YnceErrorException(YnceError.YNCE_218031, exception.getMessage()); } // 保存企业的电子账簿ID walletCompany.setWalletId(chinaumsCreateWalletVO.getBalanceAcctId()); companyRepository.saveAndFlush(walletCompany); // 生成新的银联认证信息 ChinaumsAuthInfo chinaumsAuthInfo = new ChinaumsAuthInfo(); BeanUtils.copyProperties(company.getChinaumsAuthInfo(), chinaumsAuthInfo, "id", "chinaumsBankCard"); chinaumsAuthInfo.setOutRequestNo(chinaumsCreateWalletVO.getOutRequestNo()); chinaumsAuthInfo.setPassword(chinaumsUtil.getDefaultPassword()); chinaumsAuthInfo.setCompany(walletCompany); chinaumsAuthInfo.setRelAcctNo(chinaumsCreateWalletVO.getRelAcctNo()); chinaumsAuthInfo.setBankCardNo(chinaumsCreateWalletVO.getBankCardNo()); chinaumsAuthInfo.setBalanceAcctId(chinaumsCreateWalletVO.getBalanceAcctId()); chinaumsAuthInfoRepository.save(chinaumsAuthInfo); } @Transactional(rollbackFor = Exception.class) @Override public void createWalletCreditRefund() { Company company = getUser().getCompany(); ChinaumsAuthInfo dbChinaumsAuthInfo = company.getChinaumsAuthInfo(); if (StringUtils.isBlank(company.getWalletId()) || dbChinaumsAuthInfo == null) { throw new YnceErrorException(YnceError.YNCE_218031, "企业暂未认证"); } ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getCompany(company.getId()); if (thirdPartyPaySet == null) { throw new YnceErrorException("第三方企业配置不存在"); } if (StringUtils.isNotBlank(thirdPartyPaySet.getChinaumsCreditBalanceAcctId())) { throw new YnceErrorException("授信资金池账户已存在"); } // 拼接请求参数 ChinaumsCreateWalletDTO chinaumsCreateWalletDTO = ChinaumsCreateWalletDTO.builder() .cusId(dbChinaumsAuthInfo.getCusId()) .mchId(dbChinaumsAuthInfo.getMchId()) .password(chinaumsUtil.getDefaultPassword()) .build(); // 调用创建服务 ChinaumsCreateWalletVO chinaumsCreateWalletVO; try { chinaumsCreateWalletVO = this.createWallet(chinaumsCreateWalletDTO); } catch (Exception exception) { throw new YnceErrorException(YnceError.YNCE_218031, exception.getMessage()); } // 保存电子账簿ID thirdPartyPaySet.setChinaumsCreditBalanceAcctId(chinaumsCreateWalletVO.getBalanceAcctId()); thirdPartyPaySetRepository.saveAndFlush(thirdPartyPaySet); } private ChinaumsCreateWalletVO createWallet(ChinaumsCreateWalletDTO chinaumsCreateWalletDTO) { chinaumsCreateWalletDTO.setOutRequestNo(sequenceUtil.getNextSequenceNumber("YLRZ")); try { // 密码加密 chinaumsCreateWalletDTO.setPassword(RSAEncryptorUtil.encryptByPublicKey(chinaumsCreateWalletDTO.getPassword(), chinaumsUtil.getPublicKey())); } catch (Exception exception) { throw new YnceErrorException(YnceError.YNCE_218014); } return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_UPAPI_BALANCE_ACCTS, (JSONObject) JSONObject.toJSON(chinaumsCreateWalletDTO), ChinaumsCreateWalletVO.class); } /** * 获取银联电子账簿id锁 * * @param balanceAcctId * @return */ private String getBalanceAcctIdLockKey(String balanceAcctId) { return balanceAcctId + ":BALANCE_ACCT_ID"; } /** * 转账入金回调处理 */ private void paymentCallBack(ExternalIncomeDTO externalIncomeDTO){ // log.info("转账入金 交易类型为:{}", externalIncomeDTO.getTradeType()); // 加锁,避免并发请求 String lockKey = "paymentCallBack-"+externalIncomeDTO.getTradeId(); Boolean lockTradeId = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "locked", 5, TimeUnit.MINUTES); // 拿不到锁直接返回 if (!lockTradeId) { throw new YnceErrorException("转账入金(充值)处理中,稍后重试"); } // stringRedisTemplate.expire(lockKeyTradeId, 1, TimeUnit.MINUTES); try { ChinaumsAuthInfo outputAuthInfo = chinaumsAuthInfoRepository.findFirstByBalanceAcctId(externalIncomeDTO.getPayBalanceAcctId()); ChinaumsAuthInfo inputAuthInfo = chinaumsAuthInfoRepository.findFirstByBalanceAcctId(externalIncomeDTO.getBalanceAcctId()); if (outputAuthInfo == null) { throw new YnceErrorException("未查询到银联认证信息"); } AccountChangeList accountChangeList = accountChangeListRepository.findFirstBySourceNo(externalIncomeDTO.getTradeId()); if (accountChangeList != null) { log.warn("该入金已生成异动记录!!!"); return; } Company company = outputAuthInfo.getCompany(); // Account account = accountRepository.findDepositAccount(company.getId()); // TopUpList topUpList = topUpListRepository.findTopByAccountAndStateOrderByCreatedOnDesc(account, TopUpState.PAID); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss+08:00") .withZone(ZoneId.of("Asia/Shanghai")); // 可查90个自然日的交易,单次查询开始和结束时间间隔不大于7天 LocalDateTime dateTime = LocalDateTime.now().minusDays(1L); BalanceTransactionsPageVO balanceTransactionsPageVO = this.balanceTransactions(company.getWalletId(),externalIncomeDTO.getTradeId(), dateTimeFormatter.format(dateTime), dateTimeFormatter.format(LocalDateTime.now())); if (balanceTransactionsPageVO ==null || balanceTransactionsPageVO.getTotal() <= 0) { log.warn("未查询到流水记录!!!"); return; } // 标记查询的流水中是否有当前入金的回调 boolean flag = false; List<BalanceTransactionsPageVO.BalanceTransactionsVO> data = balanceTransactionsPageVO.getData(); for (BalanceTransactionsPageVO.BalanceTransactionsVO d : data) { // log.info("BalanceTransactionsVO:{}",d); if (externalIncomeDTO.getTradeId().equals(d.getTradeId())) { flag = true; RechargeDTO rechargeDTO = new RechargeDTO(); rechargeDTO.setCompanyId(company.getId()); BigDecimal rechargeAmount; if (d.getSettledAmount() > 0) { rechargeAmount = new BigDecimal(d.getSettledAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } else { rechargeAmount = new BigDecimal(d.getPendingAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } rechargeDTO.setRechargeAmount(rechargeAmount); if (StringUtils.isNotEmpty(d.getRemark())) { rechargeDTO.setRemarks(d.getRemark()); } else { rechargeDTO.setRemarks("转账-"+inputAuthInfo.getCompany().getName()); } rechargeDTO.setPaymentMethod("银联支付"); // rechargeDTO.setFinishedDate(LocalDateTime.parse(d.getSucceededAt(), DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSzzz"))); rechargeDTO.setFinishedDate(DateTimeUtils.getLocalDateTimeByRFC3339Str(d.getSucceededAt())); rechargeDTO.setSourceNo(d.getTradeId()); rechargeDTO.setChangeDirection(ChangeDirection.REDUCE); rechargeDTO.setAccountChangeType(AccountChangeType.TRANSFER); // 转出账号生成转账记录 unionpayAccountService.rechargeMoney(rechargeDTO); // 转入账号生成充值记录 RechargeDTO transferIntoDTO = new RechargeDTO(); transferIntoDTO.setCompanyId(inputAuthInfo.getCompany().getId()); transferIntoDTO.setRechargeAmount(rechargeAmount); transferIntoDTO.setRemarks("转账-来自" + outputAuthInfo.getCompany().getName()); transferIntoDTO.setPaymentMethod("银联支付"); transferIntoDTO.setFinishedDate(rechargeDTO.getFinishedDate()); transferIntoDTO.setSourceNo(d.getTradeId()); transferIntoDTO.setChangeDirection(ChangeDirection.ADD); transferIntoDTO.setAccountChangeType(AccountChangeType.TRANSFER); unionpayAccountService.rechargeMoney(transferIntoDTO); break; } } } finally { // 执行成功和失败都需要删除锁 stringRedisTemplate.delete(lockKey); } } }
package com.yn.bftl.thirdparty.modules.chinaums.service.impl; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONObject; import com.yn.bftl.common.common.exception.YnceError; import com.yn.bftl.common.common.util.ByxRouteUtil; import com.yn.bftl.common.common.util.RSAEncryptorUtil; import com.yn.bftl.common.common.util.RouteUtil; import com.yn.bftl.common.modules.account.dto.*; import com.yn.bftl.common.modules.account.entity.*; import com.yn.bftl.common.modules.account.enums.AccountChangeType; import com.yn.bftl.common.modules.account.enums.AccountState; import com.yn.bftl.common.modules.account.enums.ChangeDirection; import com.yn.bftl.common.modules.account.enums.TransferState; import com.yn.bftl.common.modules.account.vo.AccountPaymentsVO; import com.yn.bftl.common.modules.account.vo.BalanceAcctsVO; import com.yn.bftl.common.modules.account.vo.BalanceTransactionsPageVO; import com.yn.bftl.common.modules.account.vo.WithdrawalsVO; import com.yn.bftl.common.modules.company.entity.Brand; import com.yn.bftl.common.modules.company.entity.ChinaumsAuthInfo; import com.yn.bftl.common.modules.company.entity.Company; import com.yn.bftl.common.modules.company.enums.ApplicationStatus; import com.yn.bftl.common.modules.configuration.entity.ThirdPartyPaySet; import com.yn.bftl.common.modules.order.dto.SubaccountRefundDTO; import com.yn.bftl.common.modules.order.dto.WalletRefundDTO; import com.yn.bftl.common.modules.order.entity.*; import com.yn.bftl.common.modules.order.enums.*; import com.yn.bftl.common.modules.order.vo.OrderOnlinePayVO; import com.yn.bftl.common.modules.order.vo.RefundVO; import com.yn.bftl.common.modules.order.vo.SubaccountRefundVO; import com.yn.bftl.common.modules.subaccount.entity.AllinpayMutual; import com.yn.bftl.common.modules.subaccount.entity.ChinaumsPayment; import com.yn.bftl.common.modules.subaccount.entity.ChinaumsRefund; import com.yn.bftl.common.modules.subaccount.entity.SubaccountRefund; import com.yn.bftl.common.modules.subaccount.enums.DealStatus; import com.yn.bftl.common.modules.subaccount.enums.SubaccountState; import com.yn.bftl.common.modules.subaccount.enums.SubaccountType; import com.yn.bftl.thirdparty.common.constants.Constant; import com.yn.bftl.thirdparty.common.exception.YnceErrorException; import com.yn.bftl.thirdparty.common.repository.*; import com.yn.bftl.thirdparty.common.service.BaseMemberService; import com.yn.bftl.thirdparty.common.service.ByxTradeWayService; import com.yn.bftl.thirdparty.common.util.DateTimeUtils; import com.yn.bftl.thirdparty.common.util.HttpClientUtil; import com.yn.bftl.thirdparty.common.util.SequenceUtil; import com.yn.bftl.thirdparty.common.repository.RefundRepository; import com.yn.bftl.thirdparty.modules.business.dto.RefundSubaccountDTO; import com.yn.bftl.thirdparty.modules.business.repository.ChinaumsPaymentRepository; import com.yn.bftl.thirdparty.modules.business.repository.ChinaumsRefundRepository; import com.yn.bftl.thirdparty.modules.business.repository.SubaccountRefundRepository; import com.yn.bftl.thirdparty.modules.business.service.RefundService; import com.yn.bftl.thirdparty.modules.business.service.SubaccountService; import com.yn.bftl.thirdparty.modules.business.util.ThirdPartyConfigUtil; import com.yn.bftl.thirdparty.modules.chinaums.dto.TradeResultDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.WalletCreateByCompanyDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.WalletOrderPayDTO; import com.yn.bftl.thirdparty.modules.chinaums.dto.byx.*; import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.*; import com.yn.bftl.thirdparty.modules.chinaums.enums.OrderPayStatusEnum; import com.yn.bftl.thirdparty.modules.chinaums.enums.OrderPaymentStatusEnum; import com.yn.bftl.thirdparty.modules.chinaums.repository.ChinaumsAuthInfoRepository; import com.yn.bftl.thirdparty.modules.chinaums.service.AuthService; import com.yn.bftl.thirdparty.modules.chinaums.service.WalletService; import com.yn.bftl.thirdparty.modules.chinaums.util.ByxChinaumsUtil; import com.yn.bftl.thirdparty.modules.chinaums.util.ChinaumsUtil; import com.yn.bftl.thirdparty.modules.chinaums.vo.ChinaumsRechargeAccountVO; import com.yn.bftl.thirdparty.modules.chinaums.vo.ElectronicReceiptVO; import com.yn.bftl.thirdparty.modules.chinaums.vo.byx.*; import com.yn.bftl.thirdparty.modules.chinaums.vo.chinaums.*; import com.yn.bftl.thirdparty.modules.log.service.LoggerService; import com.yn.bftl.thirdparty.modules.secret.service.RandomKeyService; import com.yn.bftl.thirdparty.modules.unionpay.enums.UnionpayAppOrderType; import com.yn.bftl.thirdparty.modules.unionpay.repository.OrderFeeRatioRepository; import com.yn.bftl.thirdparty.modules.unionpay.repository.TopUpOrderRepository; import com.yn.bftl.thirdparty.modules.unionpay.service.UnionpayAccountService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.*; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * @author huabiao * @create 2022/12/5 20:25 **/ @Slf4j @Service public class WalletServiceImpl extends BaseMemberService implements WalletService { @Resource private ByxChinaumsUtil byxChinaumsUtil; @Resource private ChinaumsUtil chinaumsUtil; @Resource private ChinaumsAuthInfoRepository chinaumsAuthInfoRepository; @Resource private OrderRepository orderRepository; @Resource private SubaccountService subaccountService; @Resource private PaymentRepository paymentRepository; @Resource private BrandRepository brandRepository; @Resource private ChinaumsPaymentRepository chinaumsPaymentRepository; @Resource private OrderFeeRatioRepository orderFeeRatioRepository; @Resource private AccountChangeListRepository accountChangeListRepository; @Resource private AccountRepository accountRepository; @Resource private UnionpayAccountService unionpayAccountService; @Resource private WalletService walletService; @Resource private AllinpayMutualRepository allinpayMutualRepository; @Resource private TransferListRepository transferListRepository; @Resource private ChinaumsRefundRepository chinaumsRefundRepository; @Resource private TopUpOrderRepository topUpOrderRepository; @Resource private ThirdPartyConfigUtil thirdPartyConfigUtil; @Resource private StringRedisTemplate stringRedisTemplate; @Resource private SequenceUtil sequenceUtil; @Resource private LoggerService loggerService; @Resource private CompanyRepository companyRepository; @Resource private ReimbursementRecordRepository reimbursementRecordRepository; @Resource private SubaccountRefundRepository subaccountRefundRepository; @Resource private RefundService refundService; @Resource private RefundRepository refundRepository; @Resource private ThirdPartyPaySetRepository thirdPartyPaySetRepository; @Resource private AuthService authService; @Resource private RandomKeyService randomKeyService; @Resource private ByxTradeWayService byxTradeWayService; @Override public BalanceAcctsVO balanceAcctsQryByAcctId(String balanceAcctId) { Company company = getUser().getCompany(); ChinaumsAuthInfo chinaumsAuthInfo = company.getChinaumsAuthInfo(); if (StringUtils.isBlank(balanceAcctId)) { balanceAcctId = chinaumsAuthInfo.getBalanceAcctId(); } // Map<String, String> map = new HashMap<>(); // map.put("balanceAcctId", balanceAcctId); // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_BALANCE_ACCTS_QRY, (JSONObject) JSONObject.toJSON(map), BalanceAcctsVO.class); BalanceAcctsVO balanceAcctsVO = new BalanceAcctsVO(); ByxQueryAcctBalDTO byxQueryAcctBalDTO = new ByxQueryAcctBalDTO(); byxQueryAcctBalDTO.setWalletId(balanceAcctId); // byxTradeWayService.setCert(byxQueryAcctBalDTO, company.getWalletId()); ByxQueryAcctBalVO byxQueryAcctBalVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_BALANCE_ACCTS_QRY,(JSONObject) JSONObject.toJSON(byxQueryAcctBalDTO),ByxQueryAcctBalVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxQueryAcctBalVO.getRspCode())){ balanceAcctsVO.setBalanceAcctId(byxQueryAcctBalVO.getWalletId()); balanceAcctsVO.setRelAcctNo(chinaumsAuthInfo.getRelAcctNo()); balanceAcctsVO.setSettledAmount(Convert.toLong( byxQueryAcctBalVO.getAvlblAmt())); balanceAcctsVO.setFrozenSettledAmount(Convert.toLong(byxQueryAcctBalVO.getFrznAmt())); balanceAcctsVO.setPendingAmount(BigDecimal.ZERO.longValue()); ByxQueryAcctInfoDTO byxQueryAcctInfoDTO = new ByxQueryAcctInfoDTO(); byxQueryAcctInfoDTO.setWalletId(company.getWalletId()); ByxQueryAcctInfoVO byxQueryAcctInfoVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_QUERY_ACCOUNT_INFORMATION,(JSONObject) JSONObject.toJSON(byxQueryAcctInfoDTO),ByxQueryAcctInfoVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxQueryAcctInfoVO.getRspCode())){ if("2".equals(byxQueryAcctInfoVO.getAcctStatus())){ balanceAcctsVO.setIsFrozen(true); } else { balanceAcctsVO.setIsFrozen(false); } } } return balanceAcctsVO; } @Override public BalanceTransactionsPageVO balanceTransactions(String balanceAcctId,String transOrderNo, String startAt, String endAt) { // if (StringUtils.isBlank(balanceAcctId)) { // balanceAcctId = getUser().getCompany().getWalletId(); // } // Map<String, Object> map = new HashMap<>(); // map.put("balanceAcctId", balanceAcctId); // // 必须小于等于100 // map.put("size", 100); // if (StringUtils.isNotBlank(startAt)) { // map.put("startAt", startAt.replace(" ", "+")); // } // if (StringUtils.isNotBlank(endAt)) { // map.put("endAt", endAt.replace(" ", "+")); // } // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_BALANCE_TRANSACTIONS, (JSONObject) JSONObject.toJSON(map), BalanceTransactionsPageVO.class); BalanceTransactionsPageVO balanceTransactionsPageVO = new BalanceTransactionsPageVO(); ByxQueryTransListDTO byxQueryTransListDTO = new ByxQueryTransListDTO(); if (StringUtils.isBlank(balanceAcctId)) { balanceAcctId = getUser().getCompany().getWalletId(); } byxQueryTransListDTO.setWalletId(balanceAcctId); // 必须小于等于50 byxQueryTransListDTO.setPageSize("50"); byxQueryTransListDTO.setPageNo("1"); if (StrUtil.isBlank(startAt)) { startAt = DateUtil.now(); } if (StrUtil.isBlank(endAt)) { endAt = startAt; } byxQueryTransListDTO.setStartDate(DateUtil.format(Convert.toLocalDateTime(startAt), "yyyyMMdd") ); byxQueryTransListDTO.setEndDate(DateUtil.format(Convert.toLocalDateTime(endAt), "yyyyMMdd") ); if(null!=transOrderNo){ byxQueryTransListDTO.setTransOrderNo(transOrderNo); } //log.info("byxQueryTransListDTO:{}",byxQueryTransListDTO); // byxTradeWayService.setTradeWayInCert(byxQueryTransListDTO,balanceAcctId); ByxQueryTransListVO byxQueryTransListVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_BALANCE_TRANSACTIONS, (JSONObject) JSONObject.toJSON(byxQueryTransListDTO), ByxQueryTransListVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxQueryTransListVO.getRspCode())){ balanceTransactionsPageVO.setSize(Convert.toInt(byxQueryTransListVO.getPageSize()) ); balanceTransactionsPageVO.setPage(Convert.toInt(byxQueryTransListVO.getPageNo()) ); balanceTransactionsPageVO.setTotal(Convert.toInt(byxQueryTransListVO.getTotal()) ); List<BalanceTransactionsPageVO.BalanceTransactionsVO> data = new ArrayList<>(); if(ObjectUtil.isNotEmpty(byxQueryTransListVO.getRowList())){ for (ByxQueryTransListRowVO byxQueryTransListRowVO : byxQueryTransListVO.getRowList()) { BalanceTransactionsPageVO.BalanceTransactionsVO balanceTransactionsVO = new BalanceTransactionsPageVO.BalanceTransactionsVO(); balanceTransactionsVO.setBalanceAcctId(byxQueryTransListRowVO.getWalletId()); balanceTransactionsVO.setTradeId(byxQueryTransListRowVO.getTransOrderNo()); balanceTransactionsVO.setOutOrderNo(byxQueryTransListRowVO.getMctOrderNo()); balanceTransactionsVO.setAmtSymbol(byxQueryTransListRowVO.getAmtSymbol()); if("+".equals(byxQueryTransListRowVO.getAmtSymbol())){ // amtSymbol+表示入金,-表示出金 // tradeType 11 --> 转账入金 balanceTransactionsVO.setTradeType(11); } if("-".equals(byxQueryTransListRowVO.getAmtSymbol())){ // amtSymbol+表示入金,-表示出金 // tradeType 40 --> 消费(转账) balanceTransactionsVO.setTradeType(40); } balanceTransactionsVO.setSettledAmount(Convert.toLong(byxQueryTransListRowVO.getTransAmt()) ); balanceTransactionsVO.setRemark(byxQueryTransListRowVO.getRemark()); balanceTransactionsVO.setSucceededAt(DateTimeUtils.getDateTimeToRFC3339(byxQueryTransListRowVO.getProcTime())); data.add(balanceTransactionsVO); } } balanceTransactionsPageVO.setData(data); } return balanceTransactionsPageVO; } @Override public ChinaumsRechargeAccountVO getWalletRechargeAccount() { Company company = getUser().getCompany(); ChinaumsAuthInfo chinaumsAuthInfo = chinaumsAuthInfoRepository.findFirstByCompanyId(company.getId()); if (chinaumsAuthInfo == null) { throw new YnceErrorException(YnceError.YNCE_218009); } ChinaumsRechargeAccountVO chinaumsRechargeAccountVO = new ChinaumsRechargeAccountVO(); chinaumsRechargeAccountVO.setAccountName(chinaumsAuthInfo.getBindAcctName()); chinaumsRechargeAccountVO.setAccountNumber(chinaumsAuthInfo.getRelAcctNo()); return chinaumsRechargeAccountVO; } private Order getOrderAndCheck(WalletOrderPayDTO walletOrderPayDTO) { Order order = orderRepository.findById(walletOrderPayDTO.getOrderId()).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_204003); } if (!order.getApprovalStatus().equals(ApprovalStatus.APPROVE)) { throw new YnceErrorException(YnceError.YNCE_204016); } if (!order.getPaymentStatus().equals(PaymentStatus.UN_PAID)) { throw new YnceErrorException(YnceError.YNCE_204015); } return order; } /** * 电子账本 订单支付 * @Description step 1.根据订单ID查询预存款的支付单 * step 2.如果支付单不存在,则创建支付单号及费用明细,否则直接返回支付单的银联支付号 * step 3.调用银行下单及支付接口---调用下单返回银行订单号,通过银行订单号调用支付接口,返回银行交易单号 * step 4.如果支付成功则保存银行交易单号并更新支付状态, 否则保存失败状态 * step 5.根据订单对应的所有明细支付信息创建对应的银联支付单号并保存入库 * @param walletOrderPayDTO:订单支付DTO * @return String----银联支付单号 */ @Override public String orderPay(WalletOrderPayDTO walletOrderPayDTO) { if (walletOrderPayDTO.getOrderId() == null) { log.error("支付失败,订单号为空"); throw new YnceErrorException(YnceError.YNCE_204003); } if (StringUtils.isEmpty(walletOrderPayDTO.getPassword())) { log.error("密码不为空"); throw new YnceErrorException(YnceError.YNCE_204101); } if (StringUtils.isEmpty(walletOrderPayDTO.getPlugRandomKey())) { log.error("随机因子不为空"); throw new YnceErrorException(YnceError.YNCE_204101); } Order order = getOrderAndCheck(walletOrderPayDTO); // 获取预存款的支付单, 订单和支付单是1:1关系 Payment payment = paymentRepository.findFirstByOrderIdAndPaymentMethod(order.getId().toString(), PaymentMethod.DEPOSIT); if (payment != null && PayStatus.SUCC.equals(payment.getPayStatus())) { return payment.getExternalId(); } // 银联钱包的支付和下单是实时的,返回数据要么成功要么失败 // 校验 this.checkBalance(order, payment); // 平台支付单号 String paymentSn = ""; // 创建支付单 if (payment == null) { paymentSn = subaccountService.createPayment(order, null, UnionpayAppOrderType.DEPOSIT, null, null, null); } // 处理费用等 List<ChinaumsGuaranteePayParamsDTO> chinaumsGuaranteePayParamsDTOList = this.getChinaumsGuaranteePayParamsDTO(order); // 判断金额是否一致 BigDecimal totalAmount = new BigDecimal(chinaumsGuaranteePayParamsDTOList.stream().mapToInt(ChinaumsGuaranteePayParamsDTO::getAmount).sum()); if (totalAmount.compareTo(order.getAmount().multiply(new BigDecimal(100))) != 0) { log.error("银联请求参数总金额" + totalAmount + "与订单支付金额" + order.getAmount() + "不一致"); throw new YnceErrorException(YnceError.YNCE_218006); } // 发送 下单 String guaranteedOrderNo = this.sendChinaumsOrder(order); if (StringUtils.isEmpty(guaranteedOrderNo)) { throw new YnceErrorException("系统异常,支付失败"); } payment = paymentRepository.findFirstBySnOrderByIdDesc(paymentSn); payment.setExternalId(guaranteedOrderNo); paymentRepository.saveAndFlush(payment); // 发送 支付-------支付接口是实时返回成功或失败,判断条件是rspCode为00000 JSONObject jsonObject = this.sendChinaumsPay(order, paymentSn, guaranteedOrderNo, walletOrderPayDTO); if (jsonObject == null || jsonObject.get("rspCode") == null || jsonObject.get("transOrderNo") == null) { throw new YnceErrorException("系统异常,支付失败"); } log.info("支付成功:" + jsonObject.toJSONString()); // payment = paymentRepository.findFirstBySnOrderByIdDesc(paymentSn); // String transOrderNo = jsonObject.get("transOrderNo").toString(); // 支付成功 if (jsonObject.get("rspCode").equals("00000")) { // 修改支付单状态 payment.setPayStatus(PayStatus.SUCC); payment.setPaymentTime(LocalDateTime.now()); payment.setExternalId(guaranteedOrderNo); payment.setUnionpaySn(guaranteedOrderNo); paymentRepository.saveAndFlush(payment); // try { // // // 若订单未支付进行回调处理 // if (PaymentStatus.UN_PAID.equals(order.getPaymentStatus())) { // // 生成收款单以及后续业务操作 // OrderOnlinePayVO orderOnlinePayVO = new OrderOnlinePayVO(); // orderOnlinePayVO.setOrderId(Long.valueOf(payment.getOrderId())); // orderOnlinePayVO.setPaymentId(payment.getId()); // orderOnlinePayVO.setExternalId(payment.getExternalId()); // JSONObject result = HttpClientUtil.getInstance().sendPost(thirdPartyConfigUtil.getPlatform().getServiceUrl() + RouteUtil.ROUTE_RECEIPT_ONLINE_PAY, orderOnlinePayVO); // if (!"200".equals(result.get("code").toString())) { // log.error("预存款支付回调失败:请求收款失败"); // } // } this.handlePayStateSuccess(order, guaranteedOrderNo, chinaumsGuaranteePayParamsDTOList); // } catch (Exception e) { // log.error(e.getMessage()); // throw new YnceErrorException("支付处理失败"); // } return payment.getExternalId(); } // 当支付失败时,抛出异常 payment.setPayStatus(PayStatus.FAILED); payment.setExternalId(guaranteedOrderNo); paymentRepository.saveAndFlush(payment); throw new YnceErrorException(YnceError.YNCE_218033); } private void checkBalance(Order order, Payment payment) { // 获取电子账户余额 BigDecimal balance; try { BalanceAcctsVO balanceAcctsVO = this.balanceAcctsQryByAcctId(null); balance = new BigDecimal(balanceAcctsVO.getSettledAmount() + balanceAcctsVO.getPendingAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } catch (Exception exception) { throw new YnceErrorException(YnceError.YNCE_205010); } // 校验 this.checkCondition(order, payment, balance); } private String sendChinaumsOrder(Order order) { ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); String subject = order.getOrderItems().get(0).getGoodsName(); if (StringUtils.isNotEmpty(order.getInvoiceContent())) { subject = order.getRemark(); } else if (StringUtils.isNotEmpty(order.getRemark())) { subject = order.getRemark(); } ByxChinaumsGuaranteeOrderParamsDTO byxChinaumsGuaranteeOrderParamsDTO = ByxChinaumsGuaranteeOrderParamsDTO .builder() .mctOrderNo(order.getId()) .oprType(1) .buyerWalletId(order.getBuyerCompany().getWalletId()) .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .merWalletId(order.getSellerCompany().getWalletId()) .merName(order.getSellerCompany().getName()) .orderAmt(order.getAmount().multiply(new BigDecimal(100)).longValue()) .subject(subject) .payTimeoutExpress("1h") .notifyUrl(thirdPartyPaySet.getThirdPartyUrl() + "/chinaums/call_back/byx/result") .remark(order.getRemark()) .build(); JSONObject requestJsonObject = (JSONObject) JSONObject.toJSON(byxChinaumsGuaranteeOrderParamsDTO); try { log.info("===========================调用银联下单接口"); JSONObject jsonObject = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLECT_COMBINED_GUARANTEE_ORDER, requestJsonObject, JSONObject.class); if ("10004".equals(jsonObject.get("rspCode").toString())) { ByxChinaumsGuaranteePayVO byxChinaumsGuaranteePayVO = this.orderPaymentsByOutOrderNo(order.getId().toString(), thirdPartyPaySet.getChinaumsFeeBalanceAcctId()); return byxChinaumsGuaranteePayVO.getGuaranteedOrderNo(); } return jsonObject.get("guaranteedOrderNo").toString(); } catch (Exception exception) { log.error("银联请求合并消费担保下单失败:" + exception.getMessage()); } return null; } private JSONObject sendChinaumsPay(Order order, String paymentSn, String guaranteedOrderNo, WalletOrderPayDTO walletOrderPayDTO) { log.info("===========================调用银联支付接口"); // 参数准备 ByxChinaumsGuaranteePayParamsDTO byxChinaumsGuaranteePayParamsDTO = getByxChinaumsGuaranteePayParamsDTO(order, paymentSn, guaranteedOrderNo, walletOrderPayDTO); JSONObject requestJsonObject = (JSONObject) JSONObject.toJSON(byxChinaumsGuaranteePayParamsDTO); try { return byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS, requestJsonObject, JSONObject.class); } catch (Exception exception) { log.error("银联请求合并消费担保下单失败:" + exception.getMessage()); } return null; } private void handlePayStateSuccess(Order order, String guaranteedOrderNo, List<ChinaumsGuaranteePayParamsDTO> chinaumsGuaranteePayParamsDTOList) { // 保存担保消费子订单信息 for (ChinaumsGuaranteePayParamsDTO chinaumsGuaranteePayParamsDTO : chinaumsGuaranteePayParamsDTOList) { if (chinaumsGuaranteePayParamsDTO.getMetadata() != null) { // 没有合并数据的子订单 if (chinaumsGuaranteePayParamsDTO.getMetadata().getBrandFee() == null && CollectionUtils.isEmpty(chinaumsGuaranteePayParamsDTO.getMetadata().getBrandList())) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(chinaumsGuaranteePayParamsDTO, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(chinaumsGuaranteePayParamsDTO.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setGuaranteePaymentId(guaranteedOrderNo); chinaumsPayment.setSubaccountType(SubaccountType.valueOf(chinaumsGuaranteePayParamsDTO.getMetadata().getSubaccountType())); chinaumsPaymentRepository.save(chinaumsPayment); } else { // 品牌费处理 if (chinaumsGuaranteePayParamsDTO.getMetadata().getBrandFee() != null) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(chinaumsGuaranteePayParamsDTO, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(chinaumsGuaranteePayParamsDTO.getMetadata().getBrandFee()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setGuaranteePaymentId(guaranteedOrderNo); chinaumsPayment.setSubaccountType(SubaccountType.BRAND_FEE); chinaumsPaymentRepository.save(chinaumsPayment); } // 品牌授权费处理 if (CollectionUtils.isNotEmpty(chinaumsGuaranteePayParamsDTO.getMetadata().getBrandList())) { for (GuaranteePayMetaDataBrandDTO guaranteePayMetaDataBrand : chinaumsGuaranteePayParamsDTO.getMetadata().getBrandList()) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(chinaumsGuaranteePayParamsDTO, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(guaranteePayMetaDataBrand.getBrandAuthFee()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setGuaranteePaymentId(guaranteedOrderNo); chinaumsPayment.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); chinaumsPayment.setBrandId(Long.valueOf(guaranteePayMetaDataBrand.getBrandId())); chinaumsPaymentRepository.save(chinaumsPayment); } } } } else { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); chinaumsPayment.setRecvBalanceAcctId(chinaumsGuaranteePayParamsDTO.getRecvBalanceAcctId()); chinaumsPayment.setRemark(chinaumsGuaranteePayParamsDTO.getRemark()); chinaumsPayment.setOutOrderNo(chinaumsGuaranteePayParamsDTO.getOutOrderNo()); chinaumsPayment.setAmount(new BigDecimal(chinaumsGuaranteePayParamsDTO.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setGuaranteePaymentId(guaranteedOrderNo); chinaumsPaymentRepository.save(chinaumsPayment); } } } private void checkCondition(Order order, Payment payment, BigDecimal balance) { // 跟平台预存款余额比较,若不一致则抛出异常 Account depositAccount = accountRepository.findDepositAccount(order.getBuyerCompany().getId()); if (depositAccount.getBalance().compareTo(balance) != 0) { throw new YnceErrorException(YnceError.YNCE_205010); } // 判断余额是否充足 if (balance.compareTo(BigDecimal.ZERO) < 1 || balance.compareTo(order.getAmount()) == -1) { throw new YnceErrorException(YnceError.YNCE_205001); } // 获取处理中的预存款支付订单金额 BigDecimal progressPaymentAmount = paymentRepository.getProgressPaymentAmount(order.getBuyerCompany().getId()); if (progressPaymentAmount.compareTo(BigDecimal.ZERO) == 1) { // 若存在支付单,则预存款支付订单金额需减去该支付单金额 if (payment != null) { progressPaymentAmount = progressPaymentAmount.subtract(payment.getAmount()); } // 若存在处理中的,则判断余额是否足够 balance = balance.subtract(progressPaymentAmount); if (balance.compareTo(BigDecimal.ZERO) < 1 || balance.compareTo(order.getAmount()) == -1) { throw new YnceErrorException(YnceError.YNCE_205011); } } } private ByxChinaumsGuaranteePayParamsDTO getByxChinaumsGuaranteePayParamsDTO(Order order, String paymentSn, String guaranteedOrderNo, WalletOrderPayDTO walletOrderPayDTO) { ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); String subject = order.getOrderItems().get(0).getGoodsName(); if (StringUtils.isNotEmpty(order.getInvoiceContent())) { subject = order.getRemark(); } else if (StringUtils.isNotEmpty(order.getRemark())) { subject = order.getRemark(); } ByxChinaumsGuaranteePayParamsDTO byxChinaumsGuaranteePayParamsDTO = ByxChinaumsGuaranteePayParamsDTO .builder() .mctOrderNo(paymentSn) .guaranteedOrderNo(guaranteedOrderNo) .oprType(1) .payType("00") .buyerWalletId(order.getBuyerCompany().getWalletId()) .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .merWalletId(order.getSellerCompany().getWalletId()) .merName(order.getSellerCompany().getName()) .orderAmt(order.getAmount().multiply(new BigDecimal(100)).longValue()) .subject(subject) .payTimeoutExpress("1h") .notifyUrl(thirdPartyPaySet.getThirdPartyUrl() + "/chinaums/call_back/byx/result") .remark(order.getRemark()) .build(); byxChinaumsGuaranteePayParamsDTO.setEncryptPwd(walletOrderPayDTO.getPassword()); byxChinaumsGuaranteePayParamsDTO.setPlugRandomKey(walletOrderPayDTO.getPlugRandomKey()); // byxTradeWayService.setTradeWayInCert(byxChinaumsGuaranteePayParamsDTO, order.getBuyerCompany().getWalletId()); byxTradeWayService.setTradeWayByBPass(byxChinaumsGuaranteePayParamsDTO); return byxChinaumsGuaranteePayParamsDTO; } /** * 银联支付查询-通过平台单号 * * @param mctOrderNo 支付单号 * @return 银联合并消费担保下单VO * @author huabiao * @create 2023/10/17 15:07 */ @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) @Override public ByxChinaumsGuaranteePayVO orderPaymentsByOutOrderNo(String mctOrderNo, String platformWalletId) { ByxChinaumsGuaranteePayVO byxChinaumsGuaranteePayVO = new ByxChinaumsGuaranteePayVO(); try { JSONObject jsonObject = new JSONObject(); jsonObject.put("mctOrderNo", mctOrderNo); jsonObject.put("platformWalletId", platformWalletId); byxChinaumsGuaranteePayVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_QUERY_INFO, jsonObject, ByxChinaumsGuaranteePayVO.class); } catch (Exception exception) { byxChinaumsGuaranteePayVO.setRspMsg(exception.getMessage()); } return byxChinaumsGuaranteePayVO; } @Override @Transactional(rollbackFor = Exception.class) public AccountPaymentsVO payments(AccountPaymentsDTO accountPaymentsDTO) { ByxTransferDTO byxTransferDTO = new ByxTransferDTO(); AccountPaymentsVO accountPaymentsVO = new AccountPaymentsVO(); if (StringUtils.isBlank(accountPaymentsDTO.getPayBalanceAcctId())) { Company company = getUser().getCompany(); accountPaymentsDTO.setPayBalanceAcctId(company.getWalletId()); } byxTransferDTO.setMctOrderNo(accountPaymentsDTO.getOutOrderNo()); byxTransferDTO.setFromWalletId(accountPaymentsDTO.getPayBalanceAcctId()); byxTransferDTO.setIntoWalletId(accountPaymentsDTO.getRecvBalanceAcctId()); byxTransferDTO.setTransferAmt(Convert.toStr(accountPaymentsDTO.getAmount()) ); // byxTradeWayService.setTradeWayInCert(); // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_PAYMENTS, (JSONObject) JSONObject.toJSON(accountPaymentsDTO), AccountPaymentsVO.class); byxTransferDTO.setPlugRandomKey(accountPaymentsDTO.getPlugRandomKey()); byxTransferDTO.setEncryptPwd(accountPaymentsDTO.getPassword()); byxTradeWayService.setTradeWayByBPass(byxTransferDTO); ByxTransferVO byxTransferVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_PAYMENTS, (JSONObject) JSONObject.toJSON(byxTransferDTO), ByxTransferVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxTransferVO.getRspCode())){ accountPaymentsVO.setStatus( TransferState.SUCCESS.getValue()); } else { accountPaymentsVO.setStatus(TransferState.FAIL.getValue()); accountPaymentsVO.setReason(byxTransferVO.getRspResult()); } accountPaymentsVO.setPaymentId(byxTransferVO.getTransOrderNo()); accountPaymentsVO.setOutOrderNo(byxTransferVO.getTransOrderNo()); accountPaymentsVO.setTotalAmount(accountPaymentsDTO.getTotalAmount() ); accountPaymentsVO.setAmount(accountPaymentsDTO.getAmount() ); accountPaymentsVO.setDiscountAmount(accountPaymentsDTO.getDiscountAmount() ); accountPaymentsVO.setCreatedAt(accountPaymentsDTO.getSentAt() ); accountPaymentsVO.setFinishedAt(DateTimeUtils.getDateTimeToRFC3339(DateUtil.format(LocalDateTimeUtil.now(),"yyyyMMddHHmmss") ) ); accountPaymentsVO.setPayBalanceAcctId(accountPaymentsDTO.getPayBalanceAcctId()); accountPaymentsVO.setRecvBalanceAcctId(accountPaymentsDTO.getRecvBalanceAcctId()); ExternalIncomeDTO externalIncomeDTO = new ExternalIncomeDTO(); externalIncomeDTO.setAmount(accountPaymentsVO.getAmount()); externalIncomeDTO.setTradeId(accountPaymentsVO.getPaymentId()); externalIncomeDTO.setPayBalanceAcctId(accountPaymentsVO.getPayBalanceAcctId()); externalIncomeDTO.setBalanceAcctId(accountPaymentsVO.getRecvBalanceAcctId()); externalIncomeDTO.setTransactionNo(accountPaymentsVO.getPaymentId()); externalIncomeDTO.setTradeId(accountPaymentsVO.getPaymentId()); externalIncomeDTO.setRecordedAt(accountPaymentsVO.getFinishedAt()); externalIncomeDTO.setCreatedAt(accountPaymentsVO.getCreatedAt()); externalIncomeDTO.setBankMemo(accountPaymentsVO.getRemark()); externalIncomeDTO.setOrigOutOrderNo(accountPaymentsVO.getOutOrderNo()); paymentCallBack(externalIncomeDTO); return accountPaymentsVO; } /** * 分账退款 * @param byxChinaumsRefundDTO----byxChinaumsRefundDTO * @return ByxChinaumsRefundVO */ public ByxChinaumsRefundVO refundForProfitSharing(ByxChinaumsRefundDTO byxChinaumsRefundDTO) { if (StringUtils.isBlank(byxChinaumsRefundDTO.getPlatformWalletId())) { ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); byxChinaumsRefundDTO.setPlatformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()); } ByxChinaumsRefundVO byxChinaumsRefundVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_REFUND, (JSONObject) JSONObject.toJSON(byxChinaumsRefundDTO), ByxChinaumsRefundVO.class); if (byxChinaumsRefundVO == null) { log.error("系统异常,退款失败: ROUTE_WALLET_REFUND接口返回为空"); throw new YnceErrorException("系统异常,退款失败"); } return byxChinaumsRefundVO; } @Override public AccountPaymentsVO paymentsByOutOrderNo(String outOrderNo) { // Map<String, String> map = new HashMap<String, String>() {{ // put("outOrderNo", outOrderNo); // }}; // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_PAYMENTS_BY_OUT_ORDER_NO, (JSONObject) JSONObject.toJSON(byxQueryConsumePayOrderInfoDTO), AccountPaymentsVO.class); AccountPaymentsVO accountPaymentsVO = new AccountPaymentsVO(); ByxQueryConsumePayOrderInfoDTO byxQueryConsumePayOrderInfoDTO = new ByxQueryConsumePayOrderInfoDTO(); byxQueryConsumePayOrderInfoDTO.setGuaranteedOrderNo(outOrderNo); ByxQueryConsumePayOrderInfoVO byxQueryConsumePayOrderInfoVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_PAYMENTS_BY_OUT_ORDER_NO, (JSONObject) JSONObject.toJSON(byxQueryConsumePayOrderInfoDTO), ByxQueryConsumePayOrderInfoVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxQueryConsumePayOrderInfoVO.getRspCode())){ accountPaymentsVO.setPaymentId(byxQueryConsumePayOrderInfoVO.getMctOrderNo()); accountPaymentsVO.setOutOrderNo(byxQueryConsumePayOrderInfoVO.getGuaranteedOrderNo()); accountPaymentsVO.setAmount(Convert.toLong(byxQueryConsumePayOrderInfoVO.getActPayedAmt()) ); accountPaymentsVO.setTotalAmount(Convert.toLong(byxQueryConsumePayOrderInfoVO.getOrderAmt()) ); accountPaymentsVO.setRefundedAmount(Convert.toLong(byxQueryConsumePayOrderInfoVO.getRefundedAmt()) ); if(ObjectUtil.isNotEmpty(byxQueryConsumePayOrderInfoVO.getByxQueryOrderDetailPayRowVOList())){ ByxQueryOrderDetailPayRowVO byxQueryOrderDetailPayRowVO = byxQueryConsumePayOrderInfoVO.getByxQueryOrderDetailPayRowVOList().get(0); ByxQueryOrderDetailSettRowVO byxQueryOrderDetailSettRowVO = byxQueryConsumePayOrderInfoVO.getByxQueryOrderDetailSettRowVOList().get(0); if(OrderPayStatusEnum.PAYMENT_SUCCESSFUL.getValue().equals(byxQueryOrderDetailPayRowVO.getPayStatus())){ accountPaymentsVO.setStatus(OrderPaymentStatusEnum.SUCCEEDED.getValue()); } else if(OrderPayStatusEnum.SUBMITTED_PAYMENT.getValue().equals(byxQueryOrderDetailPayRowVO.getPayStatus())){ accountPaymentsVO.setStatus(OrderPaymentStatusEnum.PROCESSING.getValue()); } else if(OrderPayStatusEnum.PAYMENT_FAILED.getValue().equals(byxQueryOrderDetailPayRowVO.getPayStatus())){ accountPaymentsVO.setStatus(OrderPaymentStatusEnum.FAILED.getValue()); } // 类型为普通订单支付和合并支付时,返回订单金额。 类型为补充支付时,返回交易金额 if("02".equals(byxQueryOrderDetailPayRowVO.getType()) ){ accountPaymentsVO.setAmount(Convert.toLong(byxQueryOrderDetailPayRowVO.getPayAmt())); } else { accountPaymentsVO.setTotalAmount(Convert.toLong(byxQueryOrderDetailPayRowVO.getPayAmt())); } accountPaymentsVO.setFinishedAt(DateTimeUtils.getDateTimeToRFC3339(byxQueryOrderDetailSettRowVO.getSettTime())); } } else { accountPaymentsVO.setStatus(OrderPaymentStatusEnum.FAILED.getValue()); accountPaymentsVO.setReason(byxQueryConsumePayOrderInfoVO.getRspResult()); } return accountPaymentsVO; } @Override @Transactional(rollbackFor = Exception.class) public WithdrawalsVO withdrawals(WithdrawalsDTO withdrawalsDTO) { // Company company = getUser().getCompany(); // ByxAsyncWithdrawDTO byxAsyncWithdrawDTO = new ByxAsyncWithdrawDTO(); // if (StringUtils.isBlank(withdrawalsDTO.getBalanceAcctId())) { // withdrawalsDTO.setBalanceAcctId(company.getWalletId()); // } // withdrawalsDTO.setBusinessType("1"); // if (StringUtils.isBlank(withdrawalsDTO.getBankAcctNo())) { // ChinaumsAuthInfo chinaumsAuthInfo = chinaumsAuthInfoRepository.findFirstByCompanyId(company.getId()); // if (chinaumsAuthInfo == null) { // throw new YnceErrorException("获取银联认证信息失败"); // } // String publicKey = chinaumsUtil.getPublicKey(); // try { // withdrawalsDTO.setBankAcctNo(RSAEncryptorUtil.encryptByPublicKey(chinaumsAuthInfo.getSettleAcctBankAcctNo(), publicKey)); // } catch (Exception e) { // throw new RuntimeException(e); // } // } // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_WITHDRAWALS, (JSONObject) JSONObject.toJSON(withdrawalsDTO), WithdrawalsVO.class); // log.error("withdrawalsDTO:{}",withdrawalsDTO); WithdrawalsVO withdrawalsVO = new WithdrawalsVO(); Company company = getUser().getCompany(); ByxAsyncWithdrawDTO byxAsyncWithdrawDTO = new ByxAsyncWithdrawDTO(); if (StringUtils.isBlank(withdrawalsDTO.getBalanceAcctId())) { byxAsyncWithdrawDTO.setWalletId(company.getWalletId()); } else { byxAsyncWithdrawDTO.setWalletId(withdrawalsDTO.getBalanceAcctId()); } if (StringUtils.isBlank(withdrawalsDTO.getBankAcctNo())) { ChinaumsAuthInfo chinaumsAuthInfo = chinaumsAuthInfoRepository.findFirstByCompanyId(company.getId()); if (chinaumsAuthInfo == null) { throw new YnceErrorException("获取银联认证信息失败"); } } withdrawalsVO.setBusinessType("1"); withdrawalsVO.setBalanceAcctId(company.getWalletId()); withdrawalsVO.setAmount(Convert.toStr(withdrawalsDTO.getAmount()) ); withdrawalsVO.setOutOrderNo(withdrawalsDTO.getOutOrderNo()); withdrawalsVO.setCreatedAt(withdrawalsDTO.getSentAt()); withdrawalsVO.setServiceFee(Convert.toInt(withdrawalsDTO.getServiceFee()) ); // 提现金额 byxAsyncWithdrawDTO.setAmount(Convert.toStr(withdrawalsDTO.getAmount())); // 我们的订单号 byxAsyncWithdrawDTO.setMctOrderNo(withdrawalsDTO.getOutOrderNo()); byxAsyncWithdrawDTO.setPlugRandomKey(withdrawalsDTO.getPlugRandomKey()); byxAsyncWithdrawDTO.setEncryptPwd(withdrawalsDTO.getPassword()); byxTradeWayService.setTradeWayByBPass(byxAsyncWithdrawDTO); log.error("byxAsyncWithdrawDTO:{}",byxAsyncWithdrawDTO); ByxAsyncWithdrawVO byxAsyncWithdrawVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_WITHDRAWALS, (JSONObject) JSONObject.toJSON(byxAsyncWithdrawDTO), ByxAsyncWithdrawVO.class); // 20000:表示处理中。 通过调用查询交易结果查询最终交易状态。 if("20000".equals(byxAsyncWithdrawVO.getRspCode())){ withdrawalsVO.setStatus("processing"); withdrawalsVO.setWithdrawalId(byxAsyncWithdrawVO.getTransOrderNo()); // withdrawalsCallBack(withdrawalsVO.getOutOrderNo()); } else { withdrawalsVO.setStatus("failed"); withdrawalsVO.setReason(byxAsyncWithdrawVO.getRspResult()); } return withdrawalsVO; } @Override @Transactional(rollbackFor = Exception.class) public void withdrawalsCallBack(String outOrderNo) { AllinpayMutual allinpayMutual = allinpayMutualRepository.findFirstByBizOrderNo(outOrderNo); if (allinpayMutual == null) { log.error("未查询到提现记录!!!"); return; } if (DealStatus.DEALSTATUS_SUCC.equals(allinpayMutual.getDealStatus())) { log.warn("提现状态已更新!!!"); return; } WithdrawalsVO withdrawalsVO = withdrawalsByOutOrderNo(outOrderNo); if (withdrawalsVO == null) { log.error("【提现订单查询(平台订单号)】在银联未查询到记录!!!"); return; } if (!"processing".equals(withdrawalsVO.getStatus())) { Long companyId = allinpayMutual.getCompany().getId(); Account account = accountRepository.findDepositAccount(companyId); if (account == null) { throw new YnceErrorException("账户不存在"); } unionpayAccountService.withdrawalsHandle(account, withdrawalsVO); } } @Override @Transactional public WithdrawalsVO withdrawalsByOutOrderNo(String outOrderNo) { // Map<String, String> map = new HashMap<String, String>() {{ // put("outOrderNo", outOrderNo); // }}; // return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_WITHDRAWALS_BY_OUT_ORDER_NO, (JSONObject) JSONObject.toJSON(map), WithdrawalsVO.class); WithdrawalsVO withdrawalsVO = new WithdrawalsVO(); AllinpayMutual allinpayMutual = allinpayMutualRepository.findFirstByBizOrderNo(outOrderNo); if(ObjectUtil.isNull(allinpayMutual)){ throw new YnceErrorException("未查询到提现记录!!!"); } Company company = allinpayMutual.getCompany(); if(ObjectUtil.isNull(company)){ throw new YnceErrorException(YnceError.YNCE_201009); } ChinaumsAuthInfo chinaumsAuthInfo = company.getChinaumsAuthInfo(); if( ObjectUtil.isNull(chinaumsAuthInfo)){ throw new YnceErrorException(YnceError.YNCE_218009); } ByxQueryTransResultDTO byxQueryTransResultDTO = new ByxQueryTransResultDTO(); byxQueryTransResultDTO.setWalletId(chinaumsAuthInfo.getBalanceAcctId()); byxQueryTransResultDTO.setMctOrderNo(allinpayMutual.getBizOrderNo()); // byxTradeWayService.setTradeWayInCert(byxQueryTransResultDTO,byxQueryTransResultDTO.getWalletId()); // log.info("提现回调查询:{}",byxQueryTransResultDTO); ByxQueryTransResultVO byxQueryTransResultVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_WITHDRAWALS_BY_OUT_ORDER_NO, (JSONObject) JSONObject.toJSON(byxQueryTransResultDTO), ByxQueryTransResultVO.class); if(Constant.RETURN_SUCCESS_CODE.equals(byxQueryTransResultVO.getRspCode())){ if(ObjectUtil.isNotEmpty(byxQueryTransResultVO.getRowList())){ ByxQueryTransResultRowVO byxQueryTransResultRowVO = byxQueryTransResultVO.getRowList().get(0); withdrawalsVO.setWithdrawalId(allinpayMutual.getOriBizOrderNo()); withdrawalsVO.setOutOrderNo(outOrderNo); withdrawalsVO.setReason(byxQueryTransResultRowVO.getProcResultDscrb()); withdrawalsVO.setFinishedAt(DateTimeUtils.getDateTimeToRFC3339(byxQueryTransResultRowVO.getTransTime()) ); withdrawalsVO.setAmount(byxQueryTransResultRowVO.getSettAmt()); if("0".equals(byxQueryTransResultRowVO.getProcStatus()) || "5".equals(byxQueryTransResultRowVO.getProcStatus())){ withdrawalsVO.setStatus("processing"); } else if("1".equals(byxQueryTransResultRowVO.getProcStatus())){ withdrawalsVO.setStatus("succeeded"); } else { withdrawalsVO.setStatus("failed"); } } } return withdrawalsVO; } @Transactional(rollbackFor = Exception.class) @Override public boolean tradeResult(TradeResultDTO tradeResultDTO) { /* * 20: 支付充值; * 21: 充值退款; * 25: 可提现支付充值; * 30: 单笔提现/批量提现申请; * 40: 消费; * 41: 消费退款; * 51: 分账; * 52: 合并支付充值; * 53: 批量提现确认; * 60: 担保下单; * 62: 担保未确认退款; * 63: 担保已确认退款; * 64: 担保支付; * 66: 担保支付退款; * 67: 担保支付确认退款; * 73: 资金调拨; * 74: 提前入账 * 81: 收单通道验证打款 */ Integer tradeType = tradeResultDTO.getTradeType(); switch (tradeType) { // 支付充值 case 20: break; // 单笔提现/批量提现申请 case 30: AllinpayMutual allinpayMutual = allinpayMutualRepository.findFirstByBizOrderNo(tradeResultDTO.getOutOrderNo()); if (allinpayMutual == null) { log.error("未查询到提现记录!!!"); return false; } if (DealStatus.DEALSTATUS_SUCC.equals(allinpayMutual.getDealStatus())) { log.warn("提现状态已更新!!!"); return true; } WithdrawalsVO withdrawalsVO = walletService.withdrawalsByOutOrderNo(tradeResultDTO.getOutOrderNo()); if (withdrawalsVO == null) { log.error("【提现订单查询(平台订单号)】在银联未查询到记录!!!"); return false; } if (!"processing".equals(withdrawalsVO.getStatus())) { Long companyId = allinpayMutual.getCompany().getId(); Account account = accountRepository.findDepositAccount(companyId); if (account == null) { throw new YnceErrorException("账户不存在"); } unionpayAccountService.withdrawalsHandle(account, withdrawalsVO); } return true; // 消费(转账) case 40: //***** 分账退款转账 start *****// if (tradeResultDTO.getOutOrderNo().startsWith("FZTK-")) { // 查询分账退款单 SubaccountRefund subaccountRefund = subaccountRefundRepository.findFirstBySn(tradeResultDTO.getOutOrderNo()); if (subaccountRefund == null) { log.error("未查询到分账退款单"); return false; } if (subaccountRefund.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)) { log.info("分账退款单状态已更新"); return true; } // 通过退款单号查询订单 Refund refund = refundRepository.findFirstByRefundSn(subaccountRefund.getRefundSn()); if (refund == null) { log.error("未查询到退款单"); return false; } // 调用流水处理 subaccountRefund.setExternalId(tradeResultDTO.getTradeId()); subaccountRefund.setRefundTime(DateTimeUtils.getLocalDateTimeByRFC3339(tradeResultDTO.getFinishedAt())); subaccountRefund.setSubaccountState(SubaccountState.SEPARATE_SUCC); subaccountRefund.setOrders(refund.getOrders()); // 查询订单 subaccountRefundRepository.save(subaccountRefund); subaccountService.generateRefundSubaccount(subaccountRefund); // 处理退款单 RefundSubaccountDTO subaccountRefundDTO = RefundSubaccountDTO .builder() .refundAmount(subaccountRefund.getAmount()) .refundTime(subaccountRefund.getRefundTime()) .refundSn(subaccountRefund.getRefundSn()) .externalId(subaccountRefund.getExternalId()) .build(); refundService.handleSubaccountRefund(subaccountRefundDTO); return true; } //***** 分账退款转账 end *****// //***** 授信还款转账 start *****// if (tradeResultDTO.getOutOrderNo().startsWith("HK-")) { ReimbursementRecord record = reimbursementRecordRepository.findByOrderNo(tradeResultDTO.getOutOrderNo()); if (record != null) { if (TransferState.SUCCESS.equals(record.getState())) { log.warn("转账状态已更新!!!"); return true; } AccountPaymentsVO accountPaymentsVO = walletService.paymentsByOutOrderNo(tradeResultDTO.getOutOrderNo()); if (accountPaymentsVO == null) { log.error("【消费订单查询(平台订单号)】在银联未查询到记录!!!"); return false; } if (!"processing".equals(accountPaymentsVO.getStatus())) { PaymentDTO paymentDTO = new PaymentDTO(); paymentDTO.setId(record.getAccounts().getId()); paymentDTO.setPaymentAmount(record.getAmount()); paymentDTO.setRemarks(accountPaymentsVO.getRemark()); unionpayAccountService.unionpayCreditRefundHandle(paymentDTO, record.getReceiptCompany().getId(), accountPaymentsVO); } return true; } } //***** 授信还款转账 end *****// TransferList transferList = transferListRepository.findByTransOrderNo(tradeResultDTO.getOutOrderNo()); //***** 充值转账 start *****// if (transferList == null) { TopUpOrder topUpOrder = topUpOrderRepository.findByTransferSn(tradeResultDTO.getOutOrderNo()); if (topUpOrder == null) { log.error("未查询到转账记录!!!"); return false; } else { if (SyncState.SYNCED.equals(topUpOrder.getSyncState())) { log.warn("转账状态已更新!!!"); return true; } AccountPaymentsVO accountPaymentsVO = walletService.paymentsByOutOrderNo(tradeResultDTO.getOutOrderNo()); if (accountPaymentsVO == null) { log.error("【消费订单查询(平台订单号)】在银联未查询到记录!!!"); return false; } if ("succeeded".equals(accountPaymentsVO.getStatus())) { this.rechargeHandle(topUpOrder, accountPaymentsVO); } else if ("failed".equals(accountPaymentsVO.getStatus())) { // 转账失败,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); topUpOrderRepository.save(topUpOrder); } return true; } } //***** 充值转账 end *****// //***** 正常转账 start *****// if (TransferState.SUCCESS.equals(transferList.getState())) { log.warn("转账状态已更新!!!"); return true; } AccountPaymentsVO accountPaymentsVO = walletService.paymentsByOutOrderNo(tradeResultDTO.getOutOrderNo()); if (accountPaymentsVO == null) { log.error("【消费订单查询(平台订单号)】在银联未查询到记录!!!"); return false; } if (!"processing".equals(accountPaymentsVO.getStatus())) { Account outputAccount = accountRepository.findDepositAccount(transferList.getOutputCompany().getId()); Account inputAccount = accountRepository.findDepositAccount(transferList.getInputCompany().getId()); unionpayAccountService.transferHandle(transferList.getAmount(), inputAccount, outputAccount, accountPaymentsVO); } return true; //***** 正常转账 end *****// // 担保下单 case 60: return payCallback(tradeResultDTO); // 担保未确认退款 case 62: // 若断是否完成时间是否已超过30秒,若是则处理数据 LocalDateTime refundTime = DateTimeUtils.getLocalDateTimeByRFC3339(tradeResultDTO.getFinishedAt()); Duration duration = Duration.between(refundTime, LocalDateTime.now()); if (duration.toMillis() < 30000) { return false; } // 根据平台订单号获取银联退款单 ChinaumsRefund chinaumsRefund = chinaumsRefundRepository.findFirstByOutOrderNo(tradeResultDTO.getOutOrderNo()); if (chinaumsRefund == null) { log.error("未查询到银联退款单"); return false; } Refund refund = refundRepository.findById(chinaumsRefund.getPlatformRefundId()).orElse(null); if (refund == null) { log.error("未查询到退款单"); return false; } if ("failed".equals(tradeResultDTO.getStatus())) { chinaumsRefund.setStatus(tradeResultDTO.getStatus()); chinaumsRefundRepository.save(chinaumsRefund); return true; } else if ("succeeded".equals(tradeResultDTO.getStatus())) { // 当银联退款单状态为空或者处理中的时候,手动回写数据 if (StringUtils.isBlank(chinaumsRefund.getStatus()) || "processing".equals(chinaumsRefund.getStatus())) { // 注意:这里可能因为退款单存在多个银联退款单而导致同时更新同一个退库单而导致报错,故这里直接捕捉异常并抛出异常回滚 try { // 回写银联退款单 chinaumsRefund.setRefundId(tradeResultDTO.getTradeId()); chinaumsRefund.setStatus(tradeResultDTO.getStatus()); chinaumsRefundRepository.save(chinaumsRefund); // 获取退款单对应退款退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByPlatformRefundIdAndStatus(refund.getId(), "succeeded"); // 回写退款单 refund.setActualAmount(chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add)); refund.setRefundStatus(refund.getActualAmount().compareTo(refund.getAmount()) == 0 ? RefundStatus.REFUNDED : RefundStatus.PARTIAL_REFUNDED); refund.setRefundTime(DateTimeUtils.getLocalDateTimeByRFC3339(tradeResultDTO.getFinishedAt())); // 获取退款单号 String unionpayRefundSn = StringUtils.join(chinaumsRefundList.stream().map(ChinaumsRefund::getRefundId).collect(Collectors.toList()), ","); refund.setUnionpayRefundSn(unionpayRefundSn); refund.setThirdPartyAccount(unionpayRefundSn); refundRepository.save(refund); } catch (Exception exception) { log.error("处理银联退款单异常:" + exception.getMessage()); throw new YnceErrorException(YnceError.YNCE_000000); } } return true; } else { log.error("担保未确认退款回调状态异常"); return false; } default: throw new YnceErrorException("暂时不支持此交易类型"); } return true; } public boolean payCallback(TradeResultDTO tradeResultDTO) { // 获取支付单 Payment payment = paymentRepository.findFirstBySnOrderByIdDesc(tradeResultDTO.getOutOrderNo()); if (payment == null) { log.error("未查询到支付单"); return false; } // 支付失败 if ("03".equals(tradeResultDTO.getStatus())) { payment.setExternalId(tradeResultDTO.getTradeId()); payment.setPayStatus(PayStatus.FAILED); paymentRepository.saveAndFlush(payment); return true; } else if ("06".equals(tradeResultDTO.getStatus())) { // 获取订单 Order order = orderRepository.findById(Long.valueOf(payment.getOrderId())).orElse(null); if (order == null) { log.error("支付回调(MERGE_GUARANTEED_PAY)异常,订单不存在"); return false; } // 若订单未支付进行回调处理 if (PaymentStatus.UN_PAID.equals(order.getPaymentStatus())) { // 若订单未支付则判断是否支付时间已超过30秒,若是则手动回调 // LocalDateTime payTime = DateTimeUtils.getLocalDateTimeByRFC3339(tradeResultDTO.getFinishedAt()); // Duration duration = Duration.between(payTime, LocalDateTime.now()); // if (duration.toMillis() < 30000) { // return false; // } payment.setExternalId(tradeResultDTO.getTradeId()); payment.setPayStatus(PayStatus.SUCC); // payment.setPaymentTime(payTime); payment.setUnionpaySn(tradeResultDTO.getTradeId()); paymentRepository.saveAndFlush(payment); // 如果不存在银联支付单则生成 ---//TODO: 注释以下代码,未测试 // if (!chinaumsPaymentRepository.existsByOrdersId(order.getId())) { // handleChinaumsPayment(order); // } // 生成收款单以及后续业务操作 OrderOnlinePayVO orderOnlinePayVO = new OrderOnlinePayVO(); orderOnlinePayVO.setOrderId(Long.valueOf(payment.getOrderId())); orderOnlinePayVO.setPaymentId(payment.getId()); // orderOnlinePayVO.setPayTime(payTime); orderOnlinePayVO.setExternalId(payment.getExternalId()); ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); if (thirdPartyPaySet == null || StringUtils.isBlank(thirdPartyPaySet.getServiceUrl())) { log.error("预存款支付回调失败:未配置第三方请求地址"); return false; } JSONObject result = HttpClientUtil.getInstance().sendPost(thirdPartyPaySet.getServiceUrl() + RouteUtil.ROUTE_RECEIPT_ONLINE_PAY, orderOnlinePayVO); if (!"200".equals(result.get("code").toString())) { log.error("预存款支付回调失败:请求收款失败"); return false; } } return true; } else { log.error("担保下单回调状态异常"); return false; } } /** * POS充值后续处理 * * @param topUpOrder * @param accountPaymentsVO * @return */ private boolean rechargeHandle(TopUpOrder topUpOrder, AccountPaymentsVO accountPaymentsVO) { topUpOrder.setSyncState(SyncState.SYNCED); topUpOrder.setUnionpaySn(accountPaymentsVO.getPaymentId()); topUpOrderRepository.save(topUpOrder); AccountChangeList accountChangeList = accountChangeListRepository.findFirstBySourceNo(accountPaymentsVO.getPaymentId()); if (accountChangeList != null) { log.warn("{}充值转账入金已生成异动记录!!!", topUpOrder.getOrderType().getName()); return true; } RechargeDTO rechargeDTO = new RechargeDTO(); rechargeDTO.setCompanyId(topUpOrder.getTopUpCompany().getId()); rechargeDTO.setRechargeAmount(topUpOrder.getAmount()); rechargeDTO.setRemarks(topUpOrder.getOrderType().getName() + "充值"); rechargeDTO.setPaymentMethod(topUpOrder.getOrderType().getName() + "支付"); rechargeDTO.setFinishedDate(DateTimeUtils.getLocalDateTimeByRFC3339(accountPaymentsVO.getFinishedAt())); rechargeDTO.setSourceNo(accountPaymentsVO.getPaymentId()); return unionpayAccountService.rechargeMoney(rechargeDTO); } /** * <p>这里要根据根据订单区分计算分账金额</p> * <p>1.普通销售订单:货款、品牌公司、策划公司、服务费</p> * <p>2.OEM销售订单:货款、品牌公司、策划公司、服务费、品牌授权费</p> * * @param order 订单 * @return 银联担保支付参数DTO数组 * @description * @author huabiao * @create 2022/12/12 16:41 */ private List<ChinaumsGuaranteePayParamsDTO> getChinaumsGuaranteePayParamsDTO(Order order) { List<ChinaumsGuaranteePayParamsDTO> chinaumsGuaranteePayParamsDTOList = new ArrayList<>(); // 获取订单费用比例 OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId()); // 平台服务费 BigDecimal platformServiceFee = BigDecimal.ZERO; // 品牌授权费数组 List<ChinaumsGuaranteePayParamsDTO> brandAuthFeeChinaumsGuaranteePayParamsDTOList = new ArrayList<>(); // 计算货款 ChinaumsGuaranteePayParamsDTO goodsCost = new ChinaumsGuaranteePayParamsDTO(); if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) { if (StringUtils.isBlank(order.getSellerCompany().getWalletId())) { log.error(order.getSn() + "货款公司暂未认证银联"); throw new YnceErrorException(YnceError.YNCE_218006); } // 剩余货款 BigDecimal residueGoodsPayment = order.getGoodsPayment(); // 计算货款平台服务费 BigDecimal goodsCostPlatformServiceFee = BigDecimal.ZERO; if (orderFeeRatio.getSellerServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { goodsCostPlatformServiceFee = order.getGoodsAmount().multiply(orderFeeRatio.getSellerServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); platformServiceFee = platformServiceFee.add(goodsCostPlatformServiceFee); residueGoodsPayment = residueGoodsPayment.subtract(goodsCostPlatformServiceFee); } // 计算品牌授权费(只有当剩余货款大于0的时候才计算品牌授权费) BigDecimal totalBrandAuthCost = BigDecimal.ZERO; if (residueGoodsPayment.compareTo(BigDecimal.ZERO) == 1 && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) { // 通过订单项中的品牌ID分组 Map<Long, List<OrderItemFeeRatio>> brandIdOrderItemFeeRatioListMap = orderFeeRatio.getOrderItemFeeRatio().stream() .collect(Collectors.groupingBy(orderItemFeeRatio -> orderItemFeeRatio.getOrderItem().getBrandId())); int i = 1; for (Map.Entry<Long, List<OrderItemFeeRatio>> brandIdOrderItemFeeRatioListEntry : brandIdOrderItemFeeRatioListMap.entrySet()) { Long brandId = brandIdOrderItemFeeRatioListEntry.getKey(); List<OrderItemFeeRatio> orderItemFeeRatioList = brandIdOrderItemFeeRatioListEntry.getValue(); Brand brand = brandRepository.findById(brandId).orElse(null); if (brand == null || StringUtils.isBlank(brand.getCompany().getWalletId())) { continue; } // 获取订单项 List<OrderItem> orderItemList = orderItemFeeRatioList.stream().map(orderItemFeeRatio -> orderItemFeeRatio.getOrderItem()).collect(Collectors.toList()); BigDecimal orderAmount = orderItemList.stream().map(OrderItem::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); // 品牌授权费比例 BigDecimal brandAuthCostRatio = orderItemFeeRatioList.get(0).getBrandAuthCostRatio(); // 计算货款 BigDecimal brandGoodsPayment = orderItemList.stream().map(OrderItem::getGoodsPayment).reduce(BigDecimal.ZERO, BigDecimal::add); // 品牌授权费(采取四舍五入的计算方式) BigDecimal brandAuthCost = brandGoodsPayment.multiply(brandAuthCostRatio).setScale(2, BigDecimal.ROUND_HALF_UP); // 品牌授权费服务费比例 BigDecimal brandAuthCostServiceCostRatio = orderItemFeeRatioList.get(0).getBrandAuthCostServiceCostRatio(); // 计算平台服务费 BigDecimal brandAuthCostServiceFee = BigDecimal.ZERO; if (brandAuthCostServiceCostRatio.compareTo(BigDecimal.ZERO) == 1) { brandAuthCostServiceFee = brandAuthCost.multiply(brandAuthCostServiceCostRatio).setScale(2, BigDecimal.ROUND_UP); platformServiceFee = platformServiceFee.add(brandAuthCostServiceFee); brandAuthCost = brandAuthCost.subtract(brandAuthCostServiceFee); } // 品牌授权费 if (brandAuthCost.compareTo(BigDecimal.ZERO) == 1) { ChinaumsGuaranteePayParamsDTO brandAuthFee = new ChinaumsGuaranteePayParamsDTO(); brandAuthFee.setAmount(brandAuthCost.multiply(new BigDecimal(100)).intValue()); brandAuthFee.setRecvBalanceAcctId(brand.getCompany().getWalletId()); brandAuthFee.setOutOrderNo(order.getSn() + "-" + SubaccountType.BRAND_AUTH_FEE.getValue() + "-" + i); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO brandAuthExtraDTO = new ChinaumsGuaranteePayExtraDTO(); brandAuthExtraDTO.setProductInfos(this.handleProductInfo(orderItemList, order.getSn(), orderAmount, brandAuthCost)); brandAuthFee.setExtra(brandAuthExtraDTO); List<GuaranteePayMetaDataBrandDTO> brandList = Arrays.asList(GuaranteePayMetaDataBrandDTO.builder().brandId(brandId.toString()).brandAuthFee(brandAuthFee.getAmount()).build()); brandAuthFee.setMetadata(ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.BRAND_AUTH_FEE.getValue()).brandList(brandList).build()); brandAuthFeeChinaumsGuaranteePayParamsDTOList.add(brandAuthFee); i++; totalBrandAuthCost = totalBrandAuthCost.add(brandAuthCost).add(brandAuthCostServiceFee); } } } // 货款 = 初始货款 - 平台服务费 - 品牌授权费 BigDecimal goodsPayment = order.getGoodsPayment().subtract(goodsCostPlatformServiceFee).subtract(totalBrandAuthCost); if (goodsPayment.compareTo(BigDecimal.ZERO) == 1) { goodsCost.setAmount(goodsPayment.multiply(new BigDecimal(100)).intValue()); goodsCost.setRecvBalanceAcctId(order.getSellerCompany().getWalletId()); goodsCost.setOutOrderNo(order.getSn() + "-" + SubaccountType.GOODS_COST.getValue()); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfo(order.getOrderItems(), order.getSn(), order.getAmount(), goodsPayment)); goodsCost.setExtra(chinaumsGuaranteePayExtraDTO); goodsCost.setMetadata(ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.GOODS_COST.getValue()).build()); chinaumsGuaranteePayParamsDTOList.add(goodsCost); } } // 计算品牌费 ChinaumsGuaranteePayParamsDTO brandFee = new ChinaumsGuaranteePayParamsDTO(); if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) { if (StringUtils.isBlank(order.getBrandCompany().getWalletId())) { log.error(order.getSn() + "品牌公司暂未认证银联"); throw new YnceErrorException(YnceError.YNCE_218006); } // 计算货款平台服务费 BigDecimal brandFeePlatformServiceFee = BigDecimal.ZERO; if (orderFeeRatio.getBrandServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { brandFeePlatformServiceFee = order.getBrandCost().multiply(orderFeeRatio.getBrandServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); platformServiceFee = platformServiceFee.add(brandFeePlatformServiceFee); } brandFee.setRecvBalanceAcctId(order.getBrandCompany().getWalletId()); brandFee.setOutOrderNo(order.getSn() + "-" + SubaccountType.BRAND_FEE.getValue()); // 品牌费 BigDecimal brandCost = order.getBrandCost().subtract(brandFeePlatformServiceFee); // 自定义参数 ChinaumsGuaranteePayMetaDataDTO metadata; if (CollectionUtils.isNotEmpty(brandAuthFeeChinaumsGuaranteePayParamsDTOList)) { BigDecimal originalBrandCost = brandCost; List<GuaranteePayMetaDataBrandDTO> brandList = new ArrayList<>(); for (ChinaumsGuaranteePayParamsDTO chinaumsGuaranteePayParamsDTO : brandAuthFeeChinaumsGuaranteePayParamsDTOList) { // 判断品牌授权费和品牌是否为同一家公司 if (!brandFee.getRecvBalanceAcctId().equals(chinaumsGuaranteePayParamsDTO.getRecvBalanceAcctId())) { log.error("品牌授权费和品牌费的所属公司不是一家"); throw new YnceErrorException(YnceError.YNCE_218006); } brandCost = brandCost.add(new BigDecimal(chinaumsGuaranteePayParamsDTO.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); brandList.addAll(chinaumsGuaranteePayParamsDTO.getMetadata().getBrandList()); } if (originalBrandCost.compareTo(BigDecimal.ZERO) == 1) { metadata = ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.BRAND_FEE.getValue()).brandFee(originalBrandCost.multiply(new BigDecimal(100)).intValue()).brandList(brandList).build(); } else { metadata = ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.BRAND_FEE.getValue()).brandList(brandList).build(); } } else { metadata = ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.BRAND_FEE.getValue()).brandFee(brandCost.multiply(new BigDecimal(100)).intValue()).build(); } if (brandCost.compareTo(BigDecimal.ZERO) == 1) { brandFee.setAmount(brandCost.multiply(new BigDecimal(100)).intValue()); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); List<JSONObject> productInfos = this.handleProductInfo(order.getOrderItems(), order.getSn(), order.getAmount(), brandCost); chinaumsGuaranteePayExtraDTO.setProductInfos(productInfos); brandFee.setExtra(chinaumsGuaranteePayExtraDTO); // 拼接自定义参数 brandFee.setMetadata(metadata); chinaumsGuaranteePayParamsDTOList.add(brandFee); } } else { // 不存在品牌费但是存在品牌授权费 if (CollectionUtils.isNotEmpty(brandAuthFeeChinaumsGuaranteePayParamsDTOList)) { brandFee.setRecvBalanceAcctId(brandAuthFeeChinaumsGuaranteePayParamsDTOList.get(0).getRecvBalanceAcctId()); brandFee.setOutOrderNo(order.getSn() + "-" + SubaccountType.BRAND_FEE.getValue()); BigDecimal brandAuthCost = BigDecimal.ZERO; ChinaumsGuaranteePayMetaDataDTO metadata; List<GuaranteePayMetaDataBrandDTO> brandList = new ArrayList<>(); for (ChinaumsGuaranteePayParamsDTO chinaumsGuaranteePayParamsDTO : brandAuthFeeChinaumsGuaranteePayParamsDTOList) { if (!brandFee.getRecvBalanceAcctId().equals(chinaumsGuaranteePayParamsDTO.getRecvBalanceAcctId())) { log.error("品牌授权费所属公司不是一家"); throw new YnceErrorException(YnceError.YNCE_218006); } brandAuthCost = brandAuthCost.add(new BigDecimal(chinaumsGuaranteePayParamsDTO.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); brandList.addAll(chinaumsGuaranteePayParamsDTO.getMetadata().getBrandList()); } brandFee.setAmount(brandAuthCost.multiply(new BigDecimal(100)).intValue()); metadata = ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.BRAND_FEE.getValue()).brandList(brandList).build(); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); List<JSONObject> productInfos = this.handleProductInfo(order.getOrderItems(), order.getSn(), order.getAmount(), brandAuthCost); chinaumsGuaranteePayExtraDTO.setProductInfos(productInfos); brandFee.setExtra(chinaumsGuaranteePayExtraDTO); // 拼接自定义参数 brandFee.setMetadata(metadata); chinaumsGuaranteePayParamsDTOList.add(brandFee); } } // 计算策划费 ChinaumsGuaranteePayParamsDTO deviseFee = new ChinaumsGuaranteePayParamsDTO(); if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) { if (StringUtils.isBlank(order.getDeviseCompany().getWalletId())) { log.error(order.getSn() + "策划公司暂未认证银联"); throw new YnceErrorException(YnceError.YNCE_218006); } // 计算货款平台服务费 BigDecimal deviseFeePlatformServiceFee = BigDecimal.ZERO; if (orderFeeRatio.getDeviseServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) { deviseFeePlatformServiceFee = order.getDeviseCost().multiply(orderFeeRatio.getDeviseServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP); platformServiceFee = platformServiceFee.add(deviseFeePlatformServiceFee); } // 实际分账的策划费 BigDecimal deviseCost = order.getDeviseCost().subtract(deviseFeePlatformServiceFee); if (deviseCost.compareTo(BigDecimal.ZERO) == 1) { deviseFee.setAmount(deviseCost.multiply(new BigDecimal(100)).intValue()); deviseFee.setRecvBalanceAcctId(order.getDeviseCompany().getWalletId()); deviseFee.setOutOrderNo(order.getSn() + "-" + SubaccountType.DEVISE_FEE.getValue()); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfo(order.getOrderItems(), order.getSn(), order.getAmount(), deviseCost)); deviseFee.setExtra(chinaumsGuaranteePayExtraDTO); deviseFee.setMetadata(ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.DEVISE_FEE.getValue()).build()); chinaumsGuaranteePayParamsDTOList.add(deviseFee); } } // 平台服务费 if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) { String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId(); if (StringUtils.isBlank(balanceAcctId)) { log.error(order.getSn() + "平台公司暂未认证银联"); throw new YnceErrorException(YnceError.YNCE_218006); } ChinaumsGuaranteePayParamsDTO platformServiceFeeDTO = new ChinaumsGuaranteePayParamsDTO(); platformServiceFeeDTO.setAmount(platformServiceFee.multiply(new BigDecimal(100)).intValue()); platformServiceFeeDTO.setRecvBalanceAcctId(balanceAcctId); platformServiceFeeDTO.setOutOrderNo(order.getSn() + "-" + SubaccountType.SERVICE_FEE.getValue()); // 拼接扩展商品信息 ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO(); chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfo(order.getOrderItems(), order.getSn(), order.getAmount(), platformServiceFee)); platformServiceFeeDTO.setExtra(chinaumsGuaranteePayExtraDTO); platformServiceFeeDTO.setMetadata(ChinaumsGuaranteePayMetaDataDTO.builder().subaccountType(SubaccountType.SERVICE_FEE.getValue()).build()); chinaumsGuaranteePayParamsDTOList.add(platformServiceFeeDTO); } return chinaumsGuaranteePayParamsDTOList; } /** * 处理商品数据 * * @param orderItemList:订单项 * @param sn:订单号 * @param orderAmount:订单金额 * @param amount:分摊金额 * @return 处理完的银联JSON数据 * @author huabiao * @create 2022/12/15 14:08 */ private List<JSONObject> handleProductInfo(List<OrderItem> orderItemList, String sn, BigDecimal orderAmount, BigDecimal amount) { // 循环订单项 List<JSONObject> productInfos = new ArrayList<>(); BigDecimal allocatedAmount = BigDecimal.ZERO; for (int i = 0; i < orderItemList.size(); i++) { OrderItem orderItem = orderItemList.get(i); JSONObject jsonObject = new JSONObject(); jsonObject.put("orderNo", sn + "-" + orderItem.getId()); // 按比例计算,最后一项直接减完 if (i == (orderItemList.size() - 1)) { jsonObject.put("orderAmount", amount.subtract(allocatedAmount).multiply(new BigDecimal(100)).intValue()); } else { BigDecimal orderItemPlatformServiceFee = amount.multiply(orderItem.getAmount()).divide(orderAmount, 2, BigDecimal.ROUND_DOWN); // 当计算结果不大于0时,赋值0.01 if (orderItemPlatformServiceFee.compareTo(BigDecimal.ZERO) != 1) { orderItemPlatformServiceFee = new BigDecimal("0.01"); } jsonObject.put("orderAmount", orderItemPlatformServiceFee.multiply(new BigDecimal(100)).intValue()); allocatedAmount = allocatedAmount.add(orderItemPlatformServiceFee); } jsonObject.put("productName", orderItem.getGoodsName() + orderItem.getSkuName()); jsonObject.put("productCount", orderItem.getQuantity()); productInfos.add(jsonObject); } return productInfos; } @Transactional(propagation = Propagation.NOT_SUPPORTED) @Override public ChinaumsGuaranteePayConfirmsVO paySettlement(ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO) { ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS, (JSONObject) JSONObject.toJSON(chinaumsGuaranteePayConfirmsDTO), ChinaumsGuaranteePayConfirmsVO.class); return chinaumsGuaranteePayConfirmsVO; } @Override @Transactional(propagation = Propagation.NOT_SUPPORTED) public String paySettlementConfirms(ByxChinaumsGuaranteePayConfirmsDTO byxChinaumsGuaranteePayConfirmsDTO) { JSONObject result = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS, (JSONObject) JSONObject.toJSON(byxChinaumsGuaranteePayConfirmsDTO), JSONObject.class); // 返回数据为空,则表示异常 if (result == null || result.get("settOrderNo") == null) { return null; } JSONObject params = new JSONObject(); params.put("settOrderNo", result.get("settOrderNo")); // 循环5次,每次卡睡眠2秒,共10秒 for (int i = 0; i < 5; i++) { try { Thread.sleep(2000); } catch (InterruptedException e) { log.error("结算确认的调度睡眠异常:" + e.getMessage()); } JSONObject queryResult = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS_QUERY, params, JSONObject.class); if (queryResult == null || queryResult.get("settStatus") == null) { continue; } // 01: if ("00".equals(queryResult.get("settStatus").toString()) || "01".equals(queryResult.get("settStatus").toString()) || "03".equals(queryResult.get("settStatus").toString())) { continue; } break; } return result.get("settOrderNo").toString(); } @Override @Transactional(rollbackFor = Exception.class) public List<ChinaumsPayment> handleChinaumsPayment(Order order) { List<ChinaumsPayment> chinaumsPaymentList = new ArrayList<>(); // 获取支付单 List<Payment> paymentList = paymentRepository.findAllByOrderId(order.getId().toString()); if (CollectionUtils.isEmpty(paymentList)) { return chinaumsPaymentList; } Payment payment = paymentList.get(0); // 通过系统订单号查询合并消费担保下单数据 // ByxChinaumsGuaranteePayVO byxChinaumsGuaranteePayVO = walletService.orderPaymentsByOutOrderNo(payment.getExternalId()); List<ChinaumsGuaranteePayParamsDTO> chinaumsGuaranteePayParamsDTOList = this.getChinaumsGuaranteePayParamsDTO(order); // JSONObject jsonObject = new JSONObject(); // jsonObject.put("combinedGuaranteePaymentId", payment.getExternalId()); // ChinaumsGuaranteePayVO chinaumsGuaranteePayVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_BY_SYS_NO, jsonObject, ChinaumsGuaranteePayVO.class); // 保存担保消费子订单信息 for (ChinaumsGuaranteePayParamsDTO guaranteePaymentResult : chinaumsGuaranteePayParamsDTOList) { if (guaranteePaymentResult.getMetadata() != null) { // 没有合并数据的子订单 if (guaranteePaymentResult.getMetadata().getBrandFee() == null && CollectionUtils.isEmpty(guaranteePaymentResult.getMetadata().getBrandList())) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(guaranteePaymentResult, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(guaranteePaymentResult.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setSubaccountType(SubaccountType.valueOf(guaranteePaymentResult.getMetadata().getSubaccountType())); chinaumsPaymentRepository.save(chinaumsPayment); chinaumsPaymentList.add(chinaumsPayment); } else { // 品牌费处理 if (guaranteePaymentResult.getMetadata().getBrandFee() != null && guaranteePaymentResult.getMetadata().getBrandFee() > 0) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(guaranteePaymentResult, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(guaranteePaymentResult.getMetadata().getBrandFee()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setSubaccountType(SubaccountType.BRAND_FEE); chinaumsPaymentRepository.save(chinaumsPayment); chinaumsPaymentList.add(chinaumsPayment); } // 品牌授权费处理 if (CollectionUtils.isNotEmpty(guaranteePaymentResult.getMetadata().getBrandList())) { for (GuaranteePayMetaDataBrandDTO guaranteePayMetaDataBrand : guaranteePaymentResult.getMetadata().getBrandList()) { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(guaranteePaymentResult, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(guaranteePayMetaDataBrand.getBrandAuthFee()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPayment.setSubaccountType(SubaccountType.BRAND_AUTH_FEE); chinaumsPayment.setBrandId(Long.valueOf(guaranteePayMetaDataBrand.getBrandId())); chinaumsPaymentRepository.save(chinaumsPayment); chinaumsPaymentList.add(chinaumsPayment); } } } } else { ChinaumsPayment chinaumsPayment = new ChinaumsPayment(); BeanUtils.copyProperties(guaranteePaymentResult, chinaumsPayment, "amount"); chinaumsPayment.setAmount(new BigDecimal(guaranteePaymentResult.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP)); chinaumsPayment.setOrders(order); chinaumsPaymentRepository.save(chinaumsPayment); chinaumsPaymentList.add(chinaumsPayment); } } return chinaumsPaymentList; } @Transactional(rollbackFor = Exception.class) @Override public Boolean transferDeposit(ExternalIncomeDTO externalIncomeDTO) { /* * 10: 母户入金 * 11: 转账入金 * 13: 大额订单入金 * 33: 提现退汇 * 37: 虚户入金退回退汇 * 39: 大额订单入金退回退汇 * 79: 资金划扣退汇 * 84: 收单通道验证打款退汇 */ switch (externalIncomeDTO.getTradeType()) { // 母户入金 case "10": log.info("母户入金【{}】:{}", externalIncomeDTO.getBalanceAcctId(), externalIncomeDTO.getAmount()); break; case "94": // 在途金额已生成流水,所以这里在途金额到账不处理 log.info("在途金额到账【{}】:{}", externalIncomeDTO.getBalanceAcctId(), externalIncomeDTO.getAmount()); break; // 转账入金(用户通过手机银行充值) case "11": case "93": ChinaumsAuthInfo chinaumsAuthInfo = chinaumsAuthInfoRepository.findFirstByBalanceAcctId(externalIncomeDTO.getBalanceAcctId()); if (chinaumsAuthInfo == null) { throw new YnceErrorException("未查询到银联认证信息"); } AccountChangeList accountChangeList = accountChangeListRepository.findFirstBySourceNo(externalIncomeDTO.getTradeId()); if (accountChangeList != null) { log.warn("该入金已生成异动记录!!!"); return true; } Company company = chinaumsAuthInfo.getCompany(); // Account account = accountRepository.findDepositAccount(company.getId()); // TopUpList topUpList = topUpListRepository.findTopByAccountAndStateOrderByCreatedOnDesc(account, TopUpState.PAID); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss+08:00") .withZone(ZoneId.of("Asia/Shanghai")); // 可查90个自然日的交易,单次查询开始和结束时间间隔不大于7天 LocalDateTime dateTime = LocalDateTime.now().minusDays(1L); BalanceTransactionsPageVO balanceTransactionsPageVO = this.balanceTransactions(company.getWalletId(),externalIncomeDTO.getTradeId(), dateTime.toString(), LocalDateTime.now().toString()); if (balanceTransactionsPageVO.getTotal() <= 0) { log.warn("未查询到流水记录!!!"); return false; } // 标记查询的流水中是否有当前入金的回调 boolean flag = false; List<BalanceTransactionsPageVO.BalanceTransactionsVO> data = balanceTransactionsPageVO.getData(); for (BalanceTransactionsPageVO.BalanceTransactionsVO d : data) { // 只处理交易类型为入金的流水 if (d.getTradeType() != 11 && d.getTradeType() != 93) { continue; } if (externalIncomeDTO.getTradeId().equals(d.getTradeId())) { flag = true; RechargeDTO rechargeDTO = new RechargeDTO(); rechargeDTO.setCompanyId(company.getId()); BigDecimal rechargeAmount; if (d.getSettledAmount() > 0) { rechargeAmount = new BigDecimal(d.getSettledAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } else { rechargeAmount = new BigDecimal(d.getPendingAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } rechargeDTO.setRechargeAmount(rechargeAmount); if (StringUtils.isNotEmpty(d.getRemark())) { rechargeDTO.setRemarks(d.getRemark()); } else { rechargeDTO.setRemarks("银联钱包充值"); } rechargeDTO.setPaymentMethod("银联支付"); // rechargeDTO.setFinishedDate(LocalDateTime.parse(d.getSucceededAt(), DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSzzz"))); rechargeDTO.setFinishedDate(Convert.toLocalDateTime(d.getSucceededAt())); rechargeDTO.setSourceNo(d.getTradeId()); if(unionpayAccountService.rechargeMoney(rechargeDTO)){ log.info("【{}】生成充值记录成功",company.getName()); } else { log.error("【{}】生成充值记录失败",company.getName()); } break; } } return flag; default: throw new YnceErrorException("暂不支持此交易类型:{}", externalIncomeDTO.getTradeType()); } return true; } @Override public RefundVO refund(WalletRefundDTO walletRefundDTO) { Payment payment = paymentRepository.findFirstBySnOrderByIdDesc(walletRefundDTO.getPaymentNo()); if (payment == null) { throw new YnceErrorException(YnceError.YNCE_205007); } if (!payment.getPayStatus().equals(PayStatus.SUCC)) { throw new YnceErrorException(YnceError.YNCE_218013); } Order order = orderRepository.findById(walletRefundDTO.getOrderId()).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_211004); } if (order.getIsSeparateAccounts()) { throw new YnceErrorException(YnceError.YNCE_227001); } // 获取退款单已请求的所有银联退款单 List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByPlatformRefundId(walletRefundDTO.getRefundId()); // 获取银联支付单 List<ChinaumsPayment> chinaumsPaymentList = chinaumsPaymentRepository.findAllByOrdersId(walletRefundDTO.getOrderId()); if (CollectionUtils.isNotEmpty(chinaumsPaymentList)) { // 计算总银联支付金额 BigDecimal totalAmount = chinaumsPaymentList.stream().map(chinaumsPayment -> chinaumsPayment.getAmount()).reduce(BigDecimal.ZERO, BigDecimal::add); // 订单银联退款单(该订单下的所有银联退款单,不包含当前退款单) List<ChinaumsRefund> orderChinaumsRefundList = new ArrayList<>(); // 查询银联该合并消费担保订单的总退款金额 BigDecimal totalRefundAmount = BigDecimal.ZERO; // 查询所有银联退款单的总金额(不包含当前退款单) List<Long> orderRefundIdList = order.getRefunds().stream().filter(refund -> !refund.getId().equals(walletRefundDTO.getRefundId())).map(Refund::getId).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(orderRefundIdList)) { orderChinaumsRefundList = chinaumsRefundRepository.findAllByPlatformRefundIdIn(orderRefundIdList); // TODO 这里是否需要考虑退款成功与否 totalRefundAmount = orderChinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } // 判断是否最后一次退款【订单支付金额-总退款金额 = 本次退款金额】 Boolean isFinallyRefund = order.getPayAmount().subtract(totalRefundAmount).compareTo(walletRefundDTO.getAmount()) == 0; // 已处理退款金额 ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); BigDecimal handleAmount = BigDecimal.ZERO; for (int i = 0; i < chinaumsPaymentList.size(); i++) { Boolean isRequestRefund = false; ChinaumsPayment chinaumsPayment = chinaumsPaymentList.get(i); // 根据平台退款ID和原始系统订单号以及分账类型查询是否存在银联退款单(因为品牌费和品牌授权费是同一家公司收取,所以这里需要通过分账类型区分) ChinaumsRefund chinaumsRefund = chinaumsRefundList.stream().filter(filterChinaumsRefund -> filterChinaumsRefund.getPlatformRefundId().equals(walletRefundDTO.getRefundId()) && filterChinaumsRefund.getOrigTradeId().equals(chinaumsPayment.getGuaranteePaymentId()) && filterChinaumsRefund.getSubaccountType().equals(chinaumsPayment.getSubaccountType())).findFirst().orElse(null); if (chinaumsRefund != null) { handleAmount = handleAmount.add(chinaumsRefund.getAmount()); // 若状态为空则主动查询 if (StringUtils.isBlank(chinaumsRefund.getStatus())) { try { // 调用查询接口 JSONObject jsonObject = new JSONObject(); // jsonObject.put("outOrderNo", chinaumsRefund.getOutOrderNo()); jsonObject.put("transOrderNo", walletRefundDTO.getPaymentNo()); jsonObject.put("platformWalletId", thirdPartyPaySet.getChinaumsFeeBalanceAcctId()); ByxChinaumsRefundVO chinaumsRefundVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_REFUND_QUERY, (JSONObject) JSONObject.toJSON(jsonObject), ByxChinaumsRefundVO.class); chinaumsRefund.setRefundId(chinaumsRefundVO.getMctOrderNo()); chinaumsRefund.setStatus(chinaumsRefundVO.getRefundStatus()); chinaumsRefund.setReason(chinaumsRefundVO.getAbst()); chinaumsRefund.setRemark(chinaumsRefundVO.getRemark()); chinaumsRefundRepository.save(chinaumsRefund); } catch (Exception exception) { log.error("{}请求查询银联退款单失败:{}", chinaumsRefund.getOutOrderNo(), exception.getMessage()); if (StringUtils.isNotBlank(exception.getMessage()) && exception.getMessage().contains("请求的资源不存在")) { isRequestRefund = true; } else { continue; } } } } else { BigDecimal refundAmount; // 当为最后一次退款时,需要将子订单剩余金额退完 if (isFinallyRefund) { // 获取已退款金额 BigDecimal refundedAmount = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(orderChinaumsRefundList)) { // 根据原始系统订单号以及分账类型查询已退款金额(因为品牌费和品牌授权费是同一家公司收取,所以这里需要通过分账类型区分) refundedAmount = orderChinaumsRefundList.stream().filter(orderChinaumsRefund -> orderChinaumsRefund.getOrigTradeId().equals(chinaumsPayment.getGuaranteePaymentId()) && orderChinaumsRefund.getSubaccountType().equals(chinaumsPayment.getSubaccountType())) .collect(Collectors.toList()).stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); } refundAmount = chinaumsPayment.getAmount().subtract(refundedAmount); } else { // 最后一个单时直接用剩余的金额计算 if (i == (chinaumsPaymentList.size() - 1)) { refundAmount = walletRefundDTO.getAmount().subtract(handleAmount); } else { refundAmount = walletRefundDTO.getAmount().multiply(chinaumsPayment.getAmount()).divide(totalAmount, 2, RoundingMode.DOWN); } } String outOrderNo = walletRefundDTO.getRefundNo() + chinaumsPayment.getId(); // 先保存银联退款单 chinaumsRefund = new ChinaumsRefund(); chinaumsRefund.setOutOrderNo(outOrderNo); chinaumsRefund.setAmount(refundAmount); chinaumsRefund.setOrigTradeId(chinaumsPayment.getGuaranteePaymentId()); chinaumsRefund.setOrigOutOrderNo(chinaumsPayment.getOutOrderNo()); chinaumsRefund.setOrigPayBalanceAcctId(chinaumsPayment.getPayBalanceAcctId()); chinaumsRefund.setOrigRecvBalanceAcctId(chinaumsPayment.getRecvBalanceAcctId()); chinaumsRefund.setPlatformRefundId(walletRefundDTO.getRefundId()); chinaumsRefund.setSubaccountType(chinaumsPayment.getSubaccountType()); chinaumsRefundRepository.save(chinaumsRefund); chinaumsRefundList.add(chinaumsRefund); handleAmount = handleAmount.add(chinaumsRefund.getAmount()); isRequestRefund = true; } // 请求银联退款 if (isRequestRefund) { // ChinaumsRefundDTO chinaumsRefundDTO = ChinaumsRefundDTO // .builder() // .outOrderNo(chinaumsRefund.getOutOrderNo()) // .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date())) // .amount(chinaumsRefund.getAmount().multiply(new BigDecimal(100)).intValue()) // .origTradeId(chinaumsPayment.getGuaranteePaymentId()) // .build(); ByxChinaumsRefundDTO byxChinaumsRefundDTO = ByxChinaumsRefundDTO .builder() .mctOrderNo(chinaumsRefund.getOutOrderNo()) .refundAmt(chinaumsRefund.getAmount().multiply(new BigDecimal(100)).longValue()) .guaranteedOrderNo(chinaumsPayment.getGuaranteePaymentId()) .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .build(); try { // 发起退款请求-----实时 ByxChinaumsRefundVO byxChinaumsRefundVO = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_REFUND, (JSONObject) JSONObject.toJSON(byxChinaumsRefundDTO), ByxChinaumsRefundVO.class); // // processing:处理中 // succeeded:成功 // failed:失败 // chinaumsRefund.setStatus("succeeded"); if (!"00000".equals(byxChinaumsRefundVO.getRspCode())) { log.error("{}请求银联退款失败:{}", byxChinaumsRefundVO.getMctOrderNo(), byxChinaumsRefundVO.getRspResult()); chinaumsRefund.setStatus("failed"); throw new YnceErrorException("请求银联退款失败:" + byxChinaumsRefundVO.getRspResult()); } // 获取请求结果 chinaumsRefund.setRefundId(byxChinaumsRefundVO.getTransOrderNo()); chinaumsRefund.setReason(byxChinaumsRefundVO.getAbst()); chinaumsRefund.setRemark(byxChinaumsRefundVO.getRemark()); chinaumsRefundRepository.save(chinaumsRefund); // 更新账号余额 if (chinaumsRefund.getStatus().equals("succeeded")) { accountRepository.subBalanceForCompany(chinaumsRefund.getAmount(), Long.parseLong(chinaumsRefund.getOrigRecvBalanceAcctId())); } } catch (Exception exception) { log.error("{}请求银联退款失败:{}", byxChinaumsRefundDTO.getMctOrderNo(), exception.getMessage()); } } // 如果退款状态是处理中,则循环查询,时间不超过5秒 // if ("processing".equals(chinaumsRefund.getStatus())) { // try { // long currentTimeMillis = System.currentTimeMillis(); // while (true) { // // 调用查询接口 // JSONObject jsonObject = new JSONObject(); // jsonObject.put("refundId", chinaumsRefund.getRefundId()); // ChinaumsRefundVO chinaumsRefundVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_REFUND_BY_SYS_NO, (JSONObject) JSONObject.toJSON(jsonObject), ChinaumsRefundVO.class); // // 当请求成功或者时间超时时,结束循环 // if (!"processing".equals(chinaumsRefundVO.getStatus()) || System.currentTimeMillis() - currentTimeMillis > 5000) { // chinaumsRefund.setStatus(chinaumsRefundVO.getStatus()); // chinaumsRefund.setReason(chinaumsRefundVO.getReason()); // chinaumsRefund.setRemark(chinaumsRefundVO.getRemark()); // chinaumsRefundRepository.save(chinaumsRefund); // break; // } // } // } catch (Exception exception) { // log.error("{}请求银联退款状态失败:{}", chinaumsRefund.getOutOrderNo(), exception.getMessage()); // } // } } } RefundVO refundVO = new RefundVO(); if (CollectionUtils.isNotEmpty(chinaumsRefundList)) { // 获取成功退款的单号 List<ChinaumsRefund> succeededChinaumsRefundList = chinaumsRefundList.stream().filter(chinaumsRefund -> "succeeded".equals(chinaumsRefund.getStatus())).collect(Collectors.toList()); refundVO.setRefundAmount(succeededChinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add)); refundVO.setRefundStatus(refundVO.getRefundAmount().compareTo(walletRefundDTO.getAmount()) == 0 ? RefundStatus.REFUNDED : RefundStatus.PARTIAL_REFUNDED); refundVO.setRefundTime(LocalDateTime.now()); // 获取退款单号 List<String> refundIdList = succeededChinaumsRefundList.stream().map(chinaumsRefund -> chinaumsRefund.getRefundId()).collect(Collectors.toList()); refundVO.setExternalId(StringUtils.join(refundIdList, ",")); } else { refundVO.setRefundStatus(RefundStatus.UN_REFUND); } return refundVO; } @Transactional(propagation = Propagation.NOT_SUPPORTED) @Override public ChinaumsAllocationsVO createSubaccount(ChinaumsAllocationsDTO chinaumsAllocationsDTO) { ChinaumsAllocationsVO chinaumsAllocationsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_UPAPI_ALLOCATIONS, (JSONObject) JSONObject.toJSON(chinaumsAllocationsDTO), ChinaumsAllocationsVO.class); return chinaumsAllocationsVO; } @Override public void posTransfer() { List<TopUpOrder> topUpOrders = topUpOrderRepository.findByOrderTypeAndPaymentStatusAndSyncStateInAndPayTimeLessThanAndRefundedIsFalseOrderByPayTime( TopUpOrderType.POS, PayStatus.SUCC, Arrays.asList(SyncState.SYNCEDERROR, SyncState.UNSYNCED), LocalDateTime.of(LocalDate.now(), LocalTime.MIN)); if (CollectionUtils.isEmpty(topUpOrders)) { log.warn("POS充值转账 - 待转账记录为空!"); return; } // 根据所属企业分组 Map<Company, List<TopUpOrder>> companyTopUpOrderList = topUpOrders.stream().collect(Collectors.groupingBy(TopUpOrder::getCompany)); // 循环分组数据 for (Map.Entry<Company, List<TopUpOrder>> companyTopUpOrderListEntry : companyTopUpOrderList.entrySet()) { // 所属企业id Long companyId = companyTopUpOrderListEntry.getKey().getId(); // 所属企业充值订单 List<TopUpOrder> topUpOrderList = companyTopUpOrderListEntry.getValue(); // 获取第三方企业配置 ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getCompany(companyId); if (thirdPartyPaySet == null || StringUtils.isEmpty(thirdPartyPaySet.getPosRechargeBalanceAcctId())) { loggerService.rechargeTransfer("POS充值收款电子账簿ID为空", null, WalletServiceImpl.class.getName(), "posTransfer", "verifyParam", companyRepository.findById(companyId).orElse(null)); continue; } // 加锁,避免并发请求 String balanceAcctIdLockKey = this.getBalanceAcctIdLockKey(thirdPartyPaySet.getPosRechargeBalanceAcctId()); Boolean balanceAcctIdLock = stringRedisTemplate.opsForValue().setIfAbsent(balanceAcctIdLockKey, balanceAcctIdLockKey); if (!balanceAcctIdLock) { throw new YnceErrorException(YnceError.YNCE_000000); } stringRedisTemplate.expire(balanceAcctIdLockKey, 3, TimeUnit.MINUTES); for (TopUpOrder topUpOrder : topUpOrderList) { Company inputCompany = companyRepository.findById(topUpOrder.getTopUpCompany().getId()).orElse(null); if (inputCompany == null || StringUtils.isEmpty(inputCompany.getWalletId())) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入企业未认证", null, WalletServiceImpl.class.getName(), "posTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } Account inputAccount = accountRepository.findDepositAccount(inputCompany.getId()); if (inputAccount == null) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入账户不存在", null, WalletServiceImpl.class.getName(), "posTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } if (!inputAccount.getState().equals(AccountState.ENABLED)) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入账户非启用状态", null, WalletServiceImpl.class.getName(), "posTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } // 如果充值订单已有转账订单号,但却是未同步状态,则尝试更新 if (StringUtils.isNotBlank(topUpOrder.getTransferSn())) { AccountPaymentsVO accountPaymentsVO = null; try { accountPaymentsVO = walletService.paymentsByOutOrderNo(topUpOrder.getTransferSn()); if (accountPaymentsVO == null) { log.warn("POS充值转账同步 -【消费订单查询(平台订单号):{}】在银联未查询到记录!!!", topUpOrder.getTransferSn()); // 说明在发起转账时银联那边并未接收到,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { if ("succeeded".equals(accountPaymentsVO.getStatus())) { this.rechargeHandle(topUpOrder, accountPaymentsVO); continue; } else if ("failed".equals(accountPaymentsVO.getStatus())) { // 转账失败,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { continue; } } } catch (Exception e) { if (e.getMessage().contains("请求的资源不存在")) { // 说明在发起转账时银联那边并未接收到,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",查询转账记录失败", accountPaymentsVO, WalletServiceImpl.class.getName(), "posTransfer", "queryTransferRecord", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } } } try { // 判断余额是否足够 Long amountPenny = topUpOrder.getAmount().multiply(new BigDecimal("100")).longValue(); BalanceAcctsVO balanceAcctsVO = this.balanceAcctsQryByAcctId(thirdPartyPaySet.getPosRechargeBalanceAcctId()); if (balanceAcctsVO.getSettledAmount() < amountPenny) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转出账簿id" + thirdPartyPaySet.getPosRechargeBalanceAcctId() + "余额不足,余额为" + balanceAcctsVO.getSettledAmount(), null, WalletServiceImpl.class.getName(), "posTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); break; } // 记录转账单号,后续成功再生成充值记录 String zz = sequenceUtil.getNextSequenceNumber("ZZ"); topUpOrder.setTransferSn(zz); topUpOrderRepository.saveAndFlush(topUpOrder); AccountPaymentsDTO accountTransfer = null; try { // 请求银联【电子账簿消费(转账)】 accountTransfer = new AccountPaymentsDTO(); accountTransfer.setAmount(amountPenny) .setPayBalanceAcctId(thirdPartyPaySet.getPosRechargeBalanceAcctId()) .setRecvBalanceAcctId(inputCompany.getWalletId()) // .setPassword(RSAEncryptorUtil.encryptByPublicKey(dto.getEncryptPwd(), thirdPartyPaySet.getChinaumsPublicKey())) .setOutOrderNo(zz) .setRemark(topUpOrder.getRemark()); Map<String, Object> productInfos = new HashMap<String, Object>() {{ put("orderNo", zz); put("orderAmount", amountPenny); put("productName", "POS充值转账"); put("productCount", 1); }}; Map<String, Object> extra = new HashMap<String, Object>() {{ put("productInfos", Collections.singletonList(productInfos)); }}; accountTransfer.setExtra(extra); this.payments(accountTransfer); } catch (Exception e) { log.error("转账出现异常 - ", e); loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转账出现异常:" + e.getMessage(), accountTransfer, WalletServiceImpl.class.getName(), "posTransfer", "transfer", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); } } catch (Exception e) { log.error("POS充值转账 - ", e); loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + "," + e.getMessage(), null, WalletServiceImpl.class.getName(), "posTransfer", "transfer", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); } } } } @Override public void scanTransfer() { List<TopUpOrder> topUpOrders = topUpOrderRepository.findByOrderTypeAndPaymentStatusAndSyncStateInAndPayTimeLessThanAndRefundedIsFalseOrderByPayTime( TopUpOrderType.SCAN, PayStatus.SUCC, Arrays.asList(SyncState.SYNCEDERROR, SyncState.UNSYNCED), LocalDateTime.of(LocalDate.now(), LocalTime.MIN)); if (CollectionUtils.isEmpty(topUpOrders)) { log.warn("扫码充值转账 - 待转账记录为空!"); return; } // 根据所属企业分组 Map<Company, List<TopUpOrder>> companyTopUpOrderList = topUpOrders.stream().collect(Collectors.groupingBy(TopUpOrder::getCompany)); // 循环分组数据 for (Map.Entry<Company, List<TopUpOrder>> companyTopUpOrderListEntry : companyTopUpOrderList.entrySet()) { // 所属企业Id Long companyId = companyTopUpOrderListEntry.getKey().getId(); // 所属企业充值订单 List<TopUpOrder> topUpOrderList = companyTopUpOrderListEntry.getValue(); // 获取第三方企业配置 ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getCompany(companyId); if (thirdPartyPaySet == null || StringUtils.isEmpty(thirdPartyPaySet.getScanRechargeBalanceAcctId())) { loggerService.rechargeTransfer("扫码充值收款电子账簿ID为空", null, WalletServiceImpl.class.getName(), "scanTransfer", "verifyParam", companyRepository.findById(companyId).orElse(null)); continue; } // 加锁,避免并发请求 String balanceAcctIdLockKey = this.getBalanceAcctIdLockKey(thirdPartyPaySet.getScanRechargeBalanceAcctId()); Boolean balanceAcctIdLock = stringRedisTemplate.opsForValue().setIfAbsent(balanceAcctIdLockKey, balanceAcctIdLockKey); if (!balanceAcctIdLock) { throw new YnceErrorException(YnceError.YNCE_000000); } stringRedisTemplate.expire(balanceAcctIdLockKey, 3, TimeUnit.MINUTES); for (TopUpOrder topUpOrder : topUpOrderList) { Company inputCompany = companyRepository.findById(topUpOrder.getTopUpCompany().getId()).orElse(null); if (inputCompany == null || StringUtils.isEmpty(inputCompany.getWalletId())) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入企业未认证", null, WalletServiceImpl.class.getName(), "scanTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } Account inputAccount = accountRepository.findDepositAccount(inputCompany.getId()); if (inputAccount == null) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入账户不存在", null, WalletServiceImpl.class.getName(), "scanTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } if (!inputAccount.getState().equals(AccountState.ENABLED)) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转入账户非启用状态", null, WalletServiceImpl.class.getName(), "scanTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } // 如果充值订单已有转账订单号,但却是未同步状态,则尝试更新 if (StringUtils.isNotBlank(topUpOrder.getTransferSn())) { AccountPaymentsVO accountPaymentsVO = null; try { accountPaymentsVO = walletService.paymentsByOutOrderNo(topUpOrder.getTransferSn()); if (accountPaymentsVO == null) { log.warn("扫码充值转账同步 -【消费订单查询(平台订单号):{}】在银联未查询到记录!!!", topUpOrder.getTransferSn()); // 说明在发起转账时银联那边并未接收到,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { if ("succeeded".equals(accountPaymentsVO.getStatus())) { this.rechargeHandle(topUpOrder, accountPaymentsVO); continue; } else if ("failed".equals(accountPaymentsVO.getStatus())) { // 转账失败,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { continue; } } } catch (Exception e) { if (e.getMessage().contains("请求的资源不存在")) { // 说明在发起转账时银联那边并未接收到,清掉单号重新走转账流程 topUpOrder.setTransferSn(null); } else { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",查询转账记录失败", accountPaymentsVO, WalletServiceImpl.class.getName(), "scanTransfer", "queryTransferRecord", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); continue; } } } try { // 判断余额是否足够 Long amountPenny = topUpOrder.getAmount().multiply(new BigDecimal("100")).longValue(); BalanceAcctsVO balanceAcctsVO = this.balanceAcctsQryByAcctId(thirdPartyPaySet.getScanRechargeBalanceAcctId()); if (balanceAcctsVO.getSettledAmount() < amountPenny) { loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转出账簿id" + thirdPartyPaySet.getScanRechargeBalanceAcctId() + "余额不足,余额为" + balanceAcctsVO.getSettledAmount(), null, WalletServiceImpl.class.getName(), "scanTransfer", "verifyParam", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); break; } // 记录转账单号,后续成功再生成充值记录 String zz = sequenceUtil.getNextSequenceNumber("ZZ"); topUpOrder.setTransferSn(zz); topUpOrderRepository.saveAndFlush(topUpOrder); AccountPaymentsDTO accountTransfer = null; try { // 请求银联【电子账簿消费(转账)】 accountTransfer = new AccountPaymentsDTO(); accountTransfer.setAmount(amountPenny) .setPayBalanceAcctId(thirdPartyPaySet.getScanRechargeBalanceAcctId()) .setRecvBalanceAcctId(inputCompany.getWalletId()) // .setPassword(RSAEncryptorUtil.encryptByPublicKey(dto.getEncryptPwd(), thirdPartyPaySet.getChinaumsPublicKey())) .setOutOrderNo(zz) .setRemark(topUpOrder.getRemark()); Map<String, Object> productInfos = new HashMap<String, Object>() {{ put("orderNo", zz); put("orderAmount", amountPenny); put("productName", "扫码充值转账"); put("productCount", 1); }}; Map<String, Object> extra = new HashMap<String, Object>() {{ put("productInfos", Collections.singletonList(productInfos)); }}; accountTransfer.setExtra(extra); this.payments(accountTransfer); } catch (Exception e) { log.error("转账出现异常 - ", e); loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + ",转账出现异常:" + e.getMessage(), accountTransfer, WalletServiceImpl.class.getName(), "scanTransfer", "transfer", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); } } catch (Exception e) { log.error("扫码充值转账 - ", e); loggerService.rechargeTransfer("订单:" + topUpOrder.getSn() + "," + e.getMessage(), null, WalletServiceImpl.class.getName(), "scanTransfer", "transfer", companyRepository.findById(topUpOrder.getCompany().getId()).orElse(null)); } } } } @Override @Transactional(rollbackFor = Exception.class) public SubaccountRefundVO subaccountRefund(SubaccountRefundDTO subaccountRefundDTO) { Order order = orderRepository.findById(subaccountRefundDTO.getOrderId()).orElse(null); if (order == null) { throw new YnceErrorException(YnceError.YNCE_206012); } if (StringUtils.isBlank(order.getBuyerCompany().getWalletId())) { throw new YnceErrorException(YnceError.YNCE_204095, YnceError.YNCE_218009.getMsg()); } OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(subaccountRefundDTO.getOrderId()); if (orderFeeRatio == null) { throw new YnceErrorException(YnceError.YNCE_204095, "订单费用比例不存在"); } Refund refund = refundRepository.findFirstByRefundSn(subaccountRefundDTO.getRefundNo()); if (refund == null) { throw new YnceErrorException(YnceError.YNCE_204028); } // 分账退款单列表 List<SubaccountRefund> subaccountRefundList = new ArrayList<>(); // 计算品牌退款费用 BigDecimal brandCost = calBrandRefundCost(refund, subaccountRefundDTO, order, orderFeeRatio, subaccountRefundList); // 计算策划退款费用 BigDecimal deviseCost = calPlanningRefundCost(refund, subaccountRefundDTO, order, orderFeeRatio, subaccountRefundList); // 计算货款退款费用 calGoodsRefundCost(refund, subaccountRefundDTO, order, orderFeeRatio, subaccountRefundList, brandCost, deviseCost); return getSubaccountRefundVO(subaccountRefundDTO, subaccountRefundList); } private void calGoodsRefundCost(Refund refund, SubaccountRefundDTO subaccountRefundDTO, Order order, OrderFeeRatio orderFeeRatio, List<SubaccountRefund> subaccountRefundList, BigDecimal brandCost, BigDecimal deviseCost) { BigDecimal goodsPayment = subaccountRefundDTO.getAmount().subtract(brandCost).subtract(deviseCost); ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); if (goodsPayment.compareTo(BigDecimal.ZERO) > 0) { // 判断是否已生成分账退款单 SubaccountRefund subaccountRefund = subaccountRefundRepository.findFirstByRefundSnAndSubaccountType(subaccountRefundDTO.getRefundNo(), SubaccountType.GOODS_COST); // 转账结果 AccountPaymentsVO accountPaymentsVO = new AccountPaymentsVO(); if (subaccountRefund == null) { String sn = sequenceUtil.getNextSequenceNumber("FZTK"); // 拼接转账申请 ByxChinaumsRefundDTO byxChinaumsRefundDTO = ByxChinaumsRefundDTO.builder() .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .refundAmt(goodsPayment.multiply(BigDecimal.valueOf(100)).longValue()) .guaranteedOrderNo(refund.getThirdPartyAccount()) .build(); // 转账结果 ByxChinaumsRefundVO byxChinaumsRefundVO = null; try { byxChinaumsRefundVO = this.refundForProfitSharing(byxChinaumsRefundDTO); } catch (Exception exception) { log.error(subaccountRefundDTO.getRefundNo() + "请求分账退款失败:" + exception.getMessage()); } if (byxChinaumsRefundVO == null) { throw new YnceErrorException("系统异常,退款失败"); } // 保存分账退款单 subaccountRefund = new SubaccountRefund(); subaccountRefund.setSn(sn); subaccountRefund.setAmount(goodsPayment); subaccountRefund.setRefundCompany(order.getSellerCompany()); subaccountRefund.setReceiptCompany(order.getBuyerCompany()); subaccountRefund.setExternalId(byxChinaumsRefundVO.getTransOrderNo()); subaccountRefund.setSubaccountType(SubaccountType.GOODS_COST); subaccountRefund.setSubaccountCostRatio(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio())); subaccountRefund.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccountRefund.setRefundSn(subaccountRefundDTO.getRefundNo()); } subaccountRefundRepository.saveAndFlush(subaccountRefund); subaccountRefundList.add(subaccountRefund); } } private BigDecimal calPlanningRefundCost(Refund refund, SubaccountRefundDTO subaccountRefundDTO, Order order, OrderFeeRatio orderFeeRatio, List<SubaccountRefund> subaccountRefundList) { BigDecimal deviseCost = BigDecimal.ZERO; ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); if (orderFeeRatio.getDeviseCostRatio().compareTo(BigDecimal.ZERO) != 0) { // 判断是否已生成分账退款单 SubaccountRefund subaccountRefund = subaccountRefundRepository.findFirstByRefundSnAndSubaccountType(subaccountRefundDTO.getRefundNo(), SubaccountType.DEVISE_FEE); deviseCost = subaccountRefundDTO.getAmount().multiply(orderFeeRatio.getDeviseCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); if (subaccountRefund == null) { String sn = sequenceUtil.getNextSequenceNumber("FZTK"); // 拼接转账申请 ByxChinaumsRefundDTO byxChinaumsRefundDTO = ByxChinaumsRefundDTO.builder() .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .refundAmt(deviseCost.multiply(BigDecimal.valueOf(100)).longValue()) .guaranteedOrderNo(refund.getThirdPartyAccount()) .build(); // 转账结果 ByxChinaumsRefundVO byxChinaumsRefundVO = null; try { byxChinaumsRefundVO = this.refundForProfitSharing(byxChinaumsRefundDTO); } catch (Exception exception) { log.error(subaccountRefundDTO.getRefundNo() + "请求分账退款失败:" + exception.getMessage()); } if (byxChinaumsRefundVO == null) { throw new YnceErrorException("系统异常,退款失败"); } // 保存分账退款单 subaccountRefund = new SubaccountRefund(); subaccountRefund.setSn(sn); subaccountRefund.setAmount(deviseCost); subaccountRefund.setRefundCompany(order.getDeviseCompany()); subaccountRefund.setReceiptCompany(order.getBuyerCompany()); // subaccountRefund.setOrders(order); subaccountRefund.setExternalId(byxChinaumsRefundVO.getTransOrderNo()); subaccountRefund.setSubaccountType(SubaccountType.DEVISE_FEE); subaccountRefund.setSubaccountCostRatio(orderFeeRatio.getDeviseCostRatio()); subaccountRefund.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccountRefund.setRefundSn(subaccountRefundDTO.getRefundNo()); } subaccountRefundRepository.saveAndFlush(subaccountRefund); subaccountRefundList.add(subaccountRefund); } return deviseCost; } private BigDecimal calBrandRefundCost(Refund refund, SubaccountRefundDTO subaccountRefundDTO, Order order, OrderFeeRatio orderFeeRatio, List<SubaccountRefund> subaccountRefundList) { BigDecimal brandCost = BigDecimal.ZERO; ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform(); if (orderFeeRatio.getBrandCostRatio().compareTo(BigDecimal.ZERO) == 1) { // 判断是否已生成分账退款单 SubaccountRefund subaccountRefund = subaccountRefundRepository.findFirstByRefundSnAndSubaccountType(subaccountRefundDTO.getRefundNo(), SubaccountType.BRAND_FEE); brandCost = subaccountRefundDTO.getAmount().multiply(orderFeeRatio.getBrandCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP); if (subaccountRefund == null) { String sn = sequenceUtil.getNextSequenceNumber("FZTK"); // 拼接转账申请 ByxChinaumsRefundDTO byxChinaumsRefundDTO = ByxChinaumsRefundDTO.builder() .platformWalletId(thirdPartyPaySet.getChinaumsFeeBalanceAcctId()) .refundAmt(brandCost.multiply(BigDecimal.valueOf(100)).longValue()) .guaranteedOrderNo(refund.getThirdPartyAccount()) .build(); // 转账结果 ByxChinaumsRefundVO byxChinaumsRefundVO = null; try { byxChinaumsRefundVO = this.refundForProfitSharing(byxChinaumsRefundDTO); } catch (Exception exception) { log.error(subaccountRefundDTO.getRefundNo() + "请求分账退款失败:" + exception.getMessage()); } if (byxChinaumsRefundVO == null) { throw new YnceErrorException("系统异常,退款失败"); } // 保存分账退款单 subaccountRefund = new SubaccountRefund(); subaccountRefund.setSn(sn); subaccountRefund.setAmount(brandCost); subaccountRefund.setRefundCompany(order.getBrandCompany()); subaccountRefund.setReceiptCompany(order.getBuyerCompany()); subaccountRefund.setExternalId(byxChinaumsRefundVO.getTransOrderNo()); subaccountRefund.setSubaccountType(SubaccountType.BRAND_FEE); subaccountRefund.setSubaccountCostRatio(orderFeeRatio.getBrandCostRatio()); subaccountRefund.setSubaccountState(SubaccountState.SEPARATE_NOT); subaccountRefund.setRefundSn(subaccountRefundDTO.getRefundNo()); } subaccountRefundRepository.saveAndFlush(subaccountRefund); subaccountRefundList.add(subaccountRefund); } return brandCost; } private static SubaccountRefundVO getSubaccountRefundVO(SubaccountRefundDTO subaccountRefundDTO, List<SubaccountRefund> subaccountRefundList) { SubaccountRefundVO subaccountRefundVO = new SubaccountRefundVO(); if (CollectionUtils.isNotEmpty(subaccountRefundList)) { BigDecimal refundAmount = BigDecimal.ZERO; List<String> externalIdList = new ArrayList<>(); for (SubaccountRefund subaccountRefund : subaccountRefundList) { if (subaccountRefund.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)) { refundAmount = refundAmount.add(subaccountRefund.getAmount()); externalIdList.add(subaccountRefund.getExternalId()); } } if (refundAmount.compareTo(BigDecimal.ZERO) == 0) { subaccountRefundVO.setRefundStatus(RefundStatus.UN_REFUND); subaccountRefundVO.setRefundAmount(BigDecimal.ZERO); } else { if (refundAmount.compareTo(subaccountRefundDTO.getAmount()) == 0) { subaccountRefundVO.setRefundStatus(RefundStatus.REFUNDED); } else { subaccountRefundVO.setRefundStatus(RefundStatus.PARTIAL_REFUNDED); } subaccountRefundVO.setExternalId(StringUtils.join(externalIdList, ",")); subaccountRefundVO.setRefundTime(LocalDateTime.now()); subaccountRefundVO.setRefundAmount(refundAmount); } } else { subaccountRefundVO.setRefundStatus(RefundStatus.UN_REFUND); subaccountRefundVO.setRefundAmount(BigDecimal.ZERO); } return subaccountRefundVO; } @Override public ElectronicReceiptVO electronicReceipts(String tradeId) { Map<String, Object> map = new HashMap<>(); List<String> list = new ArrayList<>(); list.add(tradeId); map.put("list", list); JSONObject result = chinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_ELECTRONIC_RECEIPTS, (JSONObject) JSONObject.toJSON(map), JSONObject.class); if (result == null || result.get("downloadUrl") == null) { throw new YnceErrorException("查询电子回单失败"); } ElectronicReceiptVO vo = new ElectronicReceiptVO(); vo.setTradeId(tradeId); vo.setFileUrl(result.get("downloadUrl").toString()); vo.setOutOrderNo(result.get("mctOrderNo") == null ? null : result.get("mctOrderNo").toString()); return vo; } @Override @Transactional(rollbackFor = Exception.class) public void createWalletByCompany(WalletCreateByCompanyDTO walletCreateByCompanyDTO) { Company company = companyRepository.findById(walletCreateByCompanyDTO.getCompanyId()).orElse(null); if (company == null) { throw new YnceErrorException(YnceError.YNCE_218031, "企业不存在"); } if (StringUtils.isBlank(company.getWalletId())) { throw new YnceErrorException(YnceError.YNCE_218031, "企业暂未认证"); } if (!ApplicationStatus.REGISTER_SUCCESS.equals(company.getChinaumsAuthInfo().getApplicationStatus())) { throw new YnceErrorException(YnceError.YNCE_218031, "企业认证修改中"); } Company walletCompany = companyRepository.findById(walletCreateByCompanyDTO.getWalletCompanyId()).orElse(null); if (walletCompany == null) { throw new YnceErrorException(YnceError.YNCE_218031, "新电子账簿所属企业不存在"); } if (StringUtils.isNotBlank(walletCompany.getWalletId())) { throw new YnceErrorException(YnceError.YNCE_218031, "新电子账簿所属企业已认证"); } if (walletCompany.getChinaumsAuthInfo() != null && !ApplicationStatus.REGISTER_SUCCESS.equals(walletCompany.getChinaumsAuthInfo().getApplicationStatus())) { throw new YnceErrorException(YnceError.YNCE_218031, "新电子账簿所属企业认证修改中"); } // 拼接请求参数 ChinaumsCreateWalletDTO chinaumsCreateWalletDTO = ChinaumsCreateWalletDTO.builder() .cusId(company.getChinaumsAuthInfo().getCusId()) .mchId(company.getChinaumsAuthInfo().getMchId()) .password(chinaumsUtil.getDefaultPassword()) .build(); // 调用创建服务 ChinaumsCreateWalletVO chinaumsCreateWalletVO; try { chinaumsCreateWalletVO = this.createWallet(chinaumsCreateWalletDTO); } catch (Exception exception) { throw new YnceErrorException(YnceError.YNCE_218031, exception.getMessage()); } // 保存企业的电子账簿ID walletCompany.setWalletId(chinaumsCreateWalletVO.getBalanceAcctId()); companyRepository.saveAndFlush(walletCompany); // 生成新的银联认证信息 ChinaumsAuthInfo chinaumsAuthInfo = new ChinaumsAuthInfo(); BeanUtils.copyProperties(company.getChinaumsAuthInfo(), chinaumsAuthInfo, "id", "chinaumsBankCard"); chinaumsAuthInfo.setOutRequestNo(chinaumsCreateWalletVO.getOutRequestNo()); chinaumsAuthInfo.setPassword(chinaumsUtil.getDefaultPassword()); chinaumsAuthInfo.setCompany(walletCompany); chinaumsAuthInfo.setRelAcctNo(chinaumsCreateWalletVO.getRelAcctNo()); chinaumsAuthInfo.setBankCardNo(chinaumsCreateWalletVO.getBankCardNo()); chinaumsAuthInfo.setBalanceAcctId(chinaumsCreateWalletVO.getBalanceAcctId()); chinaumsAuthInfoRepository.save(chinaumsAuthInfo); } @Transactional(rollbackFor = Exception.class) @Override public void createWalletCreditRefund() { Company company = getUser().getCompany(); ChinaumsAuthInfo dbChinaumsAuthInfo = company.getChinaumsAuthInfo(); if (StringUtils.isBlank(company.getWalletId()) || dbChinaumsAuthInfo == null) { throw new YnceErrorException(YnceError.YNCE_218031, "企业暂未认证"); } ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getCompany(company.getId()); if (thirdPartyPaySet == null) { throw new YnceErrorException("第三方企业配置不存在"); } if (StringUtils.isNotBlank(thirdPartyPaySet.getChinaumsCreditBalanceAcctId())) { throw new YnceErrorException("授信资金池账户已存在"); } // 拼接请求参数 ChinaumsCreateWalletDTO chinaumsCreateWalletDTO = ChinaumsCreateWalletDTO.builder() .cusId(dbChinaumsAuthInfo.getCusId()) .mchId(dbChinaumsAuthInfo.getMchId()) .password(chinaumsUtil.getDefaultPassword()) .build(); // 调用创建服务 ChinaumsCreateWalletVO chinaumsCreateWalletVO; try { chinaumsCreateWalletVO = this.createWallet(chinaumsCreateWalletDTO); } catch (Exception exception) { throw new YnceErrorException(YnceError.YNCE_218031, exception.getMessage()); } // 保存电子账簿ID thirdPartyPaySet.setChinaumsCreditBalanceAcctId(chinaumsCreateWalletVO.getBalanceAcctId()); thirdPartyPaySetRepository.saveAndFlush(thirdPartyPaySet); } private ChinaumsCreateWalletVO createWallet(ChinaumsCreateWalletDTO chinaumsCreateWalletDTO) { chinaumsCreateWalletDTO.setOutRequestNo(sequenceUtil.getNextSequenceNumber("YLRZ")); try { // 密码加密 chinaumsCreateWalletDTO.setPassword(RSAEncryptorUtil.encryptByPublicKey(chinaumsCreateWalletDTO.getPassword(), chinaumsUtil.getPublicKey())); } catch (Exception exception) { throw new YnceErrorException(YnceError.YNCE_218014); } return chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_UPAPI_BALANCE_ACCTS, (JSONObject) JSONObject.toJSON(chinaumsCreateWalletDTO), ChinaumsCreateWalletVO.class); } /** * 获取银联电子账簿id锁 * * @param balanceAcctId * @return */ private String getBalanceAcctIdLockKey(String balanceAcctId) { return balanceAcctId + ":BALANCE_ACCT_ID"; } /** * 转账入金回调处理 */ private void paymentCallBack(ExternalIncomeDTO externalIncomeDTO){ // log.info("转账入金 交易类型为:{}", externalIncomeDTO.getTradeType()); // 加锁,避免并发请求 String lockKey = "paymentCallBack-"+externalIncomeDTO.getTradeId(); Boolean lockTradeId = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "locked", 5, TimeUnit.MINUTES); // 拿不到锁直接返回 if (!lockTradeId) { throw new YnceErrorException("转账入金(充值)处理中,稍后重试"); } // stringRedisTemplate.expire(lockKeyTradeId, 1, TimeUnit.MINUTES); try { ChinaumsAuthInfo outputAuthInfo = chinaumsAuthInfoRepository.findFirstByBalanceAcctId(externalIncomeDTO.getPayBalanceAcctId()); ChinaumsAuthInfo inputAuthInfo = chinaumsAuthInfoRepository.findFirstByBalanceAcctId(externalIncomeDTO.getBalanceAcctId()); if (outputAuthInfo == null) { throw new YnceErrorException("未查询到银联认证信息"); } AccountChangeList accountChangeList = accountChangeListRepository.findFirstBySourceNo(externalIncomeDTO.getTradeId()); if (accountChangeList != null) { log.warn("该入金已生成异动记录!!!"); return; } Company company = outputAuthInfo.getCompany(); // Account account = accountRepository.findDepositAccount(company.getId()); // TopUpList topUpList = topUpListRepository.findTopByAccountAndStateOrderByCreatedOnDesc(account, TopUpState.PAID); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss+08:00") .withZone(ZoneId.of("Asia/Shanghai")); // 可查90个自然日的交易,单次查询开始和结束时间间隔不大于7天 LocalDateTime dateTime = LocalDateTime.now().minusDays(1L); BalanceTransactionsPageVO balanceTransactionsPageVO = this.balanceTransactions(company.getWalletId(),externalIncomeDTO.getTradeId(), dateTimeFormatter.format(dateTime), dateTimeFormatter.format(LocalDateTime.now())); if (balanceTransactionsPageVO ==null || balanceTransactionsPageVO.getTotal() <= 0) { log.warn("未查询到流水记录!!!"); return; } // 标记查询的流水中是否有当前入金的回调 boolean flag = false; List<BalanceTransactionsPageVO.BalanceTransactionsVO> data = balanceTransactionsPageVO.getData(); for (BalanceTransactionsPageVO.BalanceTransactionsVO d : data) { // log.info("BalanceTransactionsVO:{}",d); if (externalIncomeDTO.getTradeId().equals(d.getTradeId())) { flag = true; RechargeDTO rechargeDTO = new RechargeDTO(); rechargeDTO.setCompanyId(company.getId()); BigDecimal rechargeAmount; if (d.getSettledAmount() > 0) { rechargeAmount = new BigDecimal(d.getSettledAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } else { rechargeAmount = new BigDecimal(d.getPendingAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); } rechargeDTO.setRechargeAmount(rechargeAmount); if (StringUtils.isNotEmpty(d.getRemark())) { rechargeDTO.setRemarks(d.getRemark()); } else { rechargeDTO.setRemarks("转账-"+inputAuthInfo.getCompany().getName()); } rechargeDTO.setPaymentMethod("银联支付"); // rechargeDTO.setFinishedDate(LocalDateTime.parse(d.getSucceededAt(), DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSzzz"))); rechargeDTO.setFinishedDate(DateTimeUtils.getLocalDateTimeByRFC3339Str(d.getSucceededAt())); rechargeDTO.setSourceNo(d.getTradeId()); rechargeDTO.setChangeDirection(ChangeDirection.REDUCE); rechargeDTO.setAccountChangeType(AccountChangeType.TRANSFER); // 转出账号生成转账记录 unionpayAccountService.rechargeMoney(rechargeDTO); // 转入账号生成充值记录 RechargeDTO transferIntoDTO = new RechargeDTO(); transferIntoDTO.setCompanyId(inputAuthInfo.getCompany().getId()); transferIntoDTO.setRechargeAmount(rechargeAmount); transferIntoDTO.setRemarks("转账-来自" + outputAuthInfo.getCompany().getName()); transferIntoDTO.setPaymentMethod("银联支付"); transferIntoDTO.setFinishedDate(rechargeDTO.getFinishedDate()); transferIntoDTO.setSourceNo(d.getTradeId()); transferIntoDTO.setChangeDirection(ChangeDirection.ADD); transferIntoDTO.setAccountChangeType(AccountChangeType.TRANSFER); unionpayAccountService.rechargeMoney(transferIntoDTO); break; } } } finally { // 执行成功和失败都需要删除锁 stringRedisTemplate.delete(lockKey); } } }
Show line notes below