Skip to content

Commit

Permalink
Merge pull request #46 from Team-Haruchi/feat/5-monthbudget#4
Browse files Browse the repository at this point in the history
[FEAT] 한 주 예산 금액 조회 API 구현
  • Loading branch information
ohu-star authored Aug 4, 2024
2 parents bb1a4e1 + 954306b commit 7da8286
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 7 deletions.
30 changes: 30 additions & 0 deletions src/main/java/umc/haruchi/converter/MonthBudgetConverter.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package umc.haruchi.converter;

import umc.haruchi.domain.DayBudget;
import umc.haruchi.domain.MonthBudget;
import umc.haruchi.web.dto.MonthBudgetRequestDTO;
import umc.haruchi.web.dto.MonthBudgetResponseDTO;

import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;

public class MonthBudgetConverter {
public static MonthBudgetResponseDTO.CreateMonthResultDTO toCreateMonthResultDTO(MonthBudget monthBudget) {
Expand All @@ -26,6 +29,14 @@ public static MonthBudget toMonthBudget(Long monthBudget) {
.build();
}

public static MonthBudget toMonthBudgetWithMonth(Long monthBudget, Integer year, Integer month) {
return MonthBudget.builder()
.monthBudget(monthBudget)
.year(year)
.month(month)
.build();
}

public static MonthBudgetResponseDTO.GetMonthResultDTO toGetMonthResultDTO(MonthBudget monthBudget) {
return MonthBudgetResponseDTO.GetMonthResultDTO.builder()
.monthBudget(monthBudget.getMonthBudget())
Expand All @@ -39,4 +50,23 @@ public static MonthBudgetResponseDTO.GetMonthUsedPercentResultDTO toGetMonthUsed
.monthUsedPercent(percent)
.build();
}

public static MonthBudgetResponseDTO.GetWeekBudgetResultDTO toGetWeekBudgetResultDTO(DayBudget dayBudget) {
return MonthBudgetResponseDTO.GetWeekBudgetResultDTO.builder()
.day(dayBudget.getDay())
.dayBudget(dayBudget.getDayBudget())
.status(dayBudget.getDayBudgetStatus())
.build();
}

public static MonthBudgetResponseDTO.GetWeekBudgetResultListDTO toGetWeekBudgetResultListDTO(List<DayBudget> budgets, Integer month, Integer week) {
List<MonthBudgetResponseDTO.GetWeekBudgetResultDTO> weekBudgetDTOList = budgets.stream()
.map(MonthBudgetConverter::toGetWeekBudgetResultDTO).collect(Collectors.toList());

return MonthBudgetResponseDTO.GetWeekBudgetResultListDTO.builder()
.month(month)
.week(week)
.weekBudget(weekBudgetDTOList)
.build();
}
}
9 changes: 4 additions & 5 deletions src/main/java/umc/haruchi/domain/MonthBudget.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class MonthBudget extends BaseEntity {
@Builder.Default
private List<DayBudget> dayBudgetList = new ArrayList<>();

@PrePersist
//@PrePersist
public void prePersist() {
LocalDate now = LocalDate.now();
this.year = now.getYear();
Expand All @@ -57,10 +57,9 @@ public void setMember(Member member) {
member.getMonthBudgetList().add(this);
}

public void updateMonthBudget(Long monthBudget) {
LocalDate now = LocalDate.now();
this.year = now.getYear();
this.month = now.getMonthValue();
public void updateMonthBudget(Long monthBudget, Integer year, Integer month) {
this.year = year;
this.month = month;
this.monthBudget = monthBudget;
}

Expand Down
4 changes: 3 additions & 1 deletion src/main/java/umc/haruchi/service/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import umc.haruchi.web.dto.MemberRequestDTO;
import umc.haruchi.web.dto.MemberResponseDTO;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
Expand All @@ -51,12 +52,13 @@ public class MemberService {
// 회원가입
@Transactional
public Member joinMember(MemberRequestDTO.MemberJoinDTO request) throws Exception {
LocalDate today = LocalDate.now();

Member newMember = MemberConverter.toMember(request);
newMember.encodePassword(passwordEncoder.encode(request.getPassword()));

//회원가입 시 monthBudget 생성
MonthBudget monthBudget = MonthBudgetConverter.toMonthBudget(request.getMonthBudget());
MonthBudget monthBudget = MonthBudgetConverter.toMonthBudgetWithMonth(request.getMonthBudget(), today.getYear(), today.getMonthValue());
monthBudget.setMember(newMember);
monthBudgetRepository.save(monthBudget);

Expand Down
156 changes: 155 additions & 1 deletion src/main/java/umc/haruchi/service/MonthBudgetService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import umc.haruchi.apiPayload.exception.handler.DayBudgetHandler;
import umc.haruchi.apiPayload.exception.handler.MonthBudgetHandler;
import umc.haruchi.converter.DayBudgetConverter;
import umc.haruchi.converter.MonthBudgetConverter;
import umc.haruchi.domain.DayBudget;
import umc.haruchi.domain.Member;
import umc.haruchi.domain.MonthBudget;
Expand All @@ -19,12 +20,16 @@
import umc.haruchi.web.dto.MonthBudgetRequestDTO;
import umc.haruchi.web.dto.MonthBudgetResponseDTO;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Optional;

import static umc.haruchi.apiPayload.code.status.ErrorStatus.NOT_SOME_DAY_BUDGET;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
Expand All @@ -33,6 +38,21 @@ public class MonthBudgetService {
private final MemberRepository memberRepository;
private final DayBudgetRepository dayBudgetRepository;

@Transactional
public MonthBudget createMonthBudget(Long memberId, Integer year, Integer month, Long budget) {
//member가 존재하는 지 확인
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MonthBudgetHandler(ErrorStatus.NO_MEMBER_EXIST));

MonthBudget monthBudget = monthBudgetRepository.findByMemberIdAndYearAndMonth(memberId, year, month)
.orElseGet(() -> MonthBudgetConverter.toMonthBudgetWithMonth(budget, year, month));

//지정된 날짜의 MonthBudget 생성
monthBudget.setMember(member);

return monthBudgetRepository.save(monthBudget);
}

@Transactional
public MonthBudget updateMonthBudget(Long memberId, MonthBudgetRequestDTO.UpdateMonthDTO request) {
LocalDate today = LocalDate.now();
Expand All @@ -45,7 +65,7 @@ public MonthBudget updateMonthBudget(Long memberId, MonthBudgetRequestDTO.Update
MonthBudget monthBudget = monthBudgetRepository.findByMemberIdAndYearAndMonth(memberId, today.getYear(), today.getMonthValue())
.orElseThrow(() -> new MonthBudgetHandler(ErrorStatus.MONTH_BUDGET_NOT_FOUND));

monthBudget.updateMonthBudget(request.getMonthBudget());
monthBudget.updateMonthBudget(request.getMonthBudget(), today.getYear(), today.getMonthValue());

//하루 예산 재분배하여 저장
List<DayBudget> dayBudgets = distributeDayBudgets(memberId);
Expand Down Expand Up @@ -114,6 +134,38 @@ public List<DayBudget> distributeDayBudgets(Long memberId) {
return dayBudgets;
}

//저번 달의 dayBudget 생성에만 사용(우선 지난 달 dayBudget이 없을 때 생성용)
@Transactional
public List<DayBudget> createDayBudgetsWithMonth(Long memberId, Integer year, Integer month, Long budget) {
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MonthBudgetHandler(ErrorStatus.NO_MEMBER_EXIST));

MonthBudget monthBudget = createMonthBudget(memberId, year, month, budget);

//지정된 달의 일 수
int dayInMonth = YearMonth.of(year, month).lengthOfMonth();

List<DayBudget> dayBudgets = new ArrayList<>();

for(int day = 1; day <= dayInMonth; day++) {
final int currentDay = day;
//이전 달의 dayBudget을 모두 INACTIVE로 생성
DayBudgetStatus status = DayBudgetStatus.INACTIVE;
int nowDistributedAmount = 0;

//dayBudget 생성 혹은 업뎃
DayBudget dayBudget = dayBudgetRepository.findByMonthBudgetAndDay(monthBudget, day)
.orElseGet(() -> DayBudgetConverter.toDayBudget(nowDistributedAmount, currentDay, status, monthBudget));

dayBudget.setStatus(status);
dayBudget.setDayBudget(nowDistributedAmount);

dayBudgets.add(dayBudget);
}

return dayBudgetRepository.saveAll(dayBudgets);
}

public MonthBudget getMonthBudget(Long memberId) {
LocalDate today = LocalDate.now();

Expand Down Expand Up @@ -145,6 +197,108 @@ public double getMonthUsedPercent(Long memberId) {
//소수점 6번째자리에서 반올림해서 리턴
return Math.round(monthUsedAmountPercent*1000000)/1000000.0;
}

//저번 달의 monthBudget이 없다면 생성해야해서 Transactional
@Transactional
public List<DayBudget> getWeekBudget(Long memberId) {
LocalDate today = LocalDate.now();

//member가 존재하는 지 확인
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MonthBudgetHandler(ErrorStatus.NO_MEMBER_EXIST));

//member와 year, month 기반으로 해당하는 monthBudget 찾기
MonthBudget monthBudget = monthBudgetRepository.findByMemberIdAndYearAndMonth(memberId, today.getYear(), today.getMonthValue())
.orElseThrow(() -> new MonthBudgetHandler(ErrorStatus.MONTH_BUDGET_NOT_FOUND));

//상대날짜 구하기
int dayInWeek = today.getDayOfWeek().getValue() - DayOfWeek.MONDAY.getValue();

//이번 주 월요일 구하기
int firstDayOfWeek = today.getDayOfMonth() - dayInWeek;
System.out.println("시작 날짜: " + firstDayOfWeek);
//남은 일수의 dayBudget 구하기
List<DayBudget> dayBudgets = new ArrayList<>();

//이번주에 저번달이 포함되어 있다면 저번 달의 monthBudget 생성.
//더 좋은 로직이 있는 지 고민..
Integer daysInLastMonth = 0;
Integer newYear = 0;
Integer newMonth = 0;

if(firstDayOfWeek < 1) {
//헌재 1월이라면 작년 12월의 monthBudget 생성
if(monthBudget.getMonth() == 1) {
createDayBudgetsWithMonth(memberId, today.getYear()-1, 12, 0L);
daysInLastMonth = YearMonth.of(today.getYear()-1, 12).lengthOfMonth();
newYear = today.getYear() - 1;
newMonth = 12;
}
//아니라면 저번달의 monthBudget 생성
else {
createDayBudgetsWithMonth(memberId, today.getYear(), monthBudget.getMonth()-1, 0L);
daysInLastMonth = YearMonth.of(today.getYear(), monthBudget.getMonth()-1).lengthOfMonth();
newYear = today.getYear();
newMonth = monthBudget.getMonth()-1;
}

//지난달 monthBudget 찾기
MonthBudget lastMonthBudget = monthBudgetRepository.findByMemberIdAndYearAndMonth(memberId, newYear, newMonth)
.orElseThrow(() -> new MonthBudgetHandler(ErrorStatus.MONTH_BUDGET_NOT_FOUND));

//dayBudget 찾기
for(int i=0; i< 7; i++){
int plusDay = i;
//저번달 날짜라면 저번달 monthBudget에서 찾기
if(firstDayOfWeek + i < 1) {
plusDay += daysInLastMonth;
DayBudget dayBudget = dayBudgetRepository.findByMonthBudgetAndDay(lastMonthBudget, firstDayOfWeek + plusDay)
.orElseThrow(() -> new DayBudgetHandler(NOT_SOME_DAY_BUDGET));
dayBudgets.add(dayBudget);
}
//이번달 날짜라면 이번달 monthBudget에서 찾기
else {
DayBudget dayBudget = dayBudgetRepository.findByMonthBudgetAndDay(monthBudget, firstDayOfWeek + plusDay)
.orElseThrow(() -> new DayBudgetHandler(NOT_SOME_DAY_BUDGET));
dayBudgets.add(dayBudget);
}
}
}
else {
for(int i=0; i< 7; i++){
DayBudget dayBudget = dayBudgetRepository.findByMonthBudgetAndDay(monthBudget, firstDayOfWeek+i)
.orElseThrow(() -> new DayBudgetHandler(NOT_SOME_DAY_BUDGET));
dayBudgets.add(dayBudget);
}
}

//이번 주의 dayBudget 리턴
return dayBudgets;
}

public List<Integer> getMonthAndWeek(Long memberId) {
LocalDate today = LocalDate.now();

//member가 존재하는 지 확인
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MonthBudgetHandler(ErrorStatus.NO_MEMBER_EXIST));

//member와 year, month 기반으로 해당하는 monthBudget 찾기
MonthBudget monthBudget = monthBudgetRepository.findByMemberIdAndYearAndMonth(memberId, today.getYear(), today.getMonthValue())
.orElseThrow(() -> new MonthBudgetHandler(ErrorStatus.MONTH_BUDGET_NOT_FOUND));

List<Integer> currentWeek = new ArrayList<>();

Calendar calendar = Calendar.getInstance();
Integer week = Integer.valueOf(calendar.get(Calendar.WEEK_OF_MONTH));

//현재 달
currentWeek.add(monthBudget.getMonth());
currentWeek.add(week);

return currentWeek;
}

private long roundDownToNearestHundred(long amount) {
return (amount / 100) * 100;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@
import umc.haruchi.apiPayload.ApiResponse;
import umc.haruchi.config.login.auth.MemberDetail;
import umc.haruchi.converter.MonthBudgetConverter;
import umc.haruchi.domain.DayBudget;
import umc.haruchi.domain.Member;
import umc.haruchi.domain.MonthBudget;
import umc.haruchi.service.MonthBudgetService;
import umc.haruchi.web.dto.MonthBudgetRequestDTO;
import umc.haruchi.web.dto.MonthBudgetResponseDTO;

import java.time.LocalDateTime;
import java.util.List;

@RestController
@RequiredArgsConstructor
Expand Down Expand Up @@ -44,4 +47,13 @@ public ApiResponse<MonthBudgetResponseDTO.GetMonthUsedPercentResultDTO> getMonth
double monthBudgetPercent = monthBudgetService.getMonthUsedPercent(memberDetail.getMember().getId());
return ApiResponse.onSuccess(MonthBudgetConverter.toGetMonthUsedPercentResultDTO(monthBudgetPercent));
}

//한 주 예산 금액 조회
@Operation(summary = "한 주 예산 금액 조회 API", description = "본인의 한 주 예산 금액을 조회하는 API 입니다.")
@GetMapping("/week")
public ApiResponse<MonthBudgetResponseDTO.GetWeekBudgetResultListDTO> getWeekBudget(@AuthenticationPrincipal MemberDetail memberDetail) {
List<DayBudget> weekBudget = monthBudgetService.getWeekBudget(memberDetail.getMember().getId());
List<Integer> currentWeek = monthBudgetService.getMonthAndWeek(memberDetail.getMember().getId());
return ApiResponse.onSuccess(MonthBudgetConverter.toGetWeekBudgetResultListDTO(weekBudget, currentWeek.get(0), currentWeek.get(1)));
}
}
23 changes: 23 additions & 0 deletions src/main/java/umc/haruchi/web/dto/MonthBudgetResponseDTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import umc.haruchi.domain.DayBudget;
import umc.haruchi.domain.enums.DayBudgetStatus;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

public class MonthBudgetResponseDTO {
@Builder
Expand Down Expand Up @@ -44,4 +47,24 @@ public static class GetMonthResultDTO {
public static class GetMonthUsedPercentResultDTO {
double monthUsedPercent;
}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class GetWeekBudgetResultDTO {
Long day;
Integer dayBudget;
DayBudgetStatus status;
}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class GetWeekBudgetResultListDTO {
List<GetWeekBudgetResultDTO> weekBudget;
Integer month;
Integer week;
}
}

0 comments on commit 7da8286

Please sign in to comment.