Ver Fonte

支付修改

zhangchen há 1 mês atrás
pai
commit
a3ca72a1d7

+ 8 - 0
alien-entity/src/main/java/shop/alien/mapper/UserReservationMapper.java

@@ -40,4 +40,12 @@ public interface UserReservationMapper extends BaseMapper<UserReservation> {
      * @return 删除行数
      * @return 删除行数
      */
      */
     int physicalDeleteById(@Param("id") Integer id);
     int physicalDeleteById(@Param("id") Integer id);
+
+    /**
+     * 关联查询:订单为待使用且预约结束时间已过的 reservation_id 列表。
+     * 用于定时任务将「未到店超时」的预订与订单批量更新。
+     *
+     * @return 需要标记为已过期/未到店超时的 user_reservation.id 列表
+     */
+    List<Integer> listReservationIdsForTimeoutMark();
 }
 }

+ 12 - 0
alien-entity/src/main/resources/mapper/UserReservationMapper.xml

@@ -139,4 +139,16 @@
         DELETE FROM user_reservation WHERE id = #{id}
         DELETE FROM user_reservation WHERE id = #{id}
     </delete>
     </delete>
 
 
+    <!-- 关联查询:订单待使用 + 预约结束时间已过,仅返回 reservation_id -->
+    <select id="listReservationIdsForTimeoutMark" resultType="java.lang.Integer">
+        SELECT DISTINCT r.id
+        FROM user_reservation r
+        INNER JOIN user_reservation_order o ON o.reservation_id = r.id AND o.delete_flag = 0
+        WHERE r.delete_flag = 0
+          AND o.order_status = 1
+          AND r.status IN (0, 1)
+          AND r.end_time IS NOT NULL AND TRIM(r.end_time) != ''
+          AND STR_TO_DATE(CONCAT(DATE(r.reservation_date), ' ', TRIM(r.end_time)), '%Y-%m-%d %H:%i') &lt; NOW()
+    </select>
+
 </mapper>
 </mapper>

+ 8 - 0
alien-job/src/main/java/shop/alien/job/feign/AlienStoreFeign.java

@@ -69,4 +69,12 @@ public interface AlienStoreFeign {
     @RequestMapping("payment/refunds")
     @RequestMapping("payment/refunds")
     public R refunds(@RequestBody Map<String, String> params);
     public R refunds(@RequestBody Map<String, String> params);
 
 
+    /**
+     * 预订未到店超时定时任务:将 end_time 已过且订单状态为待使用的预订标记为已过期/未到店超时
+     *
+     * @return R.data 为本次更新的预约数量
+     */
+    @org.springframework.web.bind.annotation.PostMapping("/reservation/job/markTimeout")
+    R<Integer> markReservationTimeoutByEndTime();
+
 }
 }

+ 35 - 0
alien-job/src/main/java/shop/alien/job/store/ReservationTimeoutJob.java

@@ -0,0 +1,35 @@
+package shop.alien.job.store;
+
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import shop.alien.entity.result.R;
+import shop.alien.job.feign.AlienStoreFeign;
+
+/**
+ * 预订未到店超时定时任务
+ * 将 user_reservation.end_time 小于当前时间且对应 user_reservation_order 订单状态为「待使用」的预订:
+ * - user_reservation.status 置为 4(未到店超时)
+ * - user_reservation_order.order_status 置为 3(已过期)
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class ReservationTimeoutJob {
+
+    private final AlienStoreFeign alienStoreFeign;
+
+    @XxlJob("reservationTimeoutJob")
+    public void reservationTimeoutJob() {
+        log.info("【定时任务】预订未到店超时:开始执行");
+        try {
+            R<Integer> result = alienStoreFeign.markReservationTimeoutByEndTime();
+            int count = (result != null && result.getData() != null) ? result.getData() : 0;
+            log.info("【定时任务】预订未到店超时:执行完成,本次更新条数={}", count);
+        } catch (Exception e) {
+            log.error("【定时任务】预订未到店超时:执行异常", e);
+            throw e;
+        }
+    }
+}

+ 33 - 0
alien-store/src/main/java/shop/alien/store/controller/ReservationJobController.java

@@ -0,0 +1,33 @@
+package shop.alien.store.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import shop.alien.entity.result.R;
+import shop.alien.store.service.UserReservationService;
+
+/**
+ * 预订相关定时任务回调(供 XXL-JOB 通过 Feign 调用)
+ */
+@Slf4j
+@Api(tags = {"预订定时任务"})
+@RestController
+@RequestMapping("/reservation/job")
+@RequiredArgsConstructor
+public class ReservationJobController {
+
+    private final UserReservationService userReservationService;
+
+    @ApiOperation("标记「结束时间已过且订单待使用」的预订为未到店超时/已过期")
+    @PostMapping("/markTimeout")
+    public R<Integer> markReservationTimeoutByEndTime() {
+        log.info("reservation job: markTimeout 开始");
+        int count = userReservationService.markReservationTimeoutByEndTime();
+        log.info("reservation job: markTimeout 结束,更新条数={}", count);
+        return R.data(count);
+    }
+}

