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
0bbd04d0
Commit
0bbd04d0
authored
Sep 26, 2021
by
dingzhiwei
Browse files
增加退款回调处理逻辑&优化小新支付退款处理
parent
7663b202
Changes
12
Hide whitespace changes
Inline
Side-by-side
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/AbstractChannelRefundNoticeService.java
0 → 100644
View file @
0bbd04d0
/*
* 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.pay.util.ChannelCertConfigKitBean
;
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
;
/*
* 实现退款回调接口抽象类
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/25 23:18
*/
public
abstract
class
AbstractChannelRefundNoticeService
implements
IChannelRefundNoticeService
{
@Autowired
private
RequestKitBean
requestKitBean
;
@Autowired
private
ChannelCertConfigKitBean
channelCertConfigKitBean
;
@Override
public
ResponseEntity
doNotifyOrderNotExists
(
HttpServletRequest
request
)
{
return
textResp
(
"order not exists"
);
}
@Override
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/AbstractRefundService.java
View file @
0bbd04d0
...
...
@@ -36,8 +36,8 @@ public abstract class AbstractRefundService implements IRefundService{
return
sysConfigService
.
getDBApplicationConfig
().
getPaySiteUrl
()
+
"/api/refund/notify/"
+
getIfCode
();
}
protected
String
getNotifyUrl
(
String
pay
OrderId
){
return
sysConfigService
.
getDBApplicationConfig
().
getPaySiteUrl
()
+
"/api/refund/notify/"
+
getIfCode
()
+
"/"
+
pay
OrderId
;
protected
String
getNotifyUrl
(
String
refund
OrderId
){
return
sysConfigService
.
getDBApplicationConfig
().
getPaySiteUrl
()
+
"/api/refund/notify/"
+
getIfCode
()
+
"/"
+
refund
OrderId
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/IChannelNoticeService.java
View file @
0bbd04d0
...
...
@@ -24,7 +24,7 @@ import org.springframework.http.ResponseEntity;
import
javax.servlet.http.HttpServletRequest
;
/*
* 渠道侧的通知解析实现 【分为同步跳转(doReturn)和异步回调(doNotify) 】
* 渠道侧的
支付订单
通知解析实现 【分为同步跳转(doReturn)和异步回调(doNotify) 】
*
* @author terrfly
* @site https://www.jeequan.com
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/IChannelRefundNoticeService.java
0 → 100644
View file @
0bbd04d0
/*
* 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.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.entity.RefundOrder
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
org.apache.commons.lang3.tuple.MutablePair
;
import
org.springframework.http.ResponseEntity
;
import
javax.servlet.http.HttpServletRequest
;
/*
* 渠道侧的退款订单通知解析实现 【分为同步跳转(doReturn)和异步回调(doNotify) 】
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/25 23:14
*/
public
interface
IChannelRefundNoticeService
{
/** 通知类型 **/
enum
NoticeTypeEnum
{
DO_NOTIFY
//异步回调
}
/** 获取到接口code **/
String
getIfCode
();
/** 解析参数: 订单号 和 请求参数
* 异常需要自行捕捉,并返回null , 表示已响应数据。
* **/
MutablePair
<
String
,
Object
>
parseParams
(
HttpServletRequest
request
,
String
urlOrderId
,
NoticeTypeEnum
noticeTypeEnum
);
/** 返回需要更新的订单状态 和响应数据 **/
ChannelRetMsg
doNotice
(
HttpServletRequest
request
,
Object
params
,
RefundOrder
refundOrder
,
MchAppConfigContext
mchAppConfigContext
,
NoticeTypeEnum
noticeTypeEnum
);
/** 数据库订单 状态更新异常 (仅异步通知使用) **/
ResponseEntity
doNotifyOrderStateUpdateFail
(
HttpServletRequest
request
);
/** 数据库订单数据不存在 (仅异步通知使用) **/
ResponseEntity
doNotifyOrderNotExists
(
HttpServletRequest
request
);
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/xxpay/XxpayChannelNoticeService.java
View file @
0bbd04d0
...
...
@@ -31,7 +31,7 @@ import org.springframework.stereotype.Service;
import
javax.servlet.http.HttpServletRequest
;
/*
* 小新支付 回调接口实现类
* 小新支付
支付
回调接口实现类
*
* @author jmdhappy
* @site https://www.jeequan.com
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/xxpay/XxpayChannelRefundNoticeService.java
0 → 100644
View file @
0bbd04d0
/*
* 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.xxpay
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.RefundOrder
;
import
com.jeequan.jeepay.core.exception.ResponseException
;
import
com.jeequan.jeepay.core.model.params.xxpay.XxpayNormalMchParams
;
import
com.jeequan.jeepay.pay.channel.AbstractChannelRefundNoticeService
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
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
;
/*
* 小新支付 退款回调接口实现类
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/21 00:16
*/
@Service
@Slf4j
public
class
XxpayChannelRefundNoticeService
extends
AbstractChannelRefundNoticeService
{
@Override
public
String
getIfCode
()
{
return
CS
.
IF_CODE
.
XXPAY
;
}
@Override
public
MutablePair
<
String
,
Object
>
parseParams
(
HttpServletRequest
request
,
String
urlOrderId
,
NoticeTypeEnum
noticeTypeEnum
)
{
try
{
JSONObject
params
=
getReqParamJSON
();
String
refundOrderId
=
params
.
getString
(
"mchRefundNo"
);
return
MutablePair
.
of
(
refundOrderId
,
params
);
}
catch
(
Exception
e
)
{
log
.
error
(
"error"
,
e
);
throw
ResponseException
.
buildText
(
"ERROR"
);
}
}
@Override
public
ChannelRetMsg
doNotice
(
HttpServletRequest
request
,
Object
params
,
RefundOrder
refundOrder
,
MchAppConfigContext
mchAppConfigContext
,
NoticeTypeEnum
noticeTypeEnum
)
{
try
{
XxpayNormalMchParams
xxpayParams
=
mchAppConfigContext
.
getNormalMchParamsByIfCode
(
getIfCode
(),
XxpayNormalMchParams
.
class
);
// 获取请求参数
JSONObject
jsonParams
=
(
JSONObject
)
params
;
String
checkSign
=
jsonParams
.
getString
(
"sign"
);
jsonParams
.
remove
(
"sign"
);
// 验证签名
if
(!
checkSign
.
equals
(
XxpayKit
.
getSign
(
jsonParams
,
xxpayParams
.
getKey
())))
{
throw
ResponseException
.
buildText
(
"ERROR"
);
}
//验签成功后判断上游订单状态
ResponseEntity
okResponse
=
textResp
(
"success"
);
// 支付状态,0-订单生成,1-支付中,2-支付成功,3-业务处理完成
String
status
=
jsonParams
.
getString
(
"status"
);
ChannelRetMsg
result
=
new
ChannelRetMsg
();
result
.
setChannelOrderId
(
jsonParams
.
getString
(
"channelOrderNo"
));
//渠道订单号
result
.
setResponseEntity
(
okResponse
);
//响应数据
result
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
// 默认支付中
if
(
"2"
.
equals
(
status
)
||
"3"
.
equals
(
status
)){
result
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
}
return
result
;
}
catch
(
Exception
e
)
{
log
.
error
(
"error"
,
e
);
throw
ResponseException
.
buildText
(
"ERROR"
);
}
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/xxpay/XxpayPayOrderQueryService.java
View file @
0bbd04d0
...
...
@@ -50,7 +50,6 @@ public class XxpayPayOrderQueryService implements IPayOrderQueryService {
@Override
public
ChannelRetMsg
query
(
PayOrder
payOrder
,
MchAppConfigContext
mchAppConfigContext
){
XxpayNormalMchParams
xxpayParams
=
mchAppConfigContext
.
getNormalMchParamsByIfCode
(
getIfCode
(),
XxpayNormalMchParams
.
class
);
String
queryPayOrderUrl
=
XxpayKit
.
getQueryPayOrderUrl
(
xxpayParams
.
getPayUrl
());
Map
<
String
,
Object
>
paramMap
=
new
TreeMap
();
// 接口类型
paramMap
.
put
(
"mchId"
,
xxpayParams
.
getMchId
());
...
...
@@ -58,8 +57,11 @@ public class XxpayPayOrderQueryService implements IPayOrderQueryService {
String
sign
=
XxpayKit
.
getSign
(
paramMap
,
xxpayParams
.
getKey
());
paramMap
.
put
(
"sign"
,
sign
);
String
resStr
=
""
;
String
queryPayOrderUrl
=
XxpayKit
.
getQueryPayOrderUrl
(
xxpayParams
.
getPayUrl
())
+
"?"
+
JeepayKit
.
genUrlParams
(
paramMap
);
try
{
resStr
=
HttpUtil
.
createPost
(
queryPayOrderUrl
+
"?"
+
JeepayKit
.
genUrlParams
(
paramMap
)).
timeout
(
60
*
1000
).
execute
().
body
();
log
.
info
(
"支付查询[{}]参数:{}"
,
getIfCode
(),
queryPayOrderUrl
);
resStr
=
HttpUtil
.
createPost
(
queryPayOrderUrl
).
timeout
(
60
*
1000
).
execute
().
body
();
log
.
info
(
"支付查询[{}]结果:{}"
,
getIfCode
(),
resStr
);
}
catch
(
Exception
e
)
{
log
.
error
(
"http error"
,
e
);
}
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/xxpay/XxpayPaymentService.java
View file @
0bbd04d0
...
...
@@ -81,9 +81,9 @@ public class XxpayPaymentService extends AbstractPaymentService {
String
payUrl
=
XxpayKit
.
getPaymentUrl
(
params
.
getPayUrl
())+
"?"
+
JeepayKit
.
genUrlParams
(
paramMap
);
String
resStr
=
""
;
try
{
log
.
info
(
"
请求
{}参数:{}"
,
getIfCode
(),
payUrl
);
log
.
info
(
"
发起支付[
{}
]
参数:{}"
,
getIfCode
(),
payUrl
);
resStr
=
HttpUtil
.
createPost
(
payUrl
).
timeout
(
60
*
1000
).
execute
().
body
();
log
.
info
(
"
请求
{}结果:{}"
,
getIfCode
(),
resStr
);
log
.
info
(
"
发起支付[
{}
]
结果:{}"
,
getIfCode
(),
resStr
);
}
catch
(
Exception
e
)
{
log
.
error
(
"http error"
,
e
);
}
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/xxpay/XxpayRefundService.java
0 → 100644
View file @
0bbd04d0
/*
* 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.xxpay
;
import
cn.hutool.http.HttpUtil
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.entity.RefundOrder
;
import
com.jeequan.jeepay.core.model.params.xxpay.XxpayNormalMchParams
;
import
com.jeequan.jeepay.core.utils.JeepayKit
;
import
com.jeequan.jeepay.pay.channel.AbstractRefundService
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.rqrs.refund.RefundOrderRQ
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
import
java.util.Map
;
import
java.util.TreeMap
;
/*
* 退款接口: 小新支付
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/26 9:38
*/
@Service
@Slf4j
public
class
XxpayRefundService
extends
AbstractRefundService
{
@Override
public
String
getIfCode
()
{
return
CS
.
IF_CODE
.
XXPAY
;
}
@Override
public
String
preCheck
(
RefundOrderRQ
bizRQ
,
RefundOrder
refundOrder
,
PayOrder
payOrder
)
{
return
null
;
}
@Override
public
ChannelRetMsg
refund
(
RefundOrderRQ
bizRQ
,
RefundOrder
refundOrder
,
PayOrder
payOrder
,
MchAppConfigContext
mchAppConfigContext
)
throws
Exception
{
XxpayNormalMchParams
params
=
mchAppConfigContext
.
getNormalMchParamsByIfCode
(
getIfCode
(),
XxpayNormalMchParams
.
class
);
// 构造支付请求参数
Map
<
String
,
Object
>
paramMap
=
new
TreeMap
();
paramMap
.
put
(
"mchId"
,
params
.
getMchId
());
//商户ID
paramMap
.
put
(
"mchOrderNo"
,
refundOrder
.
getPayOrderId
());
//支付订单-商户订单号
paramMap
.
put
(
"mchRefundNo"
,
refundOrder
.
getRefundOrderId
());
//商户退款单号
paramMap
.
put
(
"amount"
,
refundOrder
.
getRefundAmount
());
//退款金额
paramMap
.
put
(
"currency"
,
"cny"
);
//币种
paramMap
.
put
(
"clientIp"
,
refundOrder
.
getClientIp
());
//客户端IP
paramMap
.
put
(
"device"
,
"web"
);
//客户端设备
//如果notifyUrl 不为空表示异步退款,具体退款结果以退款通知为准
paramMap
.
put
(
"notifyUrl"
,
getNotifyUrl
(
refundOrder
.
getRefundOrderId
()));
// 异步退款通知
paramMap
.
put
(
"remarkInfo"
,
refundOrder
.
getRefundReason
());
// 退款原因
// 生成签名
String
sign
=
XxpayKit
.
getSign
(
paramMap
,
params
.
getKey
());
paramMap
.
put
(
"sign"
,
sign
);
// 退款地址
String
refundUrl
=
XxpayKit
.
getRefundUrl
(
params
.
getPayUrl
())+
"?"
+
JeepayKit
.
genUrlParams
(
paramMap
);
String
resStr
=
""
;
try
{
log
.
info
(
"发起退款[{}]参数:{}"
,
getIfCode
(),
refundUrl
);
resStr
=
HttpUtil
.
createPost
(
refundUrl
).
timeout
(
60
*
1000
).
execute
().
body
();
log
.
info
(
"发起退款[{}]结果:{}"
,
getIfCode
(),
resStr
);
}
catch
(
Exception
e
)
{
log
.
error
(
"http error"
,
e
);
}
ChannelRetMsg
channelRetMsg
=
new
ChannelRetMsg
();
// 默认退款中状态
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
if
(
StringUtils
.
isEmpty
(
resStr
))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelErrCode
(
""
);
channelRetMsg
.
setChannelErrMsg
(
"请求"
+
getIfCode
()+
"接口异常"
);
return
null
;
}
JSONObject
resObj
=
JSONObject
.
parseObject
(
resStr
);
if
(!
"0"
.
equals
(
resObj
.
getString
(
"retCode"
))){
String
retMsg
=
resObj
.
getString
(
"retMsg"
);
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelErrCode
(
""
);
channelRetMsg
.
setChannelErrMsg
(
retMsg
);
return
null
;
}
// 验证响应数据签名
String
checkSign
=
resObj
.
getString
(
"sign"
);
resObj
.
remove
(
"sign"
);
if
(!
checkSign
.
equals
(
XxpayKit
.
getSign
(
resObj
,
params
.
getKey
())))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
return
null
;
}
// 退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败
String
status
=
resObj
.
getString
(
"status"
);
if
(
"2"
.
equals
(
status
))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
}
else
if
(
"3"
.
equals
(
status
))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelErrMsg
(
resObj
.
getString
(
"retMsg"
));
}
return
channelRetMsg
;
}
@Override
public
ChannelRetMsg
query
(
RefundOrder
refundOrder
,
MchAppConfigContext
mchAppConfigContext
)
throws
Exception
{
XxpayNormalMchParams
params
=
mchAppConfigContext
.
getNormalMchParamsByIfCode
(
getIfCode
(),
XxpayNormalMchParams
.
class
);
// 构造支付请求参数
Map
<
String
,
Object
>
paramMap
=
new
TreeMap
();
paramMap
.
put
(
"mchId"
,
params
.
getMchId
());
//商户ID
paramMap
.
put
(
"mchRefundNo"
,
refundOrder
.
getRefundOrderId
());
//商户退款单号
// 生成签名
String
sign
=
XxpayKit
.
getSign
(
paramMap
,
params
.
getKey
());
paramMap
.
put
(
"sign"
,
sign
);
// 退款查询地址
String
queryRefundOrderUrl
=
XxpayKit
.
getQueryRefundOrderUrl
(
params
.
getPayUrl
())+
"?"
+
JeepayKit
.
genUrlParams
(
paramMap
);
String
resStr
=
""
;
try
{
log
.
info
(
"查询退款[{}]参数:{}"
,
getIfCode
(),
queryRefundOrderUrl
);
resStr
=
HttpUtil
.
createPost
(
queryRefundOrderUrl
).
timeout
(
60
*
1000
).
execute
().
body
();
log
.
info
(
"查询退款[{}]结果:{}"
,
getIfCode
(),
resStr
);
}
catch
(
Exception
e
)
{
log
.
error
(
"http error"
,
e
);
}
ChannelRetMsg
channelRetMsg
=
new
ChannelRetMsg
();
// 默认退款中状态
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
if
(
StringUtils
.
isEmpty
(
resStr
))
{
return
null
;
}
JSONObject
resObj
=
JSONObject
.
parseObject
(
resStr
);
if
(!
"0"
.
equals
(
resObj
.
getString
(
"retCode"
))){
return
null
;
}
// 验证响应数据签名
String
checkSign
=
resObj
.
getString
(
"sign"
);
resObj
.
remove
(
"sign"
);
if
(!
checkSign
.
equals
(
XxpayKit
.
getSign
(
resObj
,
params
.
getKey
())))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
return
null
;
}
// 退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败
String
status
=
resObj
.
getString
(
"status"
);
if
(
"2"
.
equals
(
status
))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
}
else
if
(
"3"
.
equals
(
status
))
{
channelRetMsg
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
channelRetMsg
.
setChannelErrMsg
(
resObj
.
getString
(
"retMsg"
));
}
return
channelRetMsg
;
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/refund/ChannelRefundNoticeController.java
0 → 100644
View file @
0bbd04d0
/*
* 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.refund
;
import
com.jeequan.jeepay.core.ctrls.AbstractCtrl
;
import
com.jeequan.jeepay.core.entity.RefundOrder
;
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.IChannelRefundNoticeService
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.service.ConfigContextService
;
import
com.jeequan.jeepay.pay.service.RefundOrderProcessService
;
import
com.jeequan.jeepay.service.impl.RefundOrderService
;
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
;
/*
* 渠道侧的退款通知入口Controller 【异步回调(doNotify) 】
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/25 22:35
*/
@Slf4j
@Controller
public
class
ChannelRefundNoticeController
extends
AbstractCtrl
{
@Autowired
private
RefundOrderService
refundOrderService
;
@Autowired
private
ConfigContextService
configContextService
;
@Autowired
private
RefundOrderProcessService
refundOrderProcessService
;
/** 异步回调入口 **/
@ResponseBody
@RequestMapping
(
value
=
{
"/api/refund/notify/{ifCode}"
,
"/api/refund/notify/{ifCode}/{refundOrderId}"
})
public
ResponseEntity
doNotify
(
HttpServletRequest
request
,
@PathVariable
(
"ifCode"
)
String
ifCode
,
@PathVariable
(
value
=
"refundOrderId"
,
required
=
false
)
String
urlOrderId
){
String
refundOrderId
=
null
;
String
logPrefix
=
"进入["
+
ifCode
+
"]退款回调:urlOrderId:["
+
StringUtils
.
defaultIfEmpty
(
urlOrderId
,
""
)
+
"] "
;
log
.
info
(
"===== {} ====="
,
logPrefix
);
try
{
// 参数有误
if
(
StringUtils
.
isEmpty
(
ifCode
)){
return
ResponseEntity
.
badRequest
().
body
(
"ifCode is empty"
);
}
//查询退款接口是否存在
IChannelRefundNoticeService
refundNotifyService
=
SpringBeansUtil
.
getBean
(
ifCode
+
"ChannelRefundNoticeService"
,
IChannelRefundNoticeService
.
class
);
// 支付通道接口实现不存在
if
(
refundNotifyService
==
null
){
log
.
error
(
"{}, interface not exists "
,
logPrefix
);
return
ResponseEntity
.
badRequest
().
body
(
"["
+
ifCode
+
"] interface not exists"
);
}
// 解析订单号 和 请求参数
MutablePair
<
String
,
Object
>
mutablePair
=
refundNotifyService
.
parseParams
(
request
,
urlOrderId
,
IChannelRefundNoticeService
.
NoticeTypeEnum
.
DO_NOTIFY
);
if
(
mutablePair
==
null
){
// 解析数据失败, 响应已处理
log
.
error
(
"{}, mutablePair is null "
,
logPrefix
);
throw
new
BizException
(
"解析数据异常!"
);
//需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
// 解析到订单号
refundOrderId
=
mutablePair
.
left
;
log
.
info
(
"{}, 解析数据为:refundOrderId:{}, params:{}"
,
logPrefix
,
refundOrderId
,
mutablePair
.
getRight
());
if
(
StringUtils
.
isNotEmpty
(
urlOrderId
)
&&
!
urlOrderId
.
equals
(
refundOrderId
)){
log
.
error
(
"{}, 订单号不匹配. urlOrderId={}, refundOrderId={} "
,
logPrefix
,
urlOrderId
,
refundOrderId
);
throw
new
BizException
(
"退款单号不匹配!"
);
}
//获取订单号 和 订单数据
RefundOrder
refundOrder
=
refundOrderService
.
getById
(
refundOrderId
);
// 订单不存在
if
(
refundOrder
==
null
){
log
.
error
(
"{}, 退款订单不存在. refundOrder={} "
,
logPrefix
,
refundOrder
);
return
refundNotifyService
.
doNotifyOrderNotExists
(
request
);
}
//查询出商户应用的配置信息
MchAppConfigContext
mchAppConfigContext
=
configContextService
.
getMchAppConfigContext
(
refundOrder
.
getMchNo
(),
refundOrder
.
getAppId
());
//调起接口的回调判断
ChannelRetMsg
notifyResult
=
refundNotifyService
.
doNotice
(
request
,
mutablePair
.
getRight
(),
refundOrder
,
mchAppConfigContext
,
IChannelRefundNoticeService
.
NoticeTypeEnum
.
DO_NOTIFY
);
// 返回null 表明出现异常, 无需处理通知下游等操作。
if
(
notifyResult
==
null
||
notifyResult
.
getChannelState
()
==
null
||
notifyResult
.
getResponseEntity
()
==
null
){
log
.
error
(
"{}, 处理回调事件异常 notifyResult data error, notifyResult ={} "
,
logPrefix
,
notifyResult
);
throw
new
BizException
(
"处理回调事件异常!"
);
//需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
// 处理退款订单
boolean
updateOrderSuccess
=
refundOrderProcessService
.
handleRefundOrder4Channel
(
notifyResult
,
refundOrder
);
// 更新退款订单 异常
if
(!
updateOrderSuccess
){
log
.
error
(
"{}, updateOrderSuccess = {} "
,
logPrefix
,
updateOrderSuccess
);
return
refundNotifyService
.
doNotifyOrderStateUpdateFail
(
request
);
}
log
.
info
(
"===== {}, 订单通知完成。 refundOrderId={}, parseState = {} ====="
,
logPrefix
,
refundOrderId
,
notifyResult
.
getChannelState
());
return
notifyResult
.
getResponseEntity
();
}
catch
(
BizException
e
)
{
log
.
error
(
"{}, refundOrderId={}, BizException"
,
logPrefix
,
refundOrderId
,
e
);
return
ResponseEntity
.
badRequest
().
body
(
e
.
getMessage
());
}
catch
(
ResponseException
e
)
{
log
.
error
(
"{}, refundOrderId={}, ResponseException"
,
logPrefix
,
refundOrderId
,
e
);
return
e
.
getResponseEntity
();
}
catch
(
Exception
e
)
{
log
.
error
(
"{}, refundOrderId={}, 系统异常"
,
logPrefix
,
refundOrderId
,
e
);
return
ResponseEntity
.
badRequest
().
body
(
e
.
getMessage
());
}
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/service/ChannelOrderReissueService.java
View file @
0bbd04d0
...
...
@@ -46,6 +46,7 @@ public class ChannelOrderReissueService {
@Autowired
private
RefundOrderService
refundOrderService
;
@Autowired
private
PayOrderProcessService
payOrderProcessService
;
@Autowired
private
PayMchNotifyService
payMchNotifyService
;
@Autowired
private
RefundOrderProcessService
refundOrderProcessService
;
/** 处理订单 **/
...
...
@@ -124,28 +125,8 @@ public class ChannelOrderReissueService {
}
log
.
info
(
"退款补单:[{}]查询结果为:{}"
,
refundOrderId
,
channelRetMsg
);
// 查询成功
if
(
channelRetMsg
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
)
{
if
(
refundOrderService
.
updateIng2Success
(
refundOrderId
,
channelRetMsg
.
getChannelOrderId
()))
{
// 通知商户系统
if
(
StringUtils
.
isNotEmpty
(
refundOrder
.
getNotifyUrl
())){
payMchNotifyService
.
refundOrderNotify
(
refundOrderService
.
getById
(
refundOrderId
));
}
}
}
else
if
(
channelRetMsg
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
){
//确认失败
//1. 更新支付订单表为失败状态
refundOrderService
.
updateIng2Fail
(
refundOrderId
,
channelRetMsg
.
getChannelOrderId
(),
channelRetMsg
.
getChannelErrCode
(),
channelRetMsg
.
getChannelErrMsg
());
// 通知商户系统
if
(
StringUtils
.
isNotEmpty
(
refundOrder
.
getNotifyUrl
())){
payMchNotifyService
.
refundOrderNotify
(
refundOrderService
.
getById
(
refundOrderId
));
}
}
// 根据渠道返回结果,处理退款订单
refundOrderProcessService
.
handleRefundOrder4Channel
(
channelRetMsg
,
refundOrder
);
return
channelRetMsg
;
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/service/RefundOrderProcessService.java
0 → 100644
View file @
0bbd04d0
/*
* 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.service
;
import
com.jeequan.jeepay.core.entity.RefundOrder
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.service.impl.RefundOrderService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
/***
* 退款处理通用逻辑
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/25 23:50
*/
@Service
@Slf4j
public
class
RefundOrderProcessService
{
@Autowired
private
RefundOrderService
refundOrderService
;
@Autowired
private
PayMchNotifyService
payMchNotifyService
;
/** 根据通道返回的状态,处理退款订单业务 **/
public
boolean
handleRefundOrder4Channel
(
ChannelRetMsg
channelRetMsg
,
RefundOrder
refundOrder
){
boolean
updateOrderSuccess
=
true
;
//默认更新成功
String
refundOrderId
=
refundOrder
.
getRefundOrderId
();
// 明确退款成功
if
(
channelRetMsg
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
)
{
updateOrderSuccess
=
refundOrderService
.
updateIng2Success
(
refundOrderId
,
channelRetMsg
.
getChannelOrderId
());
if
(
updateOrderSuccess
)
{
// 通知商户系统
if
(
StringUtils
.
isNotEmpty
(
refundOrder
.
getNotifyUrl
())){
payMchNotifyService
.
refundOrderNotify
(
refundOrderService
.
getById
(
refundOrderId
));
}
}
//确认失败
}
else
if
(
channelRetMsg
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
){
// 更新为失败状态
updateOrderSuccess
=
refundOrderService
.
updateIng2Fail
(
refundOrderId
,
channelRetMsg
.
getChannelOrderId
(),
channelRetMsg
.
getChannelErrCode
(),
channelRetMsg
.
getChannelErrMsg
());
// 通知商户系统
if
(
StringUtils
.
isNotEmpty
(
refundOrder
.
getNotifyUrl
())){
payMchNotifyService
.
refundOrderNotify
(
refundOrderService
.
getById
(
refundOrderId
));
}
}
return
updateOrderSuccess
;
}
}
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