xuhy
2023-08-11 3c1223bf3eb6df077b48637a7c93a93246a1a8ae
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
package com.stylefeng.guns.modular.system.util.LiuZhouBank;
 
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fop.sdk.*;
import com.fop.sdk.domain.*;
import com.fop.sdk.request.*;
import com.fop.sdk.response.*;
import com.stylefeng.guns.core.util.ToolUtil;
 
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
 
/**
 * 支付工具类
 * @author pzb
 * @Date 2022/11/28 21:10
 */
public class PayUtil {
 
 
    /**
     * 聚合支付预下单(微信、本行卡)
     * @param subAppId          微信分配商户的子商户公众账号 ID
     * @param openid            微信小程序openid
     * @param chnlPayPage       微信商户号
     * @param payType           支付类型:01-本行卡支付,02-聚合 微信,03-本行卡支付,微信支付 04-支付宝支付,05-本行卡支付,支付宝支付,06-微信支付,支付宝支付 07-全部
     * @param amount            支付金额
     * @param transDesc         交易描述
     * @param backNotifyUrl     回调地址
     * @param transSeq          商户流水号
     * @return
     */
    public static String polymericPay(String subAppId, String openid, String chnlPayPage, String payType, Double amount, String transDesc, String backNotifyUrl, String transSeq){
        String uri = "/api/conductor/cashier/polymericPay/1.0.0";
        FopClient fopClient = DefaultFopClient.builder(Config.APP_ID, Config.PRIVATE_KEY, Config.FOP_PUBLIC_KEY)
                .IsBodyEncrypt(true)
                .SererUrl(Config.PRODUCTION_URL + uri)
                .EncryptType(EncryptType.SM4)
                .SignType(SignType.SM2).build();
 
        /**
         * model,request,response类
         * 不同接口的model,request,response均不相同
         * 其中,ConductorCashierXXXX需与apiUrl相互对应。在引入开放平台jar包后,驼峰可使用ide快捷键补全
         * 或查看jar包中com.fop.sdk中的domain包,request包,response包,引入对象皆在此目录中
         * 如,协议支付的model 为 ConductorCashierProtocolpaytransModel_100
         */
        ConductorCashierPolymericpayModel_100 model = new ConductorCashierPolymericpayModel_100();
        ConductorCashierPolymericpayRequest_100 request = new ConductorCashierPolymericpayRequest_100();
        ConductorCashierPolymericpayResponse_100 response = null;
 
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMdd");
        SimpleDateFormat sdf2 = new SimpleDateFormat("HHmmss");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String format = sdf1.format(new Date());
        String format1 = sdf2.format(new Date());
        model.setMchtNo(Config.MCHT_NO);
        model.setTransSeq(transSeq);
        model.setTransDate(format);
        model.setTransTime(format1);
        model.setVersion("1.0");
        model.setSndDt(format + format1);
 
        model.setSubAppId(subAppId);//微信分配商户的子商户公众账号 ID
        model.setOpenId(openid);//商户通过微信预授权获取的用户唯一标识,当payChnlType=02时必传
        model.setChnlPayPage(chnlPayPage);//微信分配商户的子商户账号 ID,当 payChnlType=02 时必传
        model.setPayChnlType(ToolUtil.isNotEmpty(openid) ? "02" : "01");//01-H5  02-微信小程序
        model.setPayType(payType);//支付类型:01-本行卡支付,02-聚合 微信,03-本行卡支付,微信支付 04-支付宝支付,05-本行卡支付,支 付宝支付,06-微信支付,支付宝支 付 07-全部
        model.setTransAmount(amount.toString());//交易金额
        model.setTransDesc(transDesc);//交易描述
        model.setBackNotifyUrl(backNotifyUrl);//后台异步通知回调地址
        try {
            model.setTermIp(InetAddress.getLocalHost().getHostAddress());//终端IP
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        request.setBizModel(model);
        try {
            response = fopClient.execute(request);
        } catch (FopApiException e) {
            e.printStackTrace();
        }
        System.err.println("预下单:" + JSON.toJSONString(response));
        if("00000000".equals(response.getBizCode()) || "88888888".equals(response.getBizCode())){
            String transDate = response.getTransDate();
            String transTime = response.getTransTime();
            String transSeq1 = response.getTransSeq();
            return response.getCodeUrl();
        }else{
            System.err.println(response.getBizCode() + ":" + response.getBizMsg());
        }
        return null;
    }
 
 
    /**
     * 聚合支付交易状态查询
     * @param oriTransSeq       原商户上送交易流水号
     * @param oriTransDate      原交易日期
     * @param oriTansTime       原交易时间
     * @param oriTransAmount    原交易金额
     * @return
     */
    public static String poPayTransStatusQuery(String oriTransSeq, String oriTransDate, String oriTansTime, Double oriTransAmount){
        String uri = "/api/conductor/cashier/poPayTransStatusQuery/1.0.0";
        FopClient fopClient = DefaultFopClient.builder(Config.APP_ID, Config.PRIVATE_KEY, Config.FOP_PUBLIC_KEY)
                .IsBodyEncrypt(true)
                .SererUrl(Config.PRODUCTION_URL + uri)
                .EncryptType(EncryptType.SM4)
                .SignType(SignType.SM2).build();
 
        /**
         * model,request,response类
         * 不同接口的model,request,response均不相同
         * 其中,ConductorCashierXXXX需与apiUrl相互对应。在引入开放平台jar包后,驼峰可使用ide快捷键补全
         * 或查看jar包中com.fop.sdk中的domain包,request包,response包,引入对象皆在此目录中
         * 如,协议支付的model 为 ConductorCashierProtocolpaytransModel_100
         */
        ConductorCashierPopaytransstatusqueryModel_100 model = new ConductorCashierPopaytransstatusqueryModel_100();
        ConductorCashierPopaytransstatusqueryRequest_100 request = new ConductorCashierPopaytransstatusqueryRequest_100();
        ConductorCashierPopaytransstatusqueryResponse_100 response = null;
 
        model.setOriTransSeq(oriTransSeq);//原商户上送交易流水号
        model.setOriTransType("mergePay.order");//sign.pay 协议支付,sign.deposit协议代付,sign.wx.jspay协议代付关联微信公众号支付,sign.ali.jspay协议代付关联支付宝服务窗支付,loan.pay欠款订单还款,card.prepay本行卡支付预下单,unified.pay客户被扫接口,ali.dynamic.code支付宝扫码支付,union.dynamic.code银联扫码支付,wx.jspay微信公众号支付,ali.jspay支付宝服务窗支付,mergePay.order聚合支付预下单
        model.setOriTransDate(oriTransDate);//原交易日期
        model.setOriTransTime(oriTansTime);//原交易时间
        model.setOriTransAmount(oriTransAmount.toString());//原交易金额
        request.setBizModel(model);
        try {
            response = fopClient.execute(request);
        } catch (FopApiException e) {
            e.printStackTrace();
        }
        return JSONObject.toJSONString(response);
    }
 
 
    /**
     * 聚合支付退款
     * @param oriTransSeq       原商户上送交易流水号
     * @param oriTransDate      原交易日期
     * @param oriTansTime       原交易时间
     * @param oriTransAmount    原交易金额
     * @param refundAmount      退款金额
     * @return
     */
    public static String polymericPayRefund(String oriTransSeq, String oriTransDate, String oriTansTime, Double oriTransAmount, Double refundAmount){
        String uri = "/api/conductor/cashier/polymericPayRefund/1.0.0";
        FopClient fopClient = DefaultFopClient.builder(Config.APP_ID, Config.PRIVATE_KEY, Config.FOP_PUBLIC_KEY)
                .IsBodyEncrypt(true)
                .SererUrl(Config.PRODUCTION_URL + uri)
                .EncryptType(EncryptType.SM4)
                .SignType(SignType.SM2).build();
 
        /**
         * model,request,response类
         * 不同接口的model,request,response均不相同
         * 其中,ConductorCashierXXXX需与apiUrl相互对应。在引入开放平台jar包后,驼峰可使用ide快捷键补全
         * 或查看jar包中com.fop.sdk中的domain包,request包,response包,引入对象皆在此目录中
         * 如,协议支付的model 为 ConductorCashierProtocolpaytransModel_100
         */
        ConductorCashierPolymericpayrefundModel_100 model = new ConductorCashierPolymericpayrefundModel_100();
        ConductorCashierPolymericpayrefundRequest_100 request = new ConductorCashierPolymericpayrefundRequest_100();
        ConductorCashierPolymericpayrefundResponse_100 response = null;
 
        model.setOriTransSeq(oriTransSeq);//原商户上送交易流水号
        model.setOriTransType("mergePay.order");//sign.pay 协议支付,sign.deposit协议代付,sign.wx.jspay协议代付关联微信公众号支付,sign.ali.jspay协议代付关联支付宝服务窗支付,loan.pay欠款订单还款,card.prepay本行卡支付预下单,unified.pay客户被扫接口,ali.dynamic.code支付宝扫码支付,union.dynamic.code银联扫码支付,wx.jspay微信公众号支付,ali.jspay支付宝服务窗支付,mergePay.order聚合支付预下单
        model.setOriTransDate(oriTransDate);//原交易日期
        model.setOriTransTime(oriTansTime);//原交易时间
        model.setOriTransAmount(oriTransAmount.toString());//原交易金额
        model.setRefundAmount(refundAmount.toString());//退款金额
        request.setBizModel(model);
        try {
            response = fopClient.execute(request);
        } catch (FopApiException e) {
            e.printStackTrace();
        }
        return JSONObject.toJSONString(response);
    }
 
 
    /**
     * 协议代付关联支付宝服务窗支付
     * @param chnlSeq       渠道流水号(自定义,唯一)
     * @param signNum       签约协议号
     * @param mchtReserve   商户保留内容,和签约上送一致
     * @param buyerId       支付宝买家用户id
     * @param body          商品描述
     * @param totalFee      支付金额
     * @param notifyUrl     通知回调地址
     */
    public static void relatedZFBOfficialPay(String chnlSeq, String signNum, String mchtReserve, String buyerId, String body, String totalFee, String notifyUrl){
        String uri = "/api/conductor/cashier/relatedZFBOfficialPay/1.0.0";
        FopClient fopClient = DefaultFopClient.builder(Config.APP_ID, Config.PRIVATE_KEY, Config.FOP_PUBLIC_KEY)
                .IsBodyEncrypt(true)
                .SererUrl(Config.PRODUCTION_URL + uri)
                .EncryptType(EncryptType.SM4)
                .SignType(SignType.SM2).build();
 
        /**
         * model,request,response类
         * 不同接口的model,request,response均不相同
         * 其中,ConductorCashierXXXX需与apiUrl相互对应。在引入开放平台jar包后,驼峰可使用ide快捷键补全
         * 或查看jar包中com.fop.sdk中的domain包,request包,response包,引入对象皆在此目录中
         * 如,协议支付的model 为 ConductorCashierProtocolpaytransModel_100
         */
        ConductorCashierRelatedzfbofficialpayModel_100 model = new ConductorCashierRelatedzfbofficialpayModel_100();
        ConductorCashierRelatedzfbofficialpayRequest_100 request = new ConductorCashierRelatedzfbofficialpayRequest_100();
        ConductorCashierRelatedzfbofficialpayResponse_100 response = null;
 
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        SimpleDateFormat sdf1 = new SimpleDateFormat("HHmmss");
 
        model.setChnlSeq(chnlSeq);//渠道流水号
        model.setChnlDate(sdf.format(date));//渠道日期
        model.setChnlTime(sdf1.format(date));//渠道时间
        model.setSignNum(signNum);//签约协议号
        model.setMchtReserve(mchtReserve);//商户保留 即在协议签约时,上送的商户保留字段,普通商户一般为用户标识号,需要确保唯一
        model.setDeviceInfo("");//设备号
        model.setBuyerId(buyerId);//卖价支付宝用户ID
        model.setBody(body);//商品描述
        model.setTotalFee(totalFee);//支付总金额
        try {
            model.setTermIp(InetAddress.getLocalHost().getHostAddress());//终端IP
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        model.setTermMac("");//终端MAC信息
        model.setLocations("");//经纬度信息
        model.setNotifyUrl(notifyUrl);//通知回调地址
        request.setBizModel(model);
        try {
            response = fopClient.execute(request);
        } catch (FopApiException e) {
            e.printStackTrace();
        }
        if("00000000".equals(response.getBizCode())){
            if("00".equals(response.getCode())){
                String tradeMoney = response.getTradeMoney();//实际支付金额
                String totalFee1 = response.getTotalFee();//订单金额
                String tradeNo = response.getTradeNo();//支付宝JS订单号
            }else{
                System.err.println(response.getMsg());
            }
 
            String transDate = response.getTransDate();
            String transTime = response.getTransTime();
            String transSeq1 = response.getTransSeq();
 
        }else{
            System.err.println(response.getBizMsg());
        }
 
    }
 
 
 
 
 
 
    /**
     * 支付宝扫码支付
     * @param chnlSeq
     * @param deviceInfo
     * @param body
     * @param totalFee
     * @param subject
     * @param notifyUrl
     * @return
     */
    public static String zfbScanCodePay(String chnlSeq, String deviceInfo, String body, Double totalFee, String subject, String notifyUrl){
        String uri = "/api/conductor/cashier/zfbScanCodePay/1.0.0";
        FopClient fopClient = DefaultFopClient.builder(Config.APP_ID, Config.PRIVATE_KEY, Config.FOP_PUBLIC_KEY)
                .IsBodyEncrypt(true)
                .SererUrl(Config.PRODUCTION_URL + uri)
                .EncryptType(EncryptType.SM4)
                .SignType(SignType.SM2).build();
 
        /**
         * model,request,response类
         * 不同接口的model,request,response均不相同
         * 其中,ConductorCashierXXXX需与apiUrl相互对应。在引入开放平台jar包后,驼峰可使用ide快捷键补全
         * 或查看jar包中com.fop.sdk中的domain包,request包,response包,引入对象皆在此目录中
         * 如,协议支付的model 为 ConductorCashierProtocolpaytransModel_100
         */
        ConductorCashierZfbscancodepayModel_100 model = new ConductorCashierZfbscancodepayModel_100();
        ConductorCashierZfbscancodepayRequest_100 request = new ConductorCashierZfbscancodepayRequest_100();
        ConductorCashierZfbscancodepayResponse_100 response = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss");
        String format = sdf.format(new Date());
        model.setChnlSeq(chnlSeq);//渠道流水号
        model.setChnlDate(format.split(" ")[0]);//渠道日期
        model.setChnlTime(format.split(" ")[1]);//渠道时间
        model.setDeviceInfo(deviceInfo);//设备号
        model.setBody(body);//商品描述
        model.setFeeType("CNY");//货币类型
        model.setTotalFee(totalFee.toString());//总金额
        model.setSubject(subject);//订单标题
        try {
            model.setTermIp(InetAddress.getLocalHost().getHostAddress());//终端IP
            model.setTermMac("");//终端MAC信息
            model.setLocations("");//经纬度信息
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        model.setNotifyUrl(notifyUrl);//异步通知回调地址
        request.setBizModel(model);
        try {
            response = fopClient.execute(request);
        } catch (FopApiException e) {
            e.printStackTrace();
        }
        if("00000000".equals(response.getBizCode())){
            if("00".equals(response.getResultCode())){//成功
                return response.getCodeUrl();
            }else{
                System.err.println(response.getResultMsg());
                return null;
            }
        }else{
            System.err.println(response.getBizMsg());
            return null;
        }
    }
 
 
 
 
    /**
     * 支付回调处理
     * @param request
     * @return
     */
    public static ResultNotification payResultNotification(HttpServletRequest request){
        String param = null;
        try {
            param = getParam(request);
        } catch (IOException e) {
            e.printStackTrace();
        }
        JSONObject jsonObject1 = JSON.parseObject(param);
        JSONObject jsonObject = FopClient.SM2checkSign(jsonObject1, Config.FOP_PUBLIC_KEY);
        if(!jsonObject.getBoolean("sign")){
            System.err.println("线下收款回调异常---------->" + jsonObject.getString("msg"));
            return null;
        }
        ResultNotification resultNotification = jsonObject1.toJavaObject(ResultNotification.class);
        resultNotification.setResponseStr("success");//响应内容
        return resultNotification;
    }
 
 
 
    /**
     * 获取请求内容
     * @param request
     * @return
     * @throws IOException
     */
    private static String getParam(HttpServletRequest request) throws IOException {
        // 读取参数
        InputStream inputStream;
        StringBuilder sb = new StringBuilder();
        inputStream = request.getInputStream();
        String s;
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        while ((s = in.readLine()) != null) {
            sb.append(s);
        }
        in.close();
        inputStream.close();
        return sb.toString();
    }
 
 
}