完成二维码消费接口
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePayTransDao.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePayTransDao.java
index 1a54012..191eb57 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePayTransDao.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePayTransDao.java
@@ -2,10 +2,14 @@
import com.supwisdom.dlpay.agent.domain.QrcodePayTrans;
import org.springframework.data.jpa.repository.Lock;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.jpa.repository.QueryHints;
import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import javax.persistence.LockModeType;
+import javax.persistence.QueryHint;
@Repository
@@ -16,5 +20,11 @@
QrcodePayTrans findByAgentMerchIdAndHostdateAndBillnoAndTenantid(String agentMerchId, String hostdate,
String billno, String tenantid);
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
+ @Query("select t from QrcodePayTrans t where t.agentMerchId=:agentMerchId and t.hostdate=:hostdate and t.billno=:billno and t.tenantid=:tenantid")
+ @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "0")})
+ QrcodePayTrans findByQrcodePayTransForUpdate(@Param("agentMerchId") String agentMerchId,@Param("hostdate") String hostdate,
+ @Param("billno")String billno,@Param("tenantid") String tenantid);
+
void deleteByRefnoAndTenantid(String refno, String tenantid);
}
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 ec57610..4619435 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
@@ -68,7 +68,7 @@
@Column(name = "tenantid", length = 20)
private String tenantid;
- @Column(name = "spid", length = 20)
+ @Column(name = "spip", length = 20)
private String spip;
public QrcodePayTrans() {
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/service/AgentServiceProxy.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/service/AgentServiceProxy.java
index e33c0db..8eaf790 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/service/AgentServiceProxy.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/service/AgentServiceProxy.java
@@ -42,6 +42,11 @@
systemUtilService.getSysdatetime().getHostdate(), billno, TenantContextHolder.getContext().getTenant().getId());
}
+ public QrcodePayTrans findByQrcodePayTransForUpdate(String merchid, String billno) {
+ return qrcodeTransDao.findByQrcodePayTransForUpdate(merchid,
+ systemUtilService.getSysdatetime().getHostdate(), billno, TenantContextHolder.getContext().getTenant().getId());
+ }
+
public QrcodePayTrans qrcodePayTransSaveOrUpdate(@NotNull QrcodePayTrans bean) {
if (StringUtil.isEmpty(bean.getTenantid())) {
bean.setTenantid(TenantContextHolder.getContext().getTenant().getId());
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/ConsumeApi.java b/payapi/src/main/java/com/supwisdom/dlpay/api/ConsumeApi.java
index 7c59309..4625ca9 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/ConsumeApi.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/ConsumeApi.java
@@ -74,7 +74,7 @@
produces = { "application/json" },
consumes = { "application/json" },
method = RequestMethod.POST)
- default ResponseEntity<QrcodePayInitResponse> qrcodePayInit(@ApiParam(value = "租户ID" ,required=true) @RequestHeader(value="X-Tenant-Id", required=true) String xTenantId,@ApiParam(value = "QrCode 初始化" ) @Valid @RequestBody QrcodePayInitRequest qrcodePayInitRequest) {
+ default ResponseEntity<QrcodePayInitResponse> qrcodePayInit(@ApiParam(value = "租户ID" ,required=true) @RequestHeader(value="X-TENANT-ID", required=true) String xTenantId,@ApiParam(value = "QrCode 初始化" ) @Valid @RequestBody QrcodePayInitRequest qrcodePayInitRequest) {
getRequest().ifPresent(request -> {
for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
@@ -96,7 +96,7 @@
@RequestMapping(value = "/consume/qrcode/query/{refno}",
produces = { "application/json" },
method = RequestMethod.GET)
- default ResponseEntity<QrcodePayConfirmResponse> qrcodePayQuery(@ApiParam(value = "租户ID" ,required=true) @RequestHeader(value="X-Tenant-Id", required=true) String xTenantId,@ApiParam(value = "系统交易参考号",required=true) @PathVariable("refno") String refno) {
+ default ResponseEntity<QrcodePayConfirmResponse> qrcodePayQuery(@ApiParam(value = "租户ID" ,required=true) @RequestHeader(value="X-TENANT-ID", required=true) String xTenantId,@ApiParam(value = "系统交易参考号",required=true) @PathVariable("refno") String refno) {
getRequest().ifPresent(request -> {
for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/k12_consume_api_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/k12_consume_api_controller.kt
index 7d86677..7bf36cd 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/k12_consume_api_controller.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/k12_consume_api_controller.kt
@@ -3,21 +3,24 @@
import com.supwisdom.dlpay.agent.AgentCode
import com.supwisdom.dlpay.agent.AgentPayService
import com.supwisdom.dlpay.agent.AgentPayServiceContext
-import com.supwisdom.dlpay.agent.domain.QrcodePattern
import com.supwisdom.dlpay.agent.domain.QrcodePayTrans
import com.supwisdom.dlpay.agent.service.AgentServiceProxy
import com.supwisdom.dlpay.api.ConsumeApi
-import com.supwisdom.dlpay.api.service.*
+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.api.service.UserService
import com.supwisdom.dlpay.exception.BadRequestError
+import com.supwisdom.dlpay.exception.ConflictError
import com.supwisdom.dlpay.exception.TransactionCheckException
import com.supwisdom.dlpay.framework.ResponseBodyBuilder
import com.supwisdom.dlpay.framework.service.SystemUtilService
import com.supwisdom.dlpay.framework.util.StringUtil
+import com.supwisdom.dlpay.framework.util.TradeDict
import com.supwisdom.dlpay.framework.util.TradeErrorCode
-import com.supwisdom.dlpay.payapi.model.QrcodePayInitRequest
-import com.supwisdom.dlpay.payapi.model.QrcodePayInitResponse
-import com.supwisdom.multitenant.TenantContextHolder
+import com.supwisdom.dlpay.payapi.model.*
import org.apache.commons.lang3.StringUtils
+import org.springframework.dao.PessimisticLockingFailureException
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@@ -35,83 +38,90 @@
private val agentPayServiceContext: AgentPayServiceContext,
private val userService: UserService,
private val consumePayService: ConsumePayService,
- private val transactionService: TransactionServiceProxy,
- private val accountUtilServcie: AccountUtilServcie) : ConsumeApi {
+ private val transactionService: TransactionServiceProxy) : ConsumeApi {
override fun getRequest(): Optional<NativeWebRequest> {
return Optional.ofNullable(request)
}
override fun qrcodePayInit(xTenantId: String, @Valid param: QrcodePayInitRequest): ResponseEntity<QrcodePayInitResponse> {
- val apiResp = QrcodePayInitResponse()
- // 1. 检查 qrcode
- val qrcode: QrcodePattern
try {
- qrcode = agentServiceProxy.qrcodeMatch(param.qrcode)
+ val apiResp = QrcodePayInitResponse()
+ // 1. 检查 qrcode
+ val qrcode = agentServiceProxy.qrcodeMatch(param.qrcode)
?: throw BadRequestError("未识别的支付码")
- } catch (e: Exception) {
- throw BadRequestError(e.message!!)
- }
- val sourceType = sourceTypeService.getBySourceType(qrcode.sourceType)
- ?: throw BadRequestError("不支持的支付方式<${qrcode.sourceType}>")
- if (sourceType.paySubjno.isEmpty()
- || !StringUtils.isNumeric(sourceType.paySubjno)) {
- throw BadRequestError("支付方式<${qrcode.sourceType}>未配置科目号")
- }
- val systime = systemUtilService.sysdatetime
- // 2. 记录 qrcode 交易明细表
- val qrcodeTrans = agentServiceProxy.qrcodePayTransSaveOrUpdate(
- QrcodePayTrans().apply {
- this.agentMerchId = param.shopaccno
- this.billno = param.billno
- this.qrcode = param.qrcode
- this.createTime = systime.sysdate
- this.hostdate = systime.hostdate
- this.sourceType = sourceType.sourceType
- this.updateTime = systime.sysdate
- })
- // 3. 查询用户身份
- val service = createAgentService<QrcodePayTrans>(qrcode.sourceType)
- val agentResp = service.auth(param.shopaccno, param.billno)
- // 4. 重新读取 qrcode 交易明细表,以获取 service.auth 查询后的结果数据
- // 修改, 通过返回值来判断
+ val sourceType = sourceTypeService.getBySourceType(qrcode.sourceType)
+ ?: throw BadRequestError("不支持的支付方式<${qrcode.sourceType}>")
+ if (sourceType.paySubjno.isEmpty()
+ || !StringUtils.isNumeric(sourceType.paySubjno)) {
+ throw BadRequestError("支付方式<${qrcode.sourceType}>未配置科目号")
+ }
+ val systime = systemUtilService.sysdatetime
+ // 2. 记录 qrcode 交易明细表
+ val qrcodeTrans = agentServiceProxy.qrcodePayTransSaveOrUpdate(
+ QrcodePayTrans().apply {
+ this.agentMerchId = param.shopaccno
+ this.billno = param.billno
+ this.qrcode = param.qrcode
+ this.createTime = systime.sysdate
+ this.hostdate = systime.hostdate
+ this.sourceType = sourceType.sourceType
+ this.updateTime = systime.sysdate
+ this.isAnonymous = true
+ })
+ // 3. 查询用户身份
+ val service = createAgentService<QrcodePayTrans>(qrcode.sourceType)
+ val agentResp = service.auth(param.shopaccno, param.billno)
+ // 4. 重新读取 qrcode 交易明细表,以获取 service.auth 查询后的结果数据
+ // 修改, 通过返回值来判断
// val qrcodeTransResp = agentServiceProxy.qrcodePayTransFindByMerchIdAndBillno(qrcodeTrans.agentMerchId,
// qrcodeTrans.billno)
- apiResp.also {
- it.sourcetype = sourceType.sourceType
- }
- return when (agentResp.code) {
- AgentCode.SUCCESS -> {
- val qrcodeTransResp = agentResp.payload
- if (!sourceType.anonymousEnable && qrcodeTransResp.isAnonymous) {
- throw BadRequestError("支付方式<${qrcode.sourceType}> 不支持匿名支付")
- } else {
- // 更新qrcode交易明细表 是否匿名 字段
- if (StringUtil.isEmpty(qrcodeTransResp.userid)) {
- qrcodeTransResp.isAnonymous = true
+ apiResp.also {
+ it.sourcetype = sourceType.sourceType
+ }
+ return when (agentResp.code) {
+ AgentCode.SUCCESS -> {
+ val qrcodeTransResp = agentResp.payload
+ if (!sourceType.anonymousEnable && qrcodeTransResp.isAnonymous) {
+ throw BadRequestError("支付方式<${qrcode.sourceType}> 不支持匿名支付")
} else {
- val person = userService.findByUseridOrThirdUniqueIdenty(qrcodeTransResp.userid, null)
- if (person == null) {
+ // 更新qrcode交易明细表 是否匿名 字段
+ if (StringUtil.isEmpty(qrcodeTransResp.userid)) {
qrcodeTransResp.isAnonymous = true
} else {
- apiResp.apply {
- qrcodeTransResp.isAnonymous = false
- this.userid = qrcodeTransResp.agentUserId
- this.username = person.name
+ val person = userService.findByUseridOrThirdUniqueIdenty(qrcodeTransResp.userid, null)
+ if (person == null) {
+ qrcodeTransResp.isAnonymous = true
+ } else {
+ apiResp.apply {
+ qrcodeTransResp.isAnonymous = false
+ this.userid = qrcodeTransResp.agentUserId
+ this.username = person.name
+ }
}
}
+ agentServiceProxy.qrcodePayTransSaveOrUpdate(qrcodeTrans.also {
+ it.isAnonymous = qrcodeTransResp.isAnonymous
+ })
+ ResponseBodyBuilder.ok(apiResp)
}
- agentServiceProxy.qrcodePayTransSaveOrUpdate(qrcodeTrans.also {
- it.isAnonymous = qrcodeTransResp.isAnonymous
- })
- ResponseBodyBuilder.ok(apiResp)
+ }
+ AgentCode.NOT_SUPPORT -> {
+ throw BadRequestError("系统或商户暂不支持当前的支付类型}")
+ }
+ else -> {
+ throw BadRequestError("第三方身份错误,<${agentResp.agentMsg}")
}
}
- AgentCode.NOT_SUPPORT -> {
- throw BadRequestError("系统或商户暂不支持当前的支付类型}")
- }
- else -> {
- throw BadRequestError("第三方身份错误,<${agentResp.agentMsg}")
+ } catch (e: Exception) {
+ when (e) {
+ is BadRequestError -> throw BadRequestError(e.message)
+ is PessimisticLockingFailureException -> throw ConflictError(e.message)
+ else -> {
+ e.printStackTrace()
+ println("二维码消费初始化异常:<${e.message}>")
+ throw InternalError(e.message)
+ }
}
}
}
@@ -122,118 +132,97 @@
"支付类型<$sourceType>未定义")
}
-// override fun qrcodePayConfirm(xTenantId: String, @Valid param: QrcodePayConfirmRequest): ResponseEntity<Void> {
-// //1. 交易检查
-// val apiResponse = QrcodePayResponse()
-// val qrcodeTrans = agentServiceProxy.qrcodePayTransFindByMerchIdAndBillno(param.shopaccno,
-// param.billno) ?: return ResponseBodyBuilder.notFound(
-// "未找到billno") as ResponseEntity<Void>
-// if (!qrcodeTrans.refno.isNullOrEmpty()) {
-// return ResponseEntity.ok(ResponseBodyBuilder.create()
-// .fail(apiResponse, TradeErrorCode.BUSINESS_DEAL_ERROR, "该交易已确认,请查询结果"))
-// }
-//
-// if (qrcodeTrans.qrcode != param.qrcode && param.qrcode.isNotEmpty()) {
-// val qrcode = agentServiceProxy.qrcodeMatch(param.qrcode)
-// ?: return ResponseEntity.ok(ResponseBodyBuilder.create()
-// .fail(apiResponse, TradeErrorCode.BUSINESS_DEAL_ERROR, "未识别的支付码"))
-// if (qrcodeTrans.sourceType != qrcode.sourceType) {
-// return ResponseEntity.ok(ResponseBodyBuilder.create()
-// .fail(apiResponse, TradeErrorCode.BUSINESS_DEAL_ERROR, "支付码不符"))
-// }
-// qrcodeTrans.qrcode = param.qrcode
-// }
-//
-// val sourceType = sourceTypeService.getBySourceType(qrcodeTrans.sourceType)
-// ?: return ResponseEntity.ok(ResponseBodyBuilder.create()
-// .fail(apiResponse, TradeErrorCode.BUSINESS_DEAL_ERROR,
-// "不支持的支付方式<${qrcodeTrans.sourceType}>"))
-// if (!sourceType.anonymousEnable && qrcodeTrans.isAnonymous) {
-// return ResponseEntity.ok(ResponseBodyBuilder.create()
-// .fail(apiResponse, TradeErrorCode.BUSINESS_DEAL_ERROR,
-// "支付方式<${qrcodeTrans.sourceType}>不支持匿名支付"))
-// }
-// qrcodeTrans.spip = param.spip
-// val dtlType = consumePayService.getDtltypeDictionary(param.dtltype, Dictionary.DTLTYPES)
-// //2. 初始化交易流水
-// // sourcetype 资产类科目
-// val stSubject = accountUtilServcie.readSubject(sourceType.paySubjno)
-// // build 交易明细
-// val builder = TransactionBuilder().apply {
-// setTransInfo(param.transdate, param.transtime, TradeCode.TRANSCODE_QRCODE, qrcodeTrans.sourceType)
-// setOutTransInfo(qrcodeTrans.agentMerchId, qrcodeTrans.billno)
-// payinfo = qrcodeSummary(sourceType)
-// description = dtlType.dictcaption
-// dtltype = param.dtltype
-// }
-//
-// val shopacc = accountUtilServcie.readShopbyShopaccno(qrcodeTrans.agentMerchId)
-// val amount = param.amount / 100.0
-// builder.shop(shopacc).apply {
-// setAmount(amount, TradeDict.TRADE_FLAG_IN)
-// }
-// if (qrcodeTrans.isAnonymous) {
-// builder.anonymous().apply {
-// setAmount(amount, TradeDict.TRADE_FLAG_OUT)
-// setOpposite(shopacc.shopaccno, shopacc.shopname)
-// }.and() // 匿名消费时,借 科目 , 贷 商户
-// .addDebitCreditRecord(AccountProxy(stSubject), AccountProxy(shopacc),
-// amount, qrcodeSummary(sourceType))
-// } else {
-// val account = accountUtilServcie.readAccount(param.userid)
-// builder.person(account).apply {
-// setAmount(amount, TradeDict.TRADE_FLAG_OUT)
-// setOpposite(shopacc.shopaccno, shopacc.shopname)
-// }.and().shop().apply {
-// setOpposite(account.accno, account.accname)
-// }.and() // 实名消费时, 1. 借 科目, 贷 个人账户 ;2. 借 个人账户 贷 商户
-// .addDebitCreditRecord(AccountProxy(stSubject), AccountProxy(account),
-// amount, qrcodeSummary(sourceType))
-// .addDebitCreditRecord(AccountProxy(account), AccountProxy(shopacc),
-// amount, qrcodeSummary(sourceType))
-// }
-//
-// // 同一个客户ID + billno 是唯一索引,如果重复请求不能保存
-// val transaction = builder.init(transactionService)
-//
-// // qrcode 交易明细表记录 refno
-// qrcodeTrans.refno = transaction.refno
-// // 保存失败,可能客户端重复请求,导致前序交易已完成
-// agentServiceProxy.qrcodePayTransSaveOrUpdate(qrcodeTrans)
-//
-// //3. 调用第三方支付
-// transactionService.wip(transaction.refno)
-// val service = createAgentService<QrcodePayTrans>(qrcodeTrans.sourceType)
-// apiResponse.apply {
-// refno = transaction.refno
-// accdate = transaction.accdate
-// isRequireQuery = false
-// anonymous = qrcodeTrans.isAnonymous
-// }
-//
-// val response = service.pay(transaction)
-// return when (response.code) {
-// AgentCode.SUCCESS -> {
-// transactionService.success(transaction.refno, response.agentRefno)
-// ResponseEntity.ok(ResponseBodyBuilder.create()
-// .success(apiResponse))
-// }
-// AgentCode.REQUIRE_QUERY -> {
-// ResponseEntity.ok(ResponseBodyBuilder.create()
-// .success(apiResponse.also {
-// it.isRequireQuery = true
-// }))
-// }
-// else -> {
-// transactionService.fail(transaction.refno, response.agentMsg)
-// ResponseEntity.ok(ResponseBodyBuilder.create()
-// .fail(apiResponse, TradeErrorCode.BUSINESS_DEAL_ERROR,
-// "第三方身份错误,<${response.agentMsg}"))
-// }
-// }
-// }
+ override fun qrcodePayConfirm(xTenantId: String, @Valid param: QrcodePayConfirmRequest): ResponseEntity<QrcodePayConfirmResponse> {
+ try {//1. 交易检查
-// override fun qrcodePayQuery(xTenantId: String, refno: String): ResponseEntity<Void> {
-// return null
-// }
+ val transaction = consumePayService.getTransactionMainByParam(param)
+ val systime = systemUtilService.sysdatetime
+ val apiResponse = QrcodePayConfirmResponse().apply {
+ this.refno = transaction.refno
+ this.hostDate = systime.hostdate
+ this.hostTime = systime.hosttime
+ }
+ if (TradeDict.DTL_STATUS_INIT != transaction.status) {
+ return when (transaction.status) {
+ TradeDict.DTL_STATUS_WIP -> {
+ ResponseBodyBuilder.ok(apiResponse.apply {
+ this.result = TransResult.REQUIRE_QUERY
+ })
+ }
+ TradeDict.DTL_STATUS_FAIL -> {
+ ResponseBodyBuilder.ok(apiResponse.apply {
+ this.result = TransResult.FAILED
+ })
+ }
+ TradeDict.DTL_STATUS_SUCCESS -> {
+ ResponseBodyBuilder.ok(apiResponse.apply {
+ this.result = TransResult.ALREADY_SUCCESS
+ })
+ }
+ else -> {
+ ResponseBodyBuilder.ok(apiResponse.apply {
+ this.result = TransResult.FAILED
+ })
+ }
+ }
+ }
+
+ transactionService.qrcodeWip(param.billno, transaction)
+
+ val service = createAgentService<QrcodePayTrans>(transaction.sourceType)
+ val response = service.pay(transaction)
+
+ consumePayService.qrcodePayConfirmPostProcess(response, param.billno, transaction)
+ return when (response.code) {
+ AgentCode.SUCCESS -> {
+ ResponseBodyBuilder.ok(apiResponse.apply { this.result = TransResult.SUCCESS })
+ }
+ AgentCode.REQUIRE_QUERY -> {
+ ResponseBodyBuilder.ok(apiResponse.apply { this.result = TransResult.REQUIRE_QUERY })
+ }
+ else -> {
+ ResponseBodyBuilder.ok(apiResponse.apply { this.result = TransResult.FAILED })
+ }
+ }
+ } catch (e: Exception) {
+ when (e) {
+ is BadRequestError -> throw BadRequestError(e.message)
+ is PessimisticLockingFailureException -> throw ConflictError(e.message)
+ else -> {
+ e.printStackTrace()
+ println("二维码消费确认异常:<${e.message}>")
+ throw InternalError(e.message)
+ }
+ }
+ }
+ }
+
+ override fun qrcodePayQuery(xTenantId: String, refno: String): ResponseEntity<QrcodePayConfirmResponse> {
+ try {
+ val systime = systemUtilService.sysdatetime
+ consumePayService.getTransactionMainDtl(refno, null, null)?.let {
+ return ResponseBodyBuilder.ok(QrcodePayConfirmResponse().apply {
+ this.refno = it.refno
+ this.hostDate = systime.hostdate
+ this.hostTime = systime.hosttime
+ this.result = when (it.status) {
+ TradeDict.DTL_STATUS_SUCCESS -> TransResult.SUCCESS
+ TradeDict.DTL_STATUS_WIP -> TransResult.REQUIRE_QUERY
+ TradeDict.DTL_STATUS_FAIL -> TransResult.FAILED
+ else -> TransResult.FAILED
+ }
+ })
+ } ?: throw BadRequestError("未找到refno")
+ } catch (e: Exception) {
+ when (e) {
+ is BadRequestError -> throw BadRequestError(e.message)
+ is PessimisticLockingFailureException -> throw ConflictError(e.message)
+ else -> {
+ e.printStackTrace()
+ println("二维码消费查询异常:<${e.message}>")
+ throw InternalError(e.message)
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt
index 29867ae..832cf5c 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt
@@ -1,7 +1,10 @@
package com.supwisdom.dlpay.api.service
+import com.supwisdom.dlpay.agent.AgentResponse
+import com.supwisdom.dlpay.agent.domain.QrcodePayTrans
import com.supwisdom.dlpay.api.domain.TTransactionMain
import com.supwisdom.dlpay.framework.domain.TDictionary
+import com.supwisdom.dlpay.payapi.model.QrcodePayConfirmRequest
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
@@ -19,9 +22,14 @@
fun getTransactionMainDtl(refno: String?, billno: String?, shopaccno: String?): TTransactionMain?
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class], readOnly = true)
- fun getDtltypeDictionary(dictval:String, dicttype:String):TDictionary
+ fun getDtltypeDictionary(dictval: String, dicttype: String): TDictionary
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class], readOnly = true)
fun checkCanReverse(sourcetype: String, shopaccno: String? = null): Boolean
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class])
+ fun qrcodePayConfirmPostProcess(response: AgentResponse<QrcodePayTrans>, billno: String,transaction:TTransactionMain)
+
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class])
+ fun getTransactionMainByParam(param: QrcodePayConfirmRequest): TTransactionMain
}
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/consume_pay_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/consume_pay_service_impl.kt
index 8830fcd..9d8b5c4 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/consume_pay_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/consume_pay_service_impl.kt
@@ -1,14 +1,30 @@
package com.supwisdom.dlpay.api.service.impl
+import com.supwisdom.dlpay.agent.AgentCode
+import com.supwisdom.dlpay.agent.AgentPayService
+import com.supwisdom.dlpay.agent.AgentPayServiceContext
+import com.supwisdom.dlpay.agent.AgentResponse
+import com.supwisdom.dlpay.agent.dao.QrcodePayTransDao
+import com.supwisdom.dlpay.agent.domain.QrcodePayTrans
+import com.supwisdom.dlpay.agent.service.AgentServiceProxy
+import com.supwisdom.dlpay.api.AccountProxy
+import com.supwisdom.dlpay.api.TransactionBuilder
import com.supwisdom.dlpay.api.dao.TransactionMainDao
+import com.supwisdom.dlpay.api.domain.TSourceType
import com.supwisdom.dlpay.api.domain.TTransactionMain
import com.supwisdom.dlpay.api.exception.RequestParamCheckException
+import com.supwisdom.dlpay.api.service.AccountUtilServcie
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.exception.BadRequestError
+import com.supwisdom.dlpay.exception.TransactionCheckException
import com.supwisdom.dlpay.framework.dao.DictionaryDao
import com.supwisdom.dlpay.framework.domain.TDictionary
-import com.supwisdom.dlpay.framework.util.StringUtil
+import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.util.*
+import com.supwisdom.dlpay.payapi.model.QrcodePayConfirmRequest
+import com.supwisdom.multitenant.TenantContextHolder
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
@@ -20,6 +36,18 @@
lateinit var transactionMainDao: TransactionMainDao
@Autowired
lateinit var dictionaryDao: DictionaryDao
+ @Autowired
+ lateinit var agentServiceProxy: AgentServiceProxy
+ @Autowired
+ lateinit var accountUtilServcie:AccountUtilServcie
+ @Autowired
+ lateinit var transactionService:TransactionServiceProxy
+ @Autowired
+ lateinit var agentPayServiceContext: AgentPayServiceContext
+ @Autowired
+ lateinit var systemUtilService: SystemUtilService
+ @Autowired
+ lateinit var qrcodePayTransDao: QrcodePayTransDao
override fun checkShopPaytype(shopaccno: String, sourceType: String, anonymousflag: Boolean?): Boolean {
return sourceTypeService.checkShopSourceType(shopaccno, sourceType, true == anonymousflag)
@@ -53,4 +81,104 @@
sourceTypeService.checkShopCanReverse(sourcetype, shopaccno);
}
}
+
+ override fun qrcodePayConfirmPostProcess(response: AgentResponse<QrcodePayTrans>, billno: String,transaction:TTransactionMain) {
+ val qrcodeTrans = qrcodePayTransDao.findByQrcodePayTransForUpdate(transaction.outId, systemUtilService.sysdatetime.hostdate,
+ billno, TenantContextHolder.getContext().tenant.id)
+ ?: throw BadRequestError("未找到billno")
+ when (response.code) {
+ AgentCode.SUCCESS -> {
+ transactionService.qrcodeSuccess(transaction.refno, response.agentRefno,transaction)
+ }
+ AgentCode.REQUIRE_QUERY -> {
+ return
+ }
+ else -> {
+ transactionService.qrcodeFail(transaction.refno, response.agentMsg,transaction)
+ }
+ }
+ }
+
+ private fun qrcodeSummary(st: TSourceType): String = st.paydesc + "扫码付"
+
+ fun <T> createAgentService(sourceType: String): AgentPayService<T> {
+ return agentPayServiceContext.findAgentPayService(sourceType)
+ ?: throw TransactionCheckException(TradeErrorCode.BUSINESS_DEAL_ERROR,
+ "支付类型<$sourceType>未定义")
+ }
+
+ override fun getTransactionMainByParam(param: QrcodePayConfirmRequest): TTransactionMain {
+ // 1.交易检查
+ val qrcodeTrans = qrcodePayTransDao.findByQrcodePayTransForUpdate(param.shopaccno, systemUtilService.sysdatetime.hostdate,
+ param.billno, TenantContextHolder.getContext().tenant.id)
+ ?: throw BadRequestError("未找到billno")
+
+ if (qrcodeTrans.qrcode != param.qrcode && param.qrcode.isNotEmpty()) {
+ val qrcode = agentServiceProxy.qrcodeMatch(param.qrcode)
+ ?: throw BadRequestError("未识别的支付码")
+ if (qrcodeTrans.sourceType != qrcode.sourceType) {
+ throw BadRequestError("支付码不符")
+ }
+ qrcodeTrans.qrcode = param.qrcode
+ }
+
+ val sourceType = sourceTypeService.getBySourceType(qrcodeTrans.sourceType)
+ ?: throw BadRequestError("不支持的支付方式<${qrcodeTrans.sourceType}>")
+ if (!sourceType.anonymousEnable && qrcodeTrans.isAnonymous) {
+ throw BadRequestError("支付方式<${qrcodeTrans.sourceType}>不支持匿名支付")
+ }
+
+ if (!qrcodeTrans.refno.isNullOrEmpty()) {
+ return getTransactionMainDtl(qrcodeTrans.refno, null, null)
+ ?: throw InternalError("未找到refno")
+ }
+
+ //2. 初始化交易流水
+ qrcodeTrans.spip = "192.168.43.90"
+ val dtlType = getDtltypeDictionary(param.dtltype, Dictionary.DTLTYPES)
+ // sourcetype 资产类科目
+ val stSubject = accountUtilServcie.readSubject(sourceType.paySubjno)
+ val builder = TransactionBuilder().apply {
+ setTransInfo(param.transDate, param.transTime, TradeCode.TRANSCODE_QRCODE, qrcodeTrans.sourceType)
+ setOutTransInfo(qrcodeTrans.agentMerchId, qrcodeTrans.billno)
+ payinfo = qrcodeSummary(sourceType)
+ description = dtlType.dictcaption
+ dtltype = param.dtltype
+ }
+
+ val shopacc = accountUtilServcie.readShopbyShopaccno(qrcodeTrans.agentMerchId)
+ val amount = param.amount / 100.0
+ builder.shop(shopacc).apply {
+ setAmount(amount, TradeDict.TRADE_FLAG_IN)
+ }
+ if (qrcodeTrans.isAnonymous) {
+ builder.anonymous().apply {
+ setAmount(amount, TradeDict.TRADE_FLAG_OUT)
+ setOpposite(shopacc.shopaccno, shopacc.shopname)
+ }.and() // 匿名消费时,借 科目 , 贷 商户
+ .addDebitCreditRecord(AccountProxy(stSubject), AccountProxy(shopacc),
+ amount, qrcodeSummary(sourceType))
+ } else {
+ val account = accountUtilServcie.readAccount(param.userid)
+ builder.person(account).apply {
+ setAmount(amount, TradeDict.TRADE_FLAG_OUT)
+ setOpposite(shopacc.shopaccno, shopacc.shopname)
+ }.and().shop().apply {
+ setOpposite(account.accno, account.accname)
+ }.and() // 实名消费时, 1. 借 科目, 贷 个人账户 ;2. 借 个人账户 贷 商户
+ .addDebitCreditRecord(AccountProxy(stSubject), AccountProxy(account),
+ amount, qrcodeSummary(sourceType))
+ .addDebitCreditRecord(AccountProxy(account), AccountProxy(shopacc),
+ amount, qrcodeSummary(sourceType))
+ }
+
+ // 同一个客户ID + billno 是唯一索引,如果重复请求不能保存
+ val transaction = builder.init(transactionService)
+ // qrcode 交易明细表记录 refno
+ qrcodeTrans.refno = transaction.refno
+ // 保存失败,可能客户端重复请求,导致前序交易已完成
+ agentServiceProxy.qrcodePayTransSaveOrUpdate(qrcodeTrans)
+
+ return transaction
+ }
}
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
index 6165d49..2061144 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
@@ -1,5 +1,6 @@
package com.supwisdom.dlpay.api.service.impl
+import com.supwisdom.dlpay.agent.dao.QrcodePayTransDao
import com.supwisdom.dlpay.api.TransactionBuilder
import com.supwisdom.dlpay.api.dao.TransactionMainDao
import com.supwisdom.dlpay.api.domain.*
@@ -35,6 +36,9 @@
@Autowired
private lateinit var sourceTypeService: SourceTypeService
+ @Autowired
+ private lateinit var qrcodePayTransDao: QrcodePayTransDao
+
/// 公共函数部分
private fun preCheck(builder: TransactionBuilder) {
@@ -293,6 +297,18 @@
return transaction
}
+ override fun qrcodeWip(billno: String,transaction:TTransactionMain): TTransactionMain {
+ val qrcodeTrans = qrcodePayTransDao.findByQrcodePayTransForUpdate(transaction.outId, systemUtilService.sysdatetime.hostdate,
+ billno, TenantContextHolder.getContext().tenant.id)
+ ?: throw InternalError("未找到billno")
+ if (transaction.status != TradeDict.DTL_STATUS_INIT) {
+ throw InternalError("流水<${transaction.refno}>状态错误")
+ }
+ updateRecordStatus(transaction, TradeDict.DTL_STATUS_WIP)
+ transactionMainDao.save(transaction)
+ return transaction
+ }
+
override fun fail(refno: String): TTransactionMain {
return fail(refno, "")
}
@@ -325,6 +341,32 @@
return transaction
}
+ override fun qrcodeFail(refno: String, remark: String, transaction: TTransactionMain): TTransactionMain {
+
+ val errorStatus = setOf(TradeDict.DTL_STATUS_SUCCESS, TradeDict.DTL_STATUS_CANCEL)
+ if (transaction.status in errorStatus) {
+ throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "流水<$refno>状态错误")
+ }
+
+ updateRecordStatus(transaction, TradeDict.DTL_STATUS_FAIL)
+ if (transaction.person) {
+ transaction.personDtl.remark = remark
+ }
+ if (transaction.shop) {
+ transaction.shopDtl.remark = remark
+ }
+ if (transaction.reverseType != TradeDict.REVERSE_FLAG_NONE) {
+ val originTrans = transactionMainDao.findByRefnoNoLock(transaction.reverseRefno ?: "")
+ ?: throw TransactionProcessException(TradeErrorCode.BUSINESS_DEAL_ERROR,
+ "系统异常,无法处理退款流水")
+ originTrans.reverseFlag = TradeDict.REVERSE_FLAG_NONE
+ transactionMainDao.save(originTrans)
+ }
+ transaction.endTime = systemUtilService.sysdatetime.sysdate
+ transactionMainDao.save(transaction)
+ return transaction
+ }
+
//////////////////////////////////////////////////////////////////
// 成功
private fun transactionOnSuccess(transaction: TTransactionMain, sorcetypeRefno: String, overdraft: Boolean) {
@@ -388,6 +430,37 @@
return transaction
}
+ override fun qrcodeSuccess(refno: String, sourcetypeRefno: String, transaction: TTransactionMain, accdateUpdate: Boolean?): TTransactionMain {
+ val errorStatus = setOf(TradeDict.DTL_STATUS_SUCCESS, TradeDict.DTL_STATUS_CANCEL)
+ if (transaction.status in errorStatus) {
+ throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "流水<$refno>状态错误,流水已结束")
+ }
+ transaction.status = TradeDict.DTL_STATUS_SUCCESS
+ if (true == accdateUpdate) {
+ transaction.accdate = systemUtilService.accdate
+ }
+ transactionOnSuccess(transaction, sourcetypeRefno, false)
+
+ if (transaction.reverseType != TradeDict.REVERSE_FLAG_NONE) {
+ val originTrans = transactionMainDao.findByRefnoNoLock(transaction.reverseRefno ?: "")
+ ?: throw TransactionProcessException(TradeErrorCode.BUSINESS_DEAL_ERROR,
+ "系统异常,无法处理退款流水")
+ originTrans.reverseFlag = transaction.reverseType
+ if (originTrans.person) {
+ originTrans.personDtl.reverseFlag = originTrans.reverseFlag
+ originTrans.personDtl.reverseAmount = originTrans.refundAmount
+ }
+ if (originTrans.shop) {
+ originTrans.shopDtl.reverseFlag = originTrans.reverseFlag
+ }
+ transactionMainDao.save(originTrans)
+ }
+
+ transaction.endTime = systemUtilService.sysdatetime.sysdate
+ transactionMainDao.save(transaction)
+ return transaction
+ }
+
override fun success(refno: String): TTransactionMain {
return success(refno, "", true)
}
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt
index cb4a931..dd9dff4 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt
@@ -23,15 +23,24 @@
fun wip(builder: TransactionBuilder): TTransactionMain
@Transactional
+ fun qrcodeWip(billno: String, transaction: TTransactionMain): TTransactionMain
+
+ @Transactional
fun fail(refno: String): TTransactionMain
@Transactional
fun fail(refno: String, remark: String): TTransactionMain
@Transactional
+ fun qrcodeFail(refno: String, remark: String, transaction: TTransactionMain): TTransactionMain
+
+ @Transactional
fun success(refno: String, sourcetypeRefno: String, accdateUpdate: Boolean? = true): TTransactionMain
@Transactional
+ fun qrcodeSuccess(refno: String, sourcetypeRefno: String, transaction: TTransactionMain, accdateUpdate: Boolean? = true): TTransactionMain
+
+ @Transactional
fun success(refno: String): TTransactionMain
@Transactional
@@ -93,6 +102,10 @@
return transactionService.wip(refno)
}
+ fun qrcodeWip(billno: String, transaction: TTransactionMain): TTransactionMain {
+ return transactionService.qrcodeWip(billno, transaction)
+ }
+
fun fail(refno: String): TTransactionMain {
return transactionService.fail(refno)
}
@@ -101,6 +114,10 @@
return transactionService.fail(refno, remark)
}
+ fun qrcodeFail(refno: String, remark: String, transaction: TTransactionMain): TTransactionMain {
+ return transactionService.qrcodeFail(refno, remark, transaction)
+ }
+
fun success(refno: String, sourcetypeRefno: String, accdateUpdate: Boolean? = true): TTransactionMain {
return transactionService.success(refno, sourcetypeRefno, accdateUpdate).also {
if (it.shop) {
@@ -116,6 +133,22 @@
}
}
+ fun qrcodeSuccess(refno: String, sourcetypeRefno: String, transaction: TTransactionMain, accdateUpdate: Boolean? = true): TTransactionMain {
+ return transactionService.qrcodeSuccess(refno, sourcetypeRefno, transaction, accdateUpdate).also {
+ if (it.shop) {
+ shopAccBalanceAsyncTask.updateShopBalance(TenantContextHolder.getContext().tenant, it.shopDtl)
+ }
+
+ if (it.person && !it.personDtl.userid.isNullOrEmpty()) {
+ kafkaSendMsgService.sendJpushMessage(it.personDtl.userid,
+ "交易提醒",
+ "你有一笔${it.personDtl.amount}元的支出,点击查看详情",
+ it.refno, mutableMapOf(), it.tenantid)
+ }
+ }
+ }
+
+
fun success(refno: String): TTransactionMain {
return success(refno, "")
}
diff --git a/payapi/src/main/resources/application.properties b/payapi/src/main/resources/application.properties
index 3223e1c..6df1eef 100644
--- a/payapi/src/main/resources/application.properties
+++ b/payapi/src/main/resources/application.properties
@@ -57,5 +57,5 @@
multi-tenant.session.enableSessionScopedBean=false
multi-tenant.datasource.base-package=com.supwisdom.dlpay
multi-tenant.task.datacenter=default
-multi-tenant.environment=default
+multi-tenant.environment=touchorder
multi-tenant.task.worker.name=payapi