Skip to content

Commit

Permalink
Merge pull request #135 from BudgetBuddiesTeam/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
ggamD00 authored Aug 18, 2024
2 parents d0dc3a5 + 7b1b90a commit 14ea1ea
Show file tree
Hide file tree
Showing 20 changed files with 290 additions and 214 deletions.
6 changes: 2 additions & 4 deletions src/main/java/com/bbteam/budgetbuddies/common/BaseEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

import jakarta.persistence.*;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.*;

import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.*;
Expand All @@ -22,6 +19,7 @@
@SuperBuilder
@SoftDelete(columnName = "deleted") // boolean 타입의 deleted 필드가 추가
@Getter
@Setter
public abstract class BaseEntity {

@Id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.bbteam.budgetbuddies.domain.category.dto.CategoryResponseDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
Expand Down Expand Up @@ -38,4 +39,20 @@ ResponseEntity<CategoryResponseDTO> createCategory(
})
@GetMapping("/get/{userId}")
ResponseEntity<List<CategoryResponseDTO>> getUserCategories(@PathVariable Long userId);

@Operation(summary = "특정 카테고리 삭제하기 API", description = "특정 카테고리를 삭제하는 API이며, 사용자의 ID를 입력하여 사용합니다. (추후 토큰으로 검증)")
@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))),
// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class)))
})
@Parameters({
@Parameter(name = "userId", description = "해당하는 사용자의 id"),
@Parameter(name = "categoryId", description = "삭제할 카테고리의 id"),
})
ResponseEntity<String> deleteCategory(
@RequestParam Long userId,
@PathVariable Long categoryId
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
import java.util.List;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import com.bbteam.budgetbuddies.domain.category.dto.CategoryRequestDTO;
import com.bbteam.budgetbuddies.domain.category.dto.CategoryResponseDTO;
Expand All @@ -32,10 +27,19 @@ public ResponseEntity<CategoryResponseDTO> createCategory(
return ResponseEntity.ok(response);
}

@Override
@GetMapping("/get/{userId}")
public ResponseEntity<List<CategoryResponseDTO>> getUserCategories(@PathVariable Long userId) {
List<CategoryResponseDTO> response = categoryService.getUserCategories(userId);
return ResponseEntity.ok(response);
}
@Override
@GetMapping("/get/{userId}")
public ResponseEntity<List<CategoryResponseDTO>> getUserCategories(@PathVariable Long userId) {
List<CategoryResponseDTO> response = categoryService.getUserCategories(userId);
return ResponseEntity.ok(response);
}

@Override
@DeleteMapping("/delete/{categoryId}")
public ResponseEntity<String> deleteCategory(
@RequestParam Long userId,
@PathVariable Long categoryId) {
categoryService.deleteCategory(categoryId, userId);
return ResponseEntity.ok("Successfully deleted category!");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.bbteam.budgetbuddies.domain.category.entity;

import com.bbteam.budgetbuddies.common.BaseEntity;
import com.bbteam.budgetbuddies.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.*;
Expand All @@ -24,8 +23,11 @@ public class Category {
@ColumnDefault("1")
private Boolean isDefault;

@Column(nullable = false)
@ColumnDefault("false")
private Boolean deleted = false;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.bbteam.budgetbuddies.domain.category.repository;

import java.util.List;
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
Expand All @@ -15,4 +16,5 @@ public interface CategoryRepository extends JpaRepository<Category, Long> {
@Query("SELECT c FROM Category c WHERE c.isDefault = true")
List<Category> findAllByIsDefaultTrue();
boolean existsByUserIdAndName(Long userId, String name);
Optional<Category> findById(Long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ public interface CategoryService {
List<CategoryResponseDTO> getUserCategories(Long userId);

Category handleCategoryChange(Expense expense, ExpenseUpdateRequestDto request, User user);

void deleteCategory(Long id, Long userId);
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.List;
import java.util.stream.Collectors;

import com.bbteam.budgetbuddies.domain.expense.repository.ExpenseRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -32,6 +33,7 @@ public class CategoryServiceImpl implements CategoryService {
private final UserRepository userRepository;
private final CategoryConverter categoryConverter;
private final ConsumptionGoalRepository consumptionGoalRepository;
private final ExpenseRepository expenseRepository;

@Override
public CategoryResponseDTO createCategory(Long userId, CategoryRequestDTO categoryRequestDTO) {
Expand Down Expand Up @@ -62,7 +64,7 @@ public CategoryResponseDTO createCategory(Long userId, CategoryRequestDTO catego
public List<CategoryResponseDTO> getUserCategories(Long userId) {

userRepository.findById(userId)
.orElseThrow(() -> new IllegalArgumentException("User not found with id: " + userId));
.orElseThrow(() -> new IllegalArgumentException("User not found with id: " + userId));

List<Category> categories = categoryRepository.findUserCategoryByUserId(userId);
return categories.stream().map(categoryConverter::toCategoryResponseDTO).collect(Collectors.toList());
Expand All @@ -72,11 +74,44 @@ public List<CategoryResponseDTO> getUserCategories(Long userId) {
@Transactional(readOnly = true)
public Category handleCategoryChange(Expense expense, ExpenseUpdateRequestDto request, User user) {
Category categoryToReplace = categoryRepository.findById(request.getCategoryId())
.orElseThrow(() -> new IllegalArgumentException("Not found category"));
.orElseThrow(() -> new IllegalArgumentException("Not found category"));

consumptionGoalService.recalculateConsumptionAmount(expense, request, user);

return categoryToReplace;
}

@Override
@Transactional
public void deleteCategory(Long categoryId, Long userId) {
categoryRepository.findById(categoryId).ifPresent(category -> {
if (category.getIsDefault()) {
throw new IllegalArgumentException("Default categories cannot be deleted.");
}

List<Expense> expenses = expenseRepository.findByCategoryIdAndUserId(categoryId, userId);
long totalAmount = expenses.stream().mapToLong(Expense::getAmount).sum();

Category etcCategory = categoryRepository.findById(10L)
.orElseThrow(() -> new IllegalArgumentException("etc category not found"));

expenses.forEach(expense -> {
expense.setCategory(etcCategory);
expenseRepository.save(expense);
});

ConsumptionGoal goal = consumptionGoalRepository.findByCategoryIdAndUserId(10L, userId)
.orElseThrow(() -> new IllegalArgumentException("No consumption goal found for category_id 10."));
goal.setConsumeAmount(goal.getConsumeAmount() + totalAmount);
consumptionGoalRepository.save(goal);

consumptionGoalRepository.findByCategoryIdAndUserId(categoryId, userId).ifPresent(consumptionGoal -> {
consumptionGoal.setDeleted(true);
consumptionGoalRepository.save(consumptionGoal);
});

category.setDeleted(true);
categoryRepository.save(category);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,13 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.validation.constraints.Min;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.*;
import lombok.experimental.SuperBuilder;
import lombok.extern.slf4j.Slf4j;

@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@SuperBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,61 +23,84 @@ public interface ConsumptionGoalRepository extends JpaRepository<ConsumptionGoal
@Query(value = "SELECT cg FROM ConsumptionGoal AS cg WHERE cg.user.id = :userId AND cg.goalMonth = :goalMonth")
List<ConsumptionGoal> findConsumptionGoalByUserIdAndGoalMonth(Long userId, LocalDate goalMonth);

Optional<ConsumptionGoal> findConsumptionGoalByUserAndCategoryAndGoalMonth(User user, Category category,
LocalDate goalMonth);
Optional<ConsumptionGoal> findConsumptionGoalByUserAndCategoryAndGoalMonth(User user, Category category, LocalDate goalMonth);

@Query("SELECT AVG(cg.consumeAmount) FROM ConsumptionGoal cg " + "JOIN cg.category c " + "WHERE c.id = :categoryId "
+ "AND cg.goalMonth BETWEEN :startOfWeek AND :endOfWeek "
+ "AND cg.user.age BETWEEN :peerAgeStart AND :peerAgeEnd " + "AND cg.user.gender = :peerGender")
@Query("SELECT AVG(cg.consumeAmount) FROM ConsumptionGoal cg " +
"JOIN cg.category c " +
"WHERE c.id = :categoryId " +
"AND cg.goalMonth BETWEEN :startOfWeek AND :endOfWeek " +
"AND cg.user.age BETWEEN :peerAgeStart AND :peerAgeEnd " +
"AND cg.user.gender = :peerGender")
Optional<Long> findAvgConsumptionByCategoryIdAndCurrentWeek(
@Param("categoryId") Long categoryId, @Param("startOfWeek") LocalDate startOfWeek,
@Param("endOfWeek") LocalDate endOfWeek, @Param("peerAgeStart") int peerAgeStart,
@Param("peerAgeEnd") int peerAgeEnd, @Param("peerGender") Gender peerGender);
@Param("categoryId") Long categoryId,
@Param("startOfWeek") LocalDate startOfWeek,
@Param("endOfWeek") LocalDate endOfWeek,
@Param("peerAgeStart") int peerAgeStart,
@Param("peerAgeEnd") int peerAgeEnd,
@Param("peerGender") Gender peerGender);

@Query(
"SELECT new com.bbteam.budgetbuddies.domain.consumptiongoal.dto.AvgConsumptionGoalDto("
+ "cg.category.id, AVG(cg.consumeAmount))"
+ "FROM ConsumptionGoal cg " + "WHERE cg.category.isDefault = true "
+ "AND cg.user.age BETWEEN :peerAgeStart AND :peerAgeEnd " + "AND cg.user.gender = :peerGender "
+ "AND cg.goalMonth >= :currentMonth " + "GROUP BY cg.category.id " + "ORDER BY AVG(cg.consumeAmount) DESC")
@Query("SELECT new com.bbteam.budgetbuddies.domain.consumptiongoal.dto.AvgConsumptionGoalDto(" +
"cg.category.id, AVG(cg.consumeAmount))" +
"FROM ConsumptionGoal cg " +
"WHERE cg.category.isDefault = true " +
"AND cg.user.age BETWEEN :peerAgeStart AND :peerAgeEnd " +
"AND cg.user.gender = :peerGender " +
"AND cg.goalMonth >= :currentMonth " +
"GROUP BY cg.category.id " +
"ORDER BY AVG(cg.consumeAmount) DESC")
List<AvgConsumptionGoalDto> findAvgConsumptionAmountByCategory(
@Param("peerAgeStart") int peerAgeStart,
@Param("peerAgeEnd") int peerAgeEnd,
@Param("peerGender") Gender peerGender,
@Param("currentMonth") LocalDate currentMonth);
@Param("peerAgeStart") int peerAgeStart,
@Param("peerAgeEnd") int peerAgeEnd,
@Param("peerGender") Gender peerGender,
@Param("currentMonth") LocalDate currentMonth);

@Query("SELECT new com.bbteam.budgetbuddies.domain.consumptiongoal.dto.MyConsumptionGoalDto("
+ "cg.category.id, SUM(cg.consumeAmount)) " + "FROM ConsumptionGoal cg "
+ "WHERE cg.category.isDefault = true " + "AND cg.user.id = :userId "
+ "GROUP BY cg.category.id " + "ORDER BY cg.category.id")
@Query("SELECT new com.bbteam.budgetbuddies.domain.consumptiongoal.dto.MyConsumptionGoalDto(" +
"cg.category.id, SUM(cg.consumeAmount)) " +
"FROM ConsumptionGoal cg " +
"WHERE cg.category.isDefault = true " +
"AND cg.user.id = :userId " +
"GROUP BY cg.category.id " +
"ORDER BY cg.category.id")
List<MyConsumptionGoalDto> findAllConsumptionAmountByUserId(@Param("userId") Long userId);

@Query(
"SELECT new com.bbteam.budgetbuddies.domain.consumptiongoal.dto.AvgConsumptionGoalDto(cg.category.id, AVG("
+ "cg.goalAmount))"
+ "FROM ConsumptionGoal cg " + "WHERE cg.category.isDefault = true "
+ "AND cg.user.age BETWEEN :peerAgeStart AND :peerAgeEnd " + "AND cg.user.gender = :peerGender "
+ "AND cg.goalMonth >= :currentMonth " + "GROUP BY cg.category.id " + "ORDER BY AVG(cg.goalAmount) DESC")
@Query("SELECT new com.bbteam.budgetbuddies.domain.consumptiongoal.dto.AvgConsumptionGoalDto(" +
"cg.category.id, AVG(cg.goalAmount))" +
"FROM ConsumptionGoal cg " +
"WHERE cg.category.isDefault = true " +
"AND cg.user.age BETWEEN :peerAgeStart AND :peerAgeEnd " +
"AND cg.user.gender = :peerGender " +
"AND cg.goalMonth >= :currentMonth " +
"GROUP BY cg.category.id " +
"ORDER BY AVG(cg.goalAmount) DESC")
List<AvgConsumptionGoalDto> findAvgGoalAmountByCategory(
@Param("peerAgeStart") int peerAgeStart,
@Param("peerAgeEnd") int peerAgeEnd,
@Param("peerGender") Gender peerGender,
@Param("currentMonth") LocalDate currentMonth);
@Param("peerAgeStart") int peerAgeStart,
@Param("peerAgeEnd") int peerAgeEnd,
@Param("peerGender") Gender peerGender,
@Param("currentMonth") LocalDate currentMonth);

@Query("SELECT new com.bbteam.budgetbuddies.domain.consumptiongoal.dto.MyConsumptionGoalDto("
+ "cg.category.id, SUM(cg.goalAmount)) " + "FROM ConsumptionGoal cg "
+ "WHERE cg.category.isDefault = true " + "AND cg.user.id = :userId "
+ "GROUP BY cg.category.id " + "ORDER BY cg.category.id")
@Query("SELECT new com.bbteam.budgetbuddies.domain.consumptiongoal.dto.MyConsumptionGoalDto(" +
"cg.category.id, SUM(cg.goalAmount)) " +
"FROM ConsumptionGoal cg " +
"WHERE cg.category.isDefault = true " +
"AND cg.user.id = :userId " +
"GROUP BY cg.category.id " +
"ORDER BY cg.category.id")
List<MyConsumptionGoalDto> findAllGoalAmountByUserId(@Param("userId") Long userId);

@Query(
"SELECT new com.bbteam.budgetbuddies.domain.consumptiongoal.dto.CategoryConsumptionCountDto("
+ "cg.category.id, COUNT(cg)) " + "FROM ConsumptionGoal cg " + "WHERE cg.category.isDefault = true "
+ "AND cg.user.age BETWEEN :peerAgeStart AND :peerAgeEnd " + "AND cg.user.gender = :peerGender "
+ "AND cg.goalMonth >= :currentMonth " + "GROUP BY cg.category.id " + "ORDER BY COUNT(cg) DESC")
@Query("SELECT new com.bbteam.budgetbuddies.domain.consumptiongoal.dto.CategoryConsumptionCountDto(" +
"cg.category.id, COUNT(cg)) " +
"FROM ConsumptionGoal cg " +
"WHERE cg.category.isDefault = true " +
"AND cg.user.age BETWEEN :peerAgeStart AND :peerAgeEnd " +
"AND cg.user.gender = :peerGender " +
"AND cg.goalMonth >= :currentMonth " +
"GROUP BY cg.category.id " +
"ORDER BY COUNT(cg) DESC")
List<CategoryConsumptionCountDto> findTopCategoriesByConsumptionCount(
@Param("peerAgeStart") int peerAgeStart,
@Param("peerAgeEnd") int peerAgeEnd,
@Param("peerGender") Gender peerGender,
@Param("currentMonth") LocalDate currentMonth);
@Param("peerAgeStart") int peerAgeStart,
@Param("peerAgeEnd") int peerAgeEnd,
@Param("peerGender") Gender peerGender,
@Param("currentMonth") LocalDate currentMonth);

Optional<ConsumptionGoal> findByCategoryIdAndUserId(Long categoryId, Long userId);
}
Loading

0 comments on commit 14ea1ea

Please sign in to comment.