From: Tang Cheng Date: Tue, 25 Feb 2020 01:04:15 +0000 (+0800) Subject: 增加第三方in app 支付类接口 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=6a93c6644ff622c64121e8767aecb8e5aec5a8cb;p=epayment%2Ffood_payapi.git 增加第三方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 a17a1fc8..79e04701 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 @@ public class AgentPayServiceContext { return null; } } + + public InAppPayService findInAppPayService(String service) { + try { + Object bean = applicationContext.getBean(service + "InAppAgent"); + if (bean instanceof InAppPayService) { + return (InAppPayService) 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 00000000..47f51d9f --- /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 + */ +public interface InAppPayService { + /** + * 支付初始化,由客户端发起,服务端请求第三方支付平台进行交易初始化 + * 第三方平台会返回支付相关参数,服务端根据需要保存参数,并返回给上层处理 + * + * @param transation + * @return + */ + AgentResponse init(TTransactionMain transation); + + /** + * 当用支付完成后,第三方支付平台会发起通知给服务端,由服务端处理后续业务 + * + * @param transaction - 交易参数 + * @param request - 第三方平台通知请求的 HttpRequest + * @return + */ + AgentResponse notify(TTransactionMain transaction, HttpRequest request); + + /** + * 由服务端主动发起的查询第三方支付平交易情况 + * + * @param transation - 交易参数 + * @return + */ + AgentResponse 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 00000000..933557aa --- /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 00000000..b0bcc319 --- /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 { + override fun init(transation: TTransactionMain?): AgentResponse { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun notify(transaction: TTransactionMain?, request: HttpRequest?): AgentResponse { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun query(transation: 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/agent/service/inapp_wechatpay.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/inapp_wechatpay.kt new file mode 100644 index 00000000..2022d9ad --- /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 { + val APIUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder" + + override fun init(transation: TTransactionMain?): AgentResponse { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun notify(transaction: TTransactionMain?, request: HttpRequest?): AgentResponse { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun query(transation: 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/transaction_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/transaction_controller.kt index 63312adb..44e0753b 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 com.supwisdom.multitenant.storage.TenantDetailsRegistrar 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 @@ class TransactionController(private val transactionServiceProxy: TransactionServ 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): 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(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 @@ class TransactionController(private val transactionServiceProxy: TransactionServ 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(sourceType.sourceType) + ?: return ResponseBodyBuilder.badRequest("不支持支付方式<${sourceType.sourceType}>") + val subject = accountUtilServcie.readSubject(sourceType.depositeSubjno) val tradeCode = when (param.inAppType) { @@ -133,9 +159,14 @@ class TransactionController(private val transactionServiceProxy: TransactionServ } 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 @@ class TransactionContainer(private val name: String, @RestController("/api/notify") class TransactionNotifyController(@Lazy private val tenantDetailsRegistrar: TenantDetailsRegistrar, - private val transactionServiceProxy: TransactionServiceProxy) { - - @PostMapping("/inapp/alipay/{tenant}") - fun inAppPayCallback(@PathVariable("tenant") tenant: String, - refno: String): ResponseEntity<*> { + private val transactionServiceProxy: TransactionServiceProxy, + private val agentPayServiceContext: AgentPayServiceContext) { + + @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(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 597dedf2..54863ea1 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 @@ class ResponseBodyBuilder private constructor() { 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) } }