微信電商收付通二級商戶進件API接口調用


眾所周知,騰訊的開放接口向來都對開發者不怎么友好,集中體現在接口調用示例demo少、錯誤信息提示不夠明確、問題反饋客服回復敷衍等。

在做收付通二級商戶入駐申請功能時更是深深體會到了這幾點。而作為普通開發者,所能做的無非就是搖頭苦笑然后默默記下,希望自己和類似的同學能夠少走彎路。

閑言少敘,進入正題!

二級商戶入駐申請,接口地址是https://api.mch.weixin.qq.com/v3/ecommerce/applyments/,要做的工作其實很簡單,就是把二級商戶的相關資質信息提交給這個接口,難點在於,對於不甚了解微信v3接口調用的同學來說,這樣那樣的賬號和密鑰、五花八門的簽名和加密,實在是讓人頭大。因此下文我會寫的盡量簡單明了。

准備工作

1.去微信支付服務商平台申請賬號https://pay.weixin.qq.com/partner/public/home,得到商戶id,即mchId;

2.設置API證書、API密鑰、APIv3密鑰,可以得到商戶API證書序列號mchSerialNo、商戶私鑰mchPrivateKey、API密鑰apiV3Key等;

3.很容易被忽略的一步,我想也是對於萌新而言最坑的一步,配置通用化接口權限,這一步如果不做的話,調試接口時會提示如下信息:

{"code":"APPID_MCHID_NOT_MATCH","message":"不屬於電商平台商戶,暫無權限"}

可按下圖示意配置開通;

4.maven項目中添加第三方工具包IJPay-WxPay的依賴;

<dependency>
  <groupId>com.github.javen205</groupId>
  <artifactId>IJPay-WxPay</artifactId> 
  <version>2.7.1</version>
</dependency>

5.獲取平台證書序列號platSerialNo、平台私鑰platPrivateKey,這一步也很關鍵,因為platSerialNo是必傳字段,而platPrivateKey是敏感數據加密的必要參數,平台證書的獲取改天我會單獨來寫;

6.實現微信圖片上傳功能,因為二級商戶進件接口需要商家的身份證、營業執照等圖片數據,接口不接收圖片流,而是需要事先將相關圖片通過接口上傳到微信圖片服務器,形成一個MediaID值來作為進件接口的參數,圖片上傳功能我也會另起一篇單獨寫。

開始調用

