Administrator
2024-06-17 d83e4be3fe4e5a3c52d70ab36d64584e966c1800
pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/wechatpay/PaymentCtrl.java
@@ -1,5 +1,6 @@
package com.dy.pipIrrSell.wechatpay;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.dy.common.aop.SsoAop;
import com.dy.common.webUtil.BaseResponse;
@@ -19,6 +20,7 @@
import com.dy.pipIrrSell.wallet.enums.RefundStatusENUM;
import com.dy.pipIrrSell.wechatpay.dto.Code2Session;
import com.dy.pipIrrSell.wechatpay.dto.DtoOrder;
import com.dy.pipIrrSell.wechatpay.dto.NotifyResource;
import com.dy.pipIrrSell.wechatpay.dto.OrderNotify;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
@@ -26,6 +28,7 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
@@ -37,6 +40,7 @@
import org.springframework.web.bind.annotation.*;
import javax.crypto.NoSuchPaddingException;
import java.io.BufferedReader;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
@@ -70,6 +74,7 @@
    private final String privateCertFileName = PayInfo.privateCertFileName;
    private final String appid = PayInfo.appid;
    private final String secret = PayInfo.secret;
    private final String mchid = PayInfo.mchid;
    private final String schema = PayInfo.schema;
    private final String signType = PayInfo.signType;
@@ -82,7 +87,7 @@
    private final Map CERTIFICATE_MAP = new HashMap();
    /**
     * 登录凭证校验
     * 登录凭证校验,农户绑定账号逻辑包含登录凭证校验,此接口作废
     * @param code2Session 登录凭证校验传入对象
     * @param bindingResult
     * @return
@@ -105,10 +110,13 @@
            return BaseResponseUtils.buildFail(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
        }
        String phoneNumber = code2Session.getPhoneNumber();
        String jsCode = code2Session.getJs_code();
        Map<String, Object> queryParams = new HashMap<>();
        queryParams.put("appid", appid);
        queryParams.put("secret", code2Session.getSecret());
        queryParams.put("js_code", code2Session.getJs_code());
        queryParams.put("secret", secret);
        queryParams.put("js_code", jsCode);
        queryParams.put("grant_type", grantType);
        Map<String, String> headerParams = new HashMap<>();
        JSONObject job = restTemplateUtil.get(loginUrl, queryParams, headerParams);
@@ -120,19 +128,24 @@
        String openid = job.getString("openid");
        String sessionKey = job.getString("session_key");
        // 添加登录态记录
        SeWebchatLogonState po = new SeWebchatLogonState();
        po.setOpenId(openid);
        po.setSessionKey(sessionKey);
        Date createTime = new Date();
        po.setCreateTime(createTime);
        Long id = paymentSv.insert(po);
        if(id == null || id <= 0) {
            return BaseResponseUtils.buildFail("登录态记录添加失败");
        }
        String SessionId = String.valueOf(id);
        Long clientId = clientSv.getClientIdByPhone(phoneNumber);
        String SessionId = "";
        if(clientId != null) {
            // 添加微信用户账户记录
            SeOpenId seOpenId = new SeOpenId();
            seOpenId.setClientId(clientId);
            seOpenId.setOpenId(openid);
            seOpenId.setSessionKey(sessionKey);
            seOpenId.setCreateTime(new Date());
            Long rec = clientSv.addOpenId(seOpenId);
            if(rec != null) {
                SessionId = String.valueOf(rec);
            }
            return BaseResponseUtils.buildSuccess(SessionId);
        return BaseResponseUtils.buildSuccess(SessionId) ;
        } else {
            return BaseResponseUtils.buildError(SellResultCode.PHONE_NUMBER_IS_ERROR.getMessage());
        }
    }
    /**
@@ -185,7 +198,7 @@
     * JSAPI下单
     * @param order 下单请求对象,包含需要传入的参数
     * @param bindingResult
     * @return
     * @return 预支付交易会话标识(有效期2小时)
     */
    @Operation(summary = "JSAPI下单", description = "JSAPI下单")
    @ApiResponses(value = {
@@ -203,14 +216,12 @@
        if(bindingResult != null && bindingResult.hasErrors()){
            return BaseResponseUtils.buildFail(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
        }
        // 接收参数:登录态ID、农户ID、虚拟卡ID、充值金额
        // 接收参数:登录态ID、虚拟卡ID、充值金额(分)
        Long sessionId = order.getSessionId();
        Long virtualId = order.getVirtualId();
        Long virtualId = order.getVcId();
        Integer rechargeAmount = order.getRechargeAmount();
        String prepayId = "";
        //SeWebchatLogonState po = paymentSv.selectOne(Long.parseLong(sessionId));
        //String openid = po.getOpenId();
        SeOpenId po = paymentSv.selectOne(sessionId);
        String openid = po.getOpenId();
@@ -245,7 +256,7 @@
        //订单金额
        JSONObject job_amount = new JSONObject();
        job_amount.put("total", 1);
        job_amount.put("total", rechargeAmount);
        job_amount.put("currency", "CNY");
        job_body.put("amount", job_amount);
@@ -271,18 +282,55 @@
        // 暂时注释掉,认证通过后再放开
        JSONObject job_result = restTemplateUtil.post(PayInfo.orderUrl, body, headers);
        if(job_result != null) {
            System.out.println(job_result.toString());
            prepayId = job_result.getString("prepay_id");
        if(job_result == null) {
            return BaseResponseUtils.buildFail(SellResultCode.RECHARGE_ADD_FAIL.getMessage());
        }
        return BaseResponseUtils.buildSuccess(prepayId) ;
        return BaseResponseUtils.buildSuccess(job_result) ;
    }
    /**
     * 再次签名
     * @param prepayId 预支付交易会话标识
     * @return 小程序调起支付参数
     * @throws Exception
     */
    @Operation(summary = "再次签名", description = "再次签名")
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE,
                    description = "操作结果:true:成功,false:失败(BaseResponse.content)",
                    content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                            schema = @Schema(implementation = Boolean.class))}
            )
    })
    @GetMapping(path = "/signAgain")
    @Transactional(rollbackFor = Exception.class)
    @SsoAop()
    public BaseResponse<JSONObject> signAgain(@RequestParam("prepayId") String prepayId) throws Exception {
        // 获取随机串和时间戳,放在此处以保证
        String appid = PayInfo.appid;
        String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonceStr = payHelper.generateRandomString();
        String pkg = "prepay_id=" + prepayId;
        String message = payHelper.buildMessage_signAgain(appid, timeStamp, nonceStr, pkg);
        String paySign = payHelper.sign(message.getBytes("utf-8"), privateCertFileName);
        JSONObject job_result = new JSONObject();
        job_result.put("timeStamp", timeStamp);
        job_result.put("nonceStr", nonceStr);
        job_result.put("package", pkg);
        job_result.put("signType", signType);
        job_result.put("paySign", paySign);
        return BaseResponseUtils.buildSuccess(job_result) ;
    }
    /**
     * 支付通知/退款结果通知
     * @param headers
     * @param orderNotify
     * @param request
     * @param response
     * @return
     * @throws IOException
@@ -300,12 +348,12 @@
    @PostMapping(path = "orderNotify", consumes = MediaType.APPLICATION_JSON_VALUE)
    @Transactional(rollbackFor = Exception.class)
    @SsoAop()
    public JSONObject orderNotify(@RequestHeader HttpHeaders headers, @RequestBody OrderNotify orderNotify, HttpServletResponse response) throws IOException, GeneralSecurityException {
    public JSONObject orderNotify(@RequestHeader HttpHeaders headers, HttpServletRequest request, HttpServletResponse response) throws IOException, GeneralSecurityException {
        JSONObject result = new JSONObject();
        /**
         * 1.验签处理
         *      从header中取出4个子参数,同时取出body
         *      从header中取出4个子参数
         *      验时间差,超过5分钟的不处理
         *      验证签名
         *      验证书序列号,必须与某一个证书的序列号一致
@@ -314,7 +362,18 @@
        String wechatpaySerial = String.valueOf(headers.get("Wechatpay-Serial").get(0));
        String wechatpaySignature = String.valueOf(headers.get("Wechatpay-Signature").get(0));
        String wechatpayTimestamp = String.valueOf(headers.get("Wechatpay-Timestamp").get(0));
        String bodyStr = JSONObject.toJSONString(orderNotify);
        // 获取body内容
        BufferedReader reader = request.getReader();
        StringBuilder stringBuilder = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
        }
        String bodyStr = stringBuilder.toString();
        // body转对象
        OrderNotify orderNotify = JSON.parseObject(bodyStr, OrderNotify.class);
        // 验时间戳,时间差大于5分钟的拒绝
        Long timeDiff = (System.currentTimeMillis() / 1000 - Long.parseLong(wechatpayTimestamp))/60;
@@ -350,10 +409,7 @@
            return result;
        }
        /**
         * 解密处理
         *      1
         */
        // 解密处理
        String eventType = orderNotify.getEvent_type();
        if(eventType != null && eventType.equals("TRANSACTION.SUCCESS")) {
@@ -363,7 +419,7 @@
             * 取出通知数据对象,继而取出解密所需的associatedData和nonce,以及密文ciphertext
             * 解密ciphertext得到
             */
            OrderNotify.NotifyResource notifyResource = orderNotify.getResource();
            NotifyResource notifyResource = orderNotify.getResource();
            String associatedData = notifyResource.getAssociated_data();
            String nonce = notifyResource.getNonce();
            String ciphertext = notifyResource.getCiphertext();
@@ -371,19 +427,22 @@
            String resource = AesUtil.decryptToString(PayInfo.key.getBytes("utf-8"), associatedData.getBytes("utf-8"), nonce.getBytes("utf-8"), ciphertext);
            JSONObject job_resource = JSONObject.parseObject(resource);
            // 解密后取出:商户订单员、微信支付订单号、交易状态、支付完成时间
            // 解密后取出:商户订单号、微信支付订单号、交易状态、支付完成时间
            String out_trade_no = job_resource.getString("out_trade_no");
            String transaction_id = job_resource.getString("transaction_id");
            String trade_state = job_resource.getString("trade_state");
            Date success_time = job_resource.getDate("success_time");
            // 更新虚拟卡表及充值表响应字段
            BaseResponse result_ = virtualCardSv.updateVCRecharge(out_trade_no, success_time);
            if(!result_.getCode().equals("0001")) {
                response.setStatus(500);
                result.put("code", "FAIL");
                result.put("message", "失败");
                return result;
            // 如果当前订单状态为未支付状态,则更新虚拟卡表及充值表响应字段
            SeVcRecharge seVcRecharge = virtualCardSv.getVCRechargeByorderNumber(out_trade_no);
            if(seVcRecharge != null && seVcRecharge.getOrderState() == 1) {
                BaseResponse result_ = virtualCardSv.updateVCRecharge(out_trade_no, success_time);
                if(!result_.getCode().equals("0001")) {
                    response.setStatus(500);
                    result.put("code", "FAIL");
                    result.put("message", "失败");
                    return result;
                }
            }
        } else if(eventType != null && eventType.equals("REFUND.SUCCESS")) {
            // 退款成功后回调
@@ -392,7 +451,7 @@
             * 取出通知数据对象,继而取出解密所需的associatedData和nonce,以及密文ciphertext
             * 解密ciphertext得到
             */
            OrderNotify.NotifyResource notifyResource = orderNotify.getResource();
            NotifyResource notifyResource = orderNotify.getResource();
            String associatedData = notifyResource.getAssociated_data();
            String nonce = notifyResource.getNonce();
            String ciphertext = notifyResource.getCiphertext();
@@ -456,43 +515,5 @@
        result.put("code", "SUCCESS");
        result.put("message", "成功");
        return  result;
    }
    /**
     * 再次签名
     * @param prepayId 预支付交易会话标识
     * @return 小程序调起支付参数
     * @throws Exception
     */
    @Operation(summary = "再次签名", description = "再次签名")
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE,
                    description = "操作结果:true:成功,false:失败(BaseResponse.content)",
                    content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                            schema = @Schema(implementation = Boolean.class))}
            )
    })
    @GetMapping(path = "/signAgain")
    @Transactional(rollbackFor = Exception.class)
    @SsoAop()
    public BaseResponse<JSONObject> signAgain(@RequestParam("prepayId")  String prepayId) throws Exception {
        // 获取随机串和时间戳,放在此处以保证
        String appid = PayInfo.appid;
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonceStr = payHelper.generateRandomString();
        String pkg = "prepay_id=" + prepayId;
        String message = payHelper.buildMessage_signAgain(appid, timestamp, nonceStr, pkg);
        String paySign = payHelper.sign(message.getBytes("utf-8"), privateCertFileName);
        JSONObject job_result = new JSONObject();
        job_result.put("timestamp", timestamp);
        job_result.put("nonceStr", nonceStr);
        job_result.put("package", pkg);
        job_result.put("signType", signType);
        job_result.put("paySign", paySign);
        return BaseResponseUtils.buildSuccess(job_result) ;
    }
}