微信支付API
diff --git a/src/main/java/com/supwisdom/dlpay/consume/bean/WechatReqResp.java b/src/main/java/com/supwisdom/dlpay/consume/bean/WechatReqResp.java
new file mode 100644
index 0000000..13f42c4
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/consume/bean/WechatReqResp.java
@@ -0,0 +1,472 @@
+package com.supwisdom.dlpay.consume.bean;
+
+import com.supwisdom.dlpay.framework.util.MD5;
+import com.supwisdom.dlpay.framework.util.RandomUtils;
+
+/**
+ * Created by shuwei on 17/6/12.
+ */
+public class WechatReqResp {
+    private int retcode;
+    private String retmsg;
+
+    private String nonce_str;
+    private String appid;
+    private String body;
+    private String mch_id;
+    private String openid;
+    private String out_trade_no;
+    private String spbill_create_ip;
+    private String trade_type;
+    private String key;
+    private String sign;
+    private int total_fee;
+    private String timestamp;
+    private String auth_code;
+
+    private String out_refund_no;
+    private int refund_fee;
+    private String refund_desc;
+
+    private String notify_url;
+    private String prepay_id;
+    private String wpackage;
+
+    private String scene_info;
+
+    private String mweb_url;
+
+    public String getScene_info() {
+        return scene_info;
+    }
+
+    public void setScene_info(String scene_info) {
+        this.scene_info = scene_info;
+    }
+
+    public String getMweb_url() {
+        return mweb_url;
+    }
+
+    public void setMweb_url(String mweb_url) {
+        this.mweb_url = mweb_url;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public void setBody(String body) {
+        this.body = body;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getOpenid() {
+        return openid;
+    }
+
+    public void setOpenid(String openid) {
+        this.openid = openid;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getSpbill_create_ip() {
+        return spbill_create_ip;
+    }
+
+    public void setSpbill_create_ip(String spbill_create_ip) {
+        this.spbill_create_ip = spbill_create_ip;
+    }
+
+    public String getTrade_type() {
+        return trade_type;
+    }
+
+    public void setTrade_type(String trade_type) {
+        this.trade_type = trade_type;
+    }
+
+    public String getKey() {
+        return key;
+    }
+
+    public void setKey(String key) {
+        this.key = key;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public int getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(int total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public String getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(String timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public String getAuth_code() {
+        return auth_code;
+    }
+
+    public void setAuth_code(String auth_code) {
+        this.auth_code = auth_code;
+    }
+
+
+    public String getNotify_url() {
+        return notify_url;
+    }
+
+    public void setNotify_url(String notify_url) {
+        this.notify_url = notify_url;
+    }
+
+    public String getPrepay_id() {
+        return prepay_id;
+    }
+
+    public void setPrepay_id(String prepay_id) {
+        this.prepay_id = prepay_id;
+    }
+
+    public String getWpackage() {
+        return wpackage;
+    }
+
+    public void setWpackage(String wpackage) {
+        this.wpackage = wpackage;
+    }
+
+    public int getRetcode() {
+        return retcode;
+    }
+
+    public void setRetcode(int retcode) {
+        this.retcode = retcode;
+    }
+
+    public String getRetmsg() {
+        return retmsg;
+    }
+
+    public void setRetmsg(String retmsg) {
+        this.retmsg = retmsg;
+    }
+
+    public String getOut_refund_no() {
+        return out_refund_no;
+    }
+
+    public void setOut_refund_no(String out_refund_no) {
+        this.out_refund_no = out_refund_no;
+    }
+
+    public int getRefund_fee() {
+        return refund_fee;
+    }
+
+    public void setRefund_fee(int refund_fee) {
+        this.refund_fee = refund_fee;
+    }
+
+    public String getRefund_desc() {
+        return refund_desc;
+    }
+
+    public void setRefund_desc(String refund_desc) {
+        this.refund_desc = refund_desc;
+    }
+
+    public String generalPaySign() {
+        this.nonce_str = RandomUtils.getRandomString(30);
+        StringBuffer str = new StringBuffer()
+                .append("appid=").append(this.appid)
+                .append("&auth_code=").append(this.auth_code)
+                .append("&body=").append(this.body)
+                .append("&mch_id=").append(this.mch_id)
+                .append("&nonce_str=").append(nonce_str)
+                .append("&out_trade_no=").append(this.out_trade_no)
+                .append("&spbill_create_ip=").append(this.spbill_create_ip)
+                .append("&total_fee=").append(this.total_fee)
+                ;
+        str.append("&key=").append(this.key);
+        this.sign = MD5.encodeByMD5(str.toString());
+        return sign;
+    }
+    public String generalCheckSign(){
+        this.nonce_str = RandomUtils.getRandomString(30);
+        StringBuffer str = new StringBuffer()
+                .append("appid=").append(this.appid)
+                .append("&auth_code=").append(this.auth_code)
+                .append("&mch_id=").append(this.mch_id)
+                .append("&nonce_str=").append(nonce_str);
+        str.append("&key=").append(this.key);
+        this.sign = MD5.encodeByMD5(str.toString());
+        return sign;
+    }
+    public String generalCheckXML(){
+        StringBuffer requestStr = new StringBuffer();
+        requestStr
+                .append("<xml>")
+                .append("<appid>")
+                .append(this.appid)
+                .append("</appid>")
+                .append("<auth_code>")
+                .append(this.auth_code)
+                .append("</auth_code>")
+                .append("<mch_id>")
+                .append(this.mch_id)
+                .append("</mch_id>")
+                .append("<nonce_str>")
+                .append(this.nonce_str)
+                .append("</nonce_str>")
+        ;
+        requestStr.append("<sign>")
+                .append(this.sign)
+                .append("</sign>")
+                .append("</xml>");
+        return requestStr.toString();
+    }
+
+
+    public String generaPayXML() {
+        StringBuffer requestStr = new StringBuffer();
+        requestStr
+                .append("<xml>")
+                .append("<appid>")
+                .append(this.appid)
+                .append("</appid>")
+                .append("<auth_code>")
+                .append(this.auth_code)
+                .append("</auth_code>")
+                .append("<body>")
+                .append(this.body)
+                .append("</body>")
+                .append("<mch_id>")
+                .append(this.mch_id)
+                .append("</mch_id>")
+                .append("<nonce_str>")
+                .append(this.nonce_str)
+                .append("</nonce_str>")
+                .append("<out_trade_no>")
+                .append(this.out_trade_no)
+                .append("</out_trade_no>")
+                .append("<spbill_create_ip>")
+                .append(this.spbill_create_ip)
+                .append("</spbill_create_ip>")
+                .append("<total_fee>")
+                .append(this.total_fee)
+                .append("</total_fee>")
+        ;
+
+        requestStr.append("<sign>")
+                .append(this.sign)
+                .append("</sign>")
+                .append("</xml>");
+        return requestStr.toString();
+    }
+    public String generaSign() {
+        this.nonce_str = RandomUtils.getRandomString(30);
+        StringBuffer str = new StringBuffer()
+                .append("appid=").append(this.appid)
+                .append("&body=").append(this.body)
+                .append("&mch_id=").append(this.mch_id)
+                .append("&nonce_str=").append(nonce_str)
+                .append("&notify_url=").append(this.notify_url);
+        if ("JSAPI".equals(this.trade_type)) {
+            str.append("&openid=").append(this.openid);
+        }
+        str.append("&out_trade_no=").append(this.out_trade_no);
+        if ("MWEB".equals(this.trade_type)) {
+            str.append("&scene_info=").append(this.scene_info);
+        }
+        str.append("&spbill_create_ip=").append(this.spbill_create_ip)
+                .append("&total_fee=").append(this.total_fee)
+                .append("&trade_type=").append(this.trade_type);
+        str.append("&key=").append(this.key);
+        this.sign = MD5.encodeByMD5(str.toString());
+        return sign;
+    }
+    public String generaReverseSign() {
+        this.nonce_str = RandomUtils.getRandomString(30);
+        StringBuffer str = new StringBuffer()
+                .append("appid=").append(this.appid)
+                .append("&mch_id=").append(this.mch_id)
+                .append("&nonce_str=").append(nonce_str)
+                .append("&notify_url=").append(this.notify_url)
+                .append("&out_refund_no=").append(this.out_refund_no)
+                .append("&out_trade_no=").append(this.out_trade_no)
+                .append("&refund_desc=").append(this.refund_desc)
+                .append("&refund_fee=").append(this.refund_fee)
+                .append("&total_fee=").append(this.total_fee)
+                ;
+        str.append("&key=").append(this.key);
+        this.sign = MD5.encodeByMD5(str.toString());
+        return sign;
+    }
+    public String generaXML() {
+        StringBuffer requestStr = new StringBuffer();
+        requestStr
+                .append("<xml>")
+                .append("<appid>")
+                .append(this.appid)
+                .append("</appid>")
+                .append("<body>")
+                .append(this.body)
+                .append("</body>")
+                .append("<mch_id>")
+                .append(this.mch_id)
+                .append("</mch_id>")
+                .append("<nonce_str>")
+                .append(this.nonce_str)
+                .append("</nonce_str>")
+                .append("<notify_url>")
+                .append(this.notify_url)
+                .append("</notify_url>")
+                .append("<out_trade_no>")
+                .append(this.out_trade_no)
+                .append("</out_trade_no>")
+                .append("<spbill_create_ip>")
+                .append(this.spbill_create_ip)
+                .append("</spbill_create_ip>")
+                .append("<total_fee>")
+                .append(this.total_fee)
+                .append("</total_fee>")
+                .append("<trade_type>")
+                .append(this.trade_type)
+                .append("</trade_type>")
+        ;
+        if ("JSAPI".equals(this.trade_type)) {
+            requestStr.append("<openid>")
+                    .append(this.openid)
+                    .append("</openid>");
+        }
+        if ("MWEB".equals(this.trade_type)) {
+            requestStr.append("<scene_info>")
+                    .append(this.scene_info)
+                    .append("</scene_info>");
+        }
+        requestStr.append("<sign>")
+                .append(this.sign)
+                .append("</sign>")
+                .append("</xml>");
+        return requestStr.toString();
+    }
+
+    public String generaReverseXML() {
+        StringBuffer requestStr = new StringBuffer();
+        requestStr
+                .append("<xml>")
+                .append("<appid>")
+                .append(this.appid)
+                .append("</appid>")
+                .append("<mch_id>")
+                .append(this.mch_id)
+                .append("</mch_id>")
+                .append("<nonce_str>")
+                .append(this.nonce_str)
+                .append("</nonce_str>")
+                .append("<notify_url>")
+                .append(this.notify_url)
+                .append("</notify_url>")
+                .append("<out_refund_no>")
+                .append(this.out_refund_no)
+                .append("</out_refund_no>")
+                .append("<out_trade_no>")
+                .append(this.out_trade_no)
+                .append("</out_trade_no>")
+                .append("<refund_desc>")
+                .append(this.refund_desc)
+                .append("</refund_desc>")
+                .append("<refund_fee>")
+                .append(this.refund_fee)
+                .append("</refund_fee>")
+                .append("<total_fee>")
+                .append(this.total_fee)
+                .append("</total_fee>")
+        ;
+        requestStr.append("<sign>")
+                .append(this.sign)
+                .append("</sign>")
+                .append("</xml>");
+        return requestStr.toString();
+    }
+
+
+    public String generaAPPSign() {
+        String signTemp = "appid=" + this.appid
+                + "&nonce_str=" + this.nonce_str
+                + "&package=" + this.wpackage
+                + "&partnerid=" + this.mch_id
+                + "&prepayid=" + this.prepay_id
+                + "&timestamp=" + this.timestamp
+                + "&key=" + this.key;
+        this.sign = MD5.encodeByMD5(signTemp);
+        return sign;
+    }
+
+    public String generaJSAPISign() {
+        String signTemp = "appId=" + this.appid
+                + "&nonceStr=" + this.nonce_str
+                + "&package=prepay_id=" + this.prepay_id
+                + "&signType=MD5"
+                + "&timeStamp=" + this.timestamp
+                + "&key=" + this.key;
+        this.sign = MD5.encodeByMD5(signTemp);
+        return sign;
+    }
+
+    public String generaJSAPIParamters() {
+        String json = "{\"appId\":\"" + this.appid + "\","
+                + "\"nonceStr\":\"" + this.nonce_str + "\","
+                + "\"packages\":\"prepay_id=" + this.prepay_id + "\","
+                + "\"signType\":\"MD5\","
+                + "\"timeStamp\":\"" + this.timestamp + "\","
+                + "\"paySign\":\"" + this.sign + "\"}";
+        return json;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/DateUtil.java b/src/main/java/com/supwisdom/dlpay/framework/util/DateUtil.java
index 1a70722..a17a6ee 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/DateUtil.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/DateUtil.java
@@ -299,7 +299,10 @@
   }
 
 
-
+  public static long getNowSecond() {
+    Calendar calendar = Calendar.getInstance();
+    return calendar.getTimeInMillis() / 1000;
+  }
 
 
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java b/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java
index 2c9d7df..c4dde6e 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java
@@ -6,6 +6,7 @@
 public class TradeCode {
   public static final int TRANSCODE_PAY = 6630;
   public static final int TRANSCODE_YKTPAY=1000;
+  public static final int TRANSCODE_WECHAT=1001;
 
 
   public static final int TRANSTYPE_PAY = 311;
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/XmlUtils.java b/src/main/java/com/supwisdom/dlpay/framework/util/XmlUtils.java
new file mode 100644
index 0000000..fefbc51
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/XmlUtils.java
@@ -0,0 +1,144 @@
+package com.supwisdom.dlpay.framework.util;
+
+import org.dom4j.Document;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import java.io.*;
+import java.util.*;
+
+public class XmlUtils {
+	public static <T> String getObjectToXml(T object) throws IOException {
+		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+		
+		try {
+			JAXBContext context = JAXBContext.newInstance(object.getClass());
+			// 将对象转变为xml Object------XML
+			// 指定对应的xml文件
+			Marshaller marshaller = context.createMarshaller();
+			marshaller.setProperty(Marshaller.JAXB_ENCODING,"gbk");//编码格式 
+			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);// 是否格式化生成的xml串
+			marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);// 是否省略xml头信息
+
+			// 将对象转换为对应的XML文件
+			marshaller.marshal(object, byteArrayOutputStream);
+		} catch (JAXBException e) {
+
+			e.printStackTrace();
+		}
+		// 转化为字符串返回
+		String xmlContent = new String(byteArrayOutputStream.toByteArray(),
+				"gbk");
+		return xmlContent;
+	}
+
+	public static <T> T getXmlToObject(String xmlContent, Class clazz) {
+		try {
+			JAXBContext context = JAXBContext.newInstance(clazz);
+			// xml转换为对象 XML------Object
+			InputStream inputStream;
+			try {
+				inputStream = new ByteArrayInputStream(
+						xmlContent.getBytes("GBK"));
+				Unmarshaller um = context.createUnmarshaller();
+
+				return (T) um.unmarshal(inputStream);
+			} catch (UnsupportedEncodingException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}catch (Exception e) {
+				e.printStackTrace();
+			}
+		} catch (JAXBException e) {
+
+			e.printStackTrace();
+		}
+		return null;
+	}
+	
+	public static <T> T getXmlToObject(String xmlContent,String charset, Class clazz) {
+		try {
+			JAXBContext context = JAXBContext.newInstance(clazz);
+			// xml转换为对象 XML------Object
+			InputStream inputStream;
+			try {
+				inputStream = new ByteArrayInputStream(
+						xmlContent.getBytes(charset));
+				Unmarshaller um = context.createUnmarshaller();
+
+				return (T) um.unmarshal(inputStream);
+			} catch (UnsupportedEncodingException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}catch (Exception e) {
+				e.printStackTrace();
+			}
+		} catch (JAXBException e) {
+
+			e.printStackTrace();
+		}
+		return null;
+	}
+	public static Map<String, String> parseXml(String xml) throws Exception {
+		Map<String, String> map = new HashMap<String, String>();
+		Document document = DocumentHelper.parseText(xml);
+		Element root = document.getRootElement();
+		List<Element> elementList = root.elements();
+		for (Element e : elementList)
+			map.put(e.getName(), e.getText());
+		return map;
+	}
+	/**
+	 * 除去数组中的空值和签名参数
+	 *
+	 * @param sArray 签名参数组
+	 * @return 去掉空值与签名参数后的新签名参数组
+	 */
+	public static Map<String, String> paraFilter(Map<String, String> sArray) {
+		Map<String, String> result = new HashMap<String, String>();
+		if (sArray == null || sArray.size() <= 0) {
+			return result;
+		}
+		for (String key : sArray.keySet()) {
+			String value = sArray.get(key);
+			if (value == null || "".equals(value) || "sign".equalsIgnoreCase(key)
+					|| "sign_type".equalsIgnoreCase(key)) {
+				continue;
+			}
+			result.put(key, value);
+		}
+
+		return result;
+	}
+
+	/**
+	 * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
+	 *
+	 * @param params 需要排序并参与字符拼接的参数组
+	 * @return 拼接后字符串
+	 */
+	public static String createLinkString(Map<String, String> params) {
+
+		List<String> keys = new ArrayList<String>(params.keySet());
+		Collections.sort(keys);
+
+		String prestr = "";
+
+		for (int i = 0; i < keys.size(); i++) {
+			String key = keys.get(i);
+			String value = params.get(key);
+
+			if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
+				prestr = prestr + key + "=" + value;
+			} else {
+				prestr = prestr + key + "=" + value + "&";
+			}
+		}
+
+		return prestr;
+	}
+}
diff --git a/src/main/kotlin/com/supwisdom/dlpay/consume/ThirdPayCall.kt b/src/main/kotlin/com/supwisdom/dlpay/consume/ThirdPayCall.kt
index 3defd76..c3f9704 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/consume/ThirdPayCall.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/consume/ThirdPayCall.kt
@@ -6,9 +6,10 @@
 import com.supwisdom.dlpay.consume.bean.BaseResp
 import com.supwisdom.dlpay.consume.bean.SupStatusRevResp
 import com.supwisdom.dlpay.consume.bean.SupYktResp
+import com.supwisdom.dlpay.consume.bean.WechatReqResp
 import com.supwisdom.dlpay.consume.domain.TUserdtl
-import com.supwisdom.dlpay.framework.util.MoneyUtil
-import com.supwisdom.dlpay.framework.util.HmacUtil
+import com.supwisdom.dlpay.framework.util.*
+import com.supwisdom.dlpay.util.Code
 
 /**
  * Created by shuwei on 2019/4/11.
@@ -16,10 +17,15 @@
 class CallService {
 
     companion object {
-        fun callYktPay(config: Map<String, String>, paydtl: TUserdtl, time: String,stuempno: String, yktshopid: String, devphyid: String?): BaseResp {
+        fun callYktPay(config: Map<String, String>, paydtl: TUserdtl, time: String, stuempno: String, yktshopid: String, devphyid: String?): BaseResp {
             val code = BaseResp()
-
             val appid = config["appid"]
+            if (appid.isNullOrEmpty()) {
+                code.retcode = "1"
+                code.retmsg = "一卡通支付方式未启用或未配置"
+                return code
+            }
+
             val appkey = config["appkey"]
             val orderurl = config["orderurl"]
 
@@ -90,5 +96,136 @@
             code.retmsg = "请求失败"
             return code
         }
+
+        fun callWechatPay(config: Map<String, String>, paydtl: TUserdtl, time: String, wechattype: String,
+                          realip: String?, qrcode: String?, openid: String?): BaseResp {
+            val code = BaseResp()
+            val appid = config["appid"]
+            if (appid.isNullOrEmpty()) {
+                code.retcode = "1"
+                code.retmsg = "微信支付方式未启用或未配置"
+                return code
+            }
+            val appkey = config["appkey"]
+            val orderurl = config["orderurl"]
+            val mchid = config["mchid"]
+            val wechatReqResp = WechatReqResp()
+            wechatReqResp.openid = openid
+            wechatReqResp.appid = appid
+            wechatReqResp.total_fee = MoneyUtil.YuanToFen(paydtl.amount)
+            wechatReqResp.body = paydtl.payinfo
+            wechatReqResp.key = appkey
+            wechatReqResp.mch_id = mchid
+            wechatReqResp.notify_url = config["notifyurl"] + "/notify/wechat"
+            wechatReqResp.out_trade_no = paydtl.refno
+            wechatReqResp.spbill_create_ip = realip
+            val c = Client.create()
+            c.setConnectTimeout(20000)
+            return when (wechattype) {
+                "qrcode" -> {
+                    code
+                }
+                "app" -> {
+                    wechatReqResp.trade_type = "APP"
+                    code
+                }
+                "mp" -> {
+                    wechatReqResp.trade_type = "JSAPI"
+                    wechatReqResp.generaSign()
+                    val xml = wechatReqResp.generaXML()
+                    val r = c.resource(orderurl)
+                    val respClient = r.post(ClientResponse::class.java, xml)
+                    if (200 == respClient.status) {
+                        try {
+                            val ret = respClient.getEntity(String::class.java)
+                            if (ret != null) {
+                                val eleMap = XmlUtils.parseXml(ret)
+                                val retcode = eleMap["return_code"]
+                                val result_code = eleMap["result_code"]
+                                val prepay_id = eleMap["prepay_id"]
+                                if (!retcode.isNullOrEmpty() && "SUCCESS" == retcode
+                                        && !result_code.isNullOrEmpty() && "SUCCESS" == result_code
+                                        && !prepay_id.isNullOrEmpty()) {
+                                    wechatReqResp.retcode = 0
+                                    wechatReqResp.retmsg = "初始化成功"
+                                    wechatReqResp.prepay_id = prepay_id
+                                    //TODO prepay_id 是否保存
+                                    wechatReqResp.timestamp = DateUtil.getNowSecond().toString()
+                                    wechatReqResp.nonce_str = RandomUtils.getRandomString(30)
+                                    wechatReqResp.generaJSAPISign()
+                                    val params = wechatReqResp.generaJSAPIParamters()
+                                    code.setCode(Code.SUCCESS)
+                                    code.data = params
+                                } else {
+                                    code.retcode = "1"
+                                    code.retmsg = eleMap["return_msg"]
+                                }
+                            } else {
+                                code.retcode = "1"
+                                code.retmsg = "微信支付请求失败"
+                            }
+                        } catch (e: Exception) {
+                            e.printStackTrace()
+                            code.retcode = "1"
+                            code.retmsg = "微信支付请求异常"
+                        }
+
+                    } else {
+                        code.retcode = "1"
+                        code.retmsg = "微信支付请求返回失败"
+                    }
+                    code
+                }
+                "h5" -> {
+                    wechatReqResp.trade_type = "MWEB"
+                    wechatReqResp.scene_info = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"" + config["notifyurl"] + "\",\"wap_name\": \"${paydtl.payinfo}\"}}"
+                    val xml = wechatReqResp.generaXML()
+                    val r = c.resource(orderurl)
+                    val respClient = r.post(ClientResponse::class.java, xml)
+                    if (200 == respClient.status) {
+                        try {
+                            val ret = respClient.getEntity(String::class.java)
+                            if (ret != null) {
+                                val eleMap = XmlUtils.parseXml(ret)
+                                val retcode = eleMap["return_code"]
+                                val result_code = eleMap["result_code"]
+                                val prepay_id = eleMap["prepay_id"]
+                                val mweb_url = eleMap["mweb_url"]
+                                if (!retcode.isNullOrEmpty() && "SUCCESS" == retcode
+                                        && !result_code.isNullOrEmpty() && "SUCCESS" == result_code
+                                        && !prepay_id.isNullOrEmpty()) {
+                                    wechatReqResp.retcode = 0
+                                    wechatReqResp.retmsg = "初始化成功"
+                                    wechatReqResp.prepay_id = prepay_id
+                                    wechatReqResp.mweb_url = mweb_url
+                                    code.setCode(Code.SUCCESS)
+                                    code.data = mweb_url
+                                } else {
+                                    code.retcode = "1"
+                                    code.retmsg = eleMap["return_msg"]
+                                }
+                            } else {
+                                code.retcode = "1"
+                                code.retmsg = "微信支付请求失败"
+                            }
+                        } catch (e: Exception) {
+                            e.printStackTrace()
+                            code.retcode = "1"
+                            code.retmsg = "微信支付请求异常"
+                        }
+
+                    } else {
+                        code.retcode = "1"
+                        code.retmsg = "微信支付请求返回失败"
+                    }
+                    code
+                }
+                else -> {
+                    code.retcode = "1"
+                    code.retmsg = "未标识的类型:wechattype=$wechattype"
+                    code
+                }
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/consume/comsume_builder.kt b/src/main/kotlin/com/supwisdom/dlpay/consume/comsume_builder.kt
index a650004..6c1c860 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/consume/comsume_builder.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/consume/comsume_builder.kt
@@ -340,4 +340,7 @@
     fun done(refno: String, status: String, service: PersonBalancePayService): TUserdtl {
         return service.finish(refno, status, null)
     }
+    fun done(refno: String, status: String, businessData: Map<String, String>?,service: PersonBalancePayService): TUserdtl {
+        return service.finish(refno, status, businessData)
+    }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/consume/controller/consume_service.kt b/src/main/kotlin/com/supwisdom/dlpay/consume/controller/consume_service.kt
index 2d2d465..a8adc8a 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/consume/controller/consume_service.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/consume/controller/consume_service.kt
@@ -3,6 +3,7 @@
 import com.supwisdom.dlpay.consume.AccountHolder
 import com.supwisdom.dlpay.consume.CallService
 import com.supwisdom.dlpay.consume.PersonTransBuilder
+import com.supwisdom.dlpay.consume.domain.TPaytype
 import com.supwisdom.dlpay.consume.service.AccountUtilServcie
 import com.supwisdom.dlpay.consume.service.PaytypeService
 import com.supwisdom.dlpay.consume.service.PersonBalancePayService
@@ -10,6 +11,7 @@
 import com.supwisdom.dlpay.exception.TransactionException
 import com.supwisdom.dlpay.framework.ResponseBodyBuilder
 import com.supwisdom.dlpay.framework.util.*
+import com.supwisdom.dlpay.util.ConstUtil
 import com.supwisdom.dlpay.util.PaytypeUtil
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.ResponseEntity
@@ -74,6 +76,11 @@
                    outtradeno: String, payinfo: String, feetype: String): ResponseEntity<Any> {
         //一卡通支付款 112240
         return try {
+            val paytype = paytypeService.getByPaytype(PaytypeUtil.YKTPAY)
+            if (paytype == null || ConstUtil.ENABLE_YES != paytype.enable) {
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(1, "支付方式未开启"))
+            }
             val person = personService.getPersonByThirdUniqueIdenty(stuempno)
             val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
                     .setTransDatetime(transdate, transtime)
@@ -101,6 +108,11 @@
                                                 AccountHolder.shop(shopid),
                                                 manageFee / 100.0, "优惠折扣")
                             }
+                            else -> {
+                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_YKT),
+                                        AccountHolder.shop(shopid),
+                                        amount / 100.0, "一卡通支付")
+                            }
                         }
                     }.done(personBalancePayService, false)
             ResponseEntity.ok(ResponseBodyBuilder.create()
@@ -136,4 +148,74 @@
                     .transException(e, "交易确认失败"))
         }
     }
+
+    /**
+     * 微信支付
+     * wechattype
+     * qrcode-扫微信二维码支付
+     * app-原生app微信支付
+     * mp-微信公众号支付
+     * h5-微信h5支付
+     *
+     * */
+    @PostMapping("/wechat/payinit")
+    fun wechatPayInit(userid: String, amount: Int, manageFee: Int,
+                      stuempno: String, shopid: String, transdate: String, transtime: String,
+                      outtradeno: String, payinfo: String, feetype: String,
+                      wechattype: String, realip: String?, qrcode: String?, openid: String?): ResponseEntity<Any> {
+        return try {
+            val paytype = paytypeService.getByPaytype(PaytypeUtil.WECHAT)
+            if (paytype == null || ConstUtil.ENABLE_YES != paytype.enable) {
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(1, "支付方式未开启"))
+            }
+            val person = personService.getPersonByThirdUniqueIdenty(stuempno)
+            val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+                    .setTransDatetime(transdate, transtime)
+                    .selectPaytype(PaytypeUtil.WECHAT, payinfo)
+                    .setOuttradeno(outtradeno)
+                    .setOwner(person)
+                    .tryLock(true)
+                    .setTransinfo(TradeCode.TRANSCODE_WECHAT, "微信支付")
+                    .chooseTradetype(Tradetype.CONSUME)
+                    .also {
+                        when (feetype) {
+                            TradeDict.FEETYPE_CONSUME_MEALER -> {
+                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_WECHAT),
+                                        AccountHolder.shop(shopid),
+                                        amount / 100.0, "微信支付")
+                                        .addDetail(AccountHolder.transType(TranstypeCode.TT_CONSUUME_MANAGE_FEE)
+                                                .with(AccountHolder.shop(shopid)),
+                                                manageFee / 100.0)
+                            }
+                            TradeDict.FEETYPE_CONSUME_DISCOUNT -> {
+                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_WECHAT),
+                                        AccountHolder.shop(shopid),
+                                        (amount - manageFee) / 100.0, "微信支付")
+                                        .addDetail(AccountHolder.subject(Subject.SUBJNO_CONSUME_DISCOUNT),
+                                                AccountHolder.shop(shopid),
+                                                manageFee / 100.0, "优惠折扣")
+                            }
+                            else -> {
+                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_WECHAT),
+                                        AccountHolder.shop(shopid),
+                                        amount / 100.0, "微信支付")
+                            }
+                        }
+                    }.done(personBalancePayService, false)
+            val code = CallService.callWechatPay(paytypeService.getPaytypeConfigByPaytype(PaytypeUtil.WECHAT),
+                    dtl, DateUtil.getNow(), wechattype, realip, qrcode, openid)
+            if (code.retcode == "0") {
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .data("refno", dtl.refno)
+                        .success())
+            } else {
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(TradeErrorCode.TRANSACTION_NOT_EXISTS, "交易请求失败-${code.retcode}"))
+            }
+        } catch (e: TransactionException) {
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .transException(e, "交易初始化异常"))
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/consume/controller/notify_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/consume/controller/notify_controller.kt
new file mode 100644
index 0000000..a9fe3fd
--- /dev/null
+++ b/src/main/kotlin/com/supwisdom/dlpay/consume/controller/notify_controller.kt
@@ -0,0 +1,100 @@
+package com.supwisdom.dlpay.consume.controller
+
+import com.supwisdom.dlpay.consume.PersonTransBuilder
+import com.supwisdom.dlpay.consume.service.AccountUtilServcie
+import com.supwisdom.dlpay.consume.service.PaytypeService
+import com.supwisdom.dlpay.consume.service.PersonBalancePayService
+import com.supwisdom.dlpay.framework.util.MD5
+import com.supwisdom.dlpay.framework.util.TradeDict
+import com.supwisdom.dlpay.framework.util.XmlUtils
+import com.supwisdom.dlpay.util.PaytypeUtil
+import org.dom4j.io.SAXReader
+import org.slf4j.LoggerFactory
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.util.StringUtils
+import org.springframework.web.bind.annotation.PathVariable
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.ResponseBody
+import org.springframework.web.bind.annotation.RestController
+import java.util.HashMap
+import javax.servlet.http.HttpServletRequest
+import javax.servlet.http.HttpServletResponse
+
+/**
+ * Created by shuwei on 2019/4/22.
+ */
+@RestController
+@RequestMapping("/api/notify")
+class NotifyController {
+    private val logger = LoggerFactory.getLogger(NotifyController::class.java)
+    @Autowired
+    lateinit var personBalancePayService: PersonBalancePayService
+    @Autowired
+    lateinit var paytypeService: PaytypeService
+    @Autowired
+    lateinit var accountUtilServcie: AccountUtilServcie
+
+    @RequestMapping(value = "/wechat")
+    @ResponseBody
+    fun index(@PathVariable schema: String, request: HttpServletRequest,
+              response: HttpServletResponse): String {
+        try {
+            // 解析结果存储在HashMap
+            var map: MutableMap<String, String> = HashMap()
+            val inputStream = request.inputStream
+            // 读取输入流
+            val reader = SAXReader()
+            val document = reader.read(inputStream)
+            // 得到xml根元素
+            val root = document.rootElement
+            // 得到根元素的所有子节点
+            val elementList = root.elements()
+            // 遍历所有子节点
+            for (e in elementList) {
+                map[e.name] = e.text
+                logger.error("*************" + e.name + "=" + e.text + "************************")
+            }
+            // 释放资源
+            inputStream.close()
+
+            val sign = map["sign"]
+            if (StringUtils.isEmpty(sign)) {
+                logger.error("签名错误")
+                return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名错误]]></return_msg></xml>"
+            }
+            map = XmlUtils.paraFilter(map)
+            //TODO 校验签名
+            var signStr = XmlUtils.createLinkString(map)
+            val config = paytypeService.getPaytypeConfigByPaytype(PaytypeUtil.WECHAT)
+            if (config["appkey"].isNullOrEmpty()) {
+                logger.error("签名错误")
+                return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名错误]]></return_msg></xml>"
+            }
+            val key = config["appkey"]
+            signStr += "&key=$key"
+            val signRet = MD5.encodeByMD5(signStr)
+            logger.error("*******signStr=$signStr")
+            if (!signRet.equals(sign, ignoreCase = true)) {
+                return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>"
+            }
+            logger.error("*******signRet=$signRet,sign=$sign*****************")
+            val return_code = map["return_code"]
+            val result_code = map["result_code"]
+            val out_trade_no = map["out_trade_no"]
+            if (StringUtils.isEmpty(out_trade_no)) {
+                return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[订单信息错误]]></return_msg></xml>"
+            }
+            if (!StringUtils.isEmpty(return_code) && "SUCCESS" == return_code
+                    && !StringUtils.isEmpty(result_code) && "SUCCESS" == result_code) {
+                //map.get("transaction_id") 第三方流水号
+                PersonTransBuilder.newBuilder(accountUtilServcie)
+                        .done(out_trade_no!!, TradeDict.DTL_STATUS_SUCCESS, map, personBalancePayService)
+            }
+            return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>"
+        } catch (e: Exception) {
+            e.printStackTrace()
+            logger.error("------------step7----------------" + e.message)
+            return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[解析失败]]></return_msg></xml>"
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/consume/service/impl/pay_service_impl.kt b/src/main/kotlin/com/supwisdom/dlpay/consume/service/impl/pay_service_impl.kt
index ee703a0..1034d85 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/consume/service/impl/pay_service_impl.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/consume/service/impl/pay_service_impl.kt
@@ -227,7 +227,7 @@
         if (TradeDict.DTL_STATUS_SUCCESS == userdtl.status) {
             return
         }
-
+        //TODO 校验已经成功的流水,不重复入账
         debitCreditDtlDao.findByRefno(userdtl.refno).forEach { detail ->
             //个人账户入账
             if (Subject.SUBJNO_PERSONAL_DEPOSIT == detail.drsubjno) {
diff --git a/src/main/kotlin/com/supwisdom/dlpay/security.kt b/src/main/kotlin/com/supwisdom/dlpay/security.kt
index 05d8709..6fd99ab 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/security.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/security.kt
@@ -78,6 +78,7 @@
                                 UsernamePasswordAuthenticationFilter::class.java)
                         .authorizeRequests()
                         .antMatchers("/api/auth/**").permitAll()
+                        .antMatchers("/api/notify/**").permitAll()
                         .antMatchers("/api/common/**").hasAnyRole("THIRD_COMMON", "THIRD_ADMIN")
                         .antMatchers("/api/consume/**").hasRole("THIRD_CONSUME")
                         .antMatchers("/api/deposit/**").hasRole("THIRD_DEPOSIT")