diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
new file mode 100644
index 00000000..d6b47f1f
--- /dev/null
+++ b/.github/workflows/gradle.yml
@@ -0,0 +1,46 @@
+name: server
+
+
+on:
+ push:
+ branches:
+ - dev
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v3
+ with:
+ distribution: temurin
+ java-version: 17
+
+ - name: Ensure resource directory exists
+ run: mkdir -p ./src/main/resources
+
+ - name : injection-yml
+ run : echo -E "${{ secrets.YML }}" > ./src/main/resources/application.yml
+
+ - name: Log in to Docker Hub
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_PASSWORD }}
+
+ - name: Execute Gradle build and analyze
+ run: ./gradlew jib
+
+ - name: Run scripts in server
+ uses: appleboy/ssh-action@master
+ with:
+ key: ${{ secrets.PRIVATE_KEY }}
+ host: ${{ secrets.HOST_DEV }}
+ username: ${{ secrets.USERNAME }}
+ script: ${{ secrets.SCRIPT }}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index c2065bc2..7dbfa83c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,3 +35,6 @@ out/
### VS Code ###
.vscode/
+
+### Setting File ###
+src/main/resources/application.yml
\ No newline at end of file
diff --git a/README.md b/README.md
index 580d57db..a4b2469e 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,13 @@
# 빈주머니즈_Spring
-
+![빈주머니즈_커버_대지 1 사본](https://github.com/user-attachments/assets/744ef4c6-87cd-4db9-9c0b-f848231a203c)
![Java](https://img.shields.io/badge/java-%23ED8B00.svg?style=for-the-badge&logo=openjdk&logoColor=white) ![MySQL](https://img.shields.io/badge/mysql-4479A1.svg?style=for-the-badge&logo=mysql&logoColor=white) ![IntelliJ IDEA](https://img.shields.io/badge/IntelliJIDEA-000000.svg?style=for-the-badge&logo=intellij-idea&logoColor=white) ![Postman](https://img.shields.io/badge/Postman-FF6C37?style=for-the-badge&logo=postman&logoColor=white)
+
+
## Team
|
|
|
|
|
|
|
|:-:|:-:|:-:|:-:|:-:|:-:|
diff --git a/build.gradle b/build.gradle
index 7c2d02cc..f2596c13 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,6 +2,7 @@ plugins {
id 'java'
id 'org.springframework.boot' version '3.2.7'
id 'io.spring.dependency-management' version '1.1.5'
+ id 'com.google.cloud.tools.jib' version '3.4.3'
}
group = 'com.bbteam'
@@ -38,3 +39,21 @@ dependencies {
tasks.named('test') {
useJUnitPlatform()
}
+
+jib {
+ from {
+ image = 'openjdk:17-alpine'
+ platforms {
+ platform {
+ architecture = 'amd64'
+ os = 'linux'
+ }
+ }
+ }
+ to {
+ image = 'binjumeoniz1/binjumeoniz:latest'
+ }
+ container {
+ jvmFlags = ['-Dspring.profiles.active=dev']
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/apiPayload/ApiResponse.java b/src/main/java/com/bbteam/budgetbuddies/apiPayload/ApiResponse.java
new file mode 100644
index 00000000..b9d069a0
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/apiPayload/ApiResponse.java
@@ -0,0 +1,38 @@
+package com.bbteam.budgetbuddies.apiPayload;
+
+import com.bbteam.budgetbuddies.apiPayload.code.BaseCode;
+import com.bbteam.budgetbuddies.apiPayload.code.status.SuccessStatus;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+@JsonPropertyOrder({"isSuccess", "code", "message", "result"})
+public class ApiResponse
{
+
+ @JsonProperty("isSuccess")
+ private final Boolean isSuccess;
+ private final String code;
+ private final String message;
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ private T result;
+
+
+ // 성공한 경우 응답 생성
+ public static ApiResponse onSuccess(T result){
+ return new ApiResponse<>(true, SuccessStatus.OK.getCode() , SuccessStatus.OK.getMessage(), result);
+ }
+
+ public static ApiResponse of(BaseCode code, T result){
+ return new ApiResponse<>(true, code.getReasonHttpStatus().getCode() , code.getReasonHttpStatus().getMessage(), result);
+ }
+
+
+ // 실패한 경우 응답 생성
+ public static ApiResponse onFailure(String code, String message, T data){
+ return new ApiResponse<>(true, code, message, data);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/BaseCode.java b/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/BaseCode.java
new file mode 100644
index 00000000..d5fb4d79
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/BaseCode.java
@@ -0,0 +1,10 @@
+package com.bbteam.budgetbuddies.apiPayload.code;
+
+public interface BaseCode {
+ ReasonHttpStatus getReasonHttpStatus();
+
+ interface ReasonHttpStatus {
+ String getCode();
+ String getMessage();
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/BaseErrorCode.java b/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/BaseErrorCode.java
new file mode 100644
index 00000000..c3388e55
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/BaseErrorCode.java
@@ -0,0 +1,4 @@
+package com.bbteam.budgetbuddies.apiPayload.code;
+
+public interface BaseErrorCode {
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/status/SuccessStatus.java b/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/status/SuccessStatus.java
new file mode 100644
index 00000000..414fe213
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/status/SuccessStatus.java
@@ -0,0 +1,14 @@
+package com.bbteam.budgetbuddies.apiPayload.code.status;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum SuccessStatus {
+ OK("200", "OK");
+
+ private final String code;
+ private final String message;
+}
+
diff --git a/src/main/java/com/bbteam/budgetbuddies/common/BaseEntity.java b/src/main/java/com/bbteam/budgetbuddies/common/BaseEntity.java
index 7a9756c1..21800f97 100644
--- a/src/main/java/com/bbteam/budgetbuddies/common/BaseEntity.java
+++ b/src/main/java/com/bbteam/budgetbuddies/common/BaseEntity.java
@@ -1,7 +1,12 @@
package com.bbteam.budgetbuddies.common;
import jakarta.persistence.*;
-import lombok.*;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.SoftDelete;
import org.springframework.data.annotation.CreatedDate;
@@ -17,6 +22,7 @@
@Getter
@SuperBuilder
@SoftDelete // boolean 타입의 deleted 필드가 추가
+@Getter
public abstract class BaseEntity {
@Id
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/calendar/controller/CalendarController.java b/src/main/java/com/bbteam/budgetbuddies/domain/calendar/controller/CalendarController.java
new file mode 100644
index 00000000..bc98ff3f
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/calendar/controller/CalendarController.java
@@ -0,0 +1,37 @@
+package com.bbteam.budgetbuddies.domain.calendar.controller;
+
+import com.bbteam.budgetbuddies.domain.calendar.dto.CalendarDto;
+import com.bbteam.budgetbuddies.domain.calendar.service.CalendarService;
+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.responses.ApiResponses;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/calendar")
+public class CalendarController {
+
+ private final CalendarService calendarService;
+ @Operation(summary = "[User] 주머니 캘린더 API", description = "주머니 캘린더 화면에 필요한 API를 호출합니다.")
+ @ApiResponses({
+ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
+ })
+ @Parameters({
+ @Parameter(name = "year", description = "호출할 연도입니다."),
+ @Parameter(name = "month", description = "호출할 연도의 월입니다."),
+ })
+ @GetMapping("/")
+ public ResponseEntity request(
+ @RequestParam("year") Integer year, @RequestParam("month") Integer month
+ ) {
+ CalendarDto.CalendarMonthResponseDto result = calendarService.find(year, month);
+ return ResponseEntity.ok(result);
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/calendar/converter/CalendarConverter.java b/src/main/java/com/bbteam/budgetbuddies/domain/calendar/converter/CalendarConverter.java
new file mode 100644
index 00000000..e62cd00b
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/calendar/converter/CalendarConverter.java
@@ -0,0 +1,55 @@
+package com.bbteam.budgetbuddies.domain.calendar.converter;
+
+import com.bbteam.budgetbuddies.domain.calendar.dto.CalendarDto;
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+
+import java.util.List;
+
+public class CalendarConverter {
+
+ public static CalendarDto.CalendarMonthResponseDto toCalendarMonthResponseDto(CalendarDto.CalendarMonthInfoDto calendarMonthInfoDto, CalendarDto.CalendarMonthInfoDto recommendMonthInfoDto){
+ return CalendarDto.CalendarMonthResponseDto.builder()
+ .calendarMonthInfoDto(calendarMonthInfoDto)
+ .recommendMonthInfoDto(recommendMonthInfoDto)
+ .build();
+ }
+
+ public static CalendarDto.CalendarMonthInfoDto toCalendarMonthInfoDto(List discountInfoList,
+ List supportInfoList) {
+ List discountInfoDtoList = discountInfoList.stream()
+ .map(CalendarConverter::toCalendarDiscountInfoDto)
+ .toList();
+ List supportInfoDtoList = supportInfoList.stream()
+ .map(CalendarConverter::toCalendarSupportInfoDto)
+ .toList();
+
+ return CalendarDto.CalendarMonthInfoDto.builder()
+ .discountInfoDtoList(discountInfoDtoList)
+ .supportInfoDtoList(supportInfoDtoList)
+ .build();
+ }
+
+ public static CalendarDto.CalendarDiscountInfoDto toCalendarDiscountInfoDto(DiscountInfo discountInfo) {
+ return CalendarDto.CalendarDiscountInfoDto.builder()
+ .id(discountInfo.getId())
+ .title(discountInfo.getTitle())
+ .likeCount(discountInfo.getLikeCount())
+ .startDate(discountInfo.getStartDate())
+ .endDate(discountInfo.getEndDate())
+ .discountRate(discountInfo.getDiscountRate())
+ .build();
+ }
+
+ public static CalendarDto.CalendarSupportInfoDto toCalendarSupportInfoDto(SupportInfo supportInfo) {
+ return CalendarDto.CalendarSupportInfoDto.builder()
+ .id(supportInfo.getId())
+ .title(supportInfo.getTitle())
+ .likeCount(supportInfo.getLikeCount())
+ .startDate(supportInfo.getStartDate())
+ .endDate(supportInfo.getEndDate())
+ .build();
+ }
+
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/calendar/dto/CalendarDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/calendar/dto/CalendarDto.java
new file mode 100644
index 00000000..78f6ccf7
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/calendar/dto/CalendarDto.java
@@ -0,0 +1,48 @@
+package com.bbteam.budgetbuddies.domain.calendar.dto;
+
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+public class CalendarDto {
+
+ @Getter
+ @Builder
+ public static class CalendarMonthResponseDto {
+ CalendarMonthInfoDto calendarMonthInfoDto;
+ CalendarMonthInfoDto recommendMonthInfoDto;
+ }
+
+ @Getter
+ @Builder
+ public static class CalendarMonthInfoDto {
+ private List discountInfoDtoList;
+ private List supportInfoDtoList;
+ }
+
+ @Getter
+ @Builder
+ @EqualsAndHashCode
+ public static class CalendarDiscountInfoDto {
+ private Long id;
+ private String title;
+ private LocalDate startDate;
+ private LocalDate endDate;
+ private Integer likeCount;
+ private Integer discountRate;
+ }
+
+ @Getter
+ @Builder
+ @EqualsAndHashCode
+ public static class CalendarSupportInfoDto {
+ private Long id;
+ private String title;
+ private LocalDate startDate;
+ private LocalDate endDate;
+ private Integer likeCount;
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/calendar/service/CalendarService.java b/src/main/java/com/bbteam/budgetbuddies/domain/calendar/service/CalendarService.java
new file mode 100644
index 00000000..bb4383c3
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/calendar/service/CalendarService.java
@@ -0,0 +1,9 @@
+package com.bbteam.budgetbuddies.domain.calendar.service;
+
+import com.bbteam.budgetbuddies.domain.calendar.dto.CalendarDto;
+
+public interface CalendarService {
+
+ CalendarDto.CalendarMonthResponseDto find(int year, int month);
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/calendar/service/CalendarServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/calendar/service/CalendarServiceImpl.java
new file mode 100644
index 00000000..bd543261
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/calendar/service/CalendarServiceImpl.java
@@ -0,0 +1,49 @@
+package com.bbteam.budgetbuddies.domain.calendar.service;
+
+import com.bbteam.budgetbuddies.domain.calendar.converter.CalendarConverter;
+import com.bbteam.budgetbuddies.domain.calendar.dto.CalendarDto;
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.discountinfo.repository.DiscountInfoRepository;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import com.bbteam.budgetbuddies.domain.supportinfo.repository.SupportInfoRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Service
+@Transactional(readOnly = true)
+@RequiredArgsConstructor
+public class CalendarServiceImpl implements CalendarService{
+
+ private final DiscountInfoRepository discountInfoRepository;
+
+ private final SupportInfoRepository supportInfoRepository;
+
+ public CalendarDto.CalendarMonthResponseDto find(int year, int month){
+ LocalDate firstDay = LocalDate.of(year, month, 1);
+ LocalDate lastDay = firstDay.withDayOfMonth(firstDay.lengthOfMonth());
+ CalendarDto.CalendarMonthResponseDto result = getCalendarMonthResponseDto(firstDay, lastDay);
+ return result;
+ }
+
+ private CalendarDto.CalendarMonthResponseDto getCalendarMonthResponseDto(LocalDate firstDay, LocalDate lastDay) {
+ CalendarDto.CalendarMonthInfoDto calendarMonthInfoDto = getCalendarMonthInfoDto(firstDay, lastDay);
+ CalendarDto.CalendarMonthInfoDto recommendMonthInfoDto = getRecommendMonthInfoDto(firstDay, lastDay);
+ return CalendarConverter.toCalendarMonthResponseDto(calendarMonthInfoDto, recommendMonthInfoDto);
+ }
+
+ private CalendarDto.CalendarMonthInfoDto getCalendarMonthInfoDto(LocalDate firstDay, LocalDate lastDay) {
+ List monthDiscountInfoList = discountInfoRepository.findByMonth(firstDay, lastDay);
+ List monthSupportInfoList = supportInfoRepository.findByMonth(firstDay, lastDay);
+ return CalendarConverter.toCalendarMonthInfoDto(monthDiscountInfoList, monthSupportInfoList);
+ }
+
+ private CalendarDto.CalendarMonthInfoDto getRecommendMonthInfoDto(LocalDate firstDay, LocalDate lastDay) {
+ List recommendDiscountInfoList = discountInfoRepository.findRecommendInfoByMonth(firstDay, lastDay);
+ List recommendSupportInfoList = supportInfoRepository.findRecommendInfoByMonth(firstDay, lastDay);
+ return CalendarConverter.toCalendarMonthInfoDto(recommendDiscountInfoList, recommendSupportInfoList);
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/controller/CategoryController.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/controller/CategoryController.java
new file mode 100644
index 00000000..beb16f89
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/controller/CategoryController.java
@@ -0,0 +1,38 @@
+package com.bbteam.budgetbuddies.domain.category.controller;
+
+import com.bbteam.budgetbuddies.domain.category.dto.CategoryRequestDTO;
+import com.bbteam.budgetbuddies.domain.category.dto.CategoryResponseDTO;
+import com.bbteam.budgetbuddies.domain.category.service.CategoryService;
+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 lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/categories")
+public class CategoryController {
+
+ private final CategoryService categoryService;
+
+ @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))),
+ @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)))
+ })
+ @PostMapping("/add")
+ public ResponseEntity createCategory(
+ @Parameter(description = "user_id, name(사용자가 입력한 카테고리명), is_default(default 카테고리 여부)로 request")
+ @RequestBody CategoryRequestDTO categoryRequestDTO
+ ) {
+ CategoryResponseDTO response = categoryService.createCategory(categoryRequestDTO);
+ return ResponseEntity.ok(response);
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/controller/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/controller/package-info.java
deleted file mode 100644
index 3ed2cb13..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/category/controller/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.category.controller;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/converter/CategoryConverter.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/converter/CategoryConverter.java
new file mode 100644
index 00000000..69069b9d
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/converter/CategoryConverter.java
@@ -0,0 +1,28 @@
+package com.bbteam.budgetbuddies.domain.category.converter;
+
+import com.bbteam.budgetbuddies.domain.category.dto.CategoryRequestDTO;
+import com.bbteam.budgetbuddies.domain.category.dto.CategoryResponseDTO;
+import com.bbteam.budgetbuddies.domain.category.entity.Category;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CategoryConverter {
+
+ public Category toCategoryEntity(CategoryRequestDTO categoryRequestDTO, User user) {
+ return Category.builder()
+ .name(categoryRequestDTO.getName())
+ .isDefault(categoryRequestDTO.getIsDefault())
+ .user(user)
+ .build();
+ }
+
+ public CategoryResponseDTO toCategoryResponseDTO(Category category) {
+ return CategoryResponseDTO.builder()
+ .id(category.getId())
+ .name(category.getName())
+ .userId(category.getUser().getId())
+ .isDefault(category.getIsDefault())
+ .build();
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/dto/CategoryRequestDTO.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/dto/CategoryRequestDTO.java
new file mode 100644
index 00000000..3f8eee35
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/dto/CategoryRequestDTO.java
@@ -0,0 +1,12 @@
+package com.bbteam.budgetbuddies.domain.category.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CategoryRequestDTO {
+ private Long userId;
+ private String name;
+ private Boolean isDefault;
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/dto/CategoryResponseDTO.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/dto/CategoryResponseDTO.java
new file mode 100644
index 00000000..41381edb
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/dto/CategoryResponseDTO.java
@@ -0,0 +1,14 @@
+package com.bbteam.budgetbuddies.domain.category.dto;
+
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class CategoryResponseDTO {
+ private Long id;
+ private Long userId;
+ private String name;
+ private Boolean isDefault;
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/dto/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/dto/package-info.java
deleted file mode 100644
index 54a5f6c4..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/category/dto/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.category.dto;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/entity/Category.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/entity/Category.java
index 366167ef..b25530f3 100644
--- a/src/main/java/com/bbteam/budgetbuddies/domain/category/entity/Category.java
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/entity/Category.java
@@ -3,9 +3,17 @@
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 org.hibernate.annotations.ColumnDefault;
@Entity
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
public class Category {
@Id
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/repository/CategoryRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/repository/CategoryRepository.java
new file mode 100644
index 00000000..c6b571bb
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/repository/CategoryRepository.java
@@ -0,0 +1,16 @@
+package com.bbteam.budgetbuddies.domain.category.repository;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import com.bbteam.budgetbuddies.domain.category.entity.Category;
+
+public interface CategoryRepository extends JpaRepository {
+ @Query(value = "SELECT c FROM Category AS c WHERE c.isDefault=TRUE OR c.user.id=:id")
+ List findUserCategoryByUserId(@Param("id") Long id);
+
+ boolean existsByUserIdAndName(Long userId, String name);
+}
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/repository/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/repository/package-info.java
deleted file mode 100644
index 995bc7a0..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/category/repository/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.category.repository;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryService.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryService.java
new file mode 100644
index 00000000..352b64c6
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryService.java
@@ -0,0 +1,9 @@
+package com.bbteam.budgetbuddies.domain.category.service;
+
+import com.bbteam.budgetbuddies.domain.category.dto.CategoryRequestDTO;
+import com.bbteam.budgetbuddies.domain.category.dto.CategoryResponseDTO;
+
+public interface CategoryService {
+ CategoryResponseDTO createCategory(CategoryRequestDTO categoryRequestDTO);
+}
+
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java
new file mode 100644
index 00000000..52b26658
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java
@@ -0,0 +1,38 @@
+package com.bbteam.budgetbuddies.domain.category.service;
+
+import com.bbteam.budgetbuddies.domain.category.converter.CategoryConverter;
+import com.bbteam.budgetbuddies.domain.category.dto.CategoryRequestDTO;
+import com.bbteam.budgetbuddies.domain.category.dto.CategoryResponseDTO;
+import com.bbteam.budgetbuddies.domain.category.entity.Category;
+import com.bbteam.budgetbuddies.domain.category.repository.CategoryRepository;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import com.bbteam.budgetbuddies.domain.user.repository.UserRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+@Transactional
+public class CategoryServiceImpl implements CategoryService {
+
+ private final CategoryRepository categoryRepository;
+ private final UserRepository userRepository;
+ private final CategoryConverter categoryConverter;
+
+ @Override
+ public CategoryResponseDTO createCategory(CategoryRequestDTO categoryRequestDTO) {
+ User user = userRepository.findById(categoryRequestDTO.getUserId())
+ .orElseThrow(() -> new IllegalArgumentException("cannot find user"));
+
+ if (categoryRepository.existsByUserIdAndName(categoryRequestDTO.getUserId(), categoryRequestDTO.getName())) {
+ throw new IllegalArgumentException("User already has a category with the same name");
+ }
+
+
+ Category category = categoryConverter.toCategoryEntity(categoryRequestDTO, user);
+ Category savedCategory = categoryRepository.save(category);
+
+ return categoryConverter.toCategoryResponseDTO(savedCategory);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/package-info.java
deleted file mode 100644
index 69cdabf3..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.category.service;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/controller/CommentController.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/controller/CommentController.java
new file mode 100644
index 00000000..36500a8b
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/comment/controller/CommentController.java
@@ -0,0 +1,83 @@
+package com.bbteam.budgetbuddies.domain.comment.controller;
+
+
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentRequestDto;
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentResponseDto;
+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.responses.ApiResponses;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PageableDefault;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+
+public interface CommentController {
+ @Operation(summary = "[User] 특정 할인 정보 게시글에 댓글달기", description = "특정 할인 정보 게시글에 댓글을 다는 API입니다.")
+ @ApiResponses({
+ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
+ })
+ @Parameters({
+ @Parameter(name = "userId", description = "현재 댓글을 다는 유저 id입니다. parameter"),
+ @Parameter(name = "discountInfoId", description = "댓글을 다는 할인 정보 게시글 id입니다. requestBody"),
+ @Parameter(name = "content", description = "댓글 내용입니다. requestBody"),
+ })
+ ResponseEntity saveDiscountInfoComment(
+ Long userId,
+ CommentRequestDto.DiscountInfoCommentDto discountInfoCommentDto);
+
+
+ @Operation(summary = "[User] 특정 할인 정보 게시글의 댓글 조회하기", description = "특정 할인 정보 게시글의 댓글을 가져오는 API입니다.")
+ @ApiResponses({
+ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
+ })
+ @Parameters({
+ @Parameter(name = "discountInfoId", description = "댓글을 가져올 할인 정보 게시글 id입니다. parameter"),
+ @Parameter(name = "page", description = "페이징을 위한 페이지 번호입니다. 0부터 시작합니다. parameter"),
+ @Parameter(name = "size", description = "페이징을 위한 페이지 사이즈입니다. default는 20입니다. parameter")
+ })
+ ResponseEntity> findAllByDiscountInfo(
+ Long discountInfoId,
+ Pageable pageable);
+
+ @Operation(summary = "[User] 특정 지원 정보 게시글에 댓글달기", description = "특정 지원 정보 게시글에 댓글을 다는 API입니다.")
+ @ApiResponses({
+ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
+ })
+ @Parameters({
+ @Parameter(name = "userId", description = "현재 댓글을 다는 유저 id입니다. parameter"),
+ @Parameter(name = "supportInfoId", description = "댓글을 다는 지원 정보 게시글 id입니다. requestBody"),
+ @Parameter(name = "content", description = "댓글 내용입니다. requestBody"),
+ })
+ ResponseEntity saveSupportInfoComment(
+ Long userId,
+ CommentRequestDto.SupportInfoCommentDto supportInfoCommentDto);
+
+ @Operation(summary = "[User] 특정 지원 정보 게시글의 댓글 조회하기", description = "특정 지원 정보 게시글의 댓글을 가져오는 API입니다.")
+ @ApiResponses({
+ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
+ })
+ @Parameters({
+ @Parameter(name = "supportInfoId", description = "댓글을 가져올 지원 정보 게시글 id입니다. parameter"),
+ @Parameter(name = "page", description = "페이징을 위한 페이지 번호입니다. 0부터 시작합니다. parameter"),
+ @Parameter(name = "size", description = "페이징을 위한 페이지 사이즈입니다. default는 20입니다. parameter")
+
+
+ })
+ ResponseEntity> findAllBySupportInfo(
+ Long supportInfoId,
+ Pageable pageable);
+
+ @Operation(summary = "[User] 특정 댓글 삭제하기", description = "특정 댓글을 삭제하는 API입니다.")
+ @ApiResponses({
+ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
+ })
+ @Parameters({
+ @Parameter(name = "commentId", description = "삭제할 댓글 id 입니다. parameter")
+ })
+ @GetMapping("/comments/delete")
+ ResponseEntity deleteComment(Long commentId);
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/controller/CommentControllerImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/controller/CommentControllerImpl.java
new file mode 100644
index 00000000..8f9691d7
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/comment/controller/CommentControllerImpl.java
@@ -0,0 +1,60 @@
+package com.bbteam.budgetbuddies.domain.comment.controller;
+
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentRequestDto;
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentResponseDto;
+import com.bbteam.budgetbuddies.domain.comment.service.CommentService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PageableDefault;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequiredArgsConstructor
+public class CommentControllerImpl implements CommentController{
+
+ private final CommentService commentService;
+
+ @PostMapping("/discounts/comments")
+ public ResponseEntity saveDiscountInfoComment(
+ @RequestParam("userId") Long userId,
+ @RequestBody CommentRequestDto.DiscountInfoCommentDto discountInfoCommentDto){
+ CommentResponseDto.DiscountInfoSuccessDto dto = commentService.saveDiscountComment(userId, discountInfoCommentDto);
+ return ResponseEntity.ok(dto);
+ }
+
+
+ @GetMapping("/discounts/comments")
+ public ResponseEntity> findAllByDiscountInfo(
+ @RequestParam("discountInfoId") Long discountInfoId,
+ @PageableDefault(size = 20, page = 0) Pageable pageable){
+ Page result = commentService.findByDiscountInfoWithPaging(discountInfoId, pageable);
+ return ResponseEntity.ok(result);
+ }
+
+
+ @PostMapping("/supports/comments")
+ public ResponseEntity saveSupportInfoComment(
+ @RequestParam("userId") Long userId,
+ @RequestBody CommentRequestDto.SupportInfoCommentDto supportInfoCommentDto){
+ CommentResponseDto.SupportInfoSuccessDto dto = commentService.saveSupportComment(userId, supportInfoCommentDto);
+ return ResponseEntity.ok(dto);
+ }
+
+
+ @GetMapping("/supports/comments")
+ public ResponseEntity> findAllBySupportInfo(
+ @RequestParam("supportInfoId") Long supportInfoId,
+ @PageableDefault(size = 20, page = 0)Pageable pageable){
+ Page result = commentService.findBySupportInfoWithPaging(supportInfoId, pageable);
+ return ResponseEntity.ok(result);
+ }
+
+
+ public ResponseEntity deleteComment(@RequestParam("commentId") Long commentId) {
+ commentService.deleteComment(commentId);
+ return ResponseEntity.ok("ok");
+ }
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/controller/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/controller/package-info.java
deleted file mode 100644
index 6a816c5b..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/comment/controller/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.comment.controller;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/converter/CommentConverter.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/converter/CommentConverter.java
new file mode 100644
index 00000000..626a1e6f
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/comment/converter/CommentConverter.java
@@ -0,0 +1,72 @@
+package com.bbteam.budgetbuddies.domain.comment.converter;
+
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentRequestDto;
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentResponseDto;
+import com.bbteam.budgetbuddies.domain.comment.entity.Comment;
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+
+public class CommentConverter {
+
+ public static Comment toDiscountComment(CommentRequestDto.DiscountInfoCommentDto dto, User user, DiscountInfo discountInfo,
+ Integer anonymousNumber) {
+ return Comment.builder()
+ .user(user)
+ .discountInfo(discountInfo)
+ .content(dto.getContent())
+ .anonymousNumber(anonymousNumber)
+ .build();
+ }
+
+ public static Comment toSupportComment(CommentRequestDto.SupportInfoCommentDto dto, User user, SupportInfo supportInfo,
+ Integer anonymousNumber) {
+ return Comment.builder()
+ .user(user)
+ .supportInfo(supportInfo)
+ .content(dto.getContent())
+ .anonymousNumber(anonymousNumber)
+ .build();
+ }
+
+ public static CommentResponseDto.DiscountInfoCommentDto toDiscountInfoCommentDto(Comment comment){
+ return CommentResponseDto.DiscountInfoCommentDto.builder()
+ .commentId(comment.getId())
+ .discountInfoId(comment.getDiscountInfo().getId())
+ .userId(comment.getUser().getId())
+ .content(comment.getContent())
+ .anonymousNumber(comment.getAnonymousNumber())
+ .build();
+
+ }
+
+ public static CommentResponseDto.SupportInfoCommentDto toSupportInfoCommentDto(Comment comment){
+ return CommentResponseDto.SupportInfoCommentDto.builder()
+ .commentId(comment.getId())
+ .supportInfoId(comment.getSupportInfo().getId())
+ .userId(comment.getUser().getId())
+ .content(comment.getContent())
+ .anonymousNumber(comment.getAnonymousNumber())
+ .build();
+
+ }
+
+ public static CommentResponseDto.DiscountInfoSuccessDto toDiscountInfoSuccessDto(Comment comment){
+ return CommentResponseDto.DiscountInfoSuccessDto.builder()
+ .commentId(comment.getId())
+ .discountInfoId(comment.getDiscountInfo().getId())
+ .userId(comment.getUser().getId())
+ .content(comment.getContent())
+ .build();
+ }
+
+ public static CommentResponseDto.SupportInfoSuccessDto toSupportInfoSuccessDto(Comment comment){
+ return CommentResponseDto.SupportInfoSuccessDto.builder()
+ .commentId(comment.getId())
+ .supportInfoId(comment.getSupportInfo().getId())
+ .userId(comment.getUser().getId())
+ .content(comment.getContent())
+ .build();
+ }
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/dto/CommentRequestDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/dto/CommentRequestDto.java
new file mode 100644
index 00000000..45b91e8e
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/comment/dto/CommentRequestDto.java
@@ -0,0 +1,22 @@
+package com.bbteam.budgetbuddies.domain.comment.dto;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+
+public class CommentRequestDto {
+ @Getter
+ @Builder
+ public static class DiscountInfoCommentDto {
+ private String content;
+ private Long discountInfoId;
+ }
+
+ @Getter
+ @Builder
+ public static class SupportInfoCommentDto {
+ private String content;
+ private Long supportInfoId;
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/dto/CommentResponseDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/dto/CommentResponseDto.java
new file mode 100644
index 00000000..bfc27405
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/comment/dto/CommentResponseDto.java
@@ -0,0 +1,47 @@
+package com.bbteam.budgetbuddies.domain.comment.dto;
+
+
+import lombok.Builder;
+import lombok.Getter;
+
+public class CommentResponseDto {
+
+ @Getter
+ @Builder
+ public static class DiscountInfoCommentDto{
+ private Long commentId;
+ private Long userId;
+ private Long discountInfoId;
+ private String content;
+ private Integer anonymousNumber;
+ }
+
+ @Getter
+ @Builder
+ public static class SupportInfoCommentDto{
+ private Long commentId;
+ private Long userId;
+ private Long supportInfoId;
+ private String content;
+ private Integer anonymousNumber;
+ }
+
+ @Getter
+ @Builder
+ public static class DiscountInfoSuccessDto{
+ private Long commentId;
+ private Long userId;
+ private Long discountInfoId;
+ private String content;
+ }
+
+ @Getter
+ @Builder
+ public static class SupportInfoSuccessDto{
+ private Long commentId;
+ private Long userId;
+ private Long supportInfoId;
+ private String content;
+ }
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/entity/Comment.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/entity/Comment.java
index 43918096..49dbf6dd 100644
--- a/src/main/java/com/bbteam/budgetbuddies/domain/comment/entity/Comment.java
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/comment/entity/Comment.java
@@ -10,6 +10,8 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
+import org.hibernate.annotations.Where;
+import org.springframework.lang.Nullable;
@Entity
@Getter
@@ -21,16 +23,19 @@ public class Comment extends BaseEntity {
@Column(nullable = false, length = 1000)
private String content;
- @ManyToOne(fetch = FetchType.EAGER)
+ @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
- @ManyToOne(fetch = FetchType.EAGER)
+ @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "discount_info_id")
private DiscountInfo discountInfo;
- @ManyToOne(fetch = FetchType.EAGER)
+ @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "support_info_id")
private SupportInfo supportInfo;
+ @Column(nullable = false)
+ private Integer anonymousNumber;
+
}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/repository/CommentRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/repository/CommentRepository.java
new file mode 100644
index 00000000..b734eca7
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/comment/repository/CommentRepository.java
@@ -0,0 +1,38 @@
+package com.bbteam.budgetbuddies.domain.comment.repository;
+
+import com.bbteam.budgetbuddies.domain.comment.entity.Comment;
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface CommentRepository extends JpaRepository {
+ @Query("select c from Comment c where c.discountInfo.id = :discountInfoId" +
+ " order by c.createdAt asc") // 익명번호 부여용
+ List findByDiscountInfo(@Param("discountInfoId")Long discountInfoId);
+
+ @Query("select c from Comment c where c.discountInfo.id = :discountInfoId" +
+ " order by c.createdAt asc")
+ Page findByDiscountInfoWithPaging(@Param("discountInfoId")Long discountInfoId,
+ Pageable pageable);
+
+ @Query("select c from Comment c where c.supportInfo.id = :supportInfoId" +
+ " order by c.createdAt asc")
+ List findBySupportInfo(@Param("supportInfoId")Long supportInfoId);
+
+ @Query("select c from Comment c where c.supportInfo.id = :supportInfoId" +
+ " order by c.createdAt asc")
+ Page findBySupportInfoWithPaging(@Param("supportInfoId")Long supportInfoId,
+ Pageable pageable);
+
+ Optional findTopByUserAndDiscountInfo(User user, DiscountInfo discountInfo);
+ Optional findTopByUserAndSupportInfo(User user, SupportInfo supportInfo);
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/repository/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/repository/package-info.java
deleted file mode 100644
index 4d31a705..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/comment/repository/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.comment.repository;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/service/CommentService.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/service/CommentService.java
new file mode 100644
index 00000000..ac49bc5a
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/comment/service/CommentService.java
@@ -0,0 +1,40 @@
+package com.bbteam.budgetbuddies.domain.comment.service;
+
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentRequestDto;
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentResponseDto;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+import java.util.List;
+
+public interface CommentService {
+ CommentResponseDto.SupportInfoSuccessDto saveSupportComment(Long userId, CommentRequestDto.SupportInfoCommentDto dto);
+ CommentResponseDto.DiscountInfoSuccessDto saveDiscountComment(Long userId, CommentRequestDto.DiscountInfoCommentDto dto);
+
+
+ /**
+ *
+ * @param discountInfoId
+ * @return List
+ * 해당 로직은 익명 구분을 위한 익명 구분 숫자도 같이 return 합니다.
+ */
+ List findByDiscountInfo(Long discountInfoId);
+
+ /**
+ *
+ * @param supportInfoId
+ * @return List
+ * 해당 로직은 익명 구분을 위한 익명 구분 숫자도 같이 return 합니다.
+ */
+ List findBySupportInfo(Long supportInfoId);
+
+ Page findByDiscountInfoWithPaging(Long discountInfoId, Pageable pageable);
+ Page findBySupportInfoWithPaging(Long supportInfoId, Pageable pageable);
+
+ void deleteComment(Long commentId);
+
+
+
+
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/service/CommentServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/service/CommentServiceImpl.java
new file mode 100644
index 00000000..df8063fa
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/comment/service/CommentServiceImpl.java
@@ -0,0 +1,140 @@
+package com.bbteam.budgetbuddies.domain.comment.service;
+
+
+import com.bbteam.budgetbuddies.domain.comment.converter.CommentConverter;
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentRequestDto;
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentResponseDto;
+import com.bbteam.budgetbuddies.domain.comment.entity.Comment;
+import com.bbteam.budgetbuddies.domain.comment.repository.CommentRepository;
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.discountinfo.repository.DiscountInfoRepository;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import com.bbteam.budgetbuddies.domain.supportinfo.repository.SupportInfoRepository;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import com.bbteam.budgetbuddies.domain.user.repository.UserRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+// 임시로 유저는 service에서 찾아서 처리하는 로직으로 작성함
+@Service
+@Transactional(readOnly = true)
+@RequiredArgsConstructor
+public class CommentServiceImpl implements CommentService{
+
+ private final CommentRepository commentRepository;
+ private final UserRepository userRepository;
+ private final DiscountInfoRepository discountInfoRepository;
+ private final SupportInfoRepository supportInfoRepository;
+
+ @Override
+ @Transactional
+ public CommentResponseDto.SupportInfoSuccessDto saveSupportComment(Long userId, CommentRequestDto.SupportInfoCommentDto dto) {
+ User user = userRepository.findById(userId).orElseThrow(() -> new NoSuchElementException("유저 존재 x"));
+ SupportInfo supportInfo = supportInfoRepository.findById(dto.getSupportInfoId()).orElseThrow(() -> new NoSuchElementException());
+ int anonymousNumber = getSupportAnonymousNumber(user, supportInfo);
+ Comment comment = CommentConverter.toSupportComment(dto, user, supportInfo, anonymousNumber);
+ Comment savedComment = commentRepository.save(comment);
+
+ return CommentConverter.toSupportInfoSuccessDto(savedComment);
+ }
+
+ private int getSupportAnonymousNumber(User user, SupportInfo supportInfo) {
+ int anonymousNumber;
+ Optional foundComment = commentRepository.findTopByUserAndSupportInfo(user, supportInfo);
+ if(foundComment.isEmpty()){
+ anonymousNumber = supportInfo.addAndGetAnonymousNumber();
+ } else {
+ anonymousNumber = foundComment.get().getAnonymousNumber();
+ }
+ return anonymousNumber;
+ }
+
+
+ @Override
+ @Transactional
+ public CommentResponseDto.DiscountInfoSuccessDto saveDiscountComment(Long userId, CommentRequestDto.DiscountInfoCommentDto dto) {
+ User user = userRepository.findById(userId).orElseThrow(() -> new NoSuchElementException("유저 존재 x"));
+ DiscountInfo discountInfo = discountInfoRepository.findById(dto.getDiscountInfoId()).orElseThrow(() -> new NoSuchElementException());
+ int anonymousNumber = getDiscountAnonymousNumber(user, discountInfo);
+ Comment comment = CommentConverter.toDiscountComment(dto, user, discountInfo, anonymousNumber);
+ Comment savedComment = commentRepository.save(comment);
+
+ return CommentConverter.toDiscountInfoSuccessDto(savedComment);
+ }
+
+ private int getDiscountAnonymousNumber(User user, DiscountInfo discountInfo) {
+ int anonymousNumber;
+ Optional foundComment = commentRepository.findTopByUserAndDiscountInfo(user, discountInfo);
+ if(foundComment.isEmpty()){
+ anonymousNumber = discountInfo.addAndGetAnonymousNumber();
+ } else {
+ anonymousNumber = foundComment.get().getAnonymousNumber();
+ }
+ return anonymousNumber;
+ }
+
+ @Override
+ public List findByDiscountInfo(Long discountInfoId) {
+ List commentList = commentRepository.findByDiscountInfo(discountInfoId);
+
+ HashMap anonymousMapping = countAnonymousNumber(commentList);
+ List collect = commentList.stream()
+ .map(CommentConverter::toDiscountInfoCommentDto)
+ .collect(Collectors.toList());
+ return collect;
+
+ }
+
+ @Override
+ public List findBySupportInfo(Long supportInfoId) {
+ List commentList = commentRepository.findBySupportInfo(supportInfoId);
+ HashMap anonymousMapping = countAnonymousNumber(commentList);
+ List collect = commentList.stream()
+ .map(CommentConverter::toSupportInfoCommentDto)
+ .collect(Collectors.toList());
+ return collect;
+ }
+
+ private static HashMap countAnonymousNumber(List commentList) {
+ HashMap anonymousMapping = new HashMap<>();
+ Long count = 1L;
+ for (Comment comment : commentList) {
+ Long id = comment.getUser().getId();
+ if(!anonymousMapping.containsKey(id)){
+ anonymousMapping.put(id, count);
+ count++;
+ }
+ }
+ return anonymousMapping;
+ }
+
+ @Override
+ public Page findByDiscountInfoWithPaging(Long discountInfoId, Pageable pageable) {
+ Page commentPage = commentRepository.findByDiscountInfoWithPaging(discountInfoId, pageable);
+ Page result = commentPage.map(CommentConverter::toDiscountInfoCommentDto);
+ return result;
+ }
+
+ @Override
+ public Page findBySupportInfoWithPaging(Long supportInfoId, Pageable pageable) {
+ Page commentPage = commentRepository.findBySupportInfoWithPaging(supportInfoId, pageable);
+ Page result = commentPage.map(CommentConverter::toSupportInfoCommentDto);
+ return result;
+ }
+
+ @Override
+ @Transactional
+ public void deleteComment(Long commentId) {
+ Comment comment = commentRepository.findById(commentId).orElseThrow(() -> new NoSuchElementException("No such id"));
+ commentRepository.delete(comment);
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/comment/service/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/comment/service/package-info.java
deleted file mode 100644
index 4ffc9ed9..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/comment/service/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.comment.service;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java
new file mode 100644
index 00000000..c13498b5
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java
@@ -0,0 +1,43 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.controller;
+
+import java.time.LocalDate;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalListRequestDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseListDto;
+
+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.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+
+public interface ConsumptionGoalApi {
+ @Operation(summary = "또래들이 가장 큰 계획을 세운 카테고리 조회 API", description = "특정 사용자의 소비 목표 카테고리별 소비 목표 금액을 조회하는 API 입니다.")
+ @ApiResponses(value = {@ApiResponse(responseCode = "COMMON200", description = "OK, 성공")})
+ @Parameters({@Parameter(name = "top", description = "가장 큰 목표를 세운 카테고리의 개수를 지정합니다. (기본값은 5입니다)"),
+ @Parameter(name = "userId", description = "로그인 한 유저 아이디"),
+ @Parameter(name = "peerAgeStart", description = "또래나이 시작 범위"),
+ @Parameter(name = "peerAgeEnd", description = "또래나이 끝 범위"),
+ @Parameter(name = "peerGender", description = "또래 성별")})
+ ResponseEntity> getTopGoalCategories(@RequestParam(name = "top", defaultValue = "5") int top, Long userId,
+ int peerAgeStart, int peerAgeEnd, String peerGender);
+
+ @Operation(summary = "소비 목표 조회 API", description = "date={yyyy-MM-dd} 형식의 query string을 통해서 사용자의 목표 달을 조회하는 API 입니다.")
+ @Parameters({@Parameter(name = "date", description = "yyyy-MM-dd 형식으로 목표 달의 소비를 조회")})
+ ResponseEntity findUserConsumptionGoal(LocalDate date, Long userId);
+
+ @Operation(summary = "또래나이와 성별 조회 API", description = "또래나이와 성별을 조회하는 API 입니다.")
+ @ApiResponses(value = {@ApiResponse(responseCode = "COMMON200", description = "OK, 성공")})
+ @Parameters({@Parameter(name = "userId", description = "로그인 한 유저 아이디"),
+ @Parameter(name = "peerAgeStart", description = "또래나이 시작 범위"),
+ @Parameter(name = "peerAgeEnd", description = "또래나이 끝 범위"),
+ @Parameter(name = "peerGender", description = "또래 성별")})
+ ResponseEntity> getPeerInfo(Long userId, int peerAgeStart, int peerAgeEnd, String peerGender);
+
+ @Operation(summary = "이번 달 소비 목표 수정 API", description = "다른 달의 소비 목표를 업데이트하는 것은 불가능하고 오직 이번 달의 소비 목표만 업데이트 하는 API 입니다.")
+ ResponseEntity updateOrElseGenerateConsumptionGoal(Long userId,
+ ConsumptionGoalListRequestDto consumptionGoalListRequestDto);
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java
new file mode 100644
index 00000000..53c9330f
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java
@@ -0,0 +1,67 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.controller;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import org.springframework.format.annotation.DateTimeFormat;
+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.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalListRequestDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseListDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.PeerInfoResponseDTO;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopGoalCategoryResponseDTO;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.service.ConsumptionGoalService;
+
+import lombok.RequiredArgsConstructor;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/consumption-goal")
+public class ConsumptionGoalController implements ConsumptionGoalApi {
+
+ private final ConsumptionGoalService consumptionGoalService;
+
+ @GetMapping("/top-categories")
+ public ResponseEntity> getTopGoalCategories(@RequestParam(name = "top", defaultValue = "5") int top,
+ @RequestParam(name = "userId") Long userId,
+ @RequestParam(name = "peerAgeStart", defaultValue = "0") int peerAgeStart,
+ @RequestParam(name = "peerAgeEnd", defaultValue = "0") int peerAgeEnd,
+ @RequestParam(name = "peerGender", defaultValue = "none") String peerGender) {
+ List topCategory = consumptionGoalService.getTopGoalCategories(top, userId,
+ peerAgeStart, peerAgeEnd, peerGender);
+ return ResponseEntity.ok(topCategory);
+ }
+
+ @GetMapping("/{userId}")
+ public ResponseEntity findUserConsumptionGoal(
+ @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date, @PathVariable Long userId) {
+
+ ConsumptionGoalResponseListDto response = consumptionGoalService.findUserConsumptionGoal(userId, date);
+
+ return ResponseEntity.ok(response);
+ }
+
+ @GetMapping("/peer-info")
+ public ResponseEntity> getPeerInfo(@RequestParam(name = "userId") Long userId,
+ @RequestParam(name = "peerAgeStart", defaultValue = "0") int peerAgeStart,
+ @RequestParam(name = "peerAgeEnd", defaultValue = "0") int peerAgeEnd,
+ @RequestParam(name = "peerGender", defaultValue = "none") String peerGender) {
+ PeerInfoResponseDTO response = consumptionGoalService.getPeerInfo(userId, peerAgeStart, peerAgeEnd, peerGender);
+ return ResponseEntity.ok(response);
+ }
+
+ @PostMapping("/{userId}")
+ public ResponseEntity updateOrElseGenerateConsumptionGoal(@PathVariable Long userId,
+ @RequestBody ConsumptionGoalListRequestDto consumptionGoalListRequestDto) {
+
+ return ResponseEntity.ok()
+ .body(consumptionGoalService.updateConsumptionGoals(userId, consumptionGoalListRequestDto));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/package-info.java
deleted file mode 100644
index c4780977..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.consumptiongoal.controller;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/ConsumptionGoalConverter.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/ConsumptionGoalConverter.java
new file mode 100644
index 00000000..a2c835cc
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/ConsumptionGoalConverter.java
@@ -0,0 +1,28 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.converter;
+
+import org.springframework.stereotype.Component;
+
+import com.bbteam.budgetbuddies.domain.category.entity.Category;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal;
+
+@Component
+public class ConsumptionGoalConverter {
+ public ConsumptionGoalResponseDto toConsumptionGoalResponseDto(Category category) {
+ return ConsumptionGoalResponseDto.builder()
+ .categoryName(category.getName())
+ .categoryId(category.getId())
+ .goalAmount(0L)
+ .consumeAmount(0L)
+ .build();
+ }
+
+ public ConsumptionGoalResponseDto toConsumptionGoalResponseDto(ConsumptionGoal consumptionGoal) {
+ return ConsumptionGoalResponseDto.builder()
+ .categoryName(consumptionGoal.getCategory().getName())
+ .categoryId(consumptionGoal.getCategory().getId())
+ .goalAmount(consumptionGoal.getGoalAmount())
+ .consumeAmount(consumptionGoal.getConsumeAmount())
+ .build();
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/PeerInfoConverter.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/PeerInfoConverter.java
new file mode 100644
index 00000000..d6c3eb24
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/PeerInfoConverter.java
@@ -0,0 +1,16 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.converter;
+
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.PeerInfoResponseDTO;
+import com.bbteam.budgetbuddies.enums.Gender;
+
+public class PeerInfoConverter {
+
+ public static PeerInfoResponseDTO fromEntity(int peerAgeStart, int peerAgeEnd, Gender peerGender) {
+
+ return PeerInfoResponseDTO.builder()
+ .peerAgeStart(peerAgeStart)
+ .peerAgeEnd(peerAgeEnd)
+ .peerGender(peerGender.name())
+ .build();
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/TopCategoryConverter.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/TopCategoryConverter.java
new file mode 100644
index 00000000..239dc8da
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/TopCategoryConverter.java
@@ -0,0 +1,21 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.converter;
+
+import org.springframework.stereotype.Component;
+
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopGoalCategoryResponseDTO;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal;
+
+@Component
+public class TopCategoryConverter {
+
+ public static TopGoalCategoryResponseDTO fromEntity(ConsumptionGoal consumptionGoal) {
+ if (consumptionGoal == null || consumptionGoal.getCategory() == null) {
+ return null;
+ }
+
+ return TopGoalCategoryResponseDTO.builder()
+ .categoryName(consumptionGoal.getCategory().getName())
+ .goalAmount(consumptionGoal.getGoalAmount())
+ .build();
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalListRequestDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalListRequestDto.java
new file mode 100644
index 00000000..a74c986f
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalListRequestDto.java
@@ -0,0 +1,15 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.dto;
+
+import java.util.List;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+@AllArgsConstructor
+public class ConsumptionGoalListRequestDto {
+ List consumptionGoalList;
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalRequestDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalRequestDto.java
new file mode 100644
index 00000000..da0463d7
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalRequestDto.java
@@ -0,0 +1,14 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.dto;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+@AllArgsConstructor
+public class ConsumptionGoalRequestDto {
+ private Long categoryId;
+ private Long goalAmount;
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalResponseDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalResponseDto.java
new file mode 100644
index 00000000..bd8aca1b
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalResponseDto.java
@@ -0,0 +1,20 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.dto;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+public class ConsumptionGoalResponseDto {
+ private String categoryName;
+ private Long categoryId;
+ private Long goalAmount;
+ private Long consumeAmount;
+
+ @Builder
+ public ConsumptionGoalResponseDto(String categoryName, Long categoryId, Long goalAmount, Long consumeAmount) {
+ this.categoryName = categoryName;
+ this.categoryId = categoryId;
+ this.goalAmount = goalAmount;
+ this.consumeAmount = consumeAmount;
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalResponseListDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalResponseListDto.java
new file mode 100644
index 00000000..e7f5a54e
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/ConsumptionGoalResponseListDto.java
@@ -0,0 +1,20 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.dto;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class ConsumptionGoalResponseListDto {
+ private LocalDate goalMonth;
+ private List consumptionGoalList;
+
+ public ConsumptionGoalResponseListDto(LocalDate goalMonth, List consumptionGoalList) {
+ this.goalMonth = goalMonth;
+ this.consumptionGoalList = consumptionGoalList;
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/PeerInfoResponseDTO.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/PeerInfoResponseDTO.java
new file mode 100644
index 00000000..3ac0d041
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/PeerInfoResponseDTO.java
@@ -0,0 +1,19 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PeerInfoResponseDTO {
+
+ private int peerAgeStart;
+
+ private int peerAgeEnd;
+
+ private String peerGender;
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/TopGoalCategoryResponseDTO.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/TopGoalCategoryResponseDTO.java
new file mode 100644
index 00000000..99c394b4
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/TopGoalCategoryResponseDTO.java
@@ -0,0 +1,18 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class TopGoalCategoryResponseDTO {
+
+ private String categoryName;
+
+ private Long goalAmount;
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/package-info.java
deleted file mode 100644
index 65ea60a1..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/dto/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.consumptiongoal.dto;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/entity/ConsumptionGoal.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/entity/ConsumptionGoal.java
index 932a9bf4..a0df97bc 100644
--- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/entity/ConsumptionGoal.java
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/entity/ConsumptionGoal.java
@@ -1,9 +1,16 @@
package com.bbteam.budgetbuddies.domain.consumptiongoal.entity;
+import java.time.LocalDate;
+
import com.bbteam.budgetbuddies.common.BaseEntity;
import com.bbteam.budgetbuddies.domain.category.entity.Category;
import com.bbteam.budgetbuddies.domain.user.entity.User;
-import jakarta.persistence.*;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
import jakarta.validation.constraints.Min;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
@@ -11,8 +18,6 @@
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
-import java.time.LocalDate;
-
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@@ -20,23 +25,26 @@
@SuperBuilder
public class ConsumptionGoal extends BaseEntity {
- @Column(nullable = false)
- @Min(value = 1, message = "0 또는 음수의 목표금액을 설정할 수 없습니다.")
- private Long goalAmount;
+ @Column(nullable = false)
+ @Min(value = 0, message = "음수의 목표금액을 설정할 수 없습니다.")
+ private Long goalAmount;
- @Column(nullable = false)
- @Min(value = 1, message = "0 또는 음수의 소비금액을 설정할 수 없습니다.")
- private Long consumeAmount;
+ @Column(nullable = false)
+ @Min(value = 0, message = "음수의 소비금액을 설정할 수 없습니다.")
+ private Long consumeAmount;
- @Column(nullable = false)
- private LocalDate goalMonth;
+ @Column(nullable = false)
+ private LocalDate goalMonth;
- @ManyToOne(fetch = FetchType.EAGER)
- @JoinColumn(name = "user_id")
- private User user;
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
- @ManyToOne(fetch = FetchType.EAGER)
- @JoinColumn(name = "category_id")
- private Category category;
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "category_id")
+ private Category category;
+ public void updateGoalAmount(Long goalAmount) {
+ this.goalAmount = goalAmount;
+ }
}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepository.java
new file mode 100644
index 00000000..34220a0b
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepository.java
@@ -0,0 +1,36 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.repository;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Optional;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import com.bbteam.budgetbuddies.domain.category.entity.Category;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import com.bbteam.budgetbuddies.enums.Gender;
+
+@Repository
+public interface ConsumptionGoalRepository extends JpaRepository {
+
+ @Query("SELECT cg FROM ConsumptionGoal cg "
+ + "WHERE cg.category.isDefault = true "
+ + "AND cg.user.age BETWEEN :peerAgeStart AND :peerAgeEnd "
+ + "AND cg.user.gender = :peerGender "
+ + "ORDER BY cg.goalAmount DESC limit :top")
+ List findTopCategoriesAndGoalAmount(
+ @Param("top") int top,
+ @Param("peerAgeStart") int peerAgeStart,
+ @Param("peerAgeEnd") int peerAgeEnd,
+ @Param("peerGender") Gender peerGender);
+
+ @Query(value = "SELECT cg FROM ConsumptionGoal AS cg WHERE cg.user.id = :userId AND cg.goalMonth = :goalMonth")
+ List findConsumptionGoalByUserIdAndGoalMonth(Long userId, LocalDate goalMonth);
+
+ Optional findConsumptionGoalByUserAndCategoryAndGoalMonth(User user, Category category,
+ LocalDate goalMonth);
+}
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/package-info.java
deleted file mode 100644
index ce8587a8..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.consumptiongoal.repository;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalService.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalService.java
new file mode 100644
index 00000000..e647a0ec
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalService.java
@@ -0,0 +1,25 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.service;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import org.springframework.stereotype.Service;
+
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalListRequestDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseListDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.PeerInfoResponseDTO;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopGoalCategoryResponseDTO;
+
+@Service
+public interface ConsumptionGoalService {
+
+ List getTopGoalCategories(int top, Long userId, int peerAgeStart, int peerAgeEnd,
+ String peerGender);
+
+ ConsumptionGoalResponseListDto findUserConsumptionGoal(Long userId, LocalDate date);
+
+ PeerInfoResponseDTO getPeerInfo(Long userId, int peerAgeStart, int peerAgeEnd, String peerGender);
+
+ ConsumptionGoalResponseListDto updateConsumptionGoals(Long userId,
+ ConsumptionGoalListRequestDto consumptionGoalListRequestDto);
+}
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java
new file mode 100644
index 00000000..553bb514
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java
@@ -0,0 +1,191 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.service;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.bbteam.budgetbuddies.domain.category.entity.Category;
+import com.bbteam.budgetbuddies.domain.category.repository.CategoryRepository;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.converter.ConsumptionGoalConverter;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.converter.PeerInfoConverter;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.converter.TopCategoryConverter;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalListRequestDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalRequestDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseListDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.PeerInfoResponseDTO;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopGoalCategoryResponseDTO;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.repository.ConsumptionGoalRepository;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import com.bbteam.budgetbuddies.domain.user.repository.UserRepository;
+import com.bbteam.budgetbuddies.enums.Gender;
+
+import lombok.RequiredArgsConstructor;
+
+@Service
+@RequiredArgsConstructor
+public class ConsumptionGoalServiceImpl implements ConsumptionGoalService {
+
+ private final ConsumptionGoalRepository consumptionGoalRepository;
+ private final CategoryRepository categoryRepository;
+ private final UserRepository userRepository;
+
+ private final ConsumptionGoalConverter consumptionGoalConverter;
+
+ private int peerAgeStart;
+ private int peerAgeEnd;
+ private Gender peerGender;
+
+ @Override
+ @Transactional(readOnly = true)
+ public List getTopGoalCategories(int top, Long userId, int peerAgeS, int peerAgeE,
+ String peerG) {
+
+ User user = findUserById(userId);
+
+ checkPeerInfo(user, peerAgeS, peerAgeE, peerG);
+
+ List topGoals = consumptionGoalRepository.findTopCategoriesAndGoalAmount(top, peerAgeStart,
+ peerAgeEnd, peerGender);
+ return topGoals.stream().map(TopCategoryConverter::fromEntity).collect(Collectors.toList());
+ }
+
+ @Override
+ @Transactional(readOnly = true)
+ public PeerInfoResponseDTO getPeerInfo(Long userId, int peerAgeS, int peerAgeE, String peerG) {
+
+ User user = findUserById(userId);
+
+ checkPeerInfo(user, peerAgeS, peerAgeE, peerG);
+
+ return PeerInfoConverter.fromEntity(peerAgeStart, peerAgeEnd, peerGender);
+ }
+
+ private User findUserById(Long userId) {
+ Optional user = userRepository.findById(userId);
+
+ if (user.isEmpty()) {
+ throw new NoSuchElementException("유저를 찾을 수 없습니다.");
+ }
+
+ return user.get();
+ }
+
+ private void checkPeerInfo(User user, int peerAgeS, int peerAgeE, String peerG) {
+
+ Gender gender = Gender.valueOf(peerG.toUpperCase());
+
+ if (peerAgeS == 0 || peerAgeE == 0 || gender == Gender.NONE) {
+ peerGender = user.getGender();
+ setAgeGroupByUser(user.getAge());
+ } else {
+ peerAgeStart = peerAgeS;
+ peerAgeEnd = peerAgeE;
+ peerGender = gender;
+ }
+ }
+
+ private void setAgeGroupByUser(int userAge) {
+ if (userAge >= 20 && userAge <= 22) {
+ peerAgeStart = 20;
+ peerAgeEnd = 22;
+ } else if (userAge >= 23 && userAge <= 25) {
+ peerAgeStart = 23;
+ peerAgeEnd = 25;
+ } else if (userAge >= 26 && userAge <= 28) {
+ peerAgeStart = 26;
+ peerAgeEnd = 28;
+ } else if (userAge >= 29) {
+ peerAgeStart = 29;
+ peerAgeEnd = 99;
+ } else {
+ peerAgeStart = 0;
+ peerAgeEnd = 19;
+ }
+ }
+
+ @Override
+ @Transactional(readOnly = true)
+ public ConsumptionGoalResponseListDto findUserConsumptionGoal(Long userId, LocalDate date) {
+ LocalDate goalMonth = date.withDayOfMonth(1);
+ Map goalMap = initializeGoalMap(userId, goalMonth);
+
+ updateGoalMapWithPreviousMonth(userId, goalMonth, goalMap);
+ updateGoalMapWithCurrentMonth(userId, goalMonth, goalMap);
+
+ return new ConsumptionGoalResponseListDto(goalMonth, new ArrayList<>(goalMap.values()));
+ }
+
+ private Map initializeGoalMap(Long userId, LocalDate goalMonth) {
+ return categoryRepository.findUserCategoryByUserId(userId)
+ .stream()
+ .collect(Collectors.toMap(Category::getId,
+ category -> consumptionGoalConverter.toConsumptionGoalResponseDto(category)));
+ }
+
+ private void updateGoalMapWithPreviousMonth(Long userId, LocalDate goalMonth,
+ Map goalMap) {
+ updateGoalMap(userId, goalMonth.minusMonths(1), goalMap);
+ }
+
+ private void updateGoalMapWithCurrentMonth(Long userId, LocalDate goalMonth,
+ Map goalMap) {
+ updateGoalMap(userId, goalMonth, goalMap);
+ }
+
+ private void updateGoalMap(Long userId, LocalDate month, Map goalMap) {
+ consumptionGoalRepository.findConsumptionGoalByUserIdAndGoalMonth(userId, month)
+ .stream()
+ .map(consumptionGoalConverter::toConsumptionGoalResponseDto)
+ .forEach(goal -> goalMap.put(goal.getCategoryId(), goal));
+ }
+
+ @Override
+ @Transactional
+ public ConsumptionGoalResponseListDto updateConsumptionGoals(Long userId,
+ ConsumptionGoalListRequestDto consumptionGoalListRequestDto) {
+ LocalDate thisMonth = LocalDate.now().withDayOfMonth(1);
+ User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("Not found user"));
+
+ List updatedConsumptionGoal = consumptionGoalListRequestDto.getConsumptionGoalList()
+ .stream()
+ .map(c -> updateConsumptionGoalWithRequestDto(user, c, thisMonth))
+ .toList();
+
+ List response = consumptionGoalRepository.saveAll(updatedConsumptionGoal)
+ .stream()
+ .map(consumptionGoalConverter::toConsumptionGoalResponseDto)
+ .toList();
+
+ return new ConsumptionGoalResponseListDto(thisMonth, response);
+ }
+
+ private ConsumptionGoal updateConsumptionGoalWithRequestDto(User user,
+ ConsumptionGoalRequestDto consumptionGoalRequestDto, LocalDate goalMonth) {
+
+ Category category = categoryRepository.findById(consumptionGoalRequestDto.getCategoryId())
+ .orElseThrow(() -> new IllegalArgumentException("Not found Category"));
+
+ ConsumptionGoal consumptionGoal = findOrElseGenerateConsumptionGoal(user, category, goalMonth);
+ consumptionGoal.updateGoalAmount(consumptionGoalRequestDto.getGoalAmount());
+
+ return consumptionGoal;
+ }
+
+ private ConsumptionGoal findOrElseGenerateConsumptionGoal(User user, Category category, LocalDate goalMonth) {
+ return consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, category, goalMonth)
+ .orElseGet(() -> generateConsumptionGoal(user, category, goalMonth));
+ }
+
+ private ConsumptionGoal generateConsumptionGoal(User user, Category category, LocalDate goalMonth) {
+ return ConsumptionGoal.builder().goalMonth(goalMonth).user(user).category(category).consumeAmount(0L).build();
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/package-info.java
deleted file mode 100644
index 95d9a924..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.consumptiongoal.service;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/entity/DiscountInfo.java b/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/entity/DiscountInfo.java
index 69908cd0..2beb881a 100644
--- a/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/entity/DiscountInfo.java
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/entity/DiscountInfo.java
@@ -42,4 +42,9 @@ public void subLikeCount() {
this.likeCount--;
}
+ public Integer addAndGetAnonymousNumber() {
+ this.anonymousNumber++;
+ return anonymousNumber;
+ }
+
}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/repository/DiscountInfoRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/repository/DiscountInfoRepository.java
index e41ffe49..8aa49237 100644
--- a/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/repository/DiscountInfoRepository.java
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/repository/DiscountInfoRepository.java
@@ -5,12 +5,22 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
import java.time.LocalDate;
+import java.util.List;
public interface DiscountInfoRepository extends JpaRepository {
@Query("SELECT i FROM DiscountInfo i WHERE (i.startDate <= :endDate AND i.endDate >= :startDate)")
Page findByDateRange(LocalDate startDate, LocalDate endDate, Pageable pageable);
+ @Query("SELECT i FROM DiscountInfo i WHERE ((i.startDate BETWEEN :startDate AND :endDate) OR i.endDate BETWEEN :startDate AND :endDate)")
+ List findByMonth(@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);
+
+ @Query("SELECT i FROM DiscountInfo i WHERE ((i.startDate BETWEEN :startDate AND :endDate) OR i.endDate BETWEEN :startDate AND :endDate)" +
+ " ORDER BY i.likeCount DESC" +
+ " LIMIT 2")
+ List findRecommendInfoByMonth(@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);
+
}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java
new file mode 100644
index 00000000..159c6fc9
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java
@@ -0,0 +1,37 @@
+package com.bbteam.budgetbuddies.domain.expense.controller;
+
+import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto;
+import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto;
+import com.bbteam.budgetbuddies.domain.expense.service.ExpenseService;
+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 lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/expenses")
+public class ExpenseController {
+
+ private final ExpenseService expenseService;
+
+ @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))),
+ @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)))
+ })
+ @PostMapping("/add")
+ public ResponseEntity createExpense(
+ @Parameter(description = "user_id, category_id, amount, description, expenseDate")
+ @RequestBody ExpenseRequestDto expenseRequestDto) {
+ ExpenseResponseDto response = expenseService.createExpense(expenseRequestDto);
+ return ResponseEntity.ok(response);
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/package-info.java
deleted file mode 100644
index cd648f5a..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.expense.controller;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/converter/ExpenseConverter.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/converter/ExpenseConverter.java
new file mode 100644
index 00000000..ac88217c
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/converter/ExpenseConverter.java
@@ -0,0 +1,34 @@
+package com.bbteam.budgetbuddies.domain.expense.converter;
+
+import com.bbteam.budgetbuddies.domain.category.entity.Category;
+import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto;
+import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto;
+import com.bbteam.budgetbuddies.domain.expense.entity.Expense;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ExpenseConverter {
+
+ public Expense toExpenseEntity(ExpenseRequestDto expenseRequestDto, User user, Category category) {
+ return Expense.builder()
+ .user(user)
+ .category(category)
+ .amount(expenseRequestDto.getAmount())
+ .description(expenseRequestDto.getDescription())
+ .expenseDate(expenseRequestDto.getExpenseDate())
+ .build();
+ }
+
+ public ExpenseResponseDto toExpenseResponseDto(Expense expense) {
+ return ExpenseResponseDto.builder()
+ .expenseId(expense.getId())
+ .userId(expense.getUser().getId())
+ .categoryId(expense.getCategory().getId())
+ .amount(expense.getAmount())
+ .description(expense.getDescription())
+ .expenseDate(expense.getExpenseDate())
+ .build();
+ }
+}
+
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseRequestDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseRequestDto.java
new file mode 100644
index 00000000..680be344
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseRequestDto.java
@@ -0,0 +1,20 @@
+package com.bbteam.budgetbuddies.domain.expense.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ExpenseRequestDto {
+ private Long userId;
+ private Long categoryId;
+ private Long amount;
+ private String description;
+ private LocalDateTime expenseDate;
+}
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseResponseDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseResponseDto.java
new file mode 100644
index 00000000..79b74cf6
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseResponseDto.java
@@ -0,0 +1,21 @@
+package com.bbteam.budgetbuddies.domain.expense.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ExpenseResponseDto {
+ private Long expenseId;
+ private Long userId;
+ private Long categoryId;
+ private Long amount;
+ private String description;
+ private LocalDateTime expenseDate;
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/package-info.java
deleted file mode 100644
index cd54ca0d..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.expense.dto;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/repository/ExpenseRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/repository/ExpenseRepository.java
new file mode 100644
index 00000000..c846f92e
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/repository/ExpenseRepository.java
@@ -0,0 +1,18 @@
+package com.bbteam.budgetbuddies.domain.expense.repository;
+
+import com.bbteam.budgetbuddies.domain.expense.entity.Expense;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
+
+public interface ExpenseRepository extends JpaRepository {
+
+ // 추후 적용 예정
+ @Query("SELECT e FROM Expense e WHERE e.user.id = :userId AND e.category.id = :categoryId")
+ List findByUserIdAndCategoryId(@Param("userId") Long userId, @Param("categoryId") Long categoryId);
+
+ @Query("SELECT e FROM Expense e WHERE e.user.id = :userId")
+ List findByUserId(@Param("userId") Long userId);
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/repository/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/repository/package-info.java
deleted file mode 100644
index c5184ef7..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/repository/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.expense.repository;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseService.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseService.java
new file mode 100644
index 00000000..cbcddb72
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseService.java
@@ -0,0 +1,11 @@
+package com.bbteam.budgetbuddies.domain.expense.service;
+
+import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto;
+import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto;
+import com.bbteam.budgetbuddies.domain.category.dto.CategoryResponseDTO;
+
+import java.util.List;
+
+public interface ExpenseService {
+ ExpenseResponseDto createExpense(ExpenseRequestDto expenseRequestDto);
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java
new file mode 100644
index 00000000..b4675ebe
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java
@@ -0,0 +1,36 @@
+package com.bbteam.budgetbuddies.domain.expense.service;
+
+import com.bbteam.budgetbuddies.domain.category.entity.Category;
+import com.bbteam.budgetbuddies.domain.category.repository.CategoryRepository;
+import com.bbteam.budgetbuddies.domain.expense.converter.ExpenseConverter;
+import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto;
+import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto;
+import com.bbteam.budgetbuddies.domain.expense.entity.Expense;
+import com.bbteam.budgetbuddies.domain.expense.repository.ExpenseRepository;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import com.bbteam.budgetbuddies.domain.user.repository.UserRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class ExpenseServiceImpl implements ExpenseService {
+
+ private final ExpenseRepository expenseRepository;
+ private final UserRepository userRepository;
+ private final CategoryRepository categoryRepository;
+ private final ExpenseConverter expenseConverter;
+
+ @Override
+ public ExpenseResponseDto createExpense(ExpenseRequestDto expenseRequestDto) {
+ User user = userRepository.findById(expenseRequestDto.getUserId())
+ .orElseThrow(() -> new IllegalArgumentException("Invalid user ID"));
+ Category category = categoryRepository.findById(expenseRequestDto.getCategoryId())
+ .orElseThrow(() -> new IllegalArgumentException("Invalid category ID"));
+
+ Expense expense = expenseConverter.toExpenseEntity(expenseRequestDto, user, category);
+ expenseRepository.save(expense);
+
+ return expenseConverter.toExpenseResponseDto(expense);
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/package-info.java
deleted file mode 100644
index ece79aae..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.expense.service;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/SupportInfoController.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/SupportInfoController.java
new file mode 100644
index 00000000..059ae9b6
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/SupportInfoController.java
@@ -0,0 +1,86 @@
+package com.bbteam.budgetbuddies.domain.supportinfo.controller;
+
+import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountRequestDto;
+import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountResponseDto;
+import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportRequestDto;
+import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportResponseDto;
+import com.bbteam.budgetbuddies.domain.supportinfo.service.SupportInfoService;
+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.responses.ApiResponses;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/supports")
+public class SupportInfoController {
+
+ private final SupportInfoService supportInfoService;
+
+ @Operation(summary = "[User] 특정 년월 지원정보 리스트 가져오기 API", description = "특정 년도와 월에 해당하는 지원정보 목록을 조회하는 API이며, 페이징을 포함합니다.")
+ @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 = "year", description = "데이터를 가져올 연도입니다."),
+ @Parameter(name = "month", description = "데이터를 가져올 월입니다."),
+ @Parameter(name = "page", description = "페이지 번호, 0번이 1 페이지 입니다. (기본값은 0입니다.)"),
+ @Parameter(name = "size", description = "한 페이지에 불러올 데이터 개수입니다. (기본값은 10개입니다.)")
+ })
+ @GetMapping("")
+ public ResponseEntity> getSupportsByYearAndMonth(
+ @RequestParam Integer year,
+ @RequestParam Integer month,
+ @RequestParam(defaultValue = "0") Integer page,
+ @RequestParam(defaultValue = "10") Integer size
+ ) {
+ Page supports = supportInfoService.getSupportsByYearAndMonth(year, month, page, size);
+
+ return ResponseEntity.ok(supports);
+ }
+
+ @Operation(summary = "[ADMIN] 지원정보 등록하기 API", description = "지원정보를 등록하는 API이며, 추후에는 관리자만 접근 가능하도록 할 예정입니다.")
+ @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)))
+ })
+ @PostMapping("")
+ public ResponseEntity registerDiscountInfo(
+ @RequestBody SupportRequestDto requestDto
+ ) {
+ SupportResponseDto supportResponseDto = supportInfoService.registerSupportInfo(requestDto);
+
+ return ResponseEntity.ok(supportResponseDto);
+ }
+
+ @Operation(summary = "[User] 특정 지원정보에 좋아요 클릭 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 = "supportInfoId", description = "좋아요를 누를 지원정보의 id입니다."),
+ })
+ @PostMapping("/{supportInfoId}/likes")
+ public ResponseEntity likeDiscountInfo(
+ @RequestParam Long userId,
+ @PathVariable Long supportInfoId
+ ) {
+ SupportResponseDto supportResponseDto = supportInfoService.toggleLike(userId, supportInfoId);
+
+ return ResponseEntity.ok(supportResponseDto);
+ }
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/package-info.java
deleted file mode 100644
index a4bccaf4..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.supportinfo.controller;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/converter/SupportInfoConverter.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/converter/SupportInfoConverter.java
new file mode 100644
index 00000000..8e9bd62f
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/converter/SupportInfoConverter.java
@@ -0,0 +1,46 @@
+package com.bbteam.budgetbuddies.domain.supportinfo.converter;
+
+import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountRequestDto;
+import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountResponseDto;
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportRequestDto;
+import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportResponseDto;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import org.springframework.stereotype.Service;
+
+@Service
+public class SupportInfoConverter {
+ /**
+ * @param entity
+ * @return responseDto
+ */
+ public SupportResponseDto toDto(SupportInfo entity) {
+
+ return SupportResponseDto.builder()
+ .id(entity.getId())
+ .title(entity.getTitle())
+ .startDate(entity.getStartDate())
+ .endDate(entity.getEndDate())
+ .anonymousNumber(entity.getAnonymousNumber())
+ .likeCount(entity.getLikeCount())
+ .siteUrl(entity.getSiteUrl())
+ .build();
+ }
+
+ /**
+ *
+ * @param requestDto
+ * @return entity
+ */
+ public SupportInfo toEntity(SupportRequestDto requestDto) {
+
+ return SupportInfo.builder()
+ .title(requestDto.getTitle())
+ .startDate(requestDto.getStartDate())
+ .endDate(requestDto.getEndDate())
+ .anonymousNumber(0)
+ .likeCount(0)
+ .siteUrl(requestDto.getSiteUrl())
+ .build();
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/dto/SupportRequestDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/dto/SupportRequestDto.java
new file mode 100644
index 00000000..ff883f7d
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/dto/SupportRequestDto.java
@@ -0,0 +1,24 @@
+package com.bbteam.budgetbuddies.domain.supportinfo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SupportRequestDto {
+
+ private String title;
+
+ private LocalDate startDate;
+
+ private LocalDate endDate;
+
+ private String siteUrl;
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/dto/SupportResponseDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/dto/SupportResponseDto.java
new file mode 100644
index 00000000..b04825f7
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/dto/SupportResponseDto.java
@@ -0,0 +1,30 @@
+package com.bbteam.budgetbuddies.domain.supportinfo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SupportResponseDto {
+
+ private Long id;
+
+ private String title;
+
+ private LocalDate startDate;
+
+ private LocalDate endDate;
+
+ private Integer anonymousNumber;
+
+ private Integer likeCount;
+
+ private String siteUrl;
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/dto/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/dto/package-info.java
deleted file mode 100644
index 7137c5b3..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/dto/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.supportinfo.dto;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/entity/SupportInfo.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/entity/SupportInfo.java
index 78ffa7ca..cc83973e 100644
--- a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/entity/SupportInfo.java
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/entity/SupportInfo.java
@@ -27,9 +27,25 @@ public class SupportInfo extends BaseEntity {
private LocalDate endDate;
@ColumnDefault("0")
- private Integer likeCount;
+ private Integer likeCount = 0;
+
+ @ColumnDefault("0")
+ private Integer anonymousNumber = 0;
@Column(length = 1000)
private String siteUrl;
+ public void addLikeCount() {
+ this.likeCount++;
+ }
+
+ public void subLikeCount() {
+ this.likeCount--;
+ }
+
+ public Integer addAndGetAnonymousNumber() {
+ this.anonymousNumber++;
+ return anonymousNumber;
+ }
+
}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/repository/SupportInfoRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/repository/SupportInfoRepository.java
new file mode 100644
index 00000000..4d6ba4b1
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/repository/SupportInfoRepository.java
@@ -0,0 +1,27 @@
+package com.bbteam.budgetbuddies.domain.supportinfo.repository;
+
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.time.LocalDate;
+import java.util.List;
+
+public interface SupportInfoRepository extends JpaRepository {
+
+ @Query("SELECT i FROM SupportInfo i WHERE (i.startDate <= :endDate AND i.endDate >= :startDate)")
+ Page findByDateRange(LocalDate startDate, LocalDate endDate, Pageable pageable);
+
+ @Query("SELECT i FROM SupportInfo i WHERE ((i.startDate BETWEEN :startDate AND :endDate) OR i.endDate BETWEEN :startDate AND :endDate)")
+ List findByMonth(@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);
+
+ @Query("SELECT i FROM SupportInfo i WHERE ((i.startDate BETWEEN :startDate AND :endDate) OR i.endDate BETWEEN :startDate AND :endDate)" +
+ " ORDER BY i.likeCount DESC" +
+ " LIMIT 2")
+ List findRecommendInfoByMonth(@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/repository/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/repository/package-info.java
deleted file mode 100644
index 8a76d616..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/repository/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.supportinfo.repository;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/service/SupportInfoService.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/service/SupportInfoService.java
new file mode 100644
index 00000000..bc01ebd9
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/service/SupportInfoService.java
@@ -0,0 +1,20 @@
+package com.bbteam.budgetbuddies.domain.supportinfo.service;
+
+import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountRequestDto;
+import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountResponseDto;
+import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportRequestDto;
+import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportResponseDto;
+import org.springframework.data.domain.Page;
+
+public interface SupportInfoService {
+ Page getSupportsByYearAndMonth(
+ Integer year,
+ Integer month,
+ Integer page,
+ Integer size
+ );
+
+ SupportResponseDto registerSupportInfo(SupportRequestDto supportRequestDto);
+
+ SupportResponseDto toggleLike(Long userId, Long supportInfoId);
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/service/SupportInfoServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/service/SupportInfoServiceImpl.java
new file mode 100644
index 00000000..6f5568f9
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/service/SupportInfoServiceImpl.java
@@ -0,0 +1,116 @@
+package com.bbteam.budgetbuddies.domain.supportinfo.service;
+
+import com.bbteam.budgetbuddies.domain.discountinfo.converter.DiscountInfoConverter;
+import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountRequestDto;
+import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountResponseDto;
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.discountinfo.repository.DiscountInfoRepository;
+import com.bbteam.budgetbuddies.domain.discountinfolike.entity.DiscountInfoLike;
+import com.bbteam.budgetbuddies.domain.discountinfolike.repository.DiscountInfoLikeRepository;
+import com.bbteam.budgetbuddies.domain.supportinfo.converter.SupportInfoConverter;
+import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportRequestDto;
+import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportResponseDto;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import com.bbteam.budgetbuddies.domain.supportinfo.repository.SupportInfoRepository;
+import com.bbteam.budgetbuddies.domain.supportinfolike.entity.SupportInfoLike;
+import com.bbteam.budgetbuddies.domain.supportinfolike.repository.SupportInfoLikeRepository;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import com.bbteam.budgetbuddies.domain.user.repository.UserRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDate;
+import java.util.Optional;
+
+@Service
+@RequiredArgsConstructor
+public class SupportInfoServiceImpl implements SupportInfoService {
+
+ private final SupportInfoRepository supportInfoRepository;
+
+ private final SupportInfoLikeRepository supportInfoLikeRepository;
+
+ private final SupportInfoConverter supportInfoConverter;
+
+ private final UserRepository userRepository;
+
+
+ @Transactional(readOnly = true)
+ @Override
+ public Page getSupportsByYearAndMonth(Integer year, Integer month, Integer page, Integer size) {
+ /**
+ * 1. Pageable 객체 생성 (사용자로부터 입력받은 page 번호와 size)
+ * 2. 사용자가 요청한 년월을 기준으로 해당 년월의 1일로 LocalDate 객체 생성
+ * 3. 해당 년월에 겹치는 할인정보 데이터 가져오기
+ * 4. Entity 리스트를 -> Dto로 모두 변환하여 리턴
+ */
+ Pageable pageable = PageRequest.of(page, size);
+
+ LocalDate startDate = LocalDate.of(year, month, 1);
+ LocalDate endDate = startDate.withDayOfMonth(startDate.lengthOfMonth());
+
+ Page supportInfoPage = supportInfoRepository.findByDateRange(startDate, endDate, pageable);
+
+ return supportInfoPage.map(supportInfoConverter::toDto);
+ }
+
+ @Transactional
+ @Override
+ public SupportResponseDto registerSupportInfo(SupportRequestDto supportRequestDto) {
+ /**
+ * 1. RequestDto -> Entity로 변환
+ * 2. Entity 저장
+ * 3. Entity -> ResponseDto로 변환 후 리턴
+ */
+ SupportInfo entity = supportInfoConverter.toEntity(supportRequestDto);
+
+ supportInfoRepository.save(entity);
+
+ return supportInfoConverter.toDto(entity);
+ }
+
+ @Transactional
+ @Override
+ public SupportResponseDto toggleLike(Long userId, Long supportInfoId) {
+ /**
+ * 1. 사용자 조회 -> 없으면 에러
+ * 2. 할인정보 조회 -> 없으면 에러
+ * 3. 사용자가 특정 할인정보에 좋아요를 눌렀는지 확인 (SupportInfoLike 테이블에서 userId로부터 데이터 가져오기)
+ * 4. 누르지 않은 상태라면,
+ * 4-1. SupportInfo의 likeCount 1 증가
+ * 4-2. SupportInfoLike의
+ * 5. 이미 누른 상태라면,
+ * 5-1. SupportInfo의 likeCount 1 감소
+ */
+
+ User user = userRepository.findById(userId)
+ .orElseThrow(() -> new IllegalArgumentException("User not found"));
+
+ SupportInfo supportInfo = supportInfoRepository.findById(supportInfoId)
+ .orElseThrow(() -> new IllegalArgumentException("SupportInfo not found"));
+
+ Optional existingLike = supportInfoLikeRepository.findByUserAndSupportInfo(user, supportInfo);
+
+ if (existingLike.isPresent()) {
+ // 이미 좋아요를 누른 상태라면
+ supportInfoLikeRepository.delete(existingLike.get());
+ supportInfo.subLikeCount();
+ } else {
+ // 아직 좋아요를 누르지 않은 상태라면
+ SupportInfoLike newLike = SupportInfoLike.builder()
+ .user(user)
+ .supportInfo(supportInfo)
+ .build();
+ supportInfoLikeRepository.save(newLike);
+ supportInfo.addLikeCount();
+ }
+
+ SupportInfo savedEntity = supportInfoRepository.save(supportInfo);
+
+ return supportInfoConverter.toDto(savedEntity);
+ }
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/service/package-info.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/service/package-info.java
deleted file mode 100644
index ceaba27e..00000000
--- a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/service/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.bbteam.budgetbuddies.domain.supportinfo.service;
\ No newline at end of file
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfolike/repository/SupportInfoLikeRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfolike/repository/SupportInfoLikeRepository.java
new file mode 100644
index 00000000..b2618344
--- /dev/null
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfolike/repository/SupportInfoLikeRepository.java
@@ -0,0 +1,16 @@
+package com.bbteam.budgetbuddies.domain.supportinfolike.repository;
+
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.discountinfolike.entity.DiscountInfoLike;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import com.bbteam.budgetbuddies.domain.supportinfolike.entity.SupportInfoLike;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface SupportInfoLikeRepository extends JpaRepository {
+
+ Optional findByUserAndSupportInfo(User user, SupportInfo supportInfo);
+
+}
diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/user/repository/UserRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/user/repository/UserRepository.java
index 3495835a..f932a14e 100644
--- a/src/main/java/com/bbteam/budgetbuddies/domain/user/repository/UserRepository.java
+++ b/src/main/java/com/bbteam/budgetbuddies/domain/user/repository/UserRepository.java
@@ -1,8 +1,13 @@
package com.bbteam.budgetbuddies.domain.user.repository;
-import com.bbteam.budgetbuddies.domain.user.entity.User;
+import java.util.Optional;
+
import org.springframework.data.jpa.repository.JpaRepository;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+
public interface UserRepository extends JpaRepository {
+ Optional findById(Long userId);
+
}
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
deleted file mode 100644
index d7740288..00000000
--- a/src/main/resources/application.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-spring:
- application:
- name: budgetbuddies
-
- jpa:
- show-sql: true # sql ???? ??? ???? ??.
- properties:
- format_sql: true
- dialect: org.hibernate.dialect.MySQL8Dialect
- hibernate:
- ddl-auto: create
-
- datasource:
- url: jdbc:mysql://localhost:3306/budgetbuddies # mysql ?? ?? (?? ?? DB? ?? ? ??)
- driver-class-name: com.mysql.cj.jdbc.Driver
- username: root
- password: root # db ????
\ No newline at end of file
diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/calendar/service/CalendarServiceTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/calendar/service/CalendarServiceTest.java
new file mode 100644
index 00000000..ded0e299
--- /dev/null
+++ b/src/test/java/com/bbteam/budgetbuddies/domain/calendar/service/CalendarServiceTest.java
@@ -0,0 +1,202 @@
+package com.bbteam.budgetbuddies.domain.calendar.service;
+
+import com.bbteam.budgetbuddies.domain.calendar.converter.CalendarConverter;
+import com.bbteam.budgetbuddies.domain.calendar.dto.CalendarDto;
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.discountinfo.repository.DiscountInfoRepository;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import com.bbteam.budgetbuddies.domain.supportinfo.repository.SupportInfoRepository;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+@SpringBootTest
+@Transactional
+class CalendarServiceTest {
+
+ @Autowired
+ CalendarService calendarService;
+ @Autowired
+ DiscountInfoRepository discountInfoRepository;
+ @Autowired
+ SupportInfoRepository supportInfoRepository;
+
+ @Test
+ void findTest(){
+ LocalDate discountStart1 = LocalDate.of(2024, 8, 1);
+ LocalDate discountStart2 = LocalDate.of(2024, 7, 20);
+ LocalDate discountStart3 = LocalDate.of(2024, 8, 31);
+ LocalDate discountStart4 = LocalDate.of(2024, 7, 20);
+ LocalDate discountStart5 = LocalDate.of(2024, 9, 1);
+
+ LocalDate discountEnd1 = LocalDate.of(2024, 8, 5);
+ LocalDate discountEnd2 = LocalDate.of(2024, 8, 3);
+ LocalDate discountEnd3 = LocalDate.of(2024, 9, 3);
+ LocalDate discountEnd4 = LocalDate.of(2024, 7, 24);
+ LocalDate discountEnd5 = LocalDate.of(2024, 9, 5);
+
+ DiscountInfo discountInfo1 = DiscountInfo.builder()
+ .startDate(discountStart1)
+ .endDate(discountEnd1)
+ .title("test1")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo discountInfo2 = DiscountInfo.builder()
+ .startDate(discountStart2)
+ .endDate(discountEnd2)
+ .title("test2")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo discountInfo3 = DiscountInfo.builder()
+ .startDate(discountStart3)
+ .endDate(discountEnd3)
+ .title("test3")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo discountInfo4 = DiscountInfo.builder()
+ .startDate(discountStart4)
+ .endDate(discountEnd4)
+ .title("test4")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo discountInfo5 = DiscountInfo.builder()
+ .startDate(discountStart5)
+ .endDate(discountEnd5)
+ .title("test5")
+ .likeCount(0)
+ .build();
+
+ discountInfoRepository.save(discountInfo1);
+ discountInfoRepository.save(discountInfo2);
+ discountInfoRepository.save(discountInfo3);
+ discountInfoRepository.save(discountInfo4);
+ discountInfoRepository.save(discountInfo5);
+
+ for(int i = 0; i < 3; i++){
+ discountInfo1.addLikeCount();
+ }
+ for(int i = 0; i < 4; i++){
+ discountInfo2.addLikeCount();
+ }
+ for(int i = 0; i < 5; i++){
+ discountInfo3.addLikeCount();
+ }
+ for(int i = 0; i < 6; i++){
+ discountInfo4.addLikeCount();
+ }
+ for(int i = 0; i < 7; i++){
+ discountInfo5.addLikeCount();
+ }
+
+ LocalDate firstDay = LocalDate.of(2024, 8, 1);
+ LocalDate lastDay = firstDay.withDayOfMonth(firstDay.lengthOfMonth());
+
+ LocalDate supportStart1 = LocalDate.of(2024, 8, 1);
+ LocalDate supportStart2 = LocalDate.of(2024, 7, 20);
+ LocalDate supportStart3 = LocalDate.of(2024, 8, 31);
+ LocalDate supportStart4 = LocalDate.of(2024, 7, 20);
+ LocalDate supportStart5 = LocalDate.of(2024, 9, 1);
+
+ LocalDate supportEnd1 = LocalDate.of(2024, 8, 5);
+ LocalDate supportEnd2 = LocalDate.of(2024, 7, 23);
+ LocalDate supportEnd3 = LocalDate.of(2024, 9, 3);
+ LocalDate supportEnd4 = LocalDate.of(2024, 7, 24);
+ LocalDate supportEnd5 = LocalDate.of(2024, 9, 5);
+
+ SupportInfo supportInfo1 = SupportInfo.builder()
+ .startDate(supportStart1)
+ .endDate(supportEnd1)
+ .title("test1")
+ .likeCount(0)
+ .build();
+
+ SupportInfo supportInfo2 = SupportInfo.builder()
+ .startDate(supportStart2)
+ .endDate(supportEnd2)
+ .title("test2")
+ .likeCount(0)
+ .build();
+
+ SupportInfo supportInfo3 = SupportInfo.builder()
+ .startDate(supportStart3)
+ .endDate(supportEnd3)
+ .title("test3")
+ .likeCount(0)
+ .build();
+
+ SupportInfo supportInfo4 = SupportInfo.builder()
+ .startDate(supportStart4)
+ .endDate(supportEnd4)
+ .title("test4")
+ .likeCount(0)
+ .build();
+
+ SupportInfo supportInfo5 = SupportInfo.builder()
+ .startDate(supportStart5)
+ .endDate(supportEnd5)
+ .title("test5")
+ .likeCount(0)
+ .build();
+
+ supportInfoRepository.save(supportInfo1);
+ supportInfoRepository.save(supportInfo2);
+ supportInfoRepository.save(supportInfo3);
+ supportInfoRepository.save(supportInfo4);
+ supportInfoRepository.save(supportInfo5);
+
+ for(int i = 0; i < 10; i++){
+ supportInfo1.addLikeCount();
+ }
+ for(int i = 0; i < 9; i++){
+ supportInfo2.addLikeCount();
+ }
+ for(int i = 0; i < 8; i++){
+ supportInfo3.addLikeCount();
+ }
+ for(int i = 0; i < 11; i++){
+ supportInfo4.addLikeCount();
+ }
+ for(int i = 0; i < 12; i++){
+ supportInfo5.addLikeCount();
+ }
+
+ CalendarDto.CalendarMonthResponseDto result = calendarService.find(2024, 8);
+ List discountInfoDtoList = result.getCalendarMonthInfoDto().getDiscountInfoDtoList();
+ List supportInfoDtoList = result.getCalendarMonthInfoDto().getSupportInfoDtoList();
+
+ assertThat(discountInfoDtoList.size()).isEqualTo(3);
+ CalendarDto.CalendarDiscountInfoDto discountDto1 = CalendarConverter.toCalendarDiscountInfoDto(discountInfo1);
+ CalendarDto.CalendarDiscountInfoDto discountDto2 = CalendarConverter.toCalendarDiscountInfoDto(discountInfo2);
+ CalendarDto.CalendarDiscountInfoDto discountDto3 = CalendarConverter.toCalendarDiscountInfoDto(discountInfo3);
+ assertThat(discountInfoDtoList).containsExactlyInAnyOrder(discountDto1, discountDto2, discountDto3);
+
+ assertThat(supportInfoDtoList.size()).isEqualTo(2);
+ CalendarDto.CalendarSupportInfoDto supportDto1 = CalendarConverter.toCalendarSupportInfoDto(supportInfo1);
+ CalendarDto.CalendarSupportInfoDto supportDto3 = CalendarConverter.toCalendarSupportInfoDto(supportInfo3);
+ assertThat(supportInfoDtoList).containsExactlyInAnyOrder(supportDto1, supportDto3);
+
+ List recDiscountDtoList = result.getRecommendMonthInfoDto().getDiscountInfoDtoList();
+ List recSupportDtoList = result.getRecommendMonthInfoDto().getSupportInfoDtoList();
+
+ assertThat(recDiscountDtoList.size()).isEqualTo(2);
+ assertThat(recDiscountDtoList).containsExactly(discountDto3, discountDto2);
+
+ assertThat(recSupportDtoList.size()).isEqualTo(2);
+ assertThat(recSupportDtoList).containsExactly(supportDto1, supportDto3);
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/category/repository/CategoryRepositoryTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/category/repository/CategoryRepositoryTest.java
new file mode 100644
index 00000000..f87f8a95
--- /dev/null
+++ b/src/test/java/com/bbteam/budgetbuddies/domain/category/repository/CategoryRepositoryTest.java
@@ -0,0 +1,67 @@
+package com.bbteam.budgetbuddies.domain.category.repository;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.List;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+
+import com.bbteam.budgetbuddies.domain.category.entity.Category;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import com.bbteam.budgetbuddies.domain.user.repository.UserRepository;
+
+@DisplayName("Category 레포지토리 테스트의 ")
+@DataJpaTest
+@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
+class CategoryRepositoryTest {
+ @Autowired
+ UserRepository userRepository;
+ @Autowired
+ CategoryRepository categoryRepository;
+
+ @Test
+ @DisplayName("Custom 카테고리와 Base 카테고리 조회 성공")
+ void findUserCategoryByUserIdTest_Success() {
+ User user = userRepository.save(User.builder()
+ .email("email")
+ .age(24)
+ .name("name")
+ .phoneNumber("010-1234-5678")
+ .build());
+
+ User otherUser = userRepository.save(User.builder()
+ .email("email2")
+ .age(25)
+ .name("name2")
+ .phoneNumber("010-2345-5678")
+ .build());
+
+ Category defaultCategory = categoryRepository.save(Category.builder()
+ .name("디폴트 카테고리")
+ .user(null)
+ .isDefault(true)
+ .build());
+
+ Category userCategory = categoryRepository.save(Category.builder()
+ .name("유저 카테고리")
+ .user(user)
+ .isDefault(false)
+ .build());
+
+ categoryRepository.save(Category.builder()
+ .name("다른 유저 카테고리")
+ .user(otherUser)
+ .isDefault(false)
+ .build());
+
+ // when
+ List result = categoryRepository.findUserCategoryByUserId(user.getId());
+
+ // then
+ assertThat(result).usingRecursiveComparison().isEqualTo(List.of(defaultCategory, userCategory));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/comment/repository/CommentRepositoryTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/comment/repository/CommentRepositoryTest.java
new file mode 100644
index 00000000..4aa430a7
--- /dev/null
+++ b/src/test/java/com/bbteam/budgetbuddies/domain/comment/repository/CommentRepositoryTest.java
@@ -0,0 +1,253 @@
+package com.bbteam.budgetbuddies.domain.comment.repository;
+
+import com.bbteam.budgetbuddies.domain.comment.entity.Comment;
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.discountinfo.repository.DiscountInfoRepository;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import com.bbteam.budgetbuddies.domain.supportinfo.repository.SupportInfoRepository;
+import jakarta.persistence.EntityManager;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+
+@SpringBootTest
+@Transactional
+class CommentRepositoryTest {
+
+ @Autowired
+ CommentRepository commentRepository;
+
+ @Autowired
+ SupportInfoRepository supportInfoRepository;
+
+ @Autowired
+ DiscountInfoRepository discountInfoRepository;
+
+ @Autowired
+ EntityManager em;
+
+
+ @Test
+ public void saveTest(){
+ Comment comment1 = Comment.builder().content("test1").build();
+ Comment comment2 = Comment.builder().content("test2").build();
+
+ commentRepository.save(comment1);
+ commentRepository.save(comment2);
+
+ em.flush();
+
+ Comment found1 = commentRepository.findById(comment1.getId()).get();
+ Comment found2 = commentRepository.findById(comment2.getId()).get();
+
+
+ Assertions.assertThat(comment1).isEqualTo(found1);
+ Assertions.assertThat(comment2).isEqualTo(found2);
+ }
+
+ @Test
+ public void findByDiscountInfoTest(){
+ DiscountInfo sale1 = DiscountInfo.builder().title("무신사 할인").build();
+ DiscountInfo sale2 = DiscountInfo.builder().title("옥션 할인").build();
+
+ discountInfoRepository.save(sale1);
+ discountInfoRepository.save(sale2);
+ Comment comment1 = Comment.builder().content("test1")
+ .discountInfo(sale1)
+ .build();
+ Comment comment2 = Comment.builder().content("test2")
+ .discountInfo(sale2)
+ .build();
+ Comment comment3 = Comment.builder().content("test3")
+ .discountInfo(sale1)
+ .build();
+ Comment comment4 = Comment.builder().content("test4")
+ .discountInfo(sale1)
+ .build();
+ Comment comment5 = Comment.builder().content("test5")
+ .discountInfo(sale2)
+ .build();
+
+ commentRepository.save(comment1);
+ commentRepository.save(comment2);
+ commentRepository.save(comment3);
+ commentRepository.save(comment4);
+ commentRepository.save(comment5);
+
+
+ em.flush();
+
+ List found1 = commentRepository.findByDiscountInfo(sale1.getId());
+ List found2 = commentRepository.findByDiscountInfo(sale2.getId());
+
+ Assertions.assertThat(found1.size()).isEqualTo(3);
+ Assertions.assertThat(found2.size()).isEqualTo(2);
+
+
+ Assertions.assertThat(found1.get(0)).isEqualTo(comment1);
+ Assertions.assertThat(found1.get(1)).isEqualTo(comment3);
+ Assertions.assertThat(found1.get(2)).isEqualTo(comment4);
+ Assertions.assertThat(found2.get(0)).isEqualTo(comment2);
+ Assertions.assertThat(found2.get(1)).isEqualTo(comment5);
+
+
+ }
+
+ @Test
+ public void findBySupportInfoTest(){
+// DiscountInfo sale1 = DiscountInfo.builder().title("무신사 할인").build();
+// DiscountInfo sale2 = DiscountInfo.builder().title("옥션 할인").build();
+
+ SupportInfo support1 = SupportInfo.builder().title("국가장학금").build();
+ SupportInfo support2 = SupportInfo.builder().title("비전장학금").build();
+ SupportInfo support3 = SupportInfo.builder().title("좋은장학금").build();
+ SupportInfo support4 = SupportInfo.builder().title("서울봉사").build();
+ SupportInfo support5 = SupportInfo.builder().title("청년대출").build();
+
+ supportInfoRepository.save(support1);
+ supportInfoRepository.save(support2);
+ supportInfoRepository.save(support3);
+ supportInfoRepository.save(support4);
+ supportInfoRepository.save(support5);
+
+ Comment comment1 = Comment.builder().content("test1")
+ .supportInfo(support1)
+ .build();
+ Comment comment2 = Comment.builder().content("test2")
+ .supportInfo(support2)
+ .build();
+ Comment comment3 = Comment.builder().content("test3")
+ .supportInfo(support3)
+ .build();
+ Comment comment4 = Comment.builder().content("test4")
+ .supportInfo(support4)
+ .build();
+ Comment comment5 = Comment.builder().content("test5")
+ .supportInfo(support5)
+ .build();
+ Comment comment6 = Comment.builder().content("test6")
+ .supportInfo(support1)
+ .build();
+ Comment comment7 = Comment.builder().content("test7")
+ .supportInfo(support1)
+ .build();
+ Comment comment8 = Comment.builder().content("test8")
+ .supportInfo(support3)
+ .build();
+ Comment comment9 = Comment.builder().content("test9")
+ .supportInfo(support4)
+ .build();
+ Comment comment10 = Comment.builder().content("test10")
+ .supportInfo(support4)
+ .build();
+
+
+ commentRepository.save(comment1);
+ commentRepository.save(comment2);
+ commentRepository.save(comment3);
+ commentRepository.save(comment4);
+ commentRepository.save(comment5);
+ commentRepository.save(comment6);
+ commentRepository.save(comment7);
+ commentRepository.save(comment8);
+ commentRepository.save(comment9);
+ commentRepository.save(comment10);
+
+
+ em.flush();
+
+ List found1 = commentRepository.findBySupportInfo(support1.getId());
+ List found2 = commentRepository.findBySupportInfo(support2.getId());
+ List found3 = commentRepository.findBySupportInfo(support3.getId());
+ List found4 = commentRepository.findBySupportInfo(support4.getId());
+ List found5 = commentRepository.findBySupportInfo(support5.getId());
+
+ Assertions.assertThat(found1.size()).isEqualTo(3);
+ Assertions.assertThat(found2.size()).isEqualTo(1);
+ Assertions.assertThat(found3.size()).isEqualTo(2);
+ Assertions.assertThat(found4.size()).isEqualTo(3);
+ Assertions.assertThat(found5.size()).isEqualTo(1);
+
+ }
+
+ @Test
+ public void deleteTest(){
+ SupportInfo support1 = SupportInfo.builder().title("국가장학금").build();
+ SupportInfo support2 = SupportInfo.builder().title("비전장학금").build();
+ SupportInfo support3 = SupportInfo.builder().title("좋은장학금").build();
+ SupportInfo support4 = SupportInfo.builder().title("서울봉사").build();
+ SupportInfo support5 = SupportInfo.builder().title("청년대출").build();
+
+ supportInfoRepository.save(support1);
+ supportInfoRepository.save(support2);
+ supportInfoRepository.save(support3);
+ supportInfoRepository.save(support4);
+ supportInfoRepository.save(support5);
+
+ Comment comment1 = Comment.builder().content("test1")
+ .supportInfo(support1)
+ .build();
+ Comment comment2 = Comment.builder().content("test2")
+ .supportInfo(support2)
+ .build();
+ Comment comment3 = Comment.builder().content("test3")
+ .supportInfo(support3)
+ .build();
+ Comment comment4 = Comment.builder().content("test4")
+ .supportInfo(support4)
+ .build();
+ Comment comment5 = Comment.builder().content("test5")
+ .supportInfo(support5)
+ .build();
+ Comment comment6 = Comment.builder().content("test6")
+ .supportInfo(support1)
+ .build();
+ Comment comment7 = Comment.builder().content("test7")
+ .supportInfo(support1)
+ .build();
+ Comment comment8 = Comment.builder().content("test8")
+ .supportInfo(support3)
+ .build();
+ Comment comment9 = Comment.builder().content("test9")
+ .supportInfo(support4)
+ .build();
+ Comment comment10 = Comment.builder().content("test10")
+ .supportInfo(support4)
+ .build();
+
+
+ commentRepository.save(comment1);
+ commentRepository.save(comment2);
+ commentRepository.save(comment3);
+ commentRepository.save(comment4);
+ commentRepository.save(comment5);
+ commentRepository.save(comment6);
+ commentRepository.save(comment7);
+ commentRepository.save(comment8);
+ commentRepository.save(comment9);
+ commentRepository.save(comment10);
+
+ commentRepository.delete(comment1); // comment1이 삭제되면 support1의 개수는 2개가 되어야한다.
+
+ em.flush();
+
+ List found1 = commentRepository.findBySupportInfo(support1.getId());
+ List found2 = commentRepository.findBySupportInfo(support2.getId());
+ List found3 = commentRepository.findBySupportInfo(support3.getId());
+ List found4 = commentRepository.findBySupportInfo(support4.getId());
+ List found5 = commentRepository.findBySupportInfo(support5.getId());
+
+ Assertions.assertThat(found1.size()).isEqualTo(2); // 해당 로직 검증
+ Assertions.assertThat(found2.size()).isEqualTo(1);
+ Assertions.assertThat(found3.size()).isEqualTo(2);
+ Assertions.assertThat(found4.size()).isEqualTo(3);
+ Assertions.assertThat(found5.size()).isEqualTo(1);
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/comment/service/CommentServiceTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/comment/service/CommentServiceTest.java
new file mode 100644
index 00000000..47636c82
--- /dev/null
+++ b/src/test/java/com/bbteam/budgetbuddies/domain/comment/service/CommentServiceTest.java
@@ -0,0 +1,563 @@
+package com.bbteam.budgetbuddies.domain.comment.service;
+
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentRequestDto;
+import com.bbteam.budgetbuddies.domain.comment.dto.CommentResponseDto;
+import com.bbteam.budgetbuddies.domain.discountinfo.entity.DiscountInfo;
+import com.bbteam.budgetbuddies.domain.discountinfo.repository.DiscountInfoRepository;
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import com.bbteam.budgetbuddies.domain.supportinfo.repository.SupportInfoRepository;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import com.bbteam.budgetbuddies.domain.user.repository.UserRepository;
+import jakarta.persistence.EntityManager;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+
+/**
+ * comment service는 다음과 같은 기능을 제공해야한다.
+ * 1. comment 저장 기능
+ * 2. 특정 게시글에 따른 comment return
+ * 현재 게시글의 종류는 2가지로 각각 할인정보, 지원정보이다.
+ * 즉, 할인정보, 지원정보 ID가 들어오면 해당 게시글에 대한 댓글 정보를 다 가지고 올 수 있어야한다.
+ * 아마 관리 측면에선 댓글 삭제 기능도 필요할 것이다.
+ * 3. 특정 userid로 댓글 찾는 기능
+ * 얘는 게시글 ID랑 제목 정도 같이???
+ * 4. 특정 게시글 id로 댓글 찾는 기능
+ */
+
+
+/*
+ 테스트마다 테스트케이스가 다를 수 있어서 공통로직으로 처리하지 않아 매우 깁니다...
+ */
+@SpringBootTest
+@Transactional
+class CommentServiceTest {
+ @Autowired
+ CommentService commentService;
+
+ @Autowired
+ UserRepository userRepository;
+ @Autowired
+ DiscountInfoRepository discountInfoRepository;
+ @Autowired
+ SupportInfoRepository supportInfoRepository;
+ @Autowired
+ EntityManager em;
+
+ @Test
+ public void saveDiscountInfoCommentTest(){
+ User user1 = User.builder()
+ .name("tester1")
+ .email("1234")
+ .age(5)
+ .phoneNumber("123456")
+ .build();
+ userRepository.save(user1);
+
+ DiscountInfo sale1 = DiscountInfo.builder().title("무신사 할인")
+ .anonymousNumber(0)
+ .build();
+ discountInfoRepository.save(sale1);
+
+ CommentRequestDto.DiscountInfoCommentDto dto1 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale1.getId())
+ .content("굿")
+ .build();
+
+ commentService.saveDiscountComment(user1.getId(), dto1);
+ em.flush();
+
+ List returnDto = commentService.findByDiscountInfo(sale1.getId());
+
+ Assertions.assertThat(returnDto.size()).isEqualTo(1);
+ Assertions.assertThat(returnDto.get(0).getDiscountInfoId()).isEqualTo(sale1.getId());
+ Assertions.assertThat(returnDto.get(0).getUserId()).isEqualTo(user1.getId());
+ Assertions.assertThat(returnDto.get(0).getContent()).isEqualTo("굿");
+
+ }
+
+ @Test
+ public void saveDiscountInfoCommentTest2(){
+ User user1 = User.builder()
+ .name("tester1")
+ .email("1234")
+ .age(5)
+ .phoneNumber("123456")
+ .build();
+ userRepository.save(user1);
+
+ User user2 = User.builder()
+ .name("tester2")
+ .email("12345")
+ .age(7)
+ .phoneNumber("1234567")
+ .build();
+ userRepository.save(user2);
+
+ DiscountInfo sale1 = DiscountInfo.builder().title("무신사 할인")
+ .anonymousNumber(0)
+ .build();
+ discountInfoRepository.save(sale1);
+ DiscountInfo sale2 = DiscountInfo.builder().title("핫트랙스 할인")
+ .anonymousNumber(0)
+ .build();
+ discountInfoRepository.save(sale2);
+
+
+ CommentRequestDto.DiscountInfoCommentDto dto1 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale1.getId())
+ .content("굿")
+ .build();
+
+ CommentRequestDto.DiscountInfoCommentDto dto2 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale1.getId())
+ .content("좋아요")
+ .build();
+ CommentRequestDto.DiscountInfoCommentDto dto3 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale2.getId())
+ .content("유용해요!")
+ .build();
+
+ commentService.saveDiscountComment(user1.getId(), dto1);
+ commentService.saveDiscountComment(user2.getId(), dto2);
+ commentService.saveDiscountComment(user1.getId(), dto3);
+
+ em.flush();
+
+ List returnDto = commentService.findByDiscountInfo(sale1.getId());
+ List returnDto2 = commentService.findByDiscountInfo(sale2.getId());
+ Assertions.assertThat(returnDto.size()).isEqualTo(2);
+ Assertions.assertThat(returnDto.get(0).getDiscountInfoId()).isEqualTo(sale1.getId());
+ Assertions.assertThat(returnDto.get(0).getUserId()).isEqualTo(user1.getId());
+ Assertions.assertThat(returnDto.get(0).getContent()).isEqualTo("굿");
+ Assertions.assertThat(returnDto.get(1).getDiscountInfoId()).isEqualTo(sale1.getId());
+ Assertions.assertThat(returnDto.get(1).getUserId()).isEqualTo(user2.getId());
+ Assertions.assertThat(returnDto.get(1).getContent()).isEqualTo("좋아요");
+
+ Assertions.assertThat(returnDto2.size()).isEqualTo(1);
+ Assertions.assertThat(returnDto2.get(0).getDiscountInfoId()).isEqualTo(sale2.getId());
+ Assertions.assertThat(returnDto2.get(0).getUserId()).isEqualTo(user1.getId());
+ Assertions.assertThat(returnDto2.get(0).getContent()).isEqualTo("유용해요!");
+
+ }
+
+ @Test
+ void DiscountAnonymousCommentTest(){
+ User user1 = User.builder()
+ .name("tester1")
+ .email("1234")
+ .age(5)
+ .phoneNumber("123456")
+ .build();
+ userRepository.save(user1);
+
+ User user2 = User.builder()
+ .name("tester2")
+ .email("12345")
+ .age(7)
+ .phoneNumber("1234567")
+ .build();
+
+ User user3 = User.builder()
+ .name("tester3")
+ .email("1234553")
+ .age(9)
+ .phoneNumber("1232134567")
+ .build();
+ userRepository.save(user2);
+ userRepository.save(user3);
+
+ DiscountInfo sale1 = DiscountInfo.builder().anonymousNumber(0).title("무신사 할인").build();
+ discountInfoRepository.save(sale1);
+ DiscountInfo sale2 = DiscountInfo.builder().anonymousNumber(0).title("핫트랙스 할인").build();
+ discountInfoRepository.save(sale2);
+
+
+ CommentRequestDto.DiscountInfoCommentDto dto1 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale1.getId())
+ .content("굿")
+ .build();
+
+ CommentRequestDto.DiscountInfoCommentDto dto2 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale1.getId())
+ .content("좋아요")
+ .build();
+ CommentRequestDto.DiscountInfoCommentDto dto3 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale2.getId())
+ .content("유용해요!")
+ .build();
+ CommentRequestDto.DiscountInfoCommentDto dto4 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale1.getId())
+ .content("구웃!")
+ .build();
+
+ commentService.saveDiscountComment(user1.getId(), dto1);
+ commentService.saveDiscountComment(user2.getId(), dto2);
+ commentService.saveDiscountComment(user1.getId(), dto3);
+
+ commentService.saveDiscountComment(user1.getId(), dto4);
+ commentService.saveDiscountComment(user3.getId(), dto4);
+
+ em.flush();
+
+ List result = commentService.findByDiscountInfo(sale1.getId());
+ Integer test1 = result.get(0).getAnonymousNumber();
+ Integer test2 = result.get(1).getAnonymousNumber();
+ Integer test3 = result.get(2).getAnonymousNumber();
+ Integer test4 = result.get(3).getAnonymousNumber();
+
+ Assertions.assertThat(test1).isEqualTo(1);
+ Assertions.assertThat(test2).isEqualTo(2);
+ Assertions.assertThat(test3).isEqualTo(1);
+ Assertions.assertThat(test4).isEqualTo(3);
+
+
+ }
+
+ @Test
+ public void saveSupportInfoCommentTest2(){
+ User user1 = User.builder()
+ .name("tester1")
+ .email("1234")
+ .age(5)
+ .phoneNumber("123456")
+ .build();
+ userRepository.save(user1);
+
+ User user2 = User.builder()
+ .name("tester2")
+ .email("12345")
+ .age(7)
+ .phoneNumber("1234567")
+ .build();
+ userRepository.save(user2);
+
+ SupportInfo info1 = SupportInfo.builder().anonymousNumber(0).title("국가장학금 신청").build();
+ supportInfoRepository.save(info1);
+ SupportInfo info2 = SupportInfo.builder().anonymousNumber(0).title("봉사활동").build();
+ supportInfoRepository.save(info2);
+
+
+ CommentRequestDto.SupportInfoCommentDto dto1 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("굿")
+ .build();
+
+ CommentRequestDto.SupportInfoCommentDto dto2 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("좋아요")
+ .build();
+ CommentRequestDto.SupportInfoCommentDto dto3 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info2.getId())
+ .content("유용해요!")
+ .build();
+
+ commentService.saveSupportComment(user1.getId(), dto1);
+ commentService.saveSupportComment(user2.getId(), dto2);
+ commentService.saveSupportComment(user1.getId(), dto3);
+
+ em.flush();
+
+ List returnDto = commentService.findBySupportInfo(info1.getId());
+ List returnDto2 = commentService.findBySupportInfo(info2.getId());
+ Assertions.assertThat(returnDto.size()).isEqualTo(2);
+ Assertions.assertThat(returnDto.get(0).getSupportInfoId()).isEqualTo(info1.getId());
+ Assertions.assertThat(returnDto.get(0).getUserId()).isEqualTo(user1.getId());
+ Assertions.assertThat(returnDto.get(0).getContent()).isEqualTo("굿");
+ Assertions.assertThat(returnDto.get(1).getSupportInfoId()).isEqualTo(info1.getId());
+ Assertions.assertThat(returnDto.get(1).getUserId()).isEqualTo(user2.getId());
+ Assertions.assertThat(returnDto.get(1).getContent()).isEqualTo("좋아요");
+
+ Assertions.assertThat(returnDto2.size()).isEqualTo(1);
+ Assertions.assertThat(returnDto2.get(0).getSupportInfoId()).isEqualTo(info2.getId());
+ Assertions.assertThat(returnDto2.get(0).getUserId()).isEqualTo(user1.getId());
+ Assertions.assertThat(returnDto2.get(0).getContent()).isEqualTo("유용해요!");
+
+ }
+
+ @Test
+ void supportAnonymousCommentTest(){
+ User user1 = User.builder()
+ .name("tester1")
+ .email("1234")
+ .age(5)
+ .phoneNumber("123456")
+ .build();
+ userRepository.save(user1);
+
+ User user2 = User.builder()
+ .name("tester2")
+ .email("12345")
+ .age(7)
+ .phoneNumber("1234567")
+ .build();
+ User user3 = User.builder()
+ .name("tester432")
+ .email("123423445")
+ .age(7)
+ .phoneNumber("1423234567")
+ .build();
+ User user4 = User.builder()
+ .name("test43er2")
+ .email("1232445")
+ .age(7)
+ .phoneNumber("123454267")
+ .build();
+ userRepository.save(user2);
+ userRepository.save(user3);
+ userRepository.save(user4);
+
+ SupportInfo info1 = SupportInfo.builder().anonymousNumber(0).title("국가장학금 신청").build();
+ supportInfoRepository.save(info1);
+ SupportInfo info2 = SupportInfo.builder().anonymousNumber(0).title("봉사활동").build();
+ supportInfoRepository.save(info2);
+
+
+ CommentRequestDto.SupportInfoCommentDto dto1 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("굿")
+ .build();
+
+ CommentRequestDto.SupportInfoCommentDto dto2 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("좋아요")
+ .build();
+ CommentRequestDto.SupportInfoCommentDto dto3 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info2.getId())
+ .content("유용해요!")
+ .build();
+ CommentRequestDto.SupportInfoCommentDto dto6 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("굿")
+ .build();
+ CommentRequestDto.SupportInfoCommentDto dto4 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("굿")
+ .build();
+ CommentRequestDto.SupportInfoCommentDto dto5 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("굿")
+ .build();
+
+ commentService.saveSupportComment(user1.getId(), dto1);
+ commentService.saveSupportComment(user2.getId(), dto2);
+ commentService.saveSupportComment(user1.getId(), dto3);
+ commentService.saveSupportComment(user3.getId(), dto4);
+ commentService.saveSupportComment(user4.getId(), dto5);
+ commentService.saveSupportComment(user1.getId(), dto6);
+
+ em.flush();
+
+ List returnDto = commentService.findBySupportInfo(info1.getId());
+ List returnDto2 = commentService.findBySupportInfo(info2.getId());
+
+ Integer test1 = returnDto.get(0).getAnonymousNumber();
+ Integer test2 = returnDto.get(1).getAnonymousNumber();
+ Integer test3 = returnDto.get(2).getAnonymousNumber();
+ Integer test4 = returnDto.get(3).getAnonymousNumber();
+ Integer test5 = returnDto.get(4).getAnonymousNumber();
+
+ Assertions.assertThat(test1).isEqualTo(1);
+ Assertions.assertThat(test2).isEqualTo(2);
+ Assertions.assertThat(test3).isEqualTo(3);
+ Assertions.assertThat(test4).isEqualTo(4);
+ Assertions.assertThat(test5).isEqualTo(1);
+ }
+
+ @Test
+ void DiscountInfoCommentPagingTest() {
+ User user1 = User.builder()
+ .name("tester1")
+ .email("1234")
+ .age(5)
+ .phoneNumber("123456")
+ .build();
+ userRepository.save(user1);
+
+ User user2 = User.builder()
+ .name("tester2")
+ .email("12345")
+ .age(7)
+ .phoneNumber("1234567")
+ .build();
+
+ User user3 = User.builder()
+ .name("tester3")
+ .email("1234553")
+ .age(9)
+ .phoneNumber("1232134567")
+ .build();
+ userRepository.save(user2);
+ userRepository.save(user3);
+
+ DiscountInfo sale1 = DiscountInfo.builder().anonymousNumber(0).title("무신사 할인").build();
+ discountInfoRepository.save(sale1);
+ DiscountInfo sale2 = DiscountInfo.builder().anonymousNumber(0).title("핫트랙스 할인").build();
+ discountInfoRepository.save(sale2);
+
+
+ CommentRequestDto.DiscountInfoCommentDto dto1 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale1.getId())
+ .content("굿")
+ .build();
+
+ CommentRequestDto.DiscountInfoCommentDto dto2 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale1.getId())
+ .content("좋아요")
+ .build();
+ CommentRequestDto.DiscountInfoCommentDto dto3 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale2.getId())
+ .content("유용해요!")
+ .build();
+ CommentRequestDto.DiscountInfoCommentDto dto4 = CommentRequestDto.DiscountInfoCommentDto.builder()
+ .discountInfoId(sale1.getId())
+ .content("구웃!")
+ .build();
+
+ commentService.saveDiscountComment(user1.getId(), dto1);
+ commentService.saveDiscountComment(user2.getId(), dto2);
+ commentService.saveDiscountComment(user1.getId(), dto3);
+
+ commentService.saveDiscountComment(user1.getId(), dto4);
+ commentService.saveDiscountComment(user3.getId(), dto4);
+ commentService.saveDiscountComment(user2.getId(), dto4);
+ //sale1 = 5
+ em.flush();
+
+ PageRequest pageRequest1 = PageRequest.of(0, 2);
+
+ Page result1 = commentService.findByDiscountInfoWithPaging(sale1.getId(), pageRequest1);
+ Assertions.assertThat(result1.getTotalElements()).isEqualTo(5);
+ Assertions.assertThat(result1.getTotalPages()).isEqualTo(3);
+ Assertions.assertThat(result1.hasNext()).isTrue();
+ Assertions.assertThat(result1.hasPrevious()).isFalse();
+ List list1 = result1.getContent();
+ Assertions.assertThat(list1.get(0).getUserId()).isEqualTo(user1.getId());
+ Assertions.assertThat(list1.get(0).getContent()).isEqualTo("굿");
+ Assertions.assertThat(list1.get(0).getAnonymousNumber()).isEqualTo(1);
+
+ PageRequest pageRequest2 = PageRequest.of(1, 3);
+
+ Page result2 = commentService.findByDiscountInfoWithPaging(sale1.getId(), pageRequest2);
+ Assertions.assertThat(result2.getTotalElements()).isEqualTo(5);
+ Assertions.assertThat(result2.getTotalPages()).isEqualTo(2);
+ Assertions.assertThat(result2.hasNext()).isFalse();
+ Assertions.assertThat(result2.hasPrevious()).isTrue();
+ List list2 = result2.getContent();
+ Assertions.assertThat(list2.get(0).getUserId()).isEqualTo(user3.getId());
+ Assertions.assertThat(list2.get(0).getContent()).isEqualTo("구웃!");
+ Assertions.assertThat(list2.get(0).getAnonymousNumber()).isEqualTo(3);
+
+
+ }
+
+ @Test
+ void SupportInfoPagingTest() {
+ User user1 = User.builder()
+ .name("tester1")
+ .email("1234")
+ .age(5)
+ .phoneNumber("123456")
+ .build();
+ userRepository.save(user1);
+
+ User user2 = User.builder()
+ .name("tester2")
+ .email("12345")
+ .age(7)
+ .phoneNumber("1234567")
+ .build();
+ User user3 = User.builder()
+ .name("tester432")
+ .email("123423445")
+ .age(7)
+ .phoneNumber("1423234567")
+ .build();
+ User user4 = User.builder()
+ .name("test43er2")
+ .email("1232445")
+ .age(7)
+ .phoneNumber("123454267")
+ .build();
+ userRepository.save(user2);
+ userRepository.save(user3);
+ userRepository.save(user4);
+
+ SupportInfo info1 = SupportInfo.builder().anonymousNumber(0).title("국가장학금 신청").build();
+ supportInfoRepository.save(info1);
+ SupportInfo info2 = SupportInfo.builder().anonymousNumber(0).title("봉사활동").build();
+ supportInfoRepository.save(info2);
+
+
+ CommentRequestDto.SupportInfoCommentDto dto1 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("굿")
+ .build();
+
+ CommentRequestDto.SupportInfoCommentDto dto2 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("좋아요")
+ .build();
+ CommentRequestDto.SupportInfoCommentDto dto3 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info2.getId())
+ .content("유용해요!")
+ .build();
+ CommentRequestDto.SupportInfoCommentDto dto6 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("굿")
+ .build();
+ CommentRequestDto.SupportInfoCommentDto dto4 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("굿")
+ .build();
+ CommentRequestDto.SupportInfoCommentDto dto5 = CommentRequestDto.SupportInfoCommentDto.builder()
+ .supportInfoId(info1.getId())
+ .content("굿")
+ .build();
+
+ commentService.saveSupportComment(user1.getId(), dto1);
+ commentService.saveSupportComment(user2.getId(), dto2);
+ commentService.saveSupportComment(user1.getId(), dto3); // 얘만 info2
+ commentService.saveSupportComment(user3.getId(), dto4);
+ commentService.saveSupportComment(user4.getId(), dto5);
+ commentService.saveSupportComment(user1.getId(), dto6);
+ commentService.saveSupportComment(user2.getId(), dto5);
+ commentService.saveSupportComment(user3.getId(), dto5);
+ em.flush();
+
+ PageRequest pageRequest1 = PageRequest.of(0, 2);
+ Page result1 = commentService.findBySupportInfoWithPaging(info1.getId(), pageRequest1);
+
+ Assertions.assertThat(result1.getTotalElements()).isEqualTo(7);
+ Assertions.assertThat(result1.getTotalPages()).isEqualTo(4);
+ Assertions.assertThat(result1.hasNext()).isTrue();
+ Assertions.assertThat(result1.hasPrevious()).isFalse();
+ List list1 = result1.getContent();
+ Assertions.assertThat(list1.get(0).getUserId()).isEqualTo(user1.getId());
+ Assertions.assertThat(list1.get(0).getContent()).isEqualTo("굿");
+ Assertions.assertThat(list1.get(0).getAnonymousNumber()).isEqualTo(1);
+
+ PageRequest pageRequest2 = PageRequest.of(1, 5);
+ Page result2 = commentService.findBySupportInfoWithPaging(info1.getId(), pageRequest2);
+
+ Assertions.assertThat(result2.getTotalElements()).isEqualTo(7);
+ Assertions.assertThat(result2.getTotalPages()).isEqualTo(2);
+ Assertions.assertThat(result2.hasNext()).isFalse();
+ Assertions.assertThat(result2.hasPrevious()).isTrue();
+ List list2 = result2.getContent();
+ Assertions.assertThat(list2.get(0).getUserId()).isEqualTo(user2.getId());
+ Assertions.assertThat(list2.get(0).getContent()).isEqualTo("굿");
+ Assertions.assertThat(list2.get(0).getAnonymousNumber()).isEqualTo(2);
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepositoryTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepositoryTest.java
new file mode 100644
index 00000000..571f5189
--- /dev/null
+++ b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepositoryTest.java
@@ -0,0 +1,96 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.repository;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+
+import com.bbteam.budgetbuddies.domain.category.entity.Category;
+import com.bbteam.budgetbuddies.domain.category.repository.CategoryRepository;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import com.bbteam.budgetbuddies.domain.user.repository.UserRepository;
+
+@DisplayName("ConsumptionGoal 레포지토리 테스트의 ")
+@DataJpaTest
+@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
+class ConsumptionGoalRepositoryTest {
+ @Autowired
+ ConsumptionGoalRepository consumptionGoalRepository;
+ @Autowired
+ UserRepository userRepository;
+ @Autowired
+ CategoryRepository categoryRepository;
+
+ @Test
+ @DisplayName("유저 아이디와 goalMonth를 통해 GoalConsumption 조회 성공")
+ void findConsumptionGoalByUserIdAndGoalMonth_Success() {
+ // given
+ // 목표 달
+ LocalDate goalMonth = LocalDate.of(2024, 07, 01);
+
+ User mainUser = userRepository.save(
+ User.builder().email("email").age(24).name("name").phoneNumber("010-1234-5678").build());
+
+ Category defaultCategory = categoryRepository.save(
+ Category.builder().name("디폴트 카테고리").user(null).isDefault(true).build());
+
+ Category userCategory = categoryRepository.save(
+ Category.builder().name("유저 카테고리").user(mainUser).isDefault(false).build());
+
+ ConsumptionGoal defaultCategoryConsumptionGoal = consumptionGoalRepository.save(ConsumptionGoal.builder()
+ .goalAmount(1L)
+ .consumeAmount(1L)
+ .user(mainUser)
+ .goalMonth(goalMonth)
+ .category(defaultCategory)
+ .build());
+
+ ConsumptionGoal userCategoryConsumptionGoal = consumptionGoalRepository.save(ConsumptionGoal.builder()
+ .goalAmount(1L)
+ .consumeAmount(1L)
+ .user(mainUser)
+ .goalMonth(goalMonth)
+ .category(userCategory)
+ .build());
+
+ setUnselectedConsumptionGoal(mainUser, goalMonth, defaultCategory);
+
+ // when
+ List result = consumptionGoalRepository.findConsumptionGoalByUserIdAndGoalMonth(mainUser.getId(),
+ goalMonth);
+
+ // then
+ assertThat(result).usingRecursiveComparison()
+ .isEqualTo(List.of(defaultCategoryConsumptionGoal, userCategoryConsumptionGoal));
+ }
+
+ private void setUnselectedConsumptionGoal(User mainUser, LocalDate goalMonth, Category defaultCategory) {
+ User otherUser = userRepository.save(
+ User.builder().email("email2").age(24).name("name2").phoneNumber("010-1567-5678").build());
+
+ ConsumptionGoal lastMonthDefaultCategoryConsumptionGoal = consumptionGoalRepository.save(
+ ConsumptionGoal.builder()
+ .goalAmount(1L)
+ .consumeAmount(1L)
+ .user(mainUser)
+ .goalMonth(goalMonth.minusMonths(1))
+ .category(defaultCategory)
+ .build());
+
+ ConsumptionGoal otherUserDefaultCategoryConsumptionGoal = consumptionGoalRepository.save(
+ ConsumptionGoal.builder()
+ .goalAmount(1L)
+ .consumeAmount(1L)
+ .user(otherUser)
+ .goalMonth(goalMonth)
+ .category(defaultCategory)
+ .build());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java
new file mode 100644
index 00000000..261e25f9
--- /dev/null
+++ b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java
@@ -0,0 +1,231 @@
+package com.bbteam.budgetbuddies.domain.consumptiongoal.service;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.BDDMockito.*;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Optional;
+import java.util.Random;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import com.bbteam.budgetbuddies.domain.category.entity.Category;
+import com.bbteam.budgetbuddies.domain.category.repository.CategoryRepository;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.converter.ConsumptionGoalConverter;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalListRequestDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalRequestDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseListDto;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal;
+import com.bbteam.budgetbuddies.domain.consumptiongoal.repository.ConsumptionGoalRepository;
+import com.bbteam.budgetbuddies.domain.user.entity.User;
+import com.bbteam.budgetbuddies.domain.user.repository.UserRepository;
+
+@DisplayName("ConsumptionGoalImpl 서비스 테스트의 ")
+@ExtendWith(MockitoExtension.class)
+class ConsumptionGoalServiceTest {
+ private final LocalDate GOAL_MONTH = LocalDate.of(2024, 07, 01);
+ private User user;
+ private LocalDate goalMonthRandomDay;
+
+ @InjectMocks
+ private ConsumptionGoalServiceImpl consumptionGoalService;
+ @Mock
+ private ConsumptionGoalRepository consumptionGoalRepository;
+ @Mock
+ private CategoryRepository categoryRepository;
+ @Mock
+ private UserRepository userRepository;
+ @Spy
+ private ConsumptionGoalConverter consumptionGoalConverter;
+
+ @BeforeEach
+ void setUp() {
+ Random random = new Random();
+ int randomDay = random.nextInt(30) + 1;
+ goalMonthRandomDay = LocalDate.of(GOAL_MONTH.getYear(), GOAL_MONTH.getMonth(), randomDay);
+
+ user = Mockito.spy(User.builder().email("email").age(24).name("name").phoneNumber("010-1234-5678").build());
+ given(user.getId()).willReturn(-1L);
+ given(userRepository.findById(user.getId())).willReturn(Optional.ofNullable(user));
+ }
+
+ @Test
+ @DisplayName("findUserConsumptionGoal : 생성된 ConsumptionGoal이 없고 카테고리만 있는 경우 목표 금액, 소비 금액 0으로 초기화")
+ void findUserConsumptionGoal_onlyCategory() {
+ // given
+ Category defaultCategory = Mockito.spy(Category.builder().name("디폴트 카테고리").user(null).isDefault(true).build());
+ given(defaultCategory.getId()).willReturn(-1L);
+
+ Category userCategory = Mockito.spy(Category.builder().name("유저 카테고리").user(user).isDefault(false).build());
+ given(userCategory.getId()).willReturn(-2L);
+
+ List categoryList = List.of(defaultCategory, userCategory);
+
+ given(categoryRepository.findUserCategoryByUserId(user.getId())).willReturn(categoryList);
+
+ List expected = categoryList.stream()
+ .map(category -> consumptionGoalConverter.toConsumptionGoalResponseDto(category))
+ .toList();
+
+ // when
+ ConsumptionGoalResponseListDto result = consumptionGoalService.findUserConsumptionGoal(user.getId(),
+ goalMonthRandomDay);
+
+ // then
+ assertThat(result.getConsumptionGoalList()).usingRecursiveComparison().isEqualTo(expected);
+ }
+
+ @Test
+ @DisplayName("findUserConsumptionGoal : 한달전 ConsumptionGoal만 있을 경우 한달전으로 초기화")
+ void findUserConsumptionGoal_previousMonth() {
+ // given
+ Category defaultCategory = Mockito.spy(Category.builder().name("디폴트 카테고리").user(null).isDefault(true).build());
+ given(defaultCategory.getId()).willReturn(-1L);
+
+ Category userCategory = Mockito.spy(Category.builder().name("유저 카테고리").user(user).isDefault(false).build());
+ given(userCategory.getId()).willReturn(-2L);
+
+ given(categoryRepository.findUserCategoryByUserId(user.getId())).willReturn(
+ List.of(defaultCategory, userCategory));
+
+ ConsumptionGoal previousMonthDefaultCategoryGoal = ConsumptionGoal.builder()
+ .goalAmount(1_000_000L)
+ .consumeAmount(20_000L)
+ .user(user)
+ .category(defaultCategory)
+ .goalMonth(goalMonthRandomDay.minusMonths(1))
+ .build();
+
+ ConsumptionGoal previousMonthUserCategoryGoal = ConsumptionGoal.builder()
+ .goalAmount(1_000_000L)
+ .consumeAmount(20_000L)
+ .user(user)
+ .category(userCategory)
+ .goalMonth(goalMonthRandomDay.minusMonths(1))
+ .build();
+
+ List previousGoalList = List.of(previousMonthDefaultCategoryGoal,
+ previousMonthUserCategoryGoal);
+
+ given(consumptionGoalRepository.findConsumptionGoalByUserIdAndGoalMonth(user.getId(),
+ GOAL_MONTH.minusMonths(1))).willReturn(previousGoalList);
+
+ List expected = previousGoalList.stream()
+ .map(consumptionGoalConverter::toConsumptionGoalResponseDto)
+ .toList();
+
+ // when
+ ConsumptionGoalResponseListDto result = consumptionGoalService.findUserConsumptionGoal(user.getId(),
+ goalMonthRandomDay);
+
+ // then
+ assertThat(result.getConsumptionGoalList()).usingRecursiveComparison().isEqualTo(expected);
+ }
+
+ @Test
+ @DisplayName("findUserConsumptionGoal : 한달 전과 목표 달 ConsumptionGoal이 있을 경우 목표 달로 초기화")
+ void findUserConsumptionGoal_previousMonthAndGoalMonth() {
+ // given
+ Category userCategory = Mockito.spy(Category.builder().name("유저 카테고리").user(user).isDefault(false).build());
+ given(userCategory.getId()).willReturn(-2L);
+
+ ConsumptionGoal previousMonthUserCategoryGoal = ConsumptionGoal.builder()
+ .goalAmount(1_000_000L)
+ .consumeAmount(20_000L)
+ .user(user)
+ .category(userCategory)
+ .goalMonth(goalMonthRandomDay.minusMonths(1))
+ .build();
+
+ ConsumptionGoal goalMonthUserCategoryGoal = ConsumptionGoal.builder()
+ .goalAmount(2_000_000L)
+ .consumeAmount(30_000L)
+ .user(user)
+ .category(userCategory)
+ .goalMonth(goalMonthRandomDay)
+ .build();
+
+ given(consumptionGoalRepository.findConsumptionGoalByUserIdAndGoalMonth(user.getId(),
+ GOAL_MONTH.minusMonths(1))).willReturn(List.of(previousMonthUserCategoryGoal));
+
+ given(consumptionGoalRepository.findConsumptionGoalByUserIdAndGoalMonth(user.getId(), GOAL_MONTH)).willReturn(
+ List.of(goalMonthUserCategoryGoal));
+
+ // when
+ ConsumptionGoalResponseListDto result = consumptionGoalService.findUserConsumptionGoal(user.getId(),
+ goalMonthRandomDay);
+
+ // then
+ assertThat(result.getConsumptionGoalList()).usingRecursiveComparison()
+ .isEqualTo(List.of(consumptionGoalConverter.toConsumptionGoalResponseDto(goalMonthUserCategoryGoal)));
+ }
+
+ @Test
+ @DisplayName("updateConsumptionGoal : 이번달 목표가 있는 경우(defaultCategory)와 목표가 없는 경우(userCategory)")
+ void updateConsumptionGoal_Success() {
+ // given
+ Long defaultGoalAmount = 100L;
+ Long userGoalAmount = 200L;
+
+ ConsumptionGoalListRequestDto request = new ConsumptionGoalListRequestDto(
+ List.of(new ConsumptionGoalRequestDto(-1L, defaultGoalAmount),
+ new ConsumptionGoalRequestDto(-2L, userGoalAmount)));
+
+ Category defaultCategory = Mockito.spy(Category.builder().name("디폴트 카테고리").user(null).isDefault(true).build());
+ given(defaultCategory.getId()).willReturn(-1L);
+ given(categoryRepository.findById(defaultCategory.getId())).willReturn(Optional.of(defaultCategory));
+
+ Category userCategory = Mockito.spy(Category.builder().name("유저 카테고리").user(user).isDefault(false).build());
+ given(userCategory.getId()).willReturn(-2L);
+ given(categoryRepository.findById(userCategory.getId())).willReturn(Optional.of(userCategory));
+
+ ConsumptionGoal defaultCategoryGoal = ConsumptionGoal.builder()
+ .goalAmount(1_000_000L)
+ .consumeAmount(20_000L)
+ .user(user)
+ .category(defaultCategory)
+ .goalMonth(GOAL_MONTH)
+ .build();
+ given(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, defaultCategory,
+ GOAL_MONTH)).willReturn(Optional.ofNullable(defaultCategoryGoal));
+
+ given(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, userCategory,
+ GOAL_MONTH)).willReturn(Optional.ofNullable(null));
+
+ when(consumptionGoalRepository.saveAll(any())).thenAnswer(invocation -> {
+ List goalsToSave = invocation.getArgument(0);
+ return goalsToSave;
+ });
+
+ List expected = List.of(
+ ConsumptionGoalResponseDto.builder()
+ .goalAmount(defaultGoalAmount)
+ .consumeAmount(defaultCategoryGoal.getConsumeAmount())
+ .categoryName(defaultCategory.getName())
+ .categoryId(defaultCategory.getId())
+ .build(),
+ ConsumptionGoalResponseDto.builder()
+ .goalAmount(userGoalAmount)
+ .consumeAmount(0L)
+ .categoryName(userCategory.getName())
+ .categoryId(userCategory.getId())
+ .build()
+ );
+
+ // when
+ ConsumptionGoalResponseListDto result = consumptionGoalService.updateConsumptionGoals(user.getId(), request);
+
+ // then
+ assertThat(result.getConsumptionGoalList()).usingRecursiveComparison().isEqualTo(expected);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/discountinfo/repository/DiscountInfoRepositoryTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/discountinfo/repository/DiscountInfoRepositoryTest.java
index 22348c61..467f624a 100644
--- a/src/test/java/com/bbteam/budgetbuddies/domain/discountinfo/repository/DiscountInfoRepositoryTest.java
+++ b/src/test/java/com/bbteam/budgetbuddies/domain/discountinfo/repository/DiscountInfoRepositoryTest.java
@@ -70,4 +70,164 @@ void findByDateRangeFailure() {
// then
assertThat(results).hasSize(0);
}
+
+ @Test
+ void findByMonthTest(){
+ LocalDate start1 = LocalDate.of(2024, 8, 1);
+ LocalDate start2 = LocalDate.of(2024, 7, 20);
+ LocalDate start3 = LocalDate.of(2024, 8, 31);
+ LocalDate start4 = LocalDate.of(2024, 7, 20);
+ LocalDate start5 = LocalDate.of(2024, 9, 1);
+
+ LocalDate end1 = LocalDate.of(2024, 8, 5);
+ LocalDate end2 = LocalDate.of(2024, 8, 3);
+ LocalDate end3 = LocalDate.of(2024, 9, 3);
+ LocalDate end4 = LocalDate.of(2024, 7, 24);
+ LocalDate end5 = LocalDate.of(2024, 9, 5);
+
+ DiscountInfo info1 = DiscountInfo.builder()
+ .startDate(start1)
+ .endDate(end1)
+ .title("test1")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo info2 = DiscountInfo.builder()
+ .startDate(start2)
+ .endDate(end2)
+ .title("test2")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo info3 = DiscountInfo.builder()
+ .startDate(start3)
+ .endDate(end3)
+ .title("test3")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo info4 = DiscountInfo.builder()
+ .startDate(start4)
+ .endDate(end4)
+ .title("test4")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo info5 = DiscountInfo.builder()
+ .startDate(start5)
+ .endDate(end5)
+ .title("test5")
+ .likeCount(0)
+ .build();
+
+ discountInfoRepository.save(info1);
+ discountInfoRepository.save(info2);
+ discountInfoRepository.save(info3);
+ discountInfoRepository.save(info4);
+ discountInfoRepository.save(info5);
+
+ LocalDate firstDay = LocalDate.of(2024, 8, 1);
+ LocalDate lastDay = firstDay.withDayOfMonth(firstDay.lengthOfMonth());
+
+ List result = discountInfoRepository.findByMonth(firstDay, lastDay);
+
+ Assertions.assertThat(result.size()).isEqualTo(3);
+ Assertions.assertThat(result).containsExactlyInAnyOrder(info1, info2, info3);
+ }
+
+ @Test
+ void findRecommendInfoByMonthTest(){
+ LocalDate start1 = LocalDate.of(2024, 8, 1);
+ LocalDate start2 = LocalDate.of(2024, 7, 20);
+ LocalDate start3 = LocalDate.of(2024, 8, 31);
+ LocalDate start4 = LocalDate.of(2024, 7, 20);
+ LocalDate start5 = LocalDate.of(2024, 9, 1);
+
+ LocalDate end1 = LocalDate.of(2024, 8, 5);
+ LocalDate end2 = LocalDate.of(2024, 8, 3);
+ LocalDate end3 = LocalDate.of(2024, 9, 3);
+ LocalDate end4 = LocalDate.of(2024, 7, 24);
+ LocalDate end5 = LocalDate.of(2024, 9, 5);
+
+ DiscountInfo info1 = DiscountInfo.builder()
+ .startDate(start1)
+ .endDate(end1)
+ .title("test1")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo info2 = DiscountInfo.builder()
+ .startDate(start2)
+ .endDate(end2)
+ .title("test2")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo info3 = DiscountInfo.builder()
+ .startDate(start3)
+ .endDate(end3)
+ .title("test3")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo info4 = DiscountInfo.builder()
+ .startDate(start4)
+ .endDate(end4)
+ .title("test4")
+ .likeCount(0)
+ .build();
+
+ DiscountInfo info5 = DiscountInfo.builder()
+ .startDate(start5)
+ .endDate(end5)
+ .title("test5")
+ .likeCount(0)
+ .build();
+
+ discountInfoRepository.save(info1);
+ discountInfoRepository.save(info2);
+ discountInfoRepository.save(info3);
+ discountInfoRepository.save(info4);
+ discountInfoRepository.save(info5);
+
+ for(int i = 0; i < 3; i++){
+ info1.addLikeCount();
+ }
+ for(int i = 0; i < 4; i++){
+ info2.addLikeCount();
+ }
+ for(int i = 0; i < 5; i++){
+ info3.addLikeCount();
+ }
+ for(int i = 0; i < 6; i++){
+ info4.addLikeCount();
+ }
+ for(int i = 0; i < 7; i++){
+ info5.addLikeCount();
+ }
+ LocalDate firstDay = LocalDate.of(2024, 8, 1);
+ LocalDate lastDay = firstDay.withDayOfMonth(firstDay.lengthOfMonth());
+
+ List result = discountInfoRepository.findRecommendInfoByMonth(firstDay, lastDay);
+
+ Assertions.assertThat(result.size()).isEqualTo(2);
+ Assertions.assertThat(result).containsExactly(info3, info2);
+
+ discountInfoRepository.delete(info3);
+
+ List result2 = discountInfoRepository.findRecommendInfoByMonth(firstDay, lastDay);
+
+ Assertions.assertThat(result2.size()).isEqualTo(2);
+ Assertions.assertThat(result2).containsExactly(info2, info1);
+
+ discountInfoRepository.delete(info2);
+
+ List result3 = discountInfoRepository.findRecommendInfoByMonth(firstDay, lastDay);
+
+ Assertions.assertThat(result3.size()).isEqualTo(1);
+ Assertions.assertThat(result3).containsExactly(info1);
+
+
+ }
+
}
\ No newline at end of file
diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/supportinfo/repository/SupportInfoRepositoryTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/supportinfo/repository/SupportInfoRepositoryTest.java
new file mode 100644
index 00000000..7d490ee8
--- /dev/null
+++ b/src/test/java/com/bbteam/budgetbuddies/domain/supportinfo/repository/SupportInfoRepositoryTest.java
@@ -0,0 +1,181 @@
+package com.bbteam.budgetbuddies.domain.supportinfo.repository;
+
+import com.bbteam.budgetbuddies.domain.supportinfo.entity.SupportInfo;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@SpringBootTest
+@Transactional
+class SupportInfoRepositoryTest {
+
+ @Autowired
+ SupportInfoRepository supportInfoRepository;
+
+
+ @Test
+ void findByMonthTest(){
+ LocalDate start1 = LocalDate.of(2024, 7, 27);
+ LocalDate start2 = LocalDate.of(2024, 7, 20);
+ LocalDate start3 = LocalDate.of(2024, 8, 31);
+ LocalDate start4 = LocalDate.of(2024, 7, 20);
+ LocalDate start5 = LocalDate.of(2024, 8, 30);
+
+ LocalDate end1 = LocalDate.of(2024, 8, 5);
+ LocalDate end2 = LocalDate.of(2024, 8, 3);
+ LocalDate end3 = LocalDate.of(2024, 9, 3);
+ LocalDate end4 = LocalDate.of(2024, 7, 24);
+ LocalDate end5 = LocalDate.of(2024, 9, 5);
+
+ SupportInfo info1 = SupportInfo.builder()
+ .startDate(start1)
+ .endDate(end1)
+ .title("test1")
+ .likeCount(0)
+ .build();
+
+ SupportInfo info2 = SupportInfo.builder()
+ .startDate(start2)
+ .endDate(end2)
+ .title("test2")
+ .likeCount(0)
+ .build();
+
+ SupportInfo info3 = SupportInfo.builder()
+ .startDate(start3)
+ .endDate(end3)
+ .title("test3")
+ .likeCount(0)
+ .build();
+
+ SupportInfo info4 = SupportInfo.builder()
+ .startDate(start4)
+ .endDate(end4)
+ .title("test4")
+ .likeCount(0)
+ .build();
+
+ SupportInfo info5 = SupportInfo.builder()
+ .startDate(start5)
+ .endDate(end5)
+ .title("test5")
+ .likeCount(0)
+ .build();
+
+ supportInfoRepository.save(info1);
+ supportInfoRepository.save(info2);
+ supportInfoRepository.save(info3);
+ supportInfoRepository.save(info4);
+ supportInfoRepository.save(info5);
+
+ LocalDate firstDay = LocalDate.of(2024, 8, 1);
+ LocalDate lastDay = firstDay.withDayOfMonth(firstDay.lengthOfMonth());
+
+ List result = supportInfoRepository.findByMonth(firstDay, lastDay);
+
+ Assertions.assertThat(result.size()).isEqualTo(4);
+ Assertions.assertThat(result).containsExactlyInAnyOrder(info1, info2, info3, info5);
+ }
+
+ @Test
+ void findRecommendInfoByMonthTest(){
+ LocalDate start1 = LocalDate.of(2024, 8, 1);
+ LocalDate start2 = LocalDate.of(2024, 7, 20);
+ LocalDate start3 = LocalDate.of(2024, 8, 31);
+ LocalDate start4 = LocalDate.of(2024, 7, 20);
+ LocalDate start5 = LocalDate.of(2024, 9, 1);
+
+ LocalDate end1 = LocalDate.of(2024, 8, 5);
+ LocalDate end2 = LocalDate.of(2024, 8, 3);
+ LocalDate end3 = LocalDate.of(2024, 9, 3);
+ LocalDate end4 = LocalDate.of(2024, 7, 24);
+ LocalDate end5 = LocalDate.of(2024, 9, 5);
+
+ SupportInfo info1 = SupportInfo.builder()
+ .startDate(start1)
+ .endDate(end1)
+ .title("test1")
+ .likeCount(0)
+ .build();
+
+ SupportInfo info2 = SupportInfo.builder()
+ .startDate(start2)
+ .endDate(end2)
+ .title("test2")
+ .likeCount(0)
+ .build();
+
+ SupportInfo info3 = SupportInfo.builder()
+ .startDate(start3)
+ .endDate(end3)
+ .title("test3")
+ .likeCount(0)
+ .build();
+
+ SupportInfo info4 = SupportInfo.builder()
+ .startDate(start4)
+ .endDate(end4)
+ .title("test4")
+ .likeCount(0)
+ .build();
+
+ SupportInfo info5 = SupportInfo.builder()
+ .startDate(start5)
+ .endDate(end5)
+ .title("test5")
+ .likeCount(0)
+ .build();
+
+ supportInfoRepository.save(info1);
+ supportInfoRepository.save(info2);
+ supportInfoRepository.save(info3);
+ supportInfoRepository.save(info4);
+ supportInfoRepository.save(info5);
+
+ for(int i = 0; i < 10; i++){
+ info1.addLikeCount();
+ }
+ for(int i = 0; i < 9; i++){
+ info2.addLikeCount();
+ }
+ for(int i = 0; i < 8; i++){
+ info3.addLikeCount();
+ }
+ for(int i = 0; i < 11; i++){
+ info4.addLikeCount();
+ }
+ for(int i = 0; i < 12; i++){
+ info5.addLikeCount();
+ }
+ LocalDate firstDay = LocalDate.of(2024, 8, 1);
+ LocalDate lastDay = firstDay.withDayOfMonth(firstDay.lengthOfMonth());
+
+ List result = supportInfoRepository.findRecommendInfoByMonth(firstDay, lastDay);
+
+ Assertions.assertThat(result.size()).isEqualTo(2);
+ Assertions.assertThat(result).containsExactly(info1, info2);
+
+ supportInfoRepository.delete(info3);
+
+ List result2 = supportInfoRepository.findRecommendInfoByMonth(firstDay, lastDay);
+
+ Assertions.assertThat(result2.size()).isEqualTo(2);
+ Assertions.assertThat(result2).containsExactly(info1, info2);
+
+ supportInfoRepository.delete(info1);
+
+ List result3 = supportInfoRepository.findRecommendInfoByMonth(firstDay, lastDay);
+
+ Assertions.assertThat(result3.size()).isEqualTo(1);
+ Assertions.assertThat(result3).containsExactly(info2);
+
+
+ }
+}
\ No newline at end of file