1
sunshine
2024-11-05 92a9e53e82c74d36a72eb92f93777bbb16e2db73
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
package com.nova.sankuai.service.impl;
 
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nova.sankuai.domain.api.shantai.ShanTaiCheckVo;
import com.nova.sankuai.domain.api.yinsheng.enums.SignStatusEnum;
import com.nova.sankuai.domain.entity.Customer;
import com.nova.sankuai.domain.entity.ShanTaiSignRecord;
import com.nova.sankuai.domain.vo.huifubao.HuifubaoSignRecordVO;
import com.nova.sankuai.domain.entity.CustomerUser;
import com.nova.sankuai.domain.entity.HuifubaoSignRecord;
import com.nova.sankuai.domain.vo.huifubao.SignCallBackVo;
import com.nova.sankuai.infra.config.CommonException;
import com.nova.sankuai.infra.constants.ResultCode;
import com.nova.sankuai.infra.mapper.CustomerMapper;
import com.nova.sankuai.infra.utils.ResultJson;
import com.nova.sankuai.infra.utils.UserUtil;
import com.nova.sankuai.infra.utils.huifubao.common.*;
import com.nova.sankuai.infra.utils.huifubao.request.BaseRequest;
import com.nova.sankuai.infra.utils.huifubao.request.SignRequest;
import com.nova.sankuai.infra.utils.huifubao.respone.BaseResponse;
import com.nova.sankuai.infra.utils.huifubao.respone.SignResponse;
import com.nova.sankuai.security.UserDetail;
import com.nova.sankuai.service.ICustomerUserService;
import com.nova.sankuai.service.IHuifubaoSignRecordService;
import com.nova.sankuai.service.IHuiFuBaoSignService;
import lombok.SneakyThrows;
import org.bouncycastle.util.encoders.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.*;
 
import static com.nova.sankuai.infra.constants.ResultCode.BAD_REQUEST;
 
 
@Service
public class HuiFuBaoSignServiceImpl implements IHuiFuBaoSignService {
 
    private static final Logger logger = LoggerFactory.getLogger("huibaofu-sign");
 
    private static final String SERVER_URL = "https://pay.Heepay.com/API/PageSign/Index.aspx";
 
    private static final String METHOD = "heepay.agreement.bank.sign.page";
 
    @Value("${huifubao.merchId}")
    private String merchId;
 
    @Value("${huifubao.domainUrl}")
    private String domainUrl;
 
    @Value("${huifubao.returnSignUrl}")
    private String returnSignUrl;
 
    @Resource
    private ICustomerUserService iCustomerUserService;
 
    @Resource
    private IHuifubaoSignRecordService iHuiFuBaoSignRecordService;
 