1.以一個小微商戶為例,先構建主體信息類結構,主類是SubmitInfo,關聯類包括BusinessLicenseInfo、OrganizationCertInfo、IdCardInfo、IdDocInfo、AccountInfo、ContactInfo、SalesSceneInfo;

 1 /**
 2  * 進件信息
 3  */
 4 @Data
 5 public class SubmitInfo implements Serializable {
 6     private static final long serialVersionUID=1L;
 7     /**業務申請編號*/
 8     private String out_request_no;
 9     /**主體類型*/
10     private String organization_type;
11     /**營業執照/登記證書信息*/
12     private BusinessLicenseInfo business_license_info;
13     /**組織機構代碼證信息*/
14     private OrganizationCertInfo organization_cert_info;
15     /**經營者/法人證件類型*/
16     private String id_doc_type;
17     /**經營者/法人身份證信息*/
18     private IdCardInfo id_card_info;
19     /**經營者/法人其他類型證件信息*/
20     private IdDocInfo id_doc_info;
21     /**是否填寫結算銀行賬戶*/
22     private Boolean need_account_info;
23     /**結算銀行賬戶*/
24     private AccountInfo account_info;
25     /**超級管理員信息*/
26     private ContactInfo contact_info;
27     /**店鋪信息*/
28     private SalesSceneInfo sales_scene_info;
29     /**商戶簡稱*/
30     private String merchant_shortname;
31     /**特殊資質*/
32     private String qualifications;
33     /**補充材料*/
34     private String business_addition_pics;
35     /**補充說明*/
36     private String business_addition_desc;
37 }
 1 /**
 2  * 營業執照/登記證書信息
 3  */
 4 @Data
 5 public class BusinessLicenseInfo implements Serializable {
 6     private static final long serialVersionUID=1L;
 7     /**證件掃描件*/
 8     private String business_license_copy;
 9     /**證件注冊號*/
10     private String business_license_number;
11     /**商戶名稱*/
12     private String merchant_name;
13     /**經營者/法定代表人姓名*/
14     private String legal_person;
15     /**注冊地址*/
16     private String company_address;
17     /**營業期限*/
18     private String business_time;
19 }
 1 /**
 2  * 組織機構代碼證信息
 3  */
 4 @Data
 5 public class OrganizationCertInfo implements Serializable {
 6     private static final long serialVersionUID=1L;
 7     /**組織機構代碼證照片*/
 8     private String organization_copy;
 9     /**組織機構代碼*/
10     private String organization_number;
11     /**組織機構代碼有效期限*/
12     private String organization_time;
13 }
 1 /**
 2  * 經營者/法人身份證信息
 3  */
 4 @Data
 5 public class IdCardInfo implements Serializable {
 6     private static final long serialVersionUID=1L;
 7     /**身份證人像面照片*/
 8     private String id_card_copy;
 9     /**身份證國徽面照片*/
10     private String id_card_national;
11     /**身份證姓名*/
12     private String id_card_name;
13     /**身份證號碼*/
14     private String id_card_number;
15     /**身份證有效期限*/
16     private String id_card_valid_time;
17 }
 1 /**
 2  * 經營者/法人其他類型證件信息
 3  */
 4 @Data
 5 public class IdDocInfo implements Serializable {
 6     private static final long serialVersionUID=1L;
 7     /**證件姓名*/
 8     private String id_doc_name;
 9     /**證件號碼*/
10     private String id_doc_number;
11     /**證件照片*/
12     private String id_doc_copy;
13     /**證件結束日期*/
14     private String doc_period_end;
15 }
 1 /**
 2  * 結算銀行賬戶
 3  */
 4 @Data
 5 public class AccountInfo implements Serializable {
 6     private static final long serialVersionUID=1L;
 7     /**賬戶類型*/
 8     private String bank_account_type;
 9     /**開戶銀行*/
10     private String account_bank;
11     /**開戶名稱*/
12     private String account_name;
13     /**開戶銀行省市編碼*/
14     private String bank_address_code;
15     /**開戶銀行聯行號*/
16     private String bank_branch_id;
17     /**開戶銀行全稱 (含支行)*/
18     private String bank_name;
19     /**銀行帳號*/
20     private String account_number;
21 }
 1 /**
 2  * 超級管理員信息
 3  */
 4 @Data
 5 public class ContactInfo implements Serializable {
 6     private static final long serialVersionUID=1L;
 7     /**超級管理員類型*/
 8     private String contact_type;
 9     /**超級管理員姓名*/
10     private String contact_name;
11     /**超級管理員身份證件號碼*/
12     private String contact_id_card_number;
13     /**超級管理員手機*/
14     private String mobile_phone;
15     /**超級管理員郵箱*/
16     private String contact_email;
17 }
 1 /**
 2  * 店鋪信息
 3  */
 4 @Data
 5 public class SalesSceneInfo implements Serializable {
 6     private static final long serialVersionUID=1L;
 7     /**店鋪名稱*/
 8     private String store_name;
 9     /**店鋪鏈接*/
10     private String store_url;
11     /**店鋪二維碼*/
12     private String store_qr_code;
13     /**小程序AppID*/
14     private String mini_program_sub_appid;
15 }

2.實例化數據,可以根據官方提供的進件參數文檔,給必要的參數賦值,得到一個submitInfo實體對象;

SubmitInfo submitInfo=new SubmitInfo();
submitInfo.setOut_request_no("test0001");
submitInfo.setOrganization_type("2401");
submitInfo.setId_doc_type("IDENTIFICATION_TYPE_MAINLAND_IDCARD");
IdCardInfo idCardInfo=new IdCardInfo();
idCardInfo.setId_card_copy("bOCC_G-WcsHmpLxRKpict56tZPY5w07MsiAY-7xZbFV1S6OTYVNGCDh1PKhyHU_CMagKLvE-aK8t1nxIE93EvFS_PFuw-xNh9KYcdCBclA0");
idCardInfo.setId_card_national("bOCC_G-WcsHmpLxRKpict-TBIP1EB0xGCt621AA7M_GqXp5i-wFkhcNHohyXSPrUlsrfKPnV6wbYkWg-rB4fBPRvjzuZPlmzPSX7AI1UoQw");
idCardInfo.setId_card_name("李霞");
idCardInfo.setId_card_number("410711197103031527");
idCardInfo.setId_card_valid_time("2028-06-21");
submitInfo.setId_card_info(idCardInfo);
ContactInfo contactInfo=new ContactInfo();
contactInfo.setContact_type("65");
contactInfo.setContact_name("李霞");
contactInfo.setContact_id_card_number("410711197103031527");
contactInfo.setMobile_phone("13708772087");
submitInfo.setContact_info(contactInfo);
SalesSceneInfo salesSceneInfo=new SalesSceneInfo();
salesSceneInfo.setStore_name("朝陽綻放花卉店");
salesSceneInfo.setStore_url("http://www.hymng.com/");
submitInfo.setSales_scene_info(salesSceneInfo);
submitInfo.setMerchant_shortname("朝陽綻放花卉店");
submitInfo.setNeed_account_info(false);
submitInfo.setBusiness_addition_desc("該商戶已持續從事電子商務經營活動滿6個月,且期間經營收入累計超過20萬元。");

3.加密submitInfo對象中的敏感數據,比如姓名、身份證號碼、手機號碼、郵箱等,這里可以封裝一個工具方法,將submitInfo傳入即可;

private static String convertToStr(SubmitInfo submitInfo) throws Exception {
  rsaEncryptSubmitInfo(submitInfo);
  return JSONObject.toJSONString(submitInfo);
}

private static void rsaEncryptSubmitInfo(SubmitInfo submitInfo) throws Exception {
  IdCardInfo idCardInfo=submitInfo.getId_card_info();
  if(idCardInfo!=null){
    idCardInfo.setId_card_name(rsaEncryptByCert(idCardInfo.getId_card_name()));
    idCardInfo.setId_card_number(rsaEncryptByCert(idCardInfo.getId_card_number()));
  }
  ContactInfo contactInfo=submitInfo.getContact_info();
  if(contactInfo!=null){
    contactInfo.setContact_name(rsaEncryptByCert(contactInfo.getContact_name()));
    contactInfo.setContact_id_card_number(rsaEncryptByCert(contactInfo.getContact_id_card_number()));
    contactInfo.setMobile_phone(rsaEncryptByCert(contactInfo.getMobile_phone()));
    if(!StringUtils.isEmpty(contactInfo.getContact_email())){
      contactInfo.setContact_email(rsaEncryptByCert(contactInfo.getContact_email()));
    }
  }
}

private static String rsaEncryptByCert(String content) throws Exception {
  InputStream inStream=new ByteArrayInputStream(platPrivateKey.getBytes(StandardCharsets.UTF_8));
  CertificateFactory cf = CertificateFactory.getInstance("X.509");
  X509Certificate certificate = (X509Certificate)cf.generateCertificate(inStream);
  PublicKey publicKey=certificate.getPublicKey();
  Cipher ci=Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
  ci.init(Cipher.ENCRYPT_MODE,publicKey);
  return Base64.getEncoder().encodeToString(ci.doFinal(content.getBytes(StandardCharsets.UTF_8)));
}

4.編寫一個公開的工具方法,將加密后的submitInfo信息發送給微信接口,這里用到了第3步中的方法,以及第三方工具包WxPayApi提供的方法調用,這樣可以節省掉微信接口簽名等工作,對於新手來說不可謂不省心;

public static String apply(SubmitInfo submitInfo) throws Exception {
  String bodyStr=convertToStr(submitInfo);
  IJPayHttpResponse response=WxPayApi.v3(RequestMethod.POST, WxDomain.CHINA.getType(), WxApiType.E_COMMERCE_APPLY.getType(), mchId, mchSerialNo, platSerialNo, mchKeyPath, bodyStr);
  if(response.getStatus()== HttpStatus.OK.value()){
    JSONObject json=JSONObject.parseObject(response.getBody());
    return json.getString("applyment_id");
  }else{
    throw new Exception();
  }
}

5.使用以上步驟就可以成功得到最終的進件申請編號applyment_id,后續可以使用它查詢入駐申請的審核結果。以上靜態方法可統一編寫到一個工具類中,只需要將第4步中的apply開放供業務層調用即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM