puzhibing
2023-10-13 e31a75558bd7b8ac200194d11d181d0c6e319aa9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
package com.ruoyi.shop.util;
 
import cn.hutool.http.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.shop.domain.dto.MgtShopHFTXAuthDto;
import com.ruoyi.shop.domain.vo.MerchantBasicdataVo;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.util.StringUtils;
 
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.*;
 
/**
 * 汇付天下工具类
 * @author zhibing.pu
 * @Date 2023/10/12 0:02
 */
public class HuiFuTianXiaUtil {
    //私钥(Base64编码)
    private static String privateKeyBase64 = "";
    //公钥(Base64编码)
    private static String publicKeyBase64 = "";
    //商户号
    private static String huifu_id = "6666000140729384";
    //产品号
    private static String product_id = "";
    //微信小程序appid
    private static String sub_appid = "";
    //本地文件存储位置
    private static String path = "";
    //控制台地址https://dashboard.huifu.com/partners/login,用户名为hongrt,最新密码为hongrt_2023@
 
 
 
    /**
     * 微信小程序支付
     * @param req_seq_id    支付流水号
     * @param goods_desc    商品描述
     * @param trans_amt     支付金额
     * @param sub_openid    微信小程序用户openid
     * @param notify_url    异步通知回调地址
     * @param acct_split_bunch  分账对象[{"div_amt":"0.10","huifu_id":"6666000123120001"}]
     */
    public static R<> weixinPayment(String req_seq_id, String goods_desc, Double trans_amt, String sub_openid, String notify_url, JSONArray acct_split_bunch){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        NumberFormat numberInstance = NumberFormat.getInstance();
        //最大两位小数
        numberInstance.setMaximumFractionDigits(2);
        String url = "https://api.huifu.com/v2/trade/payment/jspay";
        JSONObject data = new JSONObject();
        data.put("req_date", sdf.format(new Date()));
        data.put("req_seq_id", req_seq_id);
        data.put("huifu_id", huifu_id);
        data.put("goods_desc", goods_desc);
        data.put("trade_type", "T_MINIAPP");
        data.put("trans_amt", numberInstance.format(trans_amt));
 
        JSONObject wx_data = new JSONObject();
        wx_data.put("sub_appid", sub_appid);
        wx_data.put("sub_openid", sub_openid);
        data.put("wx_data", wx_data.toJSONString());
        data.put("notify_url", notify_url);
        data.put("acct_split_bunch", acct_split_bunch.toJSONString());
 
        JSONObject body = new JSONObject();
        body.put("sys_id", huifu_id);
        body.put("product_id", product_id);
        body.put("sign", sign(data.toJSONString()));
        body.put("data", data);
        HttpRequest post = HttpUtil.createPost(url);
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-type","application/json; charset=utf-8");
        headers.put("Accept", "application/json");
        post.addHeaders(headers);
        post.body(body.toJSONString());
        HttpResponse execute = post.execute();
        String result1 = execute.body();
        execute.close();
        if(StringUtils.hasLength(result1)){
            JSONObject result = JSONObject.parseObject(result1);
            String result_data = result.getString("data");
            String result_sign = result.getString("sign");
            boolean verify = verify(result_data, result_sign);
            if(!verify){
                return R.fail("结果验签失败");
            }
            JSONObject resultData = result.getJSONObject("data");
            /**
             * 00000000    交易受理成功;注:交易状态以trans_stat为准;
             * 00000100    下单成功
             * 10000000    产品号不能为空
             * 10000000    交易类型不能为空
             * 10000000    %s不能为空(%s代指报错参数名)
             * 10000000    %s长度固定%d位(%s代指报错参数名、%d代指字段长度)
             * 10000000    %s最大长度为%d位(%s代指报错参数名、%d代指字段长度)
             * 10000000    %s的传入枚举[%s]不存在(%s代指报错参数名)
             * 10000000    %s不符合%s格式(%s代指报错参数名)。如:交易金额不符合金额格式
             * 10000000    订单已超时
             * 20000000    重复交易
             * 21000000    手续费金额、手续费收取方式、手续费扣款标识、手续费子客户号、手续费账户号,必须同时为空或同时必填
             * 22000000    产品号不存在
             * 22000000    产品号状态异常
             * 22000002    商户信息不存在
             * 22000002    商户状态异常
             * 22000003    延迟账户不存在
             * 22000003    商户账户信息不存在
             * 22000004    暂未开通分账权限
             * 22000004    暂未开通%s权限(%s代指报错参数名)
             * 22000004    暂未开通延迟入账权限
             * 22000005    手续费承担方必须参与分账
             * 22000005    分账列表必须包含主交易账户
             * 22000005    其他商户分账比例过高
             * 22000005    商户入驻信息配置有误(多通道)
             * 22000005    商户分期贴息未激活
             * 22000005    分期交易不能重复激活
             * 22000005    手续费配置有误
             * 22000005    商户贴息信息未配置
             * 22000005    花呗分期费率配置有误
             * 22000005    分账配置有误
             * 22000005    分账配置未包含手续费承担方
             * 22000005    商户入驻配置信息有误
             * 22000005    商户支付宝/微信入驻信息配置有误
             * 22000005    商户银联入驻信息配置有误
             * 22000005    商户贴息分期费率未配置渠道号
             * 22000005    商户贴息分期费率未配置费率类型
             * 22000005    商户贴息分期费率配置有误
             * 22000005    手续费费率未配置
             * 22000005    手续费计算错误
             * 22000005    商户贴息信息配置有误
             * 22000005    商户未报名活动或活动已过期
             * 22000005    数字货币手续费费率未配置
             * 22000005    数字货币手续费配置有误
             * 22000005    商户未配置默认入驻信息(多通道)
             * 23000003    交易金额不足以支付内扣手续费
             * 23000003    优惠金额大于交易金额
             * 23000004    交易类型不支持
             * 23000004    当前交易类型不支持商户贴息
             * 90000000    业务执行失败;如:账户可用余额不足
             * 90000000    该功能已关闭,请联系客服
             * 90000000    交易失败,单日金额超限,请联系额服提额
             * 90000000    交易存在风险
             * 91111119    通道异常,请稍后重试
             * 98888888    系统错误
             */
            String resp_code = resultData.getString("resp_code");
            String resp_desc = resultData.getString("resp_desc");
            //交易状态 P: 处理中、S: 成功、F: 失败
            String trans_stat = resultData.getString("trans_stat");
            //交易受理成功;注:交易状态以trans_stat为准;
            String success1 = "00000000";
            //下单成功
            String success2 = "00000100";
            if(success1.equals(resp_code) || success2.equals(resp_code)){
 
            }
            return R.fail(resp_desc);
        }
        return R.fail("请求异常");
    }
 
 
 
    /**
     * RSA私钥签名:签名方式SHA256WithRSA
     * @param data 待签名字符串
     * @return 签名byte[]
     * @throws Exception
     */
    public static String sign(String data) {
        //先对该json对象数据按照参数字典顺序(参数名ASCII码从小到大排序,参数名区分大小写)排序生成字符串,再进行加签和验签。
        data = JSON.toJSONString(JSONObject.parseObject(data, TreeMap.class));
        // Base64 --> Key
        try {
            byte[] bytes = Base64.getDecoder().decode(privateKeyBase64);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
            KeyFactory keyFactory;
            keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            // Sign
            Signature signature = Signature.getInstance("SHA256WithRSA");
            signature.initSign(privateKey);
            signature.update(data.getBytes("UTF-8"));
            return Base64.getEncoder().encodeToString(signature.sign());
        } catch (Exception e) {
            return null;
        }
    }
 
 
 
    /**
     * 使用汇付RSA公钥验签
     * @param data 待签名字符串
     * @return 验签结果
     * @throws Exception
     */
    public static boolean verify(String data, String sign) {
        //先对该json对象数据按照参数字典顺序(参数名ASCII码从小到大排序,参数名区分大小写)排序生成字符串,再进行加签和验签。
        data = JSON.toJSONString(JSONObject.parseObject(data, TreeMap.class));
        // Base64 --> Key
        try {
            byte[] bytes = Base64.getDecoder().decode(publicKeyBase64);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
            KeyFactory keyFactory;
            keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            // verify
            Signature signature = Signature.getInstance("SHA256WithRSA");
            signature.initVerify(publicKey);
            signature.update(data.getBytes("UTF-8"));
            return signature.verify(Base64.getDecoder().decode(sign));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
 
    }
 
 
    /**
     * 商户进价
     * @param dto
     * @param req_seq_id            流水号
     * @param async_return_url      异步通知回调地址
     * @return
     */
    public static R<MerchantBasicdataVo> merchantBasicdataEnt(MgtShopHFTXAuthDto dto, String req_seq_id, String async_return_url){
        String url = "https://api.huifu.com/v2/merchant/basicdata/ent";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        JSONObject data = new JSONObject();
        data.put("req_seq_id", req_seq_id);
        data.put("req_date", sdf.format(new Date()));
        data.put("upper_huifu_id", huifu_id);
        data.put("reg_name", dto.getReg_name());
        data.put("short_name", dto.getShort_name());
        data.put("ent_type", dto.getEnt_type());
        data.put("license_code", dto.getLicense_code());
        data.put("license_validity_type", dto.getLicense_validity_type());
        data.put("license_begin_date", dto.getLicense_begin_date());
        if("0".equals(dto.getLicense_validity_type())){
            data.put("license_end_date", dto.getLicense_end_date());
        }
        data.put("reg_prov_id", dto.getReg_prov_id());
        data.put("reg_area_id", dto.getReg_area_id());
        data.put("reg_district_id", dto.getReg_district_id());
        data.put("reg_detail", dto.getReg_detail());
        data.put("legal_name", dto.getLegal_name());
        data.put("legal_cert_type", dto.getLegal_cert_type());
        data.put("legal_cert_no", dto.getLegal_cert_no());
        data.put("legal_cert_validity_type", dto.getLegal_cert_validity_type());
        data.put("legal_cert_begin_date", dto.getLegal_cert_begin_date());
        if("0".equals(dto.getLegal_cert_validity_type())){
            data.put("legal_cert_end_date", dto.getLegal_cert_end_date());
        }
        data.put("prov_id", dto.getProv_id());
        data.put("area_id", dto.getArea_id());
        data.put("district_id", dto.getDistrict_id());
        data.put("detail_addr", dto.getDetail_addr());
        data.put("contact_name", dto.getContact_name());
        data.put("contact_mobile_no", dto.getContact_mobile_no());
        data.put("contact_email", dto.getContact_email());
        data.put("service_phone", dto.getService_phone());
        data.put("busi_type", "1");
        data.put("receipt_name", dto.getReceipt_name());
        data.put("mcc", "7297");
 
        //结算卡信息配置
        JSONObject card_info = new JSONObject();
        card_info.put("card_type", dto.getCard_type());
        card_info.put("card_name", dto.getCard_name());
        card_info.put("card_no", dto.getCard_no());
        if(!"0".equals(dto.getCard_type())){
            card_info.put("prov_id", dto.getJs_prov_id());
            card_info.put("area_id", dto.getJs_area_id());
            card_info.put("cert_type", dto.getCert_type());
        }
        if("0".equals(dto.getCard_type())){
            card_info.put("branch_code", dto.getBranch_code());
        }
        card_info.put("cert_no", dto.getCert_no());
        card_info.put("cert_validity_type", dto.getCert_validity_type());
        if("0".equals(dto.getCert_validity_type())){
            card_info.put("cert_end_date", dto.getCert_end_date());
        }
        card_info.put("mp", dto.getMp());
        data.put("card_info", card_info.toJSONString());
 
        //取现信息配置
        JSONObject cash_config = new JSONObject();
        cash_config.put("cash_type", "T1");
        cash_config.put("fix_amt", "0.00");
        data.put("cash_config", cash_config.toJSONString());
 
        //结算规则配置
        JSONObject settle_config = new JSONObject();
        cash_config.put("settle_cycle", "T1");
        cash_config.put("settle_pattern", "P0");
        cash_config.put("settle_batch_no", "0");
        cash_config.put("constant_amt", "0.00");
        data.put("settle_config", settle_config.toJSONString());
 
        data.put("async_return_url", async_return_url);
        data.put("mer_icp", dto.getMer_icp());
        data.put("open_licence_no", dto.getOpen_licence_no());
        data.put("head_huifu_id", huifu_id);
        data.put("reg_acct_pic", dto.getReg_acct_pic());
        data.put("settle_card_front_pic", dto.getSettle_card_front_pic());
        data.put("settle_cert_back_pic", dto.getSettle_cert_back_pic());
        data.put("settle_cert_front_pic", dto.getSettle_cert_front_pic());
        data.put("tax_reg_pic", dto.getTax_reg_pic());
        data.put("legal_cert_back_pic", dto.getLegal_cert_back_pic());
        data.put("legal_cert_front_pic", dto.getLegal_cert_front_pic());
        data.put("license_pic", dto.getLicense_pic());
        data.put("auth_enturst_pic", dto.getAuth_enturst_pic());
        data.put("reg_capital", dto.getReg_capital());
        data.put("business_scope", dto.getBusiness_scope());
        data.put("found_date", dto.getFound_date());
        data.put("scene_type", "ALL");
        data.put("store_header_pic", dto.getStore_header_pic());
        data.put("store_indoor_pic", dto.getStore_indoor_pic());
        data.put("store_cashier_desk_pic", dto.getStore_cashier_desk_pic());
        data.put("online_company_pic", dto.getOnline_company_pic());
        data.put("online_company_area_pic", dto.getOnline_company_area_pic());
        data.put("legal_mobile_no", dto.getLegal_mobile_no());
        data.put("legal_addr", dto.getLegal_addr());
 
        JSONObject body = new JSONObject();
        body.put("sys_id", huifu_id);
        body.put("product_id", product_id);
        body.put("sign", sign(data.toJSONString()));
        body.put("data", data);
        HttpRequest post = HttpUtil.createPost(url);
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-type","application/json; charset=utf-8");
        headers.put("Accept", "application/json");
        post.addHeaders(headers);
        post.body(body.toJSONString());
        HttpResponse execute = post.execute();
        String result = execute.body();
        execute.close();
        if(!StringUtils.hasLength(result)){
            return R.fail("请求异常");
        }
        JSONObject resultData = JSON.parseObject(result);
        String resp_code = resultData.getString("resp_code");
        String resp_desc = resultData.getString("resp_desc");
        //处理成功
        String success1 = "00000000";
        //交易正在处理中
        String success2 = "00000100";
        //审核中
        String success3 = "90000000";
        MerchantBasicdataVo vo = new MerchantBasicdataVo();
        if(success1.equals(resp_code) || success2.equals(resp_code) || success3.equals(resp_code)){
            vo.setStatus(success1.equals(resp_code) ? 1 : success3.equals(resp_code) ? 2 : 3);
            vo.setHuifu_id(resultData.getString("huifu_id"));
            vo.setApply_no(resultData.getString("apply_no"));
            vo.setToken_no(resultData.getString("token_no"));
            return R.ok(vo);
        }
        return R.fail(resp_desc);
    }
 
 
    /**
     * 企业进件通知回调处理
     * @param jsonObject
     * @return
     */
    public static R<MerchantBasicdataVo> merchantBasicdataEntNotify(JSONObject jsonObject){
        String ok = "200";
        String success = "10000";
        String resp_code = jsonObject.getString("resp_code");
        if(ok.equals(resp_code) || success.equals(resp_code)){
            JSONObject data = jsonObject.getJSONObject("data");
            String sub_resp_code = data.getString("sub_resp_code");
            String sub_resp_desc = data.getString("sub_resp_desc");
            //处理成功
            String success1 = "00000000";
            //交易正在处理中
            String success2 = "00000100";
            //审核中
            String success3 = "90000000";
            MerchantBasicdataVo vo = new MerchantBasicdataVo();
            if(success1.equals(sub_resp_code) || success2.equals(sub_resp_code) || success3.equals(sub_resp_code)){
                vo.setStatus(success1.equals(sub_resp_code) ? 1 : success3.equals(sub_resp_code) ? 2 : 3);
                vo.setAudit_status(data.getString("audit_status"));
                vo.setAudit_desc(data.getString("audit_desc"));
                vo.setHuifu_id(data.getString("huifu_id"));
                vo.setApply_no(data.getString("apply_no"));
                vo.setToken_no(data.getString("token_no"));
                return R.ok(vo);
            }
            return R.fail(sub_resp_desc);
        }
        return R.fail(jsonObject.getString("resp_desc"));
    }
 
 
 
    /**
     * 个人商户进件
     * @param dto
     * @param req_seq_id            流水号
     * @param async_return_url      异步通知回调地址
     * @return
     */
    public static R<MerchantBasicdataVo> merchantBasicdataIndv(MgtShopHFTXAuthDto dto, String req_seq_id, String async_return_url){
        String url = "https://api.huifu.com/v2/merchant/basicdata/indv";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        JSONObject data = new JSONObject();
        data.put("req_seq_id", req_seq_id);
        data.put("req_date", sdf.format(new Date()));
        data.put("upper_huifu_id", huifu_id);
        data.put("reg_name", dto.getReg_name());
        data.put("prov_id", dto.getProv_id());
        data.put("area_id", dto.getArea_id());
        data.put("district_id", dto.getDistrict_id());
        data.put("detail_addr", dto.getDetail_addr());
        data.put("contact_name", dto.getContact_name());
        data.put("contact_mobile_no", dto.getContact_mobile_no());
        data.put("contact_email", dto.getContact_email());
 
        //结算卡信息配置
        JSONObject card_info = new JSONObject();
        card_info.put("card_name", dto.getCard_name());
        card_info.put("card_no", dto.getCard_no());
        card_info.put("prov_id", dto.getJs_prov_id());
        card_info.put("area_id", dto.getJs_area_id());
        card_info.put("cert_type", dto.getCert_type());
        card_info.put("cert_no", dto.getCert_no());
        card_info.put("cert_validity_type", dto.getCert_validity_type());
        card_info.put("cert_begin_date", dto.getCert_begin_date());
        card_info.put("cert_end_date", dto.getCert_end_date());
        card_info.put("mp", dto.getMp());
        data.put("card_info", card_info.toJSONString());
 
        //取现信息配置
        JSONObject cash_config = new JSONObject();
        cash_config.put("cash_type", "T1");
        cash_config.put("fix_amt", "0.00");
        data.put("cash_config", cash_config.toJSONString());
 
        //结算规则配置
        JSONObject settle_config = new JSONObject();
        cash_config.put("settle_cycle", "T1");
        cash_config.put("settle_pattern", "P0");
        cash_config.put("settle_batch_no", "0");
        cash_config.put("constant_amt", "0.00");
        data.put("settle_config", settle_config.toJSONString());
 
        data.put("async_return_url", async_return_url);
        data.put("mer_icp", dto.getMer_icp());
        data.put("scene_type", "ALL");
        data.put("legal_cert_no", dto.getLegal_cert_no());
        data.put("legal_cert_validity_type", dto.getLegal_cert_validity_type());
        data.put("legal_cert_begin_date", dto.getLegal_cert_begin_date());
        data.put("legal_cert_end_date", dto.getLegal_cert_end_date());
        data.put("legal_addr", dto.getLegal_addr());
        data.put("legal_cert_back_pic", dto.getLegal_cert_back_pic());
        data.put("legal_cert_front_pic", dto.getLegal_cert_front_pic());
        data.put("mcc", "7297");
        data.put("store_header_pic", dto.getStore_header_pic());
        data.put("store_indoor_pic", dto.getStore_indoor_pic());
        data.put("store_cashier_desk_pic", dto.getStore_cashier_desk_pic());
        data.put("settle_card_front_pic", dto.getSettle_card_front_pic());
        data.put("auth_enturst_pic", dto.getAuth_enturst_pic());
 
        JSONObject body = new JSONObject();
        body.put("sys_id", huifu_id);
        body.put("product_id", product_id);
        body.put("sign", sign(data.toJSONString()));
        body.put("data", data);
        HttpRequest post = HttpUtil.createPost(url);
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-type","application/json; charset=utf-8");
        headers.put("Accept", "application/json");
        post.addHeaders(headers);
        post.body(body.toJSONString());
        HttpResponse execute = post.execute();
        String result = execute.body();
        execute.close();
        if(!StringUtils.hasLength(result)){
            return R.fail("请求异常");
        }
        JSONObject resultData = JSON.parseObject(result);
        String resp_code = resultData.getString("resp_code");
        String resp_desc = resultData.getString("resp_desc");
        //处理成功
        String success1 = "00000000";
        //交易正在处理中
        String success2 = "00000100";
        //审核中
        String success3 = "90000000";
        MerchantBasicdataVo vo = new MerchantBasicdataVo();
        if(success1.equals(resp_code) || success2.equals(resp_code) || success3.equals(resp_code)){
            vo.setStatus(success1.equals(resp_code) ? 1 : success3.equals(resp_code) ? 2 : 3);
            vo.setHuifu_id(resultData.getString("huifu_id"));
            vo.setApply_no(resultData.getString("apply_no"));
            vo.setToken_no(resultData.getString("token_no"));
            return R.ok(vo);
        }
        return R.fail(resp_desc);
    }
 
 
 
    /**
     * 个人商户进件通知回调处理
     * @param jsonObject
     * @return
     */
    public static R<MerchantBasicdataVo> merchantBasicdataIndvNotify(JSONObject jsonObject){
        String ok = "200";
        String success = "10000";
        String resp_code = jsonObject.getString("resp_code");
        if(ok.equals(resp_code) || success.equals(resp_code)){
            JSONObject data = jsonObject.getJSONObject("data");
            String sub_resp_code = data.getString("sub_resp_code");
            String sub_resp_desc = data.getString("sub_resp_desc");
            //处理成功
            String success1 = "00000000";
            //交易正在处理中
            String success2 = "00000100";
            //审核中
            String success3 = "90000000";
            MerchantBasicdataVo vo = new MerchantBasicdataVo();
            if(success1.equals(sub_resp_code) || success2.equals(sub_resp_code) || success3.equals(sub_resp_code)){
                vo.setStatus(success1.equals(sub_resp_code) ? 1 : success3.equals(sub_resp_code) ? 2 : 3);
                vo.setAudit_status(data.getString("audit_status"));
                vo.setAudit_desc(data.getString("audit_desc"));
                vo.setHuifu_id(data.getString("huifu_id"));
                vo.setApply_no(data.getString("apply_no"));
                vo.setToken_no(data.getString("token_no"));
                return R.ok(vo);
            }
            return R.fail(sub_resp_desc);
        }
        return R.fail(jsonObject.getString("resp_desc"));
    }
 
 
    /**
     * 上传文件
     * @param file_url      文件网络地址
     * @param req_seq_id    流水号
     * @param file_type     文件类型
     * @return
     */
    public static R<String> supplementaryPicture(String file_url, String req_seq_id, String file_type){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String url = "https://api.huifu.com/v2/supplementary/picture";
        // 请求参数
        Map<String, Object> params = new HashMap<String, Object>();
        // 请求流水号,需保证当天商户下唯一,推荐采用日期时间+几位流水号的形式
        params.put("req_seq_id", req_seq_id);
        params.put("req_date", sdf.format(new Date()));
        params.put("file_type", file_type);
        params.put("huifu_id", huifu_id);
        String data = JSON.toJSONString(params);
        File file = HttpUtil.downloadFileFromUrl(file_url, path);
 
        CloseableHttpClient httpclient1 = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = null;
 
        try {
            HttpPost httpPost = new HttpPost(url);
            org.apache.http.entity.ContentType contentType = org.apache.http.entity.ContentType.create("text/plain", Charset.forName("UTF-8"));
            MultipartEntityBuilder mEntityBuilder = MultipartEntityBuilder.create();
            mEntityBuilder.addTextBody("sys_id", huifu_id, contentType);
            mEntityBuilder.addTextBody("product_id", product_id, contentType);
            mEntityBuilder.addTextBody("data", data, contentType);
            mEntityBuilder.addBinaryBody("file", file);
 
            httpPost.setEntity(mEntityBuilder.build());
            response = httpclient1.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == org.apache.http.HttpStatus.SC_OK) {
                HttpEntity resEntity = response.getEntity();
                result = EntityUtils.toString(resEntity);
                System.out.print(result);
            }
            if(!StringUtils.hasLength(result)){
                return R.fail("请求异常");
            }
            JSONObject results = JSON.parseObject(result);
            JSONObject resultData = results.getJSONObject("data");
            String resp_code = resultData.getString("resp_code");
            String resp_desc = resultData.getString("resp_desc");
            //成功
            String success1 = "00000000";
            if(success1.equals(resp_code)){
                return R.ok(resultData.getString("file_id"));
            }
            return R.fail(resp_desc);
        } catch (IOException e) {
            e.printStackTrace();
            return R.fail("请求异常");
        }
    }
 
 
    /**
     * 商户分账配置
     * @param req_seq_id            流水号
     * @param huifuId               商户号
     * @param apply_ratio           最大分账比例
     * @param async_return_url      回调通知
     * @return
     */
    public static R<String> merchantSplitConfig(String req_seq_id, String huifuId, Double apply_ratio, String async_return_url){
        NumberFormat numberInstance = NumberFormat.getInstance();
        //最大两位小数
        numberInstance.setMaximumFractionDigits(2);
        String url = "https://api.huifu.com/v2/merchant/split/config";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        JSONObject data = new JSONObject();
        data.put("req_seq_id", req_seq_id);
        data.put("req_date", sdf.format(new Date()));
        data.put("huifu_id", huifuId);
        data.put("rule_origin", "01");
        data.put("div_flag", "Y");
        data.put("apply_ratio", numberInstance.format(apply_ratio));
        data.put("start_type", "0");
        data.put("async_return_url", async_return_url);
        data.put("scene", "");
 
        JSONObject file_list = new JSONObject();
        file_list.put("file_id", "");
        data.put("file_list", file_list.toJSONString());
 
        JSONObject split_ext_info = new JSONObject();
        split_ext_info.put("busi_instruction", "");
        split_ext_info.put("capital_instruction", "");
        split_ext_info.put("function_instruction", "");
        data.put("split_ext_info", split_ext_info.toJSONString());
        data.put("online_busi_type", "");
 
        JSONObject body = new JSONObject();
        body.put("sys_id", huifu_id);
        body.put("product_id", product_id);
        body.put("sign", sign(data.toJSONString()));
        body.put("data", data);
        HttpRequest post = HttpUtil.createPost(url);
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-type","application/json; charset=utf-8");
        headers.put("Accept", "application/json");
        post.addHeaders(headers);
        post.body(body.toJSONString());
        HttpResponse execute = post.execute();
        String result = execute.body();
        execute.close();
        if(!StringUtils.hasLength(result)){
            return R.fail("请求异常");
        }
        JSONObject resultData = JSON.parseObject(result).getJSONObject("data");
        String resp_code = resultData.getString("resp_code");
        String resp_desc = resultData.getString("resp_desc");
        //处理成功
        String success1 = "00000000";
        //交易正在处理中
        String success2 = "00000100";
        //审核中
        String success3 = "90000000";
        if(success1.equals(resp_code) || success2.equals(resp_code) || success3.equals(resp_code)){
            return R.ok(resultData.getString("apply_no"));
        }
        return R.fail(resp_desc);
    }
 
 
    /**
     * 商户分账配置回调处理
     * @param jsonObject
     * @return
     */
    public static R<MerchantBasicdataVo> merchantSplitConfigNotify(JSONObject jsonObject){
        String sub_resp_code = jsonObject.getString("sub_resp_code");
        String sub_resp_desc = jsonObject.getString("sub_resp_desc");
        //处理成功
        String success1 = "00000000";
        //交易正在处理中
        String success2 = "00000100";
        //审核中
        String success3 = "90000000";
        MerchantBasicdataVo vo = new MerchantBasicdataVo();
        if(success1.equals(sub_resp_code) || success2.equals(sub_resp_code) || success3.equals(sub_resp_code)){
            vo.setStatus(success1.equals(sub_resp_code) ? 1 : success3.equals(sub_resp_code) ? 2 : 3);
            vo.setAudit_status(jsonObject.getString("audit_status"));
            vo.setAudit_desc(jsonObject.getString("audit_desc"));
            vo.setHuifu_id(jsonObject.getString("huifu_id"));
            vo.setApply_no(jsonObject.getString("apply_no"));
            return R.ok(vo);
        }
        return R.fail(sub_resp_desc);
    }
 
}