    @Resource
    private CustomerMapper customerMapper;
 
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultJson signInfo(HuifubaoSignRecordVO vo, UserDetail userDetail) {
        if (userDetail == null){
            userDetail = new UserDetail();
        }
        LambdaQueryWrapper<CustomerUser> customerUserWrapper = new LambdaQueryWrapper<>();
        customerUserWrapper.eq(CustomerUser::getPhone, userDetail.getPhone()).eq(CustomerUser::getDeleteFlag, 0);
        List<CustomerUser> customerUserList = iCustomerUserService.list(customerUserWrapper);
 
        if (CollUtil.isEmpty(customerUserList)) {
            logger.error("手机查询用户不存在,手机号:{}", userDetail.getPhone());
//            throw new CommonException("用户不存在");
            return ResultJson.failure(BAD_REQUEST,"");
        }
        CustomerUser customerUser = customerUserList.stream().min(Comparator.comparing(CustomerUser::getCreationDate)).orElse(new CustomerUser());
        LambdaQueryWrapper<HuifubaoSignRecord> huiFuBaoSignRecordWrapper = Wrappers.lambdaQuery();
        huiFuBaoSignRecordWrapper.eq(HuifubaoSignRecord::getCustomerUserId,customerUser.getId());
        huiFuBaoSignRecordWrapper.eq(HuifubaoSignRecord::getSignResult,SignStatusEnum.SUCCESS.getValue());
        List<HuifubaoSignRecord> huifubaoSignRecordList = iHuiFuBaoSignRecordService.list(huiFuBaoSignRecordWrapper);
        if (CollUtil.isNotEmpty(huifubaoSignRecordList)){
            HuifubaoSignRecord huifubaoSignRecord = huifubaoSignRecordList.stream().distinct().findFirst().orElse(new HuifubaoSignRecord());
            logger.error("该用户已录入 录入用户id:{},录入信息为:{}",customerUser.getId(),JSON.toJSONString(huifubaoSignRecord));
            throw new CommonException("该用户已录入");
        }
 
        if (StrUtil.isEmpty(vo.getSignIdNo()) || StrUtil.isEmpty(vo.getSignName())
                || StrUtil.isEmpty(vo.getSignPhone()) || StrUtil.isEmpty(vo.getSignCardNumber())){
            logger.error("录入参数不完整,请完善信息。vo:{}",JSON.toJSONString(vo));
            return ResultJson.failure(BAD_REQUEST,"录入参数不完整,请完善信息。");
        }
 
        SignRequest signRequest = new SignRequest();
        /**
         * 业务参数
         */
        BaseRequest baseRequest = new BaseRequest();
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/*        子商户号,大商户子商户模式必传
        signRequest.setSub_merch_id("");*/
 
        signRequest.setNotify_url(domainUrl + "/api/v2/hfb/sign/callback");
        signRequest.setReturn_url(returnSignUrl);
        long tenDigitTimestamp = System.currentTimeMillis() / 1000;
        //商户签约单号,自定义
        String outTradeNo = String.valueOf(tenDigitTimestamp);
        signRequest.setOut_trade_no(outTradeNo);
        Date date = new Date();
        signRequest.setOut_trade_time(sd.format(date));
        //商户平台用户标识,自定义保证唯一
        signRequest.setMerch_user_id(String.valueOf(customerUser.getId()));
        //持卡人银行卡号,若传值页面自动代入
        signRequest.setBank_card_no(vo.getSignCardNumber());
        //持卡人姓名,若传值页面自动代入
        signRequest.setBank_user_name(vo.getSignName());
        //持卡人预留银行手机号,若传值页面自动代入
        signRequest.setMobile(vo.getSignPhone());
        //持卡人证据号码
        signRequest.setCert_no(vo.getSignIdNo());
 
        /**
         ** 公共请求参数
         */
        CertRequest certRequest = new CertRequest();
        //请求URL
        certRequest.setServerUrl(SERVER_URL);
        //商户编号,(汇付宝商户内码:七位整数数字)
        certRequest.setMerchantId(merchId);
//        certRequest.setMerchantId(signRequest.getSub_merch_id());
        //版本号:固定值 1.0
        certRequest.setVersion("1.0");
        //具体业务接口名称
        certRequest.setMethod(METHOD);
        baseRequest.setBiz_content(JSON.toJSONString(signRequest));
        //商户私钥
        certRequest.setPrivateKeyStr(MyKey.privateKeystr);
        //汇付宝公钥
        certRequest.setPublicKeyStr(MyKey.publicKeystr);
        baseRequest.setBiz_content(JSON.toJSONString(signRequest));
        //请求汇付宝演
        SignResponse response = doSignPost(baseRequest,certRequest);
        if (!Objects.equals(response.getCode(), "10000")) {
            String msg = response.getMsg();
            if (StrUtil.isEmpty(msg)){
                msg = SignStatusEnum.FAILED.getValue();
            }
            return ResultJson.failure(ResultCode.OPERATE_ERROR, msg);
        }
        //录入
        HuifubaoSignRecord huifubaoSignRecord = new HuifubaoSignRecord();
        BeanUtils.copyProperties(vo, huifubaoSignRecord);
        huifubaoSignRecord.setSignOrderNo(outTradeNo);
        huifubaoSignRecord.setCustomerUserId(customerUser.getId());
        huifubaoSignRecord.setSignResult(SignStatusEnum.WAIT_CONFIRM.getValue());
        huifubaoSignRecord.setCreationDate(date);
        huifubaoSignRecord.setLastUpdatedDate(date);
        iHuiFuBaoSignRecordService.saveOrUpdate(huifubaoSignRecord);
        return ResultJson.ok(response);
    }
 
