微信支付服务商怎么赚钱_支付服务商「建议收藏」

微信支付服务商怎么赚钱_支付服务商「建议收藏」本文服务商模式实现微信支付进行详细的讲解,实现过程还是比较复杂,订单支付中涉及到重复提交、幂等性验证、同步+异步的轮询处理等问题将在后续的文章中进行讲解


背景

小程序盛行时代,一般的企业中都都会包含多个小程序,而大部分的小程序通常都需要实现支付功能,本文将针对服务商模式进行微信支付进行详细讲解。

微信支付的模式

微信支付服务商怎么赚钱_支付服务商「建议收藏」
一般企业选用是服务商或者为渠道商模式,但是成为渠道商需要相关流量支撑才能申请,本文以服务商模式进行讲解。


咨询微信支付客服关于服务商的有些问题:
1.服务商和特约只能有一个,需要注销特约商户后申请成为服务商
2.服务商不能单独收款,只能给特约商户进行收款
3.服务商可以设置分账抽成微信会自动完成分账
4.服务商下特约商户收款会直接将钱打到特约商户下
5.直连或者特约可以成为注册另一个服务商下的特约(根据风险适时调整)

一、前期准备

1.注册服务商

服务商申请需要通过已做过公司认证的公众号,登录公司的微信服务号,在【微信支付】>【服务商申请】,直接跟着官方引导一步步操作即可,具体申请流程如下:
在这里插入图片描述
说明:所以企业需要申请公共号,才能申请注册服务商。

2.服务商入驻

通过服务商来开发的系统来帮助商户微信支付,首先需要完成商户号在服务商号中的入驻过程。服务商注册成功后,进入微信支付平台,登录服务商,进行商户入驻。一般商户入驻有两种,具体如下:

  • 页面入驻
  • 调用API方式入驻

页面入驻

在这里插入图片描述
入驻可以看作是商户生成商户号的同时与服务商形成绑定关系。具体可以参考微信公众号中按流程指引一步步操作就行。
在这里插入图片描述

说明:商户入驻完成后,此商户才能用于微信支付。

申请证书

商户号入驻成功后,需要申请API证书。
在这里插入图片描述
说明:按照官方文档申请证书,设置密钥,设置好密钥后一定要在安全的前提下记住,之后只能重置不能查看。

重要参数说明

  • appid:服务商Appid
  • mchId:服务商的商户id
  • mchKey:证书的序列号
  • subAppId:子商户小程序Appid
  • subOpenId:子商户小程序用户的openId
  • subMchId:子商户的商户id

二、子商户支付

1.下单流程图

在这里插入图片描述
注意:下单流程和直连商户一样,但是接口和参数略有不同。直接参考合作伙伴平台Api

2.代码实现

服务商模式的微信支付的具体实现方案,本文采用的是Spring Boot集成weixin-java-pay来实现微信支付。
微信服务商JSAPI下单官方文档 https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_1.shtml
weixin-java-pay文档:http://binary.ac.cn/weixin-java-pay-javadoc/

踩坑:mchId和appid必须是服务商的而且是必填,如果服务商要给特约下单的appid是特约的appid也要写服务商的,subappid才可以写特约商户的。如果服务商给特约下答案appid是服务商的那么subappid可以不填。

1.引入依赖

<dependency>
     <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-pay</artifactId>
    <version>4.5.0</version>
</dependency>

2.支付配置

将证书放到resources下
在这里插入图片描述

# 微信支付配置
wx:
  pay:
    appId: wx1xxxx #服务商微信公众号或者小程序等的appid
    subAppId: wxc0xxxxx #特约商户微信公众号或者小程序等的appid
    mchId: 160000000 #服务商微信支付商户号
    apiV3Key: 7xxxxxxxxxxxxxx #apiV3秘钥
    certSerialNo: 2CCCCCCCCCCCA  #证书号
    privateKeyPath: classpath:cert/apiclient_key.pem #apiclient_key.pem证书文件的绝对路径或者以classpath:开头的类路径
    privateCertPath: classpath:cert/apiclient_cert.pem #apiclient_cert.pem证书文件的绝对路径或者以classpath:开头的类路径
    notifyUrl: https://www.xxx.com/prod-api/anonymous/wx/notify/order #回调地址

3.相关配置类

说明:读取微信支付的配置信息

package com.ruoyi.xyhj.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/** * wxpay pay properties. * * @author Binary Wang */
@Data
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayProperties { 
   
  /** * 设置微信公众号或者小程序等的appid */
  private String appId;

  /** * 设置微信公众号或者小程序等的appid */
  private String subAppId;

  /** * 微信支付商户号 */
  private String mchId;

  /** * 微信支付商户V3密钥 */
  private String apiV3Key;

  /** * 证书号 */
  private String certSerialNo;

  /** * apiclient_key.pem证书文件的绝对路径或者以classpath:开头的类路径 */
  private String privateKeyPath;

  /** * apiclient_cert.pem证书文件的绝对路径或者以classpath:开头的类路径 */
  private String privateCertPath;

  /** * 回调地址 */
  private String notifyUrl;

}

说明:将微信支付的相关参数设置到wxjava中的cofig中。

package com.ruoyi.xyhj.config;

import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/** * @author Binary Wang */
@Configuration
@ConditionalOnClass(WxPayService.class)
@EnableConfigurationProperties(WxPayProperties.class)
@AllArgsConstructor
public class WxPayConfiguration { 
   
  private WxPayProperties properties;

  @Bean("wxPayService")
  @ConditionalOnMissingBean
  public WxPayService wxService() { 
   
    WxPayConfig payConfig = new WxPayConfig();
    payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
    payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
    payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiV3Key()));
    payConfig.setCertSerialNo(StringUtils.trimToNull(this.properties.getCertSerialNo()));
    payConfig.setPrivateKeyPath(StringUtils.trimToNull(this.properties.getPrivateKeyPath()));
    payConfig.setPrivateCertPath(StringUtils.trimToNull(this.properties.getPrivateCertPath()));
    payConfig.setNotifyUrl(StringUtils.trimToNull(this.properties.getNotifyUrl()));
    payConfig.setTradeType("JSAPI");
    payConfig.setSignType("MD5");
    WxPayService wxPayService = new WxPayServiceImpl();
    wxPayService.setConfig(payConfig);
    return wxPayService;
  }

}

4.业务实现类

@RestController
@RequestMapping("/anonymous")
@Slf4j
public class TelAnonymousController
{ 
   
    
    @Autowired
    private WxPayService wxPayService; 
        
    //发起支付
    @PostMapping("/wx/order/create")
    public WxUnifiedOrderVo createOrder(){ 
   
        //发起V3 服务商发起支付
        EcommerceServiceImpl ecommerceService=new EcommerceServiceImpl(wxPayService);
     // 1. 创建请求对象
        PartnerTransactionsRequest orderRequest=new PartnerTransactionsRequest();
        // 2. 根据订单系统传过来的订单信息组装支付参数,创建支付订单
        //服务商应用ID
        orderRequest.setSpAppid(wxPayProperties.getAppId());
        //服务商户号
        orderRequest.setSpMchid(wxPayProperties.getMchId());
        //子商户号
        orderRequest.setSubMchid(dealerMerchant.getMchid());
        //子商户/二级商户应用ID
        orderRequest.setSubAppid(wxPayProperties.getSubAppId());
        //商品描述
        orderRequest.setDescription("商品描述");
        //商户订单号
        orderRequest.setOutTradeNo("订单id");
        //设置交易结束时间为24小时
        orderRequest.setTimeExpire(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()));
        //通知地址
        orderRequest.setNotifyUrl(wxPayProperties.getNotifyUrl());
        //订单金额
        PartnerTransactionsRequest.Amount amount = new PartnerTransactionsRequest.Amount();
        amount.setTotal(BaseWxPayRequest.yuanToFen("订单金额"));
        orderRequest.setAmount(amount);
        //支付者
        PartnerTransactionsRequest.Payer payer = new PartnerTransactionsRequest.Payer();
        payer.setSubOpenid("支付者的openid");
        orderRequest.setPayer(payer);
        //发起下单请求
        TransactionsResult partner = ecommerceService.partner(TradeTypeEnum.JSAPI, partnerTransactionsRequest);
        //生成签名
        WxUnifiedOrderVo tokenJSAPI = WechatSignUtil.getTokenJSAPI(wxPayProperties.getSubAppId(), partner.getPrepayId(), wxPayProperties.getPrivateKeyPath());
        tokenJSAPI.setOrderId(order.getId());
        return tokenJSAPI;
    }
		
		//支付回调
	@ApiOperation(value = "支付回调通知处理")
    @PostMapping("/wx/notify/order")
    public void parseOrderNotifyResult(@RequestBody String resultData) throws WxPayException { 
   
        log.info("回调:{}",resultData);
        EcommerceServiceImpl ecommerceService = new EcommerceServiceImpl(wxPayService);
        PartnerTransactionsNotifyResult notifyResult = ecommerceService.parsePartnerNotifyResult(resultData, null);
        //此处解析到了回调信息
        log.info("回调:{}",notifyResult.getResult());
      //业务逻辑
    }
  
    		//支付回调
	@ApiOperation(value = "主动查询支付信息")
    @PostMapping("/wx/order/select")
    public void wxSelectOrderStatus() throws WxPayException { 
   
         //构建ecommerceService
        EcommerceServiceImpl ecommerceService = new EcommerceServiceImpl(wxPayService);
        //构建PartnerTransactionsQueryRequest对象
        PartnerTransactionsQueryRequest queryRequest = new PartnerTransactionsQueryRequest();
        queryRequest.setOutTradeNo("订单ID");
        queryRequest.setSpMchid("服务商ID");
        queryRequest.setSubMchid("特约商户ID");
        PartnerTransactionsResult partnerTransactionsResult=new PartnerTransactionsResult();
        try { 
   
            //普通查询订单API
            partnerTransactionsResult = ecommerceService.queryPartnerTransactions(queryRequest);
        } catch (WxPayException e) { 
   
            e.printStackTrace();
        }
    }
}

说明:实现微信创建订单、支付回调、查询订单接口。

5. 工具类

WxUnifiedOrderVo

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel
public class WxUnifiedOrderVo { 
   
     /** * appid */
     @ApiModelProperty("appId")
     private String appId;
     /** * 时间戳 */
     @ApiModelProperty("时间戳")
     private String timeStamp;
     /** * 随机字符串 */
     @ApiModelProperty("随机字符串")
     private String nonceStr;
     /** * 小程序下单接口返回的prepay_id参数值,提交格式如:prepay_id=*** */
     @ApiModelProperty("小程序下单接口返回的prepay_id参数值,提交格式如:prepay_id=***")
     private String packageStr;
     /** * 签名类型,默认为RSA,仅支持RSA。 */
     @ApiModelProperty("签名类型,默认为RSA,仅支持RSA。")
     private String signType;
     /** * 签名 */
     @ApiModelProperty("签名")
     private String paySign;
     /** * 订单id */
     @ApiModelProperty("订单id")
     private Long orderId;
}

WechatSignUtil

package com.ruoyi.xyhj.utils;

import com.ruoyi.xyhj.domain.vo.WxUnifiedOrderVo;

import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.UUID;

public class WechatSignUtil { 
   

    /** * 参考网站 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml * 计算签名值 * * @param appId * @param prepay_id * @return * @throws IOException * @throws SignatureException * @throws NoSuchAlgorithmException * @throws InvalidKeyException */
    public static WxUnifiedOrderVo getTokenJSAPI(String appId, String prepay_id, String privateKey) throws IOException, SignatureException, NoSuchAlgorithmException, InvalidKeyException { 
   
        // 获取随机字符串
        String nonceStr = getNonceStr();
        // 获取微信小程序支付package
        String packagestr = "prepay_id=" + prepay_id;
        long timestamp = System.currentTimeMillis() / 1000;
        //签名,使用字段appId、timeStamp、nonceStr、package计算得出的签名值
        String message = buildMessageTwo(appId, timestamp, nonceStr, packagestr);
        //获取对应的签名
        String signature = sign(message.getBytes("utf-8"),privateKey);
        // 组装返回
        WxUnifiedOrderVo vo = new WxUnifiedOrderVo();
        vo.setAppId(appId);
        vo.setTimeStamp(String.valueOf(timestamp));
        vo.setNonceStr(nonceStr);
        vo.setPackageStr(packagestr);
        vo.setSignType("RSA");
        vo.setPaySign(signature);
        return vo;
    }

    /** * 生成随机数 * @return */
    public static String getNonceStr(){ 
   
        return UUID.randomUUID().toString()
                .replaceAll("-", "")
                .substring(0, 32);
    }
    /** * 拼接参数 * * @return */

    public static String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) { 
   
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + packag + "\n";
    }
    /** * 生成签名 * * @return */
    public static String sign(byte[] message,String privateKey) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException { 
   
        Signature sign = Signature.getInstance("SHA256withRSA"); //SHA256withRSA
        sign.initSign(getPrivateKey(privateKey));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }
    /** * 获取私钥 * @param filename 私钥文件路径 (required) * @return 私钥对象 */
    public static PrivateKey getPrivateKey(String filename) throws IOException { 
   
        System.out.println("filename:" + filename);
        filename = filename.replace("classpath:", "");
        WechatSignUtil wechatSignUtil = new WechatSignUtil();
        InputStream resourceAsStream = wechatSignUtil.getClass().getClassLoader().getResourceAsStream(filename);
        byte[] bytes = new byte[0];
        bytes = new byte[resourceAsStream.available()];
        resourceAsStream.read(bytes);
        String content = new String(bytes);
// String content = new String(Files.readAllBytes(Paths.get(resource.getPath())), "utf-8");
        try { 
   
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) { 
   
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) { 
   
            throw new RuntimeException("无效的密钥格式");
        }
    }
}

三、服务商进件

官方文档 https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter11_1_1.shtml

1.特约商户进件流程、时序图

  • 流程图
    在这里插入图片描述
  • 时序图
    在这里插入图片描述
  • 申请单状态如下
    在这里插入图片描述

2.代码实现

  @Operation(summary = "提交申请单")
    @GetMapping("/createApply")
    public R<String> createApply(@RequestParam(required = false) String applymentId) throws WxPayException { 
   
        WxPayApplyment4SubCreateRequest request = new WxPayApplyment4SubCreateRequest();
        // 主体资料:主体类型、是否是金融机构、营业执照、登记证书、组织机构代码证、单位证明函照片、经营者/法人身份证件、最终受益人信息列表(UBO)、小微辅助证明材料(subjectType为小微商户时必填)
        WxPayApplyment4SubCreateRequest.SubjectInfo subjectInfo = WxPayApplyment4SubCreateRequest.SubjectInfo.builder().build()
                .setFinanceInstitution(false)
                .setBusinessLicenseInfo(null);// 省略.......
        request.setSubjectInfo(subjectInfo);
        // 补充材料
        WxPayApplyment4SubCreateRequest.AdditionInfo additionInfo=new WxPayApplyment4SubCreateRequest.AdditionInfo();
        additionInfo.setBusinessAdditionMsg("补充说明");
        additionInfo.setBusinessAdditionPics(null) ;// 补充材料
        additionInfo.setLegalPersonCommitment("法人开户承诺函");
        additionInfo.setLegalPersonVideo("法人开户意愿视频");
        request.setAdditionInfo(additionInfo);
        // 结算银行账户
        WxPayApplyment4SubCreateRequest.BankAccountInfo bankAccountInfo=new WxPayApplyment4SubCreateRequest.BankAccountInfo();
        bankAccountInfo.setBankAccountType(BankAccountTypeEnum.BANK_ACCOUNT_TYPE_CORPORATE); // 账户类型:对公银行账户
        bankAccountInfo.setAccountName("开户名称");  // 开户名称
        bankAccountInfo.setAccountBank("开户银行");
        bankAccountInfo.setBankAddressCode("开户银行省市编码");
        bankAccountInfo.setBankBranchId("开户银行联行号");
        bankAccountInfo.setBankName("开户银行全称(含支行)");
        bankAccountInfo.setAccountNumber("银行账号");
        request.setBankAccountInfo(bankAccountInfo);
        // 业务申请编号
        request.setBusinessCode("业务申请编号");
        // 经营资料
        request.setBusinessInfo(null); // 省略.......
        // 超级管理员信息
        request.setContactInfo(null);// 省略.......
        // 结算规则
        request.setSettlementInfo(null);// 省略.......

        // 调用微信API
        Applyment4SubService applyment4SubService=new Applyment4SubServiceImpl(wxPayService);
        WxPayApplymentCreateResult apply = applyment4SubService.createApply(request);
        String applyMentId = apply.getApplymentId(); // 返回申请单ID
        return R.success(applyMentId);
    }
    
    @Operation(summary = "通过申请单号查询申请状态")
    @GetMapping("/queryApply")
    public R<ApplymentStateQueryResult> queryApply(@RequestParam(required = true) String applymentId) throws WxPayException { 
   
        // 调用API 查询申请状态
        Applyment4SubService applyment4SubService=new Applyment4SubServiceImpl(wxPayService);
        ApplymentStateQueryResult result = applyment4SubService.queryApplyStatusByApplymentId(applymentId);
        return R.success(result);
    }

今天的文章微信支付服务商怎么赚钱_支付服务商「建议收藏」分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/85104.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注