Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
jinli gu
Jeepay
Commits
c87405c3
Commit
c87405c3
authored
Mar 30, 2023
by
terrfly
Browse files
添加分账异步通知机制, 添加完成支付宝回调处理事件。
parent
25667a05
Changes
8
Hide whitespace changes
Inline
Side-by-side
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/AbstractDivisionRecordChannelNotifyService.java
0 → 100644
View file @
c87405c3
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.jeequan.jeepay.pay.channel
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.beans.RequestKitBean
;
import
com.jeequan.jeepay.core.entity.PayOrderDivisionRecord
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.DivisionChannelNotifyModel
;
import
com.jeequan.jeepay.pay.service.ConfigContextQueryService
;
import
com.jeequan.jeepay.pay.util.ChannelCertConfigKitBean
;
import
org.apache.commons.lang3.tuple.MutablePair
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.ResponseEntity
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.File
;
import
java.util.List
;
/*
* 分账结果回调接口抽象类
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2023/3/29 15:39
*/
public
abstract
class
AbstractDivisionRecordChannelNotifyService
{
@Autowired
private
RequestKitBean
requestKitBean
;
@Autowired
private
ChannelCertConfigKitBean
channelCertConfigKitBean
;
@Autowired
protected
ConfigContextQueryService
configContextQueryService
;
/** 获取到接口code **/
public
abstract
String
getIfCode
();
/** 解析参数: 批次号 和 请求参数
* 异常需要自行捕捉,并返回null , 表示已响应数据。
* **/
public
abstract
MutablePair
<
String
,
Object
>
parseParams
(
HttpServletRequest
request
);
/**
* 返回需要更新的记录 <ID, 结果> 状态 和响应数据
*
* **/
public
abstract
DivisionChannelNotifyModel
doNotify
(
HttpServletRequest
request
,
Object
params
,
List
<
PayOrderDivisionRecord
>
recordList
,
MchAppConfigContext
mchAppConfigContext
);
public
ResponseEntity
doNotifyOrderNotExists
(
HttpServletRequest
request
)
{
return
textResp
(
"order not exists"
);
}
public
ResponseEntity
doNotifyOrderStateUpdateFail
(
HttpServletRequest
request
)
{
return
textResp
(
"update status error"
);
}
/** 文本类型的响应数据 **/
protected
ResponseEntity
textResp
(
String
text
){
HttpHeaders
httpHeaders
=
new
HttpHeaders
();
httpHeaders
.
setContentType
(
MediaType
.
TEXT_HTML
);
return
new
ResponseEntity
(
text
,
httpHeaders
,
HttpStatus
.
OK
);
}
/** json类型的响应数据 **/
protected
ResponseEntity
jsonResp
(
Object
body
){
HttpHeaders
httpHeaders
=
new
HttpHeaders
();
httpHeaders
.
setContentType
(
MediaType
.
APPLICATION_JSON
);
return
new
ResponseEntity
(
body
,
httpHeaders
,
HttpStatus
.
OK
);
}
/**request.getParameter 获取参数 并转换为JSON格式 **/
protected
JSONObject
getReqParamJSON
()
{
return
requestKitBean
.
getReqParamJSON
();
}
/**request.getParameter 获取参数 并转换为JSON格式 **/
protected
String
getReqParamFromBody
()
{
return
requestKitBean
.
getReqParamFromBody
();
}
/** 获取文件路径 **/
protected
String
getCertFilePath
(
String
certFilePath
)
{
return
channelCertConfigKitBean
.
getCertFilePath
(
certFilePath
);
}
/** 获取文件File对象 **/
protected
File
getCertFile
(
String
certFilePath
)
{
return
channelCertConfigKitBean
.
getCertFile
(
certFilePath
);
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayDivisionRecordChannelNotifyService.java
0 → 100644
View file @
c87405c3
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.jeequan.jeepay.pay.channel.alipay
;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
com.alipay.api.internal.util.AlipaySignature
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.PayOrderDivisionRecord
;
import
com.jeequan.jeepay.core.exception.ResponseException
;
import
com.jeequan.jeepay.core.model.params.alipay.AlipayConfig
;
import
com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams
;
import
com.jeequan.jeepay.core.model.params.alipay.AlipayNormalMchParams
;
import
com.jeequan.jeepay.pay.channel.AbstractDivisionRecordChannelNotifyService
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.rqrs.msg.DivisionChannelNotifyModel
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.tuple.MutablePair
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.stereotype.Service
;
import
javax.servlet.http.HttpServletRequest
;
import
java.util.*
;
/*
* 支付宝 分账回调接口实现类
*
* 注意:
*
// royalty_mode 必须传入: async ( 使用异步: 需要 1、请配置 支付宝应用的网关地址 ( xxx.com/api/channelbiz/alipay/appGatewayMsgReceive ), 2、 订阅消息。 )
// 2023-03-30 咨询支付宝客服: 如果没有传royalty_mode分账模式,这个默认会是同步分账,同步分账不需要关注异步通知,接口调用成功就分账成功了 2,同步分账默认不会给您发送异步通知。
// 3. 服务商代商户调用商家分账,当异步分账时服务商必须调用alipay.open.app.message.topic.subscribe(订阅消息主题)对消息api做关联绑定,服务商才会收到alipay.trade.order.settle.notify通知,否则服务商无法收到通知。
// https://opendocs.alipay.com/open/20190308105425129272/quickstart#%E8%9A%82%E8%9A%81%E6%B6%88%E6%81%AF%EF%BC%9A%E4%BA%A4%E6%98%93%E5%88%86%E8%B4%A6%E7%BB%93%E6%9E%9C%E9%80%9A%E7%9F%A5
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2023/3/30 12:20
*/
@Service
@Slf4j
public
class
AlipayDivisionRecordChannelNotifyService
extends
AbstractDivisionRecordChannelNotifyService
{
@Override
public
String
getIfCode
()
{
return
CS
.
IF_CODE
.
ALIPAY
;
}
@Override
public
MutablePair
<
String
,
Object
>
parseParams
(
HttpServletRequest
request
)
{
try
{
JSONObject
params
=
getReqParamJSON
();
String
batchOrderId
=
params
.
getJSONObject
(
"biz_content"
).
getString
(
"out_request_no"
);
// 分账批次号
return
MutablePair
.
of
(
batchOrderId
,
params
);
}
catch
(
Exception
e
)
{
log
.
error
(
"error"
,
e
);
throw
ResponseException
.
buildText
(
"ERROR"
);
}
}
@Override
public
DivisionChannelNotifyModel
doNotify
(
HttpServletRequest
request
,
Object
params
,
List
<
PayOrderDivisionRecord
>
recordList
,
MchAppConfigContext
mchAppConfigContext
)
{
// 响应结果
DivisionChannelNotifyModel
result
=
new
DivisionChannelNotifyModel
();
try
{
//配置参数获取
Byte
useCert
=
null
;
String
alipaySignType
,
alipayPublicCert
,
alipayPublicKey
=
null
;
if
(
mchAppConfigContext
.
isIsvsubMch
()){
// 获取支付参数
AlipayIsvParams
alipayParams
=
(
AlipayIsvParams
)
configContextQueryService
.
queryIsvParams
(
mchAppConfigContext
.
getMchInfo
().
getIsvNo
(),
getIfCode
());
useCert
=
alipayParams
.
getUseCert
();
alipaySignType
=
alipayParams
.
getSignType
();
alipayPublicCert
=
alipayParams
.
getAlipayPublicCert
();
alipayPublicKey
=
alipayParams
.
getAlipayPublicKey
();
}
else
{
// 获取支付参数
AlipayNormalMchParams
alipayParams
=
(
AlipayNormalMchParams
)
configContextQueryService
.
queryNormalMchParams
(
mchAppConfigContext
.
getMchNo
(),
mchAppConfigContext
.
getAppId
(),
getIfCode
());
useCert
=
alipayParams
.
getUseCert
();
alipaySignType
=
alipayParams
.
getSignType
();
alipayPublicCert
=
alipayParams
.
getAlipayPublicCert
();
alipayPublicKey
=
alipayParams
.
getAlipayPublicKey
();
}
// 获取请求参数
JSONObject
jsonParams
=
(
JSONObject
)
params
;
boolean
verifyResult
;
if
(
useCert
!=
null
&&
useCert
==
CS
.
YES
){
//证书方式
verifyResult
=
AlipaySignature
.
rsaCertCheckV1
(
jsonParams
.
toJavaObject
(
Map
.
class
),
getCertFilePath
(
alipayPublicCert
),
AlipayConfig
.
CHARSET
,
alipaySignType
);
}
else
{
verifyResult
=
AlipaySignature
.
rsaCheckV1
(
jsonParams
.
toJavaObject
(
Map
.
class
),
alipayPublicKey
,
AlipayConfig
.
CHARSET
,
alipaySignType
);
}
//验签失败
if
(!
verifyResult
){
throw
ResponseException
.
buildText
(
"ERROR"
);
}
// 得到所有的 accNo 与 recordId map
Map
<
String
,
Long
>
accnoAndRecordIdSet
=
new
HashMap
<>();
for
(
PayOrderDivisionRecord
record
:
recordList
)
{
accnoAndRecordIdSet
.
put
(
record
.
getAccNo
(),
record
.
getRecordId
());
}
Map
<
Long
,
ChannelRetMsg
>
recordResultMap
=
new
HashMap
<>();
JSONObject
bizContentJSON
=
jsonParams
.
getJSONObject
(
"biz_content"
);
// 循环
JSONArray
array
=
bizContentJSON
.
getJSONArray
(
"royalty_detail_list"
);
for
(
Object
o
:
array
)
{
JSONObject
itemJSON
=
(
JSONObject
)
o
;
// 我方系统的分账接收记录ID
Long
recordId
=
accnoAndRecordIdSet
.
get
(
itemJSON
.
getString
(
"trans_in"
));
// 分账类型 && 包含该笔分账账号
if
(
"transfer"
.
equals
(
itemJSON
.
getString
(
"operation_type"
))
&&
recordId
!=
null
){
// 分账成功
if
(
"SUCCESS"
.
equals
(
itemJSON
.
getString
(
"state"
))){
recordResultMap
.
put
(
recordId
,
ChannelRetMsg
.
confirmSuccess
(
bizContentJSON
.
getString
(
"settle_no"
)));
}
// 分账失败
if
(
"FAIL"
.
equals
(
itemJSON
.
getString
(
"state"
))){
recordResultMap
.
put
(
recordId
,
ChannelRetMsg
.
confirmFail
(
bizContentJSON
.
getString
(
"settle_no"
),
itemJSON
.
getString
(
"error_code"
),
itemJSON
.
getString
(
"error_desc"
)));
}
}
}
result
.
setRecordResultMap
(
recordResultMap
);
result
.
setApiRes
(
textResp
(
"success"
));
return
result
;
}
catch
(
Exception
e
)
{
log
.
error
(
"error"
,
e
);
throw
ResponseException
.
buildText
(
"ERROR"
);
}
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayDivisionService.java
View file @
c87405c3
...
...
@@ -136,6 +136,13 @@ public class AlipayDivisionService implements IDivisionService {
model
.
setOutRequestNo
(
recordList
.
get
(
0
).
getBatchOrderId
());
//结算请求流水号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。
model
.
setTradeNo
(
recordList
.
get
(
0
).
getPayOrderChannelOrderNo
());
//支付宝订单号
// royalty_mode 参数说明: 同步执行 sync ; 分账异步执行 async ( 使用异步: 需要 1、请配置 支付宝应用的网关地址 ( xxx.com/api/channelbiz/alipay/appGatewayMsgReceive ), 2、 订阅消息。 )
// 2023-03-30 咨询支付宝客服: 如果没有传royalty_mode分账模式,这个默认会是同步分账,同步分账不需要关注异步通知,接口调用成功就分账成功了 2,同步分账默认不会给您发送异步通知。
// 3. 服务商代商户调用商家分账,当异步分账时服务商必须调用alipay.open.app.message.topic.subscribe(订阅消息主题)对消息api做关联绑定,服务商才会收到alipay.trade.order.settle.notify通知,否则服务商无法收到通知。
// https://opendocs.alipay.com/open/20190308105425129272/quickstart#%E8%9A%82%E8%9A%81%E6%B6%88%E6%81%AF%EF%BC%9A%E4%BA%A4%E6%98%93%E5%88%86%E8%B4%A6%E7%BB%93%E6%9E%9C%E9%80%9A%E7%9F%A5
model
.
setRoyaltyMode
(
"sync"
);
// 综上所述, 目前使用同步调用。
//统一放置 isv接口必传信息
AlipayKit
.
putApiIsvInfo
(
mchAppConfigContext
,
request
,
model
);
...
...
@@ -152,9 +159,6 @@ public class AlipayDivisionService implements IDivisionService {
OpenApiRoyaltyDetailInfoPojo
reqReceiver
=
new
OpenApiRoyaltyDetailInfoPojo
();
reqReceiver
.
setRoyaltyType
(
"transfer"
);
//分账类型: 普通分账
// 出款信息
// reqReceiver.setTransOutType("loginName"); reqReceiver.setTransOut("xqxemt4735@sandbox.com");
// 入款信息
reqReceiver
.
setTransIn
(
record
.
getAccNo
());
//收入方账号
reqReceiver
.
setTransInType
(
"loginName"
);
...
...
@@ -169,7 +173,7 @@ public class AlipayDivisionService implements IDivisionService {
}
if
(
reqReceiverList
.
isEmpty
()){
// 当无分账用户时, 支付宝不允许发起分账请求, 支付宝没有完结接口,直接响应成功即可。
return
ChannelRetMsg
.
confirmSuccess
(
null
);
return
ChannelRetMsg
.
confirmSuccess
(
null
);
// 明确成功。
}
model
.
setRoyaltyParameters
(
reqReceiverList
);
// 分账明细信息
...
...
@@ -203,7 +207,7 @@ public class AlipayDivisionService implements IDivisionService {
return
channelRetMsg
;
}
catch
(
Exception
e
)
{
log
.
error
(
"
绑定
支付宝账
号
异常"
,
e
);
log
.
error
(
"支付宝
分
账异常"
,
e
);
ChannelRetMsg
channelRetMsg
=
ChannelRetMsg
.
confirmFail
();
channelRetMsg
.
setChannelErrMsg
(
e
.
getMessage
());
return
channelRetMsg
;
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/ctrl/AlipayBizController.java
View file @
c87405c3
...
...
@@ -42,6 +42,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.stereotype.Controller
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.servlet.ModelAndView
;
import
java.io.IOException
;
import
java.math.BigDecimal
;
...
...
@@ -64,6 +65,7 @@ public class AlipayBizController extends AbstractCtrl {
@Autowired
private
MchAppService
mchAppService
;
@Autowired
private
IMQSender
mqSender
;
/** 跳转到支付宝的授权页面 (统一从pay项目获取到isv配置信息)
* isvAndMchNo 格式: ISVNO_MCHAPPID
* example: https://pay.jeepay.cn/api/channelbiz/alipay/redirectAppToAppAuth/V1623998765_60cc41694ee0e6685f57eb1f
...
...
@@ -158,4 +160,29 @@ public class AlipayBizController extends AbstractCtrl {
return
"channel/alipay/isvsubMchAuth"
;
}
/**
* 接收 支付宝 应用 配置中: 【应用网关地址 : 用于接收支付宝异步通知消息(例如 From蚂蚁消息等),需要传入http(s)公网可访问的网页地址。选填,若不设置,则无法接收相应的异步通知消息。】
*
* **/
@RequestMapping
(
"/appGatewayMsgReceive"
)
public
ModelAndView
alipayAppGatewayMsgReceive
()
{
JSONObject
reqJSON
=
getReqParamJSON
();
// 获取到报文信息, 然后 转发到对应的ctrl
log
.
error
(
"支付宝应用网关接收消息参数:{}"
,
reqJSON
);
// 分账交易通知
if
(
"alipay.trade.order.settle.notify"
.
equals
(
reqJSON
.
getString
(
"msg_method"
))){
// 直接转发到 分账通知的 URL去。
ModelAndView
mv
=
new
ModelAndView
();
mv
.
setViewName
(
"forward:/api/divisionRecordChannelNotify/"
+
CS
.
IF_CODE
.
ALIPAY
);
return
mv
;
}
throw
new
BizException
(
"无此事件["
+
reqJSON
.
getString
(
"msg_method"
)
+
"]处理器"
);
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/division/DivisionRecordChannelNotifyController.java
0 → 100644
View file @
c87405c3
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.jeequan.jeepay.pay.ctrl.division
;
import
com.jeequan.jeepay.core.ctrls.AbstractCtrl
;
import
com.jeequan.jeepay.core.entity.PayOrderDivisionRecord
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.exception.ResponseException
;
import
com.jeequan.jeepay.core.utils.SpringBeansUtil
;
import
com.jeequan.jeepay.pay.channel.AbstractDivisionRecordChannelNotifyService
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.rqrs.msg.DivisionChannelNotifyModel
;
import
com.jeequan.jeepay.pay.service.ConfigContextQueryService
;
import
com.jeequan.jeepay.pay.service.PayOrderProcessService
;
import
com.jeequan.jeepay.service.impl.PayOrderDivisionRecordService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.commons.lang3.tuple.MutablePair
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
javax.servlet.http.HttpServletRequest
;
import
java.util.List
;
/*
* 分账渠道侧的通知入口Controller
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2023/3/29 15:35
*/
@Slf4j
@Controller
public
class
DivisionRecordChannelNotifyController
extends
AbstractCtrl
{
@Autowired
private
PayOrderDivisionRecordService
payOrderDivisionRecordService
;
@Autowired
private
ConfigContextQueryService
configContextQueryService
;
@Autowired
private
PayOrderProcessService
payOrderProcessService
;
/** 异步回调入口 **/
@ResponseBody
@RequestMapping
(
value
=
{
"/api/divisionRecordChannelNotify/{ifCode}"
})
public
ResponseEntity
doNotify
(
HttpServletRequest
request
,
@PathVariable
(
"ifCode"
)
String
ifCode
){
String
divisionBatchId
=
null
;
String
logPrefix
=
"进入["
+
ifCode
+
"]分账回调"
;
log
.
info
(
"===== {} ====="
,
logPrefix
);
try
{
// 参数有误
if
(
StringUtils
.
isEmpty
(
ifCode
)){
return
ResponseEntity
.
badRequest
().
body
(
"ifCode is empty"
);
}
//查询支付接口是否存在
AbstractDivisionRecordChannelNotifyService
divisionNotifyService
=
SpringBeansUtil
.
getBean
(
ifCode
+
"DivisionRecordChannelNotifyService"
,
AbstractDivisionRecordChannelNotifyService
.
class
);
// 支付通道接口实现不存在
if
(
divisionNotifyService
==
null
){
log
.
error
(
"{}, interface not exists "
,
logPrefix
);
return
ResponseEntity
.
badRequest
().
body
(
"["
+
ifCode
+
"] interface not exists"
);
}
// 解析批次号 和 请求参数
MutablePair
<
String
,
Object
>
mutablePair
=
divisionNotifyService
.
parseParams
(
request
);
if
(
mutablePair
==
null
){
// 解析数据失败, 响应已处理
log
.
error
(
"{}, mutablePair is null "
,
logPrefix
);
throw
new
BizException
(
"解析数据异常!"
);
//需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
//解析到订单号
divisionBatchId
=
mutablePair
.
left
;
log
.
info
(
"{}, 解析数据为:divisionBatchId:{}, params:{}"
,
logPrefix
,
divisionBatchId
,
mutablePair
.
getRight
());
// 通过 batchId 查询出列表( 注意: 需要按照ID 排序!!!! )
List
<
PayOrderDivisionRecord
>
recordList
=
payOrderDivisionRecordService
.
list
(
PayOrderDivisionRecord
.
gw
()
.
eq
(
PayOrderDivisionRecord:
:
getState
,
PayOrderDivisionRecord
.
STATE_ACCEPT
)
.
eq
(
PayOrderDivisionRecord:
:
getBatchOrderId
,
divisionBatchId
)
.
orderByAsc
(
PayOrderDivisionRecord:
:
getRecordId
)
);
// 订单不存在
if
(
recordList
==
null
||
recordList
.
isEmpty
()){
log
.
error
(
"{}, 待处理订单不存在. divisionBatchId={} "
,
logPrefix
,
divisionBatchId
);
return
divisionNotifyService
.
doNotifyOrderNotExists
(
request
);
}
//查询出商户应用的配置信息
MchAppConfigContext
mchAppConfigContext
=
configContextQueryService
.
queryMchInfoAndAppInfo
(
recordList
.
get
(
0
).
getMchNo
(),
recordList
.
get
(
0
).
getAppId
());
//调起接口的回调判断
DivisionChannelNotifyModel
notifyResult
=
divisionNotifyService
.
doNotify
(
request
,
mutablePair
.
getRight
(),
recordList
,
mchAppConfigContext
);
// 返回null 表明出现异常, 无需处理通知下游等操作。
if
(
notifyResult
==
null
||
notifyResult
.
getApiRes
()
==
null
){
log
.
error
(
"{}, 处理回调事件异常 notifyResult data error, notifyResult ={} "
,
logPrefix
,
notifyResult
);
throw
new
BizException
(
"处理回调事件异常!"
);
//需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
if
(
notifyResult
.
getRecordResultMap
()
!=
null
&&
!
notifyResult
.
getRecordResultMap
().
isEmpty
()){
for
(
Long
divisionId
:
notifyResult
.
getRecordResultMap
().
keySet
())
{
// 单条结果
ChannelRetMsg
retMsgItem
=
notifyResult
.
getRecordResultMap
().
get
(
divisionId
);
// 明确成功
if
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
==
retMsgItem
.
getChannelState
()){
payOrderDivisionRecordService
.
updateRecordSuccessOrFailBySingleItem
(
divisionId
,
PayOrderDivisionRecord
.
STATE_SUCCESS
,
retMsgItem
.
getChannelOriginResponse
());
}
else
if
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
==
retMsgItem
.
getChannelState
()){
// 明确失败
payOrderDivisionRecordService
.
updateRecordSuccessOrFailBySingleItem
(
divisionId
,
PayOrderDivisionRecord
.
STATE_FAIL
,
StringUtils
.
defaultIfEmpty
(
retMsgItem
.
getChannelErrMsg
(),
retMsgItem
.
getChannelOriginResponse
()));
}
}
}
log
.
info
(
"===== {}, 通知完成。 divisionBatchId={}, parseState = {} ====="
,
logPrefix
,
divisionBatchId
,
notifyResult
);
return
notifyResult
.
getApiRes
();
}
catch
(
BizException
e
)
{
log
.
error
(
"{}, divisionBatchId={}, BizException"
,
logPrefix
,
divisionBatchId
,
e
);
return
ResponseEntity
.
badRequest
().
body
(
e
.
getMessage
());
}
catch
(
ResponseException
e
)
{
log
.
error
(
"{}, divisionBatchId={}, ResponseException"
,
logPrefix
,
divisionBatchId
,
e
);
return
e
.
getResponseEntity
();
}
catch
(
Exception
e
)
{
log
.
error
(
"{}, divisionBatchId={}, 系统异常"
,
logPrefix
,
divisionBatchId
,
e
);
return
ResponseEntity
.
badRequest
().
body
(
e
.
getMessage
());
}
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/rqrs/msg/DivisionChannelNotifyModel.java
0 → 100644
View file @
c87405c3
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.jeequan.jeepay.pay.rqrs.msg
;
import
lombok.Data
;
import
org.springframework.http.ResponseEntity
;
import
java.util.Map
;
/***
* 封装响应结果的数据
* 直接写: MutablePair<ResponseEntity, Map<Long, ChannelRetMsg>> 太过复杂!
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2023/3/29 15:50
*/
@Data
public
class
DivisionChannelNotifyModel
{
/** 响应接口返回的数据 **/
private
ResponseEntity
apiRes
;
/** 每一条记录的更新状态 <ID, 结果> **/
private
Map
<
Long
,
ChannelRetMsg
>
recordResultMap
;
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/service/PayOrderDivisionProcessService.java
View file @
c87405c3
...
...
@@ -112,7 +112,9 @@ public class PayOrderDivisionProcessService {
// 重发通知,可直接查库
if
(
isResend
){
recordList
=
payOrderDivisionRecordService
.
list
(
PayOrderDivisionRecord
.
gw
().
eq
(
PayOrderDivisionRecord:
:
getPayOrderId
,
payOrderId
).
eq
(
PayOrderDivisionRecord:
:
getState
,
PayOrderDivisionRecord
.
STATE_FAIL
));
// 根据payOrderId && 待分账( 重试时将更新为待分账状态 ) , 此处不可查询出分账成功的订单。
recordList
=
payOrderDivisionRecordService
.
list
(
PayOrderDivisionRecord
.
gw
()
.
eq
(
PayOrderDivisionRecord:
:
getPayOrderId
,
payOrderId
).
eq
(
PayOrderDivisionRecord:
:
getState
,
PayOrderDivisionRecord
.
STATE_WAIT
));
}
else
{
// 查询&过滤 所有的分账接收对象
...
...
jeepay-service/src/main/java/com/jeequan/jeepay/service/impl/PayOrderDivisionRecordService.java
View file @
c87405c3
...
...
@@ -28,6 +28,17 @@ public class PayOrderDivisionRecordService extends ServiceImpl<PayOrderDivisionR
@Autowired
private
PayOrderMapper
payOrderMapper
;
/** 更新分账记录为分账成功 ( 单条 ) 将: 已受理 更新为: 其他状态 **/
public
void
updateRecordSuccessOrFailBySingleItem
(
Long
recordId
,
Byte
state
,
String
channelRespResult
){
PayOrderDivisionRecord
updateRecord
=
new
PayOrderDivisionRecord
();
updateRecord
.
setState
(
state
);
updateRecord
.
setChannelRespResult
(
channelRespResult
);
update
(
updateRecord
,
PayOrderDivisionRecord
.
gw
().
eq
(
PayOrderDivisionRecord:
:
getRecordId
,
recordId
).
eq
(
PayOrderDivisionRecord:
:
getState
,
PayOrderDivisionRecord
.
STATE_ACCEPT
));
}
/** 更新分账记录为分账成功**/
public
void
updateRecordSuccessOrFail
(
List
<
PayOrderDivisionRecord
>
records
,
Byte
state
,
String
channelBatchOrderId
,
String
channelRespResult
){
...
...
@@ -61,7 +72,7 @@ public class PayOrderDivisionRecordService extends ServiceImpl<PayOrderDivisionR
}
PayOrderDivisionRecord
updateRecordByDiv
=
new
PayOrderDivisionRecord
();
updateRecordByDiv
.
setBatchOrderId
(
SeqKit
.
genDivisionBatchId
());
// 重新生成batchOrderId, 避免部分失败导致: out_trade_no重复。
updateRecordByDiv
.
setBatchOrderId
(
SeqKit
.
genDivisionBatchId
());
// 重新生成batchOrderId, 避免部分失败导致: out_trade_no重复。
updateRecordByDiv
.
setState
(
PayOrderDivisionRecord
.
STATE_WAIT
);
//待分账
updateRecordByDiv
.
setChannelRespResult
(
""
);
updateRecordByDiv
.
setChannelBatchOrderId
(
""
);
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment