新增功能:团课签到前验证是否到店签到
This commit was merged in pull request #33.
This commit is contained in:
@@ -648,7 +648,9 @@
|
|||||||
| 4 | 当前时间早于开课前2小时 | `未到签到时间,请在开课前2小时内签到` |
|
| 4 | 当前时间早于开课前2小时 | `未到签到时间,请在开课前2小时内签到` |
|
||||||
| 5 | 当前时间晚于团课结束时间 | `团课已结束,无法签到` |
|
| 5 | 当前时间晚于团课结束时间 | `团课已结束,无法签到` |
|
||||||
| 6 | 课程当前人数已达上限 | `课程已满员,无法签到` |
|
| 6 | 课程当前人数已达上限 | `课程已满员,无法签到` |
|
||||||
| 7 | 用户未预约此课程 | `您未预约此课程,无法签到` |
|
| 7 | 用户今日无到店签到记录 | `请先完成到店签到` |
|
||||||
|
| 8 | 到店签到状态非SUCCESS | `到店签到未成功,请重新签到` |
|
||||||
|
| 9 | 用户未预约此课程 | `您未预约此课程,无法签到` |
|
||||||
| - | 请求体为空 | `请求体不能为空` |
|
| - | 请求体为空 | `请求体不能为空` |
|
||||||
| - | 请求体缺少courseId | `courseId不能为空` |
|
| - | 请求体缺少courseId | `courseId不能为空` |
|
||||||
|
|
||||||
@@ -1664,6 +1666,7 @@
|
|||||||
- 团课状态不为"已结束"(含已过结束时间)
|
- 团课状态不为"已结束"(含已过结束时间)
|
||||||
- 当前时间在开课前2小时内(签到时间窗口)
|
- 当前时间在开课前2小时内(签到时间窗口)
|
||||||
- 课程当前人数未达到最大人数上限
|
- 课程当前人数未达到最大人数上限
|
||||||
|
- 用户今日已成功到店签到(查询 sign_in_record 表当日 SUCCESS 记录)
|
||||||
- 用户已预约该课程(有效预约)
|
- 用户已预约该课程(有效预约)
|
||||||
4. **删除团课**:采用软删除机制,数据保留可恢复
|
4. **删除团课**:采用软删除机制,数据保留可恢复
|
||||||
|
|
||||||
|
|||||||
+21
-4
@@ -28,6 +28,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.r2dbc.core.DatabaseClient;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
@@ -49,6 +50,7 @@ public class GroupCourseService implements IGroupCourseService {
|
|||||||
private final RedisUtil redisUtil;
|
private final RedisUtil redisUtil;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
private final GroupCourseStateMachine stateMachine;
|
private final GroupCourseStateMachine stateMachine;
|
||||||
|
private final DatabaseClient databaseClient;
|
||||||
|
|
||||||
private static final String CACHE_KEY_PREFIX = "group_course:page:";
|
private static final String CACHE_KEY_PREFIX = "group_course:page:";
|
||||||
private static final String CACHE_KEY_ID_PREFIX = "group_course:id:";
|
private static final String CACHE_KEY_ID_PREFIX = "group_course:id:";
|
||||||
@@ -65,7 +67,8 @@ public class GroupCourseService implements IGroupCourseService {
|
|||||||
MemberCardRepository memberCardRepository,
|
MemberCardRepository memberCardRepository,
|
||||||
RedisUtil redisUtil,
|
RedisUtil redisUtil,
|
||||||
ObjectMapper objectMapper,
|
ObjectMapper objectMapper,
|
||||||
GroupCourseStateMachine stateMachine){
|
GroupCourseStateMachine stateMachine,
|
||||||
|
DatabaseClient databaseClient){
|
||||||
this.groupCourseRepository = groupCourseRepository;
|
this.groupCourseRepository = groupCourseRepository;
|
||||||
this.bookingRepository = bookingRepository;
|
this.bookingRepository = bookingRepository;
|
||||||
this.groupCourseTypeRepository = groupCourseTypeRepository;
|
this.groupCourseTypeRepository = groupCourseTypeRepository;
|
||||||
@@ -75,6 +78,7 @@ public class GroupCourseService implements IGroupCourseService {
|
|||||||
this.redisUtil = redisUtil;
|
this.redisUtil = redisUtil;
|
||||||
this.objectMapper = objectMapper;
|
this.objectMapper = objectMapper;
|
||||||
this.stateMachine = stateMachine;
|
this.stateMachine = stateMachine;
|
||||||
|
this.databaseClient = databaseClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -506,18 +510,31 @@ public class GroupCourseService implements IGroupCourseService {
|
|||||||
return Mono.error(new RuntimeException("课程已满员,无法签到"));
|
return Mono.error(new RuntimeException("课程已满员,无法签到"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验5:用户已预约此课程(有效预约,状态为0-已预约)
|
// 校验5:用户今日是否已到店签到(直接查询sign_in_record表)
|
||||||
|
LocalDateTime todayStart = LocalDateTime.now().toLocalDate().atStartOfDay();
|
||||||
|
LocalDateTime todayEnd = todayStart.plusDays(1);
|
||||||
|
return databaseClient.sql("SELECT sign_in_status FROM sign_in_record WHERE member_id = :memberId AND sign_in_time >= :startTime AND sign_in_time < :endTime AND is_delete = false ORDER BY sign_in_time DESC LIMIT 1")
|
||||||
|
.bind("memberId", memberId)
|
||||||
|
.bind("startTime", todayStart)
|
||||||
|
.bind("endTime", todayEnd)
|
||||||
|
.map(row -> row.get("sign_in_status", String.class))
|
||||||
|
.one()
|
||||||
|
.switchIfEmpty(Mono.error(new RuntimeException("请先完成到店签到")))
|
||||||
|
.flatMap(status -> {
|
||||||
|
if (!"SUCCESS".equals(status)) {
|
||||||
|
return Mono.error(new RuntimeException("到店签到未成功,请重新签到"));
|
||||||
|
}
|
||||||
|
// 校验6:用户已预约此课程(有效预约,状态为0-已预约)
|
||||||
return bookingRepository.findValidBooking(courseId, memberId)
|
return bookingRepository.findValidBooking(courseId, memberId)
|
||||||
.switchIfEmpty(Mono.error(new RuntimeException("您未预约此课程,无法签到")))
|
.switchIfEmpty(Mono.error(new RuntimeException("您未预约此课程,无法签到")))
|
||||||
.flatMap(booking -> {
|
.flatMap(booking -> {
|
||||||
// 更新课程当前人数
|
|
||||||
return groupCourseRepository.updateCurrentMembers(courseId, 1)
|
return groupCourseRepository.updateCurrentMembers(courseId, 1)
|
||||||
.flatMap(updatedCourse -> {
|
.flatMap(updatedCourse -> {
|
||||||
// 更新预约状态为已出席
|
|
||||||
return bookingRepository.updateStatus(booking.getId(), "2")
|
return bookingRepository.updateStatus(booking.getId(), "2")
|
||||||
.thenReturn(updatedCourse);
|
.thenReturn(updatedCourse);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.doOnSuccess(course -> logger.info("团课签到成功 - courseId={}, memberId={}", courseId, memberId))
|
.doOnSuccess(course -> logger.info("团课签到成功 - courseId={}, memberId={}", courseId, memberId))
|
||||||
.flatMap(course -> clearCache().thenReturn(course))
|
.flatMap(course -> clearCache().thenReturn(course))
|
||||||
|
|||||||
Reference in New Issue
Block a user