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
71b4cc66
Commit
71b4cc66
authored
Jan 25, 2022
by
xiaoyu
Browse files
微信退款回调,微信、支付宝、云闪付关闭订单接口
parent
e6c0f794
Changes
14
Hide whitespace changes
Inline
Side-by-side
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/IPayOrderCloseService.java
0 → 100644
View file @
71b4cc66
/*
* 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.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
/**
* 关闭订单(渠道侧)接口定义
*
* @author xiaoyu
* @site https://www.jeequan.com
* @date 2022/1/24 17:23
*/
public
interface
IPayOrderCloseService
{
/** 获取到接口code **/
String
getIfCode
();
/** 查询订单 **/
ChannelRetMsg
close
(
PayOrder
payOrder
,
MchAppConfigContext
mchAppConfigContext
)
throws
Exception
;
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayKit.java
View file @
71b4cc66
...
...
@@ -77,6 +77,8 @@ public class AlipayKit {
((
AlipayTradeRoyaltyRelationBindRequest
)
req
).
putOtherTextParam
(
"app_auth_token"
,
isvsubMchParams
.
getAppAuthToken
());
}
else
if
(
req
instanceof
AlipayTradeOrderSettleRequest
)
{
((
AlipayTradeOrderSettleRequest
)
req
).
putOtherTextParam
(
"app_auth_token"
,
isvsubMchParams
.
getAppAuthToken
());
}
else
if
(
req
instanceof
AlipayTradeCloseRequest
)
{
((
AlipayTradeCloseRequest
)
req
).
putOtherTextParam
(
"app_auth_token"
,
isvsubMchParams
.
getAppAuthToken
());
}
// 服务商信息
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/alipay/AlipayPayOrderCloseService.java
0 → 100644
View file @
71b4cc66
/*
* 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.alipay.api.domain.AlipayTradeCloseModel
;
import
com.alipay.api.request.AlipayTradeCloseRequest
;
import
com.alipay.api.response.AlipayTradeCloseResponse
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.pay.channel.IPayOrderCloseService
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.service.ConfigContextQueryService
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
/**
* 支付宝 关闭订单接口实现类
*
* @author xiaoyu
* @site https://www.jeequan.com
* @date 2022/1/25 11:17
*/
@Service
public
class
AlipayPayOrderCloseService
implements
IPayOrderCloseService
{
@Autowired
private
ConfigContextQueryService
configContextQueryService
;
@Override
public
String
getIfCode
()
{
return
CS
.
IF_CODE
.
ALIPAY
;
}
@Override
public
ChannelRetMsg
close
(
PayOrder
payOrder
,
MchAppConfigContext
mchAppConfigContext
){
AlipayTradeCloseRequest
req
=
new
AlipayTradeCloseRequest
();
// 商户订单号,商户网站订单系统中唯一订单号,必填
AlipayTradeCloseModel
model
=
new
AlipayTradeCloseModel
();
model
.
setOutTradeNo
(
payOrder
.
getPayOrderId
());
req
.
setBizModel
(
model
);
//通用字段
AlipayKit
.
putApiIsvInfo
(
mchAppConfigContext
,
req
,
model
);
AlipayTradeCloseResponse
resp
=
configContextQueryService
.
getAlipayClientWrapper
(
mchAppConfigContext
).
execute
(
req
);
// 返回状态成功
if
(
resp
.
isSuccess
())
{
return
ChannelRetMsg
.
confirmSuccess
(
resp
.
getTradeNo
());
}
else
{
return
ChannelRetMsg
.
sysError
(
resp
.
getSubMsg
());
}
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/WxpayChannelRefundNoticeService.java
0 → 100644
View file @
71b4cc66
/*
* 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.wxpay
;
import
com.alibaba.fastjson.JSONObject
;
import
com.github.binarywang.wxpay.bean.notify.SignatureHeader
;
import
com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse
;
import
com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult
;
import
com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result
;
import
com.github.binarywang.wxpay.config.WxPayConfig
;
import
com.github.binarywang.wxpay.service.WxPayService
;
import
com.github.binarywang.wxpay.v3.auth.AutoUpdateCertificatesVerifier
;
import
com.github.binarywang.wxpay.v3.auth.PrivateKeySigner
;
import
com.github.binarywang.wxpay.v3.auth.WxPayCredentials
;
import
com.github.binarywang.wxpay.v3.util.PemUtils
;
import
com.jeequan.jeepay.core.constants.CS
;
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.model.params.wxpay.WxpayIsvParams
;
import
com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams
;
import
com.jeequan.jeepay.pay.channel.AbstractChannelRefundNoticeService
;
import
com.jeequan.jeepay.pay.model.IsvConfigContext
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.model.WxServiceWrapper
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.service.impl.RefundOrderService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.io.IOUtils
;
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.Service
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.FileInputStream
;
import
java.math.BigDecimal
;
import
java.security.PrivateKey
;
/*
* 微信支付 退款回调接口实现类
*
* @author xiaoyu
* @site https://www.jeequan.com
* @date 2022/1/24 9:59
*/
@Service
@Slf4j
public
class
WxpayChannelRefundNoticeService
extends
AbstractChannelRefundNoticeService
{
@Autowired
RefundOrderService
refundOrderService
;
@Override
public
String
getIfCode
()
{
return
CS
.
IF_CODE
.
WXPAY
;
}
@Override
public
MutablePair
<
String
,
Object
>
parseParams
(
HttpServletRequest
request
,
String
urlOrderId
,
NoticeTypeEnum
noticeTypeEnum
)
{
try
{
// 获取订单信息
RefundOrder
refundOrder
=
refundOrderService
.
getById
(
urlOrderId
);
if
(
refundOrder
==
null
){
throw
new
BizException
(
"订单不存在"
);
}
//获取支付参数 (缓存数据) 和 商户信息
MchAppConfigContext
mchAppConfigContext
=
configContextQueryService
.
queryMchInfoAndAppInfo
(
refundOrder
.
getMchNo
(),
refundOrder
.
getAppId
());
if
(
mchAppConfigContext
==
null
){
throw
new
BizException
(
"获取商户信息失败"
);
}
String
apiVersion
=
""
;
Byte
mchType
=
mchAppConfigContext
.
getMchType
();
if
(
CS
.
MCH_TYPE_NORMAL
==
mchType
)
{
WxpayNormalMchParams
normalMchParams
=
mchAppConfigContext
.
getNormalMchParamsByIfCode
(
getIfCode
(),
WxpayNormalMchParams
.
class
);
apiVersion
=
normalMchParams
.
getApiVersion
();
}
else
if
(
CS
.
MCH_TYPE_ISVSUB
==
mchType
)
{
IsvConfigContext
configContext
=
mchAppConfigContext
.
getIsvConfigContext
();
WxpayIsvParams
wxpayIsvParams
=
configContext
.
getIsvParamsByIfCode
(
getIfCode
(),
WxpayIsvParams
.
class
);
apiVersion
=
wxpayIsvParams
.
getApiVersion
();
}
else
{
throw
new
BizException
(
"商户类型错误"
);
}
if
(
CS
.
PAY_IF_VERSION
.
WX_V3
.
equals
(
apiVersion
)){
// V3接口回调
// 验签 && 获取订单回调数据
WxPayRefundNotifyV3Result
.
DecryptNotifyResult
result
=
parseOrderNotifyV3Result
(
request
,
mchAppConfigContext
);
return
MutablePair
.
of
(
urlOrderId
,
result
);
}
else
if
(
CS
.
PAY_IF_VERSION
.
WX_V2
.
equals
(
apiVersion
)){
// V2接口回调
String
xmlResult
=
IOUtils
.
toString
(
request
.
getInputStream
(),
request
.
getCharacterEncoding
());
if
(
StringUtils
.
isEmpty
(
xmlResult
))
{
return
null
;
}
WxpayNormalMchParams
normalMchParams
=
mchAppConfigContext
.
getNormalMchParamsByIfCode
(
getIfCode
(),
WxpayNormalMchParams
.
class
);
WxPayRefundNotifyResult
result
=
WxPayRefundNotifyResult
.
fromXML
(
xmlResult
,
normalMchParams
.
getKey
());
return
MutablePair
.
of
(
urlOrderId
,
result
.
getReqInfo
());
}
return
null
;
}
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
{
ChannelRetMsg
result
=
new
ChannelRetMsg
();
WxServiceWrapper
wxServiceWrapper
=
configContextQueryService
.
getWxServiceWrapper
(
mchAppConfigContext
);
result
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
WAITING
);
// 默认支付中
if
(
CS
.
PAY_IF_VERSION
.
WX_V3
.
equals
(
wxServiceWrapper
.
getApiVersion
()))
{
WxPayRefundNotifyV3Result
.
DecryptNotifyResult
notifyResult
=
(
WxPayRefundNotifyV3Result
.
DecryptNotifyResult
)
params
;
// 验证参数
verifyWxPay3Params
(
notifyResult
,
refundOrder
);
String
refundStatus
=
notifyResult
.
getRefundStatus
();
if
(
"SUCCESS"
.
equals
(
refundStatus
))
{
result
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
}
else
{
//CHANGE—退款异常, REFUNDCLOSE—退款关闭
result
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
//退款失败
}
result
.
setChannelOrderId
(
notifyResult
.
getTransactionId
());
// 渠道订单号
JSONObject
resJSON
=
new
JSONObject
();
resJSON
.
put
(
"code"
,
"SUCCESS"
);
resJSON
.
put
(
"message"
,
"成功"
);
ResponseEntity
okResponse
=
jsonResp
(
resJSON
);
result
.
setResponseEntity
(
okResponse
);
//响应数据
}
else
if
(
CS
.
PAY_IF_VERSION
.
WX_V2
.
equals
(
wxServiceWrapper
.
getApiVersion
()))
{
// 获取回调参数
WxPayRefundNotifyResult
.
ReqInfo
notifyResult
=
(
WxPayRefundNotifyResult
.
ReqInfo
)
params
;
// 验证参数
verifyWxPay2Params
(
notifyResult
,
refundOrder
);
result
.
setChannelOrderId
(
notifyResult
.
getTransactionId
());
//渠道订单号
if
(
"SUCCESS"
.
equals
(
notifyResult
.
getRefundStatus
()))
{
result
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
);
}
else
{
//CHANGE—退款异常, REFUNDCLOSE—退款关闭
result
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
//退款失败
}
result
.
setResponseEntity
(
textResp
(
WxPayNotifyResponse
.
successResp
(
"OK"
)));
}
else
{
result
.
setChannelState
(
ChannelRetMsg
.
ChannelState
.
CONFIRM_FAIL
);
//退款失败
}
return
result
;
}
catch
(
Exception
e
)
{
log
.
error
(
"error"
,
e
);
throw
ResponseException
.
buildText
(
"ERROR"
);
}
}
/**
* V3校验通知签名
* @param request 请求信息
* @param mchAppConfigContext 商户配置
* @return true:校验通过 false:校验不通过
*/
private
WxPayRefundNotifyV3Result
.
DecryptNotifyResult
parseOrderNotifyV3Result
(
HttpServletRequest
request
,
MchAppConfigContext
mchAppConfigContext
)
throws
Exception
{
SignatureHeader
header
=
new
SignatureHeader
();
header
.
setTimeStamp
(
request
.
getHeader
(
"Wechatpay-Timestamp"
));
header
.
setNonce
(
request
.
getHeader
(
"Wechatpay-Nonce"
));
header
.
setSerial
(
request
.
getHeader
(
"Wechatpay-Serial"
));
header
.
setSignature
(
request
.
getHeader
(
"Wechatpay-Signature"
));
// 获取加密信息
String
params
=
getReqParamFromBody
();
log
.
info
(
"\n【请求头信息】:{}\n【加密数据】:{}"
,
header
.
toString
(),
params
);
WxPayService
wxPayService
=
configContextQueryService
.
getWxServiceWrapper
(
mchAppConfigContext
).
getWxPayService
();
WxPayConfig
wxPayConfig
=
wxPayService
.
getConfig
();
// 自动获取微信平台证书
PrivateKey
privateKey
=
PemUtils
.
loadPrivateKey
(
new
FileInputStream
(
wxPayConfig
.
getPrivateKeyPath
()));
AutoUpdateCertificatesVerifier
verifier
=
new
AutoUpdateCertificatesVerifier
(
new
WxPayCredentials
(
wxPayConfig
.
getMchId
(),
new
PrivateKeySigner
(
wxPayConfig
.
getCertSerialNo
(),
privateKey
)),
wxPayConfig
.
getApiV3Key
().
getBytes
(
"utf-8"
));
wxPayConfig
.
setVerifier
(
verifier
);
wxPayService
.
setConfig
(
wxPayConfig
);
WxPayRefundNotifyV3Result
result
=
wxPayService
.
parseRefundNotifyV3Result
(
params
,
header
);
return
result
.
getResult
();
}
/**
* V3接口验证微信支付通知参数
* @return
*/
public
void
verifyWxPay3Params
(
WxPayRefundNotifyV3Result
.
DecryptNotifyResult
result
,
RefundOrder
refundOrder
)
{
try
{
// 核对金额
Integer
total_fee
=
result
.
getAmount
().
getTotal
();
// 退款金额
long
wxPayAmt
=
new
BigDecimal
(
total_fee
).
longValue
();
long
dbPayAmt
=
refundOrder
.
getRefundAmount
().
longValue
();
if
(
dbPayAmt
!=
wxPayAmt
)
{
throw
ResponseException
.
buildText
(
"AMOUNT ERROR"
);
}
}
catch
(
Exception
e
)
{
throw
ResponseException
.
buildText
(
"ERROR"
);
}
}
/**
* V2接口验证微信支付通知参数
* @return
*/
public
void
verifyWxPay2Params
(
WxPayRefundNotifyResult
.
ReqInfo
result
,
RefundOrder
refundOrder
)
{
try
{
// 核对金额
Integer
total_fee
=
result
.
getRefundFee
();
// 退款金额
long
wxPayAmt
=
new
BigDecimal
(
total_fee
).
longValue
();
long
dbPayAmt
=
refundOrder
.
getRefundAmount
().
longValue
();
if
(
dbPayAmt
!=
wxPayAmt
)
{
throw
ResponseException
.
buildText
(
"AMOUNT ERROR"
);
}
}
catch
(
Exception
e
)
{
throw
ResponseException
.
buildText
(
"ERROR"
);
}
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/WxpayPayOrderCloseService.java
0 → 100644
View file @
71b4cc66
/*
* 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.wxpay
;
import
com.alibaba.fastjson.JSONObject
;
import
com.github.binarywang.wxpay.bean.request.WxPayOrderCloseRequest
;
import
com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult
;
import
com.github.binarywang.wxpay.exception.WxPayException
;
import
com.github.binarywang.wxpay.service.WxPayService
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams
;
import
com.jeequan.jeepay.pay.channel.IPayOrderCloseService
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit
;
import
com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayV3Util
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.model.WxServiceWrapper
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.service.ConfigContextQueryService
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
/**
* 微信关闭订单
*
* @author xiaoyu
* @site https://www.jeequan.com
* @date 2022/1/24 17:25
*/
@Service
public
class
WxpayPayOrderCloseService
implements
IPayOrderCloseService
{
@Autowired
private
ConfigContextQueryService
configContextQueryService
;
@Override
public
String
getIfCode
()
{
return
CS
.
IF_CODE
.
WXPAY
;
}
@Override
public
ChannelRetMsg
close
(
PayOrder
payOrder
,
MchAppConfigContext
mchAppConfigContext
)
{
try
{
WxServiceWrapper
wxServiceWrapper
=
configContextQueryService
.
getWxServiceWrapper
(
mchAppConfigContext
);
if
(
CS
.
PAY_IF_VERSION
.
WX_V2
.
equals
(
wxServiceWrapper
.
getApiVersion
()))
{
//V2
WxPayOrderCloseRequest
req
=
new
WxPayOrderCloseRequest
();
//放置isv信息
WxpayKit
.
putApiIsvInfo
(
mchAppConfigContext
,
req
);
req
.
setOutTradeNo
(
payOrder
.
getPayOrderId
());
WxPayService
wxPayService
=
wxServiceWrapper
.
getWxPayService
();
WxPayOrderCloseResult
result
=
wxPayService
.
closeOrder
(
req
);
if
(
"SUCCESS"
.
equals
(
result
.
getResultCode
())){
//关闭订单成功
return
ChannelRetMsg
.
confirmSuccess
(
null
);
}
else
if
(
"FAIL"
.
equals
(
result
.
getResultCode
())){
//关闭订单失败
return
ChannelRetMsg
.
confirmFail
();
//关闭失败
}
else
{
return
ChannelRetMsg
.
waiting
();
//关闭中
}
}
else
if
(
CS
.
PAY_IF_VERSION
.
WX_V3
.
equals
(
wxServiceWrapper
.
getApiVersion
()))
{
//V3
String
reqUrl
;
JSONObject
reqJson
=
new
JSONObject
();
if
(
mchAppConfigContext
.
isIsvsubMch
()){
// 特约商户
WxpayIsvsubMchParams
isvsubMchParams
=
(
WxpayIsvsubMchParams
)
configContextQueryService
.
queryIsvsubMchParams
(
mchAppConfigContext
.
getMchNo
(),
mchAppConfigContext
.
getAppId
(),
getIfCode
());
reqUrl
=
String
.
format
(
"/v3/pay/partner/transactions/out-trade-no/%s/close"
,
payOrder
.
getMchOrderNo
());
reqJson
.
put
(
"sp_mchid"
,
wxServiceWrapper
.
getWxPayService
().
getConfig
().
getMchId
());
reqJson
.
put
(
"sub_mchid"
,
isvsubMchParams
.
getSubMchId
());
}
else
{
reqUrl
=
String
.
format
(
"/v3/pay/transactions/out-trade-no/%s/close"
,
payOrder
.
getMchOrderNo
());
reqJson
.
put
(
"mchid"
,
wxServiceWrapper
.
getWxPayService
().
getConfig
().
getMchId
());
}
WxpayV3Util
.
closeOrderV3
(
reqUrl
,
reqJson
,
wxServiceWrapper
.
getWxPayService
().
getConfig
());
return
ChannelRetMsg
.
confirmSuccess
(
null
);
}
return
ChannelRetMsg
.
confirmFail
();
}
catch
(
WxPayException
e
)
{
return
ChannelRetMsg
.
sysError
(
e
.
getReturnMsg
());
}
catch
(
Exception
e
)
{
return
ChannelRetMsg
.
sysError
(
e
.
getMessage
());
}
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/WxpayRefundService.java
View file @
71b4cc66
...
...
@@ -79,6 +79,7 @@ public class WxpayRefundService extends AbstractRefundService {
req
.
setOutRefundNo
(
refundOrder
.
getRefundOrderId
());
// 退款单号
req
.
setTotalFee
(
payOrder
.
getAmount
().
intValue
());
// 订单总金额
req
.
setRefundFee
(
refundOrder
.
getRefundAmount
().
intValue
());
// 退款金额
req
.
setNotifyUrl
(
getNotifyUrl
(
refundOrder
.
getRefundOrderId
()));
// 回调url
WxPayService
wxPayService
=
wxServiceWrapper
.
getWxPayService
();
setCretPath
(
mchAppConfigContext
,
wxPayService
);
// 证书路径
...
...
@@ -96,6 +97,7 @@ public class WxpayRefundService extends AbstractRefundService {
JSONObject
reqJSON
=
new
JSONObject
();
reqJSON
.
put
(
"out_trade_no"
,
refundOrder
.
getPayOrderId
());
// 订单号
reqJSON
.
put
(
"out_refund_no"
,
refundOrder
.
getRefundOrderId
());
// 退款订单号
reqJSON
.
put
(
"notify_url"
,
getNotifyUrl
(
refundOrder
.
getRefundOrderId
()));
// 回调地址
JSONObject
amountJson
=
new
JSONObject
();
amountJson
.
put
(
"refund"
,
refundOrder
.
getRefundAmount
());
// 退款金额
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/wxpay/kits/WxpayV3Util.java
View file @
71b4cc66
...
...
@@ -83,6 +83,11 @@ public class WxpayV3Util {
return
JSON
.
parseObject
(
response
);
}
public
static
JSONObject
closeOrderV3
(
String
url
,
JSONObject
reqJSON
,
WxPayConfig
wxPayConfig
)
throws
WxPayException
{
String
response
=
postV3
(
PAY_BASE_URL
+
url
,
reqJSON
.
toJSONString
(),
wxPayConfig
);
return
JSON
.
parseObject
(
response
);
}
public
static
JSONObject
refundV3
(
JSONObject
reqJSON
,
WxPayConfig
wxPayConfig
)
throws
WxPayException
{
String
url
=
String
.
format
(
"%s/v3/refund/domestic/refunds"
,
PAY_BASE_URL
);
String
response
=
postV3
(
url
,
reqJSON
.
toJSONString
(),
wxPayConfig
);
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/channel/ysfpay/YsfpayPayOrderCloseService.java
0 → 100644
View file @
71b4cc66
/*
* 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.ysfpay
;
import
com.alibaba.fastjson.JSONObject
;
import
com.jeequan.jeepay.core.constants.CS
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.pay.channel.IPayOrderCloseService
;
import
com.jeequan.jeepay.pay.channel.IPayOrderQueryService
;
import
com.jeequan.jeepay.pay.channel.ysfpay.utils.YsfHttpUtil
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
/**
* 云闪付 关闭订单接口实现类
*
* @author pangxiaoyu
* @site https://www.jeequan.com
* @date 2021-06-07 07:15
*/
@Service
@Slf4j
public
class
YsfpayPayOrderCloseService
implements
IPayOrderCloseService
{
@Override
public
String
getIfCode
()
{
return
CS
.
IF_CODE
.
YSFPAY
;
}
@Autowired
private
YsfpayPaymentService
ysfpayPaymentService
;
@Override
public
ChannelRetMsg
close
(
PayOrder
payOrder
,
MchAppConfigContext
mchAppConfigContext
)
throws
Exception
{
JSONObject
reqParams
=
new
JSONObject
();
String
orderType
=
YsfHttpUtil
.
getOrderTypeByCommon
(
payOrder
.
getWayCode
());
String
logPrefix
=
"【云闪付("
+
orderType
+
")关闭订单】"
;
try
{
reqParams
.
put
(
"orderNo"
,
payOrder
.
getPayOrderId
());
//订单号
reqParams
.
put
(
"orderType"
,
orderType
);
//订单类型
//封装公共参数 & 签名 & 调起http请求 & 返回响应数据并包装为json格式。
JSONObject
resJSON
=
ysfpayPaymentService
.
packageParamAndReq
(
"/gateway/api/pay/closeOrder"
,
reqParams
,
logPrefix
,
mchAppConfigContext
);
log
.
info
(
"关闭订单 payorderId:{}, 返回结果:{}"
,
payOrder
.
getPayOrderId
(),
resJSON
);
if
(
resJSON
==
null
){
return
ChannelRetMsg
.
sysError
(
"【云闪付】请求关闭订单异常"
);
}
//请求 & 响应成功, 判断业务逻辑
String
respCode
=
resJSON
.
getString
(
"respCode"
);
//应答码
String
respMsg
=
resJSON
.
getString
(
"respMsg"
);
//应答信息
if
((
"00"
).
equals
(
respCode
)){
// 请求成功
return
ChannelRetMsg
.
confirmSuccess
(
null
);
//关单成功
}
return
ChannelRetMsg
.
sysError
(
respMsg
);
// 关单失败
}
catch
(
Exception
e
)
{
return
ChannelRetMsg
.
sysError
(
e
.
getMessage
());
// 关单失败
}
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/payorder/CloseOrderController.java
0 → 100644
View file @
71b4cc66
/*
* 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.payorder
;
import
com.jeequan.jeepay.core.entity.PayOrder
;
import
com.jeequan.jeepay.core.exception.BizException
;
import
com.jeequan.jeepay.core.model.ApiRes
;
import
com.jeequan.jeepay.core.utils.SpringBeansUtil
;
import
com.jeequan.jeepay.pay.channel.IPayOrderCloseService
;
import
com.jeequan.jeepay.pay.ctrl.ApiController
;
import
com.jeequan.jeepay.pay.model.MchAppConfigContext
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
com.jeequan.jeepay.pay.rqrs.payorder.ClosePayOrderRQ
;
import
com.jeequan.jeepay.pay.rqrs.payorder.ClosePayOrderRS
;
import
com.jeequan.jeepay.pay.service.ConfigContextQueryService
;
import
com.jeequan.jeepay.service.impl.PayOrderService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
/*
* 关闭订单 controller
*
* @author xiaoyu
* @site https://www.jeequan.com
* @date 2022/1/25 9:19
*/
@Slf4j
@RestController
public
class
CloseOrderController
extends
ApiController
{
@Autowired
private
PayOrderService
payOrderService
;
@Autowired
private
ConfigContextQueryService
configContextQueryService
;
/**
* @author: xiaoyu
* @date: 2022/1/25 9:19
* @describe: 关闭订单
*/
@RequestMapping
(
"/api/pay/close"
)
public
ApiRes
queryOrder
(){
//获取参数 & 验签
ClosePayOrderRQ
rq
=
getRQByWithMchSign
(
ClosePayOrderRQ
.
class
);
if
(
StringUtils
.
isEmpty
(
rq
.
getPayOrderId
())){
throw
new
BizException
(
"payOrderId不能为空"
);
}
PayOrder
payOrder
=
payOrderService
.
queryMchOrder
(
rq
.
getMchNo
(),
rq
.
getPayOrderId
(),
rq
.
getMchOrderNo
());
if
(
payOrder
==
null
){
throw
new
BizException
(
"订单不存在"
);
}
if
(
payOrder
.
getState
()
!=
PayOrder
.
STATE_INIT
&&
payOrder
.
getState
()
!=
PayOrder
.
STATE_ING
)
{
throw
new
BizException
(
"当前订单不可关闭"
);
}
ClosePayOrderRS
bizRes
=
new
ClosePayOrderRS
();
try
{
String
payOrderId
=
payOrder
.
getPayOrderId
();
//查询支付接口是否存在
IPayOrderCloseService
closeService
=
SpringBeansUtil
.
getBean
(
payOrder
.
getIfCode
()
+
"PayOrderCloseService"
,
IPayOrderCloseService
.
class
);
// 支付通道接口实现不存在
if
(
closeService
==
null
){
log
.
error
(
"{} interface not exists!"
,
payOrder
.
getIfCode
());
return
null
;
}
//查询出商户应用的配置信息
MchAppConfigContext
mchAppConfigContext
=
configContextQueryService
.
queryMchInfoAndAppInfo
(
payOrder
.
getMchNo
(),
payOrder
.
getAppId
());
ChannelRetMsg
channelRetMsg
=
closeService
.
close
(
payOrder
,
mchAppConfigContext
);
if
(
channelRetMsg
==
null
){
log
.
error
(
"channelRetMsg is null"
);
return
null
;
}
log
.
info
(
"关闭订单[{}]结果为:{}"
,
payOrderId
,
channelRetMsg
);
// 关闭订单 成功
if
(
channelRetMsg
.
getChannelState
()
==
ChannelRetMsg
.
ChannelState
.
CONFIRM_SUCCESS
)
{
payOrderService
.
updateIng2Close
(
payOrderId
);
}
else
{
return
ApiRes
.
customFail
(
channelRetMsg
.
getChannelErrMsg
());
}
bizRes
.
setChannelRetMsg
(
channelRetMsg
);
}
catch
(
Exception
e
)
{
// 关闭订单异常
log
.
error
(
"error payOrderId = {}"
,
payOrder
.
getPayOrderId
(),
e
);
return
null
;
}
return
ApiRes
.
okWithSign
(
bizRes
,
configContextQueryService
.
queryMchApp
(
rq
.
getMchNo
(),
rq
.
getAppId
()).
getAppSecret
());
}
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/ctrl/refund/RefundOrderController.java
View file @
71b4cc66
...
...
@@ -261,7 +261,7 @@ public class RefundOrderController extends ApiController {
refundOrder
.
setErrMsg
(
channelRetMsg
.
getChannelErrMsg
());
boolean
isSuccess
=
refundOrderService
.
updateInit2Ing
(
refundOrder
.
getRefundOrderId
());
boolean
isSuccess
=
refundOrderService
.
updateInit2Ing
(
refundOrder
.
getRefundOrderId
()
,
channelRetMsg
.
getChannelOrderId
()
);
if
(!
isSuccess
){
throw
new
BizException
(
"更新退款单异常!"
);
}
...
...
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/rqrs/payorder/ClosePayOrderRQ.java
0 → 100644
View file @
71b4cc66
/*
* 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.payorder
;
import
com.jeequan.jeepay.pay.rqrs.AbstractMchAppRQ
;
import
lombok.Data
;
/*
* 关闭订单 请求参数对象
*
* @author xiaoyu
* @site https://www.jeequan.com
* @date 2022/1/25 9:16
*/
@Data
public
class
ClosePayOrderRQ
extends
AbstractMchAppRQ
{
/** 商户订单号 **/
private
String
mchOrderNo
;
/** 支付系统订单号 **/
private
String
payOrderId
;
}
jeepay-payment/src/main/java/com/jeequan/jeepay/pay/rqrs/payorder/ClosePayOrderRS.java
0 → 100644
View file @
71b4cc66
/*
* 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.payorder
;
import
com.alibaba.fastjson.annotation.JSONField
;
import
com.jeequan.jeepay.pay.rqrs.AbstractRS
;
import
com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg
;
import
lombok.Data
;
/*
* 关闭订单 响应参数
*
* @author xiaoyu
* @site https://www.jeequan.com
* @date 2022/1/25 9:17
*/
@Data
public
class
ClosePayOrderRS
extends
AbstractRS
{
/** 上游渠道返回数据包 (无需JSON序列化) **/
@JSONField
(
serialize
=
false
)
private
ChannelRetMsg
channelRetMsg
;
}
jeepay-service/src/main/java/com/jeequan/jeepay/service/impl/PayOrderService.java
View file @
71b4cc66
...
...
@@ -66,6 +66,7 @@ public class PayOrderService extends ServiceImpl<PayOrderMapper, PayOrder> {
updateRecord
.
setMchFeeRate
(
payOrder
.
getMchFeeRate
());
updateRecord
.
setMchFeeAmount
(
payOrder
.
getMchFeeAmount
());
updateRecord
.
setChannelUser
(
payOrder
.
getChannelUser
());
updateRecord
.
setChannelOrderNo
(
payOrder
.
getChannelOrderNo
());
return
update
(
updateRecord
,
new
LambdaUpdateWrapper
<
PayOrder
>()
.
eq
(
PayOrder:
:
getPayOrderId
,
payOrderId
).
eq
(
PayOrder:
:
getState
,
PayOrder
.
STATE_INIT
));
...
...
@@ -84,6 +85,17 @@ public class PayOrderService extends ServiceImpl<PayOrderMapper, PayOrder> {
.
eq
(
PayOrder:
:
getPayOrderId
,
payOrderId
).
eq
(
PayOrder:
:
getState
,
PayOrder
.
STATE_ING
));
}
/** 更新订单状态 【支付中】 --》 【订单关闭】 **/
public
boolean
updateIng2Close
(
String
payOrderId
){
PayOrder
updateRecord
=
new
PayOrder
();
updateRecord
.
setState
(
PayOrder
.
STATE_CLOSED
);
updateRecord
.
setSuccessTime
(
new
Date
());
return
update
(
updateRecord
,
new
LambdaUpdateWrapper
<
PayOrder
>()
.
eq
(
PayOrder:
:
getPayOrderId
,
payOrderId
).
eq
(
PayOrder:
:
getState
,
PayOrder
.
STATE_ING
));
}
/** 更新订单状态 【支付中】 --》 【支付失败】 **/
public
boolean
updateIng2Fail
(
String
payOrderId
,
String
channelOrderNo
,
String
channelUserId
,
String
channelErrCode
,
String
channelErrMsg
){
...
...
jeepay-service/src/main/java/com/jeequan/jeepay/service/impl/RefundOrderService.java
View file @
71b4cc66
...
...
@@ -59,10 +59,11 @@ public class RefundOrderService extends ServiceImpl<RefundOrderMapper, RefundOrd
/** 更新退款单状态 【退款单生成】 --》 【退款中】 **/
public
boolean
updateInit2Ing
(
String
refundOrderId
){
public
boolean
updateInit2Ing
(
String
refundOrderId
,
String
channelOrderNo
){
RefundOrder
updateRecord
=
new
RefundOrder
();
updateRecord
.
setState
(
RefundOrder
.
STATE_ING
);
updateRecord
.
setChannelOrderNo
(
channelOrderNo
);
return
update
(
updateRecord
,
new
LambdaUpdateWrapper
<
RefundOrder
>()
.
eq
(
RefundOrder:
:
getRefundOrderId
,
refundOrderId
).
eq
(
RefundOrder:
:
getState
,
RefundOrder
.
STATE_INIT
));
...
...
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