支付宝接口、微信接口
diff --git a/payapi/build.gradle b/payapi/build.gradle
index e2cdedd..0381f48 100644
--- a/payapi/build.gradle
+++ b/payapi/build.gradle
@@ -83,6 +83,8 @@
     implementation 'commons-dbcp:commons-dbcp:1.4'
 
     implementation project(':payapi-common')
+    /*支付宝SDK*/
+    implementation group: 'com.alipay.sdk', name: 'alipay-sdk-java', version: '3.7.110.ALL'
 
     annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
     annotationProcessor 'org.projectlombok:lombok:1.18.8'
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java
index 950f338..0d56cc1 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java
@@ -10,8 +10,8 @@
   WAIT_NOTIFY("wait_notify", "交易已发起,等待通知"),
   SHORT_OF_BALANCE("short_of_balance", "余额不足"),
   NOT_SUPPORT("not_support", "不支持功能"),
-  COMMON_ERROR("common_error", "其它错误");
-
+  COMMON_ERROR("common_error", "其它错误"),
+  CONFIG_ERROR("config_error", "参数配置错误");
   AgentCode(String code, String msg) {
     this.code = code;
     this.msg = msg;
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentResponse.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentResponse.java
index e776671..80f65a3 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentResponse.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentResponse.java
@@ -1,50 +1,54 @@
 package com.supwisdom.dlpay.agent;
 
 public class AgentResponse {
-  private AgentCode code;
-  private String agentCode;
-  private String agentMsg;
+    public static final String AGENTCODE_SUCCESS = "0";
 
-  private String agentRefno;
-  private DtlStatus dtlStatus;
+    public static final String AGENTCODE_FAIL = "1";
 
-  public AgentCode getCode() {
-    return code;
-  }
+    private AgentCode code;
+    private String agentCode;
+    private String agentMsg;
 
-  public void setCode(AgentCode code) {
-    this.code = code;
-  }
+    private String agentRefno;
+    private DtlStatus dtlStatus;
 
-  public String getAgentCode() {
-    return agentCode;
-  }
+    public AgentCode getCode() {
+        return code;
+    }
 
-  public void setAgentCode(String agentCode) {
-    this.agentCode = agentCode;
-  }
+    public void setCode(AgentCode code) {
+        this.code = code;
+    }
 
-  public String getAgentMsg() {
-    return agentMsg;
-  }
+    public String getAgentCode() {
+        return agentCode;
+    }
 
-  public void setAgentMsg(String agentMsg) {
-    this.agentMsg = agentMsg;
-  }
+    public void setAgentCode(String agentCode) {
+        this.agentCode = agentCode;
+    }
 
-  public String getAgentRefno() {
-    return agentRefno;
-  }
+    public String getAgentMsg() {
+        return agentMsg;
+    }
 
-  public void setAgentRefno(String agentRefno) {
-    this.agentRefno = agentRefno;
-  }
+    public void setAgentMsg(String agentMsg) {
+        this.agentMsg = agentMsg;
+    }
 
-  public DtlStatus getDtlStatus() {
-    return dtlStatus;
-  }
+    public String getAgentRefno() {
+        return agentRefno;
+    }
 
-  public void setDtlStatus(DtlStatus dtlStatus) {
-    this.dtlStatus = dtlStatus;
-  }
+    public void setAgentRefno(String agentRefno) {
+        this.agentRefno = agentRefno;
+    }
+
+    public DtlStatus getDtlStatus() {
+        return dtlStatus;
+    }
+
+    public void setDtlStatus(DtlStatus dtlStatus) {
+        this.dtlStatus = dtlStatus;
+    }
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/DtlStatus.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/DtlStatus.java
index d80d503..a13f1d5 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/DtlStatus.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/DtlStatus.java
@@ -4,5 +4,6 @@
   SUCCESS, //成功
   FAIL,  //失败
   REFUND, //已退款
-  PARTIAL_REFUND //部分退款
+  PARTIAL_REFUND, //部分退款
+  WAIT //等待付款
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java
index 96f8b06..fb42041 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java
@@ -65,6 +65,9 @@
   @Column(name = "tenantid", length = 20)
   private String tenantid;
 
+  @Column(name = "spid", length = 20)
+  private String spip;
+
   public QrcodePayTrans() {
   }
 
@@ -179,4 +182,12 @@
   public void setUpdateTime(Timestamp updateTime) {
     this.updateTime = updateTime;
   }
+
+  public String getSpip() {
+    return spip;
+  }
+
+  public void setSpip(String spip) {
+    this.spip = spip;
+  }
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/bean/WechatReqResp.java b/payapi/src/main/java/com/supwisdom/dlpay/api/bean/WechatReqResp.java
index f69eb68..40b62e5 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/bean/WechatReqResp.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/bean/WechatReqResp.java
@@ -237,6 +237,41 @@
         this.sign = MD5.encodeByMD5(str.toString());
         return sign;
     }
+    public String generalQuerySign(){
+        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("&out_trade_no=").append(this.out_trade_no);
+        str.append("&key=").append(this.key);
+        this.sign = MD5.encodeByMD5(str.toString());
+        return sign;
+    }
+    public String generalQueryXML(){
+        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("<out_trade_no>")
+                .append(this.out_trade_no)
+                .append("</out_trade_no>")
+        ;
+        requestStr.append("<sign>")
+                .append(this.sign)
+                .append("</sign>")
+                .append("</xml>");
+        return requestStr.toString();
+    }
+
     public String generalCheckSign(){
         this.nonce_str = RandomUtils.getRandomString(30);
         StringBuffer str = new StringBuffer()
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/util/PaytypeUtil.java b/payapi/src/main/java/com/supwisdom/dlpay/util/PaytypeUtil.java
index 8222e90..55108af 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/util/PaytypeUtil.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/util/PaytypeUtil.java
@@ -7,4 +7,40 @@
     public static final String YKTPAY = "yktpay";
 
     public static final String WECHAT = "wechat";
+
+
+    /**
+     * 支付宝支付,配置的KEY值
+     */
+    public static final String CFG_ALIPAY_APPID = "alipay.appid";
+
+    public static final String CFG_ALIPAY_PRIVATEKEY = "alipay.privatekey";
+
+    public static final String CFG_ALIPAY_PUBLICKEY = "alipay.publickey";
+
+    public static final String CFG_ALIPAY_PAYURL = "alipay.payurl";
+
+    public static final String CFG_ALIPAY_NOTIFY = "alipay.notify";
+
+    public static final String CFG_ALIPAY_RETURNURL = "alipay.returnurl";
+
+    /**
+     * 微信支付,配置的KEY值
+     */
+    public static final String CFG_WECHAT_APPID = "wechat.appid";
+
+    public static final String CFG_WECHAT_MECHID = "wechat.mechid";
+
+    public static final String CFG_WECHAT_MECHKEY = "wechat.mechkey";
+
+    public static final String CFG_WECHAT_NOTIFY = "wechat.notify";
+
+    public static final String CFG_WECHAT_OAUTHCODE = "https://api.mch.weixin.qq.com/tools/authcodetoopenid";
+
+    public static final String CFG_WECHAT_QRCODEPAY = "https://api.mch.weixin.qq.com/pay/micropay";
+
+    public static final String CFG_WECHAT_UNIONPAY = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+
+    public static final String CFG_WECHAT_QUERY = "https://api.mch.weixin.qq.com/pay/orderquery";
+
 }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt
index a89e2e1..3f8cde2 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt
@@ -4,29 +4,52 @@
 import com.supwisdom.dlpay.agent.AgentPayService
 import com.supwisdom.dlpay.agent.AgentResponse
 import com.supwisdom.dlpay.api.domain.TTransactionMain
+import com.supwisdom.dlpay.api.service.ConsumePayService
+import com.supwisdom.dlpay.framework.util.TradeCode
+import com.supwisdom.dlpay.framework.util.TradeDict
 import org.springframework.stereotype.Component
 
+interface AlipayService {
+    fun doQrcodepay(transaction: TTransactionMain): AgentResponse
+
+    fun doPrepay(transaction: TTransactionMain): AgentResponse
+
+    fun doRefund(transaction: TTransactionMain): AgentResponse
+
+    fun doQuery(transaction: TTransactionMain): AgentResponse
+
+    fun doNotify(param: Map<String, String>): AgentResponse
+}
+
 @Component("alipayAgent")
-class AlipayAgentService : AgentPayService {
+class AlipayAgentService(val consumePayService: ConsumePayService,
+                         val aipayService: AlipayService) : AgentPayService {
+
     override fun auth(shopaccno: String?, billno: String?): AgentResponse {
+        if (consumePayService.checkShopPaytype(shopaccno!!, TradeDict.PAYTYPE_ALIPAY, true)) {
+            //TODO 支付宝实名认证逻辑
+        }
         return AgentResponse().apply {
             this.code = AgentCode.NOT_SUPPORT
         }
     }
 
     override fun pay(transaction: TTransactionMain): AgentResponse {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+        return when (transaction.transCode) {
+            TradeCode.TRANSCODE_QRCODE -> aipayService.doQrcodepay(transaction)
+            else -> aipayService.doPrepay(transaction)
+        }
     }
 
     override fun cancel(transaction: TTransactionMain): AgentResponse {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+        return refund(transaction)
     }
 
     override fun refund(transaction: TTransactionMain): AgentResponse {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+        return aipayService.doRefund(transaction)
     }
 
     override fun query(transaction: TTransactionMain): AgentResponse {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+        return aipayService.doQuery(transaction)
     }
 }
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/alipay_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/alipay_service_impl.kt
new file mode 100644
index 0000000..53afcd7
--- /dev/null
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/alipay_service_impl.kt
@@ -0,0 +1,260 @@
+package com.supwisdom.dlpay.agent.service.impl
+
+import com.supwisdom.dlpay.agent.AgentCode
+import com.supwisdom.dlpay.agent.AgentResponse
+import com.supwisdom.dlpay.agent.service.AlipayService
+import com.supwisdom.dlpay.api.service.SourceTypeService
+import com.supwisdom.dlpay.framework.util.TradeDict
+import com.supwisdom.dlpay.util.PaytypeUtil
+import mu.KotlinLogging
+import org.springframework.stereotype.Service
+import com.alipay.api.request.AlipayTradePayRequest
+import com.alipay.api.DefaultAlipayClient
+import com.alipay.api.domain.AlipayTradePayModel
+import com.supwisdom.dlpay.agent.service.AgentServiceProxy
+import com.supwisdom.dlpay.api.domain.TTransactionMain
+import com.alipay.api.AlipayApiException
+import com.alipay.api.internal.util.AlipaySignature
+import com.alipay.api.request.AlipayTradeAppPayRequest
+import com.supwisdom.dlpay.api.service.ConsumePayService
+import com.supwisdom.dlpay.api.service.TransactionServiceProxy
+import com.alipay.api.request.AlipayTradeQueryRequest
+import com.supwisdom.dlpay.agent.DtlStatus
+import com.alipay.api.domain.AlipayTradeQueryModel
+import com.alipay.api.domain.AlipayTradeRefundModel
+
+
+@Service
+class AlipayServiceImpl(val sourceTypeService: SourceTypeService,
+                        val agentServiceProxy: AgentServiceProxy,
+                        val consumePayService: ConsumePayService,
+                        val transactionService: TransactionServiceProxy) : AlipayService {
+    val logger = KotlinLogging.logger { }
+
+    fun checkCfg(config: Map<String, String?>, resp: AgentResponse): Boolean {
+        if (config[PaytypeUtil.CFG_ALIPAY_APPID].isNullOrEmpty()
+                || config[PaytypeUtil.CFG_ALIPAY_PRIVATEKEY].isNullOrEmpty()
+                || config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY].isNullOrEmpty()) {
+            resp.code = AgentCode.CONFIG_ERROR
+            resp.agentCode = AgentResponse.AGENTCODE_FAIL
+            resp.agentMsg = "支付宝相关配置为空"
+            logger.error { "请检查:${PaytypeUtil.CFG_ALIPAY_APPID},${PaytypeUtil.CFG_ALIPAY_PRIVATEKEY},${PaytypeUtil.CFG_ALIPAY_PUBLICKEY}" }
+            return false
+        }
+        return true
+    }
+
+    override fun doQrcodepay(transaction: TTransactionMain): AgentResponse {
+        var qrcodePayTrans = agentServiceProxy.qrcodePayTransFindByRefno(transaction.refno)
+        val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_ALIPAY, transaction.shopDtl.shopaccno, qrcodePayTrans.isAnonymous, false)
+        var agentResponse = AgentResponse()
+        if (checkCfg(config, agentResponse)) {
+            var payurl = config[PaytypeUtil.CFG_ALIPAY_PAYURL]
+            if (payurl.isNullOrEmpty()) {
+                payurl = "https://openapi.alipay.com/gateway.do"
+            }
+            val alipayClient = DefaultAlipayClient(payurl, config[PaytypeUtil.CFG_ALIPAY_APPID], config[PaytypeUtil.CFG_ALIPAY_PRIVATEKEY], "json", "UTF-8", config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY], "RSA2")
+            val request = AlipayTradePayRequest()
+            request.bizModel = AlipayTradePayModel().apply {
+                this.authCode = qrcodePayTrans.qrcode
+                this.outTradeNo = transaction.refno
+                this.subject = "POS扫支付宝二维码消费"
+                this.totalAmount = transaction.shopDtl.amount.toString()
+            }
+            try {
+                val response = alipayClient.execute(request)
+                if ("10000" == response.code) {
+                    if (response.isSuccess) {
+                        agentResponse.agentRefno = response.tradeNo
+                        agentResponse.code = AgentCode.SUCCESS
+                        agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS
+                    } else {
+                        agentResponse.code = AgentCode.FAIL
+                        agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                        agentResponse.agentMsg = response.subMsg
+                        logger.error { "支付宝:${response.code},${response.msg},${response.subCode},${response.subMsg}" }
+                    }
+                } else if ("10003" == response.code || "20000" == response.code) {
+                    agentResponse.code = AgentCode.REQUIRE_QUERY
+                    agentResponse.agentMsg = "支付请求已提交,等待用户支付"
+                    agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                    logger.error { "支付宝:${response.code},${response.msg},${response.subCode},${response.subMsg}" }
+                } else {
+                    agentResponse.code = AgentCode.FAIL
+                    agentResponse.agentMsg = response.msg
+                    agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                    logger.error { "支付宝:${response.code},${response.msg},${response.subCode},${response.subMsg}" }
+                }
+            } catch (e: AlipayApiException) {
+                logger.error { "支付宝:${e.message}" }
+                agentResponse.code = AgentCode.FAIL
+                agentResponse.agentMsg = "调用支付宝异常"
+                agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            }
+        }
+        return agentResponse
+    }
+
+    override fun doPrepay(transaction: TTransactionMain): AgentResponse {
+        val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_ALIPAY, transaction.shopDtl.shopaccno, false, false)
+        var agentResponse = AgentResponse()
+        if (checkCfg(config, agentResponse)) {
+            if (config[PaytypeUtil.CFG_ALIPAY_NOTIFY].isNullOrEmpty()) {
+                agentResponse.code = AgentCode.CONFIG_ERROR
+                agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                agentResponse.agentMsg = "支付宝相关配置为空"
+                logger.error { "支付宝异步通知地址未配置:${PaytypeUtil.CFG_ALIPAY_NOTIFY}" }
+            }
+            var payurl = config[PaytypeUtil.CFG_ALIPAY_PAYURL]
+            if (payurl.isNullOrEmpty()) {
+                payurl = "https://openapi.alipay.com/gateway.do"
+            }
+            val alipayClient = DefaultAlipayClient(payurl, config[PaytypeUtil.CFG_ALIPAY_APPID], config[PaytypeUtil.CFG_ALIPAY_PRIVATEKEY], "json", "UTF-8", config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY], "RSA2")
+            val request = AlipayTradeAppPayRequest()
+            var productCode = ""
+            //判断是否为H5
+            //productCode = "QUICK_WAP_WAY"
+            request.bizModel = AlipayTradePayModel().apply {
+                this.outTradeNo = transaction.refno
+                this.subject = "支付宝支付"
+                this.totalAmount = transaction.shopDtl.amount.toString()
+                this.productCode = productCode
+            }
+            request.notifyUrl = config[PaytypeUtil.CFG_ALIPAY_NOTIFY]
+            request.returnUrl = config[PaytypeUtil.CFG_ALIPAY_RETURNURL]
+            try {
+                /**
+                 * h5 支付方式
+                 * String form = alipayClient.pageExecute(request).getBody();
+                 *
+                 * */
+                val response = alipayClient.sdkExecute(request)
+                if (response.isSuccess) {
+                    agentResponse.agentRefno = response.tradeNo
+                    agentResponse.code = AgentCode.REQUIRE_QUERY
+                    agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS
+                    //body 为APP
+                    agentResponse.agentMsg = response.body
+                } else {
+                    agentResponse.code = AgentCode.FAIL
+                    agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                    agentResponse.agentMsg = response.subMsg
+                    logger.error { "支付宝:${response.code},${response.msg},${response.subCode},${response.subMsg}" }
+                }
+            } catch (e: AlipayApiException) {
+                logger.error { "支付宝:${e.message}" }
+                agentResponse.code = AgentCode.FAIL
+                agentResponse.agentMsg = "调用支付宝异常"
+                agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            }
+        }
+        return agentResponse
+    }
+
+    override fun doRefund(transaction: TTransactionMain): AgentResponse {
+        var agentResponse = AgentResponse()
+        val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_ALIPAY, transaction.shopDtl.shopaccno, false, false)
+        if (checkCfg(config, agentResponse)) {
+            var payurl = config[PaytypeUtil.CFG_ALIPAY_PAYURL]
+            if (payurl.isNullOrEmpty()) {
+                payurl = "https://openapi.alipay.com/gateway.do"
+            }
+            val alipayClient = DefaultAlipayClient(payurl, config[PaytypeUtil.CFG_ALIPAY_APPID], config[PaytypeUtil.CFG_ALIPAY_PRIVATEKEY], "json", "UTF-8", config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY], "RSA2")
+            val request = AlipayTradeQueryRequest()
+            request.bizModel = AlipayTradeRefundModel().apply {
+                this.outTradeNo = transaction.refno
+                this.refundAmount = transaction.shopDtl.amount.toString()
+            }
+            val response = alipayClient.execute(request)
+            if (response.isSuccess) {
+                agentResponse.code = AgentCode.SUCCESS
+                agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS
+                agentResponse.dtlStatus = DtlStatus.REFUND
+            } else {
+                agentResponse.code = AgentCode.FAIL
+                agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                agentResponse.agentMsg = "支付宝退款失败"
+            }
+        }
+        return agentResponse
+    }
+
+    override fun doQuery(transaction: TTransactionMain): AgentResponse {
+        var agentResponse = AgentResponse()
+        val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_ALIPAY, transaction.shopDtl.shopaccno, false, false)
+        if (checkCfg(config, agentResponse)) {
+            var payurl = config[PaytypeUtil.CFG_ALIPAY_PAYURL]
+            if (payurl.isNullOrEmpty()) {
+                payurl = "https://openapi.alipay.com/gateway.do"
+            }
+            val alipayClient = DefaultAlipayClient(payurl, config[PaytypeUtil.CFG_ALIPAY_APPID], config[PaytypeUtil.CFG_ALIPAY_PRIVATEKEY], "json", "UTF-8", config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY], "RSA2")
+            val request = AlipayTradeQueryRequest()
+            request.bizModel = AlipayTradeQueryModel().apply {
+                this.outTradeNo = transaction.refno
+            }
+            val response = alipayClient.execute(request)
+            if (response.isSuccess) {
+                //check response.totalAmount
+                agentResponse.code = AgentCode.SUCCESS
+                agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS
+                when (response.tradeStatus) {
+                    "TRADE_SUCCESS", "TRADE_FINISHED" -> agentResponse.dtlStatus = DtlStatus.SUCCESS
+                    "TRADE_CLOSED" -> agentResponse.dtlStatus = DtlStatus.REFUND
+                    "WAIT_BUYER_PAY" -> agentResponse.dtlStatus = DtlStatus.WAIT
+                }
+            } else {
+                agentResponse.code = AgentCode.FAIL
+                agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                agentResponse.agentMsg = "支付宝查询失败"
+            }
+        }
+        return agentResponse
+    }
+
+    override fun doNotify(param: Map<String, String>): AgentResponse {
+        var refno = param["out_trade_no"]
+        var agentResponse = AgentResponse()
+        if (refno.isNullOrEmpty()) {
+            agentResponse.code = AgentCode.FAIL
+            agentResponse.agentMsg = "返回流水号为空"
+            agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            return agentResponse
+        }
+        var transaction = consumePayService.getTransactionMainDtl(refno, null, null)
+        if (transaction == null) {
+            agentResponse.code = AgentCode.REFNO_NOT_EXISTS
+            agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            return agentResponse
+        }
+        if (transaction.status == TradeDict.DTL_STATUS_SUCCESS) {
+            agentResponse.code = AgentCode.SUCCESS
+            agentResponse.agentMsg = "流水已成功,不能重复入账"
+            agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            return agentResponse
+        }
+        val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_ALIPAY, transaction.shopDtl.shopaccno, false, false)
+        if (config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY].isNullOrEmpty()) {
+            agentResponse.code = AgentCode.CONFIG_ERROR
+            agentResponse.agentMsg = "商户公钥未配置"
+            agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            return agentResponse
+        }
+        var flag = AlipaySignature.rsaCheckV1(param, config[PaytypeUtil.CFG_ALIPAY_PUBLICKEY], "UTF-8", "RSA2")
+        return when (flag) {
+            true -> {
+                //total amt 校验 map["total_amount"]
+                transactionService.success(refno)
+                agentResponse.code = AgentCode.SUCCESS
+                agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS
+                agentResponse
+            }
+            false -> {
+                logger.error { "支付宝签名校验错误" }
+                agentResponse.code = AgentCode.FAIL
+                agentResponse.agentMsg = "签名校验错误"
+                agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                agentResponse
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/wechat_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/wechat_service_impl.kt
new file mode 100644
index 0000000..e3beb79
--- /dev/null
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/wechat_service_impl.kt
@@ -0,0 +1,263 @@
+package com.supwisdom.dlpay.agent.service.impl
+
+import com.supwisdom.dlpay.agent.AgentCode
+import com.supwisdom.dlpay.agent.AgentResponse
+import com.supwisdom.dlpay.agent.DtlStatus
+import com.supwisdom.dlpay.agent.service.AgentServiceProxy
+import com.supwisdom.dlpay.agent.service.WechatService
+import com.supwisdom.dlpay.api.bean.WechatReqResp
+import com.supwisdom.dlpay.api.dao.PersonIdentityDao
+import com.supwisdom.dlpay.api.domain.TTransactionMain
+import com.supwisdom.dlpay.api.service.ConsumePayService
+import com.supwisdom.dlpay.api.service.SourceTypeService
+import com.supwisdom.dlpay.api.service.TransactionServiceProxy
+import com.supwisdom.dlpay.framework.util.*
+import com.supwisdom.dlpay.util.PaytypeUtil
+import mu.KotlinLogging
+import org.apache.commons.lang.StringUtils
+import org.springframework.stereotype.Service
+import org.springframework.web.client.RestTemplate
+
+
+@Service
+class WechatServiceImpl(val sourceTypeService: SourceTypeService,
+                        val agentServiceProxy: AgentServiceProxy,
+                        val personIdentityDao: PersonIdentityDao,
+                        val consumePayService: ConsumePayService,
+                        val transactionService: TransactionServiceProxy,
+                        val restTemplate: RestTemplate) : WechatService {
+
+    val logger = KotlinLogging.logger { }
+
+    fun checkCfg(config: Map<String, String?>, resp: AgentResponse): Boolean {
+        if (config[PaytypeUtil.CFG_WECHAT_APPID].isNullOrEmpty()
+                || config[PaytypeUtil.CFG_WECHAT_MECHKEY].isNullOrEmpty()
+                || config[PaytypeUtil.CFG_WECHAT_MECHID].isNullOrEmpty()) {
+            resp.code = AgentCode.CONFIG_ERROR
+            resp.agentCode = AgentResponse.AGENTCODE_FAIL
+            resp.agentMsg = "微信相关配置为空"
+            logger.error { "请检查:${PaytypeUtil.CFG_WECHAT_APPID},${PaytypeUtil.CFG_WECHAT_MECHID},${PaytypeUtil.CFG_WECHAT_MECHKEY}" }
+            return false
+        }
+        return true
+    }
+
+    override fun doAuth(shopaccno: String?, billno: String?): AgentResponse {
+        var qrcodeTrans = agentServiceProxy.qrcodePayTransFindByMerchIdAndBillno(shopaccno, billno)
+        var agentResponse = AgentResponse()
+        if (qrcodeTrans == null) {
+            agentResponse.code = AgentCode.REFNO_NOT_EXISTS
+            agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            return agentResponse
+        }
+        val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_WECHAT, shopaccno, qrcodeTrans.isAnonymous, false)
+        if (checkCfg(config, agentResponse)) {
+            val bean = WechatReqResp().apply {
+                this.appid = config[PaytypeUtil.CFG_WECHAT_APPID]
+                this.auth_code = qrcodeTrans.qrcode
+                this.mch_id = config[PaytypeUtil.CFG_WECHAT_MECHID]
+                this.key = config[PaytypeUtil.CFG_WECHAT_MECHKEY]
+            }
+            bean.generalCheckSign()
+            var xml = bean.generalCheckXML()
+            var res = restTemplate.postForEntity(PaytypeUtil.CFG_WECHAT_OAUTHCODE, xml, String::class.java)
+            var eleMap = XmlUtils.parseXml(res.body)
+            var retcode = eleMap["return_code"]
+            var resultCode = eleMap["result_code"]
+            var openid = eleMap["openid"]
+            if (!retcode.isNullOrEmpty() && "SUCCESS" == retcode
+                    && !resultCode.isNullOrEmpty() && "SUCCESS" == resultCode && !openid.isNullOrEmpty()) {
+                qrcodeTrans.agentUserId = openid
+                var ip = personIdentityDao.getByThirdUid(openid)
+                if (ip != null) {
+                    qrcodeTrans.agentUserId = ip.person.userid
+                }
+                agentServiceProxy.qrcodePayTransSaveOrUpdate(qrcodeTrans)
+                agentResponse.code = AgentCode.SUCCESS
+                agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS
+            } else {
+                logger.error { "code=${eleMap["err_code"]},des=${eleMap["err_code_des"]}" }
+                agentResponse.code = AgentCode.FAIL
+                agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                agentResponse.agentMsg = "二维码身份查询失败"
+            }
+        }
+        return agentResponse
+    }
+
+    override fun doQrcodepay(transaction: TTransactionMain): AgentResponse {
+        var qrcodeTrans = agentServiceProxy.qrcodePayTransFindByRefno(transaction.refno)
+        var agentResponse = AgentResponse()
+        if (qrcodeTrans == null) {
+            agentResponse.code = AgentCode.REFNO_NOT_EXISTS
+            agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            return agentResponse
+        }
+        val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_WECHAT, transaction.shopDtl.shopaccno, qrcodeTrans.isAnonymous, false)
+        if (checkCfg(config, agentResponse)) {
+            val bean = WechatReqResp().apply {
+                this.appid = config[PaytypeUtil.CFG_WECHAT_APPID]
+                this.auth_code = qrcodeTrans.qrcode
+                this.mch_id = config[PaytypeUtil.CFG_WECHAT_MECHID]
+                this.key = config[PaytypeUtil.CFG_WECHAT_MECHKEY]
+                this.out_trade_no = transaction.refno
+                this.total_fee = MoneyUtil.YuanToFen(transaction.shopDtl.amount)
+                this.spbill_create_ip = qrcodeTrans.spip
+            }
+
+            bean.generalPaySign()
+            var xml = bean.generaPayXML()
+            var res = restTemplate.postForEntity(PaytypeUtil.CFG_WECHAT_QRCODEPAY, xml, String::class.java)
+            var eleMap = XmlUtils.parseXml(res.body)
+            var retcode = eleMap["return_code"]
+            var resultCode = eleMap["result_code"]
+            var openid = eleMap["openid"]
+            if (!retcode.isNullOrEmpty() && "SUCCESS" == retcode
+                    && !resultCode.isNullOrEmpty() && "SUCCESS" == resultCode && !openid.isNullOrEmpty()) {
+                agentResponse.code = AgentCode.SUCCESS
+                agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS
+                agentResponse.dtlStatus = DtlStatus.SUCCESS
+            } else {
+                logger.error { "code=${eleMap["err_code"]},des=${eleMap["err_code_des"]}" }
+                agentResponse.code = AgentCode.REQUIRE_QUERY
+                agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                agentResponse.agentMsg = "请查询支付结果"
+            }
+        }
+        return agentResponse
+    }
+
+    override fun doPrepay(transaction: TTransactionMain): AgentResponse {
+        var agentResponse = AgentResponse()
+
+        val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_WECHAT, transaction.shopDtl.shopaccno, false, false)
+        if (checkCfg(config, agentResponse)) {
+            //H5 支付
+            val bean = WechatReqResp().apply {
+                this.appid = config[PaytypeUtil.CFG_WECHAT_APPID]
+                this.mch_id = config[PaytypeUtil.CFG_WECHAT_MECHID]
+                this.key = config[PaytypeUtil.CFG_WECHAT_MECHKEY]
+                this.out_trade_no = transaction.refno
+                this.total_fee = MoneyUtil.YuanToFen(transaction.shopDtl.amount)
+                this.spbill_create_ip = ""
+                this.body = "微信支付"
+                this.trade_type = "MWEB"
+                this.notify_url = config[PaytypeUtil.CFG_WECHAT_NOTIFY]
+                this.scene_info = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"" + config[PaytypeUtil.CFG_WECHAT_NOTIFY] + "\",\"wap_name\": \"微信支付\"}}"
+            }
+            //TODO IP 问题
+            bean.generaSign()
+            val xml = bean.generaXML()
+            var res = restTemplate.postForEntity(PaytypeUtil.CFG_WECHAT_UNIONPAY, xml, String::class.java)
+            var eleMap = XmlUtils.parseXml(res.body)
+            var retcode = eleMap["return_code"]
+            var resultCode = eleMap["result_code"]
+            val mweb_url = eleMap["mweb_url"]
+            if (!retcode.isNullOrEmpty() && "SUCCESS" == retcode
+                    && !resultCode.isNullOrEmpty() && "SUCCESS" == resultCode && !mweb_url.isNullOrEmpty()) {
+                agentResponse.code = AgentCode.REQUIRE_QUERY
+                agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS
+                agentResponse.agentMsg = mweb_url
+                agentResponse.agentRefno = eleMap["prepay_id"]
+            } else {
+                logger.error { "code=${eleMap["err_code"]},des=${eleMap["err_code_des"]}" }
+                agentResponse.code = AgentCode.FAIL
+                agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                agentResponse.agentMsg = "预下单失败"
+            }
+        }
+        return agentResponse
+    }
+
+    override fun doQuery(transaction: TTransactionMain): AgentResponse {
+        var agentResponse = AgentResponse()
+        val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_WECHAT, transaction.shopDtl.shopaccno, false, false)
+        if (checkCfg(config, agentResponse)) {
+            //H5 支付
+            val bean = WechatReqResp().apply {
+                this.appid = config[PaytypeUtil.CFG_WECHAT_APPID]
+                this.mch_id = config[PaytypeUtil.CFG_WECHAT_MECHID]
+                this.key = config[PaytypeUtil.CFG_WECHAT_MECHKEY]
+                this.out_trade_no = transaction.refno
+            }
+            bean.generalQuerySign()
+            val xml = bean.generalQueryXML()
+            var res = restTemplate.postForEntity(PaytypeUtil.CFG_WECHAT_QUERY, xml, String::class.java)
+            var eleMap = XmlUtils.parseXml(res.body)
+            var retcode = eleMap["return_code"]
+            var resultCode = eleMap["result_code"]
+            val trade_state = eleMap["trade_state"]
+            if (!retcode.isNullOrEmpty() && "SUCCESS" == retcode
+                    && !resultCode.isNullOrEmpty() && "SUCCESS" == resultCode) {
+                agentResponse.code = AgentCode.REQUIRE_QUERY
+                agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS
+                when (trade_state) {
+                    "SUCCESS" -> agentResponse.dtlStatus = DtlStatus.SUCCESS
+                    "REFUND" -> agentResponse.dtlStatus = DtlStatus.REFUND
+                    "NOTPAY", "CLOSED", "REVOKED", "PAYERROR" -> agentResponse.dtlStatus = DtlStatus.FAIL
+                    "USERPAYING" -> agentResponse.dtlStatus = DtlStatus.WAIT
+                }
+            } else {
+                logger.error { "code=${eleMap["err_code"]},des=${eleMap["err_code_des"]}" }
+                agentResponse.code = AgentCode.FAIL
+                agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+                agentResponse.agentMsg = "查询失败"
+            }
+        }
+        return agentResponse
+    }
+
+    override fun doRefund(transaction: TTransactionMain): AgentResponse {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun doNotify(param: Map<String, String>): AgentResponse {
+        var agentResponse = AgentResponse()
+        var transaction = consumePayService.getTransactionMainDtl(param["out_trade_no"], null, null)
+        if (transaction == null) {
+            agentResponse.code = AgentCode.REFNO_NOT_EXISTS
+            agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            return agentResponse
+        }
+        if (transaction.status == TradeDict.DTL_STATUS_SUCCESS) {
+            agentResponse.code = AgentCode.SUCCESS
+            agentResponse.agentMsg = "流水已成功,不能重复入账"
+            agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            return agentResponse
+        }
+        val sign = param["sign"]
+        if (StringUtils.isEmpty(sign)) {
+            logger.error("签名错误")
+            agentResponse.code = AgentCode.FAIL
+            agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            agentResponse.agentMsg = "签名错误"
+        }
+        var temp = StringUtil.paraFilter(param)
+        var signStr = StringUtil.createLinkString(temp)
+        val config = sourceTypeService.getConsumePaytypeConfig(TradeDict.PAYTYPE_WECHAT, transaction.shopDtl.shopaccno, false, false)
+        var key = config[PaytypeUtil.CFG_WECHAT_MECHKEY]
+        signStr += "&key=$key"
+        val signRet = MD5.encodeByMD5(signStr)
+        logger.error("*******signStr=$signStr")
+        if (!signRet.equals(sign, ignoreCase = true)) {
+            logger.error("签名错误:$signRet,$sign")
+            agentResponse.code = AgentCode.FAIL
+            agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            agentResponse.agentMsg = "签名错误"
+        }
+        val returnCode = param["return_code"]
+        val resultCode = param["result_code"]
+        if (!returnCode.isNullOrEmpty() && "SUCCESS" == returnCode
+                && !resultCode.isNullOrEmpty() && "SUCCESS" == resultCode) {
+            transactionService.success(transaction.refno)
+            agentResponse.code = AgentCode.SUCCESS
+            agentResponse.agentCode = AgentResponse.AGENTCODE_SUCCESS
+        } else {
+            agentResponse.code = AgentCode.FAIL
+            agentResponse.agentCode = AgentResponse.AGENTCODE_FAIL
+            agentResponse.agentMsg = "${param["err_code"]}:${param["err_code_des"]}"
+            logger.error { "code=${param["err_code"]},des=${param["err_code_des"]}" }
+        }
+        return agentResponse
+    }
+}
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/wechat_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/wechat_service.kt
new file mode 100644
index 0000000..380221c
--- /dev/null
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/wechat_service.kt
@@ -0,0 +1,56 @@
+package com.supwisdom.dlpay.agent.service
+
+import com.supwisdom.dlpay.agent.AgentCode
+import com.supwisdom.dlpay.agent.AgentPayService
+import com.supwisdom.dlpay.agent.AgentResponse
+import com.supwisdom.dlpay.api.domain.TTransactionMain
+import com.supwisdom.dlpay.api.service.ConsumePayService
+import com.supwisdom.dlpay.framework.util.TradeCode
+import com.supwisdom.dlpay.framework.util.TradeDict
+import org.springframework.stereotype.Component
+
+interface WechatService {
+    fun doAuth(shopaccno: String?, billno: String?): AgentResponse
+
+    fun doQrcodepay(transaction: TTransactionMain): AgentResponse
+
+    fun doPrepay(transaction: TTransactionMain): AgentResponse
+
+    fun doQuery(transaction: TTransactionMain): AgentResponse
+
+    fun doRefund(transaction: TTransactionMain): AgentResponse
+
+    fun doNotify(param: Map<String, String>): AgentResponse
+}
+
+@Component("wechatpayAgent")
+class WeChatPayAgentService(val consumePayService: ConsumePayService,
+                            val wechatService: WechatService) : AgentPayService {
+    override fun auth(shopaccno: String?, billno: String?): AgentResponse {
+        if (consumePayService.checkShopPaytype(shopaccno!!, TradeDict.PAYTYPE_WECHAT, true)) {
+            return wechatService.doAuth(shopaccno, billno)
+        }
+        return AgentResponse().apply {
+            this.code = AgentCode.NOT_SUPPORT
+        }
+    }
+
+    override fun pay(transaction: TTransactionMain?): AgentResponse {
+        return when (transaction!!.transCode) {
+            TradeCode.TRANSCODE_QRCODE -> wechatService.doQrcodepay(transaction!!)
+            else -> wechatService.doPrepay(transaction!!)
+        }
+    }
+
+    override fun cancel(transaction: TTransactionMain?): AgentResponse {
+        return refund(transaction)
+    }
+
+    override fun refund(transaction: TTransactionMain?): AgentResponse {
+        return wechatService.doRefund(transaction!!)
+    }
+
+    override fun query(transaction: TTransactionMain?): AgentResponse {
+        return wechatService.doQuery(transaction!!)
+    }
+}
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/weichat_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/weichat_service.kt
deleted file mode 100644
index dc748d7..0000000
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/weichat_service.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.supwisdom.dlpay.agent.service
-
-import com.supwisdom.dlpay.agent.AgentCode
-import com.supwisdom.dlpay.agent.AgentPayService
-import com.supwisdom.dlpay.agent.AgentResponse
-import com.supwisdom.dlpay.api.domain.TTransactionMain
-import org.springframework.stereotype.Component
-
-@Component("wechatpayAgent")
-class WeChatPayAgentService : AgentPayService {
-    override fun auth(shopaccno: String?, billno: String?): AgentResponse {
-        return AgentResponse().apply {
-            this.code = AgentCode.NOT_SUPPORT
-        }
-    }
-
-    override fun pay(transaction: TTransactionMain?): AgentResponse {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-
-    override fun cancel(transaction: TTransactionMain?): AgentResponse {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-
-    override fun refund(transaction: TTransactionMain?): AgentResponse {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-
-    override fun query(transaction: TTransactionMain?): AgentResponse {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
-    }
-}
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
index 9d923d2..3751c40 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
@@ -20,6 +20,7 @@
 import org.springframework.http.ResponseEntity
 import org.springframework.validation.annotation.Validated
 import org.springframework.web.bind.annotation.*
+import javax.servlet.http.HttpServletRequest
 import javax.validation.Valid
 
 @RestController
@@ -548,6 +549,7 @@
                     .fail(apiResponse, TradeErrorCode.BUSINESS_DEAL_ERROR,
                             "支付方式<${qrcodeTrans.sourceType}>不支持匿名支付"))
         }
+        qrcodeTrans.spip = param.spip
 
         //2. 初始化交易流水
         // sourcetype 资产类科目