    @SneakyThrows
    @Override
    public ResponseEntity CallBack(SignCallBackVo vo) {
        String outTradeNo = vo.getOut_trade_no();
        String sign = vo.getSign();
        String signNo = vo.getSign_no();
        if (StrUtil.isEmpty(outTradeNo)){
            logger.error("商户签约单号不能为空");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("商户签约单号不能为空");
        }
 
        if (StrUtil.isEmpty(sign)){
            logger.error("RSA签名结果不能为空");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("RSA签名结果不能为空");
        }
 
        if (StrUtil.isEmpty(signNo)){
            logger.error("支付授权码不能为空");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("支付授权码不能为空");
        }
        //查询是否存在签约单
        LambdaQueryWrapper<HuifubaoSignRecord> huifubaoSignRecordLambdaQueryWrapper = Wrappers.lambdaQuery();
        huifubaoSignRecordLambdaQueryWrapper.eq(HuifubaoSignRecord::getSignOrderNo,outTradeNo);
        HuifubaoSignRecord huifubaoSignRecord = iHuiFuBaoSignRecordService.getOne(huifubaoSignRecordLambdaQueryWrapper);
        if (huifubaoSignRecord == null){
            logger.error("系统中不存在当前商户签约单,单号:{}",outTradeNo);
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("系统中不存在当前商户签约单号:" + outTradeNo);
        }
 
        //decrypt为解密后的值
        String decrypt = getKeyPath(signNo,0,false);
        huifubaoSignRecord.setSignUniqueCode(decrypt);
        huifubaoSignRecord.setLastUpdatedDate(new Date());
        huifubaoSignRecord.setSignResult("签约成功");
        iHuiFuBaoSignRecordService.saveOrUpdate(huifubaoSignRecord);
        return ResponseEntity.ok("ok");
    }
 
    @Override
    public ResultJson querySignStatus(HuifubaoSignRecordVO vo, HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        UserDetail user = UserUtil.getUser(token);
        if (Objects.isNull(user) || Objects.isNull(user.getId())) {
            logger.error("Token无效 当前token:{}",token);
            return ResultJson.failure(ResultCode.UNAUTHORIZED,"Token无效");
        }
 
        LambdaQueryWrapper<CustomerUser> customerUserWrapper = new LambdaQueryWrapper<>();
        customerUserWrapper.eq(CustomerUser::getPhone, user.getPhone()).eq(CustomerUser::getDeleteFlag, 0);
        List<CustomerUser> customerUserList = iCustomerUserService.list(customerUserWrapper);
 
        if (CollUtil.isEmpty(customerUserList)) {
            logger.error("手机查询用户不存在,手机号:{}", user.getPhone());
//            throw new CommonException("用户不存在");
            return ResultJson.failure(BAD_REQUEST,"");
        }
        CustomerUser customerUser = customerUserList.stream().min(Comparator.comparing(CustomerUser::getCreationDate)).orElse(new CustomerUser());
        //判断是否录入系统
        LambdaQueryWrapper<HuifubaoSignRecord> recordLambdaQueryWrapper = Wrappers.lambdaQuery();
        recordLambdaQueryWrapper.eq(HuifubaoSignRecord::getCustomerUserId,customerUser.getId());
        List<HuifubaoSignRecord> huifubaoSignRecordList = iHuiFuBaoSignRecordService.list(recordLambdaQueryWrapper);
 
        if (CollUtil.isEmpty(huifubaoSignRecordList)){
            logger.error("当前用户不存在 当前id:{}",user.getId());
            return ResultJson.failure(ResultCode.OPERATE_ERROR,"当前用户不存在");
        }
        HuifubaoSignRecord huifubaoSignRecord = huifubaoSignRecordList.stream().min(Comparator.comparing(HuifubaoSignRecord::getCreationDate)).orElse(new HuifubaoSignRecord());
        if (!Objects.equals(huifubaoSignRecord.getSignResult(), SignStatusEnum.SUCCESS.getValue())){
                //枚举值不存在 会导致报错 抛出捕获预防参数不一致
            logger.error("当前订单未成功签约,签约状态为:" + huifubaoSignRecord.getSignResult());
            return ResultJson.failure(ResultCode.OPERATE_ERROR,"当前订单未成功签约,签约状态为:" + huifubaoSignRecord.getSignResult());
        }
        return ResultJson.ok(huifubaoSignRecord);
    }
 
    @Override
    public boolean checkBeforePayment(Long id) {
        CustomerUser customerUser = iCustomerUserService.getById(id);
         //判断是否录入系统
        LambdaQueryWrapper<HuifubaoSignRecord> recordLambdaQueryWrapper = Wrappers.lambdaQuery();
        recordLambdaQueryWrapper.eq(HuifubaoSignRecord::getCustomerUserId,customerUser.getId());
        List<HuifubaoSignRecord> huifubaoSignRecordList = iHuiFuBaoSignRecordService.list(recordLambdaQueryWrapper);
 
        if (CollUtil.isEmpty(huifubaoSignRecordList)){
            logger.error("当前用户不存在 当前id:{}",customerUser.getId());
            return false;
        }
        HuifubaoSignRecord huifubaoSignRecord = huifubaoSignRecordList.stream().min(Comparator.comparing(HuifubaoSignRecord::getCreationDate)).orElse(new HuifubaoSignRecord());
        if (!Objects.equals(huifubaoSignRecord.getSignResult(), SignStatusEnum.SUCCESS.getValue())){
            //枚举值不存在 会导致报错 抛出捕获预防参数不一致
            logger.error("当前订单未成功签约,签约状态为:" + huifubaoSignRecord.getSignResult());
            return false;
        }
        return true;
    }
 
    @Override
    public ShanTaiCheckVo checkProtocolSignBySt(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        UserDetail user = UserUtil.getUser(token);
        if (user == null || user.getId() == null) {
            throw new CommonException("Token无效");
        }
        CustomerUser customerUser = iCustomerUserService.getById(user.getId());
        if (customerUser == null) {
            throw new CommonException("用户不存在");
        }
        ShanTaiCheckVo checkVo = new ShanTaiCheckVo();
        HuifubaoSignRecord signRecord = null;
        List<HuifubaoSignRecord> signRecords = iHuiFuBaoSignRecordService.list(Wrappers.lambdaQuery(HuifubaoSignRecord.class).
                eq(HuifubaoSignRecord::getCustomerUserId, customerUser.getId()).orderByDesc(HuifubaoSignRecord::getCreationDate));
        if (!signRecords.isEmpty()) {
            signRecord = signRecords.get(0);
        }
        if (signRecord != null && SignStatusEnum.SUCCESS.getValue().equals(signRecord.getSignResult())) {
            checkVo.setSign(true);
            checkVo.setSignCardNumber(signRecord.getSignCardNumber());
            checkVo.setSignIdNo(signRecord.getSignIdNo());
            checkVo.setSignName(signRecord.getSignName());
            checkVo.setSignPhone(signRecord.getSignPhone());
        } else {
            checkVo.setSign(false);
        }
        return checkVo;
    }
 
 
    @SneakyThrows
    private String getKeyPath(String value,Integer type,boolean isSign){
        String str = "";
        SignEncrypt signEncrypt = new SignEncrypt();
        // 使用类名和常量名来访问常量
        String publicKeystr = MyKey.publicKeystr;
        String privateKeystr = MyKey.privateKeystr;
        //密钥配置
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] publicKeyPath = Base64.decode(publicKeystr.getBytes());
        byte[] privateKeyPath = Base64.decode(privateKeystr.getBytes());
        PublicKey heepayPublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyPath));
        PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyPath));
        //是否是签约加密
        if (isSign){
            str = signEncrypt.sign(value,privateKey);
        }else if (type == 1){
            //RSA加密
            str = signEncrypt.encrypt(value, heepayPublicKey);
        }else {
            //RSA解密
            str = signEncrypt.decrypt(value, privateKey);
        }
        return str;
    }
 
    private SignResponse doSignPost(BaseRequest baseRequest,CertRequest certRequest){
        SignEncrypt signEncrypt = new SignEncrypt();
        HttpUtil httpUtil = new HttpUtil();
        // 使用类名和常量名来访问常量
        String publicKeystr = MyKey.publicKeystr;
        String privateKeystr = MyKey.privateKeystr;
        PublicKey heepayPublicKey = null;
        PrivateKey privateKey = null;
        SignResponse signResponse = new SignResponse();
        try {
            baseRequest.setMerch_id(certRequest.getMerchantId());
            baseRequest.setVersion(certRequest.getVersion());
            baseRequest.setMethod(certRequest.getMethod());
            //密钥配置
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] publicKeyPath = Base64.decode(publicKeystr.getBytes());
            byte[] privateKeyPath = Base64.decode(privateKeystr.getBytes());
            heepayPublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyPath));
            privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyPath));
 
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            baseRequest.setTimestamp(df.format(new Date()));
            Map<String, String> map = Utils.convertBeanNoneEmpty(baseRequest);
            String bizJson = Utils.coverMap2String(map);
            logger.info("待签名:{}",bizJson);
            //签名
            String sign = signEncrypt.sign(bizJson, privateKey);
            logger.info("签名后:{}",sign);
            baseRequest.setSign(sign);
 
 
            //bizContent加密
            String content = signEncrypt.encrypt(baseRequest.getBiz_content(), heepayPublicKey);
            logger.info("加密后:{}",content);
            baseRequest.setBiz_content(content);
 
            String res = httpUtil.sendJsonHttpPost(SERVER_URL, JSON.toJSONString(baseRequest));
            logger.info("resq:{}",JSON.toJSONString(baseRequest));
            logger.info("resp:{}",res);
 
            //解析response 取到data并解密
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode jsonNode = objectMapper.readTree(res.toString());
            String data = jsonNode.get("data").asText();
            //decrypt为解密后的值
            String decrypt = signEncrypt.decrypt(data, privateKey);
            //继续解析解密后的值拿到sign_url
            JsonNode jsonNode1 = objectMapper.readTree(decrypt.toString());
            String sign_url = jsonNode1.get("sign_url").asText();
            logger.info("sign_url:{}",sign_url);
 
            if (StrUtil.isEmpty(res)) {
                return new SignResponse();
            }
            BaseResponse response = JSONObject.parseObject(res, BaseResponse.class);
            signResponse = JSON.parseObject(decrypt, SignResponse.class);
            signResponse.setCode(response.getCode());
            signResponse.setMsg(response.getMsg());
            signResponse.setSub_code(response.getSub_code());
            signResponse.setSub_msg(response.getSub_msg());
            signResponse.setData(response.getData());
            signResponse.setSign(response.getSign());
        }catch (Exception e){
            e.printStackTrace();
            logger.error("签约状态异常,请求参数:{}",baseRequest);
            throw new RuntimeException("签约异常");
        }
        return signResponse;
    }
}