微信支付
This commit is contained in:
parent
2f68392778
commit
cee381fcef
@ -191,6 +191,29 @@
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-redis</artifactId>
|
||||
<version>5.5.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.12.6</version>
|
||||
</dependency>
|
||||
<!-- Jackson数据绑定库 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.12.6</version>
|
||||
</dependency>
|
||||
<!-- Jackson数据格式化支持库,例如JSON -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>2.12.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
package com.yf.exam.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.integration.redis.util.RedisLockRegistry;
|
||||
|
||||
/**
|
||||
* @Description Redis分布式锁配置
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-26 15:27:41
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Configuration
|
||||
public class RedisDistributedLockUtilsConfig {
|
||||
|
||||
@Bean
|
||||
public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
|
||||
return new RedisLockRegistry(redisConnectionFactory, this.getClass().getName());
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,31 @@ public class Constants {
|
||||
*/
|
||||
public static final String TOKEN = "token";
|
||||
|
||||
/**
|
||||
* 微信小程序支付prepay_id前缀
|
||||
*/
|
||||
public static final String PREPAY_ID_KEY = "PREPAY_ID_KEY:";
|
||||
|
||||
/**
|
||||
* 微信支付回调标识
|
||||
*/
|
||||
public static final String PAY_NOTIFY = "PAY";
|
||||
|
||||
/**
|
||||
* 微信退款回调标识
|
||||
*/
|
||||
public static final String REFUND_NOTIFY = "REFUND";
|
||||
|
||||
/**
|
||||
* 微信支付回调通知订单锁前缀
|
||||
*/
|
||||
public static final String WE_CHAT_NOTIFY_KEY = "WE_CHAT_NOTIFY_KEY:";
|
||||
|
||||
/**
|
||||
* 微信退款回调通知订单锁前缀
|
||||
*/
|
||||
public static final String WE_CHAT_REFUND_KEY = "WE_CHAT_REFUND_KEY:";
|
||||
|
||||
/**
|
||||
* 文件上传路径
|
||||
*/
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package com.yf.exam.core.api.controller;
|
||||
|
||||
|
||||
import com.yf.exam.core.api.ApiError;
|
||||
import com.yf.exam.core.api.ApiRest;
|
||||
import com.yf.exam.core.domain.AjaxResult;
|
||||
import com.yf.exam.core.exception.ServiceException;
|
||||
|
||||
/**
|
||||
@ -151,4 +151,14 @@ public class BaseController {
|
||||
ApiRest<T> apiRest = message(ex.getCode(), ex.getMsg(), null);
|
||||
return apiRest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应返回结果
|
||||
*
|
||||
* @param rows 影响行数
|
||||
* @return 操作结果
|
||||
*/
|
||||
protected AjaxResult toAjax(int rows) {
|
||||
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package com.yf.exam.core.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @Description 确认退款状态枚举
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-26 11:15:21
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Getter
|
||||
public enum ConfirmRefundStatusEnum {
|
||||
|
||||
/**
|
||||
* 未确认
|
||||
*/
|
||||
NOT_CONFIRM("NOT_CONFIRM"),
|
||||
|
||||
/**
|
||||
* 已确认
|
||||
*/
|
||||
CONFIRMED("CONFIRMED"),
|
||||
;
|
||||
final private String info;
|
||||
|
||||
ConfirmRefundStatusEnum(String info) {
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.yf.exam.core.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @Description 商品订单状态枚举
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-19 09:15:38
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Getter
|
||||
public enum GooodsOrderStatusEnum {
|
||||
|
||||
/**
|
||||
* 待付款
|
||||
*/
|
||||
WAIT_PAY("WAIT_PAY"),
|
||||
|
||||
/**
|
||||
* 已付款
|
||||
*/
|
||||
PAY("PAY"),
|
||||
|
||||
/**
|
||||
* 已取消
|
||||
*/
|
||||
CANCEL("CANCEL"),
|
||||
|
||||
/**
|
||||
* 待收货
|
||||
*/
|
||||
WAIT_RECEIVED_GOODS("WAIT_RECEIVED_GOODS"),
|
||||
|
||||
/**
|
||||
* 已收货
|
||||
*/
|
||||
RECEIVED_GOODS("RECEIVED_GOODS"),
|
||||
|
||||
/**
|
||||
* 退款中
|
||||
*/
|
||||
WAIT_REFUND("WAIT_REFUND"),
|
||||
|
||||
/**
|
||||
* 已退款
|
||||
*/
|
||||
REFUNDED("REFUNDED"),
|
||||
|
||||
/**
|
||||
* 待退货
|
||||
*/
|
||||
WAIT_RETURNED_GOODS("WAIT_RETURNED_GOODS"),
|
||||
|
||||
/**
|
||||
* 已退货
|
||||
*/
|
||||
RETURNED_GOODS("RETURNED_GOODS"),
|
||||
|
||||
/**
|
||||
* 已评价
|
||||
*/
|
||||
EVALUATED("EVALUATED"),
|
||||
;
|
||||
final private String info;
|
||||
|
||||
GooodsOrderStatusEnum(String info) {
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.yf.exam.core.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @Description 支付了类型枚举
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-18 15:16:02
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Getter
|
||||
public enum PayTypeEnum {
|
||||
|
||||
/**
|
||||
* 微信
|
||||
*/
|
||||
WECHAT_PAY("WECHAT_PAY"),
|
||||
|
||||
/**
|
||||
* 支付宝
|
||||
*/
|
||||
ALI_PAY("ALI_PAY"),
|
||||
;
|
||||
|
||||
final private String info;
|
||||
|
||||
PayTypeEnum(String info) {
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.yf.exam.core.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @Description 微信退款通知枚举
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-25 13:12:03
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Getter
|
||||
public enum RefundStatusEnum {
|
||||
/**
|
||||
* 退款成功
|
||||
*/
|
||||
SUCCESS("SUCCESS"),
|
||||
|
||||
/**
|
||||
* 退款关闭
|
||||
*/
|
||||
CLOSED("CLOSED"),
|
||||
|
||||
/**
|
||||
* 退款处理中
|
||||
*/
|
||||
PROCESSING("PROCESSING"),
|
||||
|
||||
/**
|
||||
* 退款异常,退款到银行发现用户的卡作废或者冻结了,
|
||||
* 导致原路退款银行卡失败,可前往【商户平台—>交易中心】,手动处理此笔退款
|
||||
*/
|
||||
ABNORMAL("ABNORMAL"),
|
||||
|
||||
;
|
||||
|
||||
final private String info;
|
||||
|
||||
RefundStatusEnum(String info) {
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package com.yf.exam.core.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 微信支付回调通知状态
|
||||
*/
|
||||
@Getter
|
||||
public enum WeChatTradeStateEnum {
|
||||
|
||||
/**
|
||||
* 支付成功
|
||||
*/
|
||||
SUCCESS("SUCCESS"),
|
||||
|
||||
/**
|
||||
* 未支付
|
||||
*/
|
||||
NOTPAY("NOTPAY"),
|
||||
|
||||
/**
|
||||
* 已关闭
|
||||
*/
|
||||
CLOSED("CLOSED"),
|
||||
|
||||
/**
|
||||
* 转入退款
|
||||
*/
|
||||
REFUND("REFUND"),
|
||||
|
||||
/**
|
||||
* 已撤销(付款码支付)
|
||||
*/
|
||||
REVOKED("REVOKED"),
|
||||
|
||||
/**
|
||||
* 用户支付中(付款码支付)
|
||||
*/
|
||||
USERPAYING("USERPAYING"),
|
||||
|
||||
/**
|
||||
* 支付失败(其他原因,如银行返回失败)
|
||||
*/
|
||||
PAYERROR("PAYERROR")
|
||||
;
|
||||
|
||||
final private String info;
|
||||
|
||||
WeChatTradeStateEnum(String info) {
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.yf.exam.core.utils;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import javax.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.integration.redis.util.RedisLockRegistry;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @Description Redis锁工具类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-24 10:00:00
|
||||
* @Version 1.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RedisDistributedLockUtils {
|
||||
|
||||
/**
|
||||
* 默认的有效时长
|
||||
*/
|
||||
private static final long DEFAULT_EXPIRE_UNUSED = 30000L;
|
||||
|
||||
@Resource
|
||||
private RedisLockRegistry redisLockRegistry;
|
||||
|
||||
/**
|
||||
* 加锁
|
||||
*
|
||||
* @param lockKey 键
|
||||
*/
|
||||
@SuppressWarnings("AlibabaLockShouldWithTryFinally")
|
||||
public void lock(String lockKey) {
|
||||
Lock lock = obtainLock(lockKey);
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取锁
|
||||
*
|
||||
* @param lockKey 键
|
||||
* @return 结果
|
||||
*/
|
||||
public boolean tryLock(String lockKey) {
|
||||
Lock lock = obtainLock(lockKey);
|
||||
return lock.tryLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取锁,带有时间单位
|
||||
*
|
||||
* @param lockKey 键
|
||||
* @param seconds 时间,单位秒
|
||||
* @return 结果
|
||||
*/
|
||||
public boolean tryLock(String lockKey, long seconds) {
|
||||
Lock lock = obtainLock(lockKey);
|
||||
try {
|
||||
return lock.tryLock(seconds, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放锁
|
||||
*
|
||||
* @param lockKey 键
|
||||
*/
|
||||
public void unlock(String lockKey) {
|
||||
try {
|
||||
Lock lock = obtainLock(lockKey);
|
||||
lock.unlock();
|
||||
redisLockRegistry.expireUnusedOlderThan(DEFAULT_EXPIRE_UNUSED);
|
||||
} catch (Exception e) {
|
||||
log.warn("分布式锁 [{}] 释放异常", lockKey, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放锁
|
||||
*
|
||||
* @param lockKey 键
|
||||
* @return 结果
|
||||
*/
|
||||
private Lock obtainLock(String lockKey) {
|
||||
return redisLockRegistry.obtain(lockKey);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.yf.exam.modules.applet.controller;
|
||||
|
||||
import com.yf.exam.core.api.ApiRest;
|
||||
import com.yf.exam.core.api.controller.BaseController;
|
||||
import com.yf.exam.modules.exam.dto.ExamDTO;
|
||||
import com.yf.exam.modules.exam.dto.request.ExamSearchDTO;
|
||||
import com.yf.exam.modules.exam.service.ExamService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: haown
|
||||
* @create: 2025-08-14 14:07
|
||||
**/
|
||||
@Api(tags={"小程序端考试"})
|
||||
@RestController
|
||||
@RequestMapping("/examApplet/api/exam")
|
||||
public class AppletExamController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private ExamService examService;
|
||||
|
||||
/**
|
||||
* 查询可考试列表
|
||||
* @param reqDTO
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "查询可考试列表")
|
||||
@RequestMapping(value = "/getExamList", method = { RequestMethod.GET})
|
||||
public ApiRest getExamList(ExamSearchDTO reqDTO) {
|
||||
List<ExamDTO> list = examService.getExamList(reqDTO);
|
||||
return super.success(list);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.yf.exam.modules.applet.controller;
|
||||
|
||||
import com.yf.exam.core.api.ApiRest;
|
||||
import com.yf.exam.core.api.controller.BaseController;
|
||||
import com.yf.exam.core.enums.GooodsOrderStatusEnum;
|
||||
import com.yf.exam.modules.exam.dto.ExamRegistrationDTO;
|
||||
import com.yf.exam.modules.exam.dto.response.ExamRegistrationVO;
|
||||
import com.yf.exam.modules.exam.service.ExamRegistrationService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @description: 考试报名控制器
|
||||
* @author: haown
|
||||
* @create: 2025-08-14 14:12
|
||||
**/
|
||||
@Api(tags={"小程序考试报名"})
|
||||
@RestController
|
||||
@RequestMapping("/examApplet/api/exam/registration")
|
||||
public class AppletExamRegistrationController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private ExamRegistrationService baseService;
|
||||
|
||||
/**
|
||||
* 添加或修改
|
||||
* @param reqDTO
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "添加或修改")
|
||||
@RequestMapping(value = "/save", method = { RequestMethod.POST})
|
||||
public ApiRest save(@RequestBody ExamRegistrationDTO reqDTO) {
|
||||
//复制参数
|
||||
return super.success(baseService.save(reqDTO));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询已报名的考试列表
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "查询已报名的考试列表")
|
||||
@RequestMapping(value = "/getRegExamList", method = { RequestMethod.GET})
|
||||
public ApiRest getRegExamList(ExamRegistrationDTO examRegistrationDTO) {
|
||||
examRegistrationDTO.setPaymentState(GooodsOrderStatusEnum.PAY.getInfo());
|
||||
List<ExamRegistrationVO> list = baseService.getRegExamList(examRegistrationDTO);
|
||||
return super.success(list);
|
||||
}
|
||||
}
|
||||
@ -55,6 +55,9 @@ public class AppletLoginController extends BaseController {
|
||||
if (BooleanUtils.isFalse(cardNo)) {
|
||||
return AjaxResult.error("您输入的身份证号不正确,请重新输入!");
|
||||
}
|
||||
if (StringUtils.isBlank(reqDTO.getOpenid())) {
|
||||
return AjaxResult.error("登录凭证不能为空!");
|
||||
}
|
||||
return AjaxResult.success(sysUserService.reg(reqDTO));
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,139 @@
|
||||
package com.yf.exam.modules.applet.controller;
|
||||
|
||||
import com.yf.exam.core.api.controller.BaseController;
|
||||
import com.yf.exam.core.domain.AjaxResult;
|
||||
import com.yf.exam.core.exception.ServiceException;
|
||||
import com.yf.exam.modules.applet.dto.PaymentDTO;
|
||||
import com.yf.exam.modules.applet.dto.RefundDTO;
|
||||
import com.yf.exam.modules.applet.service.WeChatPayNotifyService;
|
||||
import com.yf.exam.modules.applet.service.WeChatPaymentService;
|
||||
import com.yf.exam.modules.applet.service.WeChatRefundService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @Description 微信小程序支付控制器
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-18 14:47:11
|
||||
* @Version 1.0`
|
||||
*/
|
||||
@Api(tags={"支付控制器"})
|
||||
@RestController
|
||||
@RequestMapping("/examApplet/weChatPayment")
|
||||
public class WeChatPaymentController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private WeChatPaymentService weChatPaymentService;
|
||||
@Resource
|
||||
private WeChatPayNotifyService weChatPayNotifyService;
|
||||
@Resource
|
||||
private WeChatRefundService weChatRefundService;
|
||||
|
||||
/**
|
||||
* 微信小程序支付接口
|
||||
*
|
||||
* @param paymentDTO 输入参数
|
||||
* @return 支付返回结果
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
@ApiOperation(value = "微信小程序支付接口")
|
||||
@PostMapping("/appletPay")
|
||||
public AjaxResult appletPay(@RequestBody PaymentDTO paymentDTO, BindingResult bindingResult) throws Exception {
|
||||
if (bindingResult.hasErrors()) {
|
||||
throw new ServiceException(bindingResult.getAllErrors().get(0).getDefaultMessage());
|
||||
}
|
||||
if (StringUtils.isBlank(paymentDTO.getOpenid())) {
|
||||
return AjaxResult.error("微信openid不能为空!");
|
||||
}
|
||||
if (Objects.nonNull(paymentDTO.getPaymentPrice()) && paymentDTO.getPaymentPrice().compareTo(BigDecimal.ZERO) < 0) {
|
||||
return AjaxResult.error("订单支付金额不能为负数,无法支付!");
|
||||
}
|
||||
if (Objects.nonNull(paymentDTO.getPaymentPrice()) && paymentDTO.getPaymentPrice().compareTo(BigDecimal.ZERO) == 0) {
|
||||
return AjaxResult.error("订单支付金额不能为零,无法支付!");
|
||||
}
|
||||
return weChatPaymentService.appletPay(paymentDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新医路微信支付回调通知接口
|
||||
*
|
||||
* @param request 请求头信息
|
||||
* @param response 响应信息
|
||||
* @return 应答信息,避免微信平台重复发送回调通知
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
@ApiOperation(value = "微信支付回调通知接口")
|
||||
@PostMapping("/xylWeChatPayNotify")
|
||||
public String xylWeChatPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
return weChatPayNotifyService.xylWeChatPayNotify(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消订单接口(暂时废弃)
|
||||
*
|
||||
* @param orderNo 订单编号
|
||||
* @return 返回结果信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
@PostMapping("/cancelOrderInfo")
|
||||
public AjaxResult cancelOrderInfo(@RequestParam("orderNo") String orderNo) throws Exception {
|
||||
if (StringUtils.isBlank(orderNo)) {
|
||||
return AjaxResult.error("请选择所要取消的订单信息!");
|
||||
}
|
||||
return weChatPaymentService.cancelOrderInfo(orderNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单状态接口(暂时废弃)
|
||||
*
|
||||
* @param orderNo 订单编号
|
||||
* @return 返回结果信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
@PostMapping("/getOrderStatusInfo")
|
||||
public AjaxResult getOrderStatusInfo(@RequestParam("orderNo") String orderNo) throws Exception {
|
||||
if (StringUtils.isBlank(orderNo)) {
|
||||
return AjaxResult.error("请选择所要查询的订单信息!");
|
||||
}
|
||||
return weChatPaymentService.getOrderStatusInfo(orderNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信确认退款接口
|
||||
*
|
||||
* @param refundDTO 退款参数
|
||||
* @return 退款申请结果
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
@ApiOperation(value = "微信确认退款接口")
|
||||
@PostMapping("/weChatRefundOrderApply")
|
||||
public AjaxResult weChatRefundOrderApply(@RequestBody RefundDTO refundDTO) throws Exception {
|
||||
return weChatRefundService.weChatRefundOrderApply(refundDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新医路微信退款回调通知接口
|
||||
*
|
||||
* @param request 请求头信息
|
||||
* @param response 响应信息
|
||||
* @return 应答信息,避免微信平台重复发送回调通知
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
@PostMapping("/xylWeChatRefundNotify")
|
||||
public String xylWeChatRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
return weChatPayNotifyService.xylWeChatRefundNotify(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
package com.yf.exam.modules.applet.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description 微信支付参数接受实体类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-18 15:12:51
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class PaymentDTO implements Serializable {
|
||||
private static final long serialVersionUID = 4090244715734558969L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@NotNull(message = "考试报名主键不能为空!")
|
||||
@ApiModelProperty(value = "考试报名表主键", required=true)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 考生id
|
||||
*/
|
||||
@NotNull(message = "考生id不能为空!")
|
||||
@ApiModelProperty(value = "考生id", required=true)
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 微信用户openid
|
||||
*/
|
||||
@ApiModelProperty(value = "微信用户openid", required=true)
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 考试id
|
||||
*/
|
||||
@ApiModelProperty(value = "考试表主键", required=true)
|
||||
private String examId;
|
||||
|
||||
/**
|
||||
* 支付类型,微信支付:WECHAT_PAY,支付宝支付:ALI_PAY
|
||||
*/
|
||||
@NotBlank(message = "支付类型不能为空!")
|
||||
@ApiModelProperty(value = "支付类型,微信支付:WECHAT_PAY,支付宝支付:ALI_PAY", required=true)
|
||||
private String payType;
|
||||
|
||||
/**
|
||||
* 支付渠道,手机App:MOBILE_APP,微信小程序:WECHAT_APPLET,支付宝小程序:ALI_PAY_APPLE
|
||||
*/
|
||||
@NotBlank(message = "支付渠道不能为空!")
|
||||
@ApiModelProperty(value = "支付渠道,手机App:MOBILE_APP,微信小程序:WECHAT_APPLET,支付宝小程序:ALI_PAY_APPLE", required=true)
|
||||
private String orderChannel;
|
||||
|
||||
/**
|
||||
* 支付金额
|
||||
*/
|
||||
@NotNull(message = "支付金额不能为空!")
|
||||
@ApiModelProperty(value = "支付金额", required=true)
|
||||
private BigDecimal paymentPrice;
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.yf.exam.modules.applet.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-24 16:15:44
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class RefundDTO implements Serializable {
|
||||
private static final long serialVersionUID = -1990509784850994288L;
|
||||
|
||||
/**
|
||||
* 订单编号,必传字段
|
||||
*/
|
||||
@NotBlank(message = "订单编号不能为空!")
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 退款原因
|
||||
*/
|
||||
private String refundReason;
|
||||
|
||||
/**
|
||||
* 退款金额,必传字段
|
||||
*/
|
||||
@NotNull(message = "退款金额不能为空!")
|
||||
private BigDecimal refundPrice;
|
||||
|
||||
/**
|
||||
* 补充描述和凭证
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 货物到货状态,目前用不到
|
||||
*/
|
||||
private String goodsStatus;
|
||||
|
||||
/**
|
||||
* 订单类型(健康咨询订单退款使用),积分兑换:INTEGRAL_EXCHANGE,直接购买:DIRECT_BUY,健康咨询:HEALTH_CONSULTATION
|
||||
*/
|
||||
private String orderType;
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.yf.exam.modules.applet.service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @Description 微信支付回调业务层
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-20 14:00:21
|
||||
* @Version 1.0
|
||||
*/
|
||||
public interface WeChatPayNotifyService {
|
||||
|
||||
/**
|
||||
* 新医路支付回调接口
|
||||
*
|
||||
* @param request 请求信息
|
||||
* @param response 响应信息
|
||||
* @return 应答信息,避免微信平台重复发送回调通知
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
String xylWeChatPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception;
|
||||
|
||||
/**
|
||||
* 新医路退款回调接口
|
||||
*
|
||||
* @param request 请求信息
|
||||
* @param response 响应信息
|
||||
* @return 应答信息,避免微信平台重复发送回调通知
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
String xylWeChatRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception;
|
||||
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
package com.yf.exam.modules.applet.service;
|
||||
|
||||
import com.yf.exam.core.domain.AjaxResult;
|
||||
import com.yf.exam.modules.applet.dto.PaymentDTO;
|
||||
import com.yf.exam.modules.applet.vo.OrderStatusInfoVO;
|
||||
|
||||
/**
|
||||
* @Description 微信小程序和App支付业务层
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-18 15:02:27
|
||||
* @Version 1.0
|
||||
*/
|
||||
public interface WeChatPaymentService {
|
||||
|
||||
/**
|
||||
* 微信小程序支付接口
|
||||
*
|
||||
* @param paymentDTO 输入参数
|
||||
* @return 支付结果
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
AjaxResult appletPay(PaymentDTO paymentDTO) throws Exception;
|
||||
|
||||
/**
|
||||
* 取消订单接口
|
||||
*
|
||||
* @param orderNo 点单编号
|
||||
* @return 取消结果信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
AjaxResult cancelOrderInfo(String orderNo) throws Exception;
|
||||
|
||||
/**
|
||||
* 查询订单状态信息
|
||||
*
|
||||
* @param orderNo 点单编号
|
||||
* @return 结果信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
AjaxResult getOrderStatusInfo(String orderNo) throws Exception;
|
||||
|
||||
/**
|
||||
* 微信关闭订单方法
|
||||
*
|
||||
* @param orderNo 订单编号
|
||||
* @return 状态码
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
int closeWeChatOrderInfo(String orderNo) throws Exception;
|
||||
|
||||
/**
|
||||
* 查询预约服务订单信息
|
||||
*
|
||||
* @param orderNo 订单编号
|
||||
* @param vo 返回值信息
|
||||
* @return 订单状态标识
|
||||
*/
|
||||
OrderStatusInfoVO queryAppointmentOrderStatus(String orderNo, OrderStatusInfoVO vo);
|
||||
|
||||
/**
|
||||
* 查询上商品订单信息
|
||||
*
|
||||
* @param orderNo 订单编号
|
||||
* @param vo 返回值信息
|
||||
* @return 订单状态标识
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
OrderStatusInfoVO queryGoodsOrderStatus(String orderNo, OrderStatusInfoVO vo) throws Exception;
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.yf.exam.modules.applet.service;
|
||||
|
||||
import com.yf.exam.core.domain.AjaxResult;
|
||||
import com.yf.exam.modules.applet.dto.RefundDTO;
|
||||
|
||||
/**
|
||||
* @Description 微信退款业务层
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-24 15:22:49
|
||||
* @Version 1.0
|
||||
*/
|
||||
public interface WeChatRefundService {
|
||||
|
||||
/**
|
||||
* 微信确认退款接口
|
||||
*
|
||||
* @param refundDTO 退款参数
|
||||
* @return 返回信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
AjaxResult weChatRefundOrderApply(RefundDTO refundDTO) throws Exception;
|
||||
|
||||
/**
|
||||
* 调用微信查询单笔退款接口查询预约订单状态信息
|
||||
*
|
||||
* @param refundNo 退款单号
|
||||
* @return 退款信息
|
||||
*/
|
||||
//WeChatRefundInfoVO queryAppointmentOrderRefundStatus(String refundNo);
|
||||
|
||||
/**
|
||||
* 调用微信查询单笔退款接口查询商品订单状态信息
|
||||
*
|
||||
* @param refundNo 退单编号
|
||||
* @param buySource 购买来源
|
||||
* @return 退款信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
//WeChatRefundInfoVO queryGoodsOrderRefundStatus(String refundNo, String buySource) throws Exception;
|
||||
}
|
||||
@ -61,7 +61,7 @@ public class AppletLoginServiceImpl implements AppletLoginService {
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult appletLogin(String loginCode) {
|
||||
//根据code获取用户的微信unionId以及openId等信息
|
||||
//根据code获取用户的微信openId等信息
|
||||
AppletLoginVO appletLoginInfo = AppletChatUtil.getAppletLoginInfo(appletChatConfig.getAppletId(), appletChatConfig.getSecret(), loginCode, appletChatConfig.getGrantType());
|
||||
if (Objects.isNull(appletLoginInfo)) {
|
||||
return AjaxResult.error("获取微信小程序用户信息失败");
|
||||
@ -75,56 +75,26 @@ public class AppletLoginServiceImpl implements AppletLoginService {
|
||||
//从Redis中取出accessToken
|
||||
Object object = redisTemplate.opsForValue().get(accessTokenKey);
|
||||
if (Objects.isNull(object)) {
|
||||
//没有,获取accessToken
|
||||
//没有,获取accessToken,并存入redis
|
||||
accessToken = appletAccessTokenUtil.getAppletAccessToken();
|
||||
} else {
|
||||
accessToken = (String) object;
|
||||
}
|
||||
//获取用户手机号
|
||||
|
||||
//AppletPhoneVO appletPhoneInfo = AppletChatUtil.getAppletPhoneInfo(phoneCode, accessToken);
|
||||
//if (Objects.isNull(appletPhoneInfo)) {
|
||||
// return AjaxResult.error("获取用户手机号失败");
|
||||
//}
|
||||
//if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == ERROR_ACCESS_CODE) {
|
||||
// //当前Redis缓存中的access_token无效直接删除
|
||||
// if (Objects.nonNull(object)) {
|
||||
// redisTemplate.delete(accessTokenKey);
|
||||
// //删除之后重新获取获取accessToken
|
||||
// accessToken = appletAccessTokenUtil.getAppletAccessToken();
|
||||
// appletPhoneInfo = AppletChatUtil.getAppletPhoneInfo(phoneCode, accessToken);
|
||||
// if (Objects.isNull(appletPhoneInfo)) {
|
||||
// return AjaxResult.error("获取用户手机号失败");
|
||||
// }
|
||||
// if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == ERROR_ACCESS_CODE) {
|
||||
// return AjaxResult.error("登录失败!");
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//if (StringUtils.isNotBlank(appletPhoneInfo.getErrmsg()) && !OK.equals(appletPhoneInfo.getErrmsg())) {
|
||||
// return AjaxResult.error("获取用户手机号失败,失败信息为:" + appletPhoneInfo.getErrmsg());
|
||||
//}
|
||||
// 根据手机号和openid判断当前用户是否存在
|
||||
//String phone = StringUtils.isBlank(appletPhoneInfo.getPhoneInfo().getPhoneNumber()) ? "" : appletPhoneInfo.getPhoneInfo().getPhoneNumber();
|
||||
// 根据openid判断当前用户是否存在
|
||||
String openId = StringUtils.isBlank(appletLoginInfo.getOpenid()) ? "" : appletLoginInfo.getOpenid();
|
||||
QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
|
||||
wrapper.lambda()
|
||||
//.eq(SysUser::getPhone, phone)
|
||||
.eq(SysUser::getOpenid, openId);
|
||||
SysUser userByPhone = sysUserService.getOne(wrapper, false);
|
||||
wrapper.lambda().eq(SysUser::getOpenid, openId);
|
||||
SysUser userByOpenid = sysUserService.getOne(wrapper, false);
|
||||
|
||||
SysUser user = new SysUser();
|
||||
// 考生信息为空,返回openId
|
||||
if (Objects.isNull(userByPhone)) {
|
||||
if (Objects.isNull(userByOpenid)) {
|
||||
return AjaxResult.success("您还未注册,请注册后使用!", openId);
|
||||
}
|
||||
//更新用户的openid等微信标识信息
|
||||
user.setId(userByPhone.getId());
|
||||
user.setOpenid(openId);
|
||||
user.setPhone(StringUtils.isBlank(userByPhone.getPhone()) ? "" : userByPhone.getPhone());
|
||||
user.setUpdateTime(new Date());
|
||||
sysUserService.updateById(user);
|
||||
return AjaxResult.success(user);
|
||||
userByOpenid.setOpenid(openId);
|
||||
userByOpenid.setUpdateTime(new Date());
|
||||
sysUserService.updateById(userByOpenid);
|
||||
return AjaxResult.success(userByOpenid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,381 @@
|
||||
package com.yf.exam.modules.applet.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
|
||||
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
|
||||
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
|
||||
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
|
||||
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
|
||||
import com.yf.exam.config.XylWeChatPaymentConfig;
|
||||
import com.yf.exam.constant.Constants;
|
||||
import com.yf.exam.core.enums.GooodsOrderStatusEnum;
|
||||
import com.yf.exam.core.enums.PayTypeEnum;
|
||||
import com.yf.exam.core.enums.RefundStatusEnum;
|
||||
import com.yf.exam.core.enums.WeChatTradeStateEnum;
|
||||
import com.yf.exam.core.exception.ServiceException;
|
||||
import com.yf.exam.core.utils.RedisDistributedLockUtils;
|
||||
import com.yf.exam.core.utils.http.HttpUtils;
|
||||
import com.yf.exam.modules.applet.service.WeChatPayNotifyService;
|
||||
import com.yf.exam.modules.applet.vo.WeChatPayNotifyPlaintextVO;
|
||||
import com.yf.exam.modules.exam.entity.ExamRegistration;
|
||||
import com.yf.exam.modules.exam.mapper.ExamRegistrationMapper;
|
||||
import com.yf.exam.modules.payment.entity.PaymentInfo;
|
||||
import com.yf.exam.modules.payment.entity.RefundInfo;
|
||||
import com.yf.exam.modules.payment.mapper.PaymentInfoMapper;
|
||||
import com.yf.exam.modules.payment.mapper.RefundInfoMapper;
|
||||
import com.yf.exam.modules.payment.vo.WeChatRefundNotifyVO;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
|
||||
/**
|
||||
* @Description 微信支付回调业务层实现类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-20 14:00:52
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WeChatPayNotifyServiceImpl implements WeChatPayNotifyService {
|
||||
|
||||
@Resource
|
||||
private XylWeChatPaymentConfig xylWeChatPaymentConfig;
|
||||
@Resource
|
||||
private ExamRegistrationMapper examRegistrationMapper;
|
||||
/*@Resource
|
||||
private GoodsOrderMapper goodsOrderMapper;
|
||||
@Resource
|
||||
private AppointmentOrderMapper appointmentOrderMapper;
|
||||
@Resource
|
||||
private YlypWeChatPaymentConfig ylypWeChatPaymentConfig;*/
|
||||
@Resource
|
||||
private PaymentInfoMapper paymentInfoMapper;
|
||||
@Resource
|
||||
private RedisDistributedLockUtils redisDistributedLockUtils;
|
||||
@Resource(name = "transactionManager")
|
||||
private DataSourceTransactionManager transactionManager;
|
||||
@Resource
|
||||
private RefundInfoMapper refundInfoMapper;
|
||||
@Resource(name = "xylVerifier")
|
||||
private Verifier xylVerifier;
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* 新医路账户标识
|
||||
*/
|
||||
private static final String XINYILU_ACCOUNT = "BAIXING";
|
||||
|
||||
/**
|
||||
* 新医路账户标识
|
||||
*/
|
||||
private static final String YILUYOUPIN_ACCOUNT = "YILUYOUPIN";
|
||||
|
||||
/**
|
||||
* 支付回调标识
|
||||
*/
|
||||
private static final String PAY = "PAY";
|
||||
|
||||
/**
|
||||
* 退款回调标识
|
||||
*/
|
||||
private static final String REFUND = "REFUND";
|
||||
|
||||
/**
|
||||
* 新医路支付回调接口
|
||||
*
|
||||
* @param request 请求信息
|
||||
* @param response 响应信息
|
||||
* @return 应答信息,避免微信平台重复发送回调通知
|
||||
*/
|
||||
@Override
|
||||
public String xylWeChatPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
log.info("新医路微信支付回调开始执行...........");
|
||||
return weChatPayNotifyInfo(request, response, PAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新医路退款回调接口
|
||||
*
|
||||
* @param request 请求信息
|
||||
* @param response 响应信息
|
||||
* @return 应答信息,避免微信平台重复发送回调通知
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
@Override
|
||||
public String xylWeChatRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
log.info("新医路微信退款回调开始执行...........");
|
||||
return weChatPayNotifyInfo(request, response, REFUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信支付回调通知公共方法
|
||||
*
|
||||
* @param request 请求信息
|
||||
* @param response 响应信息
|
||||
* @param refundAndPaymentFlag 支付和回调标识
|
||||
* @return 返回信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
private String weChatPayNotifyInfo(HttpServletRequest request, HttpServletResponse response,
|
||||
String refundAndPaymentFlag) throws Exception {
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
//请求体
|
||||
String body = HttpUtils.readRequestData(request);
|
||||
if (StringUtils.isBlank(body)) {
|
||||
log.error("微信回调通知失败,请求体 ====> {}", body);
|
||||
response.setStatus(500);
|
||||
resultMap.put("code", "ERROR");
|
||||
resultMap.put("message", "通知验签失败");
|
||||
return JSON.toJSONString(resultMap);
|
||||
}
|
||||
log.info("微信通知的请求体信息 ===> {}", body);
|
||||
//验证签名
|
||||
String nonce = request.getHeader("Wechatpay-Nonce");
|
||||
String timestamp = request.getHeader("Wechatpay-Timestamp");
|
||||
String signature = request.getHeader("Wechatpay-Signature");
|
||||
String serialNo = request.getHeader("Wechatpay-Serial");
|
||||
//构建request,传入必要参数
|
||||
Notification notification = null;
|
||||
NotificationRequest notificationRequest = new NotificationRequest.Builder().withSerialNumber(serialNo)
|
||||
.withNonce(nonce).withTimestamp(timestamp).withSignature(signature).withBody(body).build();
|
||||
NotificationHandler handler = new NotificationHandler(xylVerifier, xylWeChatPaymentConfig.getXylPaymentKey().getBytes(StandardCharsets.UTF_8));
|
||||
notification = handler.parse(notificationRequest);
|
||||
if (Objects.isNull(notification)) {
|
||||
log.error("微信通知验签失败,请求体 ====> {}", body);
|
||||
response.setStatus(500);
|
||||
resultMap.put("code", "ERROR");
|
||||
resultMap.put("message", "通知验签失败");
|
||||
return JSON.toJSONString(resultMap);
|
||||
}
|
||||
//密文,随机串,附件数据
|
||||
String ciphertext = StringUtils.isBlank(notification.getResource().getCiphertext()) ? "" : notification.getResource().getCiphertext();
|
||||
String nonceTwo = StringUtils.isBlank(notification.getResource().getNonce()) ? "" : notification.getResource().getNonce();
|
||||
String associatedData = StringUtils.isBlank(notification.getResource().getAssociatedData()) ? "" : notification.getResource().getAssociatedData();
|
||||
//解密密文
|
||||
String plainText = "";
|
||||
AesUtil aesUtil = new AesUtil(xylWeChatPaymentConfig.getXylPaymentKey().getBytes(StandardCharsets.UTF_8));
|
||||
plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonceTwo.getBytes(StandardCharsets.UTF_8), ciphertext);
|
||||
if (StringUtils.isBlank(plainText)) {
|
||||
response.setStatus(500);
|
||||
resultMap.put("code", "ERROR");
|
||||
resultMap.put("message", "解密失败!");
|
||||
return JSON.toJSONString(resultMap);
|
||||
}
|
||||
//记录支付日志和修改订单状态
|
||||
if (Constants.PAY_NOTIFY.equals(refundAndPaymentFlag)) {
|
||||
this.processPaymentInfo(plainText);
|
||||
}
|
||||
//修改订单状态
|
||||
if (Constants.REFUND_NOTIFY.equals(refundAndPaymentFlag)) {
|
||||
this.processRefundInfo(plainText);
|
||||
}
|
||||
response.setStatus(200);
|
||||
resultMap.put("code", "SUCCESS");
|
||||
resultMap.put("message", "成功");
|
||||
log.info("微信回调方法执行完成!");
|
||||
return JSON.toJSONString(resultMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录支付信息和修改订单状态
|
||||
*
|
||||
* @param plainText 支付验签以后的通知内容
|
||||
*/
|
||||
private void processPaymentInfo(String plainText) {
|
||||
log.info("支付回调明文 ====> {}", plainText);
|
||||
//密文信息,随机串,附件数据
|
||||
WeChatPayNotifyPlaintextVO notifyPlaintext = JSONObject.parseObject(plainText, WeChatPayNotifyPlaintextVO.class);
|
||||
if (StringUtils.isBlank(notifyPlaintext.getOutTradeNo())) {
|
||||
return;
|
||||
}
|
||||
//尝试获取锁
|
||||
String orderNoLockKey = Constants.WE_CHAT_NOTIFY_KEY + notifyPlaintext.getOutTradeNo();
|
||||
boolean tryLock = redisDistributedLockUtils.tryLock(orderNoLockKey, 5);
|
||||
if (!tryLock) {
|
||||
return;
|
||||
}
|
||||
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
|
||||
try {
|
||||
//记录商品订单支付日志和修改订单状态
|
||||
ExamRegistration examRegistration = examRegistrationMapper.selectById(notifyPlaintext.getOutTradeNo());
|
||||
if (Objects.nonNull(examRegistration)) {
|
||||
insertPaymentInfo(notifyPlaintext, examRegistration, plainText);
|
||||
if (WeChatTradeStateEnum.SUCCESS.getInfo().equals(notifyPlaintext.getTradeState())) {
|
||||
examRegistrationMapper.updatePaymentStateById(GooodsOrderStatusEnum.PAY.getInfo(), examRegistration.getId());
|
||||
} else {
|
||||
log.info("商品订单微信订单状态异常,订单状态为 ====> {}", notifyPlaintext.getTradeState());
|
||||
}
|
||||
transactionManager.commit(transactionStatus);
|
||||
return;
|
||||
}
|
||||
transactionManager.commit(transactionStatus);
|
||||
} catch (Exception e) {
|
||||
transactionManager.rollback(transactionStatus);
|
||||
log.error("微信支付回调失败,失败原因:{}", e.getMessage());
|
||||
throw e;
|
||||
} finally {
|
||||
redisDistributedLockUtils.unlock(orderNoLockKey);
|
||||
log.info("支付回调释放锁完成...........");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录支付日志信息
|
||||
*
|
||||
* @param notifyPlaintext 回调信息
|
||||
* @param examRegistration 订单信息
|
||||
* @param plainText 回调明文
|
||||
*/
|
||||
private void insertPaymentInfo(WeChatPayNotifyPlaintextVO notifyPlaintext, ExamRegistration examRegistration,
|
||||
String plainText) {
|
||||
//记录支付日志
|
||||
int paymentInfoCount = paymentInfoMapper.getByRegistrationId(notifyPlaintext.getOutTradeNo());
|
||||
if (paymentInfoCount <= 0) {
|
||||
//构建支付订单信息
|
||||
PaymentInfo paymentInfo = buildPaymentInfo(notifyPlaintext, examRegistration, plainText);
|
||||
int insertCount = paymentInfoMapper.insertPaymentInfo(paymentInfo);
|
||||
if (insertCount <= 0) {
|
||||
log.error("记录支付日志出错,参数为 ====> [{}]", paymentInfo);
|
||||
throw new ServiceException("记录支付日志出错,请联系管理员!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建支付信息参数
|
||||
*
|
||||
* @param notifyPlaintext 通知明文信息
|
||||
* @param examRegistration 商品订单信息
|
||||
*/
|
||||
private PaymentInfo buildPaymentInfo(WeChatPayNotifyPlaintextVO notifyPlaintext, ExamRegistration examRegistration,
|
||||
String plainText) {
|
||||
PaymentInfo paymentInfo = new PaymentInfo();
|
||||
if (Objects.nonNull(examRegistration)) {
|
||||
paymentInfo.setUserId(Objects.isNull(examRegistration.getUserId()) ? null : examRegistration.getUserId());
|
||||
paymentInfo.setExamRegistrationId(StringUtils.isBlank(examRegistration.getId()) ? "" : examRegistration.getId());
|
||||
//paymentInfo.setPayChannel(StringUtils.isBlank(examRegistration.getOrderChannel()) ? "" : examRegistration.getOrderChannel());
|
||||
}
|
||||
paymentInfo.setTransactionNo(StringUtils.isBlank(notifyPlaintext.getTransactionId()) ? "" : notifyPlaintext.getTransactionId());
|
||||
paymentInfo.setPayPrice(BigDecimal.valueOf(Objects.isNull(notifyPlaintext.getAmount().getPayerTotal()) ? 0 : notifyPlaintext.getAmount().getPayerTotal()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN));
|
||||
paymentInfo.setPayType(PayTypeEnum.WECHAT_PAY.getInfo());
|
||||
paymentInfo.setWechatTradeState(StringUtils.isBlank(notifyPlaintext.getTradeState()) ? "" : notifyPlaintext.getTradeState());
|
||||
paymentInfo.setPayNotifyContent(plainText);
|
||||
paymentInfo.setPayTime(LocalDateTime.parse(StringUtils.isBlank(notifyPlaintext.getSuccessTime()) ? "" : notifyPlaintext.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME));
|
||||
paymentInfo.setPaymentMerchantType("WEISHENGXUEHUI");
|
||||
paymentInfo.setDelFlag(0);
|
||||
paymentInfo.setCreateTime(new Date());
|
||||
return paymentInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改订单状态以及减少库存信息
|
||||
*
|
||||
* @param plainText 支付验签以后的通知内容
|
||||
*/
|
||||
private void processRefundInfo(String plainText) {
|
||||
log.info("退款回调明文 =====> {}", plainText);
|
||||
//将明文信息转为实体类映射
|
||||
WeChatRefundNotifyVO refundNotifyVO = JSONObject.parseObject(plainText, WeChatRefundNotifyVO.class);
|
||||
if (StringUtils.isBlank(refundNotifyVO.getOutTradeNo())) {
|
||||
return;
|
||||
}
|
||||
//尝试获取锁
|
||||
String orderNoLockKey = Constants.WE_CHAT_REFUND_KEY + refundNotifyVO.getOutTradeNo();
|
||||
boolean tryLock = redisDistributedLockUtils.tryLock(orderNoLockKey, 5);
|
||||
if (!tryLock) {
|
||||
return;
|
||||
}
|
||||
//手动开启事务
|
||||
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
|
||||
RedisAtomicLong redisAtomicLong = null;
|
||||
try {
|
||||
//根据订单编号查询订单信息
|
||||
ExamRegistration examRegistration = examRegistrationMapper.selectById(refundNotifyVO.getOutTradeNo());
|
||||
if (Objects.isNull(examRegistration)) {
|
||||
return;
|
||||
}
|
||||
//修改商品订单状态
|
||||
if (Objects.nonNull(examRegistration)) {
|
||||
updateGoodsInfo(examRegistration, plainText, refundNotifyVO);
|
||||
}
|
||||
transactionManager.commit(transactionStatus);
|
||||
} catch (Exception e) {
|
||||
transactionManager.rollback(transactionStatus);
|
||||
log.error("微信退款回调通知失败,失败信息为:{}", e.getMessage());
|
||||
if (Objects.nonNull(redisAtomicLong) && redisAtomicLong.get() > 0) {
|
||||
//出现异常减一
|
||||
redisAtomicLong.decrementAndGet();
|
||||
}
|
||||
throw e;
|
||||
} finally {
|
||||
redisDistributedLockUtils.unlock(orderNoLockKey);
|
||||
log.info("退款回调释放锁完成.............");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理商品订单信息
|
||||
*
|
||||
* @param examRegistration 订单信息
|
||||
* @param plainText 明文
|
||||
* @param refundNotifyVO 退款回调信息
|
||||
*/
|
||||
private void updateGoodsInfo(ExamRegistration examRegistration, String plainText, WeChatRefundNotifyVO refundNotifyVO) {
|
||||
if (RefundStatusEnum.SUCCESS.getInfo().equals(refundNotifyVO.getRefundStatus())
|
||||
&& StringUtils.isNotBlank(examRegistration.getPaymentState())
|
||||
&& !(GooodsOrderStatusEnum.REFUNDED.getInfo().equals(examRegistration.getPaymentState()))) {
|
||||
int updateCount = examRegistrationMapper.updatePaymentStateById(GooodsOrderStatusEnum.REFUNDED.getInfo(), examRegistration.getPaymentState());
|
||||
if (updateCount < 1) {
|
||||
log.info("微信退款通知,修改商品单状态失败,订单编号 =====> {}", refundNotifyVO.getOutTradeNo());
|
||||
}
|
||||
//修改退款信息
|
||||
RefundInfo refundInfo = buildRefundInfo(plainText, refundNotifyVO);
|
||||
int refundCount = refundInfoMapper.updateRefundInfoByNo(refundInfo);
|
||||
if (refundCount < 1) {
|
||||
log.info("微信退款通知,记录商品订单微信退款单信息失败,订单编号 =====> {}", refundNotifyVO.getOutTradeNo());
|
||||
}
|
||||
}
|
||||
if (RefundStatusEnum.CLOSED.getInfo().equals(refundNotifyVO.getRefundStatus())) {
|
||||
log.info("当前商品退款单已经关闭,订单号 ====> {}, 退款单号 =====> {}", refundNotifyVO.getOutTradeNo(), refundNotifyVO.getOutRefundNo());
|
||||
}
|
||||
if (RefundStatusEnum.ABNORMAL.getInfo().equals(refundNotifyVO.getRefundStatus())) {
|
||||
log.info("商品订单退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往【商户平台—>交易中心】,手动处理此笔退款,订单号 ====> {}, 退款单号 =====> {}", refundNotifyVO.getOutTradeNo(), refundNotifyVO.getOutRefundNo());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建退款单信息
|
||||
*
|
||||
* @param plainText 退款通知解密的明文信息
|
||||
* @param refundNotifyVO 通知参数
|
||||
* @return 结果
|
||||
*/
|
||||
private RefundInfo buildRefundInfo(String plainText, WeChatRefundNotifyVO refundNotifyVO) {
|
||||
RefundInfo refundInfo = new RefundInfo();
|
||||
refundInfo.setWechatRefundStatus(StringUtils.isBlank(refundNotifyVO.getRefundStatus()) ? "" : refundNotifyVO.getRefundStatus());
|
||||
refundInfo.setSuccessTime(LocalDateTime.parse(StringUtils.isBlank(refundNotifyVO.getSuccessTime()) ? "" : refundNotifyVO.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME));
|
||||
refundInfo.setRefundNotifyContent(plainText);
|
||||
refundInfo.setExamRegistrationId(StringUtils.isBlank(refundNotifyVO.getOutTradeNo()) ? "" : refundNotifyVO.getOutTradeNo());
|
||||
refundInfo.setOutRefundNo(StringUtils.isBlank(refundNotifyVO.getOutRefundNo()) ? "" : refundNotifyVO.getOutRefundNo());
|
||||
return refundInfo;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,449 @@
|
||||
package com.yf.exam.modules.applet.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.yf.exam.config.AppletChatConfig;
|
||||
import com.yf.exam.config.WeChatPaymentUrlConfig;
|
||||
import com.yf.exam.config.XylWeChatPaymentConfig;
|
||||
import com.yf.exam.constant.Constants;
|
||||
import com.yf.exam.core.domain.AjaxResult;
|
||||
import com.yf.exam.core.enums.GooodsOrderStatusEnum;
|
||||
import com.yf.exam.core.enums.WeChatTradeStateEnum;
|
||||
import com.yf.exam.core.exception.ServiceException;
|
||||
import com.yf.exam.modules.applet.dto.PaymentDTO;
|
||||
import com.yf.exam.modules.applet.service.WeChatPaymentService;
|
||||
import com.yf.exam.modules.applet.vo.OrderStatusInfoVO;
|
||||
import com.yf.exam.modules.applet.vo.WeChatAppletSignVO;
|
||||
import com.yf.exam.modules.applet.vo.WeChatQueryOrderVO;
|
||||
import com.yf.exam.modules.exam.entity.ExamRegistration;
|
||||
import com.yf.exam.modules.exam.mapper.ExamRegistrationMapper;
|
||||
import com.yf.exam.modules.utils.WeChatUtil;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Signature;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
/**
|
||||
* @Description 微信小程序和App支付业务层实现类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-18 15:02:40
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class WeChatPaymentServiceImpl implements WeChatPaymentService {
|
||||
|
||||
@Resource
|
||||
private ExamRegistrationMapper examRegistrationMapper;
|
||||
@Resource
|
||||
private AppletChatConfig appletChatConfig;
|
||||
@Resource
|
||||
private XylWeChatPaymentConfig xylWeChatPaymentConfig;
|
||||
@Resource(name = "xinYiLuWeChatPayClient")
|
||||
private CloseableHttpClient xinYiLuWeChatPayClient;
|
||||
@Resource
|
||||
private WeChatPaymentUrlConfig weChatPaymentUrlConfig;
|
||||
@Resource
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Resource
|
||||
private WeChatUtil weChatUtil;
|
||||
@Resource
|
||||
private AppletChatConfig AppletChatConfig;
|
||||
|
||||
/**
|
||||
* 山东省公共卫生学会支付商品描述
|
||||
*/
|
||||
private static final String SD_GONGGONGWEISHENG_XUEHUI_DESCRIPTION = "山东省公共卫生学会";
|
||||
|
||||
/**
|
||||
* JsApi下单成功状态码
|
||||
*/
|
||||
private static final int HAVE_BODY_SUCCESS_CODE = 200;
|
||||
|
||||
/**
|
||||
* JsApi下单成功状态码
|
||||
*/
|
||||
private static final int NO_HAVE_BODY_SUCCESS_CODE = 204;
|
||||
|
||||
/**
|
||||
* 签名算法
|
||||
*/
|
||||
private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
|
||||
|
||||
/**
|
||||
* 签名方式
|
||||
*/
|
||||
private static final String SIGN_TYPE = "RSA";
|
||||
|
||||
/**
|
||||
* 支付回调接口地址
|
||||
*/
|
||||
private static final String XINYILU_WE_CHAT_NOTIFY_URL = "/examApplet/weChatPayment/xylWeChatPayNotify";
|
||||
|
||||
/**
|
||||
* 微信小程序支付接口
|
||||
*
|
||||
* @param paymentDTO 输入参数
|
||||
* @return 支付结果
|
||||
* @throws Exception 常信息
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult appletPay(PaymentDTO paymentDTO) throws Exception {
|
||||
//从Redis中获取当前prepay_id的值
|
||||
String prepayId = redisTemplate.opsForValue().get(Constants.PREPAY_ID_KEY + paymentDTO.getId());
|
||||
if (StringUtils.isBlank(prepayId)) {
|
||||
//根据订单编号查询商品订单信息
|
||||
ExamRegistration examRegistration = examRegistrationMapper.selectById(paymentDTO.getId());
|
||||
if (Objects.isNull(examRegistration) || StringUtils.isEmpty(examRegistration.getPaymentState())) {
|
||||
return AjaxResult.error("未查询到当前订单信息,请选择正确的订单信息!");
|
||||
}
|
||||
//判断订单状态
|
||||
if (!examRegistration.getPaymentState().equals(GooodsOrderStatusEnum.WAIT_PAY.getInfo())) {
|
||||
return AjaxResult.error("订单状态异常,无法支付,请联系管理员!");
|
||||
}
|
||||
//构建JsApi下单参数
|
||||
String jsApiParams = this.buildGoodsOrderJsApiParams(paymentDTO, examRegistration);
|
||||
//请求微信JsApi下单接口获取prepay_id的值
|
||||
prepayId = this.requestJsApiInterface(jsApiParams, paymentDTO, prepayId);
|
||||
} else {
|
||||
prepayId = redisTemplate.opsForValue().get(Constants.PREPAY_ID_KEY + paymentDTO.getId());
|
||||
}
|
||||
//构建小程序调起支付参数信息
|
||||
return AjaxResult.success(getSignInfo(prepayId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消订单接口
|
||||
*
|
||||
* @param orderNo 点单编号
|
||||
* @return 取消结果信息
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public AjaxResult cancelOrderInfo(String orderNo) throws Exception {
|
||||
//根据订单编号查询订单信息
|
||||
ExamRegistration examRegistration = examRegistrationMapper.selectById(orderNo);
|
||||
if (Objects.isNull(examRegistration)) {
|
||||
return AjaxResult.error("当前订单信息不存在,请重新选择!");
|
||||
}
|
||||
//商品订单信息
|
||||
if (StringUtils.isBlank(examRegistration.getPaymentState())
|
||||
|| !GooodsOrderStatusEnum.WAIT_PAY.getInfo().equals(examRegistration.getPaymentState())) {
|
||||
log.info("订单状态为:====> {}", StringUtils.isBlank(examRegistration.getPaymentState()) ? "不存在" : examRegistration.getPaymentState());
|
||||
return AjaxResult.error("当前订单状态异常,请联系管理员!");
|
||||
}
|
||||
//下单10分种以后才可以取消订单
|
||||
//LocalDateTime tenAfterTime = goodsOrderInfo.getOrderTime().plusMinutes(10);
|
||||
//if (LocalDateTime.now().isBefore(tenAfterTime)) {
|
||||
// return AjaxResult.error("10分钟以后才能取消当前订单,请耐心等待!");
|
||||
//}
|
||||
//调用微信查单接口确定微信系统中订单的状态
|
||||
OrderStatusInfoVO orderStatusInfoVO = new OrderStatusInfoVO();
|
||||
OrderStatusInfoVO vo = this.queryGoodsOrderStatus(examRegistration.getId(), orderStatusInfoVO);
|
||||
if (BooleanUtils.isTrue(vo.getPayFlag())) {
|
||||
//关闭微信系统的订单和修改本地系统中的订单状态
|
||||
int statusCode = this.closeWeChatOrderInfo(examRegistration.getId());
|
||||
if (!(statusCode == HAVE_BODY_SUCCESS_CODE || statusCode == NO_HAVE_BODY_SUCCESS_CODE)) {
|
||||
return AjaxResult.error("取消订单失败,请联系管理员!");
|
||||
}
|
||||
// 修改本地订单状态
|
||||
examRegistrationMapper.updatePaymentStateById(GooodsOrderStatusEnum.CANCEL.getInfo(), orderNo);
|
||||
}
|
||||
return AjaxResult.success("取消订单成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单状态信息
|
||||
*
|
||||
* @param orderNo 订单编号
|
||||
* @return 结果信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult getOrderStatusInfo(String orderNo) throws Exception {
|
||||
OrderStatusInfoVO vo = new OrderStatusInfoVO();
|
||||
//根据订单编号查询订单信息
|
||||
ExamRegistration examRegistration = examRegistrationMapper.selectById(orderNo);
|
||||
if (Objects.isNull(examRegistration)) {
|
||||
// 订单都不存在,说明没有下过订单,可以支付
|
||||
vo.setPayFlag(true);
|
||||
return AjaxResult.success(vo);
|
||||
}
|
||||
//商品订单不为空,调用微信查单接口确认订单状态
|
||||
if (Objects.nonNull(examRegistration)) {
|
||||
OrderStatusInfoVO order = new OrderStatusInfoVO();
|
||||
vo = this.queryGoodsOrderStatus(examRegistration.getId(), order);
|
||||
}
|
||||
return AjaxResult.success(vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信关闭订单方法
|
||||
*
|
||||
* @param orderNo 订单编号
|
||||
* @return 状态码
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
@Override
|
||||
public int closeWeChatOrderInfo(String orderNo) throws Exception {
|
||||
log.info("调用微信关闭订单接口,订单号 ====> {}", orderNo);
|
||||
String closeUrl = String.format(weChatPaymentUrlConfig.getCloseOrderUrl(), orderNo);
|
||||
HttpPost httpPost = new HttpPost(closeUrl);
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
String jsonParams;
|
||||
CloseableHttpResponse response = null;
|
||||
paramMap.put("mchid", xylWeChatPaymentConfig.getXylMchId());
|
||||
jsonParams = JSON.toJSONString(paramMap);
|
||||
StringEntity entity = new StringEntity(jsonParams, "utf-8");
|
||||
entity.setContentType("application/json");
|
||||
httpPost.setEntity(entity);
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
response = xinYiLuWeChatPayClient.execute(httpPost);
|
||||
try {
|
||||
if (response == null) {
|
||||
throw new ServiceException("获取微信HttpClient对象失败,请联系管理员!");
|
||||
}
|
||||
//响应状态码
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
switch (statusCode) {
|
||||
case HAVE_BODY_SUCCESS_CODE:
|
||||
log.info("微信关闭订单成功!");
|
||||
break;
|
||||
case NO_HAVE_BODY_SUCCESS_CODE:
|
||||
log.info("微信关闭订单成功,无返回体!");
|
||||
break;
|
||||
default:
|
||||
throw new ServiceException("微信关闭订单失败!");
|
||||
}
|
||||
return statusCode;
|
||||
} finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询预约服务订单状态
|
||||
*
|
||||
* @param orderNo 订单编号
|
||||
* @param vo 返回值信息
|
||||
*/
|
||||
@Override
|
||||
public OrderStatusInfoVO queryAppointmentOrderStatus(String orderNo, OrderStatusInfoVO vo) {
|
||||
log.info("调用微信查询订单接口,订单编号 ====> {}", orderNo);
|
||||
String requestUrl = String.format(weChatPaymentUrlConfig.getQueryMchIdUrl(), orderNo);
|
||||
requestUrl = requestUrl.concat("?mchid=").concat(xylWeChatPaymentConfig.getXylMchId());
|
||||
HttpGet httpGet = new HttpGet(requestUrl);
|
||||
httpGet.setHeader("Accept", "application/json");
|
||||
try (CloseableHttpResponse response = xinYiLuWeChatPayClient.execute(httpGet)) {
|
||||
//响应体
|
||||
String responseBody = EntityUtils.toString(response.getEntity());
|
||||
//响应状态码
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode == HAVE_BODY_SUCCESS_CODE) {
|
||||
WeChatQueryOrderVO weChatQueryOrderVO = JSONObject.parseObject(responseBody, WeChatQueryOrderVO.class);
|
||||
//是否可以支付标识
|
||||
vo.setPayFlag(StringUtils.isNotBlank(weChatQueryOrderVO.getTradeState())
|
||||
&& WeChatTradeStateEnum.NOTPAY.getInfo().equals(weChatQueryOrderVO.getTradeState()));
|
||||
//支付状态
|
||||
vo.setTradeStatus(weChatQueryOrderVO.getTradeState());
|
||||
//返回值所有参数
|
||||
vo.setWeChatQueryOrderVO(weChatQueryOrderVO);
|
||||
} else if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
|
||||
log.warn("请求微信查单接口成功,无返回信息!");
|
||||
} else {
|
||||
throw new ServiceException("调用微信查询订单接口异常,响应码为:" + statusCode + ", 查询订单返回结果 = " + responseBody);
|
||||
}
|
||||
return vo;
|
||||
} catch (Exception e) {
|
||||
log.error("请求微信查单接口异常,异常信息为 ====> {}", e.getMessage());
|
||||
throw new ServiceException("查询预约订单状态失败,请联系管理员!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询商品订单状态
|
||||
*
|
||||
* @param orderNo 订单编号
|
||||
* @param vo 返回值信息
|
||||
*/
|
||||
@Override
|
||||
public OrderStatusInfoVO queryGoodsOrderStatus(String orderNo, OrderStatusInfoVO vo) throws Exception {
|
||||
log.info("调用微信查询订单接口,订单编号 ====> {}", orderNo);
|
||||
String requestUrl = String.format(weChatPaymentUrlConfig.getQueryMchIdUrl(), orderNo).concat("?mchid=").concat(xylWeChatPaymentConfig.getXylMchId());
|
||||
HttpGet httpGet = new HttpGet(requestUrl);
|
||||
httpGet.setHeader("Accept", "application/json");
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
response = xinYiLuWeChatPayClient.execute(httpGet);
|
||||
if (response == null) {
|
||||
throw new ServiceException("获取微信HttpClient对象失败,请联系管理员!");
|
||||
}
|
||||
//响应体
|
||||
String responseBody = EntityUtils.toString(response.getEntity());
|
||||
//响应状态码
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode == HAVE_BODY_SUCCESS_CODE) {
|
||||
WeChatQueryOrderVO weChatQueryOrderVO = JSONObject.parseObject(responseBody, WeChatQueryOrderVO.class);
|
||||
//是否可以支付标识
|
||||
vo.setPayFlag(StringUtils.isNotBlank(weChatQueryOrderVO.getTradeState())
|
||||
&& WeChatTradeStateEnum.NOTPAY.getInfo().equals(weChatQueryOrderVO.getTradeState()));
|
||||
//支付状态
|
||||
vo.setTradeStatus(weChatQueryOrderVO.getTradeState());
|
||||
//返回值所有信息
|
||||
vo.setWeChatQueryOrderVO(weChatQueryOrderVO);
|
||||
}
|
||||
if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
|
||||
log.warn("请求微信查单接口成功,无返回信息!");
|
||||
}
|
||||
return vo;
|
||||
} catch (Exception e) {
|
||||
log.error("请求微信查单接口异常,异常信息为 ====> {}", e.getMessage());
|
||||
throw new ServiceException("查询商品订单状态失败,请联系管理员!");
|
||||
} finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建商品订单JsApi微信下单参数
|
||||
*
|
||||
* @param paymentDTO 前端传值
|
||||
* @param examRegistration 订单信息
|
||||
* @return 下单参数json串
|
||||
*/
|
||||
private String buildGoodsOrderJsApiParams(PaymentDTO paymentDTO, ExamRegistration examRegistration) {
|
||||
Map<String, Object> paramMap = new LinkedHashMap<>();
|
||||
paramMap.put("mchid", xylWeChatPaymentConfig.getXylMchId());
|
||||
paramMap.put("out_trade_no", examRegistration.getId());
|
||||
//应用id,此处为小程序id
|
||||
paramMap.put("appid", appletChatConfig.getAppletId());
|
||||
paramMap.put("description", SD_GONGGONGWEISHENG_XUEHUI_DESCRIPTION);
|
||||
paramMap.put("notify_url", xylWeChatPaymentConfig.getXylWeChatNotifyUrl() + XINYILU_WE_CHAT_NOTIFY_URL);
|
||||
|
||||
Map<String, Object> amountParamMap = new LinkedHashMap<>();
|
||||
//总金额
|
||||
int totalPrice = paymentDTO.getPaymentPrice().multiply(BigDecimal.valueOf(100)).intValue();
|
||||
amountParamMap.put("total", totalPrice);
|
||||
//货币类型
|
||||
amountParamMap.put("currency", "CNY");
|
||||
paramMap.put("amount", amountParamMap);
|
||||
//支付者信息
|
||||
Map<String, Object> payerParamMap = new LinkedHashMap<>();
|
||||
payerParamMap.put("openid", paymentDTO.getOpenid());
|
||||
paramMap.put("payer", payerParamMap);
|
||||
return JSON.toJSONString(paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求JsApi下单接口方法
|
||||
*
|
||||
* @param jsApiParams 下单参数
|
||||
* @param paymentDTO 输入参数
|
||||
* @param prepayId JsAp下单接口返回值
|
||||
* @return 结果
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
private String requestJsApiInterface(String jsApiParams, PaymentDTO paymentDTO, String prepayId) throws Exception {
|
||||
log.info("JsApi请求下单参数 ====> {}", jsApiParams);
|
||||
StringEntity stringEntity = new StringEntity(jsApiParams, StandardCharsets.UTF_8);
|
||||
stringEntity.setContentType("application/json");
|
||||
HttpPost httpPost = new HttpPost(weChatPaymentUrlConfig.getJsapiPalceOrderUrl());
|
||||
httpPost.setEntity(stringEntity);
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
CloseableHttpResponse response = null;
|
||||
String payAccount = "";
|
||||
try {
|
||||
response = xinYiLuWeChatPayClient.execute(httpPost);
|
||||
payAccount = "山东省公共卫生学会";
|
||||
//处理响应结果
|
||||
if (Objects.isNull(response)) {
|
||||
log.error("JsApi下单接口执行错误, 执行账户为 ====> {}", payAccount);
|
||||
throw new ServiceException("JsApi下单接口执行异常,请联系管理员!");
|
||||
}
|
||||
//响应状态码
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
//响应体
|
||||
String result = EntityUtils.toString(response.getEntity());
|
||||
if (statusCode == HAVE_BODY_SUCCESS_CODE) {
|
||||
//请求成功,取出prepay_id的值并放入Redis缓存中,prepay_id的有效期为两小时,此处缓存一个半小时
|
||||
Map<String, Object> resultMap = JSONObject.parseObject(result);
|
||||
prepayId = resultMap.getOrDefault("prepay_id", "").toString();
|
||||
redisTemplate.opsForValue().set(Constants.PREPAY_ID_KEY + paymentDTO.getId(), prepayId, 5400, TimeUnit.SECONDS);
|
||||
} else if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
|
||||
//请求成功,无返回体
|
||||
log.info("JsApi下单成功,无返回值信息!");
|
||||
} else {
|
||||
//请求失败
|
||||
log.error("JsApi下单失败,失败原因为 ====> {}", result);
|
||||
throw new ServiceException("JsApi下单失败,失败原因为:" + result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("JsApi下单失败,失败原因 =====> {}", e.getMessage());
|
||||
throw new ServiceException("JsApi下单失败,请联系管理员!");
|
||||
} finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
return prepayId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建微信小程序调起支付参数设置
|
||||
*
|
||||
* @param prepayId jsapi下单返回参数信息
|
||||
* @return 参数信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
private WeChatAppletSignVO getSignInfo(String prepayId) throws Exception {
|
||||
String appId = appletChatConfig.getAppletId();
|
||||
//随机字符串
|
||||
String nonceStr = UUID.randomUUID().toString().replace("-", "");
|
||||
//时间戳
|
||||
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
//获取商户私钥
|
||||
PrivateKey privateKey = null;
|
||||
privateKey = weChatUtil.getPrivateKey(xylWeChatPaymentConfig.getXylPrivateKeyPath());
|
||||
if (privateKey == null) {
|
||||
throw new ServiceException("获取商户私钥失败,请联系管理员!");
|
||||
}
|
||||
//计算签名信息
|
||||
prepayId = "prepay_id=" + prepayId;
|
||||
String signatureStr = Stream.of(appId, timestamp, nonceStr, prepayId)
|
||||
.collect(Collectors.joining("\n", "", "\n"));
|
||||
log.info("计算签名认证信息 =====> {}", signatureStr);
|
||||
Signature sign = Signature.getInstance(SIGNATURE_ALGORITHM);
|
||||
sign.initSign(privateKey);
|
||||
sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
|
||||
String paySign = Base64Utils.encodeToString(sign.sign());
|
||||
return WeChatAppletSignVO.builder().appId(appId).timeStamp(timestamp).nonceStr(nonceStr).prepayId(prepayId)
|
||||
.signType(SIGN_TYPE).paySign(paySign).build();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,356 @@
|
||||
package com.yf.exam.modules.applet.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.yf.exam.config.WeChatPaymentUrlConfig;
|
||||
import com.yf.exam.config.XylWeChatPaymentConfig;
|
||||
import com.yf.exam.core.domain.AjaxResult;
|
||||
import com.yf.exam.core.enums.ConfirmRefundStatusEnum;
|
||||
import com.yf.exam.core.enums.RefundStatusEnum;
|
||||
import com.yf.exam.core.exception.ServiceException;
|
||||
import com.yf.exam.modules.applet.dto.RefundDTO;
|
||||
import com.yf.exam.modules.applet.service.WeChatRefundService;
|
||||
import com.yf.exam.modules.exam.entity.ExamRegistration;
|
||||
import com.yf.exam.modules.exam.mapper.ExamRegistrationMapper;
|
||||
import com.yf.exam.modules.payment.entity.RefundInfo;
|
||||
import com.yf.exam.modules.payment.mapper.RefundInfoMapper;
|
||||
import com.yf.exam.modules.payment.vo.WeChatRefundInfoVO;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @Description 微信退款业务层实现类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-24 15:23:16
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WeChatRefundServiceImpl implements WeChatRefundService {
|
||||
|
||||
@Resource
|
||||
private ExamRegistrationMapper examRegistrationMapper;
|
||||
@Resource
|
||||
private XylWeChatPaymentConfig xylWeChatPaymentConfig;
|
||||
@Resource(name = "xinYiLuWeChatPayClient")
|
||||
private CloseableHttpClient xinYiLuWeChatPayClient;
|
||||
@Resource
|
||||
private WeChatPaymentUrlConfig weChatPaymentUrlConfig;
|
||||
@Resource
|
||||
private RefundInfoMapper refundInfoMapper;
|
||||
/*@Resource
|
||||
private GoodsStockService goodsStockService;
|
||||
@Resource
|
||||
private PatientIntegralChangeMapper patientIntegralChangeMapper;
|
||||
@Resource
|
||||
private PatientInfoMapper patientInfoMapper;*/
|
||||
|
||||
|
||||
/**
|
||||
* 成功状态码
|
||||
*/
|
||||
private static final int HAVE_BODY_SUCCESS_CODE = 200;
|
||||
|
||||
/**
|
||||
* 成功状态码
|
||||
*/
|
||||
private static final int NO_HAVE_BODY_SUCCESS_CODE = 204;
|
||||
|
||||
/**
|
||||
* 新医路退款回调接口地址
|
||||
*/
|
||||
private static final String XINYILU_WE_CHAT_REFUND_URL = "/examApplet/weChatPayment/xylWeChatRefundNotify";
|
||||
|
||||
/**
|
||||
* 微信确认退款接口
|
||||
*
|
||||
* @param refundDTO 退款参数
|
||||
* @return 退款申请结果
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public AjaxResult weChatRefundOrderApply(RefundDTO refundDTO) throws Exception {
|
||||
//取消商品订单信息,修改本地订单状态并调用微信退款申请接口进行退款处理
|
||||
ExamRegistration examRegistration = examRegistrationMapper.selectById(refundDTO.getId());
|
||||
if (Objects.nonNull(examRegistration)) {
|
||||
AjaxResult ajaxResult = judgeRefundInfo(examRegistration.getOrderTime(), refundDTO.getRefundPrice(), examRegistration.getExamFee());
|
||||
if (Objects.nonNull(ajaxResult)) {
|
||||
return ajaxResult;
|
||||
}
|
||||
//判断订单状态是否确认退款
|
||||
if (StringUtils.isBlank(examRegistration.getConfirmRefundStatus())
|
||||
|| !(ConfirmRefundStatusEnum.NOT_CONFIRM.getInfo().equals(examRegistration.getConfirmRefundStatus()))) {
|
||||
return AjaxResult.error("当前商品订单未进行退款确认,请先进行确认!");
|
||||
}
|
||||
/*if (StringUtils.isBlank(examRegistration.getPaymentState())
|
||||
|| !GooodsOrderStatusEnum.WAIT_REFUND.getInfo().equals(examRegistration.getPaymentState())
|
||||
|| GooodsOrderStatusEnum.REFUNDED.getInfo().equals(examRegistration.getPaymentState())) {
|
||||
return AjaxResult.error("当前商品订单非退款中或者已退款,无法进行退款处理!");
|
||||
}*/
|
||||
//调用微信申请退款接口发起退款申请
|
||||
String userId = Objects.isNull(examRegistration.getUserId()) ? "" : examRegistration.getUserId();
|
||||
String outRefundNo = fillZeroByUserId(userId, 5) + System.nanoTime();
|
||||
String refundParam = buildRefundParam(examRegistration, refundDTO, outRefundNo);
|
||||
this.applyWeRefund(refundParam, examRegistration, userId, refundDTO);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 补0公共方法
|
||||
*
|
||||
* @param userId 考生id
|
||||
* @param length 指定长度
|
||||
* @return 部位长度
|
||||
*/
|
||||
private String fillZeroByUserId(String userId, int length) {
|
||||
if (StringUtils.length(userId) < length) {
|
||||
userId = String.format("%0" + length + "d", userId);
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用微信查询单笔退款接口查询预约订单状态信息
|
||||
*
|
||||
* @param refundNo 退款单号
|
||||
* @return 退款信息
|
||||
*/
|
||||
/*@Override
|
||||
public WeChatRefundInfoVO queryAppointmentOrderRefundStatus(String refundNo) {
|
||||
WeChatRefundInfoVO weChatRefundInfoVO = new WeChatRefundInfoVO();
|
||||
log.info("调用微信查询单笔退款订单接口查询预约订单信息,预约订单编号 ====> {}", refundNo);
|
||||
String requestUrl = String.format(weChatPaymentUrlConfig.getRefundQueryOrderUrl(), refundNo);
|
||||
HttpGet httpGet = new HttpGet(requestUrl);
|
||||
httpGet.setHeader("Accept", "application/json");
|
||||
try (CloseableHttpResponse response = xinYiLuWeChatPayClient.execute(httpGet)) {
|
||||
//请求体
|
||||
String body = EntityUtils.toString(response.getEntity());
|
||||
//请求状态
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode == HAVE_BODY_SUCCESS_CODE) {
|
||||
weChatRefundInfoVO = JSONObject.parseObject(body, WeChatRefundInfoVO.class);
|
||||
} else if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
|
||||
log.warn("请求微信查询单笔退款接口成功,无返回信息!");
|
||||
} else {
|
||||
throw new ServiceException("调用微信查询单笔退款接口异常,响应码为:" + statusCode + ", 查询退款返回结果 = " + body);
|
||||
}
|
||||
return weChatRefundInfoVO;
|
||||
} catch (Exception e) {
|
||||
log.error("请求微信查询单笔退款接口异常,异常信息为 ====> {}", e.getMessage());
|
||||
throw new ServiceException("查询预约订单状态失败,请联系管理员!");
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* 调用微信查询单笔退款接口查询商品订单状态信息
|
||||
*
|
||||
* @param refundNo 退单编号
|
||||
* @param buySource 购买来源
|
||||
* @return 退款信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
/*@Override
|
||||
public WeChatRefundInfoVO queryGoodsOrderRefundStatus(String refundNo, String buySource) throws Exception {
|
||||
WeChatRefundInfoVO weChatRefundInfoVO = new WeChatRefundInfoVO();
|
||||
log.info("调用微信查询单笔退款订单接口查询商品订单信息,商品订单编号 ====> {}", refundNo);
|
||||
String requestUrl = String.format(weChatPaymentUrlConfig.getRefundQueryOrderUrl(), refundNo);
|
||||
HttpGet httpGet = new HttpGet(requestUrl);
|
||||
httpGet.setHeader("Accept", "application/json");
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
if (BuySourceEnum.NURSE_STATION.getInfo().equals(buySource)) {
|
||||
response = xinYiLuWeChatPayClient.execute(httpGet);
|
||||
}
|
||||
if (BuySourceEnum.SHOPPING_MALL.getInfo().equals(buySource)
|
||||
|| BuySourceEnum.HEALTH_CONSULTATION.getInfo().equals(buySource) || BuySourceEnum.TRAINING.getInfo().equals(buySource)) {
|
||||
response = yiLuYouPinWeChatPayClient.execute(httpGet);
|
||||
}
|
||||
if (response == null) {
|
||||
throw new ServiceException("获取微信HttpClient对象失败,请联系管理员!");
|
||||
}
|
||||
//响应体
|
||||
String body = EntityUtils.toString(response.getEntity());
|
||||
//响应状态码
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode == HAVE_BODY_SUCCESS_CODE) {
|
||||
weChatRefundInfoVO = JSONObject.parseObject(body, WeChatRefundInfoVO.class);
|
||||
} else if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
|
||||
log.warn("请求微信查询单笔退款接口成功,无返回信息!");
|
||||
} else {
|
||||
throw new ServiceException("调用微信查询单笔退款接口异常,响应码为:" + statusCode + ", 查询退款返回结果 = " + body);
|
||||
}
|
||||
return weChatRefundInfoVO;
|
||||
} catch (Exception e) {
|
||||
log.error("请求微信查询单笔退款接口,异常信息为 ====> {}", e.getMessage());
|
||||
throw new ServiceException("查询商品订单状态失败,请联系管理员!");
|
||||
} finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* 退款参数检验
|
||||
*
|
||||
* @param orderTime 下单时间
|
||||
* @param refundPrice 退款金额
|
||||
* @param totalPrice 支付总金额
|
||||
* @return 返回结果信息
|
||||
*/
|
||||
private AjaxResult judgeRefundInfo(LocalDateTime orderTime, BigDecimal refundPrice, BigDecimal totalPrice) {
|
||||
/*LocalDateTime localDateTime = orderTime.plusYears(1);
|
||||
if (LocalDateTime.now().isAfter(localDateTime)) {
|
||||
return AjaxResult.error("当前订单超过一年,无法进行退款处理!");
|
||||
}*/
|
||||
if (refundPrice.compareTo(totalPrice) > 0) {
|
||||
return AjaxResult.error("当前退款金额大于订单支付金额,无法进行退款处理!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建微信退款参数信息
|
||||
*
|
||||
* @param examRegistration 商品订单信息
|
||||
* @param refundDTO 退款参数信息
|
||||
* @return 退款申请Json串
|
||||
*/
|
||||
private String buildRefundParam(ExamRegistration examRegistration, RefundDTO refundDTO, String outRefundNo) {
|
||||
Map<String, Object> paramMap = new LinkedHashMap<>();
|
||||
//订单编号
|
||||
paramMap.put("out_trade_no", refundDTO.getId());
|
||||
//商户退款单号
|
||||
paramMap.put("out_refund_no", outRefundNo);
|
||||
//退款金额参数
|
||||
Map<String, Object> amountMap = new LinkedHashMap<>();
|
||||
//回调通知地址和退款金额,预约订单使用新医路账户
|
||||
if (Objects.nonNull(examRegistration)) {
|
||||
//退款金额
|
||||
amountMap.put("refund", refundDTO.getRefundPrice().multiply(BigDecimal.valueOf(100)).intValue());
|
||||
//原始订单金额
|
||||
amountMap.put("total", examRegistration.getExamFee().multiply(BigDecimal.valueOf(100)).intValue());
|
||||
}
|
||||
|
||||
//退款回调地址
|
||||
paramMap.put("notify_url", xylWeChatPaymentConfig.getXylWeChatNotifyUrl() + XINYILU_WE_CHAT_REFUND_URL);
|
||||
|
||||
//货币类型
|
||||
amountMap.put("currency", "CNY");
|
||||
paramMap.put("amount", amountMap);
|
||||
return JSON.toJSONString(paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起退款申请
|
||||
*
|
||||
* @param refundParam 请求参数
|
||||
* @param goodsOrderInfo 商品订单信息
|
||||
* @param userId 考生id
|
||||
* @param refundDTO 申请信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
public void applyWeRefund(String refundParam,ExamRegistration goodsOrderInfo,
|
||||
String userId, RefundDTO refundDTO) throws Exception {
|
||||
log.info("申请退款请求参数 ===> {}", refundParam);
|
||||
String requestUrl = weChatPaymentUrlConfig.getRefundApplyUrl();
|
||||
HttpPost httpPost = new HttpPost(requestUrl);
|
||||
StringEntity entity = new StringEntity(refundParam, "utf-8");
|
||||
entity.setContentType("application/json");
|
||||
httpPost.setEntity(entity);
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
CloseableHttpResponse response = null;
|
||||
String refundMerchantType = "";
|
||||
try {
|
||||
response = xinYiLuWeChatPayClient.execute(httpPost);
|
||||
refundMerchantType = "WEISHENGXUEHUI";
|
||||
|
||||
if (Objects.isNull(response)) {
|
||||
throw new ServiceException("获取httpclient对象失败!");
|
||||
}
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
String body = EntityUtils.toString(response.getEntity());
|
||||
if (statusCode != HAVE_BODY_SUCCESS_CODE && statusCode != NO_HAVE_BODY_SUCCESS_CODE) {
|
||||
throw new ServiceException("微信申请退款异常, 响应码:" + statusCode + ", 退款返回结果:" + body);
|
||||
}
|
||||
//将商品订单状态修改为已确认
|
||||
/*if (Objects.nonNull(goodsOrderInfo)) {
|
||||
examRegistrationMapper.updateGoodsConfirmRefundStatus(goodsOrderInfo.getOrderNo(), ConfirmRefundStatusEnum.CONFIRMED.getInfo());
|
||||
}*/
|
||||
WeChatRefundInfoVO weChatRefundInfoVO = JSONObject.parseObject(body, WeChatRefundInfoVO.class);
|
||||
//记录支付日志
|
||||
int refundInfoCount = refundInfoMapper.getRefundInfoByexamRegistrationId(weChatRefundInfoVO.getOutTradeNo());
|
||||
if (refundInfoCount <= 0) {
|
||||
RefundInfo refundInfo = buildRefundInfo(userId, weChatRefundInfoVO, refundDTO, body, refundMerchantType);
|
||||
int insertCunt = refundInfoMapper.insertRefundInfo(refundInfo);
|
||||
if (insertCunt <= 0) {
|
||||
throw new ServiceException("记录退款信息失败,请联系管理员!");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("微信申请退款接口出错,原因:{}", e.getMessage());
|
||||
} finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建微信退款信息
|
||||
*
|
||||
* @param userId 会员id
|
||||
* @param refundInfoVO 退款信息参数
|
||||
* @param refundDTO 退款申请参数
|
||||
* @param refundBody 返回体
|
||||
* @param refundMerchantType 退款账户类型,新医路或者医路优品
|
||||
*/
|
||||
private RefundInfo buildRefundInfo(String userId, WeChatRefundInfoVO refundInfoVO,
|
||||
RefundDTO refundDTO, String refundBody, String refundMerchantType) {
|
||||
RefundInfo refundInfo = new RefundInfo();
|
||||
refundInfo.setUserId(userId);
|
||||
refundInfo.setExamRegistrationId(refundInfoVO.getOutTradeNo());
|
||||
refundInfo.setRefundNo(refundInfoVO.getRefundId());
|
||||
refundInfo.setOutRefundNo(refundInfoVO.getOutRefundNo());
|
||||
refundInfo.setTransactionNo(StringUtils.isBlank(refundInfoVO.getTransactionId()) ? "" : refundInfoVO.getTransactionId());
|
||||
refundInfo.setRefundReason(StringUtils.isBlank(refundDTO.getRefundReason()) ? "" : refundDTO.getRefundReason());
|
||||
refundInfo.setRefundType("WE_CHAT");
|
||||
refundInfo.setWechatRefundStatus(RefundStatusEnum.PROCESSING.getInfo());
|
||||
refundInfo.setOrderTotalPrice(BigDecimal.valueOf(refundInfoVO.getAmount().getTotal()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN));
|
||||
refundInfo.setRefundPrice(BigDecimal.valueOf(refundInfoVO.getAmount().getRefund()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN));
|
||||
refundInfo.setCurrency(refundInfoVO.getAmount().getCurrency());
|
||||
refundInfo.setChannel(refundInfoVO.getChannel());
|
||||
refundInfo.setUserreceivedaccount(refundInfoVO.getUserReceivedAccount());
|
||||
refundInfo.setSuccessTime(StringUtils.isBlank(refundInfoVO.getSuccessTime()) ? null : LocalDateTime.parse(refundInfoVO.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME));
|
||||
refundInfo.setApplyRefundReturnContent(refundBody);
|
||||
refundInfo.setRefundMerchantType(refundMerchantType);
|
||||
refundInfo.setDelFlag(0);
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
try {
|
||||
refundInfo.setCreateTime(formatter.parse(refundInfoVO.getCreateTime()));
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return refundInfo;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.yf.exam.modules.applet.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description 订单状态返回值实体类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-21 10:47:20
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class OrderStatusInfoVO implements Serializable {
|
||||
private static final long serialVersionUID = -8522003863208703215L;
|
||||
/**
|
||||
* 支付标识,true:可以支付,false:不可支付
|
||||
*/
|
||||
private Boolean payFlag;
|
||||
|
||||
/**
|
||||
* 微信订单状态,具体值参考TradeStatusEnum枚举
|
||||
*/
|
||||
private String tradeStatus;
|
||||
|
||||
/**
|
||||
* 微信查单接口返回参数信息
|
||||
*/
|
||||
WeChatQueryOrderVO weChatQueryOrderVO;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.yf.exam.modules.payment.vo;
|
||||
package com.yf.exam.modules.applet.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Builder;
|
||||
@ -0,0 +1,277 @@
|
||||
package com.yf.exam.modules.applet.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @Description 微信支付回调通知明文参数实体类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-20 14:08:07
|
||||
* @Version 1.0
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class WeChatPayNotifyPlaintextVO implements Serializable {
|
||||
private static final long serialVersionUID = -3950813376227389879L;
|
||||
|
||||
/**
|
||||
* 流水号
|
||||
*/
|
||||
@JsonProperty("transaction_id")
|
||||
private String transactionId;
|
||||
|
||||
/**
|
||||
* 金额信息
|
||||
*/
|
||||
@JsonProperty("amount")
|
||||
private AmountDTO amount;
|
||||
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
@JsonProperty("mchid")
|
||||
private String mchid;
|
||||
|
||||
/**
|
||||
* 交易状态,枚举值:
|
||||
* SUCCESS:支付成功
|
||||
* REFUND:转入退款
|
||||
* NOTPAY:未支付
|
||||
* CLOSED:已关闭
|
||||
* REVOKED:已撤销(付款码支付)
|
||||
* USERPAYING:用户支付中(付款码支付)
|
||||
* PAYERROR:支付失败(其他原因,如银行返回失败)
|
||||
*/
|
||||
@JsonProperty("trade_state")
|
||||
private String tradeState;
|
||||
|
||||
/**
|
||||
* 付款银行
|
||||
*/
|
||||
@JsonProperty("bank_type")
|
||||
private String bankType;
|
||||
|
||||
/**
|
||||
* 优惠功能
|
||||
*/
|
||||
@JsonProperty("promotion_detail")
|
||||
private List<PromotionDetailDTO> promotionDetail;
|
||||
|
||||
/**
|
||||
* 支付完成时间
|
||||
*/
|
||||
@JsonProperty("success_time")
|
||||
private String successTime;
|
||||
|
||||
/**
|
||||
* 支付者
|
||||
*/
|
||||
@JsonProperty("payer")
|
||||
private PayerDTO payer;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
@JsonProperty("out_trade_no")
|
||||
private String outTradeNo;
|
||||
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
@JsonProperty("appid")
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 交易状态描述
|
||||
*/
|
||||
@JsonProperty("trade_state_desc")
|
||||
private String tradeStateDesc;
|
||||
|
||||
/**
|
||||
* 交易类型,枚举值:
|
||||
* JSAPI:公众号支付
|
||||
* NATIVE:扫码支付
|
||||
* APP:APP支付
|
||||
* MICROPAY:付款码支付
|
||||
* MWEB:H5支付
|
||||
* FACEPAY:刷脸支付
|
||||
*/
|
||||
@JsonProperty("trade_type")
|
||||
private String tradeType;
|
||||
|
||||
/**
|
||||
* 附加数据
|
||||
*/
|
||||
@JsonProperty("attach")
|
||||
private String attach;
|
||||
|
||||
/**
|
||||
* 场景信息
|
||||
*/
|
||||
@JsonProperty("scene_info")
|
||||
private SceneInfoDTO sceneInfo;
|
||||
|
||||
/**
|
||||
* 订单金额
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class AmountDTO {
|
||||
/**
|
||||
* 用户支付金额
|
||||
*/
|
||||
@JsonProperty("payer_total")
|
||||
private Integer payerTotal;
|
||||
|
||||
/**
|
||||
* 总金额
|
||||
*/
|
||||
@JsonProperty("total")
|
||||
private Integer total;
|
||||
|
||||
/**
|
||||
* 货币类型
|
||||
*/
|
||||
@JsonProperty("currency")
|
||||
private String currency;
|
||||
|
||||
/**
|
||||
* 用户支付币种
|
||||
*/
|
||||
@JsonProperty("payer_currency")
|
||||
private String payerCurrency;
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付者
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class PayerDTO {
|
||||
/**
|
||||
* 用户标识
|
||||
*/
|
||||
@JsonProperty("openid")
|
||||
private String openid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景信息
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class SceneInfoDTO {
|
||||
/**
|
||||
* 商户端设备号
|
||||
*/
|
||||
@JsonProperty("device_id")
|
||||
private String deviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 优惠功能
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class PromotionDetailDTO {
|
||||
/**
|
||||
* 优惠券面额
|
||||
*/
|
||||
@JsonProperty("amount")
|
||||
private Integer amount;
|
||||
|
||||
/**
|
||||
* 微信出资
|
||||
*/
|
||||
@JsonProperty("wechatpay_contribute")
|
||||
private Integer wechatpayContribute;
|
||||
|
||||
/**
|
||||
* 券ID
|
||||
*/
|
||||
@JsonProperty("coupon_id")
|
||||
private String couponId;
|
||||
|
||||
/**
|
||||
* 优惠范围
|
||||
*/
|
||||
@JsonProperty("scope")
|
||||
private String scope;
|
||||
|
||||
/**
|
||||
* 商户出资
|
||||
*/
|
||||
@JsonProperty("merchant_contribute")
|
||||
private Integer merchantContribute;
|
||||
|
||||
/**
|
||||
* 优惠名称
|
||||
*/
|
||||
@JsonProperty("name")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 其他出资
|
||||
*/
|
||||
@JsonProperty("other_contribute")
|
||||
private Integer otherContribute;
|
||||
|
||||
/**
|
||||
* 优惠币种
|
||||
*/
|
||||
@JsonProperty("currency")
|
||||
private String currency;
|
||||
|
||||
/**
|
||||
* 活动ID
|
||||
*/
|
||||
@JsonProperty("stock_id")
|
||||
private String stockId;
|
||||
|
||||
/**
|
||||
* 单品列表
|
||||
*/
|
||||
@JsonProperty("goods_detail")
|
||||
private List<GoodsDetailDTO> goodsDetail;
|
||||
|
||||
/**
|
||||
* 单品列表
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class GoodsDetailDTO {
|
||||
/**
|
||||
* 商品备注
|
||||
*/
|
||||
@JsonProperty("goods_remark")
|
||||
private String goodsRemark;
|
||||
|
||||
/**
|
||||
* 商品数量
|
||||
*/
|
||||
@JsonProperty("quantity")
|
||||
private Integer quantity;
|
||||
|
||||
/**
|
||||
* 商品优惠金额
|
||||
*/
|
||||
@JsonProperty("discount_amount")
|
||||
private Integer discountAmount;
|
||||
|
||||
/**
|
||||
* 商品编码
|
||||
*/
|
||||
@JsonProperty("goods_id")
|
||||
private String goodsId;
|
||||
|
||||
/**
|
||||
* 商品单价
|
||||
*/
|
||||
@JsonProperty("unit_price")
|
||||
private Integer unitPrice;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,138 @@
|
||||
package com.yf.exam.modules.applet.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @Description 微信查单接口返回值实体类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-21 11:26:12
|
||||
* @Version 1.0
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class WeChatQueryOrderVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8467953500266751257L;
|
||||
/**
|
||||
* 返回金额信息
|
||||
*/
|
||||
@JsonProperty("amount")
|
||||
private AmountDTO amount;
|
||||
|
||||
/**
|
||||
* 应用id
|
||||
*/
|
||||
@JsonProperty("appid")
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 附加数据信息
|
||||
*/
|
||||
@JsonProperty("attach")
|
||||
private String attach;
|
||||
|
||||
/**
|
||||
* 银行类型
|
||||
*/
|
||||
@JsonProperty("bank_type")
|
||||
private String bankType;
|
||||
|
||||
/**
|
||||
* 商户id
|
||||
*/
|
||||
@JsonProperty("mchid")
|
||||
private String mchid;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
@JsonProperty("out_trade_no")
|
||||
private String outTradeNo;
|
||||
|
||||
/**
|
||||
* 支付者信息
|
||||
*/
|
||||
@JsonProperty("payer")
|
||||
private PayerDTO payer;
|
||||
|
||||
/**
|
||||
* 详情信息
|
||||
*/
|
||||
@JsonProperty("promotion_detail")
|
||||
private List<?> promotionDetail;
|
||||
|
||||
/**
|
||||
* 成功时间
|
||||
*/
|
||||
@JsonProperty("success_time")
|
||||
private String successTime;
|
||||
|
||||
/**
|
||||
* 交易状态
|
||||
*/
|
||||
@JsonProperty("trade_state")
|
||||
private String tradeState;
|
||||
|
||||
/**
|
||||
* 交易状态描述
|
||||
*/
|
||||
@JsonProperty("trade_state_desc")
|
||||
private String tradeStateDesc;
|
||||
|
||||
/**
|
||||
* 交易类型
|
||||
*/
|
||||
@JsonProperty("trade_type")
|
||||
private String tradeType;
|
||||
|
||||
/**
|
||||
* 微信平台订单id
|
||||
*/
|
||||
@JsonProperty("transaction_id")
|
||||
private String transactionId;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class AmountDTO {
|
||||
/**
|
||||
* 货币类型
|
||||
*/
|
||||
@JsonProperty("currency")
|
||||
private String currency;
|
||||
|
||||
/**
|
||||
* 支付货币类型
|
||||
*/
|
||||
@JsonProperty("payer_currency")
|
||||
private String payerCurrency;
|
||||
|
||||
/**
|
||||
* 支付金额
|
||||
*/
|
||||
@JsonProperty("payer_total")
|
||||
private Integer payerTotal;
|
||||
|
||||
/**
|
||||
* 总金额
|
||||
*/
|
||||
@JsonProperty("total")
|
||||
private Integer total;
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付者信息
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class PayerDTO {
|
||||
/**
|
||||
* 微信唯一标识
|
||||
*/
|
||||
@JsonProperty("openid")
|
||||
private String openid;
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,6 @@ import com.yf.exam.core.api.dto.BaseIdsReqDTO;
|
||||
import com.yf.exam.core.api.dto.BaseStateReqDTO;
|
||||
import com.yf.exam.core.api.dto.PagingReqDTO;
|
||||
import com.yf.exam.modules.exam.dto.ExamDTO;
|
||||
import com.yf.exam.modules.exam.dto.request.ExamSearchDTO;
|
||||
import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO;
|
||||
import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO;
|
||||
import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO;
|
||||
@ -18,7 +17,6 @@ import com.yf.exam.modules.exam.service.ExamService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -148,17 +146,7 @@ public class ExamController extends BaseController {
|
||||
return super.success(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询可考试列表
|
||||
* @param reqDTO
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "查询可考试列表")
|
||||
@RequestMapping(value = "/getExamList", method = { RequestMethod.GET})
|
||||
public ApiRest getExamList(ExamSearchDTO reqDTO) {
|
||||
List<ExamDTO> list = baseService.getExamList(reqDTO);
|
||||
return super.success(list);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ public class ExamRegistrationController extends BaseController {
|
||||
public ApiRest save(@RequestBody ExamRegistrationDTO reqDTO) {
|
||||
//复制参数
|
||||
baseService.save(reqDTO);
|
||||
return super.success();
|
||||
return super.success(reqDTO.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -5,6 +5,7 @@ import com.yf.exam.modules.exam.entity.UserAttachment;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
@ -84,10 +85,10 @@ public class ExamRegistrationDTO extends UserAttachment implements Serializable
|
||||
private Integer finishState;
|
||||
|
||||
/**
|
||||
* 交费状态(0:未交费,1:已交费)
|
||||
* 交费状态,待付款:WAIT_PAY,已付款:PAY,已取消:CANCEL,待收货:WAIT_RECEIVED_GOODS,已收货:RECEIVED_GOODS,退款中:WAIT_REFUND,已退款:REFUNDED,待退货:WAIT_RETURNED_GOODS,已退货:RETURNED_GOODS
|
||||
*/
|
||||
@ApiModelProperty(value = "交费状态(0:未交费,1:已交费)", required=true)
|
||||
private Integer paymentState;
|
||||
@ApiModelProperty(value = "交费状态,待付款:WAIT_PAY,已付款:PAY,已取消:CANCEL,待收货:WAIT_RECEIVED_GOODS,已收货:RECEIVED_GOODS,退款中:WAIT_REFUND,已退款:REFUNDED,待退货:WAIT_RETURNED_GOODS,已退货:RETURNED_GOODS", required=true)
|
||||
private String paymentState;
|
||||
|
||||
/**
|
||||
* 考试类型(1:模拟考试,2:正式考试,3:补考)
|
||||
@ -95,6 +96,11 @@ public class ExamRegistrationDTO extends UserAttachment implements Serializable
|
||||
@ApiModelProperty(value = "考试类型(1:模拟考试,2:正式考试,3:补考)", required=true)
|
||||
private Integer examType;
|
||||
|
||||
/**
|
||||
* 考试费用
|
||||
*/
|
||||
private BigDecimal examFee;
|
||||
|
||||
/**
|
||||
* 交费开始时间
|
||||
* */
|
||||
|
||||
@ -54,10 +54,10 @@ public class ExamRegistrationVO {
|
||||
private Integer finishState;
|
||||
|
||||
/**
|
||||
* 交费状态(0:未交费,1:已交费)
|
||||
* 交费状态,待付款:WAIT_PAY,已付款:PAY,已取消:CANCEL,待收货:WAIT_RECEIVED_GOODS,已收货:RECEIVED_GOODS,退款中:WAIT_REFUND,已退款:REFUNDED,待退货:WAIT_RETURNED_GOODS,已退货:RETURNED_GOODS
|
||||
*/
|
||||
@ApiModelProperty(value = "交费状态(0:未交费,1:已交费)", required=true)
|
||||
private Integer paymentState;
|
||||
@ApiModelProperty(value = "交费状态,待付款:WAIT_PAY,已付款:PAY,已取消:CANCEL,待收货:WAIT_RECEIVED_GOODS,已收货:RECEIVED_GOODS,退款中:WAIT_REFUND,已退款:REFUNDED,待退货:WAIT_RETURNED_GOODS,已退货:RETURNED_GOODS", required=true)
|
||||
private String paymentState;
|
||||
|
||||
@ApiModelProperty(value = "考试主键", required=true)
|
||||
private String examId;
|
||||
|
||||
@ -4,7 +4,11 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
@ -76,15 +80,32 @@ public class ExamRegistration extends UserAttachment {
|
||||
private Integer finishState;
|
||||
|
||||
/**
|
||||
* 交费状态(0:未交费,1:已交费)
|
||||
* 考试费用
|
||||
*/
|
||||
private Integer paymentState;
|
||||
private BigDecimal examFee;
|
||||
|
||||
/**
|
||||
* 交费状态,待付款:WAIT_PAY,已付款:PAY,已取消:CANCEL,待收货:WAIT_RECEIVED_GOODS,已收货:RECEIVED_GOODS,退款中:WAIT_REFUND,已退款:REFUNDED,待退货:WAIT_RETURNED_GOODS,已退货:RETURNED_GOODS
|
||||
*/
|
||||
private String paymentState;
|
||||
|
||||
/**
|
||||
* 交费时间
|
||||
*/
|
||||
private Date paymentDate;
|
||||
|
||||
/**
|
||||
* 下单时间
|
||||
*/
|
||||
@ApiModelProperty(value = "下单时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime orderTime;
|
||||
|
||||
/**
|
||||
* 确认退款状态,未确认:NOT_CONFIRM,已确认:CONFIRMED
|
||||
*/
|
||||
private String confirmRefundStatus;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
|
||||
@ -24,4 +24,6 @@ public interface ExamRegistrationMapper extends BaseMapper<ExamRegistration> {
|
||||
void updateFinishState(ExamRegistration examRegistration);
|
||||
|
||||
IPage<ExamRegistrationVO> getRegUserList(Page page, @Param("query") ExamRegistrationDTO examRegistrationDTO);
|
||||
|
||||
int updatePaymentStateById(String paymentState, String id);
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ public interface ExamRegistrationService extends IService<ExamRegistration> {
|
||||
* 保存报名信息
|
||||
* @param reqDTO
|
||||
*/
|
||||
void save(ExamRegistrationDTO reqDTO);
|
||||
String save(ExamRegistrationDTO reqDTO);
|
||||
|
||||
/**
|
||||
* @description 查询已报名的考试列表
|
||||
|
||||
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.yf.exam.core.api.dto.PagingReqDTO;
|
||||
import com.yf.exam.core.enums.GooodsOrderStatusEnum;
|
||||
import com.yf.exam.core.exception.ServiceException;
|
||||
import com.yf.exam.modules.exam.dto.ExamRegistrationDTO;
|
||||
import com.yf.exam.modules.exam.dto.response.ExamRegistrationVO;
|
||||
@ -27,7 +28,7 @@ import org.springframework.stereotype.Service;
|
||||
public class ExamRegistrationServiceImpl extends ServiceImpl<ExamRegistrationMapper, ExamRegistration> implements ExamRegistrationService {
|
||||
|
||||
@Override
|
||||
public void save(ExamRegistrationDTO reqDTO) {
|
||||
public String save(ExamRegistrationDTO reqDTO) {
|
||||
if (StringUtils.isBlank(reqDTO.getUserId())) {
|
||||
throw new ServiceException("传输数据错误,请重新报名");
|
||||
}
|
||||
@ -38,6 +39,7 @@ public class ExamRegistrationServiceImpl extends ServiceImpl<ExamRegistrationMap
|
||||
ExamRegistrationDTO examRegistrationDTO = new ExamRegistrationDTO();
|
||||
examRegistrationDTO.setExamId(reqDTO.getExamId());
|
||||
examRegistrationDTO.setUserId(reqDTO.getUserId());
|
||||
examRegistrationDTO.setPaymentState(GooodsOrderStatusEnum.PAY.getInfo());
|
||||
List<ExamRegistrationVO> list = getRegExamList(examRegistrationDTO);
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
throw new ServiceException("您已报名过该考试,请勿重复报名");
|
||||
@ -55,8 +57,10 @@ public class ExamRegistrationServiceImpl extends ServiceImpl<ExamRegistrationMap
|
||||
// 复制基本数据
|
||||
BeanUtils.copyProperties(reqDTO, entity);
|
||||
entity.setId(id);
|
||||
entity.setPaymentState(GooodsOrderStatusEnum.WAIT_PAY.getInfo());
|
||||
entity.setFinishState(ExamFinishState.UNFINISH);
|
||||
this.saveOrUpdate(entity);
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
package com.yf.exam.modules.payment.controller;
|
||||
|
||||
import com.yf.exam.core.api.controller.BaseController;
|
||||
import com.yf.exam.core.domain.AjaxResult;
|
||||
import com.yf.exam.modules.payment.entity.PaymentInfo;
|
||||
import com.yf.exam.modules.payment.service.IPaymentInfoService;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 支付记录信息Controller
|
||||
*
|
||||
* @author xinyilu
|
||||
* @date 2022-10-18
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("exam/api/paymentInfo")
|
||||
public class PaymentInfoController extends BaseController {
|
||||
@Resource
|
||||
private IPaymentInfoService paymentInfoService;
|
||||
|
||||
/**
|
||||
* 查询支付记录信息列表
|
||||
*/
|
||||
/*@GetMapping("/list")
|
||||
public TableDataInfo list(PaymentInfo paymentInfo) {
|
||||
startPage();
|
||||
List<PaymentInfo> list = paymentInfoService.selectPaymentInfoList(paymentInfo);
|
||||
return getDataTable(list);
|
||||
}*/
|
||||
|
||||
/**
|
||||
* 获取支付记录信息详细信息
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||
return AjaxResult.success(paymentInfoService.selectPaymentInfoById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增支付记录信息
|
||||
*/
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody PaymentInfo paymentInfo) {
|
||||
return toAjax(paymentInfoService.insertPaymentInfo(paymentInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改支付记录信息
|
||||
*/
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody PaymentInfo paymentInfo) {
|
||||
return toAjax(paymentInfoService.updatePaymentInfo(paymentInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除支付记录信息
|
||||
*/
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(paymentInfoService.deletePaymentInfoByIds(ids));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,156 @@
|
||||
package com.yf.exam.modules.payment.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
/**
|
||||
* 支付记录信息对象 payment_info
|
||||
*
|
||||
* @author xinyilu
|
||||
* @date 2022-10-18
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@ApiModel(value = "支付记录信息对象", description = "payment_info")
|
||||
public class PaymentInfo extends Model<PaymentInfo> {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 考生id
|
||||
*/
|
||||
@ApiModelProperty(value = "考生id")
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 考试报名表主键,系统自动生成
|
||||
*/
|
||||
@ApiModelProperty(value = "考试报名表主键,系统自动生成")
|
||||
private String examRegistrationId;
|
||||
|
||||
/**
|
||||
* 支付标题
|
||||
*/
|
||||
@ApiModelProperty(value = "支付标题")
|
||||
private String paymentTitle;
|
||||
|
||||
/**
|
||||
* 交易流水号
|
||||
*/
|
||||
@ApiModelProperty(value = "交易流水号")
|
||||
private String transactionNo;
|
||||
|
||||
/**
|
||||
* 支付金额(分)
|
||||
*/
|
||||
@ApiModelProperty(value = "支付金额")
|
||||
private BigDecimal payPrice;
|
||||
|
||||
/**
|
||||
* 支付类型,微信支付:WECHAT_PAY,支付宝支付:ALI_PAY
|
||||
*/
|
||||
@ApiModelProperty(value = "支付类型,微信支付:WECHAT_PAY,支付宝支付:ALI_PAY")
|
||||
private String payType;
|
||||
|
||||
/**
|
||||
* 支付渠道,手机App:MOBILE_APP,微信小程序:WECHAT_APPLET,支付宝小程序:ALI_PAY_APPLET
|
||||
*/
|
||||
@ApiModelProperty(value = "支付渠道,手机App:MOBILE_APP,微信小程序:WECHAT_APPLET,支付宝小程序:ALI_PAY_APPLET")
|
||||
private String payChannel;
|
||||
|
||||
/**
|
||||
* 微信支付交易状态,支付成功:SUCCESS,转入退款:REFUND,未支付:NOTPAY,已关闭:CLOSED,已撤销(付款码支付):REVOKED,用户支付中(付款码支付):USERPAYING,支付失败(其他原因,如银行返回失败):PAYERROR
|
||||
*/
|
||||
@ApiModelProperty(value = "微信支付交易状态,支付成功:SUCCESS,转入退款:REFUND,未支付:NOTPAY,已关闭:CLOSED,已撤销")
|
||||
private String wechatTradeState;
|
||||
|
||||
/**
|
||||
* 支付宝交易状态,支付成功:SUCCESS,转入退款:REFUND,未支付:NOTPAY,已关闭:CLOSED,已撤销(付款码支付):REVOKED,用户支付中(付款码支付):USERPAYING,支付失败(其他原因,如银行返回失败):PAYERROR
|
||||
*/
|
||||
@ApiModelProperty(value = "支付宝交易状态,支付成功:SUCCESS,转入退款:REFUND,未支付:NOTPAY,已关闭:CLOSED,已撤销")
|
||||
private String alipayTradeState;
|
||||
|
||||
/**
|
||||
* 支付通知参数内容,微信或者支付宝支付回调通知信息
|
||||
*/
|
||||
@ApiModelProperty(value = "支付通知参数内容,微信或者支付宝支付回调通知信息")
|
||||
private String payNotifyContent;
|
||||
|
||||
/**
|
||||
* 支付时间
|
||||
*/
|
||||
@ApiModelProperty(value = "支付时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime payTime;
|
||||
|
||||
/**
|
||||
* 支付账户类型,新医路账户:XINYILU,医路优品:YILUYOUPIN
|
||||
*/
|
||||
@ApiModelProperty(value = "支付账户类型,新医路账户:XINYILU,医路优品:YILUYOUPIN")
|
||||
private String paymentMerchantType;
|
||||
|
||||
/**
|
||||
* 是否删除,0:否,1:是
|
||||
*/
|
||||
private Integer delFlag;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("id", getId())
|
||||
.append("userId", getUserId())
|
||||
.append("examRegistrationId", getExamRegistrationId())
|
||||
.append("paymentTitle", getPaymentTitle())
|
||||
.append("transactionNo", getTransactionNo())
|
||||
.append("payPrice", getPayPrice())
|
||||
.append("payType", getPayType())
|
||||
.append("payChannel", getPayChannel())
|
||||
.append("wechatTradeState", getWechatTradeState())
|
||||
.append("alipayTradeState", getAlipayTradeState())
|
||||
.append("payNotifyContent", getPayNotifyContent())
|
||||
.append("payTime", getPayTime())
|
||||
.append("paymentMerchantType", getPaymentMerchantType())
|
||||
.append("delFlag", getDelFlag())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("createTime", getCreateTime())
|
||||
.append("updateBy", getUpdateBy())
|
||||
.append("updateTime", getUpdateTime())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,199 @@
|
||||
package com.yf.exam.modules.payment.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
/**
|
||||
* 退款记录信息对象 refund_info
|
||||
*
|
||||
* @author xinyilu
|
||||
* @date 2022-10-18
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@ApiModel(value = "退款记录信息对象", description = "refund_info")
|
||||
public class RefundInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3202049270867033957L;
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 会员id
|
||||
*/
|
||||
@ApiModelProperty(value = "会员id")
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 商品订单号
|
||||
*/
|
||||
@ApiModelProperty(value = "商品订单号")
|
||||
private String examRegistrationId;
|
||||
|
||||
/**
|
||||
* 支付退款单号,多种支付方式共用
|
||||
*/
|
||||
@ApiModelProperty(value = "支付退款单号,多种支付方式共用")
|
||||
private String refundNo;
|
||||
|
||||
/**
|
||||
* 商户退款单号,系统自动生成
|
||||
*/
|
||||
@ApiModelProperty(value = "商户退款单号,系统自动生成")
|
||||
private String outRefundNo;
|
||||
|
||||
/**
|
||||
* 支付交易订单号,多种支付方式共用
|
||||
*/
|
||||
@ApiModelProperty(value = "支付交易订单号,多种支付方式共用")
|
||||
private String transactionNo;
|
||||
|
||||
/**
|
||||
* 退款原因
|
||||
*/
|
||||
@ApiModelProperty(value = "退款原因")
|
||||
private String refundReason;
|
||||
|
||||
/**
|
||||
* 退款方式,微信:WE_CHAT,支付宝:ALI_PAY
|
||||
*/
|
||||
@ApiModelProperty(value = "退款方式,微信:WE_CHAT,支付宝:ALI_PAY")
|
||||
private String refundType;
|
||||
|
||||
/**
|
||||
* 微信退款状态,退款成功:SUCCESS,退款关闭:CLOSED,退款处理中:PROCESSING,退款异常:ABNORMAL
|
||||
*/
|
||||
@ApiModelProperty(value = "微信退款状态,退款成功:SUCCESS,退款关闭:CLOSED,退款处理中:PROCESSING,退款异常:ABNORMAL")
|
||||
private String wechatRefundStatus;
|
||||
|
||||
/**
|
||||
* 支付宝退款状态,退款成功:SUCCESS,退款关闭:CLOSED,退款处理中:PROCESSING,退款异常:ABNORMAL
|
||||
*/
|
||||
@ApiModelProperty(value = "支付宝退款状态,退款成功:SUCCESS,退款关闭:CLOSED,退款处理中:PROCESSING,退款异常:ABNORMAL")
|
||||
private String alipayRefundStatus;
|
||||
|
||||
/**
|
||||
* 订单金额(分)
|
||||
*/
|
||||
@ApiModelProperty(value = "订单金额")
|
||||
private BigDecimal orderTotalPrice;
|
||||
|
||||
/**
|
||||
* 退款金额(分)
|
||||
*/
|
||||
@ApiModelProperty(value = "退款金额")
|
||||
private BigDecimal refundPrice;
|
||||
|
||||
/**
|
||||
* 退款币种,人民币:CNY
|
||||
*/
|
||||
@ApiModelProperty(value = "退款币种,人民币:CNY")
|
||||
private String currency;
|
||||
|
||||
/**
|
||||
* ORIGINAL:原路退款,BALANCE:退回到余额,OTHER_BALANCE:原账户异常退到其他余额账户,OTHER_BANKCARD:原银行卡异常退到其他银行卡
|
||||
*/
|
||||
@ApiModelProperty(value = "ORIGINAL:原路退款,BALANCE:退回到余额,OTHER_BALANCE:原账户异常退到其他余额账户,OTHER_BANKCARD:原银行卡异常退到其他银行卡")
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 退款入账账户
|
||||
*/
|
||||
@ApiModelProperty(value = "退款入账账户")
|
||||
private String userreceivedaccount;
|
||||
|
||||
/**
|
||||
* 退款成功时间
|
||||
*/
|
||||
@ApiModelProperty(value = "退款成功时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime successTime;
|
||||
|
||||
/**
|
||||
* 退款回调通知内容,微信或者支付款退款通知内容
|
||||
*/
|
||||
@ApiModelProperty(value = "退款回调通知内容,微信或者支付款退款通知内容")
|
||||
private String refundNotifyContent;
|
||||
|
||||
/**
|
||||
* 申请退款返回参数内容
|
||||
*/
|
||||
@ApiModelProperty(value = "申请退款返回参数内容")
|
||||
private String applyRefundReturnContent;
|
||||
|
||||
/**
|
||||
* 退款账户类型,新医路账户:XINYILU,医路优品:YILUYOUPIN
|
||||
*/
|
||||
@ApiModelProperty(value = "退款账户类型,新医路账户:XINYILU,医路优品:YILUYOUPIN")
|
||||
private String refundMerchantType;
|
||||
|
||||
/**
|
||||
* 是否删除,0:否,1:是
|
||||
*/
|
||||
private Integer delFlag;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("id", getId())
|
||||
.append("userId", getUserId())
|
||||
.append("examRegistrationId", getExamRegistrationId())
|
||||
.append("refundNo", getRefundNo())
|
||||
.append("outRefundNo", getOutRefundNo())
|
||||
.append("transactionNo", getTransactionNo())
|
||||
.append("refundReason", getRefundReason())
|
||||
.append("refundType", getRefundType())
|
||||
.append("wechatRefundStatus", getWechatRefundStatus())
|
||||
.append("alipayRefundStatus", getAlipayRefundStatus())
|
||||
.append("orderTotalPrice", getOrderTotalPrice())
|
||||
.append("refundPrice", getRefundPrice())
|
||||
.append("currency", getCurrency())
|
||||
.append("channel", getChannel())
|
||||
.append("userreceivedaccount", getUserreceivedaccount())
|
||||
.append("successTime", getSuccessTime())
|
||||
.append("refundNotifyContent", getRefundNotifyContent())
|
||||
.append("applyRefundReturnContent", getApplyRefundReturnContent())
|
||||
.append("refundMerchantType", getRefundMerchantType())
|
||||
.append("delFlag", getDelFlag())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("createTime", getCreateTime())
|
||||
.append("updateBy", getUpdateBy())
|
||||
.append("updateTime", getUpdateTime())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
package com.yf.exam.modules.payment.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.yf.exam.modules.payment.entity.PaymentInfo;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 支付记录信息Mapper接口
|
||||
*
|
||||
* @author xinyilu
|
||||
* @date 2022-10-18
|
||||
*/
|
||||
public interface PaymentInfoMapper extends BaseMapper<PaymentInfo> {
|
||||
/**
|
||||
* 查询支付记录信息
|
||||
*
|
||||
* @param id 支付记录信息主键
|
||||
* @return 支付记录信息
|
||||
*/
|
||||
PaymentInfo selectPaymentInfoById(Long id);
|
||||
|
||||
/**
|
||||
* 查询支付记录信息列表
|
||||
*
|
||||
* @param paymentInfo 支付记录信息
|
||||
* @return 支付记录信息集合
|
||||
*/
|
||||
List<PaymentInfo> selectPaymentInfoList(PaymentInfo paymentInfo);
|
||||
|
||||
/**
|
||||
* 新增支付记录信息
|
||||
*
|
||||
* @param paymentInfo 支付记录信息
|
||||
* @return 结果
|
||||
*/
|
||||
int insertPaymentInfo(PaymentInfo paymentInfo);
|
||||
|
||||
/**
|
||||
* 修改支付记录信息
|
||||
*
|
||||
* @param paymentInfo 支付记录信息
|
||||
* @return 结果
|
||||
*/
|
||||
int updatePaymentInfo(PaymentInfo paymentInfo);
|
||||
|
||||
/**
|
||||
* 删除支付记录信息
|
||||
*
|
||||
* @param id 支付记录信息主键
|
||||
* @return 结果
|
||||
*/
|
||||
int deletePaymentInfoById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除支付记录信息
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
int deletePaymentInfoByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 根据订单查询支付记录表信息
|
||||
*
|
||||
* @param orderNo 订单编号
|
||||
* @return 数量
|
||||
*/
|
||||
int getByRegistrationId(String orderNo);
|
||||
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
package com.yf.exam.modules.payment.mapper;
|
||||
|
||||
import com.yf.exam.modules.payment.entity.RefundInfo;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 退款记录信息Mapper接口
|
||||
*
|
||||
* @author xinyilu
|
||||
* @date 2022-10-18
|
||||
*/
|
||||
public interface RefundInfoMapper {
|
||||
/**
|
||||
* 查询退款记录信息
|
||||
*
|
||||
* @param id 退款记录信息主键
|
||||
* @return 退款记录信息
|
||||
*/
|
||||
RefundInfo selectRefundInfoById(Long id);
|
||||
|
||||
/**
|
||||
* 查询退款记录信息列表
|
||||
*
|
||||
* @param refundInfo 退款记录信息
|
||||
* @return 退款记录信息集合
|
||||
*/
|
||||
List<RefundInfo> selectRefundInfoList(RefundInfo refundInfo);
|
||||
|
||||
/**
|
||||
* 新增退款记录信息
|
||||
*
|
||||
* @param refundInfo 退款记录信息
|
||||
* @return 结果
|
||||
*/
|
||||
int insertRefundInfo(RefundInfo refundInfo);
|
||||
|
||||
/**
|
||||
* 修改退款记录信息
|
||||
*
|
||||
* @param refundInfo 退款记录信息
|
||||
* @return 结果
|
||||
*/
|
||||
int updateRefundInfo(RefundInfo refundInfo);
|
||||
|
||||
/**
|
||||
* 删除退款记录信息
|
||||
*
|
||||
* @param id 退款记录信息主键
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteRefundInfoById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除退款记录信息
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteRefundInfoByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 修改退款单信息
|
||||
*
|
||||
* @param refundInfo 退款单信息
|
||||
* @return 更新数量
|
||||
*/
|
||||
int updateRefundInfoByNo(RefundInfo refundInfo);
|
||||
|
||||
/**
|
||||
* 批量更新支付订单状态
|
||||
*
|
||||
* @param orderNo 订单编号
|
||||
* @param successTime 退款成功时间
|
||||
* @param weChatRefundStatus 订单状态
|
||||
* @return 更新数量
|
||||
*/
|
||||
int updateBatchRefundStatus(@Param("orderNo") String orderNo, @Param("successTime") LocalDateTime successTime,
|
||||
@Param("weChatRefundStatus") String weChatRefundStatus);
|
||||
|
||||
/**
|
||||
* 根据订单编号查询支付退款表信息
|
||||
*
|
||||
* @param examRegistrationId 订单编号
|
||||
* @return 数量
|
||||
*/
|
||||
int getRefundInfoByexamRegistrationId(String examRegistrationId);
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
package com.yf.exam.modules.payment.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.yf.exam.modules.payment.entity.PaymentInfo;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 支付记录信息Service接口
|
||||
*
|
||||
* @author xinyilu
|
||||
* @date 2022-10-18
|
||||
*/
|
||||
public interface IPaymentInfoService extends IService<PaymentInfo> {
|
||||
/**
|
||||
* 查询支付记录信息
|
||||
*
|
||||
* @param id 支付记录信息主键
|
||||
* @return 支付记录信息
|
||||
*/
|
||||
PaymentInfo selectPaymentInfoById(Long id);
|
||||
|
||||
/**
|
||||
* 查询支付记录信息列表
|
||||
*
|
||||
* @param paymentInfo 支付记录信息
|
||||
* @return 支付记录信息集合
|
||||
*/
|
||||
List<PaymentInfo> selectPaymentInfoList(PaymentInfo paymentInfo);
|
||||
|
||||
/**
|
||||
* 新增支付记录信息
|
||||
*
|
||||
* @param paymentInfo 支付记录信息
|
||||
* @return 结果
|
||||
*/
|
||||
int insertPaymentInfo(PaymentInfo paymentInfo);
|
||||
|
||||
/**
|
||||
* 修改支付记录信息
|
||||
*
|
||||
* @param paymentInfo 支付记录信息
|
||||
* @return 结果
|
||||
*/
|
||||
int updatePaymentInfo(PaymentInfo paymentInfo);
|
||||
|
||||
/**
|
||||
* 批量删除支付记录信息
|
||||
*
|
||||
* @param ids 需要删除的支付记录信息主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
int deletePaymentInfoByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 删除支付记录信息信息
|
||||
*
|
||||
* @param id 支付记录信息主键
|
||||
* @return 结果
|
||||
*/
|
||||
int deletePaymentInfoById(Long id);
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
package com.yf.exam.modules.payment.service;
|
||||
|
||||
public interface PaymentService {
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package com.yf.exam.modules.payment.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.yf.exam.modules.payment.entity.PaymentInfo;
|
||||
import com.yf.exam.modules.payment.mapper.PaymentInfoMapper;
|
||||
import com.yf.exam.modules.payment.service.IPaymentInfoService;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 支付记录信息Service业务层处理
|
||||
*
|
||||
* @author xinyilu
|
||||
* @date 2022-10-18
|
||||
*/
|
||||
@Service
|
||||
public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, PaymentInfo> implements IPaymentInfoService {
|
||||
@Resource
|
||||
private PaymentInfoMapper paymentInfoMapper;
|
||||
|
||||
/**
|
||||
* 查询支付记录信息
|
||||
*
|
||||
* @param id 支付记录信息主键
|
||||
* @return 支付记录信息
|
||||
*/
|
||||
@Override
|
||||
public PaymentInfo selectPaymentInfoById(Long id) {
|
||||
return paymentInfoMapper.selectPaymentInfoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询支付记录信息列表
|
||||
*
|
||||
* @param paymentInfo 支付记录信息
|
||||
* @return 支付记录信息
|
||||
*/
|
||||
@Override
|
||||
public List<PaymentInfo> selectPaymentInfoList(PaymentInfo paymentInfo) {
|
||||
return paymentInfoMapper.selectPaymentInfoList(paymentInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增支付记录信息
|
||||
*
|
||||
* @param paymentInfo 支付记录信息
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int insertPaymentInfo(PaymentInfo paymentInfo) {
|
||||
paymentInfo.setCreateTime(new Date());
|
||||
return paymentInfoMapper.insertPaymentInfo(paymentInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改支付记录信息
|
||||
*
|
||||
* @param paymentInfo 支付记录信息
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updatePaymentInfo(PaymentInfo paymentInfo) {
|
||||
paymentInfo.setUpdateTime(new Date());
|
||||
return paymentInfoMapper.updatePaymentInfo(paymentInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除支付记录信息
|
||||
*
|
||||
* @param ids 需要删除的支付记录信息主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deletePaymentInfoByIds(Long[] ids) {
|
||||
return paymentInfoMapper.deletePaymentInfoByIds(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除支付记录信息信息
|
||||
*
|
||||
* @param id 支付记录信息主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deletePaymentInfoById(Long id) {
|
||||
return paymentInfoMapper.deletePaymentInfoById(id);
|
||||
}
|
||||
}
|
||||
@ -1,135 +0,0 @@
|
||||
package com.yf.exam.modules.payment.service.impl;
|
||||
|
||||
import com.yf.exam.config.WeChatPaymentUrlConfig;
|
||||
import com.yf.exam.config.XylWeChatPaymentConfig;
|
||||
import com.yf.exam.modules.payment.service.PaymentService;
|
||||
import com.yf.exam.modules.utils.WeChatUtil;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: haown
|
||||
* @create: 2025-07-23 09:44
|
||||
**/
|
||||
public class PaymentServiceImpl implements PaymentService {
|
||||
|
||||
@Resource(name = "xinYiLuWeChatPayClient")
|
||||
private CloseableHttpClient xinYiLuWeChatPayClient;
|
||||
@Resource
|
||||
private WeChatPaymentUrlConfig weChatPaymentUrlConfig;
|
||||
@Resource
|
||||
private WeChatUtil weChatUtil;
|
||||
@Resource
|
||||
private XylWeChatPaymentConfig xylWeChatPaymentConfig;
|
||||
|
||||
|
||||
/**
|
||||
* H5下单成功状态码
|
||||
*/
|
||||
private static final int HAVE_BODY_SUCCESS_CODE = 200;
|
||||
|
||||
/**
|
||||
* H5下单成功状态码
|
||||
*/
|
||||
private static final int NO_HAVE_BODY_SUCCESS_CODE = 204;
|
||||
|
||||
/**
|
||||
* 签名算法
|
||||
*/
|
||||
private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
|
||||
|
||||
/**
|
||||
* 签名方式
|
||||
*/
|
||||
private static final String SIGN_TYPE = "RSA";
|
||||
|
||||
/**
|
||||
* 请求h5下单接口方法
|
||||
*
|
||||
* @param jsApiParams 下单参数
|
||||
* @param paymentDTO 输入参数
|
||||
* @param prepayId JsAp下单接口返回值
|
||||
* @return 结果
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
/*private String requestH5Interface(String jsApiParams, PaymentDTO paymentDTO, String prepayId) throws Exception {
|
||||
//log.info("JsApi请求下单参数 ====> {}", jsApiParams);
|
||||
StringEntity stringEntity = new StringEntity(jsApiParams, StandardCharsets.UTF_8);
|
||||
stringEntity.setContentType("application/json");
|
||||
HttpPost httpPost = new HttpPost(weChatPaymentUrlConfig.getJsapiPalceOrderUrl());
|
||||
httpPost.setEntity(stringEntity);
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
CloseableHttpResponse response = null;
|
||||
String payAccount = "";
|
||||
try {
|
||||
response = xinYiLuWeChatPayClient.execute(httpPost);
|
||||
payAccount = "山东柏杏新医健康服务有限公司";
|
||||
//处理响应结果
|
||||
if (Objects.isNull(response)) {
|
||||
//log.error("JsApi下单接口执行错误, 执行账户为 ====> {}", payAccount);
|
||||
throw new ServiceException("JsApi下单接口执行异常,请联系管理员!");
|
||||
}
|
||||
//响应状态码
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
//响应体
|
||||
String result = EntityUtils.toString(response.getEntity());
|
||||
if (statusCode == HAVE_BODY_SUCCESS_CODE) {
|
||||
//请求成功,取出prepay_id的值并放入Redis缓存中,prepay_id的有效期为两小时,此处缓存一个半小时
|
||||
Map<String, Object> resultMap = JSONObject.parseObject(result);
|
||||
prepayId = resultMap.getOrDefault("prepay_id", "").toString();
|
||||
redisTemplate.opsForValue().set(Constants.PREPAY_ID_KEY + paymentDTO.getOrderNo(), prepayId, 5400, TimeUnit.SECONDS);
|
||||
} else if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
|
||||
//请求成功,无返回体
|
||||
log.info("JsApi下单成功,无返回值信息!");
|
||||
} else {
|
||||
//请求失败
|
||||
log.error("JsApi下单失败,失败原因为 ====> {}", result);
|
||||
throw new ServiceException("JsApi下单失败,失败原因为:" + result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("JsApi下单失败,失败原因 =====> {}", e.getMessage());
|
||||
throw new ServiceException("JsApi下单失败,请联系管理员!");
|
||||
} finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
return prepayId;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* 构建微信小程序调起支付参数设置
|
||||
*
|
||||
* @param prepayId jsapi下单返回参数信息
|
||||
* @param buySource 购买来源
|
||||
* @return 参数信息
|
||||
* @throws Exception 异常信息
|
||||
*/
|
||||
//private WeChatAppletSignVO getSignInfo(String prepayId, String buySource) throws Exception {
|
||||
// //根据购买来源判断使用泉医到家小程序id还是泉医助手小程序id
|
||||
// String appId = BuySourceEnum.TRAINING.getInfo().equals(buySource) ? nurseAppletChatConfig.getAppletId() : appletChatConfig.getAppletId();
|
||||
// //随机字符串
|
||||
// String nonceStr = UUID.randomUUID().toString().replace("-", "");
|
||||
// //时间戳
|
||||
// String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
// //获取商户私钥
|
||||
// PrivateKey privateKey = null;
|
||||
// privateKey = weChatUtil.getPrivateKey(xylWeChatPaymentConfig.getXylPrivateKeyPath());
|
||||
// if (privateKey == null) {
|
||||
// throw new ServiceException("获取商户私钥失败,请联系管理员!");
|
||||
// }
|
||||
// //计算签名信息
|
||||
// prepayId = "prepay_id=" + prepayId;
|
||||
// String signatureStr = Stream.of(appId, timestamp, nonceStr, prepayId)
|
||||
// .collect(Collectors.joining("\n", "", "\n"));
|
||||
// log.info("计算签名认证信息 =====> {}", signatureStr);
|
||||
// Signature sign = Signature.getInstance(SIGNATURE_ALGORITHM);
|
||||
// sign.initSign(privateKey);
|
||||
// sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
|
||||
// String paySign = Base64Utils.encodeToString(sign.sign());
|
||||
// return WeChatAppletSignVO.builder().appId(appId).timeStamp(timestamp).nonceStr(nonceStr).prepayId(prepayId)
|
||||
// .signType(SIGN_TYPE).paySign(paySign).build();
|
||||
//}
|
||||
|
||||
}
|
||||
@ -0,0 +1,250 @@
|
||||
package com.yf.exam.modules.payment.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @Description 微信申请退款返回值实体类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-24 17:50:40
|
||||
* @Version 1.0
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class WeChatRefundInfoVO implements Serializable {
|
||||
private static final long serialVersionUID = -7834783600438774698L;
|
||||
|
||||
/**
|
||||
* 退款单号
|
||||
*/
|
||||
@JsonProperty("refund_id")
|
||||
private String refundId;
|
||||
|
||||
/**
|
||||
* 商户退款单号
|
||||
*/
|
||||
@JsonProperty("out_refund_no")
|
||||
private String outRefundNo;
|
||||
|
||||
/**
|
||||
* 微信平台订单号
|
||||
*/
|
||||
@JsonProperty("transaction_id")
|
||||
private String transactionId;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
@JsonProperty("out_trade_no")
|
||||
private String outTradeNo;
|
||||
|
||||
/**
|
||||
* 退款渠道
|
||||
*/
|
||||
@JsonProperty("channel")
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 到账金额
|
||||
*/
|
||||
@JsonProperty("user_received_account")
|
||||
private String userReceivedAccount;
|
||||
|
||||
/**
|
||||
* 退款成功时间
|
||||
*/
|
||||
@JsonProperty("success_time")
|
||||
private String successTime;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonProperty("create_time")
|
||||
private String createTime;
|
||||
|
||||
/**
|
||||
* 退款状态
|
||||
*/
|
||||
@JsonProperty("status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 金额信息
|
||||
*/
|
||||
@JsonProperty("funds_account")
|
||||
private String fundsAccount;
|
||||
|
||||
/**
|
||||
* 金额详情信息
|
||||
*/
|
||||
@JsonProperty("amount")
|
||||
private AmountDTO amount;
|
||||
|
||||
/**
|
||||
* 优惠退款信息
|
||||
*/
|
||||
@JsonProperty("promotion_detail")
|
||||
private List<PromotionDetailDTO> promotionDetail;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class AmountDTO {
|
||||
/**
|
||||
* 总金额
|
||||
*/
|
||||
@JsonProperty("total")
|
||||
private Integer total;
|
||||
|
||||
/**
|
||||
* 退款金额
|
||||
*/
|
||||
@JsonProperty("refund")
|
||||
private Integer refund;
|
||||
|
||||
/**
|
||||
* 退款出资账户及金额
|
||||
*/
|
||||
@JsonProperty("from")
|
||||
private List<FromDTO> from;
|
||||
|
||||
/**
|
||||
* 支付金额
|
||||
*/
|
||||
@JsonProperty("payer_total")
|
||||
private Integer payerTotal;
|
||||
|
||||
/**
|
||||
* 退款金额
|
||||
*/
|
||||
@JsonProperty("payer_refund")
|
||||
private Integer payerRefund;
|
||||
|
||||
/**
|
||||
* 应结退款金额
|
||||
*/
|
||||
@JsonProperty("settlement_refund")
|
||||
private Integer settlementRefund;
|
||||
|
||||
/**
|
||||
* 应结订单金额
|
||||
*/
|
||||
@JsonProperty("settlement_total")
|
||||
private Integer settlementTotal;
|
||||
|
||||
/**
|
||||
* 优惠退款金额
|
||||
*/
|
||||
@JsonProperty("discount_refund")
|
||||
private Integer discountRefund;
|
||||
|
||||
/**
|
||||
* 退款币种
|
||||
*/
|
||||
@JsonProperty("currency")
|
||||
private String currency;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class FromDTO {
|
||||
/**
|
||||
* 金额信息
|
||||
*/
|
||||
@JsonProperty("account")
|
||||
private String account;
|
||||
/**
|
||||
* 金额信息
|
||||
*/
|
||||
@JsonProperty("amount")
|
||||
private Integer amount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 优惠退款信息
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class PromotionDetailDTO {
|
||||
/**
|
||||
* 券ID
|
||||
*/
|
||||
@JsonProperty("promotion_id")
|
||||
private String promotionId;
|
||||
|
||||
/**
|
||||
* 优惠范围
|
||||
*/
|
||||
@JsonProperty("scope")
|
||||
private String scope;
|
||||
|
||||
/**
|
||||
* 优惠类型
|
||||
*/
|
||||
@JsonProperty("type")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 优惠券面额
|
||||
*/
|
||||
@JsonProperty("amount")
|
||||
private Integer amount;
|
||||
|
||||
/**
|
||||
* 优惠退款金额
|
||||
*/
|
||||
@JsonProperty("refund_amount")
|
||||
private Integer refundAmount;
|
||||
|
||||
/**
|
||||
* 商品列表
|
||||
*/
|
||||
@JsonProperty("goods_detail")
|
||||
private List<GoodsDetailDTO> goodsDetail;
|
||||
|
||||
/**
|
||||
* 商品列表
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class GoodsDetailDTO {
|
||||
/**
|
||||
* 商户侧商品编码
|
||||
*/
|
||||
@JsonProperty("merchant_goods_id")
|
||||
private String merchantGoodsId;
|
||||
|
||||
/**
|
||||
* 微信支付商品编码
|
||||
*/
|
||||
@JsonProperty("wechatpay_goods_id")
|
||||
private String wechatpayGoodsId;
|
||||
|
||||
/**
|
||||
* 商品名称
|
||||
*/
|
||||
@JsonProperty("goods_name")
|
||||
private String goodsName;
|
||||
|
||||
/**
|
||||
* 商品单价
|
||||
*/
|
||||
@JsonProperty("unit_price")
|
||||
private Integer unitPrice;
|
||||
|
||||
/**
|
||||
* 商品退款金额
|
||||
*/
|
||||
@JsonProperty("refund_amount")
|
||||
private Integer refundAmount;
|
||||
|
||||
/**
|
||||
* 商品退货数量
|
||||
*/
|
||||
@JsonProperty("refund_quantity")
|
||||
private Integer refundQuantity;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
package com.yf.exam.modules.payment.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @Description 微信退款回调通知参数实体类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-25 11:38:39
|
||||
* @Version 1.0
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class WeChatRefundNotifyVO implements Serializable {
|
||||
private static final long serialVersionUID = -2553550636560311860L;
|
||||
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
@JsonProperty("mchid")
|
||||
private String mchid;
|
||||
|
||||
/**
|
||||
* 微信支付订单号
|
||||
*/
|
||||
@JsonProperty("transaction_id")
|
||||
private String transactionId;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
@JsonProperty("out_trade_no")
|
||||
private String outTradeNo;
|
||||
|
||||
/**
|
||||
* 微信支付退款单号
|
||||
*/
|
||||
@JsonProperty("refund_id")
|
||||
private String refundId;
|
||||
|
||||
/**
|
||||
* 商户退款单号
|
||||
*/
|
||||
@JsonProperty("out_refund_no")
|
||||
private String outRefundNo;
|
||||
|
||||
/**
|
||||
* 退款状态
|
||||
*/
|
||||
@JsonProperty("refund_status")
|
||||
private String refundStatus;
|
||||
|
||||
/**
|
||||
* 退款成功时间
|
||||
*/
|
||||
@JsonProperty("success_time")
|
||||
private String successTime;
|
||||
|
||||
/**
|
||||
* 退款入账账户
|
||||
*/
|
||||
@JsonProperty("user_received_account")
|
||||
private String userReceivedAccount;
|
||||
|
||||
/**
|
||||
* 退款金额
|
||||
*/
|
||||
@JsonProperty("amount")
|
||||
private AmountDTO amount;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class AmountDTO {
|
||||
|
||||
/**
|
||||
* 订单金额
|
||||
*/
|
||||
@JsonProperty("total")
|
||||
private Integer total;
|
||||
|
||||
/**
|
||||
* 退款金额
|
||||
*/
|
||||
@JsonProperty("refund")
|
||||
private Integer refund;
|
||||
|
||||
/**
|
||||
* 用户支付金额
|
||||
*/
|
||||
@JsonProperty("payer_total")
|
||||
private Integer payerTotal;
|
||||
|
||||
/**
|
||||
* 用户退款金额
|
||||
*/
|
||||
@JsonProperty("payer_refund")
|
||||
private Integer payerRefund;
|
||||
}
|
||||
}
|
||||
@ -51,7 +51,7 @@ server:
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
# 考试系统微信小程序参数配置信息
|
||||
exam-applet-chat-config:
|
||||
applet-chat-config:
|
||||
# 微信小程序
|
||||
applet-id: wx26b9ecdba54bc588
|
||||
# 微信小程序密钥
|
||||
@ -73,7 +73,7 @@ xyl-we-chat-config:
|
||||
# 山东省公共卫生学会API V3版本密钥 Xyl699003981qazVFR4xsw23edcASDFG
|
||||
xyl-payment-key: gonggongweishengXUEHUI2025081100
|
||||
# 山东省公共卫生学会微信支付回调地址 https://quanyidaojia.xinelu.cn
|
||||
xyl-wechat-notify-url: http://8.131.93.145:54097
|
||||
xyl-wechat-notify-url: http://8.131.93.145:54012
|
||||
# 微信支付接口地址,包含小程序和App支付接口地址
|
||||
we-chat-payment-url-config:
|
||||
# 小程序JSAPI下单接口地址
|
||||
|
||||
@ -104,7 +104,8 @@
|
||||
|
||||
<select id="getExamList" resultMap="OnlineResultMap">
|
||||
SELECT * FROM el_exam
|
||||
where state = 0 and (exam_type = 2 or exam_type = 3) and id not in (select exam_id from el_exam_registration where user_id = #{query.userId})
|
||||
where state = 0 and (exam_type = 2 or exam_type = 3)
|
||||
and id not in (select exam_id from el_exam_registration where user_id = #{query.userId} and payment_state = 'PAY')
|
||||
<if test="query!=null">
|
||||
<if test="query.openType!=null">
|
||||
AND open_type = #{query.openType}
|
||||
|
||||
@ -105,4 +105,9 @@
|
||||
order by reg.reg_time desc
|
||||
</select>
|
||||
|
||||
<update id="updatePaymentStateById" parameterType="com.yf.exam.modules.exam.entity.ExamRegistration">
|
||||
update el_exam_registration
|
||||
set payment_state = #{paymentState}
|
||||
where id= #{id}
|
||||
</update>
|
||||
</mapper>
|
||||
|
||||
@ -0,0 +1,251 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.yf.exam.modules.payment.mapper.PaymentInfoMapper">
|
||||
|
||||
<resultMap type="com.yf.exam.modules.payment.entity.PaymentInfo" id="PaymentInfoResult">
|
||||
<result property="id" column="id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="examRegistrationId" column="exam_registration_id"/>
|
||||
<result property="paymentTitle" column="payment_title"/>
|
||||
<result property="transactionNo" column="transaction_no"/>
|
||||
<result property="payPrice" column="pay_price"/>
|
||||
<result property="payType" column="pay_type"/>
|
||||
<result property="payChannel" column="pay_channel"/>
|
||||
<result property="wechatTradeState" column="wechat_trade_state"/>
|
||||
<result property="alipayTradeState" column="alipay_trade_state"/>
|
||||
<result property="payNotifyContent" column="pay_notify_content"/>
|
||||
<result property="payTime" column="pay_time"/>
|
||||
<result property="paymentMerchantType" column="payment_merchant_type"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectPaymentInfoVo">
|
||||
select id,
|
||||
user_id,
|
||||
exam_registration_id,
|
||||
payment_title,
|
||||
transaction_no,
|
||||
pay_price,
|
||||
pay_type,
|
||||
pay_channel,
|
||||
wechat_trade_state,
|
||||
alipay_trade_state,
|
||||
pay_notify_content,
|
||||
pay_time,
|
||||
payment_merchant_type,
|
||||
del_flag,
|
||||
create_by,
|
||||
create_time,
|
||||
update_by,
|
||||
update_time
|
||||
from payment_info
|
||||
</sql>
|
||||
|
||||
<select id="selectPaymentInfoList" parameterType="com.yf.exam.modules.payment.entity.PaymentInfo" resultMap="PaymentInfoResult">
|
||||
<include refid="selectPaymentInfoVo"/>
|
||||
<where>
|
||||
<if test="userId != null ">
|
||||
and user_id = #{userId}
|
||||
</if>
|
||||
<if test="examRegistrationId != null and examRegistrationId != ''">
|
||||
and exam_registration_id = #{examRegistrationId}
|
||||
</if>
|
||||
<if test="paymentTitle != null and paymentTitle != ''">
|
||||
and payment_title = #{paymentTitle}
|
||||
</if>
|
||||
<if test="transactionNo != null and transactionNo != ''">
|
||||
and transaction_no = #{transactionNo}
|
||||
</if>
|
||||
<if test="payPrice != null ">
|
||||
and pay_price = #{payPrice}
|
||||
</if>
|
||||
<if test="payType != null and payType != ''">
|
||||
and pay_type = #{payType}
|
||||
</if>
|
||||
<if test="payChannel != null and payChannel != ''">
|
||||
and pay_channel = #{payChannel}
|
||||
</if>
|
||||
<if test="wechatTradeState != null and wechatTradeState != ''">
|
||||
and wechat_trade_state = #{wechatTradeState}
|
||||
</if>
|
||||
<if test="alipayTradeState != null and alipayTradeState != ''">
|
||||
and alipay_trade_state = #{alipayTradeState}
|
||||
</if>
|
||||
<if test="payNotifyContent != null and payNotifyContent != ''">
|
||||
and pay_notify_content = #{payNotifyContent}
|
||||
</if>
|
||||
<if test="payTime != null ">
|
||||
and pay_time = #{payTime}
|
||||
</if>
|
||||
<if test="paymentMerchantType != null and paymentMerchantType != ''">
|
||||
and payment_merchant_type = #{paymentMerchantType}
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="selectPaymentInfoById" parameterType="Long"
|
||||
resultMap="PaymentInfoResult">
|
||||
<include refid="selectPaymentInfoVo"/>
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<insert id="insertPaymentInfo" parameterType="com.yf.exam.modules.payment.entity.PaymentInfo" useGeneratedKeys="true"
|
||||
keyProperty="id">
|
||||
insert into payment_info
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">user_id,
|
||||
</if>
|
||||
<if test="examRegistrationId != null">exam_registration_id,
|
||||
</if>
|
||||
<if test="paymentTitle != null">payment_title,
|
||||
</if>
|
||||
<if test="transactionNo != null">transaction_no,
|
||||
</if>
|
||||
<if test="payPrice != null">pay_price,
|
||||
</if>
|
||||
<if test="payType != null">pay_type,
|
||||
</if>
|
||||
<if test="payChannel != null">pay_channel,
|
||||
</if>
|
||||
<if test="wechatTradeState != null">wechat_trade_state,
|
||||
</if>
|
||||
<if test="alipayTradeState != null">alipay_trade_state,
|
||||
</if>
|
||||
<if test="payNotifyContent != null">pay_notify_content,
|
||||
</if>
|
||||
<if test="payTime != null">pay_time,
|
||||
</if>
|
||||
<if test="paymentMerchantType != null">payment_merchant_type,
|
||||
</if>
|
||||
<if test="delFlag != null">del_flag,
|
||||
</if>
|
||||
<if test="createBy != null">create_by,
|
||||
</if>
|
||||
<if test="createTime != null">create_time,
|
||||
</if>
|
||||
<if test="updateBy != null">update_by,
|
||||
</if>
|
||||
<if test="updateTime != null">update_time,
|
||||
</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">#{userId},
|
||||
</if>
|
||||
<if test="examRegistrationId != null">#{examRegistrationId},
|
||||
</if>
|
||||
<if test="paymentTitle != null">#{paymentTitle},
|
||||
</if>
|
||||
<if test="transactionNo != null">#{transactionNo},
|
||||
</if>
|
||||
<if test="payPrice != null">#{payPrice},
|
||||
</if>
|
||||
<if test="payType != null">#{payType},
|
||||
</if>
|
||||
<if test="payChannel != null">#{payChannel},
|
||||
</if>
|
||||
<if test="wechatTradeState != null">#{wechatTradeState},
|
||||
</if>
|
||||
<if test="alipayTradeState != null">#{alipayTradeState},
|
||||
</if>
|
||||
<if test="payNotifyContent != null">#{payNotifyContent},
|
||||
</if>
|
||||
<if test="payTime != null">#{payTime},
|
||||
</if>
|
||||
<if test="paymentMerchantType != null">#{paymentMerchantType},
|
||||
</if>
|
||||
<if test="delFlag != null">#{delFlag},
|
||||
</if>
|
||||
<if test="createBy != null">#{createBy},
|
||||
</if>
|
||||
<if test="createTime != null">#{createTime},
|
||||
</if>
|
||||
<if test="updateBy != null">#{updateBy},
|
||||
</if>
|
||||
<if test="updateTime != null">#{updateTime},
|
||||
</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="updatePaymentInfo" parameterType="com.yf.exam.modules.payment.entity.PaymentInfo">
|
||||
update payment_info
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="userId != null">user_id =
|
||||
#{userId},
|
||||
</if>
|
||||
<if test="examRegistrationId != null">exam_registration_id =
|
||||
#{examRegistrationId},
|
||||
</if>
|
||||
<if test="paymentTitle != null">payment_title =
|
||||
#{paymentTitle},
|
||||
</if>
|
||||
<if test="transactionNo != null">transaction_no =
|
||||
#{transactionNo},
|
||||
</if>
|
||||
<if test="payPrice != null">pay_price =
|
||||
#{payPrice},
|
||||
</if>
|
||||
<if test="payType != null">pay_type =
|
||||
#{payType},
|
||||
</if>
|
||||
<if test="payChannel != null">pay_channel =
|
||||
#{payChannel},
|
||||
</if>
|
||||
<if test="wechatTradeState != null">wechat_trade_state =
|
||||
#{wechatTradeState},
|
||||
</if>
|
||||
<if test="alipayTradeState != null">alipay_trade_state =
|
||||
#{alipayTradeState},
|
||||
</if>
|
||||
<if test="payNotifyContent != null">pay_notify_content =
|
||||
#{payNotifyContent},
|
||||
</if>
|
||||
<if test="payTime != null">pay_time =
|
||||
#{payTime},
|
||||
</if>
|
||||
<if test="paymentMerchantType != null">payment_merchant_type =
|
||||
#{paymentMerchantType},
|
||||
</if>
|
||||
<if test="delFlag != null">del_flag =
|
||||
#{delFlag},
|
||||
</if>
|
||||
<if test="createBy != null">create_by =
|
||||
#{createBy},
|
||||
</if>
|
||||
<if test="createTime != null">create_time =
|
||||
#{createTime},
|
||||
</if>
|
||||
<if test="updateBy != null">update_by =
|
||||
#{updateBy},
|
||||
</if>
|
||||
<if test="updateTime != null">update_time =
|
||||
#{updateTime},
|
||||
</if>
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="deletePaymentInfoById" parameterType="Long">
|
||||
delete
|
||||
from payment_info
|
||||
where id = #{id}
|
||||
</delete>
|
||||
|
||||
<delete id="deletePaymentInfoByIds" parameterType="String">
|
||||
delete from payment_info where id in
|
||||
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<select id="getByRegistrationId" parameterType="string" resultType="int">
|
||||
select count(1) paymentCount
|
||||
from payment_info
|
||||
where exam_registration_id = #{examRegistrationId}
|
||||
</select>
|
||||
</mapper>
|
||||
@ -0,0 +1,344 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.yf.exam.modules.payment.mapper.RefundInfoMapper">
|
||||
|
||||
<resultMap type="com.yf.exam.modules.payment.entity.RefundInfo" id="RefundInfoResult">
|
||||
<result property="id" column="id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="examRegistrationId" column="exam_registration_id"/>
|
||||
<result property="refundNo" column="refund_no"/>
|
||||
<result property="outRefundNo" column="out_refund_no"/>
|
||||
<result property="transactionNo" column="transaction_no"/>
|
||||
<result property="refundReason" column="refund_reason"/>
|
||||
<result property="refundType" column="refund_type"/>
|
||||
<result property="wechatRefundStatus" column="wechat_refund_status"/>
|
||||
<result property="alipayRefundStatus" column="alipay_refund_status"/>
|
||||
<result property="orderTotalPrice" column="order_total_price"/>
|
||||
<result property="refundPrice" column="refund_price"/>
|
||||
<result property="currency" column="currency"/>
|
||||
<result property="channel" column="channel"/>
|
||||
<result property="userreceivedaccount" column="userReceivedAccount"/>
|
||||
<result property="successTime" column="success_time"/>
|
||||
<result property="refundNotifyContent" column="refund_notify_content"/>
|
||||
<result property="applyRefundReturnContent" column="apply_refund_return_content"/>
|
||||
<result property="refundMerchantType" column="refund_merchant_type"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectRefundInfoVo">
|
||||
select id,
|
||||
user_id,
|
||||
exam_registration_id,
|
||||
refund_no,
|
||||
out_refund_no,
|
||||
transaction_no,
|
||||
refund_reason,
|
||||
refund_type,
|
||||
wechat_refund_status,
|
||||
alipay_refund_status,
|
||||
order_total_price,
|
||||
refund_price,
|
||||
currency,
|
||||
channel,
|
||||
userReceivedAccount,
|
||||
success_time,
|
||||
refund_notify_content,
|
||||
apply_refund_return_content,
|
||||
refund_merchant_type,
|
||||
del_flag,
|
||||
create_by,
|
||||
create_time,
|
||||
update_by,
|
||||
update_time
|
||||
from refund_info
|
||||
</sql>
|
||||
|
||||
<select id="selectRefundInfoList" parameterType="com.yf.exam.modules.payment.entity.RefundInfo" resultMap="RefundInfoResult">
|
||||
<include refid="selectRefundInfoVo"/>
|
||||
<where>
|
||||
<if test="userId != null ">
|
||||
and user_id = #{userId}
|
||||
</if>
|
||||
<if test="examRegistrationId != null and examRegistrationId != ''">
|
||||
and exam_registration_id = #{examRegistrationId}
|
||||
</if>
|
||||
<if test="refundNo != null and refundNo != ''">
|
||||
and refund_no = #{refundNo}
|
||||
</if>
|
||||
<if test="outRefundNo != null and outRefundNo != ''">
|
||||
and out_refund_no = #{outRefundNo}
|
||||
</if>
|
||||
<if test="transactionNo != null and transactionNo != ''">
|
||||
and transaction_no = #{transactionNo}
|
||||
</if>
|
||||
<if test="refundReason != null and refundReason != ''">
|
||||
and refund_reason = #{refundReason}
|
||||
</if>
|
||||
<if test="refundType != null and refundType != ''">
|
||||
and refund_type = #{refundType}
|
||||
</if>
|
||||
<if test="wechatRefundStatus != null and wechatRefundStatus != ''">
|
||||
and wechat_refund_status = #{wechatRefundStatus}
|
||||
</if>
|
||||
<if test="alipayRefundStatus != null and alipayRefundStatus != ''">
|
||||
and alipay_refund_status = #{alipayRefundStatus}
|
||||
</if>
|
||||
<if test="orderTotalPrice != null ">
|
||||
and order_total_price = #{orderTotalPrice}
|
||||
</if>
|
||||
<if test="refundPrice != null ">
|
||||
and refund_price = #{refundPrice}
|
||||
</if>
|
||||
<if test="currency != null and currency != ''">
|
||||
and currency = #{currency}
|
||||
</if>
|
||||
<if test="channel != null and channel != ''">
|
||||
and channel = #{channel}
|
||||
</if>
|
||||
<if test="userreceivedaccount != null and userreceivedaccount != ''">
|
||||
and userReceivedAccount = #{userreceivedaccount}
|
||||
</if>
|
||||
<if test="successTime != null ">
|
||||
and success_time = #{successTime}
|
||||
</if>
|
||||
<if test="refundNotifyContent != null and refundNotifyContent != ''">
|
||||
and refund_notify_content = #{refundNotifyContent}
|
||||
</if>
|
||||
<if test="applyRefundReturnContent != null and applyRefundReturnContent != ''">
|
||||
and apply_refund_return_content = #{applyRefundReturnContent}
|
||||
</if>
|
||||
<if test="refundMerchantType != null and refundMerchantType != ''">
|
||||
and refund_merchant_type = #{refundMerchantType}
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="selectRefundInfoById" parameterType="Long"
|
||||
resultMap="RefundInfoResult">
|
||||
<include refid="selectRefundInfoVo"/>
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<insert id="insertRefundInfo" parameterType="com.yf.exam.modules.payment.entity.RefundInfo" useGeneratedKeys="true"
|
||||
keyProperty="id">
|
||||
insert into refund_info
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">user_id,
|
||||
</if>
|
||||
<if test="examRegistrationId != null">exam_registration_id,
|
||||
</if>
|
||||
<if test="refundNo != null">refund_no,
|
||||
</if>
|
||||
<if test="outRefundNo != null">out_refund_no,
|
||||
</if>
|
||||
<if test="transactionNo != null">transaction_no,
|
||||
</if>
|
||||
<if test="refundReason != null">refund_reason,
|
||||
</if>
|
||||
<if test="refundType != null">refund_type,
|
||||
</if>
|
||||
<if test="wechatRefundStatus != null">wechat_refund_status,
|
||||
</if>
|
||||
<if test="alipayRefundStatus != null">alipay_refund_status,
|
||||
</if>
|
||||
<if test="orderTotalPrice != null">order_total_price,
|
||||
</if>
|
||||
<if test="refundPrice != null">refund_price,
|
||||
</if>
|
||||
<if test="currency != null">currency,
|
||||
</if>
|
||||
<if test="channel != null">channel,
|
||||
</if>
|
||||
<if test="userreceivedaccount != null">userReceivedAccount,
|
||||
</if>
|
||||
<if test="successTime != null">success_time,
|
||||
</if>
|
||||
<if test="refundNotifyContent != null">refund_notify_content,
|
||||
</if>
|
||||
<if test="applyRefundReturnContent != null">apply_refund_return_content,
|
||||
</if>
|
||||
<if test="refundMerchantType != null">refund_merchant_type,
|
||||
</if>
|
||||
<if test="delFlag != null">del_flag,
|
||||
</if>
|
||||
<if test="createBy != null">create_by,
|
||||
</if>
|
||||
<if test="createTime != null">create_time,
|
||||
</if>
|
||||
<if test="updateBy != null">update_by,
|
||||
</if>
|
||||
<if test="updateTime != null">update_time,
|
||||
</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="userId != null">#{userId},
|
||||
</if>
|
||||
<if test="examRegistrationId != null">#{examRegistrationId},
|
||||
</if>
|
||||
<if test="refundNo != null">#{refundNo},
|
||||
</if>
|
||||
<if test="outRefundNo != null">#{outRefundNo},
|
||||
</if>
|
||||
<if test="transactionNo != null">#{transactionNo},
|
||||
</if>
|
||||
<if test="refundReason != null">#{refundReason},
|
||||
</if>
|
||||
<if test="refundType != null">#{refundType},
|
||||
</if>
|
||||
<if test="wechatRefundStatus != null">#{wechatRefundStatus},
|
||||
</if>
|
||||
<if test="alipayRefundStatus != null">#{alipayRefundStatus},
|
||||
</if>
|
||||
<if test="orderTotalPrice != null">#{orderTotalPrice},
|
||||
</if>
|
||||
<if test="refundPrice != null">#{refundPrice},
|
||||
</if>
|
||||
<if test="currency != null">#{currency},
|
||||
</if>
|
||||
<if test="channel != null">#{channel},
|
||||
</if>
|
||||
<if test="userreceivedaccount != null">#{userreceivedaccount},
|
||||
</if>
|
||||
<if test="successTime != null">#{successTime},
|
||||
</if>
|
||||
<if test="refundNotifyContent != null">#{refundNotifyContent},
|
||||
</if>
|
||||
<if test="applyRefundReturnContent != null">#{applyRefundReturnContent},
|
||||
</if>
|
||||
<if test="refundMerchantType != null">#{refundMerchantType},
|
||||
</if>
|
||||
<if test="delFlag != null">#{delFlag},
|
||||
</if>
|
||||
<if test="createBy != null">#{createBy},
|
||||
</if>
|
||||
<if test="createTime != null">#{createTime},
|
||||
</if>
|
||||
<if test="updateBy != null">#{updateBy},
|
||||
</if>
|
||||
<if test="updateTime != null">#{updateTime},
|
||||
</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="updateRefundInfo" parameterType="com.yf.exam.modules.payment.entity.RefundInfo">
|
||||
update refund_info
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="userId != null">user_id =
|
||||
#{userId},
|
||||
</if>
|
||||
<if test="examRegistrationId != null">exam_registration_id =
|
||||
#{examRegistrationId},
|
||||
</if>
|
||||
<if test="refundNo != null">refund_no =
|
||||
#{refundNo},
|
||||
</if>
|
||||
<if test="outRefundNo != null">out_refund_no =
|
||||
#{outRefundNo},
|
||||
</if>
|
||||
<if test="transactionNo != null">transaction_no =
|
||||
#{transactionNo},
|
||||
</if>
|
||||
<if test="refundReason != null">refund_reason =
|
||||
#{refundReason},
|
||||
</if>
|
||||
<if test="refundType != null">refund_type =
|
||||
#{refundType},
|
||||
</if>
|
||||
<if test="wechatRefundStatus != null">wechat_refund_status =
|
||||
#{wechatRefundStatus},
|
||||
</if>
|
||||
<if test="alipayRefundStatus != null">alipay_refund_status =
|
||||
#{alipayRefundStatus},
|
||||
</if>
|
||||
<if test="orderTotalPrice != null">order_total_price =
|
||||
#{orderTotalPrice},
|
||||
</if>
|
||||
<if test="refundPrice != null">refund_price =
|
||||
#{refundPrice},
|
||||
</if>
|
||||
<if test="currency != null">currency =
|
||||
#{currency},
|
||||
</if>
|
||||
<if test="channel != null">channel =
|
||||
#{channel},
|
||||
</if>
|
||||
<if test="userreceivedaccount != null">userReceivedAccount =
|
||||
#{userreceivedaccount},
|
||||
</if>
|
||||
<if test="successTime != null">success_time =
|
||||
#{successTime},
|
||||
</if>
|
||||
<if test="refundNotifyContent != null">refund_notify_content =
|
||||
#{refundNotifyContent},
|
||||
</if>
|
||||
<if test="applyRefundReturnContent != null">apply_refund_return_content =
|
||||
#{applyRefundReturnContent},
|
||||
</if>
|
||||
<if test="refundMerchantType != null">refund_merchant_type =
|
||||
#{refundMerchantType},
|
||||
</if>
|
||||
<if test="delFlag != null">del_flag =
|
||||
#{delFlag},
|
||||
</if>
|
||||
<if test="createBy != null">create_by =
|
||||
#{createBy},
|
||||
</if>
|
||||
<if test="createTime != null">create_time =
|
||||
#{createTime},
|
||||
</if>
|
||||
<if test="updateBy != null">update_by =
|
||||
#{updateBy},
|
||||
</if>
|
||||
<if test="updateTime != null">update_time =
|
||||
#{updateTime},
|
||||
</if>
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="deleteRefundInfoById" parameterType="Long">
|
||||
delete
|
||||
from refund_info
|
||||
where id = #{id}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteRefundInfoByIds" parameterType="String">
|
||||
delete from refund_info where id in
|
||||
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<update id="updateRefundInfoByNo" parameterType="com.yf.exam.modules.payment.entity.RefundInfo">
|
||||
update refund_info
|
||||
set wechat_refund_status = #{wechatRefundStatus},
|
||||
success_time = #{successTime},
|
||||
refund_notify_content = #{refundNotifyContent},
|
||||
update_time = now()
|
||||
where exam_registration_id = #{examRegistrationId}
|
||||
and out_refund_no = #{outRefundNo}
|
||||
and wechat_refund_status <> #{wechatRefundStatus}
|
||||
</update>
|
||||
|
||||
<update id="updateBatchRefundStatus">
|
||||
UPDATE refund_info
|
||||
SET wechat_refund_status = #{weChatRefundStatus},
|
||||
success_time = #{successTime},
|
||||
update_time = now()
|
||||
WHERE del_flag = 0
|
||||
and exam_registration_id = #{examRegistrationId}
|
||||
and wechat_refund_status <> #{weChatRefundStatus}
|
||||
</update>
|
||||
|
||||
<select id="getRefundInfoByexamRegistrationId" parameterType="string" resultType="int">
|
||||
select count(1) refundCount
|
||||
from refund_info
|
||||
where exam_registration_id = #{examRegistrationId}
|
||||
</select>
|
||||
</mapper>
|
||||
Loading…
Reference in New Issue
Block a user