|
|
@@ -49,6 +49,8 @@ public class DiningWalkInReservationServiceImpl extends ServiceImpl<UserReservat
|
|
|
/** 未填结束时间时,按 N 小时作为占用窗口做冲突判断(与订金预订「结束时间」空值场景对齐) */
|
|
|
private static final int DEFAULT_BLOCK_HOURS_WHEN_NO_END = 4;
|
|
|
private static final DateTimeFormatter HM = DateTimeFormatter.ofPattern("HH:mm");
|
|
|
+ /** 与订桌/库内既有数据一致:varchar 存 yyyy-MM-dd HH:mm */
|
|
|
+ private static final DateTimeFormatter STORE_DATE_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
|
|
|
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
@@ -67,21 +69,24 @@ public class DiningWalkInReservationServiceImpl extends ServiceImpl<UserReservat
|
|
|
}
|
|
|
|
|
|
LocalDate day = reservationDate.toInstant().atZone(SHANGHAI).toLocalDate();
|
|
|
- LocalTime newStartLt = parseHm(dto.getStartTime());
|
|
|
+ LocalTime newStartLt = parseTimeOfDayOnly(dto.getStartTime());
|
|
|
if (newStartLt == null) {
|
|
|
throw new RuntimeException("开始时间格式不正确,请使用 HH:mm");
|
|
|
}
|
|
|
- LocalTime newEndLt = parseHm(dto.getEndTime());
|
|
|
+ LocalTime newEndLt = parseTimeOfDayOnly(dto.getEndTime());
|
|
|
assertNoTableBookingConflict(table.getId(), table.getStoreId(), day, newStartLt, newEndLt);
|
|
|
|
|
|
+ LocalDateTime startLdt = LocalDateTime.of(day, newStartLt);
|
|
|
+ LocalDateTime endLdt = windowEnd(day, newStartLt, newEndLt);
|
|
|
+
|
|
|
Date now = new Date();
|
|
|
UserReservation entity = new UserReservation();
|
|
|
entity.setReservationNo(generateReservationNo());
|
|
|
entity.setUserId(userId);
|
|
|
entity.setStoreId(table.getStoreId());
|
|
|
entity.setReservationDate(reservationDate);
|
|
|
- entity.setStartTime(trimOrNull(dto.getStartTime()));
|
|
|
- entity.setEndTime(trimOrNull(dto.getEndTime()));
|
|
|
+ entity.setStartTime(startLdt.format(STORE_DATE_TIME));
|
|
|
+ entity.setEndTime(endLdt.format(STORE_DATE_TIME));
|
|
|
entity.setGuestCount(dto.getGuestCount());
|
|
|
entity.setCategoryId(table.getCategoryId());
|
|
|
entity.setStatus(STATUS_ARRIVED);
|
|
|
@@ -168,13 +173,11 @@ public class DiningWalkInReservationServiceImpl extends ServiceImpl<UserReservat
|
|
|
if (otherDay == null || !day.equals(otherDay)) {
|
|
|
continue;
|
|
|
}
|
|
|
- LocalTime oStart = parseHm(other.getStartTime());
|
|
|
- if (oStart == null) {
|
|
|
+ LocalDateTime oStartLdt = parseStoredStartLdt(otherDay, other.getStartTime());
|
|
|
+ if (oStartLdt == null) {
|
|
|
continue;
|
|
|
}
|
|
|
- LocalTime oEnd = parseHm(other.getEndTime());
|
|
|
- LocalDateTime oStartLdt = LocalDateTime.of(otherDay, oStart);
|
|
|
- LocalDateTime oEndLdt = windowEnd(otherDay, oStart, oEnd);
|
|
|
+ LocalDateTime oEndLdt = parseStoredEndLdt(oStartLdt, other.getEndTime());
|
|
|
if (newStartLdt.isBefore(oEndLdt) && oStartLdt.isBefore(newEndLdt)) {
|
|
|
log.warn("到店就餐信息与既有预订冲突 tableId={} day={} new=[{} - {}] otherResId={} other=[{} - {}]",
|
|
|
tableId, day, newStartLdt, newEndLdt, other.getId(), oStartLdt, oEndLdt);
|
|
|
@@ -195,11 +198,15 @@ public class DiningWalkInReservationServiceImpl extends ServiceImpl<UserReservat
|
|
|
return d.toInstant().atZone(SHANGHAI).toLocalDate();
|
|
|
}
|
|
|
|
|
|
- private static LocalTime parseHm(String raw) {
|
|
|
+ /** 仅时分:HH:mm / H:mm */
|
|
|
+ private static LocalTime parseTimeOfDayOnly(String raw) {
|
|
|
if (!StringUtils.hasText(raw)) {
|
|
|
return null;
|
|
|
}
|
|
|
String s = raw.trim();
|
|
|
+ if (s.contains(" ")) {
|
|
|
+ s = s.substring(s.lastIndexOf(' ') + 1).trim();
|
|
|
+ }
|
|
|
try {
|
|
|
return LocalTime.parse(s, HM);
|
|
|
} catch (DateTimeParseException e) {
|
|
|
@@ -211,6 +218,61 @@ public class DiningWalkInReservationServiceImpl extends ServiceImpl<UserReservat
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private static LocalDateTime tryParseFullDateTime(String raw) {
|
|
|
+ if (!StringUtils.hasText(raw) || !raw.trim().contains(" ")) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String s = raw.trim();
|
|
|
+ DateTimeFormatter[] fmps = new DateTimeFormatter[]{
|
|
|
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
|
|
|
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"),
|
|
|
+ DateTimeFormatter.ofPattern("yyyy-MM-dd H:mm:ss"),
|
|
|
+ DateTimeFormatter.ofPattern("yyyy-MM-dd H:mm")
|
|
|
+ };
|
|
|
+ for (DateTimeFormatter f : fmps) {
|
|
|
+ try {
|
|
|
+ return LocalDateTime.parse(s, f);
|
|
|
+ } catch (DateTimeParseException ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static LocalDateTime parseStoredStartLdt(LocalDate reservationDay, String raw) {
|
|
|
+ if (!StringUtils.hasText(raw)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String s = raw.trim();
|
|
|
+ LocalDateTime full = tryParseFullDateTime(s);
|
|
|
+ if (full != null) {
|
|
|
+ return full;
|
|
|
+ }
|
|
|
+ LocalTime t = parseTimeOfDayOnly(s);
|
|
|
+ if (t == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return LocalDateTime.of(reservationDay, t);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static LocalDateTime parseStoredEndLdt(LocalDateTime startLdt, String endRaw) {
|
|
|
+ if (startLdt == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (!StringUtils.hasText(endRaw)) {
|
|
|
+ return windowEnd(startLdt.toLocalDate(), startLdt.toLocalTime(), null);
|
|
|
+ }
|
|
|
+ String s = endRaw.trim();
|
|
|
+ LocalDateTime full = tryParseFullDateTime(s);
|
|
|
+ if (full != null) {
|
|
|
+ return full;
|
|
|
+ }
|
|
|
+ LocalTime endT = parseTimeOfDayOnly(s);
|
|
|
+ if (endT == null) {
|
|
|
+ return windowEnd(startLdt.toLocalDate(), startLdt.toLocalTime(), null);
|
|
|
+ }
|
|
|
+ return windowEnd(startLdt.toLocalDate(), startLdt.toLocalTime(), endT);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 预约结束时刻:结束早于或等于开始(同一张日历日上的钟点)则视为跨日至次日;结束时间为空则用默认时长。
|
|
|
*/
|