All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.zopen.wechat.pay.service.WechatPayService Maven / Gradle / Ivy

There is a newer version: 1.0.5
Show newest version
package com.zopen.wechat.pay.service;

import com.zcj.util.UtilRandom;
import com.zcj.util.UtilString;
import com.zcj.util.UtilXml;
import com.zopen.ato.properties.WechatPayProperties;
import com.zopen.wechat.exception.WechatAssert;
import com.zopen.wechat.pay.dto.*;
import com.zopen.wechat.pay.dto.companypay.CompanyPayRequest;
import com.zopen.wechat.pay.dto.companypay.CompanyPayResponse;
import com.zopen.wechat.pay.util.SignUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component("atoWechatPayService")
public class WechatPayService {

    private static final Logger logger = LoggerFactory.getLogger(WechatPayService.class);

    private static final String PAY_APP_UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    private static final String PAY_ORDER_QUERY = "https://api.mch.weixin.qq.com/pay/orderquery";
    private static final String PAY_COMPANY_TO_USER = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private WechatPayProperties wechatPayProperties;

    /**
     * 企业付款到零钱(读取 spring boot 的 application 中的配置)
     *
     * @param appId      *企业号appId
     * @param outTradeNo *商户订单号
     * @param openId     *收款用户openid
     * @param amount     *金额,单位:分
     * @param desc       *企业付款备注
     * @param ip         *用户端或者服务端的IP
     * @return com.zopen.wechat.pay.dto.CompanyPayResponse
     */
    public CompanyPayResponse companyToUserByBoot(String appId, String outTradeNo, String openId, Integer amount, String desc, String ip) {
        String appKey = wechatPayProperties.getAppKey();
        String mchId = wechatPayProperties.getMchId();
        return companyToUser(appId, appKey, mchId, outTradeNo, openId, amount, desc, ip);
    }

    /**
     * 企业付款到零钱
     *
     * @param appId      *商户账号appid(例:wxec38b8ff840bd989)
     * @param appKey     *商户平台的秘钥Key(例:192006250b4c09247ec02edce69f6a2d)
     * @param mchId      *商户号(例:10013274)
     * @param outTradeNo *商户订单号
     * @param openId     *收款用户openid
     * @param amount     *金额,单位:分
     * @param desc       *企业付款备注
     * @param ip         *用户端或者服务端的IP
     * @return com.zopen.wechat.pay.dto.CompanyPayResponse
     */
    public CompanyPayResponse companyToUser(String appId, String appKey, String mchId, String outTradeNo, String openId, Integer amount, String desc, String ip) {

        // 验证参数
        WechatAssert.notNullAndEmpty(appId, "appId 不能为空");
        WechatAssert.notNullAndEmpty(appKey, "appKey 不能为空");
        WechatAssert.notNullAndEmpty(mchId, "mchId 不能为空");
        WechatAssert.notNullAndEmpty(outTradeNo, "outTradeNo 不能为空");
        WechatAssert.notNullAndEmpty(openId, "openId 不能为空");
        WechatAssert.notNull(amount, "amount 不能为空");
        WechatAssert.notNullAndEmpty(desc, "desc 不能为空");
        WechatAssert.notNullAndEmpty(ip, "ip 不能为空");
        WechatAssert.checkArgument(amount != null && amount > 0, "amount 取值错误");

        // 构建请求参数
        CompanyPayRequest request = new CompanyPayRequest();
        request.setNonce_str(UtilRandom.getRandomChar(16));
        request.setMch_appid(appId);
        request.setMchid(mchId);
        request.setPartner_trade_no(outTradeNo);
        request.setOpenid(openId);
        request.setCheck_name("NO_CHECK");
        request.setAmount(amount);
        request.setDesc(desc);
        request.setSpbill_create_ip(ip);

        // 签名
        String sign = SignUtil.getSign(request, appKey);
        WechatAssert.notNullAndEmpty(sign, "签名失败");
        request.setSign(sign);

        // 发送请求
        String responseXml = post(PAY_COMPANY_TO_USER, request, "企业付款到零钱");
        CompanyPayResponse response = UtilXml.convertXmlStrToObject(CompanyPayResponse.class, responseXml);

        // 验证返回的结果
        if (!response.success()) {
            WechatAssert.notNull(null, response.errorInfo());
        }

        return response;
    }

    /**
     * 查询订单
     *
     * @param outTradeNo * 商户订单号
     * @param appId      * 公众号或小程序的appId
     * @return com.zopen.wechat.pay.dto.QueryResponse
     */
    public QueryResponse orderQuery(String outTradeNo, String appId) {

        // 验证参数
        WechatAssert.notNullAndEmpty(appId, "appId 未设置");
        WechatAssert.notNullAndEmpty(wechatPayProperties.getAppKey(), "appKey 未设置");
        WechatAssert.notNullAndEmpty(wechatPayProperties.getMchId(), "mchId 未设置");
        WechatAssert.notNullAndEmpty(outTradeNo, "outTradeNo 不能为空");

        // 构建请求参数
        QueryRequest request = new QueryRequest();
        request.setAppid(appId);
        request.setMch_id(wechatPayProperties.getMchId());
        request.setOut_trade_no(outTradeNo);
        request.setNonce_str(UtilRandom.getRandomChar(16));

        // 签名
        String sign = SignUtil.getSign(request, wechatPayProperties.getAppKey());
        WechatAssert.notNullAndEmpty(sign, "签名失败");
        request.setSign(sign);

        // 发送请求
        String responseXml = post(PAY_ORDER_QUERY, request, "查询订单");
        QueryResponse response = UtilXml.convertXmlStrToObject(QueryResponse.class, responseXml);

        // 验证返回的结果
        if (!response.success()) {
            WechatAssert.notNull(null, response.errorInfo());
        }

        // 验证签名
        String responseSign = response.getSign();
        String responseSign2 = SignUtil.getSign(response, wechatPayProperties.getAppKey());
        if (!responseSign.equals(responseSign2)) {
            WechatAssert.notNull(null, "签名错误");
        }

        return response;
    }

    /**
     * 统一下单(APP 下单),装箱后返回给客户端
     *
     * @param appId      * 小程序或公众号的appId
     * @param body       * 商品描述
     * @param clientIp   * 终端IP
     * @param totalFee   * 总金额,单位:分
     * @param outTradeNo * 商户订单号
     * @return 需要传给 APP 的内容
     */
    public AppPayClientDto unifiedOrderByApp(String appId, String body, String clientIp, Integer totalFee, String outTradeNo) {
        PayResponse response = unifiedOrderBase(appId, body, clientIp, totalFee, outTradeNo, 1, null);
        return AppPayClientDto.formAppPayResponse(response, wechatPayProperties.getAppKey());
    }

    /**
     * 统一下单(Native 下单)
     *
     * @param appId      * 小程序或公众号的appId
     * @param body       * 商品描述
     * @param clientIp   * 终端IP
     * @param totalFee   * 总金额,单位:分
     * @param outTradeNo * 商户订单号
     * @return 微信返回的内容
     */
    public PayResponse unifiedOrderByNative(String appId, String body, String clientIp, Integer totalFee, String outTradeNo) {
        return unifiedOrderBase(appId, body, clientIp, totalFee, outTradeNo, 2, null);
    }

    /**
     * 统一下单(小程序下单、微信浏览器H5下单)
     *
     * @param appId      * 小程序或公众号的appId
     * @param body       * 商品描述
     * @param clientIp   * 终端IP
     * @param totalFee   * 总金额,单位:分
     * @param outTradeNo * 商户订单号
     * @param openId     * 微信用户open_id
     * @return 需要传给小程序的内容
     */
    public JsApiPayClientDto unifiedOrderByJsApi(String appId, String body, String clientIp, Integer totalFee, String outTradeNo, String openId) {
        PayResponse response = unifiedOrderBase(appId, body, clientIp, totalFee, outTradeNo, 3, openId);
        return JsApiPayClientDto.formPayResponse(response, wechatPayProperties.getAppKey());
    }

    // payType(1:APP 下单;2:Native 下单;3:小程序下单/微信浏览器H5下单)
    private PayResponse unifiedOrderBase(String appId, String body, String clientIp, Integer totalFee, String outTradeNo, Integer payType, String openIdByJsApi) {

        // 验证参数
        WechatAssert.notNullAndEmpty(appId, "appId 未设置");
        WechatAssert.notNullAndEmpty(wechatPayProperties.getAppKey(), "appKey 未设置");
        WechatAssert.notNullAndEmpty(wechatPayProperties.getMchId(), "mchId 未设置");
        WechatAssert.notNullAndEmpty(wechatPayProperties.getDomainUrl(), "domainUrl 未设置");
        WechatAssert.notNullAndEmpty(body, "body 不能为空");
        WechatAssert.notNullAndEmpty(clientIp, "clientId 不能为空");
        WechatAssert.checkArgument(totalFee != null && totalFee > 0, "totalFee 取值错误");
        WechatAssert.notNullAndEmpty(outTradeNo, "outTradeNo 不能为空");

        // 构建请求参数 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
        PayRequest request = new PayRequest();
        if (payType == 1) {
            request.initAppPay();
        } else if (payType == 2) {
            request.initNativePay(outTradeNo);
        } else if (payType == 3) {
            request.initJsAPI(openIdByJsApi);
        }
        request.setAppid(appId);
        request.setMch_id(wechatPayProperties.getMchId());
        request.setBody(body);
        request.setOut_trade_no(outTradeNo);
        request.setTotal_fee(totalFee);
        request.setSpbill_create_ip(clientIp);
        request.setNotify_url(wechatPayProperties.getDomainUrl() + "/ato/wechat/pay/callback");

        // 签名
        String sign = SignUtil.getSign(request, wechatPayProperties.getAppKey());
        WechatAssert.notNullAndEmpty(sign, "签名失败");
        request.setSign(sign);

        // 发送请求
        String responseXml = post(PAY_APP_UNIFIED_ORDER, request, "统一下单");
        PayResponse response = UtilXml.convertXmlStrToObject(PayResponse.class, responseXml);

        // 验证返回的结果
        if (!response.success()) {
            WechatAssert.notNull(null, response.errorInfo());
        }

        // 验证签名
        String responseSign = response.getSign();
        String responseSign2 = SignUtil.getSign(response, wechatPayProperties.getAppKey());
        if (!responseSign.equals(responseSign2)) {
            WechatAssert.notNull(null, "签名错误");
        }

        return response;
    }

    private String post(String url, Object request, String requestName) {
        String body = UtilXml.convertToXml(request);
        String rid = UtilString.getSoleCode();
        logger.info(">>发送{}请求[{}]:\n{}", requestName, rid, body);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_XML);
        HttpEntity formEntity = new HttpEntity<>(body, headers);
        ResponseEntity responseEntity = restTemplate.postForEntity(url, formEntity, String.class);
        String result = responseEntity.getBody();
        logger.info("<<返回内容[{}]:\n{}", rid, result);
        return result;
    }

    // --------------------------------
    @Deprecated
    public QueryResponse orderQuery(String outTradeNo) {
        return orderQuery(outTradeNo, wechatPayProperties.getAppId());
    }

    @Deprecated
    public CompanyPayResponse companyToUserByBoot(String outTradeNo, String openId, Integer amount, String desc, String ip) {
        String mchAppId = wechatPayProperties.getAppId();
        String appKey = wechatPayProperties.getAppKey();
        String mchId = wechatPayProperties.getMchId();
        return companyToUser(mchAppId, appKey, mchId, outTradeNo, openId, amount, desc, ip);
    }

    @Deprecated
    public AppPayClientDto unifiedOrderByAppToClientDto(String body, String clientIp, Integer totalFee, String outTradeNo) {
        return unifiedOrderByApp(wechatPayProperties.getAppId(), body, clientIp, totalFee, outTradeNo);
    }

    @Deprecated
    public PayResponse unifiedOrderByApp(String body, String clientIp, Integer totalFee, String outTradeNo) {
        return unifiedOrderBase(wechatPayProperties.getAppId(), body, clientIp, totalFee, outTradeNo, 1, null);
    }

    @Deprecated
    public PayResponse unifiedOrderByNative(String body, String clientIp, Integer totalFee, String outTradeNo) {
        return unifiedOrderByNative(wechatPayProperties.getAppId(), body, clientIp, totalFee, outTradeNo);
    }

    @Deprecated
    public JsApiPayClientDto unifiedOrderByJsApi(String body, String clientIp, Integer totalFee, String outTradeNo, String openId) {
        return unifiedOrderByJsApi(wechatPayProperties.getAppId(), body, clientIp, totalFee, outTradeNo, openId);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy