package com.dy.pipIrrWechat.wechatpay; 
 | 
  
 | 
import com.alibaba.fastjson2.JSON; 
 | 
import com.alibaba.fastjson2.JSONObject; 
 | 
import com.dy.common.webUtil.BaseResponse; 
 | 
import com.dy.common.webUtil.BaseResponseUtils; 
 | 
import com.dy.common.webUtil.ResultCodeMsg; 
 | 
import com.dy.pipIrrGlobal.pojoSe.*; 
 | 
import com.dy.pipIrrGlobal.voSe.VoClient; 
 | 
import com.dy.pipIrrWechat.result.WechatResultCode; 
 | 
import com.dy.pipIrrWechat.util.AesUtil; 
 | 
import com.dy.pipIrrWechat.util.PayHelper; 
 | 
import com.dy.pipIrrWechat.util.RestTemplateUtil; 
 | 
import com.dy.pipIrrWechat.virtualCard.VirtualCardSv; 
 | 
import com.dy.pipIrrWechat.virtualCard.dto.DtoVirtualCard; 
 | 
import com.dy.pipIrrWechat.virtualCard.enums.LastOperateENUM; 
 | 
import com.dy.pipIrrWechat.virtualCard.enums.RefundItemStateENUM; 
 | 
import com.dy.pipIrrWechat.wechatpay.dto.Code2Session; 
 | 
import com.dy.pipIrrWechat.wechatpay.dto.DtoOrder; 
 | 
import com.dy.pipIrrWechat.wechatpay.dto.NotifyResource; 
 | 
import com.dy.pipIrrWechat.wechatpay.dto.OrderNotify; 
 | 
import com.dy.pipIrrWechat.wechatpay.enums.RefundStatusENUM; 
 | 
import io.swagger.v3.oas.annotations.Operation; 
 | 
import io.swagger.v3.oas.annotations.media.Content; 
 | 
import io.swagger.v3.oas.annotations.media.Schema; 
 | 
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; 
 | 
import lombok.extern.slf4j.Slf4j; 
 | 
import org.springframework.http.HttpHeaders; 
 | 
import org.springframework.http.MediaType; 
 | 
import org.springframework.transaction.annotation.Transactional; 
 | 
import org.springframework.validation.BindingResult; 
 | 
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; 
 | 
import java.security.NoSuchAlgorithmException; 
 | 
import java.security.SignatureException; 
 | 
import java.security.spec.InvalidKeySpecException; 
 | 
import java.text.SimpleDateFormat; 
 | 
import java.util.Date; 
 | 
import java.util.HashMap; 
 | 
import java.util.Map; 
 | 
import java.util.Objects; 
 | 
  
 | 
/** 
 | 
 * @author ZhuBaoMin 
 | 
 * @date 2024-07-16 15:05 
 | 
 * @LastEditTime 2024-07-16 15:05 
 | 
 * @Description 
 | 
 */ 
 | 
  
 | 
@Slf4j 
 | 
@Tag(name = "微信支付管理", description = "微信支付各种操作") 
 | 
@RestController 
 | 
@RequestMapping(path="payment") 
 | 
@RequiredArgsConstructor 
 | 
public class PaymentCtrl { 
 | 
    private final PaymentSv paymentSv; 
 | 
    private final RestTemplateUtil restTemplateUtil; 
 | 
    private final PayHelper payHelper; 
 | 
    private final VirtualCardSv virtualCardSv; 
 | 
    private final String privateCertFileName = com.dy.pipIrrWechat.wechatpay.PayInfo.privateCertFileName; 
 | 
    private final String appid = com.dy.pipIrrWechat.wechatpay.PayInfo.appid; 
 | 
    private final String secret = com.dy.pipIrrWechat.wechatpay.PayInfo.secret; 
 | 
    private final String mchid = com.dy.pipIrrWechat.wechatpay.PayInfo.mchid; 
 | 
    private final String schema = com.dy.pipIrrWechat.wechatpay.PayInfo.schema; 
 | 
    private final String signType = com.dy.pipIrrWechat.wechatpay.PayInfo.signType; 
 | 
    private final String description = com.dy.pipIrrWechat.wechatpay.PayInfo.description; 
 | 
    private final String loginUrl = com.dy.pipIrrWechat.wechatpay.PayInfo.loginUrl; 
 | 
    private final String notifyUrl = com.dy.pipIrrWechat.wechatpay.PayInfo.notifyUrl; 
 | 
    private final String grantType = com.dy.pipIrrWechat.wechatpay.PayInfo.grantType; 
 | 
  
 | 
    // 平台证书公钥 
 | 
    private final Map CERTIFICATE_MAP = new HashMap(); 
 | 
  
 | 
    /** 
 | 
     * 登录凭证校验,农户绑定账号逻辑包含登录凭证校验,此接口作废 
 | 
     * @param code2Session 登录凭证校验传入对象 
 | 
     * @param bindingResult 
 | 
     * @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))} 
 | 
            ) 
 | 
    }) 
 | 
    @PostMapping(path = "getSessionId") 
 | 
    @Transactional(rollbackFor = Exception.class) 
 | 
    public BaseResponse<Boolean> getSessionId(@RequestBody @Valid Code2Session code2Session, BindingResult bindingResult) throws Exception { 
 | 
        if(bindingResult != null && bindingResult.hasErrors()){ 
 | 
            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", secret); 
 | 
        queryParams.put("js_code", jsCode); 
 | 
        queryParams.put("grant_type", grantType); 
 | 
        Map<String, String> headerParams = new HashMap<>(); 
 | 
        JSONObject job = restTemplateUtil.get(loginUrl, queryParams, headerParams); 
 | 
  
 | 
        if(job.getLong("errcode") != null && job.getLong("errcode") >= -1) { 
 | 
            return BaseResponseUtils.buildFail("登录凭证校验失败"); 
 | 
        } 
 | 
  
 | 
        String openid = job.getString("openid"); 
 | 
        String sessionKey = job.getString("session_key"); 
 | 
  
 | 
        Long clientId = paymentSv.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 = paymentSv.addOpenId(seOpenId); 
 | 
            if(rec != null) { 
 | 
                SessionId = String.valueOf(rec); 
 | 
            } 
 | 
            return BaseResponseUtils.buildSuccess(SessionId); 
 | 
  
 | 
        } else { 
 | 
            return BaseResponseUtils.buildError(WechatResultCode.PHONE_NUMBER_IS_ERROR.getMessage()); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 下载微信支付平台证书 测试完废除 
 | 
     * @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 = "certificates") 
 | 
    @Transactional(rollbackFor = Exception.class) 
 | 
    public BaseResponse<Boolean> certificates() throws Exception { 
 | 
        String method = "GET"; 
 | 
        String httpUrl = "/v3/certificates"; 
 | 
        String nonceStr = payHelper.generateRandomString(); 
 | 
        Long timestamp = System.currentTimeMillis() / 1000; 
 | 
  
 | 
        String header = schema + " " + payHelper.getToken(method, httpUrl, "", nonceStr, timestamp, privateCertFileName); 
 | 
  
 | 
        Map<String, String> headers = new HashMap<>(); 
 | 
        headers.put("Authorization", header); 
 | 
        headers.put("Accept", "application/json"); 
 | 
        JSONObject job_result = restTemplateUtil.getHeaders(com.dy.pipIrrWechat.wechatpay.PayInfo.certificates,null, headers); 
 | 
        JSONObject job_headers = job_result.getJSONObject("headers"); 
 | 
        String wechatpayNonce = job_headers.getJSONArray("Wechatpay-Nonce").getString(0); 
 | 
        String wechatpaySerial = job_headers.getJSONArray("Wechatpay-Serial").getString(0); 
 | 
        String wechatpaySignature = job_headers.getJSONArray("Wechatpay-Signature").getString(0); 
 | 
        String wechatpaySignatureType = job_headers.getJSONArray("Wechatpay-Signature-Type").getString(0); 
 | 
        String wechatpayTimestamp = job_headers.getJSONArray("Wechatpay-Timestamp").getString(0); 
 | 
  
 | 
        JSONObject job_body = job_result.getJSONObject("body"); 
 | 
  
 | 
        // 构造验签名串 
 | 
        String signatureStr = payHelper.responseSign(wechatpayTimestamp, wechatpayNonce, job_body.toJSONString()); 
 | 
        // 验证签名 
 | 
        Boolean valid = payHelper.responseSignVerify(wechatpaySerial, signatureStr, wechatpaySignature); 
 | 
  
 | 
        return BaseResponseUtils.buildSuccess(); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * JSAPI下单 
 | 
     * @param order 下单请求对象,包含需要传入的参数 
 | 
     * @param bindingResult 
 | 
     * @return 预支付交易会话标识(有效期2小时) 
 | 
     */ 
 | 
    @PostMapping(path = "placeOrder") 
 | 
    @Transactional(rollbackFor = Exception.class) 
 | 
    public BaseResponse<Boolean> placeOrder(@RequestBody @Valid DtoOrder order, BindingResult bindingResult) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException { 
 | 
        if(bindingResult != null && bindingResult.hasErrors()){ 
 | 
            return BaseResponseUtils.buildFail(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage()); 
 | 
        } 
 | 
  
 | 
        // 接收参数:登录态ID、虚拟卡ID、充值金额(分) 
 | 
        Long sessionId = order.getSessionId(); 
 | 
        Long virtualId = order.getVcId(); 
 | 
        Integer rechargeAmount = order.getRechargeAmount(); 
 | 
  
 | 
        String prepayId = ""; 
 | 
  
 | 
        SeOpenId po = paymentSv.selectOne(sessionId); 
 | 
        if(po == null) { 
 | 
            return BaseResponseUtils.buildErrorMsg(WechatResultCode.SESSION_ID_ERROR.getMessage()); 
 | 
        } 
 | 
        String openid = po.getOpenId(); 
 | 
  
 | 
        SeVirtualCard seVirtualCard = virtualCardSv.selectVirtuCardById(virtualId); 
 | 
        if(seVirtualCard == null) { 
 | 
            return BaseResponseUtils.buildErrorMsg(WechatResultCode.VIRTUAL_CARD_NOT_EXIST.getMessage()); 
 | 
        } 
 | 
        Long clientId = seVirtualCard.getClientId(); 
 | 
  
 | 
        VoClient voClient = paymentSv.getOneClient(clientId); 
 | 
        if(voClient == null) { 
 | 
            return BaseResponseUtils.buildErrorMsg(WechatResultCode.VIRTUAL_CARD_CLIENT_NOT_EXIST.getMessage()); 
 | 
        } 
 | 
        String clientNum = voClient.getClientNum(); 
 | 
  
 | 
        // 生成订单号并添加充值记录 
 | 
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS"); 
 | 
        String orderNumber = clientNum + dateFormat.format(new Date()); 
 | 
  
 | 
        // 生成虚拟卡充值记录(部分字段) 
 | 
        DtoVirtualCard virtualCard = new DtoVirtualCard(); 
 | 
        virtualCard.setVirtualId(virtualId); 
 | 
        virtualCard.setClientId(clientId); 
 | 
        virtualCard.setOrderNumber(orderNumber); 
 | 
        virtualCard.setRechargeAmount(rechargeAmount); 
 | 
        BaseResponse result = virtualCardSv.insertVCRecharge(virtualCard); 
 | 
        if(!result.getCode().equals("0001")) { 
 | 
            return BaseResponseUtils.buildErrorMsg(WechatResultCode.RECHARGE_ADD_FAIL.getMessage()); 
 | 
        } 
 | 
  
 | 
        JSONObject job_body = new JSONObject(); 
 | 
        job_body.put("appid", appid); 
 | 
        job_body.put("mchid", mchid); 
 | 
        job_body.put("description", description); 
 | 
        job_body.put("out_trade_no", orderNumber); 
 | 
        job_body.put("notify_url", notifyUrl); 
 | 
  
 | 
        //订单金额 
 | 
        JSONObject job_amount = new JSONObject(); 
 | 
        job_amount.put("total", rechargeAmount); 
 | 
        job_amount.put("currency", "CNY"); 
 | 
        job_body.put("amount", job_amount); 
 | 
  
 | 
        //支付者 
 | 
        JSONObject job_payer = new JSONObject(); 
 | 
        job_payer.put("openid", openid); 
 | 
        job_body.put("payer", job_payer); 
 | 
  
 | 
        // 获取随机串和时间戳 
 | 
        String nonceStr = payHelper.generateRandomString(); 
 | 
        Long timestamp = System.currentTimeMillis() / 1000; 
 | 
  
 | 
        String method = "POST"; 
 | 
        String httpUrl = "/v3/pay/transactions/jsapi"; 
 | 
  
 | 
        String body = job_body.toJSONString(); 
 | 
        String header = schema + " " + payHelper.getToken(method, httpUrl, body, nonceStr, timestamp, privateCertFileName); 
 | 
  
 | 
        Map<String, String> headers = new HashMap<>(); 
 | 
        headers.put("Authorization", header); 
 | 
        headers.put("Accept", "application/json"); 
 | 
        headers.put("Content-Type", "application/json"); 
 | 
  
 | 
        // 暂时注释掉,认证通过后再放开 
 | 
        JSONObject job_result = restTemplateUtil.post(com.dy.pipIrrWechat.wechatpay.PayInfo.orderUrl, body, headers); 
 | 
        if(job_result == null) { 
 | 
            return BaseResponseUtils.buildFail(WechatResultCode.RECHARGE_ADD_FAIL.getMessage()); 
 | 
        } 
 | 
  
 | 
        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) 
 | 
    public BaseResponse<JSONObject> signAgain(@RequestParam("prepayId") String prepayId) throws Exception { 
 | 
  
 | 
        // 获取随机串和时间戳,放在此处以保证 
 | 
        String appid = com.dy.pipIrrWechat.wechatpay.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 request 
 | 
     * @param response 
 | 
     * @return 
 | 
     * @throws IOException 
 | 
     * @throws GeneralSecurityException 
 | 
     */ 
 | 
    @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))} 
 | 
            ) 
 | 
    }) 
 | 
    @PostMapping(path = "orderNotify", consumes = MediaType.APPLICATION_JSON_VALUE) 
 | 
    @Transactional(rollbackFor = Exception.class) 
 | 
    public JSONObject orderNotify(@RequestHeader HttpHeaders headers, HttpServletRequest request, HttpServletResponse response) throws IOException, GeneralSecurityException { 
 | 
        JSONObject result = new JSONObject(); 
 | 
  
 | 
        /** 
 | 
         * 1.验签处理 
 | 
         *      从header中取出4个子参数 
 | 
         *      验时间差,超过5分钟的不处理 
 | 
         *      验证签名 
 | 
         *      验证书序列号,必须与某一个证书的序列号一致 
 | 
         */ 
 | 
        String wechatpayNonce = String.valueOf(headers.get("Wechatpay-Nonce").get(0)); 
 | 
        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)); 
 | 
  
 | 
        // 获取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; 
 | 
        if(timeDiff > 5) { 
 | 
            response.setStatus(500); 
 | 
            result.put("code", "FAIL"); 
 | 
            result.put("message", "失败"); 
 | 
            return result; 
 | 
        } 
 | 
  
 | 
        // 构造验签名串 
 | 
        String signatureStr = payHelper.responseSign(wechatpayTimestamp, wechatpayNonce, bodyStr); 
 | 
        // 验证签名 
 | 
        Boolean valid = payHelper.responseSignVerify(wechatpaySerial, signatureStr, wechatpaySignature); 
 | 
        if(!valid) { 
 | 
            response.setStatus(500); 
 | 
            result.put("code", "FAIL"); 
 | 
            result.put("message", "失败"); 
 | 
            return result; 
 | 
        } 
 | 
  
 | 
        // 序列号验证要放在验签后,因为验签时可能会下载新的证书 
 | 
        boolean SerialIsValid = false; 
 | 
        for (String key : payHelper.CERTIFICATE_MAP.keySet()) { 
 | 
            if(key.equals(wechatpaySerial)) { 
 | 
                SerialIsValid = true; 
 | 
            } 
 | 
        } 
 | 
        if(!SerialIsValid) { 
 | 
            response.setStatus(500); 
 | 
            result.put("code", "FAIL"); 
 | 
            result.put("message", "失败"); 
 | 
            return result; 
 | 
        } 
 | 
  
 | 
        // 解密处理 
 | 
        String eventType = orderNotify.getEvent_type(); 
 | 
  
 | 
        if(eventType != null && eventType.equals("TRANSACTION.SUCCESS")) { 
 | 
            // 支付成功回调 
 | 
            /** 
 | 
             * 支付成功的回调 
 | 
             * 取出通知数据对象,继而取出解密所需的associatedData和nonce,以及密文ciphertext 
 | 
             * 解密ciphertext得到 
 | 
             */ 
 | 
            NotifyResource notifyResource = orderNotify.getResource(); 
 | 
            String associatedData = notifyResource.getAssociated_data(); 
 | 
            String nonce = notifyResource.getNonce(); 
 | 
            String ciphertext = notifyResource.getCiphertext(); 
 | 
  
 | 
            String resource = AesUtil.decryptToString(com.dy.pipIrrWechat.wechatpay.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"); 
 | 
  
 | 
            // 如果当前订单状态为未支付状态,则更新虚拟卡表及充值表响应字段 
 | 
            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")) { 
 | 
            // 退款成功后回调 
 | 
            /** 
 | 
             * 退款成功的回调 
 | 
             * 取出通知数据对象,继而取出解密所需的associatedData和nonce,以及密文ciphertext 
 | 
             * 解密ciphertext得到 
 | 
             */ 
 | 
            NotifyResource notifyResource = orderNotify.getResource(); 
 | 
            String associatedData = notifyResource.getAssociated_data(); 
 | 
            String nonce = notifyResource.getNonce(); 
 | 
            String ciphertext = notifyResource.getCiphertext(); 
 | 
  
 | 
            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 out_refund_no = job_resource.getString("out_refund_no"); 
 | 
            String refund_status = job_resource.getString("refund_status"); 
 | 
            Date success_time = job_resource.getDate("success_time"); 
 | 
            if(!refund_status.equals("SUCCESS")) { 
 | 
                response.setStatus(500); 
 | 
                result.put("code", "FAIL"); 
 | 
                result.put("message", "失败"); 
 | 
                return result; 
 | 
            } 
 | 
  
 | 
            // 更新虚拟卡表及充值表响应字段 
 | 
            SeVcRefundItem seVcRefundItem = new SeVcRefundItem(); 
 | 
            seVcRefundItem.setRefundTime(success_time); 
 | 
            seVcRefundItem.setRefundStatus(RefundItemStateENUM.REFUNDED.getCode()); 
 | 
            Integer rec = virtualCardSv.updateRefundItem(seVcRefundItem); 
 | 
            if(rec == null && rec <= 0) { 
 | 
                response.setStatus(500); 
 | 
                result.put("code", "FAIL"); 
 | 
                result.put("message", "失败"); 
 | 
                return result; 
 | 
            } 
 | 
  
 | 
            // 根据退款单号反查退款ID,根据退款ID获取退款状态是未退款的记录数量,如果是0则说明全部退款完成,更新退款表状态为已退款,将退款后金额更新到虚拟卡表 
 | 
            /** 
 | 
             * 根据退款通知接口返回的退款单号反查退款ID,查询该退款ID下未退款记录数量 
 | 
             *      如果结果为0,则该退款已经完成 
 | 
             *      1. 更新退款表状态为已退款 
 | 
             *      2. 将退款后余额更新到虚拟卡表中 
 | 
             */ 
 | 
            Integer noRefundedCount = virtualCardSv.getNoRefundedCount(out_refund_no); 
 | 
            if(noRefundedCount != null && noRefundedCount == 0) { 
 | 
                // 获取退款对象并修改退款状态 
 | 
                Long refundId = virtualCardSv.getRefundIdByRefundNumber(out_refund_no); 
 | 
                SeVcRefund seVcRefund = virtualCardSv.selectRefundByRefundId(refundId); 
 | 
                seVcRefund.setRefundStatus(RefundStatusENUM.REFUNDED.getCode()); 
 | 
                virtualCardSv.updateRefund(seVcRefund); 
 | 
  
 | 
                // 获取虚拟卡对象并修改余额、最后操作、最后操作时间 
 | 
                Long vcId = seVcRefund.getVcId(); 
 | 
                Double afterRefund = seVcRefund.getAfterRefund(); 
 | 
                SeVirtualCard seVirtualCard = virtualCardSv.selectVirtuCardById(vcId); 
 | 
                seVirtualCard.setMoney(afterRefund); 
 | 
                seVirtualCard.setLastOperate(LastOperateENUM.REFUND.getCode()); 
 | 
                seVirtualCard.setLastOperateTime(new Date()); 
 | 
                virtualCardSv.updateVirtualCard(seVirtualCard); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        // 通知应答 
 | 
        response.setStatus(200); 
 | 
        result.put("code", "SUCCESS"); 
 | 
        result.put("message", "成功"); 
 | 
        return  result; 
 | 
    } 
 | 
} 
 |