Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ ApiResponse<LockerSectionDetailResponse> getSectionLockers(

/** 고른 사물함을 신청하고 즉시 배정한다. */
@Operation(summary = "사물함 신청",
description = "게시된 운영 회차에서 고른 사물함을 신청하고 즉시 배정한다. 운영 회차당 한 개만 신청할 수 있고 "
+ "신청 후에는 취소하거나 변경할 수 없다. 같은 사물함에 동시에 신청하면 먼저 완료된 신청만 성공한다.")
description = "게시된 운영 회차에서 고른 사물함을 신청하고 즉시 배정한다. 모집 기간 안에서만 받는다. "
+ "운영 회차당 한 개만 신청할 수 있고 신청 후에는 취소하거나 변경할 수 없다. "
+ "같은 사물함에 동시에 신청하면 먼저 완료된 신청만 성공한다.")
@ApiErrorCode(type = CommonErrorCode.class, codes = {"INVALID_INPUT"})
@ApiErrorCode(type = LockerErrorCode.class, codes = {"LOCKER_PERIOD_NOT_FOUND", "LOCKER_ALREADY_ASSIGNED"})
@ApiErrorCode(type = LockerErrorCode.class,
codes = {"LOCKER_PERIOD_NOT_FOUND", "LOCKER_APPLY_NOT_OPEN", "LOCKER_ALREADY_ASSIGNED"})
ApiResponse<LockerApplyResponse> apply(AppApiUser apiUser, LockerApplyRequest request);

/** 내 사물함 신청 내역. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public enum LockerErrorCode implements ErrorCode {
LOCKER_PERIOD_ALREADY_ENDED(ErrorStatus.CONFLICT, "종료된 회차는 수정할 수 없습니다."),
LOCKER_PERIOD_APPLY_ALREADY_STARTED(ErrorStatus.CONFLICT, "신청이 시작된 회차는 신청 시작일을 바꿀 수 없습니다."),
LOCKER_PERIOD_HAS_APPLICATIONS(ErrorStatus.CONFLICT, "신청이 있는 회차는 삭제할 수 없습니다."),
LOCKER_APPLY_NOT_OPEN(ErrorStatus.CONFLICT, "사물함 신청 기간이 아닙니다."),
LOCKER_ALREADY_ASSIGNED(ErrorStatus.CONFLICT, "다른 사용자가 먼저 신청한 사물함입니다.");

private final int status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ public LockerPeriodStatus calculateStatus(LocalDateTime now) {
return LockerPeriodStatus.IN_PROGRESS;
}

/**
* 지금이 신청을 받는 기간인지. 신청 시작 일시부터 마감 일시까지 양 끝을 포함한다.
* <p>
* 사용 기간은 보지 않는다. 사용을 시작한 뒤 남은 자리를 추가 모집하려고 마감 일시를 늘리는 운영이 있어
* 두 기간이 겹칠 수 있다.
*/
public boolean isApplyOpen(LocalDateTime now) {
return !now.isBefore(applyStartAt) && !now.isAfter(applyEndAt);
}

/**
* 회차 범위(신청 시작일 ~ 사용 종료일)가 다른 회차와 겹치는지. 회차는 같은 시기에 둘이 돌 수 없다.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class LockerApplicationServiceImpl implements LockerApplicationService {
@Transactional
public LockerApplicationResult apply(Long memberId, LockerApplyCommand command) {
LockerPeriod period = getPublishedPeriod(command.lockerPeriodId());
requireApplyOpen(period);
Locker locker = getSelectableLocker(period.getId(), command.lockerId());

LockerApplication application = lockerApplicationRepository.save(
Expand Down Expand Up @@ -92,6 +93,17 @@ private LockerPeriod getPublishedPeriod(Long lockerPeriodId) {
.orElseThrow(() -> new BusinessException(LockerErrorCode.LOCKER_PERIOD_NOT_FOUND));
}

/**
* 모집 기간 밖에는 신청을 받지 않는다. 게시 여부만 보면 운영진이 게시를 내리기 전까지 마감 뒤에도 신청이 들어오고,
* 사물함은 선착순 즉시 배정이라 그 신청이 남의 자리를 차지한다. 행사 신청({@code EventApplicationServiceImpl})도
* 같은 자리에서 모집 상태를 본다.
*/
private void requireApplyOpen(LockerPeriod period) {
if (!period.isApplyOpen(LocalDateTime.now())) {
throw new BusinessException(LockerErrorCode.LOCKER_APPLY_NOT_OPEN);
}
}

/**
* 해당 운영 회차에 선택할 수 있는 사물함. 구역 조회와 같은 기준({@link Locker#isSelectable})으로 판정한다.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,18 @@ class LockerApplicationServiceImplTest {
private static final Long MEMBER_ID = 100L;
private static final Long LOCKER_ID = 11L;

/** 신청이 모집 기간 안에서만 되므로 기간을 현재 시각 기준으로 잡는다. 고정 날짜로 두면 그 기간이 지난 뒤 테스트가 깨진다. */
private static LockerPeriod period() {
LocalDateTime now = LocalDateTime.now();
return LockerPeriod.of(
PERIOD_ID,
2026,
now.getYear(),
2,
"2026-2학기",
LocalDateTime.of(2026, 8, 20, 10, 0),
LocalDateTime.of(2026, 8, 25, 18, 0),
LocalDate.of(2026, 9, 1),
LocalDate.of(2026, 12, 15),
"%d-2학기".formatted(now.getYear()),
now.minusDays(5),
now.plusDays(5),
now.toLocalDate().plusDays(12),
now.toLocalDate().plusMonths(4),
true
);
}
Expand Down
Loading