微信支付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("¬ify_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("¬ify_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
+ + "×tamp=" + 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")