Skip to content
Merged
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 @@ -2,6 +2,7 @@

import com.devkor.ifive.nadab.domain.monthlyreport.api.dto.response.MonthlyReportResponse;
import com.devkor.ifive.nadab.domain.monthlyreport.api.dto.response.MonthlyReportStartResponse;
import com.devkor.ifive.nadab.domain.monthlyreport.api.dto.response.MyMonthlyReportResponse;
import com.devkor.ifive.nadab.domain.monthlyreport.application.MonthlyReportQueryService;
import com.devkor.ifive.nadab.domain.monthlyreport.application.MonthlyReportService;
import com.devkor.ifive.nadab.domain.weeklyreport.api.dto.response.CompletedCountResponse;
Expand Down Expand Up @@ -86,13 +87,18 @@ public ResponseEntity<ApiResponseDto<MonthlyReportStartResponse>> startMonthlyRe
@PreAuthorize("isAuthenticated()")
@Operation(
summary = "나의 월간 리포트 조회",
description = "사용자의 (지난 달) 월간 리포트를 조회합니다.",
description = """
사용자의 (지난 달에 대한) 월간 리포트와 이전 월간 리포트를 조회합니다. </br>
이때 ```report```혹은 ```previousReport```가 ```null```인 경우 해당 주간 리포트가 존재하지 않음을 의미합니다. </br>
```report```혹은 ```previousReport```가
```null```이 아닌 경우 ```status```필드는 항상 ```COMPLETED```입니다.
""",
security = @SecurityRequirement(name = "bearerAuth"),
responses = {
@ApiResponse(
responseCode = "200",
description = "나의 월간 리포트 조회 성공",
content = @Content(schema = @Schema(implementation = MonthlyReportResponse.class), mediaType = "application/json")
content = @Content(schema = @Schema(implementation = MyMonthlyReportResponse.class), mediaType = "application/json")
),
@ApiResponse(
responseCode = "401",
Expand All @@ -103,17 +109,15 @@ public ResponseEntity<ApiResponseDto<MonthlyReportStartResponse>> startMonthlyRe
responseCode = "404",
description = """
- ErrorCode: USER_NOT_FOUND - 사용자를 찾을 수 없음
- ErrorCode: MONTHLY_REPORT_NOT_FOUND - 월간 리포트를 찾을 수 없음
- ErrorCode: MONTHLY_REPORT_NOT_COMPLETED - 해당 월간 리포트가 아직 생성 완료되지 않음
""",
content = @Content
)
}
)
public ResponseEntity<ApiResponseDto<MonthlyReportResponse>> getLastMonthMonthlyReport(
public ResponseEntity<ApiResponseDto<MyMonthlyReportResponse>> getMyMonthlyReport(
@AuthenticationPrincipal UserPrincipal principal
) {
MonthlyReportResponse response = monthlyReportQueryService.getLastMonthMonthlyReport(principal.getId());
MyMonthlyReportResponse response = monthlyReportQueryService.getMyMonthlyReport(principal.getId());
return ApiResponseEntity.ok(response);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.devkor.ifive.nadab.domain.monthlyreport.api.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(description = "나의 월간 리포트 조회 응답")
public record MyMonthlyReportResponse(

@Schema(description = "이번 월간 리포트", nullable = true)
MonthlyReportResponse report,

@Schema(description = "이전 월간 리포트", nullable = true)
MonthlyReportResponse previousReport
) {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.devkor.ifive.nadab.domain.monthlyreport.application;

import com.devkor.ifive.nadab.domain.monthlyreport.api.dto.response.MonthlyReportResponse;
import com.devkor.ifive.nadab.domain.monthlyreport.api.dto.response.MyMonthlyReportResponse;
import com.devkor.ifive.nadab.domain.monthlyreport.application.mapper.MonthlyReportMapper;
import com.devkor.ifive.nadab.domain.monthlyreport.core.entity.MonthlyReport;
import com.devkor.ifive.nadab.domain.monthlyreport.core.entity.MonthlyReportStatus;
import com.devkor.ifive.nadab.domain.monthlyreport.core.repository.MonthlyReportRepository;
Expand All @@ -22,25 +24,33 @@ public class MonthlyReportQueryService {
private final MonthlyReportRepository monthlyReportRepository;
private final UserRepository userRepository;

public MonthlyReportResponse getLastMonthMonthlyReport(Long userId) {
public MyMonthlyReportResponse getMyMonthlyReport(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND));

MonthRangeDto range = MonthRangeCalculator.getLastMonthRange();
MonthlyReportResponse reportResponse =
monthlyReportRepository.findByUserIdAndMonthStartDateAndStatus(
user.getId(),
range.monthStartDate(),
MonthlyReportStatus.COMPLETED
)
.map(report -> MonthlyReportMapper.toResponse(range, report))
.orElse(null);

MonthlyReport report = monthlyReportRepository.findByUserIdAndMonthStartDate(user.getId(), range.monthStartDate())
.orElseThrow(() -> new NotFoundException(ErrorCode.MONTHLY_REPORT_NOT_FOUND));

if (report.getStatus() != MonthlyReportStatus.COMPLETED) {
throw new NotFoundException(ErrorCode.MONTHLY_REPORT_NOT_COMPLETED);
}
MonthRangeDto prevRange = MonthRangeCalculator.getTwoMonthsAgoRange();
MonthlyReportResponse prevResponse =
monthlyReportRepository.findByUserIdAndMonthStartDateAndStatus(
user.getId(),
prevRange.monthStartDate(),
MonthlyReportStatus.COMPLETED
)
.map(report -> MonthlyReportMapper.toResponse(prevRange, report))
.orElse(null);

return new MonthlyReportResponse(
range.monthStartDate().getMonthValue(),
report.getDiscovered(),
report.getGood(),
report.getImprove(),
report.getStatus().name()
return new MyMonthlyReportResponse(
reportResponse,
prevResponse
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.devkor.ifive.nadab.domain.monthlyreport.application.mapper;

import com.devkor.ifive.nadab.domain.monthlyreport.api.dto.response.MonthlyReportResponse;
import com.devkor.ifive.nadab.domain.monthlyreport.core.entity.MonthlyReport;
import com.devkor.ifive.nadab.global.shared.util.dto.MonthRangeDto;

public final class MonthlyReportMapper {
private MonthlyReportMapper() {}

public static MonthlyReportResponse toResponse(MonthRangeDto range, MonthlyReport report) {
return new MonthlyReportResponse(
range.monthStartDate().getMonthValue(),
report.getDiscovered(),
report.getGood(),
report.getImprove(),
report.getStatus().name()
);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ public interface MonthlyReportRepository extends JpaRepository<MonthlyReport, Lo

Optional<MonthlyReport> findByUserIdAndMonthStartDate(Long userId, LocalDate monthStartDate);

Optional<MonthlyReport> findByUserIdAndMonthStartDateAndStatus(
Long userId,
LocalDate monthStartDate,
MonthlyReportStatus status
);

/**
* PENDING -> COMPLETED 확정
* - 분석 결과(discovered/good/improve) 저장
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.devkor.ifive.nadab.domain.weeklyreport.api;

import com.devkor.ifive.nadab.domain.weeklyreport.api.dto.response.CompletedCountResponse;
import com.devkor.ifive.nadab.domain.weeklyreport.api.dto.response.MyWeeklyReportResponse;
import com.devkor.ifive.nadab.domain.weeklyreport.api.dto.response.WeeklyReportResponse;
import com.devkor.ifive.nadab.domain.weeklyreport.api.dto.response.WeeklyReportStartResponse;
import com.devkor.ifive.nadab.domain.weeklyreport.application.WeeklyReportQueryService;
Expand Down Expand Up @@ -86,13 +87,18 @@ public ResponseEntity<ApiResponseDto<WeeklyReportStartResponse>> startWeeklyRepo
@PreAuthorize("isAuthenticated()")
@Operation(
summary = "나의 주간 리포트 조회",
description = "사용자의 (지난 주) 주간 리포트를 조회합니다.",
description = """
사용자의 (지난 주에 대한) 주간 리포트와 이전 주간 리포트를 조회합니다. </br>
이때 ```report```혹은 ```previousReport```가 ```null```인 경우 해당 주간 리포트가 존재하지 않음을 의미합니다. </br>
```report```혹은 ```previousReport```가
```null```이 아닌 경우 ```status```필드는 항상 ```COMPLETED```입니다.
""",
security = @SecurityRequirement(name = "bearerAuth"),
responses = {
@ApiResponse(
responseCode = "200",
description = "나의 주간 리포트 조회 성공",
content = @Content(schema = @Schema(implementation = WeeklyReportResponse.class), mediaType = "application/json")
content = @Content(schema = @Schema(implementation = MyWeeklyReportResponse.class), mediaType = "application/json")
),
@ApiResponse(
responseCode = "401",
Expand All @@ -103,17 +109,15 @@ public ResponseEntity<ApiResponseDto<WeeklyReportStartResponse>> startWeeklyRepo
responseCode = "404",
description = """
- ErrorCode: USER_NOT_FOUND - 사용자를 찾을 수 없음
- ErrorCode: WEEKLY_REPORT_NOT_FOUND - 주간 리포트를 찾을 수 없음
- ErrorCode: WEEKLY_REPORT_NOT_COMPLETED - 해당 주간 리포트가 아직 생성 완료되지 않음
""",
content = @Content
)
}
)
public ResponseEntity<ApiResponseDto<WeeklyReportResponse>> getLastWeekWeeklyReport(
public ResponseEntity<ApiResponseDto<MyWeeklyReportResponse>> getMyWeeklyReport(
@AuthenticationPrincipal UserPrincipal principal
) {
WeeklyReportResponse response = weeklyReportQueryService.getLastWeekWeeklyReport(principal.getId());
MyWeeklyReportResponse response = weeklyReportQueryService.getMyWeeklyReport(principal.getId());
return ApiResponseEntity.ok(response);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.devkor.ifive.nadab.domain.weeklyreport.api.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(description = "나의 주간 리포트 조회 응답")
public record MyWeeklyReportResponse(

@Schema(description = "이번 주간 리포트", nullable = true)
WeeklyReportResponse report,

@Schema(description = "이전 주간 리포트", nullable = true)
WeeklyReportResponse previousReport
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.devkor.ifive.nadab.domain.user.core.entity.User;
import com.devkor.ifive.nadab.domain.user.core.repository.UserRepository;
import com.devkor.ifive.nadab.domain.weeklyreport.api.dto.response.MyWeeklyReportResponse;
import com.devkor.ifive.nadab.domain.weeklyreport.api.dto.response.WeeklyReportResponse;
import com.devkor.ifive.nadab.domain.weeklyreport.application.mapper.WeeklyReportMapper;
import com.devkor.ifive.nadab.domain.weeklyreport.core.entity.WeeklyReport;
import com.devkor.ifive.nadab.domain.weeklyreport.core.entity.WeeklyReportStatus;
import com.devkor.ifive.nadab.domain.weeklyreport.core.repository.WeeklyReportRepository;
Expand All @@ -22,27 +24,32 @@ public class WeeklyReportQueryService {
private final WeeklyReportRepository weeklyReportRepository;
private final UserRepository userRepository;

public WeeklyReportResponse getLastWeekWeeklyReport(Long userId) {
public MyWeeklyReportResponse getMyWeeklyReport(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND));

WeekRangeDto range = WeekRangeCalculator.getLastWeekRange();
WeeklyReportResponse reportResponse =
weeklyReportRepository.findByUserIdAndWeekStartDateAndStatus(
user.getId(),
range.weekStartDate(),
WeeklyReportStatus.COMPLETED
).
map(report -> WeeklyReportMapper.toResponse(range, report))
.orElse(null);

WeeklyReport report = weeklyReportRepository.findByUserAndWeekStartDate(user, range.weekStartDate())
.orElseThrow(() -> new NotFoundException(ErrorCode.WEEKLY_REPORT_NOT_FOUND));

if (report.getStatus() != WeeklyReportStatus.COMPLETED) {
throw new NotFoundException(ErrorCode.WEEKLY_REPORT_NOT_COMPLETED);
}
WeekRangeDto prevRange = WeekRangeCalculator.getTwoWeeksAgoRange();
WeeklyReportResponse prevReportResponse =
weeklyReportRepository.findByUserIdAndWeekStartDateAndStatus(
user.getId(),
prevRange.weekStartDate(),
WeeklyReportStatus.COMPLETED
)
.map(report -> WeeklyReportMapper.toResponse(prevRange, report))
.orElse(null);

return new WeeklyReportResponse(
range.weekStartDate().getMonthValue(),
WeekRangeCalculator.getWeekOfMonth(range),
report.getDiscovered(),
report.getGood(),
report.getImprove(),
report.getStatus().name()
);
return new MyWeeklyReportResponse(reportResponse, prevReportResponse);
}

public WeeklyReportResponse getWeeklyReportById(Long id) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.devkor.ifive.nadab.domain.weeklyreport.application.mapper;

import com.devkor.ifive.nadab.domain.weeklyreport.api.dto.response.WeeklyReportResponse;
import com.devkor.ifive.nadab.domain.weeklyreport.core.entity.WeeklyReport;
import com.devkor.ifive.nadab.global.shared.util.WeekRangeCalculator;
import com.devkor.ifive.nadab.global.shared.util.dto.WeekRangeDto;

public final class WeeklyReportMapper {
private WeeklyReportMapper() {}

public static WeeklyReportResponse toResponse(WeekRangeDto range, WeeklyReport report) {
return new WeeklyReportResponse(
range.weekStartDate().getMonthValue(),
WeekRangeCalculator.getWeekOfMonth(range),
report.getDiscovered(),
report.getGood(),
report.getImprove(),
report.getStatus().name()
);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ public interface WeeklyReportRepository extends JpaRepository<WeeklyReport, Long
*/
Optional<WeeklyReport> findByUserAndWeekStartDate(User user, LocalDate weekStartDate);

Optional<WeeklyReport> findByUserIdAndWeekStartDateAndStatus(
Long userId,
LocalDate weekStartDate,
WeeklyReportStatus status
);

/**
* PENDING -> COMPLETED 확정
* - 분석 결과(discovered/good/improve) 저장
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ public static MonthRangeDto getLastMonthRange() {
return monthRangeOf(lastMonthDate);
}

/**
* KST 기준 "2달 전" 범위를 반환합니다.
*/
public static MonthRangeDto getTwoMonthsAgoRange() {
LocalDate today = LocalDate.now(KST);
LocalDate lastMonthDate = today.minusMonths(2);
return monthRangeOf(lastMonthDate);
}

/**
* KST 기준 "이번 달" 범위를 반환합니다.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ public static WeekRangeDto getLastWeekRange() {
return weekRangeOf(lastWeekDate);
}

/**
* 월요일 시작 ~ 일요일 종료 기준의 "2주 전" 범위를 반환합니다.
*/
public static WeekRangeDto getTwoWeeksAgoRange() {
LocalDate today = LocalDate.now(KST);
LocalDate twoWeeksAgoDate = today.minusWeeks(2);
return weekRangeOf(twoWeeksAgoDate);
}

/**
* 주어진 WeekRange가 해당 월의 몇 주차인지 반환합니다.
* (월요일 시작 기준, 해당 주의 월요일이 속한 달 기준)
Expand Down