增加第三方in app 支付类接口
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentPayServiceContext.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentPayServiceContext.java
index a17a1fc..79e0470 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentPayServiceContext.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentPayServiceContext.java
@@ -28,4 +28,18 @@
       return null;
     }
   }
+
+  public <T> InAppPayService<T> findInAppPayService(String service) {
+    try {
+      Object bean = applicationContext.getBean(service + "InAppAgent");
+      if (bean instanceof InAppPayService) {
+        return (InAppPayService<T>) bean;
+      } else {
+        return null;
+      }
+    } catch (BeansException ex) {
+      log.error("can't create bean <{}> , ex {}", service, ex.getMessage());
+      return null;
+    }
+  }
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/InAppPayService.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/InAppPayService.java
new file mode 100644
index 0000000..47f51d9
--- /dev/null
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/InAppPayService.java
@@ -0,0 +1,37 @@
+package com.supwisdom.dlpay.agent;
+
+import com.supwisdom.dlpay.api.domain.TTransactionMain;
+import org.springframework.http.HttpRequest;
+
+/**
+ * 微信、支付宝、银联等第三方支付平台 H5 , JSAPI , Native , 小程序等手机端支付接口
+ *
+ * @param <T>
+ */
+public interface InAppPayService<T> {
+  /**
+   * 支付初始化,由客户端发起,服务端请求第三方支付平台进行交易初始化
+   * 第三方平台会返回支付相关参数,服务端根据需要保存参数,并返回给上层处理
+   *
+   * @param transation
+   * @return
+   */
+  AgentResponse<T> init(TTransactionMain transation);
+
+  /**
+   * 当用支付完成后,第三方支付平台会发起通知给服务端,由服务端处理后续业务
+   *
+   * @param transaction - 交易参数
+   * @param request     - 第三方平台通知请求的 HttpRequest
+   * @return
+   */
+  AgentResponse<T> notify(TTransactionMain transaction, HttpRequest request);
+
+  /**
+   * 由服务端主动发起的查询第三方支付平交易情况
+   *
+   * @param transation - 交易参数
+   * @return
+   */
+  AgentResponse<T> query(TTransactionMain transation);
+}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/InAppPayTrans.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/InAppPayTrans.java
new file mode 100644
index 0000000..933557a
--- /dev/null
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/InAppPayTrans.java
@@ -0,0 +1,45 @@
+package com.supwisdom.dlpay.agent.domain;
+
+import org.joda.time.DateTime;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.sql.Timestamp;
+import java.time.Instant;
+
+@Entity
+@Table(name = "tb_inapp_pay_trans")
+@SequenceGenerator(name = "inapp_pay_trans_seq")
+public class InAppPayTrans implements Serializable {
+  private static final long serialVersionUID = 4414357931991577103L;
+
+  @Id
+  @Column(name = "id")
+  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "inapp_pay_trans_seq")
+  private Integer id;
+
+  @Column(name = "refno")
+  @NotNull
+  private String refno;
+
+  @Column(name = "sourcetype")
+  @NotNull
+  private String sourceType;
+
+  @Column(name = "agent_refno")
+  private String agentRefno;
+
+  @Column(name = "create_time")
+  private Timestamp createTime;
+
+  @Column(name = "update_time")
+  private Timestamp updateTime;
+
+  @PrePersist
+  public void prePersist() {
+    if (this.createTime == null) {
+      this.createTime = Timestamp.from(Instant.now());
+    }
+  }
+}
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/inapp_alipay.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/inapp_alipay.kt
new file mode 100644
index 0000000..b0bcc31
--- /dev/null
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/inapp_alipay.kt
@@ -0,0 +1,26 @@
+package com.supwisdom.dlpay.agent.service
+
+import com.supwisdom.dlpay.agent.AgentResponse
+import com.supwisdom.dlpay.agent.InAppPayService
+import com.supwisdom.dlpay.api.domain.TTransactionMain
+import org.springframework.http.HttpRequest
+import org.springframework.stereotype.Component
+
+class AlipayInAppResponse {
+
+}
+
+@Component("alipayInAppAgent")
+class AlipayInAppServcie : InAppPayService<AlipayInAppResponse> {
+    override fun init(transation: TTransactionMain?): AgentResponse<AlipayInAppResponse> {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun notify(transaction: TTransactionMain?, request: HttpRequest?): AgentResponse<AlipayInAppResponse> {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun query(transation: TTransactionMain?): AgentResponse<AlipayInAppResponse> {
+        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/agent/service/inapp_wechatpay.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/inapp_wechatpay.kt
new file mode 100644
index 0000000..2022d9a
--- /dev/null
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/inapp_wechatpay.kt
@@ -0,0 +1,30 @@
+package com.supwisdom.dlpay.agent.service
+
+import com.supwisdom.dlpay.agent.AgentResponse
+import com.supwisdom.dlpay.agent.InAppPayService
+import com.supwisdom.dlpay.api.domain.TTransactionMain
+import com.supwisdom.dlpay.api.service.SourceTypeService
+import org.springframework.http.HttpRequest
+import org.springframework.stereotype.Component
+
+class WechatPayResponse {
+    var preId: String = "";
+}
+
+@Component("wechatInAppAgent")
+class WechatInAppService(private val sourceTypeService: SourceTypeService)
+    : InAppPayService<WechatPayResponse> {
+    val APIUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"
+
+    override fun init(transation: TTransactionMain?): AgentResponse<WechatPayResponse> {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun notify(transaction: TTransactionMain?, request: HttpRequest?): AgentResponse<WechatPayResponse> {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun query(transation: TTransactionMain?): AgentResponse<WechatPayResponse> {
+        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/transaction_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/transaction_controller.kt
index 63312ad..44e0753 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/transaction_controller.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/transaction_controller.kt
@@ -1,10 +1,14 @@
 package com.supwisdom.dlpay.api.controller
 
+import com.supwisdom.dlpay.agent.AgentCode
+import com.supwisdom.dlpay.agent.AgentPayServiceContext
+import com.supwisdom.dlpay.agent.InAppPayService
 import com.supwisdom.dlpay.api.TransactionBuilder
 import com.supwisdom.dlpay.api.bean.InAppPayParam
 import com.supwisdom.dlpay.api.bean.InAppPayResponse
 import com.supwisdom.dlpay.api.bean.TransactionQueryResponse
 import com.supwisdom.dlpay.api.domain.TSourceType
+import com.supwisdom.dlpay.api.domain.TTransactionMain
 import com.supwisdom.dlpay.api.service.AccountUtilServcie
 import com.supwisdom.dlpay.api.service.SourceTypeService
 import com.supwisdom.dlpay.api.service.TransactionServiceProxy
@@ -19,6 +23,7 @@
 import org.springframework.context.annotation.Lazy
 import org.springframework.data.redis.connection.RedisConnectionFactory
 import org.springframework.data.redis.core.RedisTemplate
+import org.springframework.http.HttpRequest
 import org.springframework.http.ResponseEntity
 import org.springframework.web.bind.annotation.GetMapping
 import org.springframework.web.bind.annotation.PathVariable
@@ -33,27 +38,45 @@
                             private val systemUtilService: SystemUtilService,
                             private val accountUtilServcie: AccountUtilServcie,
                             private val sourceTypeService: SourceTypeService,
+                            private val agentPayServiceContext: AgentPayServiceContext,
                             redisConnectionFactory: RedisConnectionFactory) {
 
     private val transactionContainer = TransactionContainer("inapp.pay", redisConnectionFactory)
 
+    fun doQuery(transaction: TTransactionMain, agent: InAppPayService<Any>): TTransactionMain {
+        val agentResponse = agent.query(transaction)
+        return when (agentResponse.agentCode) {
+            AgentCode.REQUIRE_QUERY.value() -> {
+                transaction
+            }
+            AgentCode.SUCCESS.value() -> {
+                transactionServiceProxy.success(transaction.refno)
+
+            }
+            else -> {
+                transactionServiceProxy.fail(transaction.refno, agentResponse.agentMsg)
+            }
+        }
+    }
+
     @GetMapping("/inapp/query")
     fun queryTransaction(refno: String): ResponseEntity<*> {
-        val tranaction = transactionServiceProxy.findTransactionByRefno(refno)
+        val transaction = transactionServiceProxy.findTransactionByRefno(refno)
                 ?: return ResponseBodyBuilder.notFound("未找到流水")
-        if (tranaction.tenantid != TenantContextHolder.getContext().tenant.id) {
+        if (transaction.tenantid != TenantContextHolder.getContext().tenant.id) {
             return ResponseBodyBuilder.conflict("未找到流水")
         }
 
-        if (tranaction.status != TradeDict.DTL_STATUS_SUCCESS) {
-            transactionContainer.add(refno)
-            // 查询第三方
-            transactionContainer.remove(refno)
+        val agent = agentPayServiceContext.findInAppPayService<Any>(transaction.sourceType)
+                ?: return ResponseBodyBuilder.notFound("支付类别不支持 <${transaction.sourceType}>")
+        val resultTrans = when (transaction.status) {
+            TradeDict.DTL_STATUS_WIP -> doQuery(transaction, agent)
+            else -> transaction
         }
         return ResponseBodyBuilder.successEntity(TransactionQueryResponse().apply {
-            this.refno = tranaction.refno
-            accdate = tranaction.accdate
-            status = tranaction.status
+            this.refno = resultTrans.refno
+            accdate = resultTrans.accdate
+            status = resultTrans.status
             hostdate = systemUtilService.sysdatetime.hostdate
             hosttime = systemUtilService.sysdatetime.hosttime
         }, "成功")
@@ -71,11 +94,14 @@
     fun inAppPayInit(@Valid param: InAppPayParam): ResponseEntity<*> {
         val response = InAppPayResponse()
         if (transactionContainer.count() > 100) {
-            return ResponseBodyBuilder.serviceUnavailable("第三方请求异常")
+            return ResponseBodyBuilder.internalServerError("第三方请求异常")
         }
         val sourceType = sourceTypeService.getBySourceType(param.sourceType)
                 ?: return ResponseBodyBuilder.badRequest("source type <${param.sourceType}> 不存在")
 
+        val agent = agentPayServiceContext.findInAppPayService<Any>(sourceType.sourceType)
+                ?: return ResponseBodyBuilder.badRequest("不支持支付方式<${sourceType.sourceType}>")
+
         val subject = accountUtilServcie.readSubject(sourceType.depositeSubjno)
 
         val tradeCode = when (param.inAppType) {
@@ -133,9 +159,14 @@
         }
         val transaction = transactionServiceProxy.init(builder)
         // 调用第三方完成交易初始化
-
         transactionServiceProxy.wip(transaction.refno)
         transactionContainer.add(transaction.refno)
+        val agentResponse = agent.init(transaction)
+        if (agentResponse.code != AgentCode.SUCCESS) {
+            return ResponseBodyBuilder
+                    .internalServerError("请求第三方支付平台失败,${agentResponse.agentMsg}")
+        }
+
         response.apply {
             when (param.recipientType) {
                 "shop" -> actuallyAmount = (transaction.shopDtl.amount * 100).roundToInt()
@@ -181,16 +212,33 @@
 
 @RestController("/api/notify")
 class TransactionNotifyController(@Lazy private val tenantDetailsRegistrar: TenantDetailsRegistrar,
-                                  private val transactionServiceProxy: TransactionServiceProxy) {
+                                  private val transactionServiceProxy: TransactionServiceProxy,
+                                  private val agentPayServiceContext: AgentPayServiceContext) {
 
-    @PostMapping("/inapp/alipay/{tenant}")
-    fun inAppPayCallback(@PathVariable("tenant") tenant: String,
-                         refno: String): ResponseEntity<*> {
+    @PostMapping("/inapp/{sourcetype}/{tenant}")
+    fun inAppPayCallback(@PathVariable("sourcetype") sourcetype: String,
+                         @PathVariable("tenant") tenant: String,
+                         refno: String,
+                         request: HttpRequest): ResponseEntity<*> {
         val tenantDetails = tenantDetailsRegistrar.getTenantDetailsById(tenant)
                 ?: return ResponseBodyBuilder.notFound("请求租户 <$tenant> 不存在")
+        val agent = agentPayServiceContext.findInAppPayService<Any>(sourcetype)
+                ?: return ResponseBodyBuilder.badRequest("请求支付类型错误 <$sourcetype> 不存在")
         TenantContextHolder.getContext().tenant = tenantDetails.get()
-        val transaction = transactionServiceProxy.success(refno)
-        return ResponseEntity.ok(ResponseBodyBuilder.create()
-                .data("refno", transaction.refno))
+        val transaction = transactionServiceProxy.findTransactionByRefno(refno)
+        val agentResponse = agent.notify(transaction, request)
+        if (agentResponse.code == AgentCode.SUCCESS) {
+            transactionServiceProxy.success(refno)
+        } else if (agentResponse.code == AgentCode.REQUIRE_QUERY) {
+            transaction
+        } else {
+            transactionServiceProxy.fail(refno, agentResponse.agentMsg)
+        }?.let {
+            return ResponseBodyBuilder.successEntity(InAppPayResponse().apply {
+                this.refno = it.refno
+                this.status = it.status
+            })
+        }
+        return ResponseBodyBuilder.internalServerError("请求参数错误")
     }
 }
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt
index 597dedf..54863ea 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt
@@ -55,8 +55,8 @@
             return fail(HttpStatus.UNAUTHORIZED, msg)
         }
 
-        fun serviceUnavailable(msg: String): ResponseEntity<*> {
-            return fail(HttpStatus.SERVICE_UNAVAILABLE, msg)
+        fun internalServerError(msg: String): ResponseEntity<*> {
+            return fail(HttpStatus.INTERNAL_SERVER_ERROR, msg)
         }
     }