mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-30 03:01:53 +08:00
trade:【交易售后】完善发起、同意、不同意、收货、拒绝收货、退款的逻辑
This commit is contained in:
parent
ee1d362a7c
commit
cd2bc112cc
@ -32,11 +32,9 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED = new ErrorCode(1011000105, "订单项已申请售后,无法重复申请");
|
ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED = new ErrorCode(1011000105, "订单项已申请售后,无法重复申请");
|
||||||
ErrorCode AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY = new ErrorCode(1011000106, "审批失败,售后状态不处于审批中");
|
ErrorCode AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY = new ErrorCode(1011000106, "审批失败,售后状态不处于审批中");
|
||||||
ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(1011000107, "操作售后单失败,请刷新后重试");
|
ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(1011000107, "操作售后单失败,请刷新后重试");
|
||||||
ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_PASS = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】");
|
ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】");
|
||||||
ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_RETURN = new ErrorCode(1011000109, "确认收货失败,售后单状态不处于【待确认收货】");
|
ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY = new ErrorCode(1011000109, "确认收货失败,售后单状态不处于【待确认收货】");
|
||||||
ErrorCode AFTER_SALE_REFUND_FAIL_PAY_REFUND_NOT_FOUND = new ErrorCode(1011000110, "退款失败,支付退款单不存在");
|
ErrorCode AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND = new ErrorCode(1011000110, "退款失败,售后单状态不是【待退款】");
|
||||||
ErrorCode AFTER_SALE_REFUND_FAIL_PAY_REFUND_STATUS_NOT_SUCCESS = new ErrorCode(1011000111, "退款失败,支付退款单状态不是【成功】");
|
|
||||||
ErrorCode AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND = new ErrorCode(1011000112, "退款失败,售后单状态不是【待退款】");
|
|
||||||
|
|
||||||
// ========== Cart 模块 1-011-001-000 ==========
|
// ========== Cart 模块 1-011-001-000 ==========
|
||||||
ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在");
|
ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在");
|
||||||
|
@ -15,14 +15,14 @@ import lombok.Getter;
|
|||||||
public enum TradeAfterSaleStatusEnum {
|
public enum TradeAfterSaleStatusEnum {
|
||||||
|
|
||||||
APPLY(10,"申请中"),
|
APPLY(10,"申请中"),
|
||||||
SELLER_PASS(20, "已通过"), // 卖家通过售后
|
SELLER_AGREE(20, "卖家通过"), // 卖家通过售后
|
||||||
BUYER_RETURN(30,"待卖家收货"), // 买家退货,等待卖家收货
|
BUYER_DELIVERY(30,"待卖家收货"), // 买家已退货,等待卖家收货
|
||||||
WAIT_REFUND(40, "等待平台退款"), // 卖家收货,等待平台退款
|
WAIT_REFUND(40, "等待平台退款"), // 卖家已收货,等待平台退款
|
||||||
COMPLETE(50, "完成"), // 完成退款
|
COMPLETE(50, "完成"), // 完成退款
|
||||||
|
|
||||||
BUYER_CANCEL(61, "买家取消售后"),
|
BUYER_CANCEL(61, "买家取消售后"),
|
||||||
SELLER_REFUSE(62,"已拒绝"), // 卖家拒绝售后
|
SELLER_DISAGREE(62,"卖家拒绝"), // 卖家拒绝售后
|
||||||
SELLER_TERMINATION(63,"卖家终止售后"), // 卖家拒绝收货,终止售后
|
SELLER_REFUSE(63,"卖家拒绝收货"), // 卖家拒绝收货,终止售后
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,13 +4,13 @@ import lombok.Getter;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 交易订单 - 退款状态
|
* 交易订单 - 售后状态
|
||||||
*
|
*
|
||||||
* @author Sin
|
* @author Sin
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Getter
|
@Getter
|
||||||
public enum TradeOrderRefundStatusEnum {
|
public enum TradeOrderAfterSaleStatusEnum {
|
||||||
|
|
||||||
NONE(0, "未退款"),
|
NONE(0, "未退款"),
|
||||||
PART(1, "部分退款"),
|
PART(1, "部分退款"),
|
@ -13,9 +13,9 @@ import lombok.RequiredArgsConstructor;
|
|||||||
public enum TradeOrderCancelTypeEnum {
|
public enum TradeOrderCancelTypeEnum {
|
||||||
|
|
||||||
PAY_TIMEOUT(10, "超时未支付"),
|
PAY_TIMEOUT(10, "超时未支付"),
|
||||||
REFUND_CLOSE(20, "退款关闭"),
|
AFTER_SALE_CLOSE(20, "退款关闭"),
|
||||||
MEMBER_CANCEL(30, "买家取消"),
|
MEMBER_CANCEL(30, "买家取消"),
|
||||||
PAY_ON_DELIVERY(40, "已通过货到付款交易"),;
|
PAY_ON_DELIVERY(40, "已通过货到付款交易"),; // TODO 芋艿:这个类型,是不是可以去掉
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭类型
|
* 关闭类型
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.trade.controller.admin.aftersale;
|
package cn.iocoder.yudao.module.trade.controller.admin.aftersale;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO;
|
|
||||||
import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService;
|
import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
@ -13,7 +12,6 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.annotation.security.PermitAll;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
||||||
@ -29,28 +27,38 @@ public class TradeAfterSaleController {
|
|||||||
@Resource
|
@Resource
|
||||||
private TradeAfterSaleService afterSaleService;
|
private TradeAfterSaleService afterSaleService;
|
||||||
|
|
||||||
@PutMapping("/audit")
|
@PutMapping("/agree")
|
||||||
@ApiOperation("审批售后")
|
@ApiOperation("同意售后")
|
||||||
@PreAuthorize("@ss.hasPermission('trade:after-sale:audit')")
|
@ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1")
|
||||||
public CommonResult<Boolean> auditAfterSale(@RequestBody TradeAfterSaleAuditReqVO auditReqVO) {
|
@PreAuthorize("@ss.hasPermission('trade:after-sale:agree')")
|
||||||
afterSaleService.auditAfterSale(getLoginUserId(), getClientIP(), auditReqVO);
|
public CommonResult<Boolean> agreeAfterSale(@RequestParam("id") Long id) {
|
||||||
|
afterSaleService.agreeAfterSale(getLoginUserId(), id);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/confirm")
|
@PutMapping("/disagree")
|
||||||
|
@ApiOperation("拒绝售后")
|
||||||
|
@PreAuthorize("@ss.hasPermission('trade:after-sale:disagree')")
|
||||||
|
public CommonResult<Boolean> disagreeAfterSale(@RequestBody TradeAfterSaleDisagreeReqVO confirmReqVO) {
|
||||||
|
afterSaleService.disagreeAfterSale(getLoginUserId(), confirmReqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/receive")
|
||||||
@ApiOperation("确认收货")
|
@ApiOperation("确认收货")
|
||||||
@PreAuthorize("@ss.hasPermission('trade:after-sale:audit')")
|
@ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1")
|
||||||
public CommonResult<Boolean> confirmAfterSale(@RequestBody TradeAfterSaleConfirmReqVO confirmReqVO) {
|
@PreAuthorize("@ss.hasPermission('trade:after-sale:receive')")
|
||||||
afterSaleService.confirmAfterSale(getLoginUserId(), getClientIP(), confirmReqVO);
|
public CommonResult<Boolean> receiveAfterSale(@RequestParam("id") Long id) {
|
||||||
|
afterSaleService.receiveAfterSale(getLoginUserId(), id);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/refund")
|
@PostMapping("/refund")
|
||||||
@ApiOperation(value = "确认退款", notes = "提供给【pay】支付服务,退款成功后进行回调")
|
@ApiOperation(value = "确认退款")
|
||||||
@ApiImplicitParam(name = "payRefundId", value = "支付退款编号", required = true, example = "18888")
|
@ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1")
|
||||||
@PermitAll
|
@PreAuthorize("@ss.hasPermission('trade:after-sale:refund')")
|
||||||
public CommonResult<Boolean> refundAfterSale(@RequestParam("payRefundId") Long payRefundId) {
|
public CommonResult<Boolean> refundAfterSale(@RequestParam("id") Long id) {
|
||||||
afterSaleService.refundAfterSale(payRefundId);
|
afterSaleService.refundAfterSale(getLoginUserId(), getClientIP(), id);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo;
|
|
||||||
|
|
||||||
import io.swagger.annotations.ApiModel;
|
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
@ApiModel("管理后台 - 交易售后确认收货 Request VO")
|
|
||||||
@Data
|
|
||||||
public class TradeAfterSaleConfirmReqVO {
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "售后编号", required = true, example = "1024")
|
|
||||||
@NotNull(message = "售后编号不能为空")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "收货结果", required = true, example = "true",
|
|
||||||
notes = "true - 确认收货;false - 拒绝收货")
|
|
||||||
@NotNull(message = "审批结果不能为空")
|
|
||||||
private Boolean pass;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "收货备注", example = "你猜")
|
|
||||||
private String receiptMemo;
|
|
||||||
|
|
||||||
}
|
|
@ -4,22 +4,19 @@ import io.swagger.annotations.ApiModel;
|
|||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 交易售后审批 Request VO")
|
@ApiModel("管理后台 - 交易售后拒绝 Request VO")
|
||||||
@Data
|
@Data
|
||||||
public class TradeAfterSaleAuditReqVO {
|
public class TradeAfterSaleDisagreeReqVO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "售后编号", required = true, example = "1024")
|
@ApiModelProperty(value = "售后编号", required = true, example = "1024")
|
||||||
@NotNull(message = "售后编号不能为空")
|
@NotNull(message = "售后编号不能为空")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ApiModelProperty(value = "审批结果", required = true, example = "true",
|
@ApiModelProperty(value = "审批备注", required = true, example = "你猜")
|
||||||
notes = "true - 通过;false - 不通过")
|
@NotEmpty(message = "审批备注不能为空")
|
||||||
@NotNull(message = "审批结果不能为空")
|
|
||||||
private Boolean pass;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "审批备注", example = "你猜")
|
|
||||||
private String auditReason;
|
private String auditReason;
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@ApiModel("管理后台 - 交易售后拒绝收货 Request VO")
|
||||||
|
@Data
|
||||||
|
public class TradeAfterSaleRefuseReqVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "售后编号", required = true, example = "1024")
|
||||||
|
@NotNull(message = "售后编号不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "收货备注", required = true, example = "你猜")
|
||||||
|
@NotNull(message = "收货备注不能为空")
|
||||||
|
private String refuseMemo;
|
||||||
|
|
||||||
|
}
|
@ -86,6 +86,8 @@ public class TradeAfterSaleDO extends BaseDO {
|
|||||||
private Long auditUserId;
|
private Long auditUserId;
|
||||||
/**
|
/**
|
||||||
* 审批备注
|
* 审批备注
|
||||||
|
*
|
||||||
|
* 注意,只有审批不通过才会填写
|
||||||
*/
|
*/
|
||||||
private String auditReason;
|
private String auditReason;
|
||||||
|
|
||||||
@ -132,8 +134,6 @@ public class TradeAfterSaleDO extends BaseDO {
|
|||||||
private Long payRefundId;
|
private Long payRefundId;
|
||||||
/**
|
/**
|
||||||
* 退款时间
|
* 退款时间
|
||||||
*
|
|
||||||
* 退款成功后,才记录该时间
|
|
||||||
*/
|
*/
|
||||||
private LocalDateTime refundTime;
|
private LocalDateTime refundTime;
|
||||||
|
|
||||||
@ -155,10 +155,12 @@ public class TradeAfterSaleDO extends BaseDO {
|
|||||||
/**
|
/**
|
||||||
* 收货时间
|
* 收货时间
|
||||||
*/
|
*/
|
||||||
private LocalDateTime receiptTime;
|
private LocalDateTime receiveTime;
|
||||||
/**
|
/**
|
||||||
* 收货备注
|
* 收货备注
|
||||||
|
*
|
||||||
|
* 注意,只有拒绝收货才会填写
|
||||||
*/
|
*/
|
||||||
private String receiptMemo;
|
private String receiveReason;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
|
|||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO.OrderItem;
|
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO.OrderItem;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderAfterSaleStatusEnum;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
@ -219,11 +219,11 @@ public class TradeOrderDO extends BaseDO {
|
|||||||
|
|
||||||
// ========== 退款基本信息 ==========
|
// ========== 退款基本信息 ==========
|
||||||
/**
|
/**
|
||||||
* 退款状态
|
* 收货状态
|
||||||
*
|
*
|
||||||
* 枚举 {@link TradeOrderRefundStatusEnum}
|
* 枚举 {@link TradeOrderAfterSaleStatusEnum}
|
||||||
*/
|
*/
|
||||||
private Integer refundStatus;
|
private Integer afterSaleStatus;
|
||||||
/**
|
/**
|
||||||
* 退款金额,单位:分
|
* 退款金额,单位:分
|
||||||
*
|
*
|
||||||
|
@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
|
public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
|
||||||
|
|
||||||
@ -13,4 +15,8 @@ public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
|
|||||||
new LambdaUpdateWrapper<>(new TradeOrderItemDO().setId(id).setAfterSaleStatus(oldAfterSaleStatus)));
|
new LambdaUpdateWrapper<>(new TradeOrderItemDO().setId(id).setAfterSaleStatus(oldAfterSaleStatus)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default List<TradeOrderItemDO> selectListByOrderId(Long orderId) {
|
||||||
|
return selectList(TradeOrderItemDO::getOrderId, orderId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.trade.service.aftersale;
|
package cn.iocoder.yudao.module.trade.service.aftersale;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRefuseReqVO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO;
|
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO;
|
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO;
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSa
|
|||||||
public interface TradeAfterSaleService {
|
public interface TradeAfterSaleService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建交易售后
|
* 【会员】创建交易售后
|
||||||
* <p>
|
* <p>
|
||||||
* 一般是用户发起售后请求
|
* 一般是用户发起售后请求
|
||||||
*
|
*
|
||||||
@ -24,16 +24,23 @@ public interface TradeAfterSaleService {
|
|||||||
Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO);
|
Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 审批交易售后
|
* 【管理员】同意交易售后
|
||||||
*
|
*
|
||||||
* @param userId 管理员用户编号
|
* @param userId 管理员用户编号
|
||||||
* @param userIp 操作 IP
|
* @param id 交易售后编号
|
||||||
* @param auditReqVO 审批 Request 信息
|
|
||||||
*/
|
*/
|
||||||
void auditAfterSale(Long userId, String userIp, TradeAfterSaleAuditReqVO auditReqVO);
|
void agreeAfterSale(Long userId, Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退回货物
|
* 【管理员】拒绝交易售后
|
||||||
|
*
|
||||||
|
* @param userId 管理员用户编号
|
||||||
|
* @param auditReqVO 审批 Request 信息
|
||||||
|
*/
|
||||||
|
void disagreeAfterSale(Long userId, TradeAfterSaleDisagreeReqVO auditReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【会员】退回货物
|
||||||
*
|
*
|
||||||
* @param userId 会员用户编号
|
* @param userId 会员用户编号
|
||||||
* @param deliveryReqVO 退货 Request 信息
|
* @param deliveryReqVO 退货 Request 信息
|
||||||
@ -41,19 +48,28 @@ public interface TradeAfterSaleService {
|
|||||||
void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO);
|
void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 确认收货
|
* 【管理员】确认收货
|
||||||
*
|
*
|
||||||
* @param userId 管理员用户编号
|
* @param userId 管理员编号
|
||||||
* @param userIp 操作 IP
|
* @param id 交易售后编号
|
||||||
* @param confirmReqVO 收货 Request 信息
|
|
||||||
*/
|
*/
|
||||||
void confirmAfterSale(Long userId, String userIp, TradeAfterSaleConfirmReqVO confirmReqVO);
|
void receiveAfterSale(Long userId, Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 确认退款,由【pay】支付服务回调
|
* 【管理员】拒绝收货
|
||||||
*
|
*
|
||||||
* @param payRefundId 支付退款编号
|
* @param userId 管理员用户编号
|
||||||
|
* @param confirmReqVO 收货 Request 信息
|
||||||
*/
|
*/
|
||||||
void refundAfterSale(Long payRefundId);
|
void refuseAfterSale(Long userId, TradeAfterSaleRefuseReqVO confirmReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【管理员】确认退款
|
||||||
|
*
|
||||||
|
* @param userId 管理员用户编号
|
||||||
|
* @param userIp 管理员用户 IP
|
||||||
|
* @param id 售后编号
|
||||||
|
*/
|
||||||
|
void refundAfterSale(Long userId, String userIp, Long id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,8 @@ import cn.hutool.core.util.ObjectUtil;
|
|||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
|
import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
|
||||||
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
|
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
|
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRefuseReqVO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO;
|
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO;
|
|
||||||
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO;
|
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO;
|
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO;
|
||||||
import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert;
|
import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert;
|
||||||
@ -28,7 +26,6 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
|||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
@ -66,6 +63,13 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
|
|||||||
return afterSale.getId();
|
return afterSale.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验交易订单项是否可以申请售后
|
||||||
|
*
|
||||||
|
* @param userId 用户编号
|
||||||
|
* @param createReqVO 售后创建信息
|
||||||
|
* @return 交易订单项
|
||||||
|
*/
|
||||||
private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) {
|
private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) {
|
||||||
// 校验订单项存在
|
// 校验订单项存在
|
||||||
TradeOrderItemDO orderItem = tradeOrderService.getOrderItem(userId, createReqVO.getOrderItemId());
|
TradeOrderItemDO orderItem = tradeOrderService.getOrderItem(userId, createReqVO.getOrderItemId());
|
||||||
@ -116,7 +120,8 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
|
|||||||
|
|
||||||
// 更新交易订单项的售后状态
|
// 更新交易订单项的售后状态
|
||||||
tradeOrderService.updateOrderItemAfterSaleStatus(tradeOrderItem.getId(),
|
tradeOrderService.updateOrderItemAfterSaleStatus(tradeOrderItem.getId(),
|
||||||
TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus());
|
TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(),
|
||||||
|
TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), null);
|
||||||
|
|
||||||
// TODO 记录售后日志
|
// TODO 记录售后日志
|
||||||
|
|
||||||
@ -125,62 +130,179 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void auditAfterSale(Long userId, String userIp,
|
public void agreeAfterSale(Long userId, Long id) {
|
||||||
TradeAfterSaleAuditReqVO auditReqVO) {
|
|
||||||
// 校验售后单存在,并状态未审批
|
// 校验售后单存在,并状态未审批
|
||||||
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(auditReqVO.getId());
|
TradeAfterSaleDO afterSale = validateAfterSaleAuditable(id);
|
||||||
|
|
||||||
|
// 更新售后单的状态
|
||||||
|
// 情况一:退款:标记为 WAIT_REFUND 状态。后续等退款发起成功后,在标记为 COMPLETE 状态
|
||||||
|
// 情况二:退货退款:需要等用户退货后,才能发起退款
|
||||||
|
Integer newStatus = afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType()) ?
|
||||||
|
TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus();
|
||||||
|
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO()
|
||||||
|
.setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now()));
|
||||||
|
|
||||||
|
// TODO 记录售后日志
|
||||||
|
|
||||||
|
// TODO 发送售后消息
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void disagreeAfterSale(Long userId, TradeAfterSaleDisagreeReqVO auditReqVO) {
|
||||||
|
// 校验售后单存在,并状态未审批
|
||||||
|
TradeAfterSaleDO afterSale = validateAfterSaleAuditable(auditReqVO.getId());
|
||||||
|
|
||||||
|
// 更新售后单的状态
|
||||||
|
Integer newStatus = TradeAfterSaleStatusEnum.SELLER_DISAGREE.getStatus();
|
||||||
|
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO()
|
||||||
|
.setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now())
|
||||||
|
.setAuditReason(auditReqVO.getAuditReason()));
|
||||||
|
|
||||||
|
// TODO 记录售后日志
|
||||||
|
|
||||||
|
// TODO 发送售后消息
|
||||||
|
|
||||||
|
// 更新交易订单项的售后状态为【未申请】
|
||||||
|
tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(),
|
||||||
|
TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(),
|
||||||
|
TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验售后单是否可审批(同意售后、拒绝售后)
|
||||||
|
*
|
||||||
|
* @param id 售后编号
|
||||||
|
* @return 售后单
|
||||||
|
*/
|
||||||
|
private TradeAfterSaleDO validateAfterSaleAuditable(Long id) {
|
||||||
|
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
|
||||||
if (afterSale == null) {
|
if (afterSale == null) {
|
||||||
throw exception(AFTER_SALE_NOT_FOUND);
|
throw exception(AFTER_SALE_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus())) {
|
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus())) {
|
||||||
throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY);
|
throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY);
|
||||||
}
|
}
|
||||||
|
return afterSale;
|
||||||
|
}
|
||||||
|
|
||||||
// 进行审批
|
private void updateAfterSaleStatus(Long id, Integer status, TradeAfterSaleDO updateObj) {
|
||||||
if (auditReqVO.getPass()) {
|
int updateCount = tradeAfterSaleMapper.updateByIdAndStatus(id, status, updateObj);
|
||||||
auditAfterSalePass(userId, userIp, auditReqVO, afterSale);
|
if (updateCount == 0) {
|
||||||
} else {
|
throw exception(AFTER_SALE_UPDATE_STATUS_FAIL);
|
||||||
auditAfterSaleReject(userId, auditReqVO, afterSale);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void auditAfterSalePass(Long userId, String userIp,
|
@Override
|
||||||
TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) {
|
@Transactional(rollbackFor = Exception.class)
|
||||||
// 更新售后单的状态
|
public void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO) {
|
||||||
// 情况一:退款:标记为 WAIT_REFUND 状态。后续等退款发起成功后,在标记为 COMPLETE 状态
|
// 校验售后单存在,并状态未退货
|
||||||
// 情况二:退货退款:需要等用户退货后,才能发起退款
|
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(deliveryReqVO.getId());
|
||||||
Integer newStatus = afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType()) ?
|
if (afterSale == null) {
|
||||||
TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_PASS.getStatus();
|
throw exception(AFTER_SALE_NOT_FOUND);
|
||||||
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO()
|
|
||||||
.setStatus(newStatus).setAuditUserId(userId)
|
|
||||||
.setAuditReason(auditReqVO.getAuditReason()).setAuditTime(LocalDateTime.now()));
|
|
||||||
|
|
||||||
// 如果直接退款,则发起售后退款
|
|
||||||
if (afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType())) {
|
|
||||||
createPayRefund(userIp, afterSale);
|
|
||||||
}
|
}
|
||||||
|
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus())) {
|
||||||
|
throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新售后单的物流信息
|
||||||
|
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus(), new TradeAfterSaleDO()
|
||||||
|
.setStatus(TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus())
|
||||||
|
.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo())
|
||||||
|
.setDeliveryTime(deliveryReqVO.getDeliveryTime()));
|
||||||
|
|
||||||
// TODO 记录售后日志
|
// TODO 记录售后日志
|
||||||
|
|
||||||
// TODO 发送售后消息
|
// TODO 发送售后消息
|
||||||
}
|
}
|
||||||
|
|
||||||
private void auditAfterSaleReject(Long userId,
|
@Override
|
||||||
TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) {
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void receiveAfterSale(Long userId, Long id) {
|
||||||
|
// 校验售后单存在,并状态为已退货
|
||||||
|
TradeAfterSaleDO afterSale = validateAfterSaleReceivable(id);
|
||||||
|
|
||||||
// 更新售后单的状态
|
// 更新售后单的状态
|
||||||
Integer newStatus = TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus();
|
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new TradeAfterSaleDO()
|
||||||
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO()
|
.setStatus(TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus()).setReceiveTime(LocalDateTime.now()));
|
||||||
.setStatus(newStatus).setAuditUserId(userId)
|
|
||||||
.setAuditReason(auditReqVO.getAuditReason()).setAuditTime(LocalDateTime.now()));
|
// TODO 记录售后日志
|
||||||
|
|
||||||
|
// TODO 发送售后消息
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void refuseAfterSale(Long userId, TradeAfterSaleRefuseReqVO confirmReqVO) {
|
||||||
|
// 校验售后单存在,并状态为已退货
|
||||||
|
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(confirmReqVO.getId());
|
||||||
|
if (afterSale == null) {
|
||||||
|
throw exception(AFTER_SALE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
|
||||||
|
throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新售后单的状态
|
||||||
|
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new TradeAfterSaleDO()
|
||||||
|
.setStatus(TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus()).setReceiveTime(LocalDateTime.now())
|
||||||
|
.setReceiveReason(confirmReqVO.getRefuseMemo()));
|
||||||
|
|
||||||
|
// TODO 记录售后日志
|
||||||
|
|
||||||
|
// TODO 发送售后消息
|
||||||
|
|
||||||
// 更新交易订单项的售后状态为【未申请】
|
// 更新交易订单项的售后状态为【未申请】
|
||||||
tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(),
|
tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(),
|
||||||
TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
|
TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(),
|
||||||
|
TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验售后单是否可收货,即处于买家已发货
|
||||||
|
*
|
||||||
|
* @param id 售后编号
|
||||||
|
* @return 售后单
|
||||||
|
*/
|
||||||
|
private TradeAfterSaleDO validateAfterSaleReceivable(Long id) {
|
||||||
|
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
|
||||||
|
if (afterSale == null) {
|
||||||
|
throw exception(AFTER_SALE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
|
||||||
|
throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY);
|
||||||
|
}
|
||||||
|
return afterSale;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void refundAfterSale(Long userId, String userIp, Long id) {
|
||||||
|
// 校验售后单的状态,并状态待退款
|
||||||
|
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectByPayRefundId(id);
|
||||||
|
if (afterSale == null) {
|
||||||
|
throw exception(AFTER_SALE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus())) {
|
||||||
|
throw exception(AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发起退款单。注意,需要在事务提交后,再进行发起,避免重复发起
|
||||||
|
createPayRefund(userIp, afterSale);
|
||||||
|
|
||||||
|
// 更新售后单的状态为【已完成】
|
||||||
|
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus(), new TradeAfterSaleDO()
|
||||||
|
.setStatus(TradeAfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(LocalDateTime.now()));
|
||||||
|
|
||||||
// TODO 记录售后日志
|
// TODO 记录售后日志
|
||||||
|
|
||||||
// TODO 发送售后消息
|
// TODO 发送售后消息
|
||||||
|
|
||||||
|
// 更新交易订单项的售后状态为【已完成】
|
||||||
|
tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(),
|
||||||
|
TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(),
|
||||||
|
TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus(), afterSale.getRefundPrice());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPayRefund(String userIp, TradeAfterSaleDO afterSale) {
|
private void createPayRefund(String userIp, TradeAfterSaleDO afterSale) {
|
||||||
@ -197,123 +319,4 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAfterSaleStatus(Long id, Integer status, TradeAfterSaleDO updateObj) {
|
|
||||||
int updateCount = tradeAfterSaleMapper.updateByIdAndStatus(id, status, updateObj);
|
|
||||||
if (updateCount == 0) {
|
|
||||||
throw exception(AFTER_SALE_UPDATE_STATUS_FAIL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO) {
|
|
||||||
// 校验售后单存在,并状态未退货
|
|
||||||
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(deliveryReqVO.getId());
|
|
||||||
if (afterSale == null) {
|
|
||||||
throw exception(AFTER_SALE_NOT_FOUND);
|
|
||||||
}
|
|
||||||
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.SELLER_PASS.getStatus())) {
|
|
||||||
throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_PASS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新售后单的物流信息
|
|
||||||
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.SELLER_PASS.getStatus(), new TradeAfterSaleDO()
|
|
||||||
.setStatus(TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus())
|
|
||||||
.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo())
|
|
||||||
.setDeliveryTime(deliveryReqVO.getDeliveryTime()));
|
|
||||||
|
|
||||||
// TODO 记录售后日志
|
|
||||||
|
|
||||||
// TODO 发送售后消息
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void confirmAfterSale(Long userId, String userIp,
|
|
||||||
TradeAfterSaleConfirmReqVO confirmReqVO) {
|
|
||||||
// 校验售后单存在,并状态未审批
|
|
||||||
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(confirmReqVO.getId());
|
|
||||||
if (afterSale == null) {
|
|
||||||
throw exception(AFTER_SALE_NOT_FOUND);
|
|
||||||
}
|
|
||||||
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus())) {
|
|
||||||
throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_RETURN);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 进行审批
|
|
||||||
if (confirmReqVO.getPass()) {
|
|
||||||
confirmAfterSalePass(userId, userIp, confirmReqVO, afterSale);
|
|
||||||
} else {
|
|
||||||
confirmAfterSaleReject(userId, confirmReqVO, afterSale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void confirmAfterSalePass(Long userId, String userIp,
|
|
||||||
TradeAfterSaleConfirmReqVO confirmReqVO, TradeAfterSaleDO afterSale) {
|
|
||||||
// 更新售后单的状态
|
|
||||||
Integer newStatus = TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus();
|
|
||||||
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus(), new TradeAfterSaleDO()
|
|
||||||
.setStatus(newStatus).setReceiptTime(LocalDateTime.now()).setReceiptMemo(confirmReqVO.getReceiptMemo()));
|
|
||||||
|
|
||||||
// 如果直接退款,则发起售后退款
|
|
||||||
if (afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType())) {
|
|
||||||
createPayRefund(userIp, afterSale);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO 记录售后日志
|
|
||||||
|
|
||||||
// TODO 发送售后消息
|
|
||||||
}
|
|
||||||
|
|
||||||
private void confirmAfterSaleReject(Long userId, TradeAfterSaleConfirmReqVO confirmReqVO, TradeAfterSaleDO afterSale) {
|
|
||||||
// 更新售后单的状态
|
|
||||||
Integer newStatus = TradeAfterSaleStatusEnum.SELLER_TERMINATION.getStatus();
|
|
||||||
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus(), new TradeAfterSaleDO()
|
|
||||||
.setStatus(newStatus).setReceiptTime(LocalDateTime.now()).setReceiptMemo(confirmReqVO.getReceiptMemo()));
|
|
||||||
|
|
||||||
// 更新交易订单项的售后状态为【未申请】
|
|
||||||
tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(),
|
|
||||||
TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
|
|
||||||
|
|
||||||
// TODO 记录售后日志
|
|
||||||
|
|
||||||
// TODO 发送售后消息
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void refundAfterSale(Long payRefundId) {
|
|
||||||
// 校验退款单
|
|
||||||
PayRefundRespDTO payRefund = validatePayRefundSuccess(payRefundId);
|
|
||||||
|
|
||||||
// 校验售后单的状态,并状态待退款
|
|
||||||
TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectByPayRefundId(payRefundId);
|
|
||||||
if (afterSale == null) {
|
|
||||||
throw exception(AFTER_SALE_NOT_FOUND);
|
|
||||||
}
|
|
||||||
if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus())) {
|
|
||||||
throw exception(AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新售后单的状态为【已完成】
|
|
||||||
updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus(), new TradeAfterSaleDO()
|
|
||||||
.setStatus(TradeAfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(payRefund.getSuccessTime()));
|
|
||||||
|
|
||||||
// 更新交易订单项的售后状态为【已完成】
|
|
||||||
tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(),
|
|
||||||
TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus());
|
|
||||||
|
|
||||||
// TODO 记录售后日志
|
|
||||||
|
|
||||||
// TODO 发送售后消息
|
|
||||||
}
|
|
||||||
|
|
||||||
private PayRefundRespDTO validatePayRefundSuccess(Long payRefundId) {
|
|
||||||
PayRefundRespDTO payRefund = payRefundApi.getPayRefund(payRefundId);
|
|
||||||
if (payRefund == null) {
|
|
||||||
throw exception(AFTER_SALE_REFUND_FAIL_PAY_REFUND_NOT_FOUND);
|
|
||||||
}
|
|
||||||
if (PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
|
|
||||||
throw exception(AFTER_SALE_REFUND_FAIL_PAY_REFUND_STATUS_NOT_SUCCESS);
|
|
||||||
}
|
|
||||||
return payRefund;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,8 @@ public interface TradeOrderService {
|
|||||||
* @param id 交易订单项编号
|
* @param id 交易订单项编号
|
||||||
* @param oldAfterSaleStatus 当前售后状态;如果不符,更新后会抛出异常
|
* @param oldAfterSaleStatus 当前售后状态;如果不符,更新后会抛出异常
|
||||||
* @param newAfterSaleStatus 目标售后状态
|
* @param newAfterSaleStatus 目标售后状态
|
||||||
|
* @param refundPrice 退款金额;当订单项退款成功时,必须传递该值
|
||||||
*/
|
*/
|
||||||
void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus);
|
void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus,
|
||||||
|
Integer newAfterSaleStatus, Integer refundPrice);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.service.order;
|
|||||||
|
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
|
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
@ -24,17 +25,16 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreate
|
|||||||
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
|
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
|
||||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
||||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
||||||
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
|
|
||||||
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
|
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
|
||||||
|
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
|
||||||
import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
|
import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.*;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
|
||||||
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -180,12 +180,12 @@ public class TradeOrderServiceImpl implements TradeOrderService {
|
|||||||
tradeOrderDO.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的;
|
tradeOrderDO.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的;
|
||||||
tradeOrderDO.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
|
tradeOrderDO.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
|
||||||
tradeOrderDO.setType(TradeOrderTypeEnum.NORMAL.getType());
|
tradeOrderDO.setType(TradeOrderTypeEnum.NORMAL.getType());
|
||||||
tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
|
tradeOrderDO.setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.NONE.getStatus());
|
||||||
tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum));
|
tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum));
|
||||||
tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
|
tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
|
||||||
tradeOrderDO.setAdjustPrice(0).setPayed(false); // 支付信息
|
tradeOrderDO.setAdjustPrice(0).setPayed(false); // 支付信息
|
||||||
tradeOrderDO.setDeliveryStatus(false); // 物流信息
|
tradeOrderDO.setDeliveryStatus(false); // 物流信息
|
||||||
tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息
|
tradeOrderDO.setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息
|
||||||
tradeOrderMapper.insert(tradeOrderDO);
|
tradeOrderMapper.insert(tradeOrderDO);
|
||||||
return tradeOrderDO;
|
return tradeOrderDO;
|
||||||
}
|
}
|
||||||
@ -252,11 +252,52 @@ public class TradeOrderServiceImpl implements TradeOrderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus) {
|
public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, Integer refundPrice) {
|
||||||
|
// 如果退款成功,则 refundPrice 非空
|
||||||
|
if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())
|
||||||
|
&& refundPrice == null) {
|
||||||
|
throw new IllegalArgumentException(StrUtil.format("id({}) 退款成功,退款金额不能为空", id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新订单项
|
||||||
int updateCount = tradeOrderItemMapper.updateAfterSaleStatus(id, oldAfterSaleStatus, newAfterSaleStatus);
|
int updateCount = tradeOrderItemMapper.updateAfterSaleStatus(id, oldAfterSaleStatus, newAfterSaleStatus);
|
||||||
if (updateCount <= 0) {
|
if (updateCount <= 0) {
|
||||||
throw exception(ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL);
|
throw exception(ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果有退款金额,则需要更新订单
|
||||||
|
if (refundPrice == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 计算总的退款金额
|
||||||
|
TradeOrderDO order = tradeOrderMapper.selectById(tradeOrderItemMapper.selectById(id).getOrderId());
|
||||||
|
Integer orderRefundPrice = order.getRefundPrice() + refundPrice;
|
||||||
|
if (isAllOrderItemAfterSaleSuccess(order.getId())) { // 如果都售后成功,则需要取消订单
|
||||||
|
tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
|
||||||
|
.setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.ALL.getStatus()).setRefundPrice(orderRefundPrice)
|
||||||
|
.setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now()));
|
||||||
|
|
||||||
|
// TODO 芋艿:记录订单日志
|
||||||
|
|
||||||
|
// TODO 芋艿:站内信?
|
||||||
|
} else { // 如果部分售后,则更新退款金额
|
||||||
|
tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
|
||||||
|
.setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 芋艿:未来如果有分佣,需要更新相关分佣订单为已失效
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断指定订单的所有订单项,是不是都售后成功
|
||||||
|
*
|
||||||
|
* @param id 订单编号
|
||||||
|
* @return 是否都售后成功
|
||||||
|
*/
|
||||||
|
private boolean isAllOrderItemAfterSaleSuccess(Long id) {
|
||||||
|
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
|
||||||
|
return orderItems.stream().allMatch(orderItem -> Objects.equals(orderItem.getAfterSaleStatus(),
|
||||||
|
TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
|||||||
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
|
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
|
||||||
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
|
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderAfterSaleStatusEnum;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
|
||||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||||
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;
|
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;
|
||||||
@ -182,7 +182,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
|
|||||||
assertEquals(tradeOrderDO.getReceiverAreaId(), 3306L);
|
assertEquals(tradeOrderDO.getReceiverAreaId(), 3306L);
|
||||||
assertEquals(tradeOrderDO.getReceiverPostCode(), 85757);
|
assertEquals(tradeOrderDO.getReceiverPostCode(), 85757);
|
||||||
assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村");
|
assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村");
|
||||||
assertEquals(tradeOrderDO.getRefundStatus(), TradeOrderRefundStatusEnum.NONE.getStatus());
|
assertEquals(tradeOrderDO.getAfterSaleStatus(), TradeOrderAfterSaleStatusEnum.NONE.getStatus());
|
||||||
assertEquals(tradeOrderDO.getRefundPrice(), 0);
|
assertEquals(tradeOrderDO.getRefundPrice(), 0);
|
||||||
assertEquals(tradeOrderDO.getCouponPrice(), 30);
|
assertEquals(tradeOrderDO.getCouponPrice(), 30);
|
||||||
assertEquals(tradeOrderDO.getPointPrice(), 10);
|
assertEquals(tradeOrderDO.getPointPrice(), 10);
|
||||||
|
Loading…
Reference in New Issue
Block a user