发布时间:2023-01-21 08:40:56 文章来源:互联网
微博 微信 QQ空间

对接农行支付(微信和支付宝)总结(四)

对接农行支付(微信和支付宝)总结(四)

错误在哪里? 其实文档里也写了。 谁叫我们不仔细看的。 . .

可用于下载微信支付宝支付指定日期的对账单。

T日对账单是在T+1日17:00后生成的,所以请不要早于次日17:00前下载对账单。

经我验证过,时间不用等到17点,上午就可以获取到了,具体几点开始有了账单的,就不想去细究了。

好了,关于对账接口,最后贴出它的格式和解析例子。

商户号|交易类型|订单编号|交易时间|交易金额|商户账号|商户动账金额|客户账号|账户类型|商户回佣手续费|商户分期手续费|会计日期|主机流水号|9014流水号|原订单号^^
103881909993435|weixinpay|B13220406092802072109|20220406092803|0.01|19015601949001842|0.01|otDNot8jM13dT_rhF9_OOVpRiO1M|OTHERS|0|0.00|20220407|242190361|46ECEP01092733452084|B13220406092802072109^^
103881909993435|weixinpay|132204061003230B71896|20220406100323|0.01|19015601949001842|0.01|otDNot8jM13dT_rhF9_OOVpRiO1M|OTHERS|0|0.00|20220407|242190361|46ECEP01100210191273|132204061003230B71896^^
103881909993435|weixinpay|132204061017200722B71|20220406101720|0.01|19015601949001842|0.01|otDNot8jM13dT_rhF9_OOVpRiO1M|OTHERS|0|0.00|20220407|242190361|46ECEP01101514287394|132204061017200722B71^^
103881909993435|WeiXinRefund|R112204061758490B72381|20220406175849|0.01|19015601040025213|0.01|||0|0.00|20220407|242190361|46ECEP01175501714434|1122040B6175627072375^^
103881909993435|weixinpay|B13220406094924072229|20220406094924|0.01|19015601949001842|0.01|otDNot8jM13dT_rhF9_OOVpRiO1M|OTHERS|0|0.00|20220407|242190361|46ECEP01094430716845|B13220406094924072229^^
103881909993435|weixinpay|1122040B6175627072375|20220406175627|0.01|19015601949001842|0.01|otDNotxTIe0B7VT1vGxbIbXqIQu0|OTHERS|0|0.00|20220407|242190361|46ECEP01175058463786|1122040B6175627072375

最后贴出解析ABC账单的伪代码。 有时间我会写一系列关于和解的文章。

import cn.hutool.core.date.DateUtil;
import com.xxx.service.pay.constant.PayConstants;
import com.xxx.service.pay.domain.model.BillInfo;
import com.xxx.service.pay.domain.service.dto.BankTradeDTO;
import com.xxx.service.pay.utils.AmountUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@Component("billParser" + PayConstants.PayChannelType.AbcBank)
public class BillParserAbcBank implements IBillParser {
    private static final String BILL_OF_PAY_TYPE = "pay";
    private static final String BILL_OF_REFUND_TYPE = "refund";
    private static final Pattern PATTERN = Pattern.compile("(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\|(.*?)$$");
    @Override
    public  void parser(T object, BillInfo billInfo, List payTradeDTOList, List refundTradeDTOList) throws Exception {
        String billContent = (String) object;
        String[] array = billContent.split("\\^\\^");
        if (array.length > 1) {
            this.parseDetailLine(array, payTradeDTOList, refundTradeDTOList, billInfo);
        }
    }
    /**
     * 解析明细数据.
     * 

* 先删除明细数据的标题, 再循环遍历数据值 *

* * @param array * @param payTradeDTOList * @param refundTradeDTOList */ private void parseDetailLine(String[] array, List payTradeDTOList, List refundTradeDTOList, BillInfo billInfo) { int totalPayAmount = 0; int totalPayCount = 0; int totalRefundAmount = 0; int totalRefundCount = 0; int totalPayFee = 0; int totalRefundFee = 0; // 跳过第一行,下标从1开始 for (int i = 1; i < array.length; i++) { // 正则匹配校验 Matcher totalMatcher = PATTERN.matcher(array[i]); if (!totalMatcher.find()) { return; } String[] detailArray = array[i].split("\\|"); // 交易类型 String tradeType = detailArray[1].toLowerCase(); // 对银行而言, 商户订单号 String outTradeNo = detailArray[2]; // 交易时间 String tradeTime = detailArray[3]; // 交易金额 int amount = AmountUtils.changeY2F(detailArray[4]); // 手续费 int fee = AmountUtils.changeY2F(detailArray[10]); // 平台流水号 String tradeNo = detailArray[13]; //支付订单 if (tradeType.endsWith(BILL_OF_PAY_TYPE)) { BankTradeDTO payTradeDTO = BankTradeDTO.builder() .tradeTime(DateUtil.parse(tradeTime)) .outTradeNo(outTradeNo) .tradeNo(tradeNo) .amount(amount) .fee(fee) .build(); totalPayAmount += amount; totalPayFee += fee; totalPayCount++; payTradeDTOList.add(payTradeDTO); } if (tradeType.endsWith(BILL_OF_REFUND_TYPE)) { BankTradeDTO refundTradeDTO = BankTradeDTO.builder() .tradeTime(DateUtil.parse(tradeTime)) .outTradeNo(outTradeNo) .tradeNo(tradeNo) .amount(Math.abs(amount)) .fee(fee) .build(); totalRefundAmount += amount; totalRefundFee += fee; totalRefundCount++; refundTradeDTOList.add(refundTradeDTO); } } billInfo.setBankPayTrade(totalPayAmount, totalPayCount, totalPayFee); billInfo.setBankRefundTrade(totalRefundAmount, totalRefundCount, totalRefundFee); } }

import com.xxx.service.pay.domain.model.BillInfo;
import com.xxx.service.pay.domain.service.dto.BankTradeDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.stereotype.Service;
import java.util.List;
/**
 * 账单解析工厂类
 */
@Slf4j
@Service
public class BillParserFactory implements BeanFactoryAware {
    private BeanFactory beanFactory;
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
    public Object getService(String payInterface) {
        return beanFactory.getBean(payInterface);
    }
    public  void parser(T object, BillInfo billInfo, List payTradeDTOList, List refundTradeDTOList) throws Exception {
        String parserClassName = "billParser" + billInfo.getChannelType();
        IBillParser service;
        try {
            // 根据名字获取相应的解析器
            service = (IBillParser) this.getService(parserClassName);
        } catch (NoSuchBeanDefinitionException e) {
            log.error("根据解析器的名字, 没有找到相应的解析器, [parserClassName={}, mchId={}, channelType={}, billDate={}]",
                    parserClassName, billInfo.getMchId(), billInfo.getChannelType(), billInfo.getBillYmd());
            return;
        }
        // 使用相应的解析器解析文件
        service.parser(object, billInfo, payTradeDTOList, refundTradeDTOList);
    }
}

import com.xxx.service.pay.domain.model.BillInfo;
import com.xxx.service.pay.domain.service.dto.BankTradeDTO;
import java.util.List;
/**
 * 解析对账单为统一格式
 *
 */
public interface IBillParser {
    /**
     * 解析对账单
     *
     * @param object
     * @param billInfo
     * @param payTradeDTOList
     * @param refundTradeDTOList
     * @param 
     * @throws Exception
     */
     void parser(T object, BillInfo billInfo, List payTradeDTOList, List refundTradeDTOList) throws Exception;
}

4.退款界面

农行也接入了微信的API接口,所以我们要想了解农行的退款机制,首先要了解微信官方的API。 这里不得不吐槽一下,它的对账机制没有杭州银行那么灵活。 从我们的角度来看,我们正在与银行连接,但他们给您的答复是“您正在连接微信”。 真的只是桥接! !

1.微信退款接口

我们用的是老版本的界面农业银行如何查询网上支付订单号,微信支付后面会升级,但是我们不是很愿意升级。

默认是使用未结算资金,
白话讲,就是当天收到了多少钱,这笔钱就是未结算的钱,这些钱才能用来抵扣退款给用户的钱。

2.农行退款界面

没有退款资金来源字段! ! 也就是说,我们不能指定退款资金的来源,而让农行的退款机制。 使用微信默认方式,不允许对接方选择。 你生气不生气~~

    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    @Data
    public static class DicRequest {
        /**
         * 退款-Refund
         */
        private String trxType;
        /**
         * 订单日期: YYYY/MM/DD
         */
        private String orderDate;
        /**
         * 订单时间: HH:MM:SS
         */
        private String orderTime;
        /**
         * 平台支付流水号
         */
        private String orderNo;
        /**
         * 退款交易编号
         */
        private String newOrderNo;
        /**
         * 币种:156-人民币
         */
        private Integer currencyCode;
        /**
         * 退款金额,单位:元
         */
        private String trxAmount;
    }

5.说服

本文就农行退款的一个大坑具体分析一下,希望对想对接农行的朋友有所帮助。 给需要退款的朋友们的忠告农业银行如何查询网上支付订单号,这篇文章可以算是一篇劝说文章! !

另一视角

换一换