From b8d1d31df0c7067b6b850f23109ebfbe0d2d7109 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 15 Nov 2022 19:46:30 +0800 Subject: [PATCH 001/110] =?UTF-8?q?trade:=20=E8=B0=83=E6=95=B4=E9=80=80?= =?UTF-8?q?=E6=AC=BE=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aftersale/TradeAfterSaleStatusEnum.java | 37 +++++++ .../TradeAfterSaleTypeEnum.java} | 6 +- .../TradeAfterSaleDO.java} | 97 ++++++++++--------- 3 files changed, 93 insertions(+), 47 deletions(-) create mode 100644 yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java rename yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/{refund/TradeRefundTypeEnum.java => aftersale/TradeAfterSaleTypeEnum.java} (73%) rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/{refund/TradeRefundDO.java => aftersale/TradeAfterSaleDO.java} (60%) diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java new file mode 100644 index 0000000000..8d8df958cb --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.trade.enums.aftersale; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 售后状态的枚举 + * + * 状态流转 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum TradeAfterSaleStatusEnum { + + APPLY(10,"申请中"), + SELLER_PASS(20, "已通过"), // 卖家通过售后 + BUYER_RETURN(30,"待卖家收货"), // 买家退货,等待卖家收货 + WAIT_REFUND(40, "等待平台退款"), // 卖家收货,等待平台退款 + COMPLETE(50, "完成"), // 完成退款 + + BUYER_CANCEL(61, "买家取消售后"), + SELLER_REFUSE(62,"已拒绝"), // 卖家拒绝售后 + SELLER_TERMINATION(63,"卖家终止售后"), // 卖家拒绝收货,终止售后 + ; + + /** + * 状态 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + +} diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/refund/TradeRefundTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java similarity index 73% rename from yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/refund/TradeRefundTypeEnum.java rename to yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java index f74b39bbae..daa9b0a0ce 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/refund/TradeRefundTypeEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java @@ -1,16 +1,16 @@ -package cn.iocoder.yudao.module.trade.enums.refund; +package cn.iocoder.yudao.module.trade.enums.aftersale; import lombok.Getter; import lombok.RequiredArgsConstructor; /** - * 交易退款 - 申请类型 + * 交易售后 - 类型 * * @author Sin */ @RequiredArgsConstructor @Getter -public enum TradeRefundTypeEnum { +public enum TradeAfterSaleTypeEnum { REFUND(10, "退款"), RETURN_AND_REFUND(20, "退货退款"); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/refund/TradeRefundDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java similarity index 60% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/refund/TradeRefundDO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java index d052d4dd34..2e7187b951 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/refund/TradeRefundDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.module.trade.dal.dataobject.refund; +package cn.iocoder.yudao.module.trade.dal.dataobject.aftersale; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 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.enums.order.TradeOrderRefundStatusEnum; -import cn.iocoder.yudao.module.trade.enums.refund.TradeRefundTypeEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; @@ -16,32 +16,38 @@ import java.time.LocalDateTime; import java.util.List; /** - * 交易退款,用于处理 {@link TradeOrderDO} 交易订单的退货换流程 + * 交易售后,用于处理 {@link TradeOrderDO} 交易订单的退款退货流程 + * + * @author 芋道源码 */ -// TODO 芋艿:需要调整下每个字段的命名;未完全实现; @TableName(value = "trade_refund") @Data @EqualsAndHashCode(callSuper = true) @Accessors(chain = true) -public class TradeRefundDO extends BaseDO { +public class TradeAfterSaleDO extends BaseDO { /** - * 交易退款编号,主键自增 + * 售后编号,主键自增n */ - @Deprecated private Long id; /** - * 退款流水号 + * 售后流水号 * * 例如说,1146347329394184195 */ - private String sn; + private String no; /** * 退款状态 * - * 枚举 {@link TradeOrderRefundStatusEnum} + * 枚举 {@link TradeAfterSaleStatusEnum} */ private Integer status; + /** + * 售后类型 + * + * 枚举 {@link TradeAfterSaleTypeEnum} + */ + private Integer type; /** * 用户编号 * @@ -49,69 +55,75 @@ public class TradeRefundDO extends BaseDO { */ private Long userId; /** - * 用户手机 + * 申请原因 */ - private String userMobile; + private String applyReason; /** - * 申请类型 - * - * 枚举 {@link TradeRefundTypeEnum} + * 补充描述 */ - private Integer type; + private String applyDescription; /** - * 用户售后说明 - */ - private String reasonMemo; // buyer_msg - /** - * 用户售后凭证图片的地址数组 + * 补充凭证图片 * * 数组,以逗号分隔 */ @TableField(typeHandler = JacksonTypeHandler.class) - private List reasonPicUrls; // photo_files + private List applyPicUrls; // ========== 商家相关 ========== /** - * 商家处理时间 + * 审批时间 */ - private LocalDateTime handleTime; // handel_time + private LocalDateTime auditTime; /** - * 商家拒绝理由 + * 审批人 + * + * 关联 AdminUserDO 的 id 编号 */ - private String rejectReasonMemo; // seller_msg + private Long auditUserId; + /** + * 审批备注 + */ + private String auditReason; // ========== 交易订单相关 ========== /** * 交易订单编号 * - * 外键 {@link TradeOrderDO#getId()} + * 关联 {@link TradeOrderDO#getId()} */ - private Long tradeOrderId; + private Long orderId; /** * 交易订单项编号 * * 关联 {@link TradeOrderItemDO#getId()} - * 如果全部退款,则该值设置为 0 即可 */ - private Long tradeOrderItemId; + private Long orderItemId; + /** + * 商品 SPU 编号 + * + * 关联 ProductSpuDO 的编号 + */ + private Long spuId; /** * 商品 SKU 编号 + * + * 关联 ProductSkuDO 的编号 */ - @Deprecated private Integer skuId; /** * 退货商品数量 */ - private Integer stock; // goods_num + private Integer count; // ========== 退款相关 ========== /** * 退款金额,单位:分。 */ - private Integer refundPrice; // refund_amount + private Integer refundPrice; /** - * 支付退款编号 + * 支付退款编号 TODO * * 对接 pay-module-biz 支付服务的退款订单编号,即 PayRefundDO 的 id 编号 */ @@ -120,28 +132,25 @@ public class TradeRefundDO extends BaseDO { // ========== 退货相关 ========== /** - * 退货物流公司编号 + * 退货物流公司编号 TODO * * 关联 ExpressDO 的 id 编号 */ private Long returnExpressId; // express_name /** - * 退货物流单号 + * 退货物流单号 TODO */ private String returnExpressNo; // express_no /** - * 退货时间 + * 退货时间 TODO */ - private LocalDateTime returnDate; // ship_time - - // ========== 收获相关 ========== - + private LocalDateTime deliveryTime; // ship_time /** - * 收获备注 + * 收获备注 TODO */ private String receiveMemo; // receive_message /** - * 收货时间 + * 收货时间 TODO */ private LocalDateTime receiveDate; // receive_time From 10f2dbc8cd7d6f5150b50fff32c3c3ed51aec3c3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 16 Nov 2022 00:51:29 +0800 Subject: [PATCH 002/110] =?UTF-8?q?trade:=20=E5=A2=9E=E5=8A=A0=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=94=AE=E5=90=8E=E8=AE=A2=E5=8D=95=E7=9A=84=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/enums/ErrorCodeConstants.java | 14 ++- .../aftersale/TradeAfterSaleTypeEnum.java | 12 ++- .../TradeOrderItemAfterSaleStatusEnum.java | 42 ++++++++ .../order/TradeOrderItemRefundStatusEnum.java | 29 ----- .../enums/order/TradeOrderStatusEnum.java | 46 +++++++- .../app/aftersale/AppAfterSaleController.java | 36 +++++++ .../aftersale/vo/AppAfterSaleCreateReqVO.java | 41 +++++++ .../app/order/AppTradeOrderController.java | 8 +- .../app/refund/TradeRefundController.java | 4 - .../aftersale/TradeAfterSaleConvert.java | 25 +++++ .../convert/order/TradeOrderConvert.java | 4 +- .../aftersale/TradeAfterSaleDO.java | 6 +- .../dataobject/order/TradeOrderItemDO.java | 25 ++--- .../mysql/aftersale/TradeAfterSaleMapper.java | 10 ++ .../TradeOrderItemMapper.java | 2 +- .../aftersale/TradeAfterSaleService.java | 23 ++++ .../aftersale/TradeAfterSaleServiceImpl.java | 102 ++++++++++++++++++ .../service/order/TradeOrderService.java | 24 ++++- .../service/order/TradeOrderServiceImpl.java | 26 ++++- .../service/order/TradeOrderServiceTest.java | 12 +-- 20 files changed, 414 insertions(+), 77 deletions(-) create mode 100644 yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderItemAfterSaleStatusEnum.java delete mode 100644 yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderItemRefundStatusEnum.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/refund/TradeRefundController.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/{orderitem => order}/TradeOrderItemMapper.java (82%) create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 8725ac58f1..7d31d3cb70 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -19,7 +19,19 @@ public interface ErrorCodeConstants { ErrorCode ORDER_CREATE_SPU_NOT_FOUND = new ErrorCode(1011000005, "商品 SPU 不可售卖"); ErrorCode ORDER_CREATE_ADDRESS_NOT_FOUND = new ErrorCode(1011000006, "收货地址不存在"); + ErrorCode ORDER_ITEM_NOT_FOUND = new ErrorCode(1011000010, "交易订单项不存在"); + ErrorCode ORDER_NOT_FOUND = new ErrorCode(1011000010, "交易订单不存在"); + + // ========== After Sale 模块 1-011-000-000 ========== + ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在"); + ErrorCode AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR = new ErrorCode(1011000101, "申请退款金额错误"); + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED = new ErrorCode(1011000102, "订单已关闭,无法申请售后"); + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID = new ErrorCode(1011000103, "订单未支付,无法申请售后"); + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED = new ErrorCode(1011000104, "订单未发货,无法申请【退货退款】售后"); + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED = new ErrorCode(1011000105, "订单项已申请售后,无法重复申请"); + // ========== Cart 模块 1-011-001-000 ========== - ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1001001000, "购物车项不存在"); + ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); + } diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java index daa9b0a0ce..66e1902f23 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java @@ -1,8 +1,11 @@ package cn.iocoder.yudao.module.trade.enums.aftersale; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.Getter; import lombok.RequiredArgsConstructor; +import java.util.Arrays; + /** * 交易售后 - 类型 * @@ -10,11 +13,13 @@ import lombok.RequiredArgsConstructor; */ @RequiredArgsConstructor @Getter -public enum TradeAfterSaleTypeEnum { +public enum TradeAfterSaleTypeEnum implements IntArrayValuable { REFUND(10, "退款"), RETURN_AND_REFUND(20, "退货退款"); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeAfterSaleTypeEnum::getType).toArray(); + /** * 状态值 */ @@ -24,4 +29,9 @@ public enum TradeAfterSaleTypeEnum { */ private final String name; + @Override + public int[] array() { + return ARRAYS; + } + } diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderItemAfterSaleStatusEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderItemAfterSaleStatusEnum.java new file mode 100644 index 0000000000..70d7bf4bc1 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderItemAfterSaleStatusEnum.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.trade.enums.order; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * 交易订单项 - 售后状态 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum TradeOrderItemAfterSaleStatusEnum { + + NONE(0, "未申请"), + APPLY(1, "已申请"), + SUCCESS(2, "申请成功"); + + /** + * 状态值 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + // TODO 芋艿:EXPIRED 已失效不允许申请售后 + // TODO 芋艿:PART_AFTER_SALE 部分售后 + + /** + * 判断指定状态,是否正处于【未申请】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean isNone(Integer status) { + return ObjectUtil.equals(status, NONE.getStatus()); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderItemRefundStatusEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderItemRefundStatusEnum.java deleted file mode 100644 index 4d81ea9ebd..0000000000 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderItemRefundStatusEnum.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.trade.enums.order; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -/** - * 交易订单项 - 退款状态 - * - * @author Sin - */ -@RequiredArgsConstructor -@Getter -public enum TradeOrderItemRefundStatusEnum { - - NONE(0, "未申请退款"), - APPLY(1, "申请退款"), - WAIT(2, "等待退款"), - SUCCESS(3, "退款成功"); - - /** - * 状态值 - */ - private final Integer status; - /** - * 状态名 - */ - private final String name; - -} diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java index fe0a85f3dc..33ddbd662c 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.trade.enums.order; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -12,11 +14,14 @@ import lombok.RequiredArgsConstructor; @Getter public enum TradeOrderStatusEnum { - WAITING_PAYMENT(0, "待付款"), - WAIT_SHIPMENT(1, "待发货"), - ALREADY_SHIPMENT(2, "待收货"), - COMPLETED(3, "已完成"), - CANCEL(4, "已关闭"); + UNPAID(0, "未付款"), + PAID(10, "已付款"), // 例如说,拼团订单,支付后,需要拼团成功后,才会处于待发货 + UNDELIVERED(20, "待发货"), + DELIVERED(30, "已发货"), + COMPLETED(40, "已完成"), + CANCELED(50, "已取消"); + + // TODO 芋艿: TAKE("待核验"):虚拟订单需要核验商品 /** * 状态值 @@ -27,4 +32,35 @@ public enum TradeOrderStatusEnum { */ private final String name; + /** + * 判断指定状态,是否正处于【已取消】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean isCanceled(Integer status) { + return ObjectUtil.equals(status, CANCELED.getStatus()); + } + + /** + * 判断指定状态,是否有过【已付款】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean havePaid(Integer status) { + return ObjectUtils.equalsAny(status, PAID.getStatus(), UNDELIVERED.getStatus(), + DELIVERED.getStatus(), COMPLETED.getStatus()); + } + + /** + * 判断指定状态,是否有过【已发货】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean haveDelivered(Integer status) { + return ObjectUtils.equalsAny(status, DELIVERED.getStatus(), COMPLETED.getStatus()); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java new file mode 100644 index 0000000000..789b6e52a9 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.trade.controller.app.aftersale; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Api(tags = "用户 App - 交易售后") +@RestController +@RequestMapping("/trade/after-sale") +@Validated +@Slf4j +public class AppAfterSaleController { + + @Resource + private TradeAfterSaleService afterSaleService; + + @PostMapping(value = "/create") + @ApiOperation(value = "申请售后") + private CommonResult createAfterSale(@RequestBody AppAfterSaleCreateReqVO createReqVO) { + return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO)); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java new file mode 100644 index 0000000000..eceba596be --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +@ApiModel("用户 App - 交易售后创建 Request VO") +@Data +public class AppAfterSaleCreateReqVO { + + @ApiModelProperty(name = "订单项编号", required = true, example = "1024") + @NotNull(message = "订单项编号不能为空") + private Long orderItemId; + + @ApiModelProperty(name = "退款金额", required = true, example = "100", notes = "单位:分") + @NotNull(message = "退款金额不能为空") + @Min(value = 1, message = "退款金额必须大于 0") + private Integer applyPrice; + + @ApiModelProperty(name = "申请原因", required = true, example = "1", notes = "使用数据字典枚举,对应 trade_refund_apply_reason 类型") + @NotNull(message = "申请原因不能为空") + private Integer applyReason; + + @ApiModelProperty(name = "补充描述", example = "商品质量不好") + private String applyDescription; + + @ApiModelProperty(name = "补充凭证图片", example = "https://www.iocoder.cn/1.png, https://www.iocoder.cn/2.png") + private List applyPicUrls; + + @ApiModelProperty(name = "售后类型", required = true, example = "1", notes = "对应 TradeAfterSaleTypeEnum 枚举") + @NotNull(message = "售后类型不能为空") + @InEnum(value = TradeAfterSaleTypeEnum.class, message = "售后类型必须是 {value}") + private Integer type; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java index 4233867e13..64bd1f5f0d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -13,22 +13,22 @@ import cn.iocoder.yudao.module.trade.service.order.TradeOrderService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; @Api(tags = "用户 App - 交易订单") @RestController @RequestMapping("/trade/order") -@RequiredArgsConstructor // TODO @LeeYan9: 先统一使用 @Resource 注入哈; 项目只有三层, 依赖注入会存在, 所以使用 @Resource; 也因此, 最好全局保持一致 @Validated @Slf4j public class AppTradeOrderController { - private final TradeOrderService tradeOrderService; + @Resource + private TradeOrderService tradeOrderService; @GetMapping("/get-create-info") @ApiOperation("基于商品,确认创建订单") @@ -47,7 +47,7 @@ public class AppTradeOrderController { Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); String clientIp = ServletUtil.getClientIP(servletRequest); // 创建交易订单,预支付记录 - Long orderId = tradeOrderService.createTradeOrder(loginUserId, clientIp, createReqVO); + Long orderId = tradeOrderService.createOrder(loginUserId, clientIp, createReqVO); return CommonResult.success(orderId); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/refund/TradeRefundController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/refund/TradeRefundController.java deleted file mode 100644 index aa419190e5..0000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/refund/TradeRefundController.java +++ /dev/null @@ -1,4 +0,0 @@ -package cn.iocoder.yudao.module.trade.controller.app.refund; - -public class TradeRefundController { -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java new file mode 100644 index 0000000000..8354c1fec3 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.trade.convert.aftersale; + +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface TradeAfterSaleConvert { + + TradeAfterSaleConvert INSTANCE = Mappers.getMapper(TradeAfterSaleConvert.class); + + @Mappings({ + @Mapping(target = "id", ignore = true), + @Mapping(target = "createTime", ignore = true), + @Mapping(target = "updateTime", ignore = true), + @Mapping(target = "creator", ignore = true), + @Mapping(target = "updater", ignore = true), + }) + TradeAfterSaleDO convert(AppAfterSaleCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItem); + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index 54abc96984..4e2b747ffe 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; 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.enums.order.TradeOrderItemRefundStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -55,7 +55,7 @@ public interface TradeOrderConvert { TradeOrderItemDO tradeOrderItemDO = convert(orderItem, skuMap.get(orderItem.getSkuId())); tradeOrderItemDO.setOrderId(tradeOrderDO.getId()); tradeOrderItemDO.setUserId(tradeOrderDO.getUserId()); - tradeOrderItemDO.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus()).setRefundTotal(0); // 退款信息 + tradeOrderItemDO.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); // 退款信息 // tradeOrderItemDO.setCommented(false); return tradeOrderItemDO; }); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java index 2e7187b951..327dc8aebd 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java @@ -27,7 +27,7 @@ import java.util.List; public class TradeAfterSaleDO extends BaseDO { /** - * 售后编号,主键自增n + * 售后编号,主键自增 */ private Long id; /** @@ -56,8 +56,10 @@ public class TradeAfterSaleDO extends BaseDO { private Long userId; /** * 申请原因 + * + * 使用数据字典枚举,对应 trade_refund_apply_reason 类型 */ - private String applyReason; + private Integer applyReason; /** * 补充描述 */ diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java index 5dfcf4c6a3..cbee4ada1a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.order; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemRefundStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; @@ -132,26 +132,17 @@ public class TradeOrderItemDO extends BaseDO { // ========== 营销基本信息 ========== + // TODO 芋艿:在捉摸一下 + // ========== 退款基本信息 ========== /** - * 退款状态 TODO + * 退款状态 * - * 枚举 {@link TradeOrderItemRefundStatusEnum} + * 枚举 {@link TradeOrderItemAfterSaleStatusEnum} + * + * @see cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO */ - private Integer refundStatus; // TODO 芋艿:可以考虑去查 - // 如上字段,举个例子: - // 假设购买三个,即 stock = 3 。 - // originPrice = 15 - // 使用限时折扣(单品优惠)8 折,buyPrice = 12 - // 开始算总的价格 - // buyTotal = buyPrice * stock = 12 * 3 = 36 - // discountTotal ,假设有满减送(分组优惠)满 20 减 10 ,并且使用优惠劵满 1.01 减 1 ,则 discountTotal = 10 + 1 = 11 - // presentTotal = buyTotal - discountTotal = 24 - 11 = 13 - // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33 - /** - * 退款总金额,单位:分 TODO - */ - private Integer refundTotal; + private Integer afterSaleStatus; /** * 商品属性 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java new file mode 100644 index 0000000000..af729e80c4 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java @@ -0,0 +1,10 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.aftersale; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TradeAfterSaleMapper extends BaseMapperX { +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/orderitem/TradeOrderItemMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java similarity index 82% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/orderitem/TradeOrderItemMapper.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java index 3a85e0cbb1..6565c73108 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/orderitem/TradeOrderItemMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.trade.dal.mysql.orderitem; +package cn.iocoder.yudao.module.trade.dal.mysql.order; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java new file mode 100644 index 0000000000..1e3c55be1e --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.trade.service.aftersale; + +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; + +/** + * 交易售后 Service 接口 + * + * @author 芋道源码 + */ +public interface TradeAfterSaleService { + + /** + * 创建交易售后 + *

+ * 一般是用户发起售后请求 + * + * @param userId 用户编号 + * @param createReqVO 交易售后 Request 信息 + * @return 交易售后编号 + */ + Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO); + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java new file mode 100644 index 0000000000..3bfd8f7f84 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.trade.service.aftersale; + +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; +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.mysql.aftersale.TradeAfterSaleMapper; +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; + +/** + * 交易售后 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { + + @Resource + private TradeOrderService tradeOrderService; + + @Resource + private TradeAfterSaleMapper tradeAfterSaleMapper; + + @Override + public Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO) { + // 第一步,前置校验 + TradeOrderItemDO tradeOrderItem = validateOrderItemApplicable(userId, createReqVO); + + // 第二步,存储交易售后 + TradeAfterSaleDO afterSale = createAfterSale(createReqVO, tradeOrderItem); + return afterSale.getId(); + } + + private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppAfterSaleCreateReqVO createReqVO) { + // 校验订单项存在 + TradeOrderItemDO orderItem = tradeOrderService.getOrderItem(userId, createReqVO.getOrderItemId()); + if (orderItem == null) { + throw exception(ORDER_ITEM_NOT_FOUND); + } + + // 已申请售后,不允许再发起售后申请 + if (!TradeOrderItemAfterSaleStatusEnum.isNone(orderItem.getAfterSaleStatus())) { + throw exception(AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED); + } + // TODO 芋艿:超过一定时间,不允许售后 + + // 申请的退款金额,不能超过商品的价格 + if (createReqVO.getApplyPrice() > orderItem.getOrderDividePrice()) { + throw exception(AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR); + } + + // 校验订单存在 + TradeOrderDO order = tradeOrderService.getOrder(userId, orderItem.getOrderId()); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + // 已取消,无法发起售后 + if (TradeOrderStatusEnum.isCanceled(order.getStatus())) { + throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED); + } + // 未支付,无法发起售后 + if (!TradeOrderStatusEnum.havePaid(order.getStatus())) { + throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID); + } + // 如果是【退货退款】的情况,需要额外校验是否发货 + if (createReqVO.getType().equals(TradeAfterSaleTypeEnum.RETURN_AND_REFUND.getType()) + && !TradeOrderStatusEnum.haveDelivered(order.getStatus())) { + throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED); + } + return orderItem; + } + + private TradeAfterSaleDO createAfterSale(AppAfterSaleCreateReqVO createReqVO, + TradeOrderItemDO tradeOrderItem) { + // 创建售后单 + TradeAfterSaleDO afterSale = TradeAfterSaleConvert.INSTANCE.convert(createReqVO, tradeOrderItem); + afterSale.setNo(RandomUtil.randomString(10)); // TODO 芋艿:优化 no 生成逻辑 + afterSale.setStatus(TradeAfterSaleStatusEnum.APPLY.getStatus()); + // TODO 退还积分 + tradeAfterSaleMapper.insert(afterSale); + + // 更新交易订单项的售后状态 TODO + + // 发送售后消息 + return afterSale; + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java index f9e635fac2..f6f012da44 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.trade.service.order; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; /** * 交易订单 Service 接口 @@ -13,11 +15,29 @@ public interface TradeOrderService { /** * 创建交易订单 * - * @param loginUserId 登录用户 + * @param userId 登录用户 * @param userIp 用户 IP 地址 * @param createReqVO 创建交易订单请求模型 * @return 交易订单的编号 */ - Long createTradeOrder(Long loginUserId, String userIp, AppTradeOrderCreateReqVO createReqVO); + Long createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO); + + /** + * 获得指定用户,指定的交易订单项 + * + * @param userId 用户编号 + * @param itemId 交易订单项编号 + * @return 交易订单项 + */ + TradeOrderItemDO getOrderItem(Long userId, Long itemId); + + /** + * 获得指定用户,指定的交易订单 + * + * @param userId 用户编号 + * @param orderId 交易订单编号 + * @return 交易订单 + */ + TradeOrderDO getOrder(Long userId, Long orderId); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java index 95df76afe6..1a737a9efd 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java @@ -25,7 +25,7 @@ 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.TradeOrderItemDO; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; -import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper; +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; 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.TradeOrderStatusEnum; @@ -77,7 +77,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { @Override @Transactional(rollbackFor = Exception.class) - public Long createTradeOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { + public Long createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { // 商品 SKU 检查:可售状态、库存 List skus = validateSkuSaleable(createReqVO.getItems()); // 商品 SPU 检查:可售状态 @@ -99,6 +99,26 @@ public class TradeOrderServiceImpl implements TradeOrderService { return tradeOrderDO.getId(); } + @Override + public TradeOrderItemDO getOrderItem(Long userId, Long itemId) { + TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(itemId); + if (orderItem != null + && ObjectUtil.notEqual(orderItem.getUserId(), userId)) { + return null; + } + return orderItem; + } + + @Override + public TradeOrderDO getOrder(Long userId, Long orderId) { + TradeOrderDO order = tradeOrderMapper.selectById(orderId); + if (order != null + && ObjectUtil.notEqual(order.getUserId(), userId)) { + return null; + } + return order; + } + /** * 校验商品 SKU 是否可出售 * @@ -167,7 +187,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { PriceCalculateRespDTO.Order order, AddressRespDTO address) { TradeOrderDO tradeOrderDO = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, order, address); tradeOrderDO.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的; - tradeOrderDO.setStatus(TradeOrderStatusEnum.WAITING_PAYMENT.getStatus()); + tradeOrderDO.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); tradeOrderDO.setType(TradeOrderTypeEnum.NORMAL.getType()); tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum)); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java index 669680c3de..13e33d85f8 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java @@ -19,8 +19,8 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreate 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.mysql.order.TradeOrderMapper; -import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper; -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemRefundStatusEnum; +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.TradeOrderRefundStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; @@ -145,7 +145,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest { }))).thenReturn(1000L); // 调用方法 - Long tradeOrderId = tradeOrderService.createTradeOrder(userId, userIp, reqVO); + Long tradeOrderId = tradeOrderService.createOrder(userId, userIp, reqVO); // 断言 TradeOrderDO 订单 List tradeOrderDOs = tradeOrderMapper.selectList(); assertEquals(tradeOrderDOs.size(), 1); @@ -156,7 +156,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest { assertEquals(tradeOrderDO.getTerminal(), TerminalEnum.H5.getTerminal()); assertEquals(tradeOrderDO.getUserId(), userId); assertEquals(tradeOrderDO.getUserIp(), userIp); - assertEquals(tradeOrderDO.getStatus(), TradeOrderStatusEnum.WAITING_PAYMENT.getStatus()); + assertEquals(tradeOrderDO.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus()); assertEquals(tradeOrderDO.getProductCount(), 7); assertNull(tradeOrderDO.getFinishTime()); assertNull(tradeOrderDO.getCancelTime()); @@ -207,7 +207,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest { assertEquals(tradeOrderItemDO01.getPayPrice(), 130); assertEquals(tradeOrderItemDO01.getOrderPartPrice(), 7); assertEquals(tradeOrderItemDO01.getOrderDividePrice(), 35); - assertEquals(tradeOrderItemDO01.getRefundStatus(), TradeOrderItemRefundStatusEnum.NONE.getStatus()); + assertEquals(tradeOrderItemDO01.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); assertEquals(tradeOrderItemDO01.getRefundTotal(), 0); // 断言 TradeOrderItemDO 订单(第 2 个) TradeOrderItemDO tradeOrderItemDO02 = tradeOrderItemDOs.get(1); @@ -228,7 +228,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest { assertEquals(tradeOrderItemDO02.getPayPrice(), 40); assertEquals(tradeOrderItemDO02.getOrderPartPrice(), 15); assertEquals(tradeOrderItemDO02.getOrderDividePrice(), 25); - assertEquals(tradeOrderItemDO02.getRefundStatus(), TradeOrderItemRefundStatusEnum.NONE.getStatus()); + assertEquals(tradeOrderItemDO02.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); assertEquals(tradeOrderItemDO02.getRefundTotal(), 0); // 校验调用 verify(productSkuApi).updateSkuStock(argThat(new ArgumentMatcher() { From 92dbf093ead8fee50abab79f32e8d6faf406246a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 16 Nov 2022 22:17:07 +0800 Subject: [PATCH 003/110] =?UTF-8?q?trade=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=E5=AE=A1=E6=89=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/enums/ErrorCodeConstants.java | 4 +- .../aftersale/TradeAfterSaleController.java | 40 +++++++ .../vo/TradeAfterSaleAuditReqVO.java | 25 ++++ ....java => AppTradeAfterSaleController.java} | 6 +- ...java => AppTradeAfterSaleCreateReqVO.java} | 2 +- .../aftersale/TradeAfterSaleConvert.java | 14 ++- .../convert/order/TradeOrderConvert.java | 8 +- .../mysql/aftersale/TradeAfterSaleMapper.java | 8 +- .../dal/mysql/order/TradeOrderItemMapper.java | 7 ++ .../aftersale/TradeAfterSaleService.java | 17 ++- .../aftersale/TradeAfterSaleServiceImpl.java | 112 +++++++++++++++++- .../service/order/TradeOrderService.java | 24 +++- .../service/order/TradeOrderServiceImpl.java | 39 +++--- .../module/pay/api/order/PayOrderApi.java | 4 +- .../PayOrderCreateReqDTO.java} | 4 +- .../module/pay/api/refund/PayRefundApi.java | 22 ++++ .../api/refund/dto/PayRefundCreateReqDTO.java | 52 ++++++++ .../yudao/module/pay/api/PayOrderApiImpl.java | 18 --- .../module/pay/api/order/PayOrderApiImpl.java | 36 +++--- .../pay/api/refund/PayRefundApiImpl.java | 21 ++++ 20 files changed, 381 insertions(+), 82 deletions(-) create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/{AppAfterSaleController.java => AppTradeAfterSaleController.java} (87%) rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/{AppAfterSaleCreateReqVO.java => AppTradeAfterSaleCreateReqVO.java} (97%) rename yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/{PayOrderInfoCreateReqDTO.java => dto/PayOrderCreateReqDTO.java} (93%) create mode 100644 yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java create mode 100644 yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java delete mode 100644 yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/PayOrderApiImpl.java create mode 100644 yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 7d31d3cb70..1dfe17472e 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -21,6 +21,7 @@ public interface ErrorCodeConstants { ErrorCode ORDER_ITEM_NOT_FOUND = new ErrorCode(1011000010, "交易订单项不存在"); ErrorCode ORDER_NOT_FOUND = new ErrorCode(1011000010, "交易订单不存在"); + ErrorCode ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL = new ErrorCode(1011000011, "交易订单项更新售后状态失败,请重试"); // ========== After Sale 模块 1-011-000-000 ========== ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在"); @@ -29,9 +30,10 @@ public interface ErrorCodeConstants { ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID = new ErrorCode(1011000103, "订单未支付,无法申请售后"); ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED = new ErrorCode(1011000104, "订单未发货,无法申请【退货退款】售后"); 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_UPDATE_STATUS_FAIL = new ErrorCode(1011000106, "操作售后单失败,请刷新后重试"); // ========== Cart 模块 1-011-001-000 ========== ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); - } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java new file mode 100644 index 0000000000..9a63118600 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.trade.controller.admin.aftersale; + +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.service.aftersale.TradeAfterSaleService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +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; + +import javax.annotation.Resource; + +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.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Api(tags = "管理后台 - 交易售后") +@RestController +@RequestMapping("/trade/after-sale") +@Validated +@Slf4j +public class TradeAfterSaleController { + + @Resource + private TradeAfterSaleService afterSaleService; + + @PutMapping("/audit") + @ApiOperation("审批售后") + @PreAuthorize("@ss.hasPermission('trade:after-sale:audit')") + public CommonResult auditAfterSale(@RequestBody TradeAfterSaleAuditReqVO auditReqVO) { + afterSaleService.auditAfterSale(getLoginUserId(), getClientIP(), auditReqVO); + return success(true); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java new file mode 100644 index 0000000000..1df9a383ae --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java @@ -0,0 +1,25 @@ +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 TradeAfterSaleAuditReqVO { + + @ApiModelProperty(value = "售后编号", required = true, example = "1024") + @NotNull(message = "售后编号不能为空") + private Long id; + + @ApiModelProperty(value = "审批结果", required = true, example = "true", + notes = "true - 通过;false - 不通过") + @NotNull(message = "审批结果不能为空") + private Boolean audit; + + @ApiModelProperty(value = "审批备注", example = "你猜") + private String auditReason; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java similarity index 87% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java index 789b6e52a9..23fd8fcf8d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.trade.controller.app.aftersale; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -22,14 +22,14 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti @RequestMapping("/trade/after-sale") @Validated @Slf4j -public class AppAfterSaleController { +public class AppTradeAfterSaleController { @Resource private TradeAfterSaleService afterSaleService; @PostMapping(value = "/create") @ApiOperation(value = "申请售后") - private CommonResult createAfterSale(@RequestBody AppAfterSaleCreateReqVO createReqVO) { + private CommonResult createAfterSale(@RequestBody AppTradeAfterSaleCreateReqVO createReqVO) { return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO)); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java similarity index 97% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java index eceba596be..32ae406144 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java @@ -12,7 +12,7 @@ import java.util.List; @ApiModel("用户 App - 交易售后创建 Request VO") @Data -public class AppAfterSaleCreateReqVO { +public class AppTradeAfterSaleCreateReqVO { @ApiModelProperty(name = "订单项编号", required = true, example = "1024") @NotNull(message = "订单项编号不能为空") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java index 8354c1fec3..afe918d2ca 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.module.trade.convert.aftersale; -import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; @@ -20,6 +22,14 @@ public interface TradeAfterSaleConvert { @Mapping(target = "creator", ignore = true), @Mapping(target = "updater", ignore = true), }) - TradeAfterSaleDO convert(AppAfterSaleCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItem); + TradeAfterSaleDO convert(AppTradeAfterSaleCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItem); + + @Mappings({ + @Mapping(source = "afterSale.orderId", target = "merchantOrderId"), + @Mapping(source = "afterSale.applyReason", target = "reason"), + @Mapping(source = "afterSale.refundPrice", target = "amount") + }) + PayRefundCreateReqDTO convert(String userIp, TradeAfterSaleDO afterSale, + TradeOrderProperties orderProperties); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index 4e2b747ffe..c67e0e16d3 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.trade.convert.order; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; -import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; @@ -71,9 +71,9 @@ public interface TradeOrderConvert { ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean); List convertList(List list); - default PayOrderInfoCreateReqDTO convert(TradeOrderDO tradeOrderDO, List tradeOrderItemDOs, - List spus, TradeOrderProperties tradeOrderProperties) { - PayOrderInfoCreateReqDTO createReqDTO = new PayOrderInfoCreateReqDTO() + default PayOrderCreateReqDTO convert(TradeOrderDO tradeOrderDO, List tradeOrderItemDOs, + List spus, TradeOrderProperties tradeOrderProperties) { + PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO() .setAppId(tradeOrderProperties.getAppId()).setUserIp(tradeOrderDO.getUserIp()); // 商户相关字段 createReqDTO.setMerchantOrderId(String.valueOf(tradeOrderDO.getId())); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java index af729e80c4..b391c4b85f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java @@ -2,9 +2,15 @@ package cn.iocoder.yudao.module.trade.dal.mysql.aftersale; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; @Mapper public interface TradeAfterSaleMapper extends BaseMapperX { + + default int updateByIdAndStatus(Long id, Integer status, TradeAfterSaleDO update) { + return update(update, new LambdaUpdateWrapper() + .eq(TradeAfterSaleDO::getId, id).eq(TradeAfterSaleDO::getStatus, status)); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java index 6565c73108..0db4f45b47 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java @@ -2,8 +2,15 @@ package cn.iocoder.yudao.module.trade.dal.mysql.order; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; @Mapper public interface TradeOrderItemMapper extends BaseMapperX { + + default int updateAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus) { + return update(new TradeOrderItemDO().setAfterSaleStatus(newAfterSaleStatus), + new LambdaUpdateWrapper<>(new TradeOrderItemDO().setId(id).setAfterSaleStatus(oldAfterSaleStatus))); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java index 1e3c55be1e..ec9e579bf6 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.trade.service.aftersale; -import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; /** * 交易售后 Service 接口 @@ -14,10 +15,18 @@ public interface TradeAfterSaleService { *

* 一般是用户发起售后请求 * - * @param userId 用户编号 - * @param createReqVO 交易售后 Request 信息 + * @param userId 会员用户编号 + * @param createReqVO 创建 Request 信息 * @return 交易售后编号 */ - Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO); + Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO); + /** + * 审批交易售后 + * + * @param userId 管理员用户编号 + * @param userIp 操作 IP + * @param auditReqVO 审批 Request 信息 + */ + void auditAfterSale(Long userId, String userIp, TradeAfterSaleAuditReqVO auditReqVO); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java index 3bfd8f7f84..7e7ee6a807 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java @@ -1,7 +1,10 @@ package cn.iocoder.yudao.module.trade.service.aftersale; import cn.hutool.core.util.RandomUtil; -import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; @@ -11,12 +14,18 @@ import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import cn.iocoder.yudao.module.trade.service.order.TradeOrderService; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.time.LocalDateTime; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; @@ -35,8 +44,15 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { @Resource private TradeAfterSaleMapper tradeAfterSaleMapper; + @Resource + private PayRefundApi payRefundApi; + + @Resource + private TradeOrderProperties tradeOrderProperties; + @Override - public Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO) { + @Transactional(rollbackFor = Exception.class) + public Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) { // 第一步,前置校验 TradeOrderItemDO tradeOrderItem = validateOrderItemApplicable(userId, createReqVO); @@ -45,7 +61,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { return afterSale.getId(); } - private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppAfterSaleCreateReqVO createReqVO) { + private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) { // 校验订单项存在 TradeOrderItemDO orderItem = tradeOrderService.getOrderItem(userId, createReqVO.getOrderItemId()); if (orderItem == null) { @@ -84,7 +100,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { return orderItem; } - private TradeAfterSaleDO createAfterSale(AppAfterSaleCreateReqVO createReqVO, + private TradeAfterSaleDO createAfterSale(AppTradeAfterSaleCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItem) { // 创建售后单 TradeAfterSaleDO afterSale = TradeAfterSaleConvert.INSTANCE.convert(createReqVO, tradeOrderItem); @@ -93,10 +109,94 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { // TODO 退还积分 tradeAfterSaleMapper.insert(afterSale); - // 更新交易订单项的售后状态 TODO + // 更新交易订单项的售后状态 + tradeOrderService.updateOrderItemAfterSaleStatus(tradeOrderItem.getId(), + TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus()); - // 发送售后消息 + // TODO 记录售后日志 + + // TODO 发送售后消息 return afterSale; } + @Override + @Transactional + public void auditAfterSale(Long userId, String userIp, + TradeAfterSaleAuditReqVO auditReqVO) { + // 校验售后单存在,并状态未审批 + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(auditReqVO.getId()); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (afterSale.getStatus().equals(TradeAfterSaleStatusEnum.APPLY.getStatus())) { + throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY); + } + + // 进行审批 + if (auditReqVO.getAudit()) { + auditAfterSalePass(userId, userIp, auditReqVO, afterSale); + } else { + auditAfterSaleReject(userId, auditReqVO, afterSale); + } + } + + private void auditAfterSalePass(Long userId, String userIp, + TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) { + // 更新售后单的状态 + // 情况一:退款:标记为 WAIT_REFUND 状态。后续等退款发起成功后,在标记为 COMPLETE 状态 + // 情况二:退货退款:需要等用户退货后,才能发起退款 + Integer newStatus = afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType()) ? + TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_PASS.getStatus(); + 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); + } + + // TODO 记录售后日志 + + // TODO 发送售后消息 + } + + private void auditAfterSaleReject(Long userId, + TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) { + // 更新售后单的状态 + Integer newStatus = TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus(); + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() + .setStatus(newStatus).setAuditUserId(userId) + .setAuditReason(auditReqVO.getAuditReason()).setAuditTime(LocalDateTime.now())); + + // 更新交易订单项的售后状态为【未申请】 + tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); + + // TODO 记录售后日志 + + // TODO 发送售后消息 + } + + private void createPayRefund(String userIp, TradeAfterSaleDO afterSale) { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + + @Override + public void afterCommit() { + // 创建退款单 + PayRefundCreateReqDTO createReqDTO = TradeAfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties); + Long payRefundId = payRefundApi.createPayRefund(createReqDTO); + // 更新售后单的退款单号 + tradeAfterSaleMapper.updateById(new TradeAfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId)); + } + }); + } + + 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); + } + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java index f6f012da44..6a529decb5 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java @@ -12,6 +12,8 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; */ public interface TradeOrderService { + // =================== Order =================== + /** * 创建交易订单 * @@ -22,6 +24,17 @@ public interface TradeOrderService { */ Long createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO); + /** + * 获得指定用户,指定的交易订单 + * + * @param userId 用户编号 + * @param orderId 交易订单编号 + * @return 交易订单 + */ + TradeOrderDO getOrder(Long userId, Long orderId); + + // =================== Order Item =================== + /** * 获得指定用户,指定的交易订单项 * @@ -32,12 +45,11 @@ public interface TradeOrderService { TradeOrderItemDO getOrderItem(Long userId, Long itemId); /** - * 获得指定用户,指定的交易订单 + * 更新交易订单项的售后状态 * - * @param userId 用户编号 - * @param orderId 交易订单编号 - * @return 交易订单 + * @param id 交易订单项编号 + * @param oldAfterSaleStatus 当前售后状态;如果不符,更新后会抛出异常 + * @param newAfterSaleStatus 目标售后状态 */ - TradeOrderDO getOrder(Long userId, Long orderId); - + void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java index 1a737a9efd..40e8a0eac3 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java @@ -8,7 +8,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.member.api.address.AddressApi; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; -import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; @@ -42,8 +42,7 @@ import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_CREATE_SKU_NOT_SALE; -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_CREATE_SPU_NOT_FOUND; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; /** * 交易订单 Service 实现类 @@ -75,6 +74,8 @@ public class TradeOrderServiceImpl implements TradeOrderService { @Resource private TradeOrderProperties tradeOrderProperties; + // =================== Order =================== + @Override @Transactional(rollbackFor = Exception.class) public Long createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { @@ -99,16 +100,6 @@ public class TradeOrderServiceImpl implements TradeOrderService { return tradeOrderDO.getId(); } - @Override - public TradeOrderItemDO getOrderItem(Long userId, Long itemId) { - TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(itemId); - if (orderItem != null - && ObjectUtil.notEqual(orderItem.getUserId(), userId)) { - return null; - } - return orderItem; - } - @Override public TradeOrderDO getOrder(Long userId, Long orderId) { TradeOrderDO order = tradeOrderMapper.selectById(orderId); @@ -240,7 +231,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { private void createPayOrder(TradeOrderDO tradeOrderDO, List tradeOrderItemDOs, List spus) { // 创建支付单,用于后续的支付 - PayOrderInfoCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( + PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( tradeOrderDO, tradeOrderItemDOs, spus, tradeOrderProperties); Long payOrderId = payOrderApi.createPayOrder(payOrderCreateReqDTO); @@ -248,4 +239,24 @@ public class TradeOrderServiceImpl implements TradeOrderService { tradeOrderMapper.updateById(new TradeOrderDO().setId(tradeOrderDO.getId()).setPayOrderId(payOrderId)); } + // =================== Order =================== + + @Override + public TradeOrderItemDO getOrderItem(Long userId, Long itemId) { + TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(itemId); + if (orderItem != null + && ObjectUtil.notEqual(orderItem.getUserId(), userId)) { + return null; + } + return orderItem; + } + + @Override + public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus) { + int updateCount = tradeOrderItemMapper.updateAfterSaleStatus(id, oldAfterSaleStatus, newAfterSaleStatus); + if (updateCount <= 0) { + throw exception(ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL); + } + } + } diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java index 36022b172b..f6cf7be304 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.pay.api.order; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; + import javax.validation.Valid; /** @@ -16,6 +18,6 @@ public interface PayOrderApi { * @param reqDTO 创建请求 * @return 支付单编号 */ - Long createPayOrder(@Valid PayOrderInfoCreateReqDTO reqDTO); + Long createPayOrder(@Valid PayOrderCreateReqDTO reqDTO); } diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderInfoCreateReqDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderCreateReqDTO.java similarity index 93% rename from yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderInfoCreateReqDTO.java rename to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderCreateReqDTO.java index b5f64478d8..88f0342aff 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderInfoCreateReqDTO.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderCreateReqDTO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.pay.api.order; +package cn.iocoder.yudao.module.pay.api.order.dto; import lombok.Data; import org.hibernate.validator.constraints.Length; @@ -15,7 +15,7 @@ import java.time.LocalDateTime; * @author LeeYan9 */ @Data -public class PayOrderInfoCreateReqDTO implements Serializable { +public class PayOrderCreateReqDTO implements Serializable { /** * 应用编号 diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java new file mode 100644 index 0000000000..50da36e338 --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.pay.api.refund; + +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; + +import javax.validation.Valid; + +/** + * 退款单 API 接口 + * + * @author 芋道源码 + */ +public interface PayRefundApi { + + /** + * 创建退款单 + * + * @param reqDTO 创建请求 + * @return 退款单编号 + */ + Long createPayRefund(@Valid PayRefundCreateReqDTO reqDTO); + +} diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java new file mode 100644 index 0000000000..03c552640c --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.pay.api.refund.dto; + +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 退款单创建 Request DTO + * + * @author 芋道源码 + */ +@Data +public class PayRefundCreateReqDTO { + + /** + * 应用编号 + */ + @NotNull(message = "应用编号不能为空") + private Long appId; + /** + * 用户 IP + */ + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + + // ========== 商户相关字段 ========== + + /** + * 商户订单编号 + */ + @NotEmpty(message = "商户订单编号不能为空") + private String merchantOrderId; + + /** + * 退款描述 + */ + @NotEmpty(message = "退款描述不能为空") + @Length(max = 128, message = "退款描述长度不能超过128") + private String reason; + + // ========== 订单相关字段 ========== + + /** + * 退款金额,单位:分 + */ + @NotNull(message = "退款金额不能为空") + @Min(value = 1, message = "退款金额必须大于零") + private Integer amount; +} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/PayOrderApiImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/PayOrderApiImpl.java deleted file mode 100644 index d5dd64146a..0000000000 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/PayOrderApiImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.pay.api; - -import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; -import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO; -import org.springframework.stereotype.Service; - -/** - * TODO 注释 - */ -@Service -public class PayOrderApiImpl implements PayOrderApi { - - @Override - public Long createPayOrder(PayOrderInfoCreateReqDTO reqDTO) { - return null; - } - -} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java index 6f2556d357..e5a3186e8d 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java @@ -1,19 +1,17 @@ -//package cn.iocoder.yudao.module.pay.api.order; -// -//import org.springframework.stereotype.Service; -//import org.springframework.transaction.annotation.Transactional; -// -///** -// * @author LeeYan9 -// * @since 2022-09-06 -// */ -//@Service -//public class PayOrderApiImpl implements PayOrderApi { -// -// @Override -// @Transactional(rollbackFor = Exception.class) -// public Long createPayOrder(PayOrderInfoCreateReqDTO reqDTO) { -// return null; -// } -// -//} +package cn.iocoder.yudao.module.pay.api.order; + +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import org.springframework.stereotype.Service; + +/** + * TODO 注释 + */ +@Service +public class PayOrderApiImpl implements PayOrderApi { + + @Override + public Long createPayOrder(PayOrderCreateReqDTO reqDTO) { + return null; + } + +} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java new file mode 100644 index 0000000000..27a50572ac --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.pay.api.refund; + +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +/** + * 退款单 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class PayRefundApiImpl implements PayRefundApi { + + @Override + public Long createPayRefund(PayRefundCreateReqDTO reqDTO) { + // TODO 芋艿:暂未实现 + return null; + } +} From 40f0117130ee238615e8f3d0acaa01c460ef2869 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 16 Nov 2022 23:02:10 +0800 Subject: [PATCH 004/110] =?UTF-8?q?trade=EF=BC=9A=E5=94=AE=E5=90=8E?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8F=91=E8=B4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/enums/ErrorCodeConstants.java | 3 +- .../AppTradeAfterSaleController.java | 10 ++++++- .../vo/AppTradeAfterSaleDeliveryReqVO.java | 30 +++++++++++++++++++ .../aftersale/TradeAfterSaleDO.java | 22 +++++++------- .../aftersale/TradeAfterSaleService.java | 10 +++++++ .../aftersale/TradeAfterSaleServiceImpl.java | 27 +++++++++++++++-- 6 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleDeliveryReqVO.java diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 1dfe17472e..cea7ceb4ed 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -31,7 +31,8 @@ public interface ErrorCodeConstants { ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED = new ErrorCode(1011000104, "订单未发货,无法申请【退货退款】售后"); 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_UPDATE_STATUS_FAIL = new ErrorCode(1011000106, "操作售后单失败,请刷新后重试"); + ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(1011000107, "操作售后单失败,请刷新后重试"); + ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_BUYER_RETURN = new ErrorCode(1011000108, "退货失败,售后单状态不处于【买家退货】"); // ========== Cart 模块 1-011-001-000 ========== ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java index 23fd8fcf8d..494085b3fb 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.controller.app.aftersale; import cn.iocoder.yudao.framework.common.pojo.CommonResult; 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.service.aftersale.TradeAfterSaleService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -29,8 +30,15 @@ public class AppTradeAfterSaleController { @PostMapping(value = "/create") @ApiOperation(value = "申请售后") - private CommonResult createAfterSale(@RequestBody AppTradeAfterSaleCreateReqVO createReqVO) { + public CommonResult createAfterSale(@RequestBody AppTradeAfterSaleCreateReqVO createReqVO) { return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO)); } + @PostMapping(value = "/delivery") + @ApiOperation(value = "退回货物") + public CommonResult deliveryAfterSale(@RequestBody AppTradeAfterSaleDeliveryReqVO deliveryReqVO) { + afterSaleService.deliveryAfterSale(getLoginUserId(), deliveryReqVO); + return success(true); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleDeliveryReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleDeliveryReqVO.java new file mode 100644 index 0000000000..0727361d7b --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleDeliveryReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@ApiModel("用户 App - 交易售后退回货物 Request VO") +@Data +public class AppTradeAfterSaleDeliveryReqVO { + + @ApiModelProperty(name = "售后编号", required = true, example = "1024") + @NotNull(message = "售后编号不能为空") + private Long id; + + @ApiModelProperty(name = "退货物流公司编号", required = true, example = "1") + @NotNull(message = "退货物流公司编号不能为空") + private Long logisticsId; + + @ApiModelProperty(name = "退货物流单号", required = true, example = "SF123456789") + @NotNull(message = "退货物流单号不能为空") + private String logisticsNo; + + @ApiModelProperty(name = "退货时间", required = true) + @NotNull(message = "退货时间不能为空") + private LocalDateTime deliveryTime; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java index 327dc8aebd..0fdb43dc0b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java @@ -134,26 +134,26 @@ public class TradeAfterSaleDO extends BaseDO { // ========== 退货相关 ========== /** - * 退货物流公司编号 TODO + * 退货物流公司编号 * - * 关联 ExpressDO 的 id 编号 + * 关联 LogisticsDO 的 id 编号 */ - private Long returnExpressId; // express_name + private Long logisticsId; /** - * 退货物流单号 TODO + * 退货物流单号 */ - private String returnExpressNo; // express_no + private String logisticsNo; /** - * 退货时间 TODO + * 退货时间 */ - private LocalDateTime deliveryTime; // ship_time + private LocalDateTime deliveryTime; /** - * 收获备注 TODO + * 收货时间 */ - private String receiveMemo; // receive_message + private LocalDateTime receiptTime; /** - * 收货时间 TODO + * 收货备注 */ - private LocalDateTime receiveDate; // receive_time + private String receiptMemo; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java index ec9e579bf6..d0ef09342c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java @@ -2,6 +2,7 @@ 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.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO; /** * 交易售后 Service 接口 @@ -29,4 +30,13 @@ public interface TradeAfterSaleService { * @param auditReqVO 审批 Request 信息 */ void auditAfterSale(Long userId, String userIp, TradeAfterSaleAuditReqVO auditReqVO); + + /** + * 退回货物 + * + * @param userId 会员用户编号 + * @param deliveryReqVO 退货 Request 信息 + */ + void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO); + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java index 7e7ee6a807..11b439940f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO; 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.convert.aftersale.TradeAfterSaleConvert; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; @@ -147,7 +148,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { // 情况二:退货退款:需要等用户退货后,才能发起退款 Integer newStatus = afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType()) ? TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_PASS.getStatus(); - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() .setStatus(newStatus).setAuditUserId(userId) .setAuditReason(auditReqVO.getAuditReason()).setAuditTime(LocalDateTime.now())); @@ -165,7 +166,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) { // 更新售后单的状态 Integer newStatus = TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus(); - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() .setStatus(newStatus).setAuditUserId(userId) .setAuditReason(auditReqVO.getAuditReason()).setAuditTime(LocalDateTime.now())); @@ -199,4 +200,26 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { } } + @Override + public void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO) { + // 校验售后单存在,并状态未退货 + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(deliveryReqVO.getId()); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (afterSale.getStatus().equals(TradeAfterSaleStatusEnum.SELLER_PASS.getStatus())) { + throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_BUYER_RETURN); + } + + // 更新售后单的物流信息 + 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 发送售后消息 + } + } From 67050eeaa8047c57df1f5e81bac9e79185f9476a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 17 Nov 2022 00:10:59 +0800 Subject: [PATCH 005/110] =?UTF-8?q?trade=EF=BC=9A=E3=80=90=E4=BA=A4?= =?UTF-8?q?=E6=98=93=E5=94=AE=E5=90=8E=E3=80=91=E7=A1=AE=E8=AE=A4=E6=94=B6?= =?UTF-8?q?=E8=B4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/enums/ErrorCodeConstants.java | 3 +- .../aftersale/TradeAfterSaleController.java | 9 +++ .../vo/TradeAfterSaleAuditReqVO.java | 2 +- .../vo/TradeAfterSaleConfirmReqVO.java | 25 ++++++++ .../aftersale/TradeAfterSaleService.java | 10 +++ .../aftersale/TradeAfterSaleServiceImpl.java | 62 +++++++++++++++++-- 6 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index cea7ceb4ed..c50ee3610b 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -32,7 +32,8 @@ public interface ErrorCodeConstants { 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_UPDATE_STATUS_FAIL = new ErrorCode(1011000107, "操作售后单失败,请刷新后重试"); - ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_BUYER_RETURN = new ErrorCode(1011000108, "退货失败,售后单状态不处于【买家退货】"); + ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_PASS = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】"); + ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_RETURN = new ErrorCode(1011000109, "确认收货失败,售后单状态不处于【待确认收货】"); // ========== Cart 模块 1-011-001-000 ========== ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java index 9a63118600..b5c517253c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.controller.admin.aftersale; 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.TradeAfterSaleConfirmReqVO; import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -37,4 +38,12 @@ public class TradeAfterSaleController { return success(true); } + @PutMapping("/confirm") + @ApiOperation("确认收货") + @PreAuthorize("@ss.hasPermission('trade:after-sale:audit')") + public CommonResult confirmAfterSale(@RequestBody TradeAfterSaleConfirmReqVO confirmReqVO) { + afterSaleService.confirmAfterSale(getLoginUserId(), getClientIP(), confirmReqVO); + return success(true); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java index 1df9a383ae..2ee605e442 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java @@ -17,7 +17,7 @@ public class TradeAfterSaleAuditReqVO { @ApiModelProperty(value = "审批结果", required = true, example = "true", notes = "true - 通过;false - 不通过") @NotNull(message = "审批结果不能为空") - private Boolean audit; + private Boolean pass; @ApiModelProperty(value = "审批备注", example = "你猜") private String auditReason; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java new file mode 100644 index 0000000000..1c9a1fe6ec --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java @@ -0,0 +1,25 @@ +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; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java index d0ef09342c..82f577981d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java @@ -1,6 +1,7 @@ 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.TradeAfterSaleConfirmReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO; @@ -39,4 +40,13 @@ public interface TradeAfterSaleService { */ void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO); + /** + * 确认收货 + * + * @param userId 管理员用户编号 + * @param userIp 操作 IP + * @param confirmReqVO 收货 Request 信息 + */ + void confirmAfterSale(Long userId, String userIp, TradeAfterSaleConfirmReqVO confirmReqVO); + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java index 11b439940f..f9033fb65c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.trade.service.aftersale; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; 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.AppTradeAfterSaleDeliveryReqVO; import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert; @@ -129,12 +131,12 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { if (afterSale == null) { throw exception(AFTER_SALE_NOT_FOUND); } - if (afterSale.getStatus().equals(TradeAfterSaleStatusEnum.APPLY.getStatus())) { + if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus())) { throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY); } // 进行审批 - if (auditReqVO.getAudit()) { + if (auditReqVO.getPass()) { auditAfterSalePass(userId, userIp, auditReqVO, afterSale); } else { auditAfterSaleReject(userId, auditReqVO, afterSale); @@ -207,8 +209,8 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { if (afterSale == null) { throw exception(AFTER_SALE_NOT_FOUND); } - if (afterSale.getStatus().equals(TradeAfterSaleStatusEnum.SELLER_PASS.getStatus())) { - throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_BUYER_RETURN); + if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.SELLER_PASS.getStatus())) { + throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_PASS); } // 更新售后单的物流信息 @@ -222,4 +224,56 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { // 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 发送售后消息 + } + } From ee1d362a7ccac4c917ac2ae8ccbda0663683ec77 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 17 Nov 2022 01:05:12 +0800 Subject: [PATCH 006/110] =?UTF-8?q?trade=EF=BC=9A=E3=80=90=E4=BA=A4?= =?UTF-8?q?=E6=98=93=E5=94=AE=E5=90=8E=E3=80=91=E5=9B=9E=E8=B0=83=E9=80=80?= =?UTF-8?q?=E6=AC=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/enums/ErrorCodeConstants.java | 3 ++ .../aftersale/TradeAfterSaleController.java | 16 ++++++-- .../aftersale/TradeAfterSaleDO.java | 9 ++++- .../mysql/aftersale/TradeAfterSaleMapper.java | 4 ++ .../aftersale/TradeAfterSaleService.java | 7 ++++ .../aftersale/TradeAfterSaleServiceImpl.java | 40 +++++++++++++++++++ .../module/pay/api/refund/PayRefundApi.java | 9 +++++ .../pay/api/refund/dto/PayRefundRespDTO.java | 37 +++++++++++++++++ .../pay/enums/order/PayOrderStatusEnum.java | 0 .../pay/enums/refund/PayRefundStatusEnum.java | 7 ++++ .../pay/api/refund/PayRefundApiImpl.java | 8 ++++ .../dal/dataobject/refund/PayRefundDO.java | 2 - 12 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java rename yudao-module-pay/{yudao-module-pay-biz => yudao-module-pay-api}/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java (100%) rename yudao-module-pay/{yudao-module-pay-biz => yudao-module-pay-api}/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java (71%) diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index c50ee3610b..0a647c01b5 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -34,6 +34,9 @@ public interface ErrorCodeConstants { ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(1011000107, "操作售后单失败,请刷新后重试"); ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_PASS = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】"); ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_RETURN = new ErrorCode(1011000109, "确认收货失败,售后单状态不处于【待确认收货】"); + ErrorCode AFTER_SALE_REFUND_FAIL_PAY_REFUND_NOT_FOUND = 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 ========== ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java index b5c517253c..3f94bee9a6 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java @@ -5,16 +5,15 @@ import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSal import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO; import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; -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; +import org.springframework.web.bind.annotation.*; 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.util.servlet.ServletUtils.getClientIP; @@ -46,4 +45,13 @@ public class TradeAfterSaleController { return success(true); } + @PostMapping("/refund") + @ApiOperation(value = "确认退款", notes = "提供给【pay】支付服务,退款成功后进行回调") + @ApiImplicitParam(name = "payRefundId", value = "支付退款编号", required = true, example = "18888") + @PermitAll + public CommonResult refundAfterSale(@RequestParam("payRefundId") Long payRefundId) { + afterSaleService.refundAfterSale(payRefundId); + return success(true); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java index 0fdb43dc0b..ee3d48a3ae 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java @@ -125,12 +125,17 @@ public class TradeAfterSaleDO extends BaseDO { */ private Integer refundPrice; /** - * 支付退款编号 TODO + * 支付退款编号 * * 对接 pay-module-biz 支付服务的退款订单编号,即 PayRefundDO 的 id 编号 */ private Long payRefundId; - // TODO 芋艿:看看是否有必要冗余,order_number、order_amount、flow_trade_no、out_refund_no、pay_type、return_money_sts、refund_time + /** + * 退款时间 + * + * 退款成功后,才记录该时间 + */ + private LocalDateTime refundTime; // ========== 退货相关 ========== /** diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java index b391c4b85f..4e03a33de0 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java @@ -13,4 +13,8 @@ public interface TradeAfterSaleMapper extends BaseMapperX { .eq(TradeAfterSaleDO::getId, id).eq(TradeAfterSaleDO::getStatus, status)); } + default TradeAfterSaleDO selectByPayRefundId(Long payRefundId) { + return selectOne(TradeAfterSaleDO::getPayRefundId, payRefundId); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java index 82f577981d..0027bd43d5 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java @@ -49,4 +49,11 @@ public interface TradeAfterSaleService { */ void confirmAfterSale(Long userId, String userIp, TradeAfterSaleConfirmReqVO confirmReqVO); + /** + * 确认退款,由【pay】支付服务回调 + * + * @param payRefundId 支付退款编号 + */ + void refundAfterSale(Long payRefundId); + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java index f9033fb65c..85473513d2 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java @@ -4,6 +4,8 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; 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.PayRefundRespDTO; +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; 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; @@ -276,4 +278,42 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { // 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; + } + } diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java index 50da36e338..395ba1220a 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.pay.api.refund; import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; import javax.validation.Valid; @@ -19,4 +20,12 @@ public interface PayRefundApi { */ Long createPayRefund(@Valid PayRefundCreateReqDTO reqDTO); + /** + * 获得退款单 + * + * @param id 退款单编号 + * @return 退款单 + */ + PayRefundRespDTO getPayRefund(Long id); + } diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java new file mode 100644 index 0000000000..c3bd38b5e3 --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.pay.api.refund.dto; + +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 退款单信息 Response DTO + * + * TODO 芋艿:还没定好字段 + * + * @author 芋道源码 + */ +@Data +public class PayRefundRespDTO { + + /** + * 退款单编号 + */ + private Long id; + + // ========== 退款相关字段 ========== + /** + * 退款状态 + * + * 枚举 {@link PayRefundStatusEnum} + */ + private Integer status; + + // ========== 渠道相关字段 ========== + /** + * 退款成功时间 + */ + private LocalDateTime successTime; + +} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java similarity index 100% rename from yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java rename to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java similarity index 71% rename from yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java rename to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java index 390804dd3a..3fb8213f53 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.pay.enums.refund; import lombok.AllArgsConstructor; import lombok.Getter; +import java.util.Objects; + @Getter @AllArgsConstructor public enum PayRefundStatusEnum { @@ -14,4 +16,9 @@ public enum PayRefundStatusEnum { private final Integer status; private final String name; + + public static boolean isSuccess(Integer status) { + return Objects.equals(status, SUCCESS.getStatus()); + } + } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java index 27a50572ac..454aa7b87e 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.pay.api.refund; import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -18,4 +19,11 @@ public class PayRefundApiImpl implements PayRefundApi { // TODO 芋艿:暂未实现 return null; } + + @Override + public PayRefundRespDTO getPayRefund(Long id) { + // TODO 芋艿:暂未实现 + return null; + } + } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java index 1ad5aa1c73..06788440d8 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java @@ -194,6 +194,4 @@ public class PayRefundDO extends BaseDO { private LocalDateTime notifyTime; - - } From cd2bc112cc4a12e0172beaa99f4ed6224d391669 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 18 Nov 2022 00:28:41 +0800 Subject: [PATCH 007/110] =?UTF-8?q?trade=EF=BC=9A=E3=80=90=E4=BA=A4?= =?UTF-8?q?=E6=98=93=E5=94=AE=E5=90=8E=E3=80=91=E5=AE=8C=E5=96=84=E5=8F=91?= =?UTF-8?q?=E8=B5=B7=E3=80=81=E5=90=8C=E6=84=8F=E3=80=81=E4=B8=8D=E5=90=8C?= =?UTF-8?q?=E6=84=8F=E3=80=81=E6=94=B6=E8=B4=A7=E3=80=81=E6=8B=92=E7=BB=9D?= =?UTF-8?q?=E6=94=B6=E8=B4=A7=E3=80=81=E9=80=80=E6=AC=BE=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/enums/ErrorCodeConstants.java | 8 +- .../aftersale/TradeAfterSaleStatusEnum.java | 10 +- ...ava => TradeOrderAfterSaleStatusEnum.java} | 4 +- .../enums/order/TradeOrderCancelTypeEnum.java | 4 +- .../aftersale/TradeAfterSaleController.java | 42 ++- .../vo/TradeAfterSaleConfirmReqVO.java | 25 -- ....java => TradeAfterSaleDisagreeReqVO.java} | 13 +- .../vo/TradeAfterSaleRefuseReqVO.java | 21 ++ .../aftersale/TradeAfterSaleDO.java | 10 +- .../dal/dataobject/order/TradeOrderDO.java | 8 +- .../dal/mysql/order/TradeOrderItemMapper.java | 6 + .../aftersale/TradeAfterSaleService.java | 48 ++- .../aftersale/TradeAfterSaleServiceImpl.java | 313 +++++++++--------- .../service/order/TradeOrderService.java | 4 +- .../service/order/TradeOrderServiceImpl.java | 55 ++- .../service/order/TradeOrderServiceTest.java | 4 +- 16 files changed, 322 insertions(+), 253 deletions(-) rename yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/{TradeOrderRefundStatusEnum.java => TradeOrderAfterSaleStatusEnum.java} (83%) delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/{TradeAfterSaleAuditReqVO.java => TradeAfterSaleDisagreeReqVO.java} (52%) create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleRefuseReqVO.java diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 0a647c01b5..60dd89ec05 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -32,11 +32,9 @@ public interface ErrorCodeConstants { 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_UPDATE_STATUS_FAIL = new ErrorCode(1011000107, "操作售后单失败,请刷新后重试"); - ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_PASS = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】"); - ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_RETURN = new ErrorCode(1011000109, "确认收货失败,售后单状态不处于【待确认收货】"); - ErrorCode AFTER_SALE_REFUND_FAIL_PAY_REFUND_NOT_FOUND = 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, "退款失败,售后单状态不是【待退款】"); + ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】"); + ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY = new ErrorCode(1011000109, "确认收货失败,售后单状态不处于【待确认收货】"); + ErrorCode AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND = new ErrorCode(1011000110, "退款失败,售后单状态不是【待退款】"); // ========== Cart 模块 1-011-001-000 ========== ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java index 8d8df958cb..e03520ea76 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java @@ -15,14 +15,14 @@ import lombok.Getter; public enum TradeAfterSaleStatusEnum { APPLY(10,"申请中"), - SELLER_PASS(20, "已通过"), // 卖家通过售后 - BUYER_RETURN(30,"待卖家收货"), // 买家退货,等待卖家收货 - WAIT_REFUND(40, "等待平台退款"), // 卖家收货,等待平台退款 + SELLER_AGREE(20, "卖家通过"), // 卖家通过售后 + BUYER_DELIVERY(30,"待卖家收货"), // 买家已退货,等待卖家收货 + WAIT_REFUND(40, "等待平台退款"), // 卖家已收货,等待平台退款 COMPLETE(50, "完成"), // 完成退款 BUYER_CANCEL(61, "买家取消售后"), - SELLER_REFUSE(62,"已拒绝"), // 卖家拒绝售后 - SELLER_TERMINATION(63,"卖家终止售后"), // 卖家拒绝收货,终止售后 + SELLER_DISAGREE(62,"卖家拒绝"), // 卖家拒绝售后 + SELLER_REFUSE(63,"卖家拒绝收货"), // 卖家拒绝收货,终止售后 ; /** diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderRefundStatusEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderAfterSaleStatusEnum.java similarity index 83% rename from yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderRefundStatusEnum.java rename to yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderAfterSaleStatusEnum.java index 50fd88b123..d3388bfcb4 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderRefundStatusEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderAfterSaleStatusEnum.java @@ -4,13 +4,13 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; /** - * 交易订单 - 退款状态 + * 交易订单 - 售后状态 * * @author Sin */ @RequiredArgsConstructor @Getter -public enum TradeOrderRefundStatusEnum { +public enum TradeOrderAfterSaleStatusEnum { NONE(0, "未退款"), PART(1, "部分退款"), diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java index 670651d4e2..389fc75b07 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java @@ -13,9 +13,9 @@ import lombok.RequiredArgsConstructor; public enum TradeOrderCancelTypeEnum { PAY_TIMEOUT(10, "超时未支付"), - REFUND_CLOSE(20, "退款关闭"), + AFTER_SALE_CLOSE(20, "退款关闭"), MEMBER_CANCEL(30, "买家取消"), - PAY_ON_DELIVERY(40, "已通过货到付款交易"),; + PAY_ON_DELIVERY(40, "已通过货到付款交易"),; // TODO 芋艿:这个类型,是不是可以去掉 /** * 关闭类型 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java index 3f94bee9a6..945b194960 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java @@ -1,8 +1,7 @@ package cn.iocoder.yudao.module.trade.controller.admin.aftersale; 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.TradeAfterSaleConfirmReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO; import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; @@ -13,7 +12,6 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; 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.util.servlet.ServletUtils.getClientIP; @@ -29,28 +27,38 @@ public class TradeAfterSaleController { @Resource private TradeAfterSaleService afterSaleService; - @PutMapping("/audit") - @ApiOperation("审批售后") - @PreAuthorize("@ss.hasPermission('trade:after-sale:audit')") - public CommonResult auditAfterSale(@RequestBody TradeAfterSaleAuditReqVO auditReqVO) { - afterSaleService.auditAfterSale(getLoginUserId(), getClientIP(), auditReqVO); + @PutMapping("/agree") + @ApiOperation("同意售后") + @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:after-sale:agree')") + public CommonResult agreeAfterSale(@RequestParam("id") Long id) { + afterSaleService.agreeAfterSale(getLoginUserId(), id); return success(true); } - @PutMapping("/confirm") + @PutMapping("/disagree") + @ApiOperation("拒绝售后") + @PreAuthorize("@ss.hasPermission('trade:after-sale:disagree')") + public CommonResult disagreeAfterSale(@RequestBody TradeAfterSaleDisagreeReqVO confirmReqVO) { + afterSaleService.disagreeAfterSale(getLoginUserId(), confirmReqVO); + return success(true); + } + + @PutMapping("/receive") @ApiOperation("确认收货") - @PreAuthorize("@ss.hasPermission('trade:after-sale:audit')") - public CommonResult confirmAfterSale(@RequestBody TradeAfterSaleConfirmReqVO confirmReqVO) { - afterSaleService.confirmAfterSale(getLoginUserId(), getClientIP(), confirmReqVO); + @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:after-sale:receive')") + public CommonResult receiveAfterSale(@RequestParam("id") Long id) { + afterSaleService.receiveAfterSale(getLoginUserId(), id); return success(true); } @PostMapping("/refund") - @ApiOperation(value = "确认退款", notes = "提供给【pay】支付服务,退款成功后进行回调") - @ApiImplicitParam(name = "payRefundId", value = "支付退款编号", required = true, example = "18888") - @PermitAll - public CommonResult refundAfterSale(@RequestParam("payRefundId") Long payRefundId) { - afterSaleService.refundAfterSale(payRefundId); + @ApiOperation(value = "确认退款") + @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:after-sale:refund')") + public CommonResult refundAfterSale(@RequestParam("id") Long id) { + afterSaleService.refundAfterSale(getLoginUserId(), getClientIP(), id); return success(true); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java deleted file mode 100644 index 1c9a1fe6ec..0000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java +++ /dev/null @@ -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; - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleDisagreeReqVO.java similarity index 52% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleDisagreeReqVO.java index 2ee605e442..67baca3b7a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleDisagreeReqVO.java @@ -4,22 +4,19 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -@ApiModel("管理后台 - 交易售后审批 Request VO") +@ApiModel("管理后台 - 交易售后拒绝 Request VO") @Data -public class TradeAfterSaleAuditReqVO { +public class TradeAfterSaleDisagreeReqVO { @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 = "你猜") + @ApiModelProperty(value = "审批备注", required = true, example = "你猜") + @NotEmpty(message = "审批备注不能为空") private String auditReason; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleRefuseReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleRefuseReqVO.java new file mode 100644 index 0000000000..b74d73c7c9 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleRefuseReqVO.java @@ -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; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java index ee3d48a3ae..467edd0d81 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java @@ -86,6 +86,8 @@ public class TradeAfterSaleDO extends BaseDO { private Long auditUserId; /** * 审批备注 + * + * 注意,只有审批不通过才会填写 */ private String auditReason; @@ -132,8 +134,6 @@ public class TradeAfterSaleDO extends BaseDO { private Long payRefundId; /** * 退款时间 - * - * 退款成功后,才记录该时间 */ private LocalDateTime refundTime; @@ -155,10 +155,12 @@ public class TradeAfterSaleDO extends BaseDO { /** * 收货时间 */ - private LocalDateTime receiptTime; + private LocalDateTime receiveTime; /** * 收货备注 + * + * 注意,只有拒绝收货才会填写 */ - private String receiptMemo; + private String receiveReason; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java index 4d68799b99..fa0eb2ee60 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java @@ -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.module.promotion.api.price.dto.PriceCalculateRespDTO.OrderItem; 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.TradeOrderTypeEnum; 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; /** * 退款金额,单位:分 * diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java index 0db4f45b47..1eb83825f9 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java @@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + @Mapper public interface TradeOrderItemMapper extends BaseMapperX { @@ -13,4 +15,8 @@ public interface TradeOrderItemMapper extends BaseMapperX { new LambdaUpdateWrapper<>(new TradeOrderItemDO().setId(id).setAfterSaleStatus(oldAfterSaleStatus))); } + default List selectListByOrderId(Long orderId) { + return selectList(TradeOrderItemDO::getOrderId, orderId); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java index 0027bd43d5..1eff8c94a2 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java @@ -1,7 +1,7 @@ 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.TradeAfterSaleConfirmReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO; +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.AppTradeAfterSaleDeliveryReqVO; @@ -13,7 +13,7 @@ import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSa public interface TradeAfterSaleService { /** - * 创建交易售后 + * 【会员】创建交易售后 *

* 一般是用户发起售后请求 * @@ -24,16 +24,23 @@ public interface TradeAfterSaleService { Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO); /** - * 审批交易售后 + * 【管理员】同意交易售后 * * @param userId 管理员用户编号 - * @param userIp 操作 IP - * @param auditReqVO 审批 Request 信息 + * @param id 交易售后编号 */ - 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 deliveryReqVO 退货 Request 信息 @@ -41,19 +48,28 @@ public interface TradeAfterSaleService { void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO); /** - * 确认收货 + * 【管理员】确认收货 * - * @param userId 管理员用户编号 - * @param userIp 操作 IP - * @param confirmReqVO 收货 Request 信息 + * @param userId 管理员编号 + * @param id 交易售后编号 */ - 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); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java index 85473513d2..7db32ff2be 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java @@ -4,10 +4,8 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; 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.PayRefundRespDTO; -import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; -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.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO; +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.AppTradeAfterSaleDeliveryReqVO; 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 javax.annotation.Resource; - import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -66,6 +63,13 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { return afterSale.getId(); } + /** + * 校验交易订单项是否可以申请售后 + * + * @param userId 用户编号 + * @param createReqVO 售后创建信息 + * @return 交易订单项 + */ private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) { // 校验订单项存在 TradeOrderItemDO orderItem = tradeOrderService.getOrderItem(userId, createReqVO.getOrderItemId()); @@ -116,7 +120,8 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { // 更新交易订单项的售后状态 tradeOrderService.updateOrderItemAfterSaleStatus(tradeOrderItem.getId(), - TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus()); + TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), null); // TODO 记录售后日志 @@ -125,62 +130,179 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { } @Override - @Transactional - public void auditAfterSale(Long userId, String userIp, - TradeAfterSaleAuditReqVO auditReqVO) { + @Transactional(rollbackFor = Exception.class) + public void agreeAfterSale(Long userId, Long id) { // 校验售后单存在,并状态未审批 - 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) { throw exception(AFTER_SALE_NOT_FOUND); } if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus())) { throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY); } + return afterSale; + } - // 进行审批 - if (auditReqVO.getPass()) { - auditAfterSalePass(userId, userIp, auditReqVO, afterSale); - } else { - auditAfterSaleReject(userId, auditReqVO, afterSale); + 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); } } - private void auditAfterSalePass(Long userId, String userIp, - TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) { - // 更新售后单的状态 - // 情况一:退款:标记为 WAIT_REFUND 状态。后续等退款发起成功后,在标记为 COMPLETE 状态 - // 情况二:退货退款:需要等用户退货后,才能发起退款 - Integer newStatus = afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType()) ? - TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_PASS.getStatus(); - 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); + @Override + @Transactional(rollbackFor = Exception.class) + 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_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 发送售后消息 } - private void auditAfterSaleReject(Long userId, - TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) { + @Override + @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.APPLY.getStatus(), new TradeAfterSaleDO() - .setStatus(newStatus).setAuditUserId(userId) - .setAuditReason(auditReqVO.getAuditReason()).setAuditTime(LocalDateTime.now())); + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new TradeAfterSaleDO() + .setStatus(TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus()).setReceiveTime(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(), - 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 发送售后消息 + + // 更新交易订单项的售后状态为【已完成】 + tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), + TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus(), afterSale.getRefundPrice()); } 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; - } - } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java index 6a529decb5..be101bbe6d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java @@ -50,6 +50,8 @@ public interface TradeOrderService { * @param id 交易订单项编号 * @param oldAfterSaleStatus 当前售后状态;如果不符,更新后会抛出异常 * @param newAfterSaleStatus 目标售后状态 + * @param refundPrice 退款金额;当订单项退款成功时,必须传递该值 */ - void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus); + void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, + Integer newAfterSaleStatus, Integer refundPrice); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java index 40e8a0eac3..912c5116e5 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.service.order; import cn.hutool.core.util.IdUtil; 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.TerminalEnum; 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.dal.dataobject.order.TradeOrderDO; 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.TradeOrderMapper; 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.TradeOrderStatusEnum; -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.*; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.Objects; @@ -180,12 +180,12 @@ public class TradeOrderServiceImpl implements TradeOrderService { tradeOrderDO.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的; tradeOrderDO.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); 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.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? tradeOrderDO.setAdjustPrice(0).setPayed(false); // 支付信息 tradeOrderDO.setDeliveryStatus(false); // 物流信息 - tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息 + tradeOrderDO.setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息 tradeOrderMapper.insert(tradeOrderDO); return tradeOrderDO; } @@ -252,11 +252,52 @@ public class TradeOrderServiceImpl implements TradeOrderService { } @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); if (updateCount <= 0) { 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 orderItems = tradeOrderItemMapper.selectListByOrderId(id); + return orderItems.stream().allMatch(orderItem -> Objects.equals(orderItem.getAfterSaleStatus(), + TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())); } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java index 13e33d85f8..66e494b1ca 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java @@ -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.TradeOrderItemMapper; 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.TradeOrderTypeEnum; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig; @@ -182,7 +182,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest { assertEquals(tradeOrderDO.getReceiverAreaId(), 3306L); assertEquals(tradeOrderDO.getReceiverPostCode(), 85757); assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村"); - assertEquals(tradeOrderDO.getRefundStatus(), TradeOrderRefundStatusEnum.NONE.getStatus()); + assertEquals(tradeOrderDO.getAfterSaleStatus(), TradeOrderAfterSaleStatusEnum.NONE.getStatus()); assertEquals(tradeOrderDO.getRefundPrice(), 0); assertEquals(tradeOrderDO.getCouponPrice(), 30); assertEquals(tradeOrderDO.getPointPrice(), 10); From 78ae0183203d1f3628d19c61e4ad10d6880c5174 Mon Sep 17 00:00:00 2001 From: "LAPTOP-CNV4CMCJ\\cheng" <1315228474@qq.com> Date: Sat, 19 Nov 2022 00:40:13 +0800 Subject: [PATCH 008/110] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=80=80=E6=AC=BE?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E9=A1=B5=20=E8=B0=83=E6=95=B4=E5=95=86?= =?UTF-8?q?=E5=93=81=E5=88=97=E8=A1=A8=E9=A1=B5=E7=9A=84tab=E5=88=87?= =?UTF-8?q?=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-ui-admin/src/router/index.js | 6 + .../src/views/mall/trade/order/detail.vue | 10 + .../src/views/mall/trade/order/index.vue | 146 ++++----- .../views/mall/trade/orderrefund/index.vue | 289 ++++++++++++++++++ 4 files changed, 378 insertions(+), 73 deletions(-) create mode 100644 yudao-ui-admin/src/views/mall/trade/orderrefund/index.vue diff --git a/yudao-ui-admin/src/router/index.js b/yudao-ui-admin/src/router/index.js index 309a7a3b81..133eed1860 100644 --- a/yudao-ui-admin/src/router/index.js +++ b/yudao-ui-admin/src/router/index.js @@ -216,6 +216,12 @@ export const constantRoutes = [ hidden: true, meta: { title: '订单详情' }, component: (resolve) => require(['@/views/mall/trade/order/detail'], resolve) + }, + { + path: '/mall/trade/orderrefund', + name: '退款维权', + meta: { title: '退款维权' }, + component: (resolve) => require(['@/views/mall/trade/orderrefund'], resolve) } ] } diff --git a/yudao-ui-admin/src/views/mall/trade/order/detail.vue b/yudao-ui-admin/src/views/mall/trade/order/detail.vue index 4e50d8f410..13a6c3dee8 100644 --- a/yudao-ui-admin/src/views/mall/trade/order/detail.vue +++ b/yudao-ui-admin/src/views/mall/trade/order/detail.vue @@ -195,6 +195,16 @@ export default { } ], goodsList: [ // 包裹下的商品列表 + { + name: 'Otic 巴拉啦小魔仙联名麦克风儿童早教家用一体卡拉OK宝宝话筒唱歌 魔仙粉', + count: 6, + imgUrl: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg' + }, + { + name: 'Otic 巴拉啦小魔仙联名麦克风儿童早教家用一体卡拉OK宝宝话筒唱歌 魔仙粉', + count: 6, + imgUrl: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg' + }, { name: 'Otic 巴拉啦小魔仙联名麦克风儿童早教家用一体卡拉OK宝宝话筒唱歌 魔仙粉', count: 6, diff --git a/yudao-ui-admin/src/views/mall/trade/order/index.vue b/yudao-ui-admin/src/views/mall/trade/order/index.vue index 9b9da05651..91e81da744 100644 --- a/yudao-ui-admin/src/views/mall/trade/order/index.vue +++ b/yudao-ui-admin/src/views/mall/trade/order/index.vue @@ -63,70 +63,71 @@ - - {{tabPane.text}} - - - - - - - - + + + + + + + + + + @@ -234,14 +235,14 @@ }, activeTabName: 'all', tabPanes: [ - { text: '全部', label: 'all' }, - { text: '待支付', label: 'toBePay' }, - { text: '待发货', label: 'toBeSend' }, - { text: '已发货', label: 'send' }, - { text: '已收货', label: 'received' }, - { text: '已完成', label: 'finished' }, - { text: '已关闭', label: 'closed' }, - { text: '退款中', label: 'refund' } + { text: '全部', name: 'all' }, + { text: '待支付', name: 'toBePay' }, + { text: '待发货', name: 'toBeSend' }, + { text: '已发货', name: 'send' }, + { text: '已收货', name: 'received' }, + { text: '已完成', name: 'finished' }, + { text: '已关闭', name: 'closed' }, + { text: '退款中', name: 'refund' } ], tableData: [ { @@ -333,7 +334,6 @@ From e95402ab920864ab7fd69710df4c2f88d9e4fa84 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 19 Nov 2022 09:18:19 +0800 Subject: [PATCH 009/110] =?UTF-8?q?trade=EF=BC=9A=E3=80=90=E4=BA=A4?= =?UTF-8?q?=E6=98=93=E8=AE=A2=E5=8D=95=E3=80=91=E8=B0=83=E6=95=B4=E4=BA=A4?= =?UTF-8?q?=E6=98=93=E8=AE=A2=E5=8D=95=E7=9A=84=20afterSale=20=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/dataobject/sku/ProductSkuDO.java | 1 + .../aftersale/TradeAfterSaleDO.java | 2 +- .../dal/dataobject/order/TradeOrderDO.java | 1 - .../dataobject/order/TradeOrderItemDO.java | 4 ++- .../service/order/TradeOrderServiceTest.java | 27 +++++++------------ .../src/test/resources/sql/create_tables.sql | 5 ++-- 6 files changed, 16 insertions(+), 24 deletions(-) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java index f953534ed3..019edf2bff 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java @@ -38,6 +38,7 @@ public class ProductSkuDO extends BaseDO { /** * 商品 SKU 名字 */ + @Deprecated // TODO 芋艿:参考有赞,不需要 sku 的标题 private String name; /** * SPU 编号 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java index 467edd0d81..42a785f820 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java @@ -20,7 +20,7 @@ import java.util.List; * * @author 芋道源码 */ -@TableName(value = "trade_refund") +@TableName(value = "trade_after_sale") @Data @EqualsAndHashCode(callSuper = true) @Accessors(chain = true) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java index fa0eb2ee60..cf4c2276f7 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java @@ -71,7 +71,6 @@ public class TradeOrderDO extends BaseDO { * 枚举 {@link TradeOrderStatusEnum} */ private Integer status; - // TODO 芋艿:要不要存储 prod_name 购买的商品名门? /** * 购买的商品数量 */ diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java index cbee4ada1a..9a385d8719 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java @@ -61,6 +61,8 @@ public class TradeOrderItemDO extends BaseDO { private List properties; /** * 商品名称 + * + * 冗余 ProductSpuDO 的 name 字段 */ private String name; /** @@ -136,7 +138,7 @@ public class TradeOrderItemDO extends BaseDO { // ========== 退款基本信息 ========== /** - * 退款状态 + * 售后状态 * * 枚举 {@link TradeOrderItemAfterSaleStatusEnum} * diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java index 66e494b1ca..e74a7b9287 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java @@ -8,7 +8,6 @@ import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; @@ -18,17 +17,16 @@ import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; 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.mysql.order.TradeOrderMapper; 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.dal.mysql.order.TradeOrderMapper; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderAfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; 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.TradeOrderConfig; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatcher; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; @@ -208,7 +206,6 @@ class TradeOrderServiceTest extends BaseDbUnitTest { assertEquals(tradeOrderItemDO01.getOrderPartPrice(), 7); assertEquals(tradeOrderItemDO01.getOrderDividePrice(), 35); assertEquals(tradeOrderItemDO01.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); - assertEquals(tradeOrderItemDO01.getRefundTotal(), 0); // 断言 TradeOrderItemDO 订单(第 2 个) TradeOrderItemDO tradeOrderItemDO02 = tradeOrderItemDOs.get(1); assertNotNull(tradeOrderItemDO02.getId()); @@ -229,20 +226,14 @@ class TradeOrderServiceTest extends BaseDbUnitTest { assertEquals(tradeOrderItemDO02.getOrderPartPrice(), 15); assertEquals(tradeOrderItemDO02.getOrderDividePrice(), 25); assertEquals(tradeOrderItemDO02.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); - assertEquals(tradeOrderItemDO02.getRefundTotal(), 0); // 校验调用 - verify(productSkuApi).updateSkuStock(argThat(new ArgumentMatcher() { - - @Override - public boolean matches(ProductSkuUpdateStockReqDTO updateStockReqDTO) { - assertEquals(updateStockReqDTO.getItems().size(), 2); - assertEquals(updateStockReqDTO.getItems().get(0).getId(), 1L); - assertEquals(updateStockReqDTO.getItems().get(0).getIncrCount(), 3); - assertEquals(updateStockReqDTO.getItems().get(1).getId(), 2L); - assertEquals(updateStockReqDTO.getItems().get(1).getIncrCount(), 4); - return true; - } - + verify(productSkuApi).updateSkuStock(argThat(updateStockReqDTO -> { + assertEquals(updateStockReqDTO.getItems().size(), 2); + assertEquals(updateStockReqDTO.getItems().get(0).getId(), 1L); + assertEquals(updateStockReqDTO.getItems().get(0).getIncrCount(), 3); + assertEquals(updateStockReqDTO.getItems().get(1).getId(), 2L); + assertEquals(updateStockReqDTO.getItems().get(1).getIncrCount(), 4); + return true; })); verify(couponApi).useCoupon(argThat(reqDTO -> { assertEquals(reqDTO.getId(), reqVO.getCouponId()); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql index fda7251dcb..7b0b99b562 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql @@ -32,7 +32,7 @@ CREATE TABLE IF NOT EXISTS "trade_order" ( "receiver_area_id" int NOT NULL, "receiver_post_code" int, "receiver_detail_address" varchar NOT NULL, - "refund_status" int NOT NULL, + "after_sale_status" int NOT NULL, "refund_price" int NOT NULL, "coupon_id" bigint NOT NULL, "coupon_price" int NOT NULL, @@ -61,8 +61,7 @@ CREATE TABLE IF NOT EXISTS "trade_order_item" ( "pay_price" int NOT NULL, "order_part_price" int NOT NULL, "order_divide_price" int NOT NULL, - "refund_status" int NOT NULL, - "refund_total" int NOT NULL, + "after_sale_status" int NOT NULL, "creator" varchar DEFAULT '', "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, "updater" varchar DEFAULT '', From af71a19241c37271ec5241cd6b9908ff8ea8cb79 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 19 Nov 2022 12:25:53 +0800 Subject: [PATCH 010/110] =?UTF-8?q?trade=EF=BC=9A=E3=80=90=E5=95=86?= =?UTF-8?q?=E5=93=81=E3=80=91sku=20=E8=A1=A8=E5=A2=9E=E5=8A=A0=20spu=5Fnam?= =?UTF-8?q?e=20=E5=AD=97=E6=AE=B5=EF=BC=8C=E5=86=97=E4=BD=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/product/api/sku/dto/ProductSkuRespDTO.java | 2 +- .../module/product/convert/sku/ProductSkuConvert.java | 8 +++++++- .../product/dal/dataobject/sku/ProductSkuDO.java | 11 ++++++----- .../module/product/service/sku/ProductSkuService.java | 6 ++++-- .../product/service/sku/ProductSkuServiceImpl.java | 8 ++++---- .../product/service/spu/ProductSpuServiceImpl.java | 4 ++-- yudao-ui-admin/src/views/mall/product/spu/save.vue | 9 --------- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java index 4b324149b8..909a54efa3 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java @@ -19,7 +19,7 @@ public class ProductSkuRespDTO { */ private Long id; /** - * 商品 SKU 名字 + * SPU 名字 */ private String name; /** diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java index b29d612bec..ce46bb4fd5 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java @@ -32,7 +32,13 @@ public interface ProductSkuConvert { List convertList(List list); - List convertSkuDOList(List list); + List convertList06(List list); + + default List convertList06(List list, String spuName) { + List result = convertList06(list); + result.forEach(item -> item.setSpuName(spuName)); + return result; + } ProductSkuRespDTO convert02(ProductSkuDO bean); diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java index 019edf2bff..b801863ff1 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java @@ -35,17 +35,18 @@ public class ProductSkuDO extends BaseDO { */ @TableId private Long id; - /** - * 商品 SKU 名字 - */ - @Deprecated // TODO 芋艿:参考有赞,不需要 sku 的标题 - private String name; /** * SPU 编号 *

* 关联 {@link ProductSpuDO#getId()} */ private Long spuId; + /** + * SPU 名字 + * + * 冗余 {@link ProductSkuDO#getSpuName()} + */ + private String spuName; /** * 规格值数组,JSON 格式 */ diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java index 1036d8348d..3f9dde1d9e 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java @@ -55,17 +55,19 @@ public interface ProductSkuService { * 批量创建 SKU * * @param spuId 商品 SPU 编号 + * @para spuName 商品 SPU 名称 * @param list SKU 对象集合 */ - void createSkus(Long spuId, List list); + void createSkus(Long spuId, String spuName, List list); /** * 根据 SPU 编号,批量更新它的 SKU 信息 * * @param spuId SPU 编码 + * @para spuName 商品 SPU 名称 * @param skus SKU 的集合 */ - void updateSkus(Long spuId, List skus); + void updateSkus(Long spuId, String spuName, List skus); /** * 更新 SKU 库存(增量) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java index 2791ae5d3a..2cc80b7ab7 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java @@ -119,9 +119,9 @@ public class ProductSkuServiceImpl implements ProductSkuService { } @Override - public void createSkus(Long spuId, List skuCreateReqList) { + public void createSkus(Long spuId, String spuName, List skuCreateReqList) { // 批量插入 SKU - List skuDOList = ProductSkuConvert.INSTANCE.convertSkuDOList(skuCreateReqList); + List skuDOList = ProductSkuConvert.INSTANCE.convertList06(skuCreateReqList, spuName); skuDOList.forEach(v -> v.setSpuId(spuId)); productSkuMapper.insertBatch(skuDOList); } @@ -148,7 +148,7 @@ public class ProductSkuServiceImpl implements ProductSkuService { @Override @Transactional - public void updateSkus(Long spuId, List skus) { + public void updateSkus(Long spuId, String spuName, List skus) { // 查询 SPU 下已经存在的 SKU 的集合 List existsSkus = productSkuMapper.selectListBySpuId(spuId); // 构建规格与 SKU 的映射关系; @@ -168,7 +168,7 @@ public class ProductSkuServiceImpl implements ProductSkuService { List updateSkus = new ArrayList<>(); List deleteSkus = new ArrayList<>(); - List allUpdateSkus = ProductSkuConvert.INSTANCE.convertSkuDOList(skus); + List allUpdateSkus = ProductSkuConvert.INSTANCE.convertList06(skus, spuName); allUpdateSkus.forEach(p -> { String propertiesKey = p.getProperties() == null? "null": p.getProperties().stream().map(m -> String.valueOf(m.getValueId())).collect(Collectors.joining()); // 1、找得到的,进行更新 diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java index 4880d4948e..d9f8ec8dca 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java @@ -79,7 +79,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { spu.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum)); productSpuMapper.insert(spu); // 插入 SKU - productSkuService.createSkus(spu.getId(), skuCreateReqList); + productSkuService.createSkus(spu.getId(), spu.getName(), skuCreateReqList); // 返回 return spu.getId(); } @@ -105,7 +105,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { updateObj.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum)); productSpuMapper.updateById(updateObj); // 批量更新 SKU - productSkuService.updateSkus(updateObj.getId(), updateReqVO.getSkus()); + productSkuService.updateSkus(updateObj.getId(), updateObj.getName(), updateReqVO.getSkus()); } @Override diff --git a/yudao-ui-admin/src/views/mall/product/spu/save.vue b/yudao-ui-admin/src/views/mall/product/spu/save.vue index ca344bf8c3..5eee696d31 100644 --- a/yudao-ui-admin/src/views/mall/product/spu/save.vue +++ b/yudao-ui-admin/src/views/mall/product/spu/save.vue @@ -80,15 +80,6 @@ - ``` -请通过[快速上手](https://www.uviewui.com/components/quickstart.html)了解更详细的内容 - -## 链接 - -- [官方文档](https://www.uviewui.com/) -- [更新日志](https://www.www.uviewui.com/components/changelog.html) -- [升级指南](https://www.uviewui.com/components/changelog.html) -- [关于我们](https://www.uviewui.com/cooperation/about.html) - -## 预览 - -您可以通过**微信**扫码,查看最佳的演示效果。 -
-
- - -## 捐赠uView的研发 - -uView文档和源码全部开源免费,如果您认为uView帮到了您的开发工作,您可以捐赠uView的研发工作,捐赠无门槛,哪怕是一杯可乐也好(相信这比打赏主播更有意义)。 - - - ## 版权信息 uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。 + diff --git a/yudao-ui-app/uni_modules/uview-ui/changelog.md b/yudao-ui-app/uni_modules/uview-ui/changelog.md index 7a54275a2f..ca502516f0 100644 --- a/yudao-ui-app/uni_modules/uview-ui/changelog.md +++ b/yudao-ui-app/uni_modules/uview-ui/changelog.md @@ -1,3 +1,42 @@ +## 2.0.34(2022-09-25) +# uView2.0重磅发布,利剑出鞘,一统江湖 + +1. `u-input`、`u-textarea`增加`ignoreCompositionEvent`属性 +2. 修复`route`方法调用可能报错的问题 +3. 修复`u-no-network`组件`z-index`无效的问题 +4. 修复`textarea`组件在h5上confirmType=""报错的问题 +5. `u-rate`适配`nvue` +6. 优化验证手机号码的正则表达式(根据工信部发布的《电信网编号计划(2017年版)》进行修改。) +7. `form-item`添加`labelPosition`属性 +8. `u-calendar`修复`maxDate`设置为当前日期,并且当前时间大于08:00时无法显示日期列表的问题 (#724) +9. `u-radio`增加一个默认插槽用于自定义修改label内容 (#680) +10. 修复`timeFormat`函数在safari重的兼容性问题 (#664) +## 2.0.33(2022-06-17) +# uView2.0重磅发布,利剑出鞘,一统江湖 + +1. 修复`loadmore`组件`lineColor`类型错误问题 +2. 修复`u-parse`组件`imgtap`、`linktap`不生效问题 +## 2.0.32(2022-06-16) +# uView2.0重磅发布,利剑出鞘,一统江湖 +1. `u-loadmore`新增自定义颜色、虚/实线 +2. 修复`u-swiper-action`组件部分平台不能上下滑动的问题 +3. 修复`u-list`回弹问题 +4. 修复`notice-bar`组件动画在低端安卓机可能会抖动的问题 +5. `u-loading-page`添加控制图标大小的属性`iconSize` +6. 修复`u-tooltip`组件`color`参数不生效的问题 +7. 修复`u--input`组件使用`blur`事件输出为`undefined`的bug +8. `u-code-input`组件新增键盘弹起时,是否自动上推页面参数`adjustPosition` +9. 修复`image`组件`load`事件无回调对象问题 +10. 修复`button`组件`loadingSize`设置无效问题 +10. 其他修复 +## 2.0.31(2022-04-19) +# uView2.0重磅发布,利剑出鞘,一统江湖 + +1. 修复`upload`在`vue`页面上传成功后没有成功标志的问题 +2. 解决演示项目中微信小程序模拟上传图片一直出于上传中问题 +3. 修复`u-code-input`组件在`nvue`页面编译到`app`平台上光标异常问题(`app`去除此功能) +4. 修复`actionSheet`组件标题关闭按钮点击事件名称错误的问题 +5. 其他修复 ## 2.0.30(2022-04-04) # uView2.0重磅发布,利剑出鞘,一统江湖 diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u--input/u--input.vue b/yudao-ui-app/uni_modules/uview-ui/components/u--input/u--input.vue index 2887e4cf96..1e58b01072 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u--input/u--input.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u--input/u--input.vue @@ -35,8 +35,9 @@ :shape="shape" :customStyle="customStyle" :formatter="formatter" + :ignoreCompositionEvent="ignoreCompositionEvent" @focus="$emit('focus')" - @blur="$emit('blur')" + @blur="e => $emit('blur', e)" @keyboardheightchange="$emit('keyboardheightchange')" @change="e => $emit('change', e)" @input="e => $emit('input', e)" diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u--textarea/u--textarea.vue b/yudao-ui-app/uni_modules/uview-ui/components/u--textarea/u--textarea.vue index 9dbcfbb32d..f4df0b9a49 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u--textarea/u--textarea.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u--textarea/u--textarea.vue @@ -21,6 +21,7 @@ :border="border" :customStyle="customStyle" :formatter="formatter" + :ignoreCompositionEvent="ignoreCompositionEvent" @focus="e => $emit('focus')" @blur="e => $emit('blur')" @linechange="e => $emit('linechange', e)" diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-action-sheet/u-action-sheet.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-action-sheet/u-action-sheet.vue index 98a73d876e..26d5d8d9f7 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-action-sheet/u-action-sheet.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-action-sheet/u-action-sheet.vue @@ -15,7 +15,7 @@ {{title}} - + + + @@ -70,7 +75,8 @@ mixins: [uni.$u.mpMixin, uni.$u.mixin, props], data() { return { - inputValue: '' + inputValue: '', + isFocus: this.focus } }, watch: { @@ -203,6 +209,7 @@ width: 40px; background-color: $u-content-color; } + /* #ifndef APP-PLUS */ &__cursor { position: absolute; top: 50%; @@ -212,6 +219,8 @@ height: $u-code-input-cursor-height; animation: $u-code-input-cursor-animation-duration u-cursor-flicker infinite; } + /* #endif */ + } &__input { @@ -226,6 +235,7 @@ } } + /* #ifndef APP-PLUS */ @keyframes u-cursor-flicker { 0% { opacity: 0; @@ -237,4 +247,6 @@ opacity: 0; } } + /* #endif */ + diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-code/u-code.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-code/u-code.vue index cdf9f825ac..f79a09ac98 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-code/u-code.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-code/u-code.vue @@ -16,11 +16,11 @@ * @property {String} endText 倒计结束的提示语,见官网说明(默认 '重新获取' ) * @property {Boolean} keepRunning 是否在H5刷新或各端返回再进入时继续倒计时( 默认false ) * @property {String} uniqueKey 为了区分多个页面,或者一个页面多个倒计时组件本地存储的继续倒计时变了 - * + * * @event {Function} change 倒计时期间,每秒触发一次 * @event {Function} start 开始倒计时触发 * @event {Function} end 结束倒计时触发 - * @example + * @example */ export default { name: "u-code", @@ -74,7 +74,6 @@ this.canGetCode = false // 这里放这句,是为了一开始时就提示,否则要等setInterval的1秒后才会有提示 this.changeEvent(this.changeText.replace(/x|X/, this.secNum)) - this.setTimeToStorage() this.timer = setInterval(() => { if (--this.secNum) { // 用当前倒计时的秒数替换提示字符串中的"x"字母 @@ -88,7 +87,8 @@ this.canGetCode = true } }, 1000) - }, + this.setTimeToStorage() + }, // 重置,可以让用户再次获取验证码 reset() { this.canGetCode = true diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-dropdown-item/u-dropdown-item.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-dropdown-item/u-dropdown-item.vue index 07de583d66..f830291a25 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-dropdown-item/u-dropdown-item.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-dropdown-item/u-dropdown-item.vue @@ -1,146 +1,127 @@ - diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-dropdown/u-dropdown.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-dropdown/u-dropdown.vue index 9c50bfe713..f830291a25 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-dropdown/u-dropdown.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-dropdown/u-dropdown.vue @@ -1,127 +1,127 @@ diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-form-item/props.js b/yudao-ui-app/uni_modules/uview-ui/components/u-form-item/props.js index 53a0191550..7b1665561a 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-form-item/props.js +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-form-item/props.js @@ -15,6 +15,11 @@ export default { type: [String, Boolean], default: uni.$u.props.formItem.borderBottom }, + // label的位置,left-左边,top-上边 + labelPosition: { + type: String, + default: uni.$u.props.formItem.labelPosition + }, // label的宽度,单位px labelWidth: { type: [String, Number], diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-form-item/u-form-item.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-form-item/u-form-item.vue index 701d7cc0be..6aa8d6909c 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-form-item/u-form-item.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-form-item/u-form-item.vue @@ -4,7 +4,7 @@ class="u-form-item__body" @tap="clickHandler" :style="[$u.addStyle(customStyle), { - flexDirection: parentData.labelPosition === 'left' ? 'row' : 'column' + flexDirection: (labelPosition || parentData.labelPosition) === 'left' ? 'row' : 'column' }]" > diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-image/u-image.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-image/u-image.vue index d7105c2fcb..473e35b440 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-image/u-image.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-image/u-image.vue @@ -161,10 +161,10 @@ this.$emit('error', err) }, // 图片加载完成,标记loading结束 - onLoadHandler() { + onLoadHandler(event) { this.loading = false this.isError = false - this.$emit('load') + this.$emit('load', event) this.removeBgColor() // 如果不需要动画效果,就不执行下方代码,同时移除加载时的背景颜色 // 否则无需fade效果时,png图片依然能看到下方的背景色 diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-input/props.js b/yudao-ui-app/uni_modules/uview-ui/components/u-input/props.js index 88917c353d..2c50870109 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-input/props.js +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-input/props.js @@ -177,6 +177,11 @@ export default { formatter: { type: [Function, null], default: uni.$u.props.input.formatter + }, + // 是否忽略组件内对文本合成系统事件的处理 + ignoreCompositionEvent: { + type: Boolean, + default: true } } } diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-input/u-input.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-input/u-input.vue index c755390aab..30073eb259 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-input/u-input.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-input/u-input.vue @@ -38,6 +38,7 @@ :selection-end="selectionEnd" :selection-start="selectionStart" :password="password || type === 'password' || undefined" + :ignoreCompositionEvent="ignoreCompositionEvent" @input="onInput" @blur="onBlur" @focus="onFocus" @@ -114,7 +115,7 @@ import props from "./props.js"; * @property {Boolean} readonly 是否只读,与disabled不同之处在于disabled会置灰组件,而readonly则不会 ( 默认 false ) * @property {String} shape 输入框形状,circle-圆形,square-方形 ( 默认 'square' ) * @property {Object} customStyle 定义需要用到的外部样式 - * + * @property {Boolean} ignoreCompositionEvent 是否忽略组件内对文本合成系统事件的处理。 * @example */ export default { diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-line/props.js b/yudao-ui-app/uni_modules/uview-ui/components/u-line/props.js index 866bade952..2308cc364c 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-line/props.js +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-line/props.js @@ -24,7 +24,7 @@ export default { type: [String, Number], default: uni.$u.props.line.margin }, - // 是否虚线,true-实线,false-虚线 + // 是否虚线,true-虚线,false-实线 dashed: { type: Boolean, default: uni.$u.props.line.dashed diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-list/u-list.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-list/u-list.vue index 513decc783..4447cab65f 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-list/u-list.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-list/u-list.vue @@ -29,9 +29,7 @@ @scrolltolower="scrolltolower" @scrolltoupper="scrolltoupper" > - + diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-loading-page/props.js b/yudao-ui-app/uni_modules/uview-ui/components/u-loading-page/props.js index 438ab64373..e239b61245 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-loading-page/props.js +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-loading-page/props.js @@ -35,6 +35,11 @@ export default { type: [String, Number], default: uni.$u.props.loadingPage.fontSize }, + // 图标大小 + iconSize: { + type: [String, Number], + default: uni.$u.props.loadingPage.fontSize + }, // 加载中图标的颜色,只能rgb或者十六进制颜色值 loadingColor: { type: String, diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-loading-page/u-loading-page.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-loading-page/u-loading-page.vue index c6b51b973a..03a78ad8bd 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-loading-page/u-loading-page.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-loading-page/u-loading-page.vue @@ -19,11 +19,15 @@ :src="image" class="u-loading-page__warpper__loading-icon__img" mode="widthFit" + :style="{ + width: $u.addUnit(iconSize), + height: $u.addUnit(iconSize) + }" > @@ -55,6 +59,7 @@ import props from "./props.js"; * @property {String} bgColor 背景色 (默认 '#ffffff' ) * @property {String} color 文字颜色 (默认 '#C8C8C8' ) * @property {String | Number} fontSize 文字大小 (默认 19 ) + * @property {String | Number} iconSize 图标大小 (默认 28 ) * @property {String} loadingColor 加载中图标的颜色,只能rgb或者十六进制颜色值 (默认 '#C8C8C8' ) * @property {Object} customStyle 自定义样式 * @example diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-loadmore/props.js b/yudao-ui-app/uni_modules/uview-ui/components/u-loadmore/props.js index 125ad3eb78..1e67d89199 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-loadmore/props.js +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-loadmore/props.js @@ -19,13 +19,17 @@ export default { fontSize: { type: [String, Number], default: uni.$u.props.loadmore.fontSize + }, + // 图标大小 + iconSize: { + type: [String, Number], + default: uni.$u.props.loadmore.iconSize }, // 字体颜色 color: { type: String, default: uni.$u.props.loadmore.color }, - // 加载中状态的图标,spinner-花朵状图标,circle-圆圈状,semicircle-半圆 loadingIcon: { type: String, @@ -75,6 +79,16 @@ export default { line: { type: Boolean, default: uni.$u.props.loadmore.line + }, + // 线条颜色 + lineColor: { + type: String, + default: uni.$u.props.loadmore.lineColor + }, + // 是否虚线,true-虚线,false-实线 + dashed: { + type: Boolean, + default: uni.$u.props.loadmore.dashed } } } diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-loadmore/u-loadmore.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-loadmore/u-loadmore.vue index 24fb4b6a08..73c79feff6 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-loadmore/u-loadmore.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-loadmore/u-loadmore.vue @@ -13,8 +13,9 @@ > @@ -28,7 +29,7 @@ > @@ -42,8 +43,9 @@ @@ -60,6 +62,7 @@ * @property {String} bgColor 组件背景颜色,在页面是非白色时会用到(默认 'transparent' ) * @property {Boolean} icon 加载中时是否显示图标(默认 true ) * @property {String | Number} fontSize 字体大小(默认 14 ) + * @property {String | Number} iconSize 图标大小(默认 17 ) * @property {String} color 字体颜色(默认 '#606266' ) * @property {String} loadingIcon 加载图标(默认 'circle' ) * @property {String} loadmoreText 加载前的提示语(默认 '加载更多' ) @@ -67,10 +70,12 @@ * @property {String} nomoreText 没有更多的提示语(默认 '没有更多了' ) * @property {Boolean} isDot 到上一个相邻元素的距离 (默认 false ) * @property {String} iconColor 加载中图标的颜色 (默认 '#b7b7b7' ) + * @property {String} lineColor 线条颜色(默认 #E6E8EB ) * @property {String | Number} marginTop 上边距 (默认 10 ) * @property {String | Number} marginBottom 下边距 (默认 10 ) * @property {String | Number} height 高度,单位px (默认 'auto' ) * @property {Boolean} line 是否显示左边分割线 (默认 false ) + * @property {Boolean} dashed // 是否虚线,true-虚线,false-实线 (默认 false ) * @event {Function} loadmore status为loadmore时,点击组件会发出此事件 * @example */ diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-no-network/u-no-network.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-no-network/u-no-network.vue index 53db905880..9710729eb2 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-no-network/u-no-network.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-no-network/u-no-network.vue @@ -1,6 +1,7 @@ diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-rate/u-rate.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-rate/u-rate.vue index 5992038a95..1aa5dd0fe1 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-rate/u-rate.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-rate/u-rate.vue @@ -35,7 +35,8 @@ : inactiveColor " :custom-style="{ - padding: `0 ${$u.addUnit(gutter / 2)}`, + 'padding-left': $u.addUnit(gutter / 2), + 'padding-right': $u.addUnit(gutter / 2) }" :size="size" > @@ -63,7 +64,8 @@ : inactiveColor " :custom-style="{ - padding: `0 ${$u.addUnit(gutter / 2)}` + 'padding-left': $u.addUnit(gutter / 2), + 'padding-right': $u.addUnit(gutter / 2) }" :size="size" > diff --git a/yudao-ui-app/uni_modules/uview-ui/components/u-row-notice/u-row-notice.vue b/yudao-ui-app/uni_modules/uview-ui/components/u-row-notice/u-row-notice.vue index e5a2f4afc1..20f43c3766 100644 --- a/yudao-ui-app/uni_modules/uview-ui/components/u-row-notice/u-row-notice.vue +++ b/yudao-ui-app/uni_modules/uview-ui/components/u-row-notice/u-row-notice.vue @@ -19,11 +19,17 @@ class="u-notice__content" ref="u-notice__content" > - {{text}} + :style="[animationStyle]" + > + {{item}} + - - + + diff --git a/yudao-ui-app/components/yd-product-box/yd-product-box.vue b/yudao-ui-app/components/yd-product-box/yd-product-box.vue new file mode 100644 index 0000000000..ad35b968fe --- /dev/null +++ b/yudao-ui-app/components/yd-product-box/yd-product-box.vue @@ -0,0 +1,173 @@ + + + + diff --git a/yudao-ui-app/components/yd-product-more/yd-product-more.vue b/yudao-ui-app/components/yd-product-more/yd-product-more.vue new file mode 100644 index 0000000000..c5f6377214 --- /dev/null +++ b/yudao-ui-app/components/yd-product-more/yd-product-more.vue @@ -0,0 +1,114 @@ + + + + diff --git a/yudao-ui-app/components/custom-text-price/custom-text-price.vue b/yudao-ui-app/components/yd-text-price/yd-text-price.vue similarity index 97% rename from yudao-ui-app/components/custom-text-price/custom-text-price.vue rename to yudao-ui-app/components/yd-text-price/yd-text-price.vue index dd5da46207..fab0339725 100644 --- a/yudao-ui-app/components/custom-text-price/custom-text-price.vue +++ b/yudao-ui-app/components/yd-text-price/yd-text-price.vue @@ -11,7 +11,7 @@ * 此组件简单的显示特定样式的(人名币)价格数字 */ export default { - name: 'custom-text-price', + name: 'yd-text-price', components: {}, props: { price: { diff --git a/yudao-ui-app/pages/index/index.vue b/yudao-ui-app/pages/index/index.vue index 8abb50891c..137de3b221 100644 --- a/yudao-ui-app/pages/index/index.vue +++ b/yudao-ui-app/pages/index/index.vue @@ -8,17 +8,13 @@ - - - - - + - + + {{ item.title }} @@ -30,81 +26,11 @@ - - - - - 每日上新 - 查看更多 - - - - - - - - - - - - - - - - - + + + - - - - 商品热卖 - 更多 > - - - - - - - - - - - - - - - - - - - - - - - 更多宝贝 - - - - - - - - - - - - - - - - - - - - - - - + @@ -115,9 +41,23 @@ export default { components: {}, data() { return { - current: 0, - currentNum: 0, - bannerList: ['https://cdn.uviewui.com/uview/swiper/swiper3.png', 'https://cdn.uviewui.com/uview/swiper/swiper2.png', 'https://cdn.uviewui.com/uview/swiper/swiper1.png'], + bannerList: [ + { + id: 1, + title: '山不在高,有仙则名', + url: 'https://cdn.uviewui.com/uview/swiper/swiper1.png' + }, + { + id: 2, + title: '水不在深,有龙则灵', + url: 'https://cdn.uviewui.com/uview/swiper/swiper2.png' + }, + { + id: 3, + title: '斯是陋室,惟吾德馨', + url: 'https://cdn.uviewui.com/uview/swiper/swiper3.png' + } + ], menuList: [ { icon: 'gift', title: '热门推荐' }, { icon: 'star', title: '收藏转发' }, @@ -162,15 +102,12 @@ export default { price: '53.00' } ], - status: 'nomore', - loadingText: '努力加载中...', - loadmoreText: '轻轻上拉', - nomoreText: '实在没有了...' + moreStatus: 'nomore' } }, onLoad() { - this.loadBannerData(); - this.loadNoticeData(); + this.loadBannerData() + this.loadNoticeData() }, methods: { loadBannerData() { @@ -185,24 +122,9 @@ export default { }, handleSearchClick(e) { uni.$u.route('/pages/search/search') - }, - handleSwiperClick(index) { - console.log('点击了图片索引值:', index) - }, - handleProdItemClick(productId) { - uni.$u.route('/pages/product/product', { - productId: productId - }) } }, computed: { - swiperList() { - return this.bannerList.map(item => { - if (item) { - return item - } - }) - }, noticeTextList() { return this.noticeList.map(item => { if (item.title) { @@ -220,131 +142,8 @@ export default { padding: 20rpx; } -.indicator { - @include flex(row); - justify-content: center; - - &__dot { - height: 15rpx; - width: 15rpx; - border-radius: 100rpx; - background-color: rgba(255, 255, 255, 0.35); - margin: 0 10rpx; - transition: background-color 0.3s; - - &--active { - background-color: $custom-bg-color; - } - } -} - .grid-title { line-height: 50rpx; font-size: 26rpx; } - -.prod-block { - margin-top: -160px; - .bloc-header { - @include flex-space-between; - padding: 10rpx 20rpx; - - .bloc-title { - color: $custom-bg-color; - font-size: 34rpx; - } - .see-more { - color: $custom-bg-color; - background: $u-primary; - padding: 0 30rpx; - height: 50rpx; - line-height: 50rpx; - border-radius: 50rpx; - font-size: 24rpx; - } - } - - &.half, - &.list { - margin-top: 0; - .bloc-header { - margin-top: 50rpx; - margin-bottom: 20rpx; - .bloc-title { - color: #333333; - } - .more { - font-size: 24rpx; - } - } - } - - .prod-grid { - width: 730rpx; - margin: 0 auto; - @include flex; - flex-wrap: wrap; - justify-content: left; - - &.half { - .prod-item { - width: 345rpx; - margin: 10rpx; - .prod-image { - width: 345rpx; - height: 345rpx; - } - } - } - - .prod-item { - width: 223rpx; - margin: 10rpx; - background: #ffffff; - border-radius: 10rpx; - box-shadow: 0rpx 6rpx 8rpx rgba(58,134,185,0.2); - .prod-image { - width: 223rpx; - height: 223rpx; - border-radius: 10rpx 10rpx 0 0; - } - .item-info { - padding: 15rpx; - .info-text { - height: 70rpx; - padding-bottom: 10rpx; - } - .price-and-cart { - @include flex-space-between; - } - } - } - } -} - -.prod-list { - .prod-item { - background: #ffffff; - @include flex-space-between; - border-bottom: $custom-border-style; - padding: 20rpx; - .prod-image { - width: 200rpx; - height: 200rpx; - border-radius: 10rpx; - } - - .item-info { - flex: 1; - padding: 20rpx 20rpx 0; - .info-text { - height: 100rpx; - padding-bottom: 10rpx; - } - .price-and-cart { - @include flex-space-between; - } - } - } -} diff --git a/yudao-ui-app/pages/profile/profile.vue b/yudao-ui-app/pages/profile/profile.vue index 9b66ea80ee..28dd56bc26 100644 --- a/yudao-ui-app/pages/profile/profile.vue +++ b/yudao-ui-app/pages/profile/profile.vue @@ -10,43 +10,22 @@ 昵称: - - {{ userInfo.nickname }} - - - - - - - - + + 手机: {{ userInfo.mobile }} - + + + + + @@ -62,8 +41,13 @@ export default { mobile: '' }, avatarFiles: [], - nameEditOn: false, - tempName: '' + tempName: '', + borderStyle: 'none' + } + }, + computed: { + nameUpdateVisible: function () { + return this.userInfo.nickname !== this.tempName } }, onLoad() { @@ -73,6 +57,7 @@ export default { loadUserInfoData() { getUserInfo().then(res => { this.userInfo = res.data + this.tempName = this.userInfo.nickname }) }, handleAvatarClick() { @@ -86,11 +71,22 @@ export default { } }) }, + handleNameChange(val) { + let str = uni.$u.trim(val, 'all') + this.$nextTick(() => { + this.userInfo.nickname = str + }) + }, handleSaveBtnClick() { - updateNickname({ nickname: this.tempName }).then(res => { - this.nameEditOn = false; - this.userInfo.nickname = this.tempName + updateNickname({ nickname: this.userInfo.nickname }).then(res => { + this.tempName = this.userInfo.nickname this.$store.commit('SET_USER_INFO', this.userInfo) + uni.$u.toast('已保存') + setTimeout(() => { + uni.switchTab({ + url: '/pages/user/user' + }) + }, 300) }) } } @@ -107,7 +103,7 @@ export default { font-size: 30rpx; } .info { - @include flex-right; + @include flex-left; .value { font-size: 30rpx; } @@ -126,4 +122,8 @@ export default { } } } + +.btn-group { + padding: 0 30rpx; +} From 00e66216c591c7c55e82758ef3ebdc0b60679eac Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 20 Nov 2022 01:05:03 +0800 Subject: [PATCH 016/110] =?UTF-8?q?trade=EF=BC=9A=E3=80=90=E4=BA=A4?= =?UTF-8?q?=E6=98=93=E5=94=AE=E5=90=8E=E3=80=91=E6=9F=A5=E8=AF=A2=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E5=88=97=E8=A1=A8=E7=9A=84=E5=89=8D=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aftersale/TradeAfterSaleStatusEnum.java | 16 +- .../aftersale/TradeAfterSaleTypeEnum.java | 10 +- .../aftersale/TradeAfterSaleWayEnum.java | 37 ++++ .../enums/order/TradeOrderStatusEnum.java | 10 + .../aftersale/vo/TradeAfterSaleBaseVO.java | 8 +- .../aftersale/vo/TradeAfterSalePageReqVO.java | 9 +- .../vo/AppTradeAfterSaleCreateReqVO.java | 10 +- .../aftersale/TradeAfterSaleDO.java | 7 + .../mysql/aftersale/TradeAfterSaleMapper.java | 1 + .../aftersale/TradeAfterSaleServiceImpl.java | 18 +- .../aftersale/TradeAfterSaleServiceTest.java | 18 +- .../src/test/resources/sql/create_tables.sql | 1 + .../src/api/mall/trade/afterSale.js | 18 ++ yudao-ui-admin/src/router/index.js | 6 - yudao-ui-admin/src/utils/constants.js | 31 +++ yudao-ui-admin/src/utils/dateUtils.js | 8 + yudao-ui-admin/src/utils/dict.js | 5 + .../index.vue => afterSale/bak.vue} | 142 +------------ .../src/views/mall/trade/afterSale/index.vue | 195 ++++++++++++++++++ 19 files changed, 370 insertions(+), 180 deletions(-) create mode 100644 yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleWayEnum.java create mode 100644 yudao-ui-admin/src/api/mall/trade/afterSale.js rename yudao-ui-admin/src/views/mall/trade/{orderrefund/index.vue => afterSale/bak.vue} (53%) create mode 100644 yudao-ui-admin/src/views/mall/trade/afterSale/index.vue diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java index bae0b9f1ca..c82b94f027 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java @@ -17,15 +17,15 @@ import java.util.Arrays; @Getter public enum TradeAfterSaleStatusEnum implements IntArrayValuable { - APPLY(10,"申请中"), - SELLER_AGREE(20, "卖家通过"), // 卖家通过售后 - BUYER_DELIVERY(30,"待卖家收货"), // 买家已退货,等待卖家收货 - WAIT_REFUND(40, "等待平台退款"), // 卖家已收货,等待平台退款 - COMPLETE(50, "完成"), // 完成退款 + APPLY(10,"申请中"), // 【申请售后】 + SELLER_AGREE(20, "卖家通过"), // 卖家通过售后;【商品待退货】 + BUYER_DELIVERY(30,"待卖家收货"), // 买家已退货,等待卖家收货;【商家待收货】 + WAIT_REFUND(40, "等待平台退款"), // 卖家已收货,等待平台退款;等待退款【等待退款】 + COMPLETE(50, "完成"), // 完成退款【退款成功】 - BUYER_CANCEL(61, "买家取消售后"), - SELLER_DISAGREE(62,"卖家拒绝"), // 卖家拒绝售后 - SELLER_REFUSE(63,"卖家拒绝收货"), // 卖家拒绝收货,终止售后 + BUYER_CANCEL(61, "买家取消售后"), // 【买家取消】 + SELLER_DISAGREE(62,"卖家拒绝"), // 卖家拒绝售后;商家拒绝【商家拒绝】 + SELLER_REFUSE(63,"卖家拒绝收货"), // 卖家拒绝收货,终止售后;【商家拒收货】 ; public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeAfterSaleStatusEnum::getStatus).toArray(); diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java index 66e1902f23..d5323aac88 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java @@ -9,23 +9,23 @@ import java.util.Arrays; /** * 交易售后 - 类型 * - * @author Sin + * @author 芋道源码 */ @RequiredArgsConstructor @Getter public enum TradeAfterSaleTypeEnum implements IntArrayValuable { - REFUND(10, "退款"), - RETURN_AND_REFUND(20, "退货退款"); + IN_SALE(10, "售中退款"), // 交易完成前买家申请退款 + AFTER_SALE(20, "售后退款"); // 交易完成后买家申请退款 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeAfterSaleTypeEnum::getType).toArray(); /** - * 状态值 + * 类型 */ private final Integer type; /** - * 状态名 + * 类型名 */ private final String name; diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleWayEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleWayEnum.java new file mode 100644 index 0000000000..1bbb35327a --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleWayEnum.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.trade.enums.aftersale; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 交易售后 - 方式 + * + * @author Sin + */ +@RequiredArgsConstructor +@Getter +public enum TradeAfterSaleWayEnum implements IntArrayValuable { + + REFUND(10, "仅退款"), + RETURN_AND_REFUND(20, "退货退款"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeAfterSaleWayEnum::getWay).toArray(); + + /** + * 方式 + */ + private final Integer way; + /** + * 方式名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java index ad0768493e..7bfa61f74c 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java @@ -52,6 +52,16 @@ public enum TradeOrderStatusEnum implements IntArrayValuable { return ObjectUtil.equals(status, CANCELED.getStatus()); } + /** + * 判断指定状态,是否正处于【已完成】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean isCompleted(Integer status) { + return ObjectUtil.equals(status, COMPLETED.getStatus()); + } + /** * 判断指定状态,是否有过【已付款】状态 * diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleBaseVO.java index cd86a0c6ac..f4b144e71c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleBaseVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleBaseVO.java @@ -22,14 +22,18 @@ public class TradeAfterSaleBaseVO { @NotNull(message = "售后流水号不能为空") private String no; - @ApiModelProperty(value = "售后状态", required = true, example = "2", notes = "参见 TradeAfterSaleStatusEnum 枚举") + @ApiModelProperty(value = "售后状态", required = true, example = "10", notes = "参见 TradeAfterSaleStatusEnum 枚举") @NotNull(message = "售后状态不能为空") private Integer status; - @ApiModelProperty(value = "售后类型", required = true, example = "2", notes = "参见 TradeAfterSaleTypeEnum 枚举") + @ApiModelProperty(value = "售后类型", required = true, example = "20", notes = "参见 TradeAfterSaleTypeEnum 枚举") @NotNull(message = "售后类型不能为空") private Integer type; + @ApiModelProperty(value = "售后方式", required = true, example = "10", notes = "参见 TradeAfterSaleWayEnum 枚举") + @NotNull(message = "售后方式不能为空") + private Integer way; + @ApiModelProperty(value = "用户编号", required = true, example = "30337") @NotNull(message = "用户编号不能为空") private Long userId; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSalePageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSalePageReqVO.java index d21b254b04..628b8bc561 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSalePageReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSalePageReqVO.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -24,14 +25,18 @@ public class TradeAfterSalePageReqVO extends PageParam { @ApiModelProperty(value = "售后流水号", example = "202211190847450020500077", notes = "模糊匹配") private String no; - @ApiModelProperty(value = "售后状态", example = "2", notes = "参见 TradeAfterSaleStatusEnum 枚举") + @ApiModelProperty(value = "售后状态", example = "10", notes = "参见 TradeAfterSaleStatusEnum 枚举") @InEnum(value = TradeAfterSaleStatusEnum.class, message = "售后状态必须是 {value}") private Integer status; - @ApiModelProperty(value = "售后类型", example = "2", notes = "参见 TradeAfterSaleTypeEnum 枚举") + @ApiModelProperty(value = "售后类型", example = "20", notes = "参见 TradeAfterSaleTypeEnum 枚举") @InEnum(value = TradeAfterSaleTypeEnum.class, message = "售后类型必须是 {value}") private Integer type; + @ApiModelProperty(value = "售后方式", example = "10", notes = "参见 TradeAfterSaleWayEnum 枚举") + @InEnum(value = TradeAfterSaleWayEnum.class, message = "售后方式必须是 {value}") + private Integer way; + @ApiModelProperty(value = "订单编号", example = "18078", notes = "模糊匹配") private String orderNo; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java index 7607a0280e..b5ea83904b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -18,10 +18,10 @@ public class AppTradeAfterSaleCreateReqVO { @NotNull(message = "订单项编号不能为空") private Long orderItemId; - @ApiModelProperty(name = "售后类型", required = true, example = "1", notes = "对应 TradeAfterSaleTypeEnum 枚举") - @NotNull(message = "售后类型不能为空") - @InEnum(value = TradeAfterSaleTypeEnum.class, message = "售后类型必须是 {value}") - private Integer type; + @ApiModelProperty(name = "售后方式", required = true, example = "1", notes = "对应 TradeAfterSaleWayEnum 枚举") + @NotNull(message = "售后方式不能为空") + @InEnum(value = TradeAfterSaleWayEnum.class, message = "售后方式必须是 {value}") + private Integer way; @ApiModelProperty(name = "退款金额", required = true, example = "100", notes = "单位:分") @NotNull(message = "退款金额不能为空") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java index 6cda2f767e..ef5b23fccd 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java @@ -5,6 +5,7 @@ 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.enums.aftersale.TradeAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; @@ -42,6 +43,12 @@ public class TradeAfterSaleDO extends BaseDO { * 枚举 {@link TradeAfterSaleStatusEnum} */ private Integer status; + /** + * 售后方式 + * + * 枚举 {@link TradeAfterSaleWayEnum} + */ + private Integer way; /** * 售后类型 * diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java index 47be712e9f..175d7d2b0a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java @@ -16,6 +16,7 @@ public interface TradeAfterSaleMapper extends BaseMapperX { .likeIfPresent(TradeAfterSaleDO::getNo, reqVO.getNo()) .eqIfPresent(TradeAfterSaleDO::getStatus, reqVO.getStatus()) .eqIfPresent(TradeAfterSaleDO::getType, reqVO.getType()) + .eqIfPresent(TradeAfterSaleDO::getWay, reqVO.getWay()) .likeIfPresent(TradeAfterSaleDO::getOrderNo, reqVO.getOrderNo()) .likeIfPresent(TradeAfterSaleDO::getSpuName, reqVO.getSpuName()) .betweenIfPresent(TradeAfterSaleDO::getCreateTime, reqVO.getCreateTime()) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java index 45434367da..f106a3e97f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java @@ -17,6 +17,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.TradeAfterSaleMapper; import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; @@ -88,7 +89,6 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { if (!TradeOrderItemAfterSaleStatusEnum.isNone(orderItem.getAfterSaleStatus())) { throw exception(AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED); } - // TODO 芋艿:超过一定时间,不允许售后 // 申请的退款金额,不能超过商品的价格 if (createReqVO.getRefundPrice() > orderItem.getOrderDividePrice()) { @@ -100,6 +100,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { if (order == null) { throw exception(ORDER_NOT_FOUND); } + // TODO 芋艿:超过一定时间,不允许售后 // 已取消,无法发起售后 if (TradeOrderStatusEnum.isCanceled(order.getStatus())) { throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED); @@ -109,7 +110,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID); } // 如果是【退货退款】的情况,需要额外校验是否发货 - if (createReqVO.getType().equals(TradeAfterSaleTypeEnum.RETURN_AND_REFUND.getType()) + if (createReqVO.getWay().equals(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay()) && !TradeOrderStatusEnum.haveDelivered(order.getStatus())) { throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED); } @@ -117,16 +118,21 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { } private TradeAfterSaleDO createAfterSale(AppTradeAfterSaleCreateReqVO createReqVO, - TradeOrderItemDO tradeOrderItem) { + TradeOrderItemDO orderItem) { // 创建售后单 - TradeAfterSaleDO afterSale = TradeAfterSaleConvert.INSTANCE.convert(createReqVO, tradeOrderItem); + TradeAfterSaleDO afterSale = TradeAfterSaleConvert.INSTANCE.convert(createReqVO, orderItem); afterSale.setNo(RandomUtil.randomString(10)); // TODO 芋艿:优化 no 生成逻辑 afterSale.setStatus(TradeAfterSaleStatusEnum.APPLY.getStatus()); + // 标记是售中还是售后 + TradeOrderDO order = tradeOrderService.getOrder(orderItem.getUserId(), orderItem.getOrderId()); + afterSale.setOrderNo(order.getNo()); // 记录 orderNo 订单流水,方便后续检索 + afterSale.setType(TradeOrderStatusEnum.isCompleted(order.getStatus()) + ? TradeAfterSaleTypeEnum.AFTER_SALE.getType() : TradeAfterSaleTypeEnum.IN_SALE.getType()); // TODO 退还积分 tradeAfterSaleMapper.insert(afterSale); // 更新交易订单项的售后状态 - tradeOrderService.updateOrderItemAfterSaleStatus(tradeOrderItem.getId(), + tradeOrderService.updateOrderItemAfterSaleStatus(orderItem.getId(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), null); @@ -145,7 +151,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { // 更新售后单的状态 // 情况一:退款:标记为 WAIT_REFUND 状态。后续等退款发起成功后,在标记为 COMPLETE 状态 // 情况二:退货退款:需要等用户退货后,才能发起退款 - Integer newStatus = afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType()) ? + Integer newStatus = afterSale.getType().equals(TradeAfterSaleWayEnum.REFUND.getWay()) ? TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus(); updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now())); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java index c0a511468d..95229eb1ed 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java @@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.TradeAfterSaleMapper; import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; @@ -58,7 +59,7 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest { // 准备参数 Long userId = 1024L; AppTradeAfterSaleCreateReqVO createReqVO = new AppTradeAfterSaleCreateReqVO() - .setOrderItemId(1L).setRefundPrice(100).setType(TradeAfterSaleTypeEnum.RETURN_AND_REFUND.getType()) + .setOrderItemId(1L).setRefundPrice(100).setWay(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay()) .setApplyReason("退钱").setApplyDescription("快退") .setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png")); // mock 方法(交易订单项) @@ -69,7 +70,8 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest { when(tradeOrderService.getOrderItem(eq(1024L), eq(1L))) .thenReturn(orderItem); // mock 方法(交易订单) - TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> o.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus())); + TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> o.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus()) + .setNo("202211301234")); when(tradeOrderService.getOrder(eq(1024L), eq(111L))).thenReturn(order); // 调用 @@ -78,9 +80,11 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest { TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(afterSaleId); assertNotNull(afterSale.getNo()); assertEquals(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus()); + assertEquals(afterSale.getType(), TradeAfterSaleTypeEnum.IN_SALE.getType()); assertPojoEquals(afterSale, createReqVO); assertEquals(afterSale.getUserId(), 1024L); assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime"); + assertEquals(afterSale.getOrderNo(), "202211301234"); assertNull(afterSale.getPayRefundId()); assertNull(afterSale.getRefundTime()); assertNull(afterSale.getLogisticsId()); @@ -95,7 +99,8 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest { TradeAfterSaleDO dbAfterSale = randomPojo(TradeAfterSaleDO.class, o -> { // 等会查询到 o.setNo("202211190847450020500077"); o.setStatus(TradeAfterSaleStatusEnum.APPLY.getStatus()); - o.setType(TradeAfterSaleTypeEnum.RETURN_AND_REFUND.getType()); + o.setWay(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay()); + o.setType(TradeAfterSaleTypeEnum.IN_SALE.getType()); o.setOrderNo("202211190847450020500011"); o.setSpuName("芋艿"); o.setCreateTime(buildTime(2022, 1, 15)); @@ -105,8 +110,10 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest { tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setNo("202211190847450020500066"))); // 测试 status 不匹配 tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setStatus(TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus()))); + // 测试 way 不匹配 + tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setWay(TradeAfterSaleWayEnum.REFUND.getWay()))); // 测试 type 不匹配 - tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setType(TradeAfterSaleTypeEnum.REFUND.getType()))); + tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setType(TradeAfterSaleTypeEnum.AFTER_SALE.getType()))); // 测试 orderNo 不匹配 tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setOrderNo("202211190847450020500022"))); // 测试 spuName 不匹配 @@ -117,7 +124,8 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest { TradeAfterSalePageReqVO reqVO = new TradeAfterSalePageReqVO(); reqVO.setNo("20221119084745002050007"); reqVO.setStatus(TradeAfterSaleStatusEnum.APPLY.getStatus()); - reqVO.setType(TradeAfterSaleTypeEnum.RETURN_AND_REFUND.getType()); + reqVO.setWay(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay()); + reqVO.setType(TradeAfterSaleTypeEnum.IN_SALE.getType()); reqVO.setOrderNo("20221119084745002050001"); reqVO.setSpuName("芋"); reqVO.setCreateTime(new LocalDateTime[]{buildTime(2022, 1, 1), buildTime(2022, 1, 16)}); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql index b4fc69c557..fc3c47527b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql @@ -75,6 +75,7 @@ CREATE TABLE IF NOT EXISTS "trade_after_sale" ( "no" varchar NOT NULL, "status" int NOT NULL, "type" int NOT NULL, + "way" int NOT NULL, "user_id" bigint NOT NULL, "apply_reason" varchar NOT NULL, "apply_description" varchar, diff --git a/yudao-ui-admin/src/api/mall/trade/afterSale.js b/yudao-ui-admin/src/api/mall/trade/afterSale.js new file mode 100644 index 0000000000..3d71fdc207 --- /dev/null +++ b/yudao-ui-admin/src/api/mall/trade/afterSale.js @@ -0,0 +1,18 @@ +import request from '@/utils/request' + +// 获得交易售后 +export function getAfterSale(id) { + return request({ + url: '/trade/after-sale/get?id=' + id, + method: 'get' + }) +} + +// 获得交易售后分页 +export function getAfterSalePage(query) { + return request({ + url: '/trade/after-sale/page', + method: 'get', + params: query + }) +} diff --git a/yudao-ui-admin/src/router/index.js b/yudao-ui-admin/src/router/index.js index 133eed1860..309a7a3b81 100644 --- a/yudao-ui-admin/src/router/index.js +++ b/yudao-ui-admin/src/router/index.js @@ -216,12 +216,6 @@ export const constantRoutes = [ hidden: true, meta: { title: '订单详情' }, component: (resolve) => require(['@/views/mall/trade/order/detail'], resolve) - }, - { - path: '/mall/trade/orderrefund', - name: '退款维权', - meta: { title: '退款维权' }, - component: (resolve) => require(['@/views/mall/trade/orderrefund'], resolve) } ] } diff --git a/yudao-ui-admin/src/utils/constants.js b/yudao-ui-admin/src/utils/constants.js index 3efb0e3c07..33f43ac0b7 100644 --- a/yudao-ui-admin/src/utils/constants.js +++ b/yudao-ui-admin/src/utils/constants.js @@ -3,6 +3,37 @@ * * 枚举类 */ +import {beginOfDay, endOfDay} from "@/utils/dateUtils"; + +export const datePickerOptions = { + shortcuts: [{ + text: '最近一周', + onClick(picker) { + const start = new Date(); + start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); + const end = new Date(); + picker.$emit('pick', [beginOfDay(start), endOfDay(end)]); + } + }, { + text: '最近一个月', + onClick(picker) { + const start = new Date(); + start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); + const end = new Date(); + picker.$emit('pick', [beginOfDay(start), endOfDay(end)]); + } + }, { + text: '最近三个月', + onClick(picker) { + const start = new Date(); + start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); + const end = new Date(); + picker.$emit('pick', [beginOfDay(start), endOfDay(end)]); + } + }] +} + +// ========== 静态变量 ========== /** * 全局通用状态枚举 diff --git a/yudao-ui-admin/src/utils/dateUtils.js b/yudao-ui-admin/src/utils/dateUtils.js index 2e658b4a36..dd4ea5313c 100644 --- a/yudao-ui-admin/src/utils/dateUtils.js +++ b/yudao-ui-admin/src/utils/dateUtils.js @@ -24,3 +24,11 @@ export function getDate(ms) { return 0 + "秒"; } } + +export function beginOfDay(date) { + return new Date(date.getFullYear(), date.getMonth(), date.getDate()); +} + +export function endOfDay(date) { + return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999); +} diff --git a/yudao-ui-admin/src/utils/dict.js b/yudao-ui-admin/src/utils/dict.js index f669c43166..f54659012b 100644 --- a/yudao-ui-admin/src/utils/dict.js +++ b/yudao-ui-admin/src/utils/dict.js @@ -60,6 +60,11 @@ export const DICT_TYPE = { // ========== MALL - PRODUCT 模块 ========== PRODUCT_SPU_STATUS: 'product_spu_status', // 商品 SPU 状态 + // ========== MALL - ORDER 模块 ========== + TRADE_AFTER_SALE_STATUS: 'trade_after_sale_status', // 售后 - 状态 + TRADE_AFTER_SALE_WAY: 'trade_after_sale_way', // 售后 - 方式 + TRADE_AFTER_SALE_TYPE: 'trade_after_sale_type', // 售后 - 类型 + // ========== MALL - PROMOTION 模块 ========== PROMOTION_DISCOUNT_TYPE: 'promotion_discount_type', // 优惠类型 PROMOTION_PRODUCT_SCOPE: 'promotion_product_scope', // 营销的商品范围 diff --git a/yudao-ui-admin/src/views/mall/trade/orderrefund/index.vue b/yudao-ui-admin/src/views/mall/trade/afterSale/bak.vue similarity index 53% rename from yudao-ui-admin/src/views/mall/trade/orderrefund/index.vue rename to yudao-ui-admin/src/views/mall/trade/afterSale/bak.vue index 3e1029bba0..5c49b18493 100644 --- a/yudao-ui-admin/src/views/mall/trade/orderrefund/index.vue +++ b/yudao-ui-admin/src/views/mall/trade/afterSale/bak.vue @@ -3,42 +3,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -