添加退款补单和超时关闭; 添加查单控制器
This commit is contained in:
parent
7e119aa212
commit
9e8d51da02
|
|
@ -360,7 +360,7 @@ CREATE TABLE `t_refund_order` (
|
||||||
`pay_amount` BIGINT(20) NOT NULL COMMENT '支付金额,单位分',
|
`pay_amount` BIGINT(20) NOT NULL COMMENT '支付金额,单位分',
|
||||||
`refund_amount` BIGINT(20) NOT NULL COMMENT '退款金额,单位分',
|
`refund_amount` BIGINT(20) NOT NULL COMMENT '退款金额,单位分',
|
||||||
`currency` VARCHAR(3) NOT NULL DEFAULT 'cny' COMMENT '三位货币代码,人民币:cny',
|
`currency` VARCHAR(3) NOT NULL DEFAULT 'cny' COMMENT '三位货币代码,人民币:cny',
|
||||||
`state` TINYINT(6) NOT NULL DEFAULT '0' COMMENT '退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败',
|
`state` TINYINT(6) NOT NULL DEFAULT '0' COMMENT '退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败,4-退款任务关闭',
|
||||||
`client_ip` VARCHAR(32) DEFAULT NULL COMMENT '客户端IP',
|
`client_ip` VARCHAR(32) DEFAULT NULL COMMENT '客户端IP',
|
||||||
`refund_reason` VARCHAR(256) NOT NULL COMMENT '退款原因',
|
`refund_reason` VARCHAR(256) NOT NULL COMMENT '退款原因',
|
||||||
`channel_order_no` VARCHAR(32) DEFAULT NULL COMMENT '渠道订单号',
|
`channel_order_no` VARCHAR(32) DEFAULT NULL COMMENT '渠道订单号',
|
||||||
|
|
@ -370,6 +370,7 @@ CREATE TABLE `t_refund_order` (
|
||||||
`notify_url` VARCHAR(128) DEFAULT NULL COMMENT '通知地址',
|
`notify_url` VARCHAR(128) DEFAULT NULL COMMENT '通知地址',
|
||||||
`ext_param` VARCHAR(64) DEFAULT NULL COMMENT '扩展参数',
|
`ext_param` VARCHAR(64) DEFAULT NULL COMMENT '扩展参数',
|
||||||
`success_time` DATETIME DEFAULT NULL COMMENT '订单退款成功时间',
|
`success_time` DATETIME DEFAULT NULL COMMENT '订单退款成功时间',
|
||||||
|
`expired_time` DATETIME DEFAULT NULL COMMENT '退款失效时间(失效后系统更改为退款任务关闭状态)',
|
||||||
`created_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
|
`created_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
|
||||||
`updated_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
|
`updated_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
|
||||||
PRIMARY KEY (`refund_order_id`),
|
PRIMARY KEY (`refund_order_id`),
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ public class RefundOrder extends BaseModel {
|
||||||
public static final byte STATE_ING = 1; //退款中
|
public static final byte STATE_ING = 1; //退款中
|
||||||
public static final byte STATE_SUCCESS = 2; //退款成功
|
public static final byte STATE_SUCCESS = 2; //退款成功
|
||||||
public static final byte STATE_FAIL = 3; //退款失败
|
public static final byte STATE_FAIL = 3; //退款失败
|
||||||
|
public static final byte STATE_CLOSED = 4; //退款任务关闭
|
||||||
|
|
||||||
public static final LambdaQueryWrapper<RefundOrder> gw(){
|
public static final LambdaQueryWrapper<RefundOrder> gw(){
|
||||||
return new LambdaQueryWrapper<>();
|
return new LambdaQueryWrapper<>();
|
||||||
|
|
@ -122,7 +123,7 @@ public class RefundOrder extends BaseModel {
|
||||||
private String currency;
|
private String currency;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败
|
* 退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败,4-退款任务关闭
|
||||||
*/
|
*/
|
||||||
private Byte state;
|
private Byte state;
|
||||||
|
|
||||||
|
|
@ -171,6 +172,11 @@ public class RefundOrder extends BaseModel {
|
||||||
*/
|
*/
|
||||||
private Date successTime;
|
private Date successTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款失效时间(失效后系统更改为退款任务关闭状态)
|
||||||
|
*/
|
||||||
|
private Date expiredTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -39,4 +39,7 @@ public interface IRefundService {
|
||||||
/** 调起退款接口,并响应数据; 内部处理普通商户和服务商模式 **/
|
/** 调起退款接口,并响应数据; 内部处理普通商户和服务商模式 **/
|
||||||
ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception;
|
ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception;
|
||||||
|
|
||||||
|
/** 退款查单接口 **/
|
||||||
|
ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ public class AlipayKit {
|
||||||
else if(req instanceof AlipayTradeWapPayRequest) ((AlipayTradeWapPayRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken());
|
else if(req instanceof AlipayTradeWapPayRequest) ((AlipayTradeWapPayRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken());
|
||||||
else if(req instanceof AlipayTradeQueryRequest) ((AlipayTradeQueryRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken());
|
else if(req instanceof AlipayTradeQueryRequest) ((AlipayTradeQueryRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken());
|
||||||
else if(req instanceof AlipayTradeRefundRequest) ((AlipayTradeRefundRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken());
|
else if(req instanceof AlipayTradeRefundRequest) ((AlipayTradeRefundRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken());
|
||||||
|
else if(req instanceof AlipayTradeFastpayRefundQueryRequest) ((AlipayTradeFastpayRefundQueryRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken());
|
||||||
|
|
||||||
// 服务商信息
|
// 服务商信息
|
||||||
ExtendParams extendParams = new ExtendParams();
|
ExtendParams extendParams = new ExtendParams();
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package com.jeequan.jeepay.pay.channel.alipay;
|
package com.jeequan.jeepay.pay.channel.alipay;
|
||||||
|
|
||||||
|
import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel;
|
||||||
import com.alipay.api.domain.AlipayTradeRefundModel;
|
import com.alipay.api.domain.AlipayTradeRefundModel;
|
||||||
|
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
|
||||||
import com.alipay.api.request.AlipayTradeRefundRequest;
|
import com.alipay.api.request.AlipayTradeRefundRequest;
|
||||||
|
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
|
||||||
import com.alipay.api.response.AlipayTradeRefundResponse;
|
import com.alipay.api.response.AlipayTradeRefundResponse;
|
||||||
import com.jeequan.jeepay.core.constants.CS;
|
import com.jeequan.jeepay.core.constants.CS;
|
||||||
import com.jeequan.jeepay.core.entity.PayOrder;
|
import com.jeequan.jeepay.core.entity.PayOrder;
|
||||||
|
|
@ -82,5 +85,37 @@ public class AlipayRefundService extends AbstractRefundService {
|
||||||
return channelRetMsg;
|
return channelRetMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception {
|
||||||
|
|
||||||
|
AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
|
||||||
|
AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel();
|
||||||
|
model.setTradeNo(refundOrder.getChannelPayOrderNo());
|
||||||
|
model.setOutTradeNo(refundOrder.getPayOrderId());
|
||||||
|
model.setOutRequestNo(refundOrder.getRefundOrderId());
|
||||||
|
request.setBizModel(model);
|
||||||
|
|
||||||
|
//统一放置 isv接口必传信息
|
||||||
|
AlipayKit.putApiIsvInfo(mchAppConfigContext, request, model);
|
||||||
|
|
||||||
|
AlipayTradeFastpayRefundQueryResponse response = mchAppConfigContext.getAlipayClientWrapper().execute(request);
|
||||||
|
|
||||||
|
ChannelRetMsg channelRetMsg = new ChannelRetMsg();
|
||||||
|
channelRetMsg.setChannelAttach(response.getBody());
|
||||||
|
channelRetMsg.setChannelOrderId(response.getTradeNo());
|
||||||
|
|
||||||
|
// 调用成功 & 金额相等 (传入不存在的outRequestNo支付宝仍然返回响应成功只是数据不存在, 调用isSuccess() 仍是成功, 此处需判断金额是否相等)
|
||||||
|
Long channelRefundAmount = response.getRefundAmount() == null ? null : Long.parseLong(AmountUtil.convertDollar2Cent(response.getRefundAmount()));
|
||||||
|
if(response.isSuccess() && refundOrder.getRefundAmount().equals(channelRefundAmount)){
|
||||||
|
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
|
||||||
|
}else{
|
||||||
|
|
||||||
|
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); //认为是处理中
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return channelRetMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ import com.jeequan.jeepay.core.entity.PayOrder;
|
||||||
import com.jeequan.jeepay.core.exception.BizException;
|
import com.jeequan.jeepay.core.exception.BizException;
|
||||||
import com.jeequan.jeepay.core.model.ApiRes;
|
import com.jeequan.jeepay.core.model.ApiRes;
|
||||||
import com.jeequan.jeepay.pay.ctrl.ApiController;
|
import com.jeequan.jeepay.pay.ctrl.ApiController;
|
||||||
import com.jeequan.jeepay.pay.rqrs.QueryPayOrderRQ;
|
import com.jeequan.jeepay.pay.rqrs.payorder.QueryPayOrderRQ;
|
||||||
import com.jeequan.jeepay.pay.rqrs.QueryPayOrderRS;
|
import com.jeequan.jeepay.pay.rqrs.payorder.QueryPayOrderRS;
|
||||||
import com.jeequan.jeepay.pay.service.ConfigContextService;
|
import com.jeequan.jeepay.pay.service.ConfigContextService;
|
||||||
import com.jeequan.jeepay.service.impl.PayOrderService;
|
import com.jeequan.jeepay.service.impl.PayOrderService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* 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.entity.RefundOrder;
|
||||||
|
import com.jeequan.jeepay.core.exception.BizException;
|
||||||
|
import com.jeequan.jeepay.core.model.ApiRes;
|
||||||
|
import com.jeequan.jeepay.pay.ctrl.ApiController;
|
||||||
|
import com.jeequan.jeepay.pay.rqrs.refund.QueryRefundOrderRQ;
|
||||||
|
import com.jeequan.jeepay.pay.rqrs.refund.QueryRefundOrderRS;
|
||||||
|
import com.jeequan.jeepay.pay.service.ConfigContextService;
|
||||||
|
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.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商户退款单查询controller
|
||||||
|
*
|
||||||
|
* @author terrfly
|
||||||
|
* @site https://www.jeepay.vip
|
||||||
|
* @date 2021/6/17 15:20
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
public class QueryRefundOrderController extends ApiController {
|
||||||
|
|
||||||
|
@Autowired private RefundOrderService refundOrderService;
|
||||||
|
@Autowired private ConfigContextService configContextService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查单接口
|
||||||
|
* **/
|
||||||
|
@RequestMapping("/api/refund/query")
|
||||||
|
public ApiRes queryRefundOrder(){
|
||||||
|
|
||||||
|
//获取参数 & 验签
|
||||||
|
QueryRefundOrderRQ rq = getRQByWithMchSign(QueryRefundOrderRQ.class);
|
||||||
|
|
||||||
|
if(StringUtils.isAllEmpty(rq.getMchRefundNo(), rq.getRefundOrderId())){
|
||||||
|
throw new BizException("mchRefundNo 和 refundOrderId不能同时为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
RefundOrder refundOrder = refundOrderService.queryMchOrder(rq.getMchNo(), rq.getMchRefundNo(), rq.getRefundOrderId());
|
||||||
|
if(refundOrder == null){
|
||||||
|
throw new BizException("订单不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryRefundOrderRS bizRes = QueryRefundOrderRS.buildByRefundOrder(refundOrder);
|
||||||
|
return ApiRes.okWithSign(bizRes, configContextService.getMchAppConfigContext(rq.getMchNo(), rq.getAppId()).getMchApp().getAppSecret());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.jeequan.jeepay.pay.ctrl.refund;
|
package com.jeequan.jeepay.pay.ctrl.refund;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
import com.jeequan.jeepay.core.entity.MchApp;
|
import com.jeequan.jeepay.core.entity.MchApp;
|
||||||
import com.jeequan.jeepay.core.entity.MchInfo;
|
import com.jeequan.jeepay.core.entity.MchInfo;
|
||||||
import com.jeequan.jeepay.core.entity.PayOrder;
|
import com.jeequan.jeepay.core.entity.PayOrder;
|
||||||
|
|
@ -32,6 +33,7 @@ import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
|
||||||
import com.jeequan.jeepay.pay.rqrs.refund.RefundOrderRQ;
|
import com.jeequan.jeepay.pay.rqrs.refund.RefundOrderRQ;
|
||||||
import com.jeequan.jeepay.pay.rqrs.refund.RefundOrderRS;
|
import com.jeequan.jeepay.pay.rqrs.refund.RefundOrderRS;
|
||||||
import com.jeequan.jeepay.pay.service.ConfigContextService;
|
import com.jeequan.jeepay.pay.service.ConfigContextService;
|
||||||
|
import com.jeequan.jeepay.pay.service.PayMchNotifyService;
|
||||||
import com.jeequan.jeepay.service.impl.PayOrderService;
|
import com.jeequan.jeepay.service.impl.PayOrderService;
|
||||||
import com.jeequan.jeepay.service.impl.RefundOrderService;
|
import com.jeequan.jeepay.service.impl.RefundOrderService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
@ -56,6 +58,7 @@ public class RefundOrderController extends ApiController {
|
||||||
@Autowired private PayOrderService payOrderService;
|
@Autowired private PayOrderService payOrderService;
|
||||||
@Autowired private RefundOrderService refundOrderService;
|
@Autowired private RefundOrderService refundOrderService;
|
||||||
@Autowired private ConfigContextService configContextService;
|
@Autowired private ConfigContextService configContextService;
|
||||||
|
@Autowired private PayMchNotifyService payMchNotifyService;
|
||||||
|
|
||||||
/** 申请退款 **/
|
/** 申请退款 **/
|
||||||
@PostMapping("/api/refund/refundOrder")
|
@PostMapping("/api/refund/refundOrder")
|
||||||
|
|
@ -69,7 +72,6 @@ public class RefundOrderController extends ApiController {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
||||||
if(StringUtils.isAllEmpty(rq.getMchOrderNo(), rq.getPayOrderId())){
|
if(StringUtils.isAllEmpty(rq.getMchOrderNo(), rq.getPayOrderId())){
|
||||||
throw new BizException("mchOrderNo 和 payOrderId不能同时为空");
|
throw new BizException("mchOrderNo 和 payOrderId不能同时为空");
|
||||||
}
|
}
|
||||||
|
|
@ -174,6 +176,7 @@ public class RefundOrderController extends ApiController {
|
||||||
|
|
||||||
private RefundOrder genRefundOrder(RefundOrderRQ rq, PayOrder payOrder, MchInfo mchInfo, MchApp mchApp){
|
private RefundOrder genRefundOrder(RefundOrderRQ rq, PayOrder payOrder, MchInfo mchInfo, MchApp mchApp){
|
||||||
|
|
||||||
|
Date nowTime = new Date();
|
||||||
RefundOrder refundOrder = new RefundOrder();
|
RefundOrder refundOrder = new RefundOrder();
|
||||||
refundOrder.setRefundOrderId(SeqKit.genPayOrderId()); //退款订单号
|
refundOrder.setRefundOrderId(SeqKit.genPayOrderId()); //退款订单号
|
||||||
refundOrder.setPayOrderId(payOrder.getPayOrderId()); //支付订单号
|
refundOrder.setPayOrderId(payOrder.getPayOrderId()); //支付订单号
|
||||||
|
|
@ -198,8 +201,9 @@ public class RefundOrderController extends ApiController {
|
||||||
refundOrder.setChannelExtra(rq.getChannelExtra()); //特定渠道发起时额外参数
|
refundOrder.setChannelExtra(rq.getChannelExtra()); //特定渠道发起时额外参数
|
||||||
refundOrder.setNotifyUrl(rq.getNotifyUrl()); //通知地址
|
refundOrder.setNotifyUrl(rq.getNotifyUrl()); //通知地址
|
||||||
refundOrder.setExtParam(rq.getExtParam()); //扩展参数
|
refundOrder.setExtParam(rq.getExtParam()); //扩展参数
|
||||||
|
refundOrder.setExpiredTime(DateUtil.offsetHour(nowTime, 2)); //订单超时关闭时间 默认两个小时
|
||||||
refundOrder.setSuccessTime(null); //订单退款成功时间
|
refundOrder.setSuccessTime(null); //订单退款成功时间
|
||||||
refundOrder.setCreatedAt(new Date()); //创建时间
|
refundOrder.setCreatedAt(nowTime); //创建时间
|
||||||
|
|
||||||
return refundOrder;
|
return refundOrder;
|
||||||
}
|
}
|
||||||
|
|
@ -219,7 +223,7 @@ public class RefundOrderController extends ApiController {
|
||||||
if(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == channelRetMsg.getChannelState()) {
|
if(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == channelRetMsg.getChannelState()) {
|
||||||
|
|
||||||
this.updateInitOrderStateThrowException(RefundOrder.STATE_SUCCESS, refundOrder, channelRetMsg);
|
this.updateInitOrderStateThrowException(RefundOrder.STATE_SUCCESS, refundOrder, channelRetMsg);
|
||||||
// payMchNotifyService.payOrderNotify(payOrder);
|
payMchNotifyService.refundOrderNotify(refundOrder);
|
||||||
|
|
||||||
//明确失败
|
//明确失败
|
||||||
}else if(ChannelRetMsg.ChannelState.CONFIRM_FAIL == channelRetMsg.getChannelState()) {
|
}else if(ChannelRetMsg.ChannelState.CONFIRM_FAIL == channelRetMsg.getChannelState()) {
|
||||||
|
|
@ -235,7 +239,7 @@ public class RefundOrderController extends ApiController {
|
||||||
this.updateInitOrderStateThrowException(RefundOrder.STATE_ING, refundOrder, channelRetMsg);
|
this.updateInitOrderStateThrowException(RefundOrder.STATE_ING, refundOrder, channelRetMsg);
|
||||||
|
|
||||||
// 系统异常: 退款单不再处理。 为: 生成状态
|
// 系统异常: 退款单不再处理。 为: 生成状态
|
||||||
}else if( ChannelRetMsg.ChannelState.SYS_ERROR == channelRetMsg.getChannelState()){
|
}else if( ChannelRetMsg.ChannelState.SYS_ERROR == channelRetMsg.getChannelState() ){
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,9 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.jeequan.jeepay.pay.rqrs;
|
package com.jeequan.jeepay.pay.rqrs.payorder;
|
||||||
|
|
||||||
|
import com.jeequan.jeepay.pay.rqrs.AbstractMchAppRQ;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
@ -27,7 +28,7 @@ import javax.validation.constraints.NotBlank;
|
||||||
* @date 2021/6/8 17:40
|
* @date 2021/6/8 17:40
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class QueryPayOrderRQ extends AbstractMchAppRQ{
|
public class QueryPayOrderRQ extends AbstractMchAppRQ {
|
||||||
|
|
||||||
/** 商户订单号 **/
|
/** 商户订单号 **/
|
||||||
private String mchOrderNo;
|
private String mchOrderNo;
|
||||||
|
|
@ -13,9 +13,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.jeequan.jeepay.pay.rqrs;
|
package com.jeequan.jeepay.pay.rqrs.payorder;
|
||||||
|
|
||||||
import com.jeequan.jeepay.core.entity.PayOrder;
|
import com.jeequan.jeepay.core.entity.PayOrder;
|
||||||
|
import com.jeequan.jeepay.pay.rqrs.AbstractRS;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
|
|
||||||
|
|
@ -27,7 +28,7 @@ import org.springframework.beans.BeanUtils;
|
||||||
* @date 2021/6/8 17:40
|
* @date 2021/6/8 17:40
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class QueryPayOrderRS extends AbstractRS{
|
public class QueryPayOrderRS extends AbstractRS {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付订单号
|
* 支付订单号
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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.refund;
|
||||||
|
|
||||||
|
import com.jeequan.jeepay.pay.rqrs.AbstractMchAppRQ;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 查询退款单请求参数对象
|
||||||
|
*
|
||||||
|
* @author terrfly
|
||||||
|
* @site https://www.jeepay.vip
|
||||||
|
* @date 2021/6/17 14:07
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class QueryRefundOrderRQ extends AbstractMchAppRQ {
|
||||||
|
|
||||||
|
/** 商户退款单号 **/
|
||||||
|
private String mchRefundNo;
|
||||||
|
|
||||||
|
/** 支付系统退款订单号 **/
|
||||||
|
private String refundOrderId;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* 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.refund;
|
||||||
|
|
||||||
|
import com.jeequan.jeepay.core.entity.RefundOrder;
|
||||||
|
import com.jeequan.jeepay.pay.rqrs.AbstractRS;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 查询退款单 响应参数
|
||||||
|
*
|
||||||
|
* @author terrfly
|
||||||
|
* @site https://www.jeepay.vip
|
||||||
|
* @date 2021/6/17 14:08
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class QueryRefundOrderRS extends AbstractRS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款订单号(支付系统生成订单号)
|
||||||
|
*/
|
||||||
|
private String refundOrderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付订单号(与t_pay_order对应)
|
||||||
|
*/
|
||||||
|
private String payOrderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商户号
|
||||||
|
*/
|
||||||
|
private String mchNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用ID
|
||||||
|
*/
|
||||||
|
private String appId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商户退款单号(商户系统的订单号)
|
||||||
|
*/
|
||||||
|
private String mchRefundNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付金额,单位分
|
||||||
|
*/
|
||||||
|
private Long payAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款金额,单位分
|
||||||
|
*/
|
||||||
|
private Long refundAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 三位货币代码,人民币:cny
|
||||||
|
*/
|
||||||
|
private String currency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败
|
||||||
|
*/
|
||||||
|
private Byte state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渠道订单号
|
||||||
|
*/
|
||||||
|
private String channelOrderNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渠道错误码
|
||||||
|
*/
|
||||||
|
private String channelErrCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渠道错误描述
|
||||||
|
*/
|
||||||
|
private String channelErrMsg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 特定渠道发起时额外参数
|
||||||
|
*/
|
||||||
|
private String channelExtra;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扩展参数
|
||||||
|
*/
|
||||||
|
private String extParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单退款成功时间
|
||||||
|
*/
|
||||||
|
private Long successTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Long createdAt;
|
||||||
|
|
||||||
|
|
||||||
|
public static QueryRefundOrderRS buildByRefundOrder(RefundOrder refundOrder){
|
||||||
|
|
||||||
|
if(refundOrder == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryRefundOrderRS result = new QueryRefundOrderRS();
|
||||||
|
BeanUtils.copyProperties(refundOrder, result);
|
||||||
|
result.setSuccessTime(refundOrder.getSuccessTime() == null ? null : refundOrder.getSuccessTime().getTime());
|
||||||
|
result.setCreatedAt(refundOrder.getCreatedAt() == null ? null : refundOrder.getCreatedAt().getTime());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -15,10 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package com.jeequan.jeepay.pay.rqrs.refund;
|
package com.jeequan.jeepay.pay.rqrs.refund;
|
||||||
|
|
||||||
import com.jeequan.jeepay.core.entity.PayOrder;
|
|
||||||
import com.jeequan.jeepay.core.entity.RefundOrder;
|
import com.jeequan.jeepay.core.entity.RefundOrder;
|
||||||
import com.jeequan.jeepay.pay.rqrs.AbstractRS;
|
import com.jeequan.jeepay.pay.rqrs.AbstractRS;
|
||||||
import com.jeequan.jeepay.pay.rqrs.QueryPayOrderRS;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,14 @@
|
||||||
package com.jeequan.jeepay.pay.service;
|
package com.jeequan.jeepay.pay.service;
|
||||||
|
|
||||||
import com.jeequan.jeepay.core.entity.PayOrder;
|
import com.jeequan.jeepay.core.entity.PayOrder;
|
||||||
|
import com.jeequan.jeepay.core.entity.RefundOrder;
|
||||||
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
|
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
|
||||||
import com.jeequan.jeepay.pay.channel.IPayOrderQueryService;
|
import com.jeequan.jeepay.pay.channel.IPayOrderQueryService;
|
||||||
|
import com.jeequan.jeepay.pay.channel.IRefundService;
|
||||||
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
|
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
|
||||||
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
|
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
|
||||||
import com.jeequan.jeepay.service.impl.PayOrderService;
|
import com.jeequan.jeepay.service.impl.PayOrderService;
|
||||||
|
import com.jeequan.jeepay.service.impl.RefundOrderService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
@ -33,12 +36,14 @@ import org.springframework.stereotype.Service;
|
||||||
* @site https://www.jeepay.vip
|
* @site https://www.jeepay.vip
|
||||||
* @date 2021/6/8 17:40
|
* @date 2021/6/8 17:40
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ChannelOrderReissueService {
|
public class ChannelOrderReissueService {
|
||||||
|
|
||||||
@Autowired private ConfigContextService configContextService;
|
@Autowired private ConfigContextService configContextService;
|
||||||
@Autowired private PayOrderService payOrderService;
|
@Autowired private PayOrderService payOrderService;
|
||||||
|
@Autowired private RefundOrderService refundOrderService;
|
||||||
@Autowired private PayMchNotifyService payMchNotifyService;
|
@Autowired private PayMchNotifyService payMchNotifyService;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -95,5 +100,58 @@ public class ChannelOrderReissueService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 处理退款订单 **/
|
||||||
|
public ChannelRetMsg processRefundOrder(RefundOrder refundOrder){
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
String refundOrderId = refundOrder.getRefundOrderId();
|
||||||
|
|
||||||
|
//查询支付接口是否存在
|
||||||
|
IRefundService queryService = SpringBeansUtil.getBean(refundOrder.getIfCode() + "RefundService", IRefundService.class);
|
||||||
|
|
||||||
|
// 支付通道接口实现不存在
|
||||||
|
if(queryService == null){
|
||||||
|
log.error("退款补单:{} interface not exists!", refundOrder.getIfCode());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//查询出商户应用的配置信息
|
||||||
|
MchAppConfigContext mchAppConfigContext = configContextService.getMchAppConfigContext(refundOrder.getMchNo(), refundOrder.getAppId());
|
||||||
|
|
||||||
|
ChannelRetMsg channelRetMsg = queryService.query(refundOrder, mchAppConfigContext);
|
||||||
|
if(channelRetMsg == null){
|
||||||
|
log.error("退款补单:channelRetMsg is null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return channelRetMsg;
|
||||||
|
|
||||||
|
} catch (Exception e) { //继续下一次迭代查询
|
||||||
|
log.error("退款补单:error refundOrderId = {}", refundOrder.getRefundOrderId(), e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,14 @@
|
||||||
package com.jeequan.jeepay.pay.service;
|
package com.jeequan.jeepay.pay.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.jeequan.jeepay.core.entity.MchInfo;
|
|
||||||
import com.jeequan.jeepay.core.entity.MchNotifyRecord;
|
import com.jeequan.jeepay.core.entity.MchNotifyRecord;
|
||||||
import com.jeequan.jeepay.core.entity.PayOrder;
|
import com.jeequan.jeepay.core.entity.PayOrder;
|
||||||
|
import com.jeequan.jeepay.core.entity.RefundOrder;
|
||||||
import com.jeequan.jeepay.core.utils.JeepayKit;
|
import com.jeequan.jeepay.core.utils.JeepayKit;
|
||||||
import com.jeequan.jeepay.core.utils.StringKit;
|
import com.jeequan.jeepay.core.utils.StringKit;
|
||||||
import com.jeequan.jeepay.pay.mq.queue.MqQueue4PayOrderMchNotify;
|
import com.jeequan.jeepay.pay.mq.queue.MqQueue4PayOrderMchNotify;
|
||||||
import com.jeequan.jeepay.pay.rqrs.QueryPayOrderRS;
|
import com.jeequan.jeepay.pay.rqrs.payorder.QueryPayOrderRS;
|
||||||
import com.jeequan.jeepay.service.impl.MchInfoService;
|
import com.jeequan.jeepay.pay.rqrs.refund.QueryRefundOrderRS;
|
||||||
import com.jeequan.jeepay.service.impl.MchNotifyRecordService;
|
import com.jeequan.jeepay.service.impl.MchNotifyRecordService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
@ -91,6 +91,51 @@ public class PayMchNotifyService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 商户通知信息,退款成功的发送通知 **/
|
||||||
|
public void refundOrderNotify(RefundOrder dbRefundOrder){
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 通知地址为空
|
||||||
|
if(StringUtils.isEmpty(dbRefundOrder.getNotifyUrl())){
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取到通知对象
|
||||||
|
MchNotifyRecord mchNotifyRecord = mchNotifyRecordService.findByRefundOrder(dbRefundOrder.getRefundOrderId());
|
||||||
|
|
||||||
|
if(mchNotifyRecord != null){
|
||||||
|
|
||||||
|
log.info("当前已存在通知消息, 不再发送。");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//商户app私钥
|
||||||
|
String appSecret = configContextService.getMchAppConfigContext(dbRefundOrder.getMchNo(), dbRefundOrder.getAppId()).getMchApp().getAppSecret();
|
||||||
|
|
||||||
|
// 封装通知url
|
||||||
|
String notifyUrl = createNotifyUrl(dbRefundOrder, appSecret);
|
||||||
|
mchNotifyRecord = new MchNotifyRecord();
|
||||||
|
mchNotifyRecord.setOrderId(dbRefundOrder.getRefundOrderId());
|
||||||
|
mchNotifyRecord.setOrderType(MchNotifyRecord.TYPE_REFUND_ORDER);
|
||||||
|
mchNotifyRecord.setMchNo(dbRefundOrder.getMchNo());
|
||||||
|
mchNotifyRecord.setMchOrderNo(dbRefundOrder.getMchRefundNo()); //商户订单号
|
||||||
|
mchNotifyRecord.setIsvNo(dbRefundOrder.getIsvNo());
|
||||||
|
mchNotifyRecord.setAppId(dbRefundOrder.getAppId());
|
||||||
|
mchNotifyRecord.setNotifyUrl(notifyUrl);
|
||||||
|
mchNotifyRecord.setResResult("");
|
||||||
|
mchNotifyRecord.setNotifyCount(0);
|
||||||
|
mchNotifyRecord.setState(MchNotifyRecord.STATE_ING); // 通知中
|
||||||
|
mchNotifyRecordService.save(mchNotifyRecord);
|
||||||
|
|
||||||
|
//推送到MQ
|
||||||
|
Long notifyId = mchNotifyRecord.getNotifyId();
|
||||||
|
mqPayOrderMchNotifyQueue.send(notifyId + "");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("推送失败!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建响应URL
|
* 创建响应URL
|
||||||
|
|
@ -109,6 +154,23 @@ public class PayMchNotifyService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建响应URL
|
||||||
|
*/
|
||||||
|
public String createNotifyUrl(RefundOrder refundOrder, String appSecret) {
|
||||||
|
|
||||||
|
QueryRefundOrderRS queryPayOrderRS = QueryRefundOrderRS.buildByRefundOrder(refundOrder);
|
||||||
|
JSONObject jsonObject = (JSONObject)JSONObject.toJSON(queryPayOrderRS);
|
||||||
|
jsonObject.put("reqTime", System.currentTimeMillis()); //添加请求时间
|
||||||
|
|
||||||
|
// 报文签名
|
||||||
|
jsonObject.put("sign", JeepayKit.getSign(jsonObject, appSecret));
|
||||||
|
|
||||||
|
// 生成通知
|
||||||
|
return StringKit.appendUrlQuery(refundOrder.getNotifyUrl(), jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建响应URL
|
* 创建响应URL
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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.task;
|
||||||
|
|
||||||
|
import com.jeequan.jeepay.service.impl.PayOrderService;
|
||||||
|
import com.jeequan.jeepay.service.impl.RefundOrderService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 退款订单过期定时任务
|
||||||
|
*
|
||||||
|
* @author terrfly
|
||||||
|
* @site https://www.jeepay.vip
|
||||||
|
* @date 2021/6/17 14:36
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class RefundOrderExpiredTask {
|
||||||
|
|
||||||
|
@Autowired private RefundOrderService refundOrderService;
|
||||||
|
|
||||||
|
@Scheduled(cron="0 0/1 * * * ?") // 每分钟执行一次
|
||||||
|
public void start() {
|
||||||
|
|
||||||
|
int updateCount = refundOrderService.updateOrderExpired();
|
||||||
|
log.info("处理退款订单超时{}条.", updateCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* 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.task;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.jeequan.jeepay.core.entity.RefundOrder;
|
||||||
|
import com.jeequan.jeepay.pay.service.ChannelOrderReissueService;
|
||||||
|
import com.jeequan.jeepay.service.impl.RefundOrderService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 补单定时任务(退款单)
|
||||||
|
*
|
||||||
|
* @author terrfly
|
||||||
|
* @site https://www.jeepay.vip
|
||||||
|
* @date 2021/6/17 14:22
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class RefundOrderReissueTask {
|
||||||
|
|
||||||
|
private static final int QUERY_PAGE_SIZE = 100; //每次查询数量
|
||||||
|
|
||||||
|
@Autowired private RefundOrderService refundOrderService;
|
||||||
|
@Autowired private ChannelOrderReissueService channelOrderReissueService;
|
||||||
|
|
||||||
|
@Scheduled(cron="0 0/1 * * * ?") // 每分钟执行一次
|
||||||
|
public void start() {
|
||||||
|
|
||||||
|
//当前时间 减去10分钟。
|
||||||
|
Date offsetDate = DateUtil.offsetMinute(new Date(), -10);
|
||||||
|
|
||||||
|
//查询条件: 支付中的订单 & ( 订单创建时间 + 10分钟 >= 当前时间 )
|
||||||
|
LambdaQueryWrapper<RefundOrder> lambdaQueryWrapper = RefundOrder.gw().eq(RefundOrder::getState, RefundOrder.STATE_ING).le(RefundOrder::getCreatedAt, offsetDate);
|
||||||
|
|
||||||
|
int currentPageIndex = 1; //当前页码
|
||||||
|
while(true){
|
||||||
|
|
||||||
|
try {
|
||||||
|
IPage<RefundOrder> refundOrderIPage = refundOrderService.page(new Page(currentPageIndex, QUERY_PAGE_SIZE), lambdaQueryWrapper);
|
||||||
|
|
||||||
|
if(refundOrderIPage == null || refundOrderIPage.getRecords().isEmpty()){ //本次查询无结果, 不再继续查询;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(RefundOrder refundOrder: refundOrderIPage.getRecords()){
|
||||||
|
channelOrderReissueService.processRefundOrder(refundOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
//已经到达页码最大量,无需再次查询
|
||||||
|
if(refundOrderIPage.getPages() <= currentPageIndex){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
currentPageIndex++;
|
||||||
|
|
||||||
|
|
||||||
|
} catch (Exception e) { //出现异常,直接退出,避免死循环。
|
||||||
|
log.error("error", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -21,10 +21,12 @@ import com.jeequan.jeepay.core.entity.RefundOrder;
|
||||||
import com.jeequan.jeepay.core.exception.BizException;
|
import com.jeequan.jeepay.core.exception.BizException;
|
||||||
import com.jeequan.jeepay.service.mapper.PayOrderMapper;
|
import com.jeequan.jeepay.service.mapper.PayOrderMapper;
|
||||||
import com.jeequan.jeepay.service.mapper.RefundOrderMapper;
|
import com.jeequan.jeepay.service.mapper.RefundOrderMapper;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -40,6 +42,18 @@ public class RefundOrderService extends ServiceImpl<RefundOrderMapper, RefundOrd
|
||||||
|
|
||||||
@Autowired private PayOrderMapper payOrderMapper;
|
@Autowired private PayOrderMapper payOrderMapper;
|
||||||
|
|
||||||
|
/** 查询商户订单 **/
|
||||||
|
public RefundOrder queryMchOrder(String mchNo, String mchRefundNo, String refundOrderId){
|
||||||
|
|
||||||
|
if(StringUtils.isNotEmpty(refundOrderId)){
|
||||||
|
return getOne(RefundOrder.gw().eq(RefundOrder::getMchNo, mchNo).eq(RefundOrder::getRefundOrderId, refundOrderId));
|
||||||
|
}else if(StringUtils.isNotEmpty(mchRefundNo)){
|
||||||
|
return getOne(RefundOrder.gw().eq(RefundOrder::getMchNo, mchNo).eq(RefundOrder::getMchRefundNo, mchRefundNo));
|
||||||
|
}else{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** 更新退款单状态 【退款单生成】 --》 【退款中】 **/
|
/** 更新退款单状态 【退款单生成】 --》 【退款中】 **/
|
||||||
public boolean updateInit2Ing(String refundOrderId){
|
public boolean updateInit2Ing(String refundOrderId){
|
||||||
|
|
@ -108,4 +122,18 @@ public class RefundOrderService extends ServiceImpl<RefundOrderMapper, RefundOrd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 更新退款单为 关闭状态 **/
|
||||||
|
public Integer updateOrderExpired(){
|
||||||
|
|
||||||
|
RefundOrder refundOrder = new RefundOrder();
|
||||||
|
refundOrder.setState(RefundOrder.STATE_CLOSED);
|
||||||
|
|
||||||
|
return baseMapper.update(refundOrder,
|
||||||
|
RefundOrder.gw()
|
||||||
|
.in(RefundOrder::getState, Arrays.asList(RefundOrder.STATE_INIT, RefundOrder.STATE_ING))
|
||||||
|
.le(RefundOrder::getExpiredTime, new Date())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
<result column="notify_url" property="notifyUrl" />
|
<result column="notify_url" property="notifyUrl" />
|
||||||
<result column="ext_param" property="extParam" />
|
<result column="ext_param" property="extParam" />
|
||||||
<result column="success_time" property="successTime" />
|
<result column="success_time" property="successTime" />
|
||||||
|
<result column="expired_time" property="expiredTime" />
|
||||||
<result column="created_at" property="createdAt" />
|
<result column="created_at" property="createdAt" />
|
||||||
<result column="updated_at" property="updatedAt" />
|
<result column="updated_at" property="updatedAt" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue