ウィジェット微信JSPAPI支払いによる返金操作


ウィジェットは微信決済で返金操作を行います
微信支払い-返金操作の特殊性
  • 微信決済には、サブスクリプション生成インタフェース、受注ステータス照会インタフェース、受注クローズインタフェース、返金申請インタフェース、返金照会インタフェースがある.
  • 以前に、WeChat決済を使用してレジで支払う方法について書いたことがありますが、WeChatインタフェースの呼び出しから、WeChatインタフェースから返されるデータまで、処理後、フロントエンドにレジを引いてユーザーの支払いを完了する方法について完全に紹介しています.
  • 返金申請インタフェース、その他機能インタフェースの呼び出し使用を除き、類似しており、パラメータの違いを除く
  • 実は返金申請インタフェースの使用は1つの業者の証明書だけで、この証明書は身分などの情報を検証し、その証明書を送信要求のhttpclientにロードすればよい.

  • 微信の公式ガイドライン
  • 微信支払証明書の使用については、公式の説明を参照してください.https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3
  • 以下の経路で微信支払証明書をダウンロードできる:微信商戸プラットフォーム(pay.weixin.qq.com)->アカウントセンター->アカウント設定->APIセキュリティ;注ダウンロードするには管理者権限が必要
  • ダウンロードしたのは圧縮パッケージで、2つのフォーマットの証明書が入っていて、それぞれ異なる開発環境に適用されています.pkcs 12フォーマットだけでいいです.注意:証明書のパスワードのデフォルトは、ユーザーIDです.

  • 自己開発
  • 指定された業者の証明書を事前にダウンロードし、自分が指定したディレクトリに保存し、サーバーに配備する場合は、他の人が取得しないように、証明書を安全に設定したり保護したりすることをお勧めします.
  • 証明書の準備が完了したら、公式文書に従って符号化デバッグを行う.https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4

  • 開発手順
  • 証明書のロード
  • 構築要求のクライアント情報
  • パディング要求パラメータ
  • パラメータに署名しxml形式に変換する
  • 微信へのリクエスト送信
  • パラメータ処理
  • 具体的なエンコーディング
  • 払戻に必要な事業者プロファイルをプロファイルに注入
  •  	//    
        @Value("${wechat.cert}")
        private String certLocation;
        
        //   appid
        @Value("${wechat.appid}")
        private String appid;
    	
    	//   
        @Value("${wechat.partner}")
        private String partner;
        
        //    
        @Value("${wechat.partnerkey}")
        private String partnerkey;
    
  • 具体的な実装(参考までに、ウィジェット決済は以下のコードを直接使用してもよいし、自分の業務に応じて削除してもよいので、自分で作成したほうがよい):
  • import java.security.KeyStore;
    import javax.net.ssl.SSLContext;
    import org.apache.http.impl.client.CloseableHttpClient;
    /**
         *     
         *
         * @param orderNo        
         * @param refoundNo      
         * @param totalFee        
         * @param refoundFee      
         * @return
         */
        @Override
        public Map refound(String orderNo, String refoundNo, String totalFee, String refoundFee) {
            logger.info("      ,    :orderNo: "+orderNo+",refoundNo: "+refoundNo+",totalFee: "+totalFee+",refoundFee: "+refoundFee);
            Map<String, String> map = null;
            HashMap<String, String> resMap = new HashMap<>();
            try {
                KeyStore clientStore = KeyStore.getInstance("PKCS12");
                //        PKCS12    
                FileInputStream instream = new FileInputStream(certLocation);
                try {
                    //   PKCS12   (  ID)
                    clientStore.load(instream, partner.toCharArray());
                } finally {
                    instream.close();
                }
                SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(clientStore, partner.toCharArray()).build();
                //   TLS  
                SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null,
                        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
                //   httpclient SSLSocketFactory
                CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
                try {
                    HttpPost httpost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
    
                    //    
                    Map param = new HashMap();
                    param.put("appid", appid);
                    param.put("mch_id", partner);
                    param.put("out_trade_no", orderNo);
                    param.put("nonce_str", WXPayUtil.generateNonceStr());
                    //    
                    param.put("out_refund_no", refoundNo);
                    //     
                    param.put("total_fee", totalFee);
                    //    
                    param.put("refund_fee", refoundFee);
    
                    String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey);
                    System.out.println("        " + xmlParam);
    
                    logger.info("        " + xmlParam);
                    httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
                    CloseableHttpResponse response = httpclient.execute(httpost);
                    try {
                        HttpEntity entity = response.getEntity();
                        String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                        EntityUtils.consume(entity);
                        System.out.println("          :" + jsonStr);
                        logger.info("          :" + jsonStr);
                        map = WXPayUtil.xmlToMap(jsonStr);
    
                        RefoundMent refoundMent = new RefoundMent();
                        if (map.get("return_code").equals("SUCCESS")) {
                        	//    
                            resMap.put("resultCode", "SUCCESS");
                            resMap.put("mchId", map.get("mch_id"));
                           // resMap.put("sign", map.get("sign"));
                           // resMap.put("transactionId", map.get("transaction_id"));
                            resMap.put("orderNo", orderNo);
                            resMap.put("refoundNo", refoundNo);
                           // resMap.put("refundId", map.get("refund_id"));
                            resMap.put("refundFee", map.get("refund_fee"));
                            }else {
                                resMap.put("resultCode", "FAIL");
                                resMap.put("errCode", map.get("err_code"));
                                resMap.put("errCodeDes", map.get("err_code_des"));
                                logger.info("      :"+orderNo);
                                logger.info("    :"+map.get("err_code")+"   :"+map.get("err_code_des"));
                                //    ,       
                                /*
                                CompletableFuture.runAsync(() -> {
                                            RefoundMent failReFound=new RefoundMent();
                                            failReFound.setMachRefoundNo(refoundNo);
                                      
                                            failReFound.setRefoundTime(new Date());
                                            failReFound.setRefoundRes(resMap.get("err_code_des"));
    
                                            int insert = refoundMentDao.insertFail(refoundMent);
                                            logger.info("      ,    ");
                                        },
                                        threadPoolTaskExecutor
                                );
                                */
                            }
                        }
    
                    } finally {
                        response.close();
                    }
                } finally {
                    httpclient.close();
                }
            } catch (Exception e) {
                logger.error("      ,   :" + orderNo);
                e.printStackTrace();
                resMap.put("resultCode", "FAL");
                resMap.put("mesg", "    ");
    
            }
            logger.info("          :"+resMap);
            return resMap;
        }
    
    
  • これで終了
  • 注意事項
  • 伝参、原注文番号は以前に注文書を発起したときに商家がカスタマイズした商家注文番号で、返金申請に成功しなければならない.返金番号も商家がカスタマイズした重複番号で、雪花アルゴリズムが推奨されている.uuidも可能
  • 返金を申請しても、インタフェースが正常に戻っても返金に成功するわけではなく、商家口座にお金がないなどの返金に失敗する場合が多いので、返金に成功するかどうかは返金インタフェースの照会を呼び出す必要があります.
  • 同一の前払書サポート部分払戻とロット別払戻は、払戻金額が以前に支払った金額以下であるべきであり、払戻金額である部分払戻よりも小さい、バッチ別払戻は、複数回払戻を申請する必要があり、加えた金額も元の払戻金額以下であるべきであり、ロット毎の払戻書番号は重複することなく唯一であるべきである.
  • 上記のコードは、接続プールおよびlambda式を使用するライブラリー操作を行い、読者が成功と失敗後の処理方法を自分で定義することができます.注:とにかく記録ログを保持するのは良い習慣です.
  • 上記コードにおける払戻の伝達は必要なものの一部である、払戻操作について伝達可能なパラメータはまだ多く、読者が自分で選択し、自分の業務を拡張することができるなどである.

  • 最後に
    以前は微信で支払った返金を书くと言っていましたが、ブログを书く时间がないので、ずっと书いていません.今は业务が他の方向にずれています.自分で作ったものだけを読者に参考にしてください.