订单退款

This commit is contained in:
wangw 2025-02-25 14:15:13 +08:00
parent fd7ebd0d75
commit 691f12753e
10 changed files with 127 additions and 114 deletions

View File

@ -1,19 +1,14 @@
package com.czg.controller.admin;
import com.czg.order.dto.OrderInfoAddDTO;
import com.czg.order.dto.OrderInfoQueryDTO;
import com.czg.order.dto.OrderInfoRefundDTO;
import com.czg.order.entity.OrderInfo;
import com.czg.order.service.OrderInfoService;
import com.czg.order.vo.HistoryOrderVo;
import com.czg.order.vo.OrderInfoVo;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.utils.ServletUtil;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
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.RestController;
/**
@ -32,31 +27,24 @@ public class AdminOrderController {
/**
* 订单列表
*/
@PostMapping
public CzgResult<Page<OrderInfoVo>> getOrderPage(@RequestBody OrderInfoQueryDTO queryDTO) {
queryDTO.setShopId(StpKit.USER.getShopId());
return CzgResult.success(orderInfoService.getOrderByPage(queryDTO));
}
@GetMapping("/historyOrder")
public CzgResult<HistoryOrderVo> historyOrder(Long orderId) {
return CzgResult.success(orderInfoService.historyOrder(orderId));
}
@PostMapping("/createOrder")
public CzgResult<OrderInfo> createOrder(@Validated @RequestBody OrderInfoAddDTO addDto) {
addDto.setPlatformType(ServletUtil.getHeaderIgnoreCase(ServletUtil.getRequest(), "platformType"));
addDto.setStaffId(StpKit.USER.getLoginIdAsLong());
addDto.setShopId(StpKit.USER.getShopId());
addDto.setOrderType("cash");
return CzgResult.success(orderInfoService.createOrder(addDto));
}
// @PostMapping("/updateOrder")
// public CzgResult<OrderInfo> updateOrder(@Validated @RequestBody OrderInfoUpDTO upDTO) {
// AssertUtil.isListEmpty(upDTO.getDetailList(), "订单详情不能为空");
// orderInfoService.updateOrder(upDTO);
// return CzgResult.success();
// @PostMapping
// public CzgResult<Page<OrderInfoVo>> getOrderPage(@RequestBody OrderInfoQueryDTO queryDTO) {
// queryDTO.setShopId(StpKit.USER.getShopId());
// return CzgResult.success(orderInfoService.getOrderByPage(queryDTO));
// }
//
// @GetMapping("/historyOrder")
// public CzgResult<HistoryOrderVo> historyOrder(Long orderId) {
// return CzgResult.success(orderInfoService.historyOrder(orderId));
// }
//
// @PostMapping("/createOrder")
// public CzgResult<OrderInfo> createOrder(@Validated @RequestBody OrderInfoAddDTO addDto) {
// addDto.setPlatformType(ServletUtil.getHeaderIgnoreCase(ServletUtil.getRequest(), "platformType"));
// addDto.setStaffId(StpKit.USER.getLoginIdAsLong());
// addDto.setShopId(StpKit.USER.getShopId());
// addDto.setOrderType("cash");
// return CzgResult.success(orderInfoService.createOrder(addDto));
// }
/**

View File

@ -33,7 +33,7 @@ public class UserOrderController {
*/
@PostMapping
public CzgResult<Page<OrderInfoVo>> getOrderPage(@RequestBody OrderInfoQueryDTO queryDTO) {
queryDTO.setIsDel(1);
queryDTO.setIsDel(0);
queryDTO.setUserId(StpKit.USER.getLoginIdAsLong());
return CzgResult.success(orderInfoService.getOrderByPage(queryDTO));
}

View File

@ -88,4 +88,9 @@ public class ShopUserFlowDTO implements Serializable {
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
/**
* 退款失败原因
*/
private String failMsg;
}

View File

@ -86,6 +86,10 @@ public class ShopUserFlow implements Serializable {
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
/**
* 退款失败原因
*/
private String failMsg;
public BigDecimal getAmount() {

View File

@ -254,5 +254,6 @@ public class OrderInfoDTO implements Serializable {
* 是否回收站 0-1回收站
*/
private Integer isDel;
private String failMsg;
}

View File

@ -264,6 +264,8 @@ public class OrderInfo implements Serializable {
*/
private Integer isDel;
private String failMsg;
public String getRefundRemark() {
return StrUtil.isBlank(refundRemark) ? "" : refundRemark + " ";

View File

@ -27,8 +27,6 @@ public interface OrderInfoService extends IService<OrderInfo> {
HistoryOrderVo historyOrder(Long orderId);
OrderInfo createOrder(OrderInfoAddDTO param);
// void updateOrder(OrderInfoUpDTO upDTO);
OrderInfo checkOrderPay(CheckOrderPay param);
CzgResult<Object> refundOrder(OrderInfoRefundDTO param);

View File

@ -21,14 +21,17 @@ public interface PayService {
* 挂账
*/
CzgResult<Object> creditPayOrder(OrderPayParamDTO payParam);
/**
* 现金支付
*/
CzgResult<Object> cashPayOrder(OrderPayParamDTO payParam);
/**
* 会员支付
*/
CzgResult<Object> vipPayOrder(OrderPayParamDTO payParam);
/**
* h5支付
*/
@ -94,7 +97,7 @@ public interface PayService {
/**
* 订单退款
*/
CzgResult<CzgRefundResp> refundOrder(Long shopId, Long orderId, String refundReason, BigDecimal refundAmount);
CzgResult<Object> refundOrder(Long shopId, Long orderId, Long payOrderId, String refPayOrderNo, String refundReason, BigDecimal refundAmount);
/**

View File

@ -32,6 +32,7 @@ import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.service.order.enums.OrderStatusEnums;
import com.czg.service.order.mapper.OrderInfoMapper;
import com.czg.service.order.service.PayService;
import com.czg.utils.AssertUtil;
import com.czg.utils.CzgStrUtils;
import com.czg.utils.PageUtil;
@ -70,6 +71,8 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
private CashierCartService cartService;
@Resource
private OrderDetailService detailService;
@Resource
private PayService payService;
@DubboReference
private ShopInfoService shopInfoService;
@DubboReference
@ -77,6 +80,8 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
@DubboReference
private ShopUserService shopUserService;
@DubboReference
private ShopUserFlowService flowService;
@DubboReference
private ShopTableService shopTableService;
@DubboReference
private ShopActivateService activateService;
@ -202,44 +207,6 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
return orderInfo;
}
// @Override
// @Transactional
// public void updateOrder(OrderInfoUpDTO upDTO) {
// OrderInfo orderInfo = getById(upDTO.getOrderId());
// AssertUtil.isNull(orderInfo, "订单不存在");
// ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
// AssertUtil.isNull(shopInfo, "店铺不存在");
// BigDecimal totalAmount = BigDecimal.ZERO;
// BigDecimal packAmount = BigDecimal.ZERO;
// List<Long> collect = upDTO.getDetailList().stream().map(OrderDetail::getId).toList();
// List<OrderDetail> orderDetails = detailService.queryChain().eq(OrderDetail::getOrderId, orderInfo.getId()).select().list();
// List<OrderDetail> updateList = new ArrayList<>();
// List<Long> removeList = new ArrayList<>();
// for (OrderDetail orderDetail : orderDetails) {
// if (!collect.contains(orderDetail.getId())) {
// removeList.add(orderDetail.getId());
// break;
// }
// OrderDetail detail = new OrderDetail();
// detail.setId(orderDetail.getId());
// detail.setNum(orderDetail.getNum());
// detail.setPackNumber(orderDetail.getPackNumber());
// detail.setIsWaitCall(orderDetail.getIsWaitCall());
// detail.setRemark(orderDetail.getRemark());
// detail.setPayAmount(orderDetail.getNum().multiply(detail.getPrice()));
// packAmount = packAmount.add(detail.getPackAmount().multiply(detail.getPackNumber()));
// totalAmount = totalAmount.add(detail.getPayAmount());
// }
// detailService.updateBatch(updateList);
// detailService.removeByIds(removeList);
// orderInfo.setPackFee(packAmount);
// orderInfo.setOriginAmount(totalAmount.add(orderInfo.getSeatAmount()));
//
// orderInfo.setSeatNum(upDTO.getSeatNum());
// orderInfo.setSeatAmount(shopInfo.getTableFee().multiply(new BigDecimal(upDTO.getSeatNum())));
// updateById(orderInfo);
// }
@Override
public OrderInfo checkOrderPay(CheckOrderPay param) {
OrderInfo orderInfo = getById(param.getOrderId());
@ -267,18 +234,24 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
//商品券 <商品id数量>
Map<Long, Integer> prodCouponMap = new HashMap<>();
//满减券 满fullCouponAmount 减disCouponAmount
BigDecimal fullAmount = BigDecimal.ZERO;
BigDecimal discountAmount = BigDecimal.ZERO;
String fullAmountStr = "";
String discountAmountStr = "";
//校验优惠券
checkCoupon(prodCouponMap, fullAmount, discountAmount, param);
checkCoupon(prodCouponMap, fullAmountStr, discountAmountStr, param);
BigDecimal fullAmount = new BigDecimal(fullAmountStr);
BigDecimal discountAmount = new BigDecimal(discountAmountStr);
//获取商品信息 计算金额 需要传入优惠券 减去优惠券
List<OrderDetail> orderDetails = orderDetailService.queryChain().eq(OrderDetail::getOrderId, param.getOrderId()).select().list();
//商品优惠券金额
BigDecimal prodCouponAmount = BigDecimal.ZERO;
String prodCouponAmountStr = "";
//总商品支付金额 不包含打包费 用来计算后续
BigDecimal totalAmount = BigDecimal.ZERO;
processOrderDetails2(orderDetails, prodCouponMap, prodCouponAmount, totalAmount);
String totalAmountStr = "";
processOrderDetails2(orderDetails, prodCouponMap, prodCouponAmountStr, totalAmountStr);
BigDecimal prodCouponAmount = new BigDecimal(prodCouponAmountStr);
//总商品支付金额 不包含打包费 用来计算后续
BigDecimal totalAmount = new BigDecimal(totalAmountStr);
log.info("支付前置,商品金额{} 商品优惠券金额{} 总金额{}", totalAmount, prodCouponAmount, totalAmount.add(orderInfo.getPackFee()));
if (prodCouponAmount.compareTo(param.getProductCouponDiscountAmount()) != 0) {
throw new ValidateException("生成支付订单失败,商品优惠券优惠金额不正确");
}
@ -337,8 +310,10 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
//退优惠券数量 <商品id数量>
Map<Long, Integer> returnCouponMap = new HashMap<>();
boolean isPay = true;
String refPayOrderNo = "REFO" + IdUtil.getSnowflakeNextId();
if (orderInfo.getStatus().equals(OrderStatusEnums.UNPAID.getCode())) {
isPay = false;
refPayOrderNo = "";
}
if (CollUtil.isNotEmpty(param.getRefundDetails())) {
for (OrderDetail refundDetail : param.getRefundDetails()) {
@ -366,7 +341,7 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
}
}
if (refundAmount.compareTo(refundDetail.getReturnAmount()) != 0) {
throw new ValidateException("退单失败," + refundDetail.getProductName() + "退单金额不正确");
throw new ValidateException("退单失败," + orderDetail.getProductName() + "退单金额不正确");
}
refNum = refundDetail.getNum();
refundAmountTotal = refundAmountTotal.add(refundAmount);
@ -374,33 +349,49 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
orderDetail.setRefundNum(orderDetail.getRefundNum().add(refNum));
orderDetail.setReturnAmount(orderDetail.getReturnAmount().add(refundDetail.getReturnAmount()));
if (orderDetail.getReturnAmount().compareTo(orderDetail.getPayAmount()) > 0) {
throw new ValidateException("退单失败," + refundDetail.getProductName() + "退单金额不正确");
throw new ValidateException("退单失败," + orderDetail.getProductName() + "退单金额不正确");
}
} else {
orderDetail.setReturnNum(orderDetail.getRefundNum().add(refNum));
orderDetail.setPayAmount((orderDetail.getNum().subtract(orderDetail.getRefundNum()).subtract(orderDetail.getReturnNum())
.subtract(orderDetail.getCouponNum())).multiply(orderDetail.getPrice()));
}
orderDetail.setRefundRemark(refundDetail.getRefundRemark() + param.getRefundReason());
orderDetail.setRefundNo(refPayOrderNo);
orderDetail.setRefundRemark(orderDetail.getRefundRemark() + param.getRefundReason());
detailService.updateById(orderDetail);
}
} else {
refundAmountTotal = param.getRefundAmount();
}
if (param.isModify()) {
orderInfo.setOrderAmount(orderInfo.getOrderAmount().subtract(param.getRefundAmount()));
if (orderInfo.getOrderAmount().compareTo(BigDecimal.ZERO) < 0) {
throw new ValidateException("退单失败,订单金额不正确");
}
}
//总退款金额
//TODO 退款 未处理
if (isPay) {
orderInfo.setRefundAmount(orderInfo.getRefundAmount().add(refundAmountTotal));
orderInfo.setRefundRemark(orderInfo.getRefundRemark() + param.getRefundReason());
//退钱 refundAmountTotal
if (param.isModify()) {
orderInfo.setRefundAmount(orderInfo.getRefundAmount().add(param.getRefundAmount()));
if (orderInfo.getRefundAmount().compareTo(orderInfo.getPayAmount()) < 0) {
throw new ValidateException("退单失败,可退金额不足");
}
//退款 param.getRefundAmount()
payService.refundOrder(orderInfo.getShopId(), orderInfo.getId(), orderInfo.getPayOrderId(),
refPayOrderNo, param.getRefundReason(), param.getRefundAmount());
} else {
if (refundAmountTotal.compareTo(param.getRefundAmount()) != 0) {
throw new ValidateException("退单失败,退款金额不正确");
}
orderInfo.setRefundAmount(orderInfo.getRefundAmount().add(refundAmountTotal));
if (orderInfo.getRefundAmount().compareTo(orderInfo.getPayAmount()) < 0) {
throw new ValidateException("退单失败,可退金额不足");
}
//退款 refundAmountTotal
payService.refundOrder(orderInfo.getShopId(), orderInfo.getId(), orderInfo.getPayOrderId(),
refPayOrderNo, param.getRefundReason(), refundAmountTotal);
}
} else {
orderInfo.setOrderAmount(orderInfo.getOrderAmount().subtract(refundAmountTotal));
}
return null;
orderInfo.setRefundRemark(orderInfo.getRefundRemark() + param.getRefundReason());
updateById(orderInfo);
return CzgResult.success();
}
/**
@ -424,13 +415,15 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
/**
* 填充 优惠券使用数量 以及 付款金额
*
* @param orderDetails 订单详情 需要回填 优惠券抵扣数量
* @param prodCouponMap 使用优惠券<商品id,数量>
* @param prodCouponAmount 商品券优惠金额 商品单价*优惠数量 的总和
* @param totalAmount 最终总金额没加打包费 餐位费 去除优惠券金额后的
* @param orderDetails 订单详情 需要回填 优惠券抵扣数量
* @param prodCouponMap 使用优惠券<商品id,数量>
* @param prodCouponAmountStr 商品券优惠金额 商品单价*优惠数量 的总和
* @param totalAmountStr 最终总金额没加打包费 餐位费 去除优惠券金额后的
*/
private void processOrderDetails2(List<OrderDetail> orderDetails, Map<Long, Integer> prodCouponMap,
BigDecimal prodCouponAmount, BigDecimal totalAmount) {
String prodCouponAmountStr, String totalAmountStr) {
BigDecimal prodCouponAmount = BigDecimal.ZERO;
BigDecimal totalAmount = BigDecimal.ZERO;
Map<Long, List<OrderDetail>> detailMap = new HashMap<>();
for (OrderDetail detail : orderDetails) {
detailMap.computeIfAbsent(detail.getProductId(), k -> new ArrayList<>()).add(detail);
@ -470,13 +463,16 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
}
}
orderDetails = resultList;
//值传递问题
prodCouponAmountStr = prodCouponAmount.toPlainString();
totalAmountStr = totalAmount.toPlainString();
}
/**
* 校验优惠券可用性
*/
private void checkCoupon(Map<Long, Integer> prodCouponMap, BigDecimal fullAmount, BigDecimal discountAmount, CheckOrderPay param) {
private void checkCoupon(Map<Long, Integer> prodCouponMap, String fullAmountStr, String discountAmountStr, CheckOrderPay param) {
if (CollUtil.isNotEmpty(param.getCouponList())) {
//校验优惠券
List<ShopActivateCouponRecord> records = couponRecordService.list(QueryWrapper.create()
@ -493,14 +489,14 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
if (isFullMinus) {
throw new ValidateException("生成支付订单失败,满减券仅可使用一张");
}
fullAmount = record.getFullAmount();
discountAmount = record.getDiscountAmount();
fullAmountStr = record.getFullAmount().toPlainString();
discountAmountStr = record.getDiscountAmount().toPlainString();
isFullMinus = true;
} else if (record.getType().equals(2)) {
prodCouponMap.compute(record.getProId(), (key, oldValue) -> oldValue == null ? 1 : oldValue + 1);
}
}
if (discountAmount.compareTo(param.getFullCouponDiscountAmount()) != 0) {
if (new BigDecimal(discountAmountStr).compareTo(param.getFullCouponDiscountAmount()) != 0) {
throw new ValidateException("生成支付订单失败,满减券减免金额不正确");
}
}
@ -522,6 +518,7 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
OrderInfo orderInfo = getById(payment.getSourceId());
if (orderInfo == null) {
log.error("订单支付回调失败,订单不存在,支付记录Id,{}", payment.getId());
return;
}
upOrderInfo(orderInfo, new BigDecimal(czgCallBackDto.getAmount() / 100L),
DateUtil.parseLocalDateTime(czgCallBackDto.getPayTime()), payment.getId(), null);
@ -571,9 +568,17 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
.update();
if (!"SUCCESS".equals(czgCallBackDto.getState())) {
if ("refund".equals(payment.getPayType())) {
//订单退款回滚
//TODO 订单退款失败 暂不考虑回滚 填充退款原因
updateChain()
.set(OrderInfo::getRefundRemark, czgCallBackDto.getRefundReason())
.eq(OrderInfo::getId, payment.getSourceId())
.update();
} else if ("memberRefund".equals(payment.getPayType())) {
//会员退款回滚
//TODO 会员退款 暂不考虑回滚( 赠送金额 赠送的券) 填充退款原因
flowService
.updateChain()
.set(ShopUserFlow::getFailMsg, czgCallBackDto.getRefundReason())
.eq(ShopUserFlow::getId, payment.getSourceId()).update();
}
}
}
@ -653,6 +658,7 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
}
orderInfo.setPlaceNum(param.getPlaceNum());
orderInfo.setOriginAmount(orderInfo.getOriginAmount().add(param.getOriginAmount()).add(orderInfo.getSeatAmount()));
orderInfo.setOrderAmount(orderInfo.getOriginAmount());
orderInfo.setPackFee(orderInfo.getPackFee().add(param.getPackFee()));
orderInfo.setRoundAmount(BigDecimal.ZERO);
orderInfo.setPointsNum(0);

View File

@ -352,7 +352,7 @@ public class PayServiceImpl implements PayService {
} else {
return CzgResult.failure("退款失败,该充值记录不存在");
}
String refPayOrderNo = "REF" + refPayParam.getPlatformType() + IdUtil.getSnowflakeNextId();
String refPayOrderNo = "REFVIP" + IdUtil.getSnowflakeNextId();
refPaymentId = initOrderPayment(new OrderPayment(refPayParam.getShopId(), refPayParam.getShopUserId(),
"memberRefund", refPayOrderNo, null, refPayParam.getRefAmount()));
CzgResult<CzgRefundResp> res = refund(refPayParam.getShopId(), new CzgRefundReq(refPayOrderNo, refPayParam.getRemark(),
@ -393,11 +393,17 @@ public class PayServiceImpl implements PayService {
@Override
@Transactional
public CzgResult<CzgRefundResp> refundOrder(@NonNull Long shopId, @NonNull Long orderId, @NonNull String refundReason, @NonNull BigDecimal refundAmount) {
// refund(shopId, new CzgRefundReq("1", refundReason, refundAmount.multiply(MONEY_RATE).longValue(),
// "1", refundJsonExtParam));
return null;
public CzgResult<Object> refundOrder(@NonNull Long shopId, @NonNull Long orderId, @NonNull Long payOrderId, @NonNull String refPayOrderNo,
@NonNull String refundReason, @NonNull BigDecimal refundAmount) {
OrderPayment payment = paymentService.getById(payOrderId);
AssertUtil.isNull(payment, "退款失败支付记录不存在");
initOrderPayment(new OrderPayment(shopId, orderId, "refund", refPayOrderNo, null, refundAmount));
CzgResult<CzgRefundResp> refund = refund(shopId, new CzgRefundReq(refPayOrderNo, refundReason, refundAmount.multiply(MONEY_RATE).longValue(),
payment.getOrderNo(), ""));
if (refund.getCode() != 200 || refund.getData() == null) {
return CzgResult.failure(refund.getMsg());
}
return CzgResult.success();
}
@Override