Commit 580a17ec by wuwenlong

order refund dev;

parent 2ff0d567
package com.zbkj.admin.controller;
package share.web.controller.system;
import com.zbkj.service.service.CallbackService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
......@@ -9,6 +8,7 @@ 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;
import share.system.service.CallbackService;
import javax.servlet.http.HttpServletRequest;
......
......@@ -2,21 +2,18 @@ package share.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import share.common.annotation.Log;
import share.common.core.controller.BaseController;
import share.common.core.domain.AjaxResult;
import share.common.enums.BusinessType;
import share.system.domain.SOrder;
import share.system.request.OrderRefundRequest;
import share.system.service.ISOrderService;
import share.common.utils.poi.ExcelUtil;
import share.common.core.page.TableDataInfo;
......@@ -101,4 +98,15 @@ public class SOrderController extends BaseController
{
return toAjax(sOrderService.deleteSOrderByIds(ids));
}
/**
* 退款
*/
@PreAuthorize("hasAuthority('system:order:refund')")
@ApiOperation(value = "退款")
@RequestMapping(value = "/refund", method = RequestMethod.GET)
public AjaxResult<Boolean> refund(@Validated OrderRefundRequest request) {
return toAjax(sOrderService.refundAudit(request));
}
}
......@@ -10,7 +10,7 @@ import share.common.utils.StringUtils;
*
* @author ruoyi
*/
public class AjaxResult extends HashMap<String, Object>
public class AjaxResult<T> extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L;
......@@ -23,6 +23,8 @@ public class AjaxResult extends HashMap<String, Object>
/** 数据对象 */
public static final String DATA_TAG = "data";
private T data;
/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
......@@ -49,7 +51,7 @@ public class AjaxResult extends HashMap<String, Object>
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(int code, String msg, Object data)
public AjaxResult(int code, String msg, T data)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
......@@ -97,7 +99,7 @@ public class AjaxResult extends HashMap<String, Object>
* @param data 数据对象
* @return 成功消息
*/
public static AjaxResult success(String msg, Object data)
public static <T> AjaxResult<T> success(String msg, T data)
{
return new AjaxResult(HttpStatus.SUCCESS, msg, data);
}
......@@ -120,7 +122,7 @@ public class AjaxResult extends HashMap<String, Object>
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult warn(String msg, Object data)
public static <T> AjaxResult<T> warn(String msg, T data)
{
return new AjaxResult(HttpStatus.WARN, msg, data);
}
......@@ -153,7 +155,7 @@ public class AjaxResult extends HashMap<String, Object>
* @param data 数据对象
* @return 错误消息
*/
public static AjaxResult error(String msg, Object data)
public static <T> AjaxResult<T> error(String msg, T data)
{
return new AjaxResult(HttpStatus.ERROR, msg, data);
}
......
package share.common.enums;
import share.common.utils.StringUtils;
/**
* @Author wwl
* @Date 2023/10/20 10:57
......@@ -28,6 +30,17 @@ public enum PayTypeEnum {
return null;
}
public static PayTypeEnum getEnumByValue(String value){
if(StringUtils.isNotBlank(value)) {
for (PayTypeEnum type : PayTypeEnum.values()) {
if (StringUtils.equals(type.value, value)) {
return type;
}
}
}
return null;
}
public Integer getCode(){
return code;
}
......
......@@ -5,9 +5,10 @@ package share.common.enums;
* @Date 2023/10/20 10:57
*/
public enum RefundStatusEnum {
UNREFUND(0,"未退款"),
INREFUND(1,"退款中"),
REFUNDED(2,"已退款");
UNREFUND(0, "未退款"),
APPLY(1, "申请中"),
INREFUND(2, "退款中"),
REFUNDED(3, "已退款");
private Integer code;
private String name;
......@@ -26,6 +27,10 @@ public enum RefundStatusEnum {
return null;
}
public static Integer[] getNotRefundStatus(){
return new Integer[]{UNREFUND.getCode(), APPLY.getCode()};
}
public Integer getCode(){
return code;
}
......
......@@ -7,6 +7,7 @@ import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import share.common.constant.Constants;
import share.common.enums.PayTypeEnum;
import share.common.exception.base.BaseException;
import javax.crypto.Cipher;
......@@ -741,8 +742,9 @@ public class BaseUtil {
* @return 生成的随机码
*/
public static String getOrderNoPrefix(String payType){
switch (payType){
case Constants.PAY_TYPE_WE_CHAT:
PayTypeEnum payTypeEnum = PayTypeEnum.getEnumByValue(payType);
switch (payTypeEnum){
case WECHAT:
return Constants.ORDER_NO_PREFIX_WE_CHAT;
//其他平台
default:
......
......@@ -13,13 +13,20 @@ import org.springframework.transaction.support.TransactionTemplate;
import share.common.constant.Constants;
import share.common.core.redis.RedisUtil;
import share.common.enums.CouponStatusEnum;
import share.common.enums.RefundStatusEnum;
import share.common.enums.YesNoEnum;
import share.common.exception.base.BaseException;
import share.system.domain.SConsumer;
import share.system.domain.SConsumerCoupon;
import share.system.domain.SOrder;
import share.system.service.ISConsumerCouponService;
import share.system.service.ISOrderService;
import share.system.service.ISysConfigService;
import share.system.service.SConsumerService;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @Author wwl
......@@ -34,6 +41,9 @@ public class OrderTask {
private RedisUtil redisUtil;
@Autowired
private SConsumerService sConsumerService;
@Autowired
private ISysConfigService sysConfigService;
@Autowired
......@@ -111,4 +121,79 @@ public class OrderTask {
});
return execute;
}
/**
* 执行 用户退款申请
* @author Mr.Zhang
* @since 2020-07-09
*/
public void refundApply() {
String redisKey = Constants.ORDER_TASK_REDIS_KEY_AFTER_REFUND_BY_USER;
Long size = redisUtil.getListSize(redisKey);
logger.info("OrderTask.refundApply | size:" + size);
if (size < 1) {
return;
}
for (int i = 0; i < size; i++) {
//如果10秒钟拿不到一个数据,那么退出循环
Object orderId = redisUtil.getRightPop(redisKey, 10L);
if (null == orderId) {
continue;
}
try {
SOrder sOrder = orderService.getById(Integer.valueOf(orderId.toString()));
if (ObjectUtil.isNull(sOrder)) {
throw new BaseException("订单不存在,orderNo = " + orderId);
}
boolean result = refundOrder(sOrder);
if (!result) {
logger.error("订单退款错误:result = " + result);
redisUtil.lPush(redisKey, orderId);
}
} catch (Exception e) {
logger.error("订单退款错误:" + e.getMessage());
redisUtil.lPush(redisKey, orderId);
}
}
}
/**
* 订单退款处理
*/
public Boolean refundOrder(SOrder sOrder) {
// 获取用户对象
SConsumer user = sConsumerService.getById(sOrder.getConsumerId());
if (ObjectUtil.isNull(user)) {
logger.error("订单退款处理,对应的用户不存在,sOrder===>" + sOrder);
return Boolean.FALSE;
}
SOrder tempOrder = new SOrder();
tempOrder.setId(sOrder.getId());
tempOrder.setRefundStatus(RefundStatusEnum.REFUNDED.getCode());
Boolean execute = Boolean.FALSE;
try {
execute = transactionTemplate.execute(e -> {
orderService.updateById(tempOrder);
logger.info("=================开始处理优惠券退款=================");
logger.info("=================" + sOrder.getId() + "=================");
logger.info("=================" + sOrder.getCouponId() + "=================");
logger.info("=================================================");
// 退优惠券
if (Objects.nonNull(sOrder) && sOrder.getCouponId() > 0) {
SConsumerCoupon couponUser = consumerCouponService.getById(sOrder.getCouponId());
couponUser.setUseStatus(CouponStatusEnum.NORMAL.getValue());
consumerCouponService.updateById(couponUser);
}
return true;
});
} catch (Exception e) {
logger.error("订单退款处理失败");
logger.error(e.toString());
}
return execute;
}
}
......@@ -113,7 +113,7 @@ public class SOrder extends BaseEntity
@Excel(name = "订单状态(0:待使用/已预约,1:使用中,2:已使用)")
private Integer status;
@ApiModelProperty(value = "0 未退款 1 申请中 2 已退款 3 退款中")
@ApiModelProperty(value = "0 未退款 1 申请中 2 退款中 3 已退款 ")
@TableField(value = "refund_status")
private Integer refundStatus;
......
package share.system.request;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
/**
* 订单退款表
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="OrderRefundRequest对象", description="订单退款")
public class OrderRefundRequest {
private static final long serialVersionUID=1L;
@ApiModelProperty(value = "订单编号")
@NotBlank(message = "订单编号不能为空")
private String orderNo;
@ApiModelProperty(value = "退款金额")
@DecimalMin(value = "0.00", message = "退款金额不能少于0.00")
private BigDecimal amount;
@ApiModelProperty(value = "退款状态 0 未退款 1 申请中 2 退款中 3 已退款")
@NotNull(message = "退款状态不能为空")
private Integer refundStatus;
@ApiModelProperty(value = "退款说明")
private String refundReason;
@ApiModelProperty(value = "订单ID")
@NotNull(message = "订单ID不能为空")
private Long orderId;
}
package com.zbkj.service.service;
package share.system.service;
import javax.servlet.http.HttpServletRequest;
......
......@@ -8,6 +8,7 @@ import share.system.domain.SOrder;
import share.system.domain.vo.MyRecord;
import share.system.request.CreateOrderRequest;
import share.system.request.OrderComputedPriceRequest;
import share.system.request.OrderRefundRequest;
import share.system.response.ComputedOrderPriceResponse;
import share.system.response.OrderPayResultResponse;
......@@ -100,4 +101,11 @@ public interface ISOrderService extends IService<SOrder>
String openDoor(Long id);
SOrder getInfoByEntity(SOrder orderParam);
/**
*
* @param request
* @return
*/
boolean refundAudit(OrderRefundRequest request);
}
package share.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import share.system.domain.SOrder;
import share.system.request.OrderRefundRequest;
/**
* OrderRefundService 接口
*/
public interface OrderRefundService extends IService<SOrder> {
void refund(OrderRefundRequest request, SOrder storeOrder);
}
......@@ -14,6 +14,7 @@ import share.common.config.WeChatConfig;
import share.common.constant.Constants;
import share.common.core.redis.RedisUtil;
import share.common.enums.OrderTypeEnum;
import share.common.enums.RefundStatusEnum;
import share.common.enums.YesNoEnum;
import share.common.exception.base.BaseException;
import share.common.utils.BaseUtil;
......@@ -24,8 +25,8 @@ import share.system.domain.WechatPayInfo;
import share.system.domain.vo.AttachVo;
import share.system.domain.vo.CallbackVo;
import share.system.domain.vo.MyRecord;
import share.system.service.CallbackService;
import share.system.service.ISOrderService;
import share.system.service.ISysConfigService;
import share.system.service.SConsumerService;
import share.system.service.WechatPayInfoService;
import share.system.util.WxPayUtil;
......@@ -43,7 +44,7 @@ import java.util.*;
* 订单支付回调 CallbackService 实现类
*/
@Service
public class CallbackServiceImpl implements com.zbkj.service.service.CallbackService {
public class CallbackServiceImpl implements CallbackService {
private static final Logger logger = LoggerFactory.getLogger(CallbackServiceImpl.class);
......@@ -229,11 +230,11 @@ public class CallbackServiceImpl implements com.zbkj.service.service.CallbackSer
logger.error("微信退款订单查询失败==>" + refundRecord.getColumns() + ", rawData==>" + xmlInfo + ", data==>" + notifyRecord);
return refundRecord.getStr("returnXml");
}
if (sOrder.getRefundStatus() == 2) {
if (RefundStatusEnum.REFUNDED.getCode().equals(sOrder.getRefundStatus())) {
logger.warn("微信退款订单已确认成功==>" + refundRecord.getColumns() + ", rawData==>" + xmlInfo + ", data==>" + notifyRecord);
return refundRecord.getStr("returnXml");
}
sOrder.setRefundStatus(2);
sOrder.setRefundStatus(RefundStatusEnum.INREFUND.getCode());
boolean update = sOrderService.updateById(sOrder);
if (update) {
// 退款task
......
package share.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import share.common.config.WeChatConfig;
import share.common.constant.Constants;
import share.common.constant.PayConstants;
import share.common.enums.YesNoEnum;
import share.common.utils.http.RestTemplateUtil;
import share.system.domain.SOrder;
import share.system.domain.vo.WxRefundVo;
import share.system.mapper.SOrderMapper;
import share.system.request.OrderRefundRequest;
import share.system.service.ISysConfigService;
import share.system.service.OrderRefundService;
import share.system.service.WechatNewService;
import share.system.util.WxPayUtil;
import java.math.BigDecimal;
/**
* OrderServiceImpl 接口实现
*/
@Service
public class OrderRefundServiceImpl extends ServiceImpl<SOrderMapper, SOrder> implements OrderRefundService {
@Autowired
private ISysConfigService sysConfigService;
@Autowired
private RestTemplateUtil restTemplateUtil;
@Autowired
private WechatNewService wechatNewService;
@Autowired
private WeChatConfig weChatConfig;
/**
* 退款 需要优化
* @author Mr.Zhang
* @since 2020-06-03
*/
@Override
public void refund(OrderRefundRequest request, SOrder sOrder) {
refundWx(request, sOrder);
}
/**
* 公共号退款
* @param request
* @param sOrder
*/
private void refundWx(OrderRefundRequest request, SOrder sOrder) {
// 获取appid、mch_id
// 微信签名key
String appId = weChatConfig.getAppId();
String mchId = weChatConfig.getMchId();
String signKey = weChatConfig.getSignKey();
String path = "";//TODO 商户证书路径(待提供)
String apiDomain = Constants.CONFIG_KEY_API_URL;
//统一下单数据
WxRefundVo wxRefundVo = new WxRefundVo();
wxRefundVo.setAppid(appId);
wxRefundVo.setMch_id(mchId);
wxRefundVo.setNonce_str(WxPayUtil.getNonceStr());
wxRefundVo.setOut_trade_no(sOrder.getOutTradeNo());
wxRefundVo.setOut_refund_no(sOrder.getOrderNo());
wxRefundVo.setTotal_fee(sOrder.getPayPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
wxRefundVo.setRefund_fee(request.getAmount().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
wxRefundVo.setNotify_url(apiDomain + PayConstants.WX_PAY_REFUND_NOTIFY_API_URI);
String sign = WxPayUtil.getSign(wxRefundVo, signKey);
wxRefundVo.setSign(sign);
wechatNewService.payRefund(wxRefundVo, path);
}
}
......@@ -10,6 +10,7 @@ import java.util.stream.Collectors;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
......@@ -40,6 +41,7 @@ import share.system.mapper.SOrderMapper;
import share.system.domain.SOrder;
import share.system.request.CreateOrderRequest;
import share.system.request.OrderComputedPriceRequest;
import share.system.request.OrderRefundRequest;
import share.system.response.ComputedOrderPriceResponse;
import share.system.response.OrderPayResultResponse;
import share.system.service.*;
......@@ -67,6 +69,9 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper,SOrder> implemen
private ISConsumerCouponService consumerCouponService;
@Autowired
private OrderRefundService orderRefundService;
@Autowired
private ISRoomService roomService;
@Autowired
......@@ -154,6 +159,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper,SOrder> implemen
LambdaQueryWrapper<SOrder> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SOrder::getStoreId,storeId);
queryWrapper.eq(SOrder::getRoomId,roomId);
queryWrapper.notIn(SOrder::getRefundStatus,RefundStatusEnum.getNotRefundStatus());
String nowDayStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,day);
String nextDayStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,DateUtils.addDays(day,1));
queryWrapper.apply("(DATE_FORMAT(IFNULL(start_date,pre_start_date), '%Y-%m-%d') = '"+nowDayStr+"' " +
......@@ -191,6 +197,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper,SOrder> implemen
private void checkOrderDate(CreateOrderRequest request) {
LambdaQueryWrapper<SOrder> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.notIn(SOrder::getRefundStatus, RefundStatusEnum.getNotRefundStatus());
//订单开始时间在 【预定开始时间 和 预定结束时间+30分保洁】区间内
//订单结束时间在 【预定开始时间-30分钟保洁 和 预定结束时间】区间内
queryWrapper.apply("IFNULL(start_date,pre_start_date) BETWEEN '"
......@@ -277,6 +284,64 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper,SOrder> implemen
return getOne(lambdaQueryWrapper);
}
@DSTransactional
@Override
public boolean refundAudit(OrderRefundRequest request) {
SOrder sOrder = getInfoException(request.getOrderNo());
if (!YesNoEnum.yes.getIndex().equals(sOrder.getPayStatus())) {
throw new BaseException("未支付无法退款");
}
if (sOrder.getRefundPrice().add(request.getAmount()).compareTo(sOrder.getPayPrice()) > 0) {
throw new BaseException("退款金额大于支付金额,请修改退款金额");
}
if (request.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
if (sOrder.getPayPrice().compareTo(BigDecimal.ZERO) != 0) {
throw new BaseException("退款金额不能为0,请修改退款金额");
}
}
request.setOrderId(sOrder.getId());
//退款
if (sOrder.getPayType().equals(PayTypeEnum.WECHAT.getValue()) && request.getAmount().compareTo(BigDecimal.ZERO) > 0) {
try {
orderRefundService.refund(request, sOrder);
} catch (Exception e) {
e.printStackTrace();
throw new BaseException("微信申请退款失败!");
}
}
//修改订单退款状态,为退款中
sOrder.setRefundStatus(RefundStatusEnum.INREFUND.getCode());
sOrder.setRefundPrice(request.getAmount());
Boolean execute = Boolean.FALSE;
try {
updateById(sOrder);
//微信退款
if (sOrder.getPayType().equals(PayTypeEnum.WECHAT.getValue()) && request.getAmount().compareTo(BigDecimal.ZERO) == 0) {
// 退款task
redisUtil.lPush(Constants.ORDER_TASK_REDIS_KEY_AFTER_REFUND_BY_USER, sOrder.getId());
}
execute = Boolean.TRUE;
} catch (Exception e) {
logger.error("退款出错");
logger.error(e.toString());
}
if (!execute) {
throw new BaseException("订单更新失败");
}
return execute;
}
private SOrder getInfoException(String orderNo) {
LambdaQueryWrapper<SOrder> lqw = Wrappers.lambdaQuery();
lqw.eq(SOrder::getOrderNo, orderNo);
lqw.eq(SOrder::getIsDelete, 0);
SOrder sOrder = getOne(lqw);
if (ObjectUtil.isNull(sOrder)) {
throw new BaseException("没有找到订单信息");
}
return sOrder;
}
@Override
public String openDoor(Long id) {
SOrder sOrder = sOrderMapper.selectSOrderById(id);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment