Skip to content

Commit

Permalink
Merge pull request #62 from BudgetBuddiesTeam/chore/#61
Browse files Browse the repository at this point in the history
[chore] 소비 추가하기 관련 구조 수정
  • Loading branch information
ryogaeng authored Jul 30, 2024
2 parents 25bafc8 + ea6bcce commit 0eef413
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
import com.bbteam.budgetbuddies.common.BaseEntity;
import com.bbteam.budgetbuddies.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.*;
import org.hibernate.annotations.ColumnDefault;

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public class ConsumptionGoal extends BaseEntity {
@JoinColumn(name = "category_id")
private Category category;

public void updateConsumeAmount(Long amount) {
this.consumeAmount += amount;
}
public void updateGoalAmount(Long goalAmount) {
this.goalAmount = goalAmount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ ConsumptionGoalResponseListDto updateConsumptionGoals(Long userId,
ConsumptionGoalListRequestDto consumptionGoalListRequestDto);

ConsumptionAnalysisResponseDTO getTopCategoryAndConsumptionAmount(Long userId);
void updateConsumeAmount(Long userId, Long categoryId, Long amount);
}
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,21 @@ private void updateGoalMap(Long userId, LocalDate month, Map<Long, ConsumptionGo
.map(consumptionGoalConverter::toConsumptionGoalResponseDto)
.forEach(goal -> goalMap.put(goal.getCategoryId(), goal));
}

@Override
public void updateConsumeAmount(Long userId, Long categoryId, Long amount) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new IllegalArgumentException("Not found user"));

Category category = categoryRepository.findById(categoryId)
.orElseThrow(() -> new IllegalArgumentException("Not found Category"));

LocalDate thisMonth = LocalDate.now().withDayOfMonth(1);
ConsumptionGoal consumptionGoal = consumptionGoalRepository
.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, category, thisMonth)
.orElseGet(() -> generateConsumptionGoal(user, category, thisMonth));

consumptionGoal.updateConsumeAmount(amount);
consumptionGoalRepository.save(consumptionGoal);
}
}
Original file line number Diff line number Diff line change
@@ -1,42 +1,36 @@
package com.bbteam.budgetbuddies.domain.expense.controller;

import java.time.LocalDate;

import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;

import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto;
import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto;
import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseCompactResponseDto;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.web.bind.annotation.RequestBody;

public interface ExpenseApi {
@Operation(summary = "소비 내역 추가", description = "사용자가 소비 내역을 추가합니다.")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class)))
@ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
@ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class)))
})
ResponseEntity<ExpenseResponseDto> createExpense(
@Parameter(description = "user_id, category_id, amount, description, expenseDate")
ExpenseRequestDto expenseRequestDto);
@Parameter(description = "user_id, category_id, amount, description, expenseDate") @RequestBody ExpenseRequestDto expenseRequestDto);

@Operation(summary = "월별 소비 조회", description = "무한 스크롤을 통한 조회로 예상하여 Slice를 통해서 조회")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class)))
@ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
@ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class)))
})
ResponseEntity<MonthlyExpenseCompactResponseDto> findExpensesForMonth(
Pageable pageable,
Long userId,
LocalDate date);
ResponseEntity<MonthlyExpenseCompactResponseDto> findExpensesForMonth(Pageable pageable, Long userId, LocalDate date);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.time.LocalDate;

import io.swagger.v3.oas.annotations.Parameter;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.query.Param;
import org.springframework.format.annotation.DateTimeFormat;
Expand All @@ -13,13 +14,10 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto;
import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto;
import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseCompactResponseDto;
import com.bbteam.budgetbuddies.domain.expense.service.ExpenseService;

import io.swagger.v3.oas.annotations.Parameter;
import lombok.RequiredArgsConstructor;

@RestController
Expand All @@ -31,16 +29,16 @@ public class ExpenseController implements ExpenseApi {
@Override
@PostMapping("/add")
public ResponseEntity<ExpenseResponseDto> createExpense(
@Parameter(description = "user_id, category_id, amount, description, expenseDate") @RequestBody ExpenseRequestDto expenseRequestDto) {
@Parameter(description = "user_id, category_id, amount, description, expenseDate") @RequestBody ExpenseRequestDto expenseRequestDto) {
ExpenseResponseDto response = expenseService.createExpense(expenseRequestDto);
return ResponseEntity.ok(response);
}

@Override
@GetMapping("/{userId}")
public ResponseEntity<MonthlyExpenseCompactResponseDto> findExpensesForMonth(Pageable pageable,
@PathVariable @Param("userId") Long userId,
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {
@PathVariable @Param("userId") Long userId,
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {

return ResponseEntity.ok(expenseService.getMonthlyExpense(pageable, userId, date));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,7 @@
import com.bbteam.budgetbuddies.domain.user.entity.User;

public interface ExpenseRepository extends JpaRepository<Expense, Long> {

// 추후 적용 예정
@Query("SELECT e FROM Expense e WHERE e.user.id = :userId AND e.category.id = :categoryId")
List<Expense> findByUserIdAndCategoryId(@Param("userId") Long userId, @Param("categoryId") Long categoryId);

@Query("SELECT e FROM Expense e WHERE e.user.id = :userId")
List<Expense> findByUserId(@Param("userId") Long userId);

@Query("SELECT e FROM Expense e WHERE e.user = :user AND e.expenseDate BETWEEN :startDate AND :endDate ORDER BY e.expenseDate DESC")
Slice<Expense> findAllByUserIdForPeriod(Pageable pageable, @Param("user") User user,
@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate);
@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import com.bbteam.budgetbuddies.domain.category.entity.Category;
import com.bbteam.budgetbuddies.domain.category.repository.CategoryRepository;
import com.bbteam.budgetbuddies.domain.consumptiongoal.service.ConsumptionGoalService;
import com.bbteam.budgetbuddies.domain.expense.converter.ExpenseConverter;
import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto;
import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto;
Expand All @@ -28,18 +29,46 @@ public class ExpenseServiceImpl implements ExpenseService {
private final UserRepository userRepository;
private final CategoryRepository categoryRepository;
private final ExpenseConverter expenseConverter;
private final ConsumptionGoalService consumptionGoalService;

@Override
public ExpenseResponseDto createExpense(ExpenseRequestDto expenseRequestDto) {
User user = userRepository.findById(expenseRequestDto.getUserId())
.orElseThrow(() -> new IllegalArgumentException("Invalid user ID"));
.orElseThrow(() -> new IllegalArgumentException("Invalid user ID"));
Category category = categoryRepository.findById(expenseRequestDto.getCategoryId())
.orElseThrow(() -> new IllegalArgumentException("Invalid category ID"));
.orElseThrow(() -> new IllegalArgumentException("Invalid category ID"));

/*
case 1)
- 카테고리 ID가 1~10 사이 && default => DB의 immutable 필드인 default category
- DB 관리 이슈로 category에 default 카테고리의 중복이 발생할 경우, 이를 대비하기 위해 1<= id <= 10 조건도 추가
*/
if (expenseRequestDto.getCategoryId() >= 1 && expenseRequestDto.getCategoryId() <= 10 && category.getIsDefault()) {
// category.setUser(user);
// default category
}
/*
Case 2)
!default && 키테고리 테이블의 UserId 컬럼의 값이 나와 맞으면 (= custom cateogory)
*/
else if (!category.getIsDefault() && category.getUser().getId().equals(expenseRequestDto.getUserId())) {
// custom category
}
else {
throw new IllegalArgumentException("User and category are not matched properly.");
}

Expense expense = expenseConverter.toExpenseEntity(expenseRequestDto, user, category);
expenseRepository.save(expense);

// 소비 목표 업데이트
consumptionGoalService.updateConsumeAmount(expenseRequestDto.getUserId(), expenseRequestDto.getCategoryId(), expenseRequestDto.getAmount());

return expenseConverter.toExpenseResponseDto(expense);
/*
결과 Case 1) 해당 유저의 user_id + immutable 필드 중 하나의 조합으로 Expense 테이블에 저장
결과 Case 2) 내가 직접 생성한 카테고리 중 하나로 카테고리를 설정하여 Expense 테이블에 저장
*/
}

@Override
Expand All @@ -49,11 +78,12 @@ public MonthlyExpenseCompactResponseDto getMonthlyExpense(Pageable pageable, Lon
LocalDate endOfMonth = localDate.withDayOfMonth(startOfMonth.lengthOfMonth());

User user = userRepository.findById(userId)
.orElseThrow(() -> new IllegalArgumentException("Invalid user ID"));
.orElseThrow(() -> new IllegalArgumentException("Invalid user ID"));

Slice<Expense> expenseSlice = expenseRepository.findAllByUserIdForPeriod(pageable, user,
startOfMonth.atStartOfDay(), endOfMonth.atStartOfDay());
startOfMonth.atStartOfDay(), endOfMonth.atStartOfDay());

return expenseConverter.toMonthlyExpenseCompactResponseDto(expenseSlice, startOfMonth);
}
}

0 comments on commit 0eef413

Please sign in to comment.