diff --git a/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/controller/UserScheduleController.java b/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/controller/UserScheduleController.java index e98c9561..43135341 100644 --- a/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/controller/UserScheduleController.java +++ b/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/controller/UserScheduleController.java @@ -1,13 +1,10 @@ package com.dreamteam.alter.adapter.inbound.general.schedule.controller; import com.dreamteam.alter.adapter.inbound.common.dto.CommonApiResponse; -import com.dreamteam.alter.adapter.inbound.general.schedule.dto.MyScheduleResponseDto; -import com.dreamteam.alter.adapter.inbound.general.schedule.dto.WorkScheduleInquiryRequestDto; -import com.dreamteam.alter.adapter.inbound.general.schedule.dto.WorkspaceScheduleResponseDto; +import com.dreamteam.alter.adapter.inbound.general.schedule.dto.*; import com.dreamteam.alter.application.aop.AppActionContext; import com.dreamteam.alter.domain.user.context.AppActor; -import com.dreamteam.alter.domain.workspace.port.inbound.GetMyScheduleUseCase; -import com.dreamteam.alter.domain.workspace.port.inbound.GetWorkspaceScheduleUseCase; +import com.dreamteam.alter.domain.workspace.port.inbound.*; import jakarta.annotation.Resource; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -24,7 +21,7 @@ @RequestMapping("/app/schedules") public class UserScheduleController implements UserScheduleControllerSpec { - @Resource(name = "getMyWorkSchedule") + @Resource(name = "getMySchedule") private final GetMyScheduleUseCase getMySchedule; @Resource(name = "getWorkspaceWorkSchedule") @@ -32,7 +29,7 @@ public class UserScheduleController implements UserScheduleControllerSpec { @Override @GetMapping("/self") - public ResponseEntity>> getMySchedule( + public ResponseEntity> getMySchedule( WorkScheduleInquiryRequestDto request ) { AppActor actor = AppActionContext.getInstance().getActor(); diff --git a/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/controller/UserScheduleControllerSpec.java b/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/controller/UserScheduleControllerSpec.java index acca29d9..8f425267 100644 --- a/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/controller/UserScheduleControllerSpec.java +++ b/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/controller/UserScheduleControllerSpec.java @@ -2,9 +2,7 @@ import com.dreamteam.alter.adapter.inbound.common.dto.CommonApiResponse; import com.dreamteam.alter.adapter.inbound.common.dto.ErrorResponse; -import com.dreamteam.alter.adapter.inbound.general.schedule.dto.MyScheduleResponseDto; -import com.dreamteam.alter.adapter.inbound.general.schedule.dto.WorkScheduleInquiryRequestDto; -import com.dreamteam.alter.adapter.inbound.general.schedule.dto.WorkspaceScheduleResponseDto; +import com.dreamteam.alter.adapter.inbound.general.schedule.dto.*; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -21,11 +19,14 @@ @Tag(name = "APP - 근무 스케줄 관리 API") public interface UserScheduleControllerSpec { - @Operation(summary = "나의 근무 스케줄 조회", description = "특정 월의 스케줄을 조회하려면 year, month 값을 모두 포함해야합니다.") + @Operation(summary = "나의 근무 스케줄 조회", description = "파라미터 조합에 따라 조회가 달라집니다.
"+ + "- 인자 없음: 이번 주 스케줄 조회
" + + "- year, month: 해당 월 스케줄 조회
" + + "- year, month, day: 해당 일 스케줄 조회") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "스케줄 조회 성공") }) - ResponseEntity>> getMySchedule( + ResponseEntity> getMySchedule( WorkScheduleInquiryRequestDto request ); diff --git a/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/dto/GetMyScheduleResponseDto.java b/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/dto/GetMyScheduleResponseDto.java new file mode 100644 index 00000000..58270684 --- /dev/null +++ b/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/dto/GetMyScheduleResponseDto.java @@ -0,0 +1,27 @@ +package com.dreamteam.alter.adapter.inbound.general.schedule.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.util.List; + +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder(access = AccessLevel.PRIVATE) +@Schema(description = "스케줄 조회 통합 응답") +public class GetMyScheduleResponseDto { + + @Schema(description = "총 근무 시간", example = "40.5") + private double totalWorkHours; + + @Schema(description = "스케줄 목록") + private List schedules; + + public static GetMyScheduleResponseDto of(double totalWorkHours, List schedules) { + return GetMyScheduleResponseDto.builder() + .totalWorkHours(totalWorkHours) + .schedules(schedules) + .build(); + } +} diff --git a/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/dto/WorkScheduleInquiryRequestDto.java b/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/dto/WorkScheduleInquiryRequestDto.java index 91903d19..5c33239a 100644 --- a/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/dto/WorkScheduleInquiryRequestDto.java +++ b/src/main/java/com/dreamteam/alter/adapter/inbound/general/schedule/dto/WorkScheduleInquiryRequestDto.java @@ -17,4 +17,7 @@ public class WorkScheduleInquiryRequestDto { @Parameter(description = "조회할 월") private Integer month; + + @Parameter(description = "조회할 일 (일별 조회 시 사용)") + private Integer day; } diff --git a/src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceShiftQueryRepositoryImpl.java b/src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceShiftQueryRepositoryImpl.java index 906c1832..4680d0b8 100644 --- a/src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceShiftQueryRepositoryImpl.java +++ b/src/main/java/com/dreamteam/alter/adapter/outbound/workspace/persistence/WorkspaceShiftQueryRepositoryImpl.java @@ -48,6 +48,21 @@ public List findByUserAndWeeklyRange(User user, LocalDate startD .fetch(); } + @Override + public List findByUserAndDate(User user, int year, int month, int day) { + LocalDateTime startOfDay = LocalDateTime.of(year, month, day, 0, 0, 0); + LocalDateTime endOfDay = startOfDay.plusDays(1); + return queryFactory + .selectFrom(workspaceShift) + .where( + workspaceShift.assignedWorkspaceWorker.user.eq(user), + workspaceShift.startDateTime.goe(startOfDay), + workspaceShift.startDateTime.lt(endOfDay) + ) + .orderBy(workspaceShift.startDateTime.asc()) + .fetch(); + } + @Override public List findByWorkspaceAndDateRange(Workspace workspace, int year, int month) { return queryFactory diff --git a/src/main/java/com/dreamteam/alter/application/workspace/usecase/GetMySchedule.java b/src/main/java/com/dreamteam/alter/application/workspace/usecase/GetMySchedule.java new file mode 100644 index 00000000..f0e1b2f7 --- /dev/null +++ b/src/main/java/com/dreamteam/alter/application/workspace/usecase/GetMySchedule.java @@ -0,0 +1,81 @@ +package com.dreamteam.alter.application.workspace.usecase; + +import com.dreamteam.alter.adapter.inbound.general.schedule.dto.GetMyScheduleResponseDto; +import com.dreamteam.alter.adapter.inbound.general.schedule.dto.MyScheduleResponseDto; +import com.dreamteam.alter.adapter.inbound.general.schedule.dto.WorkScheduleInquiryRequestDto; +import com.dreamteam.alter.common.exception.CustomException; +import com.dreamteam.alter.common.exception.ErrorCode; +import com.dreamteam.alter.domain.user.context.AppActor; +import com.dreamteam.alter.domain.workspace.entity.WorkspaceShift; +import com.dreamteam.alter.domain.workspace.port.inbound.GetMyScheduleUseCase; +import com.dreamteam.alter.domain.workspace.port.outbound.WorkspaceShiftQueryRepository; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.DayOfWeek; +import java.time.Duration; +import java.time.LocalDate; +import java.time.temporal.TemporalAdjusters; +import java.util.List; + +@Service("getMySchedule") +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class GetMySchedule implements GetMyScheduleUseCase { + + private final WorkspaceShiftQueryRepository workspaceShiftQueryRepository; + + @Override + public GetMyScheduleResponseDto execute(AppActor actor, WorkScheduleInquiryRequestDto request) { + + List shifts; + + if (ObjectUtils.isNotEmpty(request.getYear()) && ObjectUtils.isNotEmpty(request.getMonth()) && ObjectUtils.isNotEmpty(request.getDay())) { + // 1. 년/월/일 포함 -> 일별 조회 + shifts = workspaceShiftQueryRepository.findByUserAndDate( + actor.getUser(), + request.getYear(), + request.getMonth(), + request.getDay() + ); + + } else if (ObjectUtils.isNotEmpty(request.getYear()) && ObjectUtils.isNotEmpty(request.getMonth())) { + // 2. 년/월 포함 -> 월별 조회 + shifts = workspaceShiftQueryRepository.findByUserAndDateRange( + actor.getUser(), + request.getYear(), + request.getMonth() + ); + + } else if (ObjectUtils.isEmpty(request.getYear()) && ObjectUtils.isEmpty(request.getMonth()) && ObjectUtils.isEmpty(request.getDay())) { + // 3. 인자 없음 -> 이번 주 스케줄 조회 (월~일) + LocalDate now = LocalDate.now(); + LocalDate startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); + LocalDate endOfWeek = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)); + + shifts = workspaceShiftQueryRepository.findByUserAndWeeklyRange( + actor.getUser(), + startOfWeek, + endOfWeek + ); + + } else { + throw new CustomException(ErrorCode.ILLEGAL_ARGUMENT, "연단위 요청은 불가능합니다."); + } + + double totalWorkHours = shifts.stream() + .mapToDouble(shift -> { + Duration duration = Duration.between(shift.getStartDateTime(), shift.getEndDateTime()); + return duration.toMinutes() / 60.0; + }) + .sum(); + + List scheduleDtos = shifts.stream() + .map(MyScheduleResponseDto::of) + .toList(); + + return GetMyScheduleResponseDto.of(totalWorkHours, scheduleDtos); + } +} diff --git a/src/main/java/com/dreamteam/alter/application/workspace/usecase/GetMyWorkSchedule.java b/src/main/java/com/dreamteam/alter/application/workspace/usecase/GetMyWorkSchedule.java deleted file mode 100644 index a4573f0c..00000000 --- a/src/main/java/com/dreamteam/alter/application/workspace/usecase/GetMyWorkSchedule.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.dreamteam.alter.application.workspace.usecase; - -import com.dreamteam.alter.adapter.inbound.general.schedule.dto.MyScheduleResponseDto; -import com.dreamteam.alter.adapter.inbound.general.schedule.dto.WorkScheduleInquiryRequestDto; -import com.dreamteam.alter.domain.user.context.AppActor; -import com.dreamteam.alter.domain.workspace.entity.WorkspaceShift; -import com.dreamteam.alter.domain.workspace.port.inbound.GetMyScheduleUseCase; -import com.dreamteam.alter.domain.workspace.port.outbound.WorkspaceShiftQueryRepository; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.ObjectUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.time.LocalDate; -import java.util.List; - -@Service("getMyWorkSchedule") -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class GetMyWorkSchedule implements GetMyScheduleUseCase { - - private final WorkspaceShiftQueryRepository workspaceShiftQueryRepository; - - @Override - public List execute(AppActor actor, WorkScheduleInquiryRequestDto request) { - List shifts; - - if (ObjectUtils.isEmpty(request.getYear()) || ObjectUtils.isEmpty(request.getMonth())) { - // 날짜 정보가 null인 경우: 일주일 범위 조회 - LocalDate startOfWeek = LocalDate.now(); - LocalDate endOfWeek = startOfWeek.plusDays(7); - - shifts = workspaceShiftQueryRepository.findByUserAndWeeklyRange(actor.getUser(), startOfWeek, endOfWeek); - } else { - // 날짜 정보가 제공된 경우: 해당 월의 일정 조회 - shifts = workspaceShiftQueryRepository.findByUserAndDateRange(actor.getUser(), request.getYear(), request.getMonth()); - } - - return shifts.stream() - .map(MyScheduleResponseDto::of) - .toList(); - } -} diff --git a/src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetMyScheduleUseCase.java b/src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetMyScheduleUseCase.java index 5ed1b809..e92f0a8f 100644 --- a/src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetMyScheduleUseCase.java +++ b/src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/GetMyScheduleUseCase.java @@ -1,11 +1,9 @@ package com.dreamteam.alter.domain.workspace.port.inbound; -import com.dreamteam.alter.adapter.inbound.general.schedule.dto.MyScheduleResponseDto; +import com.dreamteam.alter.adapter.inbound.general.schedule.dto.GetMyScheduleResponseDto; import com.dreamteam.alter.adapter.inbound.general.schedule.dto.WorkScheduleInquiryRequestDto; import com.dreamteam.alter.domain.user.context.AppActor; -import java.util.List; - public interface GetMyScheduleUseCase { - List execute(AppActor actor, WorkScheduleInquiryRequestDto request); + GetMyScheduleResponseDto execute(AppActor actor, WorkScheduleInquiryRequestDto request); } diff --git a/src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceShiftQueryRepository.java b/src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceShiftQueryRepository.java index 94ac6bd3..18180183 100644 --- a/src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceShiftQueryRepository.java +++ b/src/main/java/com/dreamteam/alter/domain/workspace/port/outbound/WorkspaceShiftQueryRepository.java @@ -14,6 +14,7 @@ public interface WorkspaceShiftQueryRepository { List findByUserAndDateRange(User user, int year, int month); List findByUserAndWeeklyRange(User user, LocalDate startDate, LocalDate endDate); + List findByUserAndDate(User user, int year, int month, int day); List findByWorkspaceAndDateRange(Workspace workspace, int year, int month); List findByManagerAndDateRange(ManagerUser managerUser, Long workspaceId, int year, int month); Optional findById(Long id);