+ 8 - 0
alien-store/src/main/java/shop/alien/store/service/UserReservationService.java

@@ -172,4 +172,12 @@ public interface UserReservationService extends IService<UserReservation> {
      * @return 详情 VO,订单不存在返回 null
      * @return 详情 VO,订单不存在返回 null
      */
      */
     ReservationOrderDetailVo getOrderDetailByOrderId(Integer orderId);
     ReservationOrderDetailVo getOrderDetailByOrderId(Integer orderId);
+
+    /**
+     * 定时任务:将「预约结束时间已过」且「订单状态为待使用」的预订标记为已过期/未到店超时。
+     * 更新:user_reservation.status = 4(未到店超时),user_reservation_order.order_status = 3(已过期)。
+     *
+     * @return 本次更新的预约数量(即更新的 order 数量)
+     */
+    int markReservationTimeoutByEndTime();
 }
 }

+ 46 - 6
alien-store/src/main/java/shop/alien/store/service/impl/UserReservationServiceImpl.java

@@ -70,8 +70,16 @@ public class UserReservationServiceImpl extends ServiceImpl<UserReservationMappe
 
 
     /** 预约状态:待确认 */
     /** 预约状态:待确认 */
     private static final int STATUS_PENDING = 0;
     private static final int STATUS_PENDING = 0;
+    /** 预约状态:已确认(待使用) */
+    private static final int STATUS_CONFIRMED = 1;
     /** 预约状态:已取消(不参与约满统计与展示) */
     /** 预约状态:已取消(不参与约满统计与展示) */
     private static final int STATUS_CANCELLED = 3;
     private static final int STATUS_CANCELLED = 3;
+    /** 预约状态:未到店超时 */
+    private static final int STATUS_NO_SHOW_TIMEOUT = 4;
+    /** 订单状态:待使用 */
+    private static final int ORDER_STATUS_TO_USE = 1;
+    /** 订单状态:已过期 */
+    private static final int ORDER_STATUS_EXPIRED = 3;
     /** 查找首个未约满日期时,最多往后检查的天数 */
     /** 查找首个未约满日期时,最多往后检查的天数 */
     private static final int MAX_DAYS_TO_CHECK = 366;
     private static final int MAX_DAYS_TO_CHECK = 366;
     /** 全天预订时使用的结束分钟数(24*60,即到次日0点) */
     /** 全天预订时使用的结束分钟数(24*60,即到次日0点) */
@@ -109,6 +117,11 @@ public class UserReservationServiceImpl extends ServiceImpl<UserReservationMappe
         if (order.getOrderCostType() != null && order.getOrderCostType() == 1 && order.getOrderSn() != null) {
         if (order.getOrderCostType() != null && order.getOrderCostType() == 1 && order.getOrderSn() != null) {
             reservationOrderPaymentTimeoutService.setReservationOrderPaymentTimeout(order.getOrderSn(), 15 * 60);
             reservationOrderPaymentTimeoutService.setReservationOrderPaymentTimeout(order.getOrderSn(), 15 * 60);
         }
         }
+        // 免费预订:对应预约状态设为已确认(1),与订单「待使用」一致
+        if (order.getOrderCostType() != null && order.getOrderCostType() == 0) {
+            entity.setStatus(STATUS_CONFIRMED);
+            this.updateById(entity);
+        }
 
 
         return order.getId();
         return order.getId();
     }
     }
@@ -191,6 +204,11 @@ public class UserReservationServiceImpl extends ServiceImpl<UserReservationMappe
             if (order.getOrderCostType() != null && order.getOrderCostType() == 1 && order.getOrderSn() != null) {
             if (order.getOrderCostType() != null && order.getOrderCostType() == 1 && order.getOrderSn() != null) {
                 reservationOrderPaymentTimeoutService.setReservationOrderPaymentTimeout(order.getOrderSn(), 15 * 60);
                 reservationOrderPaymentTimeoutService.setReservationOrderPaymentTimeout(order.getOrderSn(), 15 * 60);
             }
             }
+            if (order.getOrderCostType() != null && order.getOrderCostType() == 0) {
+                this.update(new LambdaUpdateWrapper<UserReservation>()
+                        .eq(UserReservation::getId, existing.getId())
+                        .set(UserReservation::getStatus, STATUS_CONFIRMED));
+            }
         } else if (order.getOrderStatus() != null && order.getOrderStatus() == 0) {
         } else if (order.getOrderStatus() != null && order.getOrderStatus() == 0) {
             fillOrderFromStoreSettings(order, updatedReservation);
             fillOrderFromStoreSettings(order, updatedReservation);
             userReservationOrderService.updateById(order);
             userReservationOrderService.updateById(order);
@@ -209,16 +227,15 @@ public class UserReservationServiceImpl extends ServiceImpl<UserReservationMappe
         if (one == null) {
         if (one == null) {
             throw new RuntimeException("预约不存在");
             throw new RuntimeException("预约不存在");
         }
         }
-        // 假删除:将 delete_flag 置为 1(与 add 对应的三张表)
+        // 订单状态置为已取消(4)
         userReservationOrderService.update(
         userReservationOrderService.update(
                 new LambdaUpdateWrapper<UserReservationOrder>()
                 new LambdaUpdateWrapper<UserReservationOrder>()
                         .eq(UserReservationOrder::getId, one.getId())
                         .eq(UserReservationOrder::getId, one.getId())
                         .set(UserReservationOrder::getOrderStatus, 4));
                         .set(UserReservationOrder::getOrderStatus, 4));
-//        userReservationTableMapper.update(null,
-//                new LambdaUpdateWrapper<UserReservationTable>()
-//                        .eq(UserReservationTable::getReservationId, one.getReservationId())
-//                        .set(UserReservationTable::getDeleteFlag, 1));
-        return this.removeById(id);
+        // 预约不再逻辑删除,仅将 status 置为已取消(3)
+        return this.update(new LambdaUpdateWrapper<UserReservation>()
+                .eq(UserReservation::getId, one.getReservationId())
+                .set(UserReservation::getStatus, STATUS_CANCELLED));
     }
     }
 
 
     @Override
     @Override
@@ -962,6 +979,29 @@ public class UserReservationServiceImpl extends ServiceImpl<UserReservationMappe
         return vo;
         return vo;
     }
     }
 
 
+    @Override
+    public int markReservationTimeoutByEndTime() {
+        // 关联查询:订单待使用 + 预约结束时间已过,在库内一次筛出需更新的 reservation_id
+        List<Integer> toUpdateReservationIds = baseMapper.listReservationIdsForTimeoutMark();
+        if (toUpdateReservationIds == null || toUpdateReservationIds.isEmpty()) {
+            return 0;
+        }
+        Date now = new Date();
+        // 1. 更新 user_reservation.status = 未到店超时(4)
+        this.update(new LambdaUpdateWrapper<UserReservation>()
+                .in(UserReservation::getId, toUpdateReservationIds)
+                .set(UserReservation::getStatus, STATUS_NO_SHOW_TIMEOUT)
+                .set(UserReservation::getUpdatedTime, now));
+        // 2. 更新 user_reservation_order.order_status = 已过期(3)
+        userReservationOrderService.update(new LambdaUpdateWrapper<UserReservationOrder>()
+                .in(UserReservationOrder::getReservationId, toUpdateReservationIds)
+                .eq(UserReservationOrder::getOrderStatus, ORDER_STATUS_TO_USE)
+                .set(UserReservationOrder::getOrderStatus, ORDER_STATUS_EXPIRED)
+                .set(UserReservationOrder::getUpdatedTime, now));
+        log.info("预订未到店超时定时任务:更新 reservationIds={} 条为未到店超时/订单已过期", toUpdateReservationIds.size());
+        return toUpdateReservationIds.size();
+    }
+
     /** 将页面 VO 字段复制到详情 VO,供前端订单详情页与 page 接口一致展示 */
     /** 将页面 VO 字段复制到详情 VO,供前端订单详情页与 page 接口一致展示 */
     private void copyPageVoToDetailVo(ReservationOrderPageVo page, ReservationOrderDetailVo detail) {
     private void copyPageVoToDetailVo(ReservationOrderPageVo page, ReservationOrderDetailVo detail) {
         detail.setOrderId(page.getOrderId());
         detail.setOrderId(page.getOrderId());