From 054375ebc0a9781ec5bdbc3f65ea842f0a3c6ba0 Mon Sep 17 00:00:00 2001 From: SjS Date: Sat, 26 Apr 2025 20:40:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A5=97=E9=A4=90=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ruoyi/common/enums/LogBizType.java | 10 +- .../bst/bonus/service/BonusConverter.java | 5 - .../service/impl/BonusConverterImpl.java | 10 -- .../bonus/service/impl/BonusServiceImpl.java | 4 - .../com/ruoyi/bst/order/domain/Order.java | 3 +- .../ruoyi/bst/order/domain/OrderQuery.java | 13 ++ .../com/ruoyi/bst/order/domain/OrderVO.java | 7 + .../bst/order/domain/bo/OrderCreateBO.java | 48 ++++++ .../bst/order/domain/dto/OrderCreateDTO.java | 35 ++++ .../bst/order/domain/enums/OrderStatus.java | 69 ++++++++ .../bst/order/domain/vo/OrderPrePriceVO.java | 14 ++ .../ruoyi/bst/order/mapper/OrderMapper.java | 17 ++ .../ruoyi/bst/order/mapper/OrderMapper.xml | 61 +++++-- .../bst/order/service/OrderConverter.java | 16 ++ .../ruoyi/bst/order/service/OrderService.java | 48 ++++++ .../bst/order/service/OrderValidator.java | 55 ++++++ .../service/impl/OrderConverterImpl.java | 133 +++++++++++++++ .../order/service/impl/OrderServiceImpl.java | 157 +++++++++++++++++- .../service/impl/OrderValidatorImpl.java | 115 +++++++++++++ .../com/ruoyi/bst/order/utils/OrderUtil.java | 50 ++++++ .../ruoyi/bst/pay/service/PayConverter.java | 8 + .../pay/service/impl/PayConverterImpl.java | 42 +++++ .../com/ruoyi/web/app/AppOrderController.java | 23 ++- .../com/ruoyi/web/bst/OrderController.java | 1 + 24 files changed, 899 insertions(+), 45 deletions(-) delete mode 100644 ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/BonusConverter.java delete mode 100644 ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/impl/BonusConverterImpl.java create mode 100644 ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/bo/OrderCreateBO.java create mode 100644 ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/dto/OrderCreateDTO.java create mode 100644 ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/enums/OrderStatus.java create mode 100644 ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/vo/OrderPrePriceVO.java create mode 100644 ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderConverter.java create mode 100644 ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderValidator.java create mode 100644 ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderConverterImpl.java create mode 100644 ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderValidatorImpl.java create mode 100644 ruoyi-service/src/main/java/com/ruoyi/bst/order/utils/OrderUtil.java diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/enums/LogBizType.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/enums/LogBizType.java index 25830e0..a010add 100644 --- a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/enums/LogBizType.java +++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/enums/LogBizType.java @@ -12,13 +12,11 @@ import lombok.Getter; @AllArgsConstructor public enum LogBizType { - UNKNOWN("0", "未知"), - PRICE("1", "单价"), - REPORT("2", "报表"), - PROD_ORDER("3", "生产订单" ), - MATERIAL("4", "物料"), + UNKNOWN("UNKNOWN", "未知"), + ORDER("ORDER", "订单"), UNIT("5", "单位"), - SHIFT("6", "调班"); + SHIFT("6", "调班"), + SUIT("SUIT", "套餐"); private final String type; private final String msg; diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/BonusConverter.java b/ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/BonusConverter.java deleted file mode 100644 index 57330ca..0000000 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/BonusConverter.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.ruoyi.bst.bonus.service; - -public interface BonusConverter { - -} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/impl/BonusConverterImpl.java b/ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/impl/BonusConverterImpl.java deleted file mode 100644 index 75e3f25..0000000 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/impl/BonusConverterImpl.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.ruoyi.bst.bonus.service.impl; - -import com.ruoyi.bst.bonus.service.BonusConverter; -import org.springframework.stereotype.Service; - -@Service -public class BonusConverterImpl implements BonusConverter { - - -} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/impl/BonusServiceImpl.java b/ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/impl/BonusServiceImpl.java index 71d193b..58293b1 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/impl/BonusServiceImpl.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/bonus/service/impl/BonusServiceImpl.java @@ -9,7 +9,6 @@ import com.ruoyi.bst.bonus.domain.enums.BonusArrivalType; import com.ruoyi.bst.bonus.domain.enums.BonusBstType; import com.ruoyi.bst.bonus.domain.enums.BonusStatus; import com.ruoyi.bst.bonus.mapper.BonusMapper; -import com.ruoyi.bst.bonus.service.BonusConverter; import com.ruoyi.bst.bonus.service.BonusService; import com.ruoyi.bst.bonus.utils.BonusUtil; import com.ruoyi.bst.bonusRefund.domain.BonusRefund; @@ -27,7 +26,6 @@ import org.springframework.transaction.support.TransactionTemplate; import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.Collections; import java.util.Date; import java.util.List; import java.util.concurrent.ScheduledExecutorService; @@ -62,8 +60,6 @@ public class BonusServiceImpl implements BonusService @Autowired private BonusRefundConverter bonusRefundConverter; - @Autowired - private BonusConverter bonusConverter; /** * 查询分成明细 diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/Order.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/Order.java index 3292826..f762843 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/Order.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/Order.java @@ -1,6 +1,7 @@ package com.ruoyi.bst.order.domain; import java.math.BigDecimal; +import java.time.LocalDateTime; import java.util.Date; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModelProperty; @@ -78,6 +79,6 @@ public class Order extends BaseEntity @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @Excel(name = "支付超时时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @ApiModelProperty("支付超时时间") - private Date payExpireTime; + private LocalDateTime payExpireTime; } diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderQuery.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderQuery.java index 91e9b49..9afc2f1 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderQuery.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderQuery.java @@ -1,7 +1,20 @@ package com.ruoyi.bst.order.domain; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import java.util.List; + @Data public class OrderQuery extends OrderVO{ + + @ApiModelProperty("订单id列表") + private List orderIds; + + @ApiModelProperty("精准订单编号") + private String eqNo; + + @ApiModelProperty("订单状态列表") + private List statusList; + } diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderVO.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderVO.java index 8891cda..4460952 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderVO.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderVO.java @@ -1,7 +1,14 @@ package com.ruoyi.bst.order.domain; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; @Data public class OrderVO extends Order{ + + // 支付 + @ApiModelProperty("支付单号") + private String payNo; + + } diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/bo/OrderCreateBO.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/bo/OrderCreateBO.java new file mode 100644 index 0000000..130e2f0 --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/bo/OrderCreateBO.java @@ -0,0 +1,48 @@ +package com.ruoyi.bst.order.domain.bo; + +import com.ruoyi.bst.app.domain.AppVO; + +import com.ruoyi.bst.channel.domain.ChannelVO; +import com.ruoyi.bst.device.domain.DeviceVO; +import com.ruoyi.bst.model.domain.ModelVO; +import com.ruoyi.bst.order.domain.Order; +import com.ruoyi.bst.order.domain.dto.OrderCreateDTO; +import com.ruoyi.bst.order.domain.vo.OrderPrePriceVO; +import com.ruoyi.bst.pay.domain.vo.DoPayVO; +import com.ruoyi.bst.suit.domain.SuitVO; +import com.ruoyi.bst.userApp.domain.UserAppVO; +import com.ruoyi.common.core.domain.vo.UserVO; +import lombok.Data; + +import java.util.List; + +@Data +public class OrderCreateBO { + + // 原始参数 + private OrderCreateDTO dto; + + // 套餐 + private SuitVO suit; + + // 下单用户 + private UserVO user; + + // 计算的价格信息 + private OrderPrePriceVO prePrice; + + // 渠道 + private ChannelVO channel; + + // APP信息 + private AppVO app; + + // 用户APP绑定信息 + private UserAppVO userApp; + + // 生成的订单 + private Order order; + + // 调起支付的返回值 + private DoPayVO doPayVO; +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/dto/OrderCreateDTO.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/dto/OrderCreateDTO.java new file mode 100644 index 0000000..b72b382 --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/dto/OrderCreateDTO.java @@ -0,0 +1,35 @@ +package com.ruoyi.bst.order.domain.dto; + +import com.ruoyi.bst.order.domain.vo.OrderPrePriceVO; +import com.ruoyi.common.core.interfaces.LogBizParam; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Data +public class OrderCreateDTO implements LogBizParam { + + @ApiModelProperty("下单用户ID") + private Long userId; + + @ApiModelProperty("套餐ID") + @NotNull(message = "套餐ID不能为空") + private Long suitId; + + @ApiModelProperty("APP ID") + @NotNull(message = "APP ID不能为空") + private Long appId; + + @ApiModelProperty("支付渠道ID") + @NotNull(message = "支付渠道ID不能为空") + private Long channelId; + + @ApiModelProperty("价格信息") + private OrderPrePriceVO price; + + @Override + public Object logBizId() { + return suitId; + } +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/enums/OrderStatus.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/enums/OrderStatus.java new file mode 100644 index 0000000..090af80 --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/enums/OrderStatus.java @@ -0,0 +1,69 @@ +package com.ruoyi.bst.order.domain.enums; + +import com.ruoyi.common.utils.collection.CollectionUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +@Getter +@AllArgsConstructor +public enum OrderStatus { + + WAIT_PAY("WAIT_PAY", "待支付"), + PROCESSING("PROCESSING", "进行中"), + FINISHED("FINISHED", "已结束"), + CANCELED("CANCELED", "已取消"), + WAIT_VERIFY("WAIT_VERIFY", "待审核"), + REJECTED("REJECTED", "已驳回"), + REFUNDED("REFUNDED", "已退款"); + + private final String code; + private final String name; + + + // 允许支付的订单状态 + public static List canPay() { + return CollectionUtils.map(OrderStatus::getCode, WAIT_PAY); + } + + // 正在使用中的订单状态 + public static List inUse() { + return CollectionUtils.map(OrderStatus::getCode, PROCESSING); + } + + // 可以支付成功的订单状态 + public static List canPaySuccess() { + return CollectionUtils.map(OrderStatus::getCode, WAIT_PAY); + } + + // 可以结束的订单状态 + public static List canEnd() { + return CollectionUtils.map(OrderStatus::getCode, PROCESSING); + } + + // 可以退款的订单状态 + public static List canRefund() { + return CollectionUtils.map(OrderStatus::getCode, FINISHED, REFUNDED, REJECTED, WAIT_VERIFY); + } + + // 未支付的订单状态 + public static List unPayList() { + return CollectionUtils.map(OrderStatus::getCode, WAIT_PAY); + } + + // 可以取消支付的订单状态 + public static List canCancelPay() { + return CollectionUtils.map(OrderStatus::getCode, WAIT_PAY); + } + + // 可以审核的订单状态 + public static List canVerify() { + return CollectionUtils.map(OrderStatus::getCode, WAIT_VERIFY); + } + + // 有效的订单状态:已支付的订单 + public static List valid() { + return CollectionUtils.map(OrderStatus::getCode, PROCESSING, FINISHED, WAIT_VERIFY, REJECTED, REFUNDED); + } +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/vo/OrderPrePriceVO.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/vo/OrderPrePriceVO.java new file mode 100644 index 0000000..e04f734 --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/vo/OrderPrePriceVO.java @@ -0,0 +1,14 @@ +package com.ruoyi.bst.order.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class OrderPrePriceVO { + + @ApiModelProperty("支付金额") + private BigDecimal payAmount; + +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.java index e6c968d..4b8ce5f 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.java @@ -71,4 +71,21 @@ public interface OrderMapper * @return 结果 */ public int deleteOrderByIds(Long[] ids); + + /** + * 根据查询条件查询订单ID列表 + * @param query 查询条件 + * @return 订单ID列表 + */ + List selectIdByQuery(@Param("query") OrderQuery query); + + + /** + * 根据查询条件更新订单 + * @param data 更新数据 + * @param query 查询条件 + * @return 结果 + */ + int updateByQuery(@Param("data") Order data, @Param("query") OrderQuery query); + } diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.xml b/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.xml index 66c208c..636c744 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.xml +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.xml @@ -25,23 +25,29 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select - id, - order_no, - store_id, - store_name, - user_id, - pay_id, - pay_amount, - mark, - status, - create_time, - suit_id, - suit_name, - suit_num, - suit_amount, - cancel_remark, - pay_expire_time - from bst_order + bo.id, + bo.order_no, + bo.store_id, + bo.store_name, + bo.user_id, + bo.pay_id, + bo.pay_amount, + bo.mark, + bo.status, + bo.create_time, + bo.suit_id, + bo.suit_name, + bo.suit_num, + bo.suit_amount, + bo.cancel_remark, + bo.pay_expire_time + from + + + + bst_order bo + left join sys_user su on bo.user_id = su.user_id + left join bst_pay bp on bo.pay_id = bp.id @@ -73,6 +79,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where id = #{id} + + + + insert into bst_order @@ -336,6 +352,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where id = #{data.id} + + + update bst_order bo + + + + + + + + order_no = #{data.orderNo}, store_id = #{data.storeId}, diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderConverter.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderConverter.java new file mode 100644 index 0000000..7eebab2 --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderConverter.java @@ -0,0 +1,16 @@ +package com.ruoyi.bst.order.service; + +import com.ruoyi.bst.order.domain.Order; +import com.ruoyi.bst.order.domain.OrderVO; +import com.ruoyi.bst.order.domain.bo.OrderCreateBO; +import com.ruoyi.bst.order.domain.dto.*; + +public interface OrderConverter { + + + /** + * 订单创建,将DTO转换为BO + */ + OrderCreateBO toCreateBO(OrderCreateDTO dto); + +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderService.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderService.java index a4d6fdf..63c6dde 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderService.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderService.java @@ -4,6 +4,8 @@ import java.util.List; import com.ruoyi.bst.order.domain.Order; import com.ruoyi.bst.order.domain.OrderVO; import com.ruoyi.bst.order.domain.OrderQuery; +import com.ruoyi.bst.order.domain.dto.OrderCreateDTO; +import com.ruoyi.bst.pay.domain.vo.DoPayVO; /** * 订单列表Service接口 @@ -60,4 +62,50 @@ public interface OrderService * @return 结果 */ public int deleteOrderById(Long id); + + /** + * 创建订单 + * @param dto 创建订单DTO + * @return 订单 + */ + public DoPayVO createOrder(OrderCreateDTO dto); + + /** + * 查询订单 + * @param no 订单编号 + * @param scope 是否数据隔离 + * @return 订单 + */ + public OrderVO selectOrderByNo(String no, boolean scope); + + /** + * 查询订单 + * @param no 订单编号 + * @return 订单 + */ + default OrderVO selectOrderByNo(String no) { + return this.selectOrderByNo(no, false); + } + + + /** + * 查询单个订单 + * @param query 查询条件 + * @return 订单 + */ + public OrderVO selectOne(OrderQuery query); + + /** + * 取消过期订单 + * @param order 订单 + */ + public void cancelWhenExpired(Order order); + + /** + * 取消订单 + * @param id 订单ID + * @return 结果 + */ + public int cancelOrder(Long id, String remark); + } diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderValidator.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderValidator.java new file mode 100644 index 0000000..5223312 --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderValidator.java @@ -0,0 +1,55 @@ +package com.ruoyi.bst.order.service; + +import com.ruoyi.bst.device.domain.DeviceVO; +import com.ruoyi.bst.order.domain.OrderVO; +import com.ruoyi.bst.order.domain.bo.OrderCreateBO; + +public interface OrderValidator { + + /** + * 校验订单BO + * @param bo 订单BO + */ + void validate(OrderCreateBO bo); + + /** + * 校验用户是否可以支付指定订单 + * @param order 订单 + * @param userId 用户ID + * @return 是否可以支付 + */ + boolean canPay(OrderVO order, Long userId); + + /** + * 校验普通用户是否可以结束指定订单 + * @param order 订单 + * @param userId 用户ID + * @return 是否可以结束 + */ + boolean canEnd(OrderVO order, Long userId); + + + /** + * 校验用户是否可以操作设备开启 + * @param order 订单 + * @param userId 用户ID + * @return 是否可以操作设备开启 + */ + boolean canOpenDevice(OrderVO order, Long userId); + + /** + * 校验用户是否可以操作设备关闭 + * @param order 订单 + * @param userId 用户ID + * @return 是否可以操作设备关闭 + */ + boolean canCloseDevice(OrderVO order, Long userId); + + /** + * 校验用户是否可以操作指定订单 + * @param orderId 订单ID + * @return 是否可以操作 + */ + boolean canOperate(Long orderId); + +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderConverterImpl.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderConverterImpl.java new file mode 100644 index 0000000..eb5f230 --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderConverterImpl.java @@ -0,0 +1,133 @@ +package com.ruoyi.bst.order.service.impl; + +import com.ruoyi.bst.app.domain.AppVO; +import com.ruoyi.bst.app.service.AppService; +import com.ruoyi.bst.channel.domain.ChannelVO; +import com.ruoyi.bst.channel.service.ChannelService; +import com.ruoyi.bst.device.service.DeviceIotService; +import com.ruoyi.bst.device.service.DeviceService; + +import com.ruoyi.bst.model.service.ModelService; +import com.ruoyi.bst.order.domain.Order; +import com.ruoyi.bst.order.domain.bo.OrderCreateBO; +import com.ruoyi.bst.order.domain.dto.*; +import com.ruoyi.bst.order.domain.vo.OrderPrePriceVO; +import com.ruoyi.bst.order.service.OrderConverter; +import com.ruoyi.bst.order.service.OrderService; +import com.ruoyi.bst.order.utils.OrderUtil; +import com.ruoyi.bst.suit.domain.SuitVO; +import com.ruoyi.bst.suit.service.SuitService; +import com.ruoyi.bst.userApp.domain.UserAppVO; +import com.ruoyi.bst.userApp.service.UserAppService; +import com.ruoyi.common.core.domain.vo.UserVO; + +import com.ruoyi.system.user.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +@Service +public class OrderConverterImpl implements OrderConverter{ + + @Autowired + private SuitService suitService; + + @Autowired + private DeviceService deviceService; + + @Autowired + private UserService userService; + + + @Autowired + private ChannelService channelService; + + @Autowired + private AppService appService; + + @Autowired + private UserAppService userAppService; + + @Autowired + private DeviceIotService deviceIotService; + + @Autowired + private OrderService orderService; + + @Autowired + private ModelService modelService; + + + @Override + public OrderCreateBO toCreateBO(OrderCreateDTO dto) { + if (dto == null) { + return null; + } + OrderCreateBO bo = new OrderCreateBO(); + bo.setDto(dto); + + // 套餐 + SuitVO suit = suitService.selectSuitById(dto.getSuitId()); + bo.setSuit(suit); + + // 用户 + UserVO user = userService.selectUserById(dto.getUserId()); + bo.setUser(user); + + // 查询渠道 + ChannelVO channel = channelService.selectChannelByChannelId(dto.getChannelId()); + bo.setChannel(channel); + + // 查询应用 + AppVO app = appService.selectAppById(dto.getAppId()); + bo.setApp(app); + + // 价格信息 + OrderPrePriceVO prePrice = OrderUtil.calcPrePrice(suit); + bo.setPrePrice(prePrice); + + + // 查询用户应用信息 + if (user != null && app != null) { + UserAppVO userApp = userAppService.selectByUserApp(user.getUserId(), app.getId()); + bo.setUserApp(userApp); + } + + // 生成订单 + Order order = this.generateOrder(bo); + bo.setOrder(order); + + return bo; + } + + + // 生成订单 + private Order generateOrder(OrderCreateBO bo) { + if (bo == null) { + return null; + } + Order order = new Order(); + // 基础信息 + order.setPayExpireTime(LocalDateTime.now().plusMinutes(3)); + + // 用户信息 + UserVO user = bo.getUser(); + if (user != null) { + order.setUserId(user.getUserId()); + } + + // 套餐信息 + SuitVO suit = bo.getSuit(); + if (suit != null) { + order.setStoreId(suit.getStoreId()); + order.setSuitId(suit.getSuitId()); + order.setSuitName(suit.getSuitName()); + order.setPayAmount(suit.getRechargeAmount()); + order.setSuitNum(suit.getLightingNums()); + } + + return order; + } + +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderServiceImpl.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderServiceImpl.java index 4a59b87..9964807 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderServiceImpl.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderServiceImpl.java @@ -1,7 +1,28 @@ package com.ruoyi.bst.order.service.impl; +import java.time.Duration; +import java.time.LocalDateTime; import java.util.List; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import com.github.pagehelper.PageHelper; +import com.ruoyi.bst.order.domain.bo.OrderCreateBO; +import com.ruoyi.bst.order.domain.dto.OrderCreateDTO; +import com.ruoyi.bst.order.domain.enums.OrderStatus; +import com.ruoyi.bst.order.service.OrderConverter; +import com.ruoyi.bst.order.service.OrderValidator; +import com.ruoyi.bst.pay.domain.Pay; +import com.ruoyi.bst.pay.domain.enums.PayBstType; +import com.ruoyi.bst.pay.domain.vo.DoPayVO; +import com.ruoyi.bst.pay.service.PayConverter; +import com.ruoyi.bst.pay.service.PayService; import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.ServiceUtil; +import com.ruoyi.common.utils.SnowFlakeUtil; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.collection.CollectionUtils; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.bst.order.mapper.OrderMapper; @@ -9,6 +30,7 @@ import com.ruoyi.bst.order.domain.Order; import com.ruoyi.bst.order.domain.OrderVO; import com.ruoyi.bst.order.domain.OrderQuery; import com.ruoyi.bst.order.service.OrderService; +import org.springframework.transaction.support.TransactionTemplate; /** * 订单列表Service业务层处理 @@ -21,7 +43,18 @@ public class OrderServiceImpl implements OrderService { @Autowired private OrderMapper orderMapper; - + @Autowired + private TransactionTemplate transactionTemplate; + @Autowired + private OrderConverter orderConverter; + @Autowired + private OrderValidator orderValidator; + @Autowired + private PayConverter payConverter; + @Autowired + private PayService payService; + @Autowired + private ScheduledExecutorService scheduledExecutorService; /** * 查询订单列表 * @@ -56,6 +89,7 @@ public class OrderServiceImpl implements OrderService public int insertOrder(Order order) { order.setCreateTime(DateUtils.getNowDate()); + order.setOrderNo(String.valueOf(SnowFlakeUtil.newId())); return orderMapper.insertOrder(order); } @@ -94,4 +128,125 @@ public class OrderServiceImpl implements OrderService { return orderMapper.deleteOrderById(id); } + + @Override + public DoPayVO createOrder(OrderCreateDTO dto) { + // 转为BO对象 + OrderCreateBO bo = orderConverter.toCreateBO(dto); + // 校验参数 + orderValidator.validate(bo); + + return transactionTemplate.execute(status -> { + + // 创建订单 + Order order = bo.getOrder(); + int rows = this.insertOrder(order); + ServiceUtil.assertion(rows != 1, "创建订单失败"); + + // 查询订单 + OrderVO vo = this.selectOrderByNo(order.getOrderNo()); + ServiceUtil.assertion(vo == null, "查询创建的订单失败"); + + // 支付 + DoPayVO doPayVO = this.pay(bo); + ServiceUtil.assertion(doPayVO == null, "支付失败"); + bo.setDoPayVO(doPayVO); + + // 加入延时队列,超时取消 + this.cancelWhenExpired(order); + return doPayVO; + }); + } + + private DoPayVO pay(OrderCreateBO bo) { + + // 转为支付PO + Pay pay = payConverter.toPayPO(bo); + ServiceUtil.assertion(pay == null, "转为支付单失败"); + + return transactionTemplate.execute(status -> { + // 创建并调起支付 + return payService.createPayBill(pay); + }); + } + + // 加入延时队列,超时取消 + @Override + public void cancelWhenExpired(Order order) { + if (order == null || order.getPayExpireTime() == null) { + return; + } + + Duration duration = Duration.between(LocalDateTime.now(), order.getPayExpireTime()); + long delay = duration.getSeconds(); + if (delay <= 0) { + delay = 1; + } + scheduledExecutorService.schedule(() -> { + // 尝试取消订单 + this.cancelOrder(order.getId(), "订单超时取消"); + }, delay, TimeUnit.SECONDS); + } + + // 取消订单 + @Override + public int cancelOrder(Long id, String remark) { + if (id == null) { + return 0; + } + // 查询订单 + OrderVO order = this.selectOrderById(id); + ServiceUtil.assertion(order == null, "ID为%s的订单不存在", id); + ServiceUtil.assertion(!OrderStatus.canCancelPay().contains(order.getStatus()), "ID为%s的订单当前状态不允许取消", id); + + // 刷新支付结果 + if (order.getPayNo() != null) { + payService.refreshPayResult(order.getPayNo()); + } + + // 查询最新订单状态 + order = this.selectOrderById(id); + ServiceUtil.assertion(order == null, "ID为%s的订单不存在", id); + ServiceUtil.assertion(!OrderStatus.canCancelPay().contains(order.getStatus()), "ID为%s的订单当前状态不允许取消", id); + + + // 取消订单 + Integer result = transactionTemplate.execute(status -> { + // 更新订单状态 + Order data = new Order(); + data.setStatus(OrderStatus.CANCELED.getCode()); + data.setCancelRemark(remark); + OrderQuery query = new OrderQuery(); + query.setId(id); + query.setStatusList(OrderStatus.canCancelPay()); + int rows = orderMapper.updateByQuery(data, query); + ServiceUtil.assertion(rows != 1, "ID为%s的订单取消失败,状态已发生变化", id); + + // 取消支付单 + boolean cancelPay = payService.closeByBstId(PayBstType.ORDER.getType(), id); + ServiceUtil.assertion(!cancelPay, "ID为%s的订单取消支付单失败", id); + + return rows; + }); + + return result == null ? 0 : result; + } + + @Override + public OrderVO selectOrderByNo(String no, boolean scope) { + if (StringUtils.isBlank(no)) { + return null; + } + OrderQuery query = new OrderQuery(); + query.setEqNo(no); + query.setScope(scope); + return this.selectOne(query); + } + + @Override + public OrderVO selectOne(OrderQuery query) { + PageHelper.startPage(1, 1); + List list = this.selectOrderList(query); + return CollectionUtils.firstElement(list); + } } diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderValidatorImpl.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderValidatorImpl.java new file mode 100644 index 0000000..b746b4c --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderValidatorImpl.java @@ -0,0 +1,115 @@ +package com.ruoyi.bst.order.service.impl; + +import com.ruoyi.bst.app.domain.AppVO; + +import com.ruoyi.bst.channel.domain.ChannelVO; + +import com.ruoyi.bst.device.service.DeviceService; + +import com.ruoyi.bst.order.domain.OrderQuery; +import com.ruoyi.bst.order.domain.OrderVO; +import com.ruoyi.bst.order.domain.bo.OrderCreateBO; + +import com.ruoyi.bst.order.domain.dto.OrderCreateDTO; + +import com.ruoyi.bst.order.domain.vo.OrderPrePriceVO; +import com.ruoyi.bst.order.mapper.OrderMapper; +import com.ruoyi.bst.order.service.OrderValidator; +import com.ruoyi.bst.order.utils.OrderUtil; +import com.ruoyi.bst.suit.domain.SuitVO; +import com.ruoyi.common.core.domain.vo.UserVO; +import com.ruoyi.common.utils.ServiceUtil; +import com.ruoyi.common.utils.collection.CollectionUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; + +@Service +@Slf4j +public class OrderValidatorImpl implements OrderValidator{ + + @Autowired + private OrderMapper orderMapper; + + @Override + public void validate(OrderCreateBO bo) { + ServiceUtil.assertion(bo == null, "参数错误"); + + OrderCreateDTO dto = bo.getDto(); + ServiceUtil.assertion(dto == null, "参数错误"); + + // 套餐 + SuitVO suit = bo.getSuit(); + ServiceUtil.assertion(suit == null, "ID为%s的套餐不存在", dto.getSuitId()); + + // 用户 + UserVO user = bo.getUser(); + ServiceUtil.assertion(user == null, "ID为%s的用户不存在", dto.getUserId()); + + // 价格 + OrderPrePriceVO prePrice = bo.getPrePrice(); + ServiceUtil.assertion(prePrice == null, "价格计算失败"); + // 是否和前端传输的价格一致 + boolean priceEquals = OrderUtil.isEquals(prePrice, dto.getPrice()); + ServiceUtil.assertion(!priceEquals, "当前价格已发生变化,请刷新后重新下单"); + + // 应用 + AppVO app = bo.getApp(); + ServiceUtil.assertion(app == null, "ID为%s的应用不存在", dto.getAppId()); + + // 渠道 + ChannelVO channel = bo.getChannel(); + ServiceUtil.assertion(channel == null, "ID为%s的渠道不存在", dto.getChannelId()); + ServiceUtil.assertion(channel.getEnabled() == null || !channel.getEnabled(), "ID为%s的渠道暂不可用", channel.getChannelId()); + ServiceUtil.assertion(channel.getAppIds() == null || !channel.getAppIds().contains(app.getId()), "ID为%s的渠道不支持ID为%s的应用", channel.getChannelId(), app.getId()); + + } + + @Override + public boolean canPay(OrderVO order, Long userId) { + return isUser(order, userId); + } + + @Override + public boolean canEnd(OrderVO order, Long userId) { + return isUser(order, userId); + } + + // 是否是下单用户 + private boolean isUser(OrderVO order, Long userId) { + return order != null && userId != null && Objects.equals(order.getUserId(), userId); + } + + + @Override + public boolean canOpenDevice(OrderVO order, Long userId) { + return isUser(order, userId); + } + + @Override + public boolean canCloseDevice(OrderVO order, Long userId) { + return isUser(order, userId); + } + + + @Override + public boolean canOperate(Long orderId) { + return hasPermission(Collections.singletonList(orderId)); + } + + private boolean hasPermission(List orderIds) { + if (CollectionUtils.isEmptyElement(orderIds)) { + return true; + } + OrderQuery query = new OrderQuery(); + query.setScope(true); + query.setOrderIds(orderIds); + List list = orderMapper.selectIdByQuery(query); + return new HashSet<>(list).containsAll(orderIds); + } +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/utils/OrderUtil.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/utils/OrderUtil.java new file mode 100644 index 0000000..8f6411a --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/utils/OrderUtil.java @@ -0,0 +1,50 @@ +package com.ruoyi.bst.order.utils; + +import com.ruoyi.bst.device.domain.DeviceQuery; +import com.ruoyi.bst.device.domain.DeviceVO; +import com.ruoyi.bst.device.domain.enums.DeviceStatus; +import com.ruoyi.bst.order.domain.OrderVO; +import com.ruoyi.bst.order.domain.vo.OrderPrePriceVO; +import com.ruoyi.bst.suit.domain.SuitVO; +import com.ruoyi.common.utils.MathUtils; + +import java.math.BigDecimal; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +public class OrderUtil { + + + /** + * 判断两个价格是否一致 + * @param a 价格A + * @param b 价格B + * @return 是否一致 + */ + public static boolean isEquals(OrderPrePriceVO a, OrderPrePriceVO b) { + if (a == null || b == null) { + return false; + } + return MathUtils.equals(a.getPayAmount(), b.getPayAmount()); + } + + public static OrderPrePriceVO calcPrePrice(SuitVO suit) { + if (suit == null) { + return null; + } + OrderPrePriceVO vo = new OrderPrePriceVO(); + vo.setPayAmount(suit.getRechargeAmount()); + return vo; + } +// +// public static BigDecimal calcCanRefundAmount(OrderVO order) { +// if (order == null) { +// return BigDecimal.ZERO; +// } +// return MathUtils.subtractDecimal(order.getPayAmount(), order.getPayRefunding(), order.getPayRefunded()); +// } + + + +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/pay/service/PayConverter.java b/ruoyi-service/src/main/java/com/ruoyi/bst/pay/service/PayConverter.java index 1d092f9..d144788 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/pay/service/PayConverter.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/pay/service/PayConverter.java @@ -1,7 +1,15 @@ package com.ruoyi.bst.pay.service; +import com.ruoyi.bst.order.domain.bo.OrderCreateBO; +import com.ruoyi.bst.pay.domain.Pay; + public interface PayConverter { + /** + * 将订单支付BO转换为支付PO + */ + Pay toPayPO(OrderCreateBO bo); + } diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/pay/service/impl/PayConverterImpl.java b/ruoyi-service/src/main/java/com/ruoyi/bst/pay/service/impl/PayConverterImpl.java index a0dd98e..3b31400 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/pay/service/impl/PayConverterImpl.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/pay/service/impl/PayConverterImpl.java @@ -2,6 +2,8 @@ package com.ruoyi.bst.pay.service.impl; import com.ruoyi.bst.app.domain.AppVO; import com.ruoyi.bst.channel.domain.ChannelVO; +import com.ruoyi.bst.order.domain.Order; +import com.ruoyi.bst.order.domain.bo.OrderCreateBO; import com.ruoyi.bst.pay.domain.Pay; import com.ruoyi.bst.pay.domain.enums.PayBstType; import com.ruoyi.bst.pay.domain.enums.PayStatus; @@ -17,5 +19,45 @@ import java.time.LocalDateTime; @Service public class PayConverterImpl implements PayConverter { + @Override + public Pay toPayPO(OrderCreateBO bo) { + if (bo == null) { + return null; + } + Order order = bo.getOrder(); + UserVO user = bo.getUser(); + ChannelVO channel = bo.getChannel(); + UserAppVO userApp = bo.getUserApp(); + AppVO app = bo.getApp(); + if (order == null || user == null || channel == null || userApp == null || app == null) { + return null; + } + + Pay pay = new Pay(); + // 基础信息 + pay.setStatus(PayStatus.WAIT_PAY.getStatus()); + pay.setExpireTime(LocalDateTime.now().plusMinutes(10)); + + // 订单信息 + pay.setBstType(PayBstType.ORDER.getType()); + pay.setBstId(order.getId()); + pay.setAmount(order.getPayAmount()); + + // 用户信息 + pay.setAccount(userApp.getOpenId()); + pay.setIp(IpUtils.getIpAddr()); + + // 应用信息 + pay.setAppId(app.getId()); + pay.setAppName(app.getName()); + + // 渠道信息 + pay.setChannelId(channel.getChannelId()); + pay.setChannelName(channel.getName()); + + // 渠道成本(放最后) + pay.setChannelCost(MathUtils.mulDecimal(channel.getCostRate(), pay.getAmount())); + return pay; + } } diff --git a/ruoyi-web/src/main/java/com/ruoyi/web/app/AppOrderController.java b/ruoyi-web/src/main/java/com/ruoyi/web/app/AppOrderController.java index 7959a62..8b38eac 100644 --- a/ruoyi-web/src/main/java/com/ruoyi/web/app/AppOrderController.java +++ b/ruoyi-web/src/main/java/com/ruoyi/web/app/AppOrderController.java @@ -1,12 +1,33 @@ package com.ruoyi.web.app; +import com.ruoyi.bst.order.domain.dto.OrderCreateDTO; +import com.ruoyi.bst.order.service.OrderService; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.enums.LogBizType; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +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; @RestController @RequestMapping("/app/order") -public class AppOrderController { +public class AppOrderController extends BaseController { + @Autowired + private OrderService orderService; + @ApiOperation("下单并支付") + @PostMapping + @Log(title = "下单并支付", businessType = BusinessType.OTHER, bizIdName = "arg0", bizType = LogBizType.SUIT) + public AjaxResult createOrder(@RequestBody @Validated OrderCreateDTO dto) { + dto.setUserId(getUserId()); + return success(orderService.createOrder(dto)); + } } diff --git a/ruoyi-web/src/main/java/com/ruoyi/web/bst/OrderController.java b/ruoyi-web/src/main/java/com/ruoyi/web/bst/OrderController.java index 46d68b4..e310ebc 100644 --- a/ruoyi-web/src/main/java/com/ruoyi/web/bst/OrderController.java +++ b/ruoyi-web/src/main/java/com/ruoyi/web/bst/OrderController.java @@ -39,6 +39,7 @@ public class OrderController extends BaseController { startPage(); startOrderBy(); + query.setScope(true); List list = orderService.selectOrderList(query); return getDataTable(list); }