1. 程式人生 > >微信退款

微信退款

1. package com.ds.tech.common.util.weixinpay;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.Security;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.ds.tech.common.constant.ApiStaticConstant;
import com.ds.tech.common.enums.WxCallBackBusiness;
import com.ds.tech.common.util.XMLUtil;
import com.ds.tech.entity.base.BaseMapEntity;
import com.ds.tech.utility.common.ConfigUtil;
import com.ds.tech.utility.log4j.LogWriter;

public class WeixinPayUtils {
    
    private static Logger logger = LogManager.getLogger(WeixinPayUtils.class);
    
    private static final String[] hexDigits = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
    
    private static String appId = null;
    private static String mchId = null;
    private static String wxRefundUrl = null;
    static {
        appId = ConfigUtil.getSettings("wx_appid").trim();
        mchId = ConfigUtil.getSettings("wx_mch_id").trim();
        wxRefundUrl = ConfigUtil.getSettings("wx_refund_url").trim();
    }
   
    /**
     * 所有引數全部必傳
     *

@param orderNo   商戶訂單號
     * @param outRefundNo  outRefundNo 支援單筆多次退款,每次不一樣
     * @param totalFee     //總金額   -- 單位元
     * @param refundFee     //退款金額  -- 單位元
     * @param refundDesc    //退款原因
     * @param refundAccount   //必傳 //REFUND_SOURCE_UNSETTLED_FUNDS---未結算資金退款(預設使用未結算資金退款)REFUND_SOURCE_RECHARGE_FUNDS---可用餘額退款
     * @param business   //業務型別,拼接到商戶訂單號後面,回撥解析取出,根據型別處理不同業務
     * @return
     */
    public static Map<String, String> wxRefund(
            String orderNo,
            String outRefundNo,
            String totalFee,
            String refundFee,
            String refundDesc,
            String refundAccount,
            WxCallBackBusiness business) {
        logger.info("微信支付退款入參:orderNo:" + orderNo + ",outRefundNo:" + outRefundNo + 
                                ",totalFee:" + totalFee + ",refundFee:" + refundFee + 
                                ",refundDesc:" + refundDesc + ",refundAccount:" + refundAccount);
        
        if (StringUtils.isBlank(orderNo)
                || StringUtils.isBlank(outRefundNo)
                || StringUtils.isBlank(totalFee)
                || StringUtils.isBlank(refundFee)
                || StringUtils.isBlank(refundDesc)
                || StringUtils.isBlank(refundAccount)
                || null == business) {
            logger.info("微信支付退款失敗,必傳引數為空!");
            return null;
        }
        
        //非必傳引數處理
        BaseMapEntity parameters = new BaseMapEntity();
        parameters.put("feeType", "CNY");
        parameters.put("refundDesc", refundDesc);
        parameters.put("refundAccount", refundAccount);
        
        //微信回撥統一地址
        String wxRefundCallbackUrl = ConfigUtil.getSettings("pament_domain")+"/api/pay/WeChatCallback/" + business.getNumber() + "/wxRefundCallback.do";
        logger.info("微信支付退款:wxRefundCallbackUrl = " + wxRefundCallbackUrl);
        parameters.put("notifyUrl", wxRefundCallbackUrl);
        
        
        //微信接收的金額單位為分,所以講入參轉換
        String totalCent = (new BigDecimal(totalFee).multiply(new BigDecimal("100"))).intValue() + "" ;
        String refundCent = (new BigDecimal(refundFee).multiply(new BigDecimal("100"))).intValue() + "";
        
        //請求引數轉換成微信支援的xml格式
        Map<String, String> map = requestWxRefundParams(orderNo,outRefundNo,totalCent,refundCent,parameters);
        String xml = mapToXML(map);
        logger.info("xml:" + xml);
        
        try {
            //讀取本機存放的PKCS12證書檔案
            String path = ApiStaticConstant.getStaticValue("apiWebClassPath") + "keys" + File.separator + "apiclient_cert.p12";
            KeyStore keyStore  = KeyStore.getInstance("PKCS12");
            FileInputStream instream = new FileInputStream(new File(path));
            
            try {
                ////指定PKCS12的密碼(商戶ID)
                keyStore.load(instream, mchId.toCharArray());
            } finally  {
                instream.close();
            }
            
            //指定TLS版本
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,new String[] { "TLSv1" },null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            
            //傳送請求
            HttpPost httpost= new HttpPost(wxRefundUrl);
            httpost.setEntity(new StringEntity(xml,"UTF-8"));
            HttpResponse wxResponse = httpclient.execute(httpost);
            
            //退款結果處理
            String jsonStr = EntityUtils.toString(wxResponse.getEntity(), "UTF-8");
            logger.info("jsonStr:" + jsonStr);
            
            return XMLUtil.doXMLParse(jsonStr);
        } catch (Exception e ) {
            logger.info("微信支付退款失敗!");
        }
        return null;
    }
    
    
    
    /**
     * 
     * @param orderNo   商戶訂單號
     * @param totalFee   交易總金額
     * @param refundFee   退款金額
     * @param parameters   擴充套件的非必傳引數
     * @return
     */
    private static Map<String, String> requestWxRefundParams(
            String orderNo,
            String outRefundNo,
            String totalFee,
            String refundFee,
            BaseMapEntity parameters){
        Map<String, String> map = new HashMap<>();
        map.put("appid", appId);
        map.put("mch_id", mchId);//微信支付分配的商戶號
        map.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));
        map.put("sign_type", "MD5");
        map.put("out_trade_no", orderNo);
        map.put("out_refund_no", outRefundNo);
        map.put("total_fee", totalFee);
        map.put("refund_fee", refundFee);
        map.put("refund_fee_type", parameters.getString("feeType"));
        map.put("refund_desc", parameters.getString("refundDesc"));
        map.put("refund_account",parameters.getString("refundAccount"));
        map.put("notify_url",parameters.getString("notifyUrl"));
        map.put("sign", getSign(map));
        return map;
    }
    
    
    /**
     * 微信小程式支付
     * @param orderName   商品描述
     * @param orderDesc   商品詳情
     * @param attach      附加資料
     * @param orderNo     訂單號
     * @param price       金額
     * @param notifyUrl   回撥地址
     * @param limitCreditCard  是否限制信用卡
     * @param openid      使用者標識
     * @return
     */
    public static Map<String, Object> getWeixinMinPayParam(String orderName, String orderDesc,String attach, String orderNo, BigDecimal price,String notifyUrl,boolean  limitCreditCard,String openid) {

        //是否限制信用卡
        String limitPay = "";
        if(limitCreditCard){
            limitPay = "no_credit";
        }
        int totalPrice = (price.multiply(new BigDecimal("100"))).intValue();
        Map<String, Object> wxMap = new HashMap();
        Map<String, String> map = requestParam(ConfigUtil.getSettings("wx_appid").trim(),orderName, orderDesc, attach, orderNo, totalPrice, notifyUrl, "JSAPI", limitPay, openid);
        Long timestamp = Long.valueOf(System.currentTimeMillis() / 1000L);
        wxMap.put("wx_appid",ConfigUtil.getSettings("wx_appid"));
        wxMap.put("timestamp", timestamp.toString());
        wxMap.put("noncestr", UUID.randomUUID().toString().replaceAll("-", ""));
        wxMap.put("package", getWXprepayID(map));
        wxMap.put("signType", "MD5");
        wxMap.put("paySign", getPaySign(wxMap));
        return wxMap;
    }

    /**
     * 微信支付
     * @Param appid
     * @param orderName  商品描述
     * @param orderDesc  商品詳情
     * @param attach     附加資料
     * @param orderNo    訂單號
     * @param totalPrice 標價金額
     * @param notifyUrl  回撥地址
     * @param tradeType  交易型別 JSAPI--公眾號支付、NATIVE--原生掃碼支付、APP--app支付
     * @param limitPay   指定支付方式 上傳此引數no_credit--可限制使用者不能使用信用卡支付
     * @param openid     使用者標識 trade_type=JSAPI,此引數必傳,使用者在商戶appid下的唯一標識
     * @return
     */
    private static Map<String, String> requestParam(String appid,String orderName,String orderDesc,String attach, String orderNo, int totalPrice, String notifyUrl,String tradeType,String limitPay,String openid) {
        Map<String, String> map = new HashMap();
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        String startTime = (new SimpleDateFormat("yyyyMMddHHmmss")).format(date);
        calendar.add(5, 1);
        date = calendar.getTime();
        String endTime = (new SimpleDateFormat("yyyyMMddHHmmss")).format(date);
        map.put("appid", appid);
        map.put("mch_id", ConfigUtil.getSettings("wx_mch_id").trim());//微信支付分配的商戶號
        map.put("device_info", "WEB");//裝置號
        map.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));//隨機字串
        map.put("sign_type", "MD5");//簽名型別
        map.put("body", orderName);//商品描述
        map.put("detail", orderDesc);//商品詳情
        map.put("attach", attach);//附加資料
        map.put("out_trade_no", orderNo);//商戶訂單號
        map.put("fee_type", "CNY");//幣種
        map.put("total_fee",String.valueOf(totalPrice));//標價金額
        map.put("spbill_create_ip", ConfigUtil.getSettings("wx_spbill_create_ip"));//終端IP
        map.put("time_start", startTime);//交易起始時間
        map.put("time_expire", endTime);//交易結束時間
        map.put("notify_url", notifyUrl);//回撥地址
        map.put("trade_type", tradeType);//交易型別  JSAPI--公眾號支付、NATIVE--原生掃碼支付、APP--app支付
        map.put("limit_pay", limitPay);//指定支付方式  上傳此引數no_credit--可限制使用者不能使用信用卡支付
        map.put("openid",openid);//trade_type=JSAPI,此引數必傳,使用者在商戶appid下的唯一標識
        map.put("sign", getSign(map));
        return map;
    }

    private static String getSign(Map<String, String> data){
        Set<String> keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals("sign")) {
                continue;
            }
            
            if (StringUtils.isBlank(data.get(k))) {
                continue;
            }
            
            // 引數值為空,則不參與簽名
            sb.append(k).append("=").append(data.get(k).trim()).append("&");
        }
        sb.append("key=").append(ConfigUtil.getSettings("wx_key").trim());
        String a = "";
        try {
            a = MD5(sb.toString()).toUpperCase();
        }catch (Exception e){
            e.printStackTrace();
        }
        return a;
    }

    /**
     * 生成 MD5
     *
     * @param data 待處理資料
     * @return MD5結果
     */
    public static String MD5(String data) throws Exception {
        java.security.MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

    private static String MD5Encode(String origin, String charsetname) {
        String resultString = null;

        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if(charsetname != null && !"".equals(charsetname)) {
                resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
            } else {
                resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
            }
        } catch (Exception var4) {
            ;
        }

        return resultString;
    }

    private static String byteArrayToHexString(byte[] b) {
        StringBuffer resultSb = new StringBuffer();

        for(int i = 0; i < b.length; ++i) {
            resultSb.append(byteToHexString(b[i]));
        }

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if(b < 0) {
            n = b + 256;
        }

        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    private static String getWXprepayID(Map<String, String> map) {
        String prepayId = null;
        String xml = mapToXML(map);
        System.out.println(xml);
        String uri = ConfigUtil.getSettings("wx_pay_url");

        try {
            URL url = new URL(uri);
            HttpURLConnection http = (HttpURLConnection)url.openConnection();
            http.setRequestMethod("POST");
            http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            http.setDoOutput(true);
            http.setDoInput(true);
            http.connect();
            OutputStream os = http.getOutputStream();
            os.write(xml.getBytes("UTF-8"));
            os.flush();
            os.close();
            InputStream is = http.getInputStream();
            int size = is.available();
            byte[] jsonBytes = new byte[size];
            is.read(jsonBytes);
            String message = new String(jsonBytes, "UTF-8");
            LogWriter.writeAccessLog("get prepayID message:" + message);
            System.out.println("get prepayID message:"+message);
            logger.info("get prepayID message:"+message);
            Document doc = DocumentHelper.parseText(message);
            Element rootElement = doc.getRootElement();
            List<Element> elements = rootElement.elements();

            for(int i = 0; i < elements.size(); ++i) {
                Element element = (Element)elements.get(i);
                String elementName = element.getName();
                if("prepay_id".equals(elementName)) {
                    prepayId = element.getText();
                }
            }
        } catch (MalformedURLException var17) {
            var17.printStackTrace();
        } catch (IOException var18) {
            var18.printStackTrace();
        } catch (DocumentException var19) {
            var19.printStackTrace();
        }

        return prepayId;
    }

    private static String mapToXML(Map<String, String> map) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        for(Map.Entry<String,String> entry:map.entrySet()){
            if(entry.getValue()!=""){
                sb.append("<"+entry.getKey()+">"+entry.getValue()+"</"+entry.getKey()+">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

    private static String getPaySign(Map<String, Object> map) {
        StringBuffer sb = new StringBuffer();
        sb.append("appId=" + ConfigUtil.getSettings("wx_appid"));
        sb.append("&nonceStr=" + map.get("noncestr"));
        sb.append("&package=prepay_id=" + map.get("package"));
        sb.append("&signType=" + map.get("signType"));
        sb.append("&timeStamp=" + map.get("timestamp"));
        String a = sb.toString();
        String stringSignTemp = a + "&key=" + ConfigUtil.getSettings("wx_key").trim();
        String sign = MD5Encode(stringSignTemp, "UTF-8").toUpperCase();
        return sign;
    }
    

    /**
     * 
     * @param reqInfoSecret
     * @param key
     * @return
     */
     @SuppressWarnings("restriction")
    public static String getRefundDecrypt(String reqInfoSecret, String key) {
         String result = "";
         try {
             Security.addProvider(new BouncyCastleProvider());
             sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
             byte[] bt = decoder.decodeBuffer(reqInfoSecret);
             String b = new String(bt);
             String md5key = MD5(key).toLowerCase();
             SecretKey secretKey = new SecretKeySpec(md5key.getBytes(), "AES");
             Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
             cipher.init(Cipher.DECRYPT_MODE, secretKey);
             byte[] resultbt = cipher.doFinal(bt);
             result = new String(resultbt,"UTF-8");
         } catch (Exception e) {
             e.printStackTrace();
         }
         return result;
     }
     
     public static String setXML(String return_code, String return_msg) {
         return "<xml><return_code><![CDATA[" + return_code
                 + "]]></return_code><return_msg><![CDATA[" + return_msg
                 + "]]></return_msg></xml>";
  
     }
    
}

 

2. package com.ds.tech.controller.zenith.callback;

import com.ds.tech.controller.base.BaseAPIController;
import com.ds.tech.service.zenith.pay.WeChatCallbackService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Controller
@RequestMapping("/api/pay/WeChatCallback")
@Scope("prototype")
public class WeChatCallbackController extends BaseAPIController {
    @Autowired
    private WeChatCallbackService weChatCallbackService;


    /**
     * 2018年11月29日
     * @param request
     * @param respone
     */
    @RequestMapping(value = "/{cbbNumber}/wxRefundCallback", method = RequestMethod.POST)
    public void wxRefundCallback(@PathVariable("cbbNumber") String cbbNumber,HttpServletRequest request, HttpServletResponse respone) {
        weChatCallbackService.wxRefundCallback(cbbNumber,request,respone);
    }

}
3. 

package com.ds.tech.service.zenith.pay;

import java.io.IOException;
import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.jdom.JDOMException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.ds.tech.common.enums.WxCallBackBusiness;
import com.ds.tech.common.model.WxRefundResponse;
import com.ds.tech.common.util.ResponseHandler;
import com.ds.tech.common.util.XMLUtil;
import com.ds.tech.common.util.weixinpay.WeixinPayUtils;
import com.ds.tech.dao.account.UserPurseWaterDao;
import com.ds.tech.dao.account.UserPurseWaterHistoryDao;
import com.ds.tech.dao.order.VehicleOrderDao;
import com.ds.tech.entity.base.BaseMapEntity;
import com.ds.tech.service.base.BaseAPIService;
import com.ds.tech.service.wxmini.order.OrderWxService;
import com.ds.tech.utility.common.ConfigUtil;
import com.ds.tech.utility.log4j.LogWriter;
import com.ds.tech.utility.model.ResultObject;


@Service
public class WeChatCallbackService extends BaseAPIService {

    @Autowired
    private OrderWxService orderWxService;
    

    @Autowired
    private VehicleOrderDao vehicleOrderMapper;
    

    @Autowired
    private UserPurseWaterDao userPurseWaterMapper;
    

    @Autowired
    private UserPurseWaterHistoryDao userPurseWaterHisMapper;
    
    /**
     * 2018年11月29日
     * @param request
     * @param response
     */
    public void wxRefundCallback(String cbbNumber,HttpServletRequest request, HttpServletResponse response) {
        LogWriter.writeAccessLog("-----微信退款回撥開始--------");
        String inputLine;
        String notityXml = "";
        
        try {
            while ((inputLine = request.getReader().readLine()) != null) {
                notityXml += inputLine;
            }
            LogWriter.writeAccessLog("接收到的報文:" + notityXml);
            
            // 建立支付應答物件
            ResponseHandler resHandler = new ResponseHandler(request, response);
            resHandler.setKey(ConfigUtil.getSettings("wx_key").trim());
            
            Map<String, String> map = XMLUtil.doXMLParse(notityXml);
            if ("SUCCESS".equals(map.get("return_code"))) {
                String reqInfo = map.get("req_info").toString();
                
                //加密內容解密
                String reqInfoDecrypt = WeixinPayUtils.getRefundDecrypt(reqInfo, ConfigUtil.getSettings("wx_key").trim());
                LogWriter.writeAccessLog("解密內容的報文:" + reqInfoDecrypt);
                
                //解密內容為空,返回呼叫失敗資訊給微信方
                if (StringUtils.isBlank(reqInfoDecrypt)) {
                    LogWriter.writeAccessLog("-----微信退款返回失敗:解析內容失敗--------");
                    String retWXMsg = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>";
                    resHandler.sendToCFT(retWXMsg);
                    return;
                }
                
                Map<String, String> refundMap = XMLUtil.doXMLParse(reqInfoDecrypt);
                WxRefundResponse resp = new WxRefundResponse();
                resp.setReturnCode(map.get("return_code"));
                resp.setReturnMsg(map.get("req_info"));
                resp.setAppId(map.get("appid"));
                resp.setMchId(map.get("mch_id"));
                resp.setNonceStr(map.get("nonce_str"));
                resp.setTransactionId(refundMap.get("transaction_id"));
                resp.setOutTradeNo(refundMap.get("out_trade_no"));
                resp.setRefundId(refundMap.get("refund_id"));
                resp.setOutRefundNo(refundMap.get("out_refund_no"));
                resp.setTotalFee(refundMap.get("total_fee"));
                resp.setSettlementTotalFee(refundMap.get("settlement_total_fee"));
                resp.setRefundFee(refundMap.get("refund_fee"));
                resp.setSettlementRefundFee(refundMap.get("settlement_refund_fee"));
                resp.setRefundStatus(refundMap.get("refund_status"));
                resp.setSuccessTime(refundMap.get("success_time"));
                resp.setRefundRecvAccout(refundMap.get("refund_recv_accout"));
                resp.setRefundAccount(refundMap.get("refund_account"));
                resp.setRefundRequestSource(refundMap.get("refund_request_source"));
                
                //訂單編號處理 outTradeNo = orderNo + number(WxCallBackBusiness)
                String orderNo = resp.getOutTradeNo();
                LogWriter.writeAccessLog("------orderNo:" + orderNo + ",cbbNumber:" + cbbNumber + "-------");
                
                //檢查訂單資訊
                BaseMapEntity orderParamMap = new BaseMapEntity();
                orderParamMap.put("orderNo",orderNo);
                BaseMapEntity vehicleOrder = vehicleOrderMapper.queryVehicleOrderInfo(orderParamMap);
                if (null == vehicleOrder) {
                    LogWriter.writeAccessLog("-----微信退款返回失敗:訂單編號找不到--------");
                    String retWXMsg = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>";
                    resHandler.sendToCFT(retWXMsg);
                    return;
                }
                
                 //查詢訂單支付時的流水,每個訂單隻有一筆支付記錄
                BaseMapEntity waterParam = new BaseMapEntity();
                waterParam.put("orderNo",orderNo);
                BaseMapEntity queryWater = userPurseWaterMapper.selectPayedPurseWaterByOrderNo(waterParam);
                if(null == queryWater){
                    LogWriter.writeAccessLog("-----微信退款返回失敗:訂單編號找不到交易流水--------");
                    String retWXMsg = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>";
                    resHandler.sendToCFT(retWXMsg);
                    return;
                }
                
                //交易流水錶
                Date curDate = new Date();
                BaseMapEntity waterMap = new BaseMapEntity();
                waterMap.put("userId", vehicleOrder.getInt("userId"));
                waterMap.put("orderNo", orderNo);
                waterMap.put("thirdTradeNo", resp.getOutRefundNo());
                waterMap.put("purseChannel", 3);
                waterMap.put("depositTime", curDate);
                waterMap.put("profitType", 2);
                waterMap.put("incomeTime", curDate);
                waterMap.put("state", 2);
                waterMap.put("tradeStartAccount", "微信");
                waterMap.put("tradeReceiveAccount", queryWater.getString("tradeStartAccount"));
                waterMap.put("tradeAmount", resp.getSettlementRefundFee());
                waterMap.put("tradeResult", resp.getRefundStatus());
                waterMap.put("waterRemark", null != WxCallBackBusiness.getEnum(cbbNumber) ? WxCallBackBusiness.getEnum(cbbNumber).getName() : null);
                waterMap.put("createUser", "weixinCallBack");
                waterMap.put("updateUser", "weixinCallBack");
                waterMap.put("payUserId", null);
                vehicleOrderMapper.insertPurseWater(waterMap);
                
                //通訊成功,且解密轉物件成功,新增流水歷史記錄表
                BaseMapEntity waterHisMap = new BaseMapEntity();
                waterHisMap.put("className", "com.ds.tech.service.zenith.pay.WeChatCallbackService");
                waterHisMap.put("methodName", "wxRefundCallback");
                waterHisMap.put("tradeType", "3");   //交易方式:1.銀行卡 2.支付寶 3.微信
                waterHisMap.put("tradeInput", JSONObject.toJSON(resp).toString());
                waterHisMap.put("tradeOutput", null);
                waterHisMap.put("tradeTime", new Date());
                userPurseWaterHisMapper.insertUserPurseWaterHistory(waterHisMap);
                
                String retWXMsg = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                resHandler.sendToCFT(retWXMsg);
                LogWriter.writeAccessLog("-----儲存資料成功,微信回撥完畢--------");
                return;
            }
            
            String retWXMsg = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>";
            resHandler.sendToCFT(retWXMsg);
            LogWriter.writeAccessLog("-----微信退款回撥失敗--------");
            return;
        } catch (Exception e) {
            LogWriter.writeErrorLog("微信退款回撥失敗,:wxRefundCallback");
        }
        LogWriter.writeAccessLog("-----微信退款回撥結束--------");
    }
    
    /***
     * 微信支付非同步通知
     */
    public void weChatCallbackForOrderPay(HttpServletRequest request, HttpServletResponse response) {
        LogWriter.writeAccessLog("-----支付回撥開始--------");
        String inputLine;
        String notityXml = "";
        try {
            LogWriter.writeAccessLog("-----支付回撥開始--------");
            while ((inputLine = request.getReader().readLine()) != null) {
                notityXml += inputLine;
            }
            request.getReader().close();

            LogWriter.writeAccessLog("接收到的報文--------" + notityXml);
            System.out.println("接收到的報文:" + notityXml);
            Map<String, String> map = XMLUtil.doXMLParse(notityXml);
            // 金鑰
            // 建立支付應答物件
            ResponseHandler resHandler = new ResponseHandler(request, response);
            resHandler.setKey(ConfigUtil.getSettings("wx_key").trim());

            if (resHandler.isTenpaySign(map)) {
                LogWriter.writeAccessLog("-----驗證成功--------");
                // 獲取返回引數
                String rescode = map.get("result_code");
                // 商戶訂單號
                String out_trade_no = map.get("out_trade_no");
                // 微信支付訂單號
                String transaction_id = map.get("transaction_id");
                // 支付完成時間
                String time_end = map.get("time_end");

                String total = map.get("total_fee");

                if ("SUCCESS".equals(rescode)) {// 返回成功
                    BaseMapEntity orderParams = new BaseMapEntity();
                    orderParams.put("orderNo",out_trade_no);//訂單編號
                    orderParams.put("payPrice",total);//支付金額
                    orderParams.put("thirdTradeNo",transaction_id);//交易流水號
                    ResultObject resultObject = orderWxService.updateOrderAfterTenantPay(orderParams);
                    if (resultObject.getErrcode() == 0) {
                        String retWXMsg = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                        resHandler.sendToCFT(retWXMsg);
                        LogWriter.writeAccessLog("-----儲存資料成功,通知微信完畢--------");
                        return;
                    }
                } else {
                    LogWriter.writeAccessLog("-----微信返回失敗--------");
                    String retWXMsg = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>";
                    resHandler.sendToCFT(retWXMsg);
                    return;
                }

            }
            LogWriter.writeAccessLog("-----微信返回失敗--------");
            String retWXMsg = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>";
            resHandler.sendToCFT(retWXMsg);
            LogWriter.writeAccessLog("-----驗證請求失敗--------");
        } catch (NumberFormatException e) {
            LogWriter.writeErrorLog("微信回撥介面失敗,原因:", e);
        } catch (JDOMException e) {
            LogWriter.writeErrorLog("微信回撥介面失敗,原因:", e);
        } catch (IOException e) {
            LogWriter.writeErrorLog("微信回撥介面失敗,原因:", e);
        }
//        catch (ParseException e) {
//            LogWriter.writeErrorLog("微信回撥介面失敗,原因:", e);
//        }
        LogWriter.writeAccessLog("-----支付回撥結束--------");
    }

    /***
     * 微信支付欠款訂單回回調函式
     * @param request
     * @param response
     */
    public void weChatCallbackForPayDebtOrder(HttpServletRequest request, HttpServletResponse response) {
        logger.info("-----支付欠款回撥開始--------");
        String inputLine;
        String notityXml = "";
        try {
            while ((inputLine = request.getReader().readLine()) != null) {
                notityXml += inputLine;
            }
            request.getReader().close();

            logger.info("接收到的報文--------" + notityXml);
            Map<String, String> map = XMLUtil.doXMLParse(notityXml);
            // 金鑰
            // 建立支付應答物件
            ResponseHandler resHandler = new ResponseHandler(request, response);
            resHandler.setKey(ConfigUtil.getSettings("wx_key").trim());

            if (resHandler.isTenpaySign(map)) {
                logger.info("-----驗證成功--------");
                // 獲取返回引數
                String rescode = map.get("result_code");
                // 商戶訂單號
                String out_trade_no = map.get("out_trade_no");
                // 微信支付訂單號
                String transaction_id = map.get("transaction_id");
                // 支付完成時間
                String time_end = map.get("time_end");

                String total = map.get("total_fee");

                if ("SUCCESS".equals(rescode)) {// 返回成功
                    BaseMapEntity orderParams = new BaseMapEntity();
                    orderParams.put("orderNo",out_trade_no);//訂單編號
                    orderParams.put("payPrice",total);//支付金額
                    orderParams.put("thirdTradeNo",transaction_id);//交易流水號
                    ResultObject resultObject = orderWxService.updateAfterTenantPayDebtOrder(orderParams);
                    if (resultObject.getErrcode() == 0) {
                        String retWXMsg = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                        resHandler.sendToCFT(retWXMsg);
                        return;
                    }
                } else {
                    logger.info("-----微信返回失敗--------");
                    String retWXMsg = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>";
                    resHandler.sendToCFT(retWXMsg);
                    return;
                }

            }
            String retWXMsg = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>";
            resHandler.sendToCFT(retWXMsg);
        } catch (NumberFormatException e) {
            logger.error("微信回撥介面失敗,原因:", e);
        } catch (JDOMException e) {
            logger.error("微信回撥介面失敗,原因:", e);
        } catch (IOException e) {
            logger.error("微信回撥介面失敗,原因:", e);
        }
        logger.info("-----支付欠款回撥結束--------");
    }
}