diff --git a/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/controller/ManagerScheduleController.java b/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/controller/ManagerScheduleController.java index 9f032ee9..9bbaabfc 100644 --- a/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/controller/ManagerScheduleController.java +++ b/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/controller/ManagerScheduleController.java @@ -5,6 +5,7 @@ import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.CreateWorkScheduleRequestDto; import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.ManagerWorkScheduleInquiryRequestDto; import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.ManagerScheduleResponseDto; +import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.ManagerTodayScheduleResponseDto; import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.UpdateWorkScheduleRequestDto; import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.UpdateWorkerRequestDto; import com.dreamteam.alter.application.aop.ManagerActionContext; @@ -48,6 +49,9 @@ public class ManagerScheduleController implements ManagerScheduleControllerSpec @Resource(name = "managerRemoveWorkerFromSchedule") private final ManagerRemoveWorkerUseCase managerRemoveWorker; + @Resource(name = "managerGetTodayWorkScheduleList") + private final ManagerGetDailyScheduleListUseCase managerGetTodayScheduleList; + @Override @PostMapping public ResponseEntity> createSchedule( @@ -68,6 +72,15 @@ public ResponseEntity>> getSc return ResponseEntity.ok(CommonApiResponse.of(managerGetScheduleList.execute(actor, request.getWorkspaceId(), request.getYear(), request.getMonth()))); } + @Override + @GetMapping("/today") + public ResponseEntity>> getTodayScheduleList( + @RequestParam Long workspaceId + ) { + ManagerActor actor = ManagerActionContext.getInstance().getActor(); + return ResponseEntity.ok(CommonApiResponse.of(managerGetTodayScheduleList.execute(actor, workspaceId))); + } + @Override @PutMapping("/{workShiftId}") public ResponseEntity> updateSchedule( diff --git a/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/controller/ManagerScheduleControllerSpec.java b/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/controller/ManagerScheduleControllerSpec.java index 1a32b1a5..ba7dd657 100644 --- a/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/controller/ManagerScheduleControllerSpec.java +++ b/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/controller/ManagerScheduleControllerSpec.java @@ -4,6 +4,7 @@ import com.dreamteam.alter.adapter.inbound.common.dto.ErrorResponse; import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.AssignWorkerRequestDto; import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.CreateWorkScheduleRequestDto; +import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.ManagerTodayScheduleResponseDto; import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.ManagerWorkScheduleInquiryRequestDto; import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.ManagerScheduleResponseDto; import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.UpdateWorkScheduleRequestDto; @@ -51,6 +52,16 @@ ResponseEntity>> getScheduleL ManagerWorkScheduleInquiryRequestDto request ); + @Operation(summary = "금일 스케줄 목록 조회", description = "특정 워크스페이스의 오늘 날짜 스케줄 목록을 조회합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "금일 스케줄 목록 조회 성공"), + @ApiResponse(responseCode = "404", description = "해당 워크스페이스 찾을 수 없음") + }) + ResponseEntity>> getTodayScheduleList( + @Parameter(description = "워크스페이스 ID", example = "1", required = true) + @RequestParam Long workspaceId + ); + @Operation(summary = "스케줄 수정", description = "기존 스케줄의 정보를 수정합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "스케줄 수정 성공"), diff --git a/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/dto/ManagerTodayScheduleResponseDto.java b/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/dto/ManagerTodayScheduleResponseDto.java new file mode 100644 index 00000000..8c1df825 --- /dev/null +++ b/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/dto/ManagerTodayScheduleResponseDto.java @@ -0,0 +1,54 @@ +package com.dreamteam.alter.adapter.inbound.manager.schedule.dto; + +import java.util.List; +import java.util.stream.Collectors; + +import com.dreamteam.alter.domain.workspace.model.WorkspaceShiftTodayResponse; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder(access = AccessLevel.PRIVATE) +@Schema(description = "매니저 금일 근무자 응답") +public class ManagerTodayScheduleResponseDto { + + @Schema(description = "근무자 ID", example = "1") + private Long workerId; + + @Schema(description = "근무자 이름", example = "홍길동") + private String workerName; + + @Schema(description = "근무자 프로필 이미지 S3 URL") + private String profileImageUrl; + + @Schema(description = "금일 근무 목록") + private List shifts; + + public static List from(List responses) { + return responses.stream() + .collect(Collectors.groupingBy(WorkspaceShiftTodayResponse::workerId)) + .values() + .stream() + .map(group -> { + WorkspaceShiftTodayResponse first = group.getFirst(); + return ManagerTodayScheduleResponseDto.builder() + .workerId(first.workerId()) + .workerName(first.workerName()) + .profileImageUrl(first.profileImageUrl()) + .shifts( + group.stream() + .map(r -> ManagerTodayScheduleShiftItem.of(r.shiftId(), r.startDateTime(), r.endDateTime())) + .toList() + ) + .build(); + }) + .toList(); + } +} diff --git a/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/dto/ManagerTodayScheduleShiftItem.java b/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/dto/ManagerTodayScheduleShiftItem.java new file mode 100644 index 00000000..f9b70b42 --- /dev/null +++ b/src/main/java/com/dreamteam/alter/adapter/inbound/manager/schedule/dto/ManagerTodayScheduleShiftItem.java @@ -0,0 +1,35 @@ +package com.dreamteam.alter.adapter.inbound.manager.schedule.dto; + +import java.time.LocalDateTime; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder(access = AccessLevel.PRIVATE) +@Schema(description = "근무 항목") +public class ManagerTodayScheduleShiftItem { + + @Schema(description = "스케줄 ID", example = "1") + private Long shiftId; + + @Schema(description = "근무 시작 시간", example = "2024-01-15T09:00:00") + private LocalDateTime startDateTime; + + @Schema(description = "근무 종료 시간", example = "2024-01-15T18:00:00") + private LocalDateTime endDateTime; + + public static ManagerTodayScheduleShiftItem of(Long shiftId, LocalDateTime startDateTime, LocalDateTime endDateTime) { + return ManagerTodayScheduleShiftItem.builder() + .shiftId(shiftId) + .startDateTime(startDateTime) + .endDateTime(endDateTime) + .build(); + } +} 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 0fd1b84c..3a5f4e6f 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 @@ -1,12 +1,16 @@ package com.dreamteam.alter.adapter.outbound.workspace.persistence; +import com.dreamteam.alter.domain.file.type.FileStatus; +import com.dreamteam.alter.domain.file.type.FileTargetType; import com.dreamteam.alter.domain.workspace.entity.WorkspaceWorker; import com.dreamteam.alter.domain.user.entity.ManagerUser; import com.dreamteam.alter.domain.user.entity.User; import com.dreamteam.alter.domain.workspace.entity.Workspace; import com.dreamteam.alter.domain.workspace.entity.WorkspaceShift; +import com.dreamteam.alter.domain.workspace.model.WorkspaceShiftTodayResponse; import com.dreamteam.alter.domain.workspace.type.WorkspaceShiftStatus; import com.dreamteam.alter.domain.workspace.port.outbound.WorkspaceShiftQueryRepository; +import com.querydsl.core.types.Projections; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -16,7 +20,10 @@ import java.util.List; import java.util.Optional; +import static com.dreamteam.alter.domain.file.entity.QFile.file; +import static com.dreamteam.alter.domain.user.entity.QUser.user; import static com.dreamteam.alter.domain.workspace.entity.QWorkspaceShift.workspaceShift; +import static com.dreamteam.alter.domain.workspace.entity.QWorkspaceWorker.workspaceWorker; @Repository @RequiredArgsConstructor @@ -24,6 +31,37 @@ public class WorkspaceShiftQueryRepositoryImpl implements WorkspaceShiftQueryRep private final JPAQueryFactory queryFactory; + @Override + public List getTodayShiftList( + Long workspaceId + ) { + LocalDateTime startOfDay = LocalDate.now().atStartOfDay(); + LocalDateTime endOfDay = startOfDay.plusDays(1); + return queryFactory + .select(Projections.constructor(WorkspaceShiftTodayResponse.class, + workspaceShift.id, + workspaceWorker.id, + user.name, + file.fileUrl, + workspaceShift.startDateTime, + workspaceShift.endDateTime + )) + .from(workspaceShift) + .leftJoin(workspaceShift.assignedWorkspaceWorker, workspaceWorker) + .leftJoin(workspaceWorker.user, user) + .leftJoin(file).on( + file.targetType.eq(FileTargetType.USER_PROFILE) + .and(file.targetId.eq(user.id.stringValue())) + .and(file.status.eq(FileStatus.ATTACHED)) + ) + .where(workspaceShift.workspace.id.eq(workspaceId) + .and(workspaceShift.startDateTime.goe(startOfDay)) + .and(workspaceShift.startDateTime.lt(endOfDay)) + .and(workspaceShift.status.eq(WorkspaceShiftStatus.CONFIRMED))) + .orderBy(workspaceShift.startDateTime.asc()) + .fetch(); + } + @Override public List findByUserAndDateRange(User user, int year, int month) { return queryFactory diff --git a/src/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetDailyWorkScheduleList.java b/src/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetDailyWorkScheduleList.java new file mode 100644 index 00000000..b414b5cf --- /dev/null +++ b/src/main/java/com/dreamteam/alter/application/workspace/usecase/ManagerGetDailyWorkScheduleList.java @@ -0,0 +1,34 @@ +package com.dreamteam.alter.application.workspace.usecase; + +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.ManagerTodayScheduleResponseDto; +import com.dreamteam.alter.common.exception.CustomException; +import com.dreamteam.alter.common.exception.ErrorCode; +import com.dreamteam.alter.domain.user.context.ManagerActor; +import com.dreamteam.alter.domain.workspace.port.inbound.ManagerGetDailyScheduleListUseCase; +import com.dreamteam.alter.domain.workspace.port.outbound.WorkspaceQueryRepository; +import com.dreamteam.alter.domain.workspace.port.outbound.WorkspaceShiftQueryRepository; + +import lombok.RequiredArgsConstructor; + +@Service("managerGetTodayWorkScheduleList") +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class ManagerGetDailyWorkScheduleList implements ManagerGetDailyScheduleListUseCase { + + private final WorkspaceShiftQueryRepository workspaceShiftQueryRepository; + private final WorkspaceQueryRepository workspaceQueryRepository; + + @Override + public List execute(ManagerActor actor, Long workspaceId) { + if (!workspaceQueryRepository.existsByIdAndManagerUser(workspaceId, actor.getManagerUser())) { + throw new CustomException(ErrorCode.WORKSPACE_NOT_FOUND); + } + + return ManagerTodayScheduleResponseDto.from(workspaceShiftQueryRepository.getTodayShiftList(workspaceId)); + } +} diff --git a/src/main/java/com/dreamteam/alter/domain/workspace/model/WorkspaceShiftTodayResponse.java b/src/main/java/com/dreamteam/alter/domain/workspace/model/WorkspaceShiftTodayResponse.java new file mode 100644 index 00000000..6e6ad046 --- /dev/null +++ b/src/main/java/com/dreamteam/alter/domain/workspace/model/WorkspaceShiftTodayResponse.java @@ -0,0 +1,12 @@ +package com.dreamteam.alter.domain.workspace.model; + +import java.time.LocalDateTime; + +public record WorkspaceShiftTodayResponse( + Long shiftId, + Long workerId, + String workerName, + String profileImageUrl, + LocalDateTime startDateTime, + LocalDateTime endDateTime +) {} diff --git a/src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/ManagerGetDailyScheduleListUseCase.java b/src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/ManagerGetDailyScheduleListUseCase.java new file mode 100644 index 00000000..848718fd --- /dev/null +++ b/src/main/java/com/dreamteam/alter/domain/workspace/port/inbound/ManagerGetDailyScheduleListUseCase.java @@ -0,0 +1,10 @@ +package com.dreamteam.alter.domain.workspace.port.inbound; + +import com.dreamteam.alter.adapter.inbound.manager.schedule.dto.ManagerTodayScheduleResponseDto; +import com.dreamteam.alter.domain.user.context.ManagerActor; + +import java.util.List; + +public interface ManagerGetDailyScheduleListUseCase { + List execute(ManagerActor actor, Long workspaceId); +} 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 3fa43c7b..22d25d0f 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 @@ -5,6 +5,7 @@ import com.dreamteam.alter.domain.user.entity.User; import com.dreamteam.alter.domain.workspace.entity.Workspace; import com.dreamteam.alter.domain.workspace.entity.WorkspaceShift; +import com.dreamteam.alter.domain.workspace.model.WorkspaceShiftTodayResponse; import java.time.LocalDate; import java.time.LocalDateTime; @@ -12,6 +13,8 @@ import java.util.Optional; public interface WorkspaceShiftQueryRepository { + List getTodayShiftList(Long workspaceId); + 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);