Skip to content

Commit

Permalink
refactor: 🔧 지출 내역 유즈케이스 리팩토링 (#113)
Browse files Browse the repository at this point in the history
* fix: 배포 파이프라인 이미지 빌드 버전 추가

* refactor: create_target_amount() 리팩토링

* rename: recent_target_amount_search_service -> target_amount_search_service

* refactor: get_target_amount_and_total_spending()

* refactor: get_target_amounts_and_total_spendings()

* refactor: update_target_amount 리팩토링

* refactor: target_amount_delete_service() 리팩토링

* style: 불필요한 transactional 어노테이션 제거

* refactor: 월별 총 지출 내역 조회 메서드 분리

* refactor: 지출 조회, 지출 목표 금액 조회 서비스 로직 분리

* refactor: 목표금액&월별 지출 내역 리스트 조회 메서드 분리

* fix: target_amount_mapper start_at 사용자 회원가입 일자 -> 가장 오래된 목표 금액 데이터 기반으로 수정

* docs: 목표금액 리스트 조회 스웨거 문서 요약 수정

* refactor: create_spending 리팩토링

* fix: spending_service read_spendings 반환 타입 list에서 optional 제거

* refactor: spending_search_service 관련 메서드 분리

* fix: spending_repository find_by_year_and_month() 반환값 optional 제거

* refactor: spending_update_service 리팩토링

* refactor: spending update & delete 분리

* test: spending_update_service_test 수정
  • Loading branch information
psychology50 authored Jun 25, 2024
1 parent a69fc70 commit 9b69bd4
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package kr.co.pennyway.api.apis.ledger.service;

import kr.co.pennyway.domain.domains.spending.domain.Spending;
import kr.co.pennyway.domain.domains.spending.exception.SpendingErrorCode;
import kr.co.pennyway.domain.domains.spending.exception.SpendingErrorException;
import kr.co.pennyway.domain.domains.spending.service.SpendingService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class SpendingDeleteService {
private final SpendingService spendingService;

@Transactional
public void deleteSpending(Long spendingId) {
Spending spending = spendingService.readSpending(spendingId)
.orElseThrow(() -> new SpendingErrorException(SpendingErrorCode.NOT_FOUND_SPENDING));

spendingService.deleteSpending(spending);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import kr.co.pennyway.domain.domains.spending.service.SpendingCustomCategoryService;
import kr.co.pennyway.domain.domains.spending.service.SpendingService;
import kr.co.pennyway.domain.domains.user.domain.User;
import kr.co.pennyway.domain.domains.user.exception.UserErrorCode;
import kr.co.pennyway.domain.domains.user.exception.UserErrorException;
import kr.co.pennyway.domain.domains.user.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand All @@ -17,13 +20,15 @@
@Service
@RequiredArgsConstructor
public class SpendingSaveService {
private final UserService userService;
private final SpendingService spendingService;
private final SpendingCustomCategoryService spendingCustomCategoryService;

@Transactional
public Spending createSpending(User user, SpendingReq request) {
Spending spending;
public Spending createSpending(Long userId, SpendingReq request) {
User user = userService.readUser(userId).orElseThrow(() -> new UserErrorException(UserErrorCode.NOT_FOUND));

Spending spending;
if (!request.isCustomCategory()) {
spending = spendingService.createSpending(request.toEntity(user));
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package kr.co.pennyway.api.apis.ledger.service;

import kr.co.pennyway.domain.domains.spending.domain.Spending;
import kr.co.pennyway.domain.domains.spending.dto.TotalSpendingAmount;
import kr.co.pennyway.domain.domains.spending.exception.SpendingErrorCode;
import kr.co.pennyway.domain.domains.spending.exception.SpendingErrorException;
import kr.co.pennyway.domain.domains.spending.service.SpendingService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -17,6 +20,16 @@
public class SpendingSearchService {
private final SpendingService spendingService;

@Transactional(readOnly = true)
public Spending readSpending(Long spendingId) {
return spendingService.readSpending(spendingId).orElseThrow(() -> new SpendingErrorException(SpendingErrorCode.NOT_FOUND_SPENDING));
}

@Transactional(readOnly = true)
public List<Spending> readSpendingsAtYearAndMonth(Long userId, int year, int month) {
return spendingService.readSpendings(userId, year, month);
}

@Transactional(readOnly = true)
public Optional<TotalSpendingAmount> readTotalSpendingAmountByUserIdThatMonth(Long userId, LocalDate date) {
return spendingService.readTotalSpendingAmountByUserId(userId, date);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import kr.co.pennyway.domain.domains.spending.exception.SpendingErrorCode;
import kr.co.pennyway.domain.domains.spending.exception.SpendingErrorException;
import kr.co.pennyway.domain.domains.spending.service.SpendingCustomCategoryService;
import kr.co.pennyway.domain.domains.spending.service.SpendingService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand All @@ -15,10 +16,13 @@
@Service
@RequiredArgsConstructor
public class SpendingUpdateService {
private final SpendingService spendingService;
private final SpendingCustomCategoryService spendingCustomCategoryService;

@Transactional
public Spending updateSpending(Spending spending, SpendingReq request) {
public Spending updateSpending(Long spendingId, SpendingReq request) {
Spending spending = spendingService.readSpending(spendingId).orElseThrow(() -> new SpendingErrorException(SpendingErrorCode.NOT_FOUND_SPENDING));

SpendingCustomCategory customCategory = (request.isCustomCategory())
? spendingCustomCategoryService.readSpendingCustomCategory(request.categoryId()).orElseThrow(() -> new SpendingErrorException(SpendingErrorCode.NOT_FOUND_CUSTOM_CATEGORY))
: null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,12 @@
import kr.co.pennyway.api.apis.ledger.dto.SpendingReq;
import kr.co.pennyway.api.apis.ledger.dto.SpendingSearchRes;
import kr.co.pennyway.api.apis.ledger.mapper.SpendingMapper;
import kr.co.pennyway.api.apis.ledger.service.SpendingDeleteService;
import kr.co.pennyway.api.apis.ledger.service.SpendingSaveService;
import kr.co.pennyway.api.apis.ledger.service.SpendingSearchService;
import kr.co.pennyway.api.apis.ledger.service.SpendingUpdateService;
import kr.co.pennyway.common.annotation.UseCase;
import kr.co.pennyway.domain.domains.spending.domain.Spending;
import kr.co.pennyway.domain.domains.spending.exception.SpendingErrorCode;
import kr.co.pennyway.domain.domains.spending.exception.SpendingErrorException;
import kr.co.pennyway.domain.domains.spending.service.SpendingService;
import kr.co.pennyway.domain.domains.user.domain.User;
import kr.co.pennyway.domain.domains.user.exception.UserErrorCode;
import kr.co.pennyway.domain.domains.user.exception.UserErrorException;
import kr.co.pennyway.domain.domains.user.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -25,68 +20,39 @@
@RequiredArgsConstructor
public class SpendingUseCase {
private final SpendingSaveService spendingSaveService;
private final SpendingSearchService spendingSearchService;
private final SpendingUpdateService spendingUpdateService;
private final SpendingService spendingService;


private final UserService userService;

private final SpendingDeleteService spendingDeleteService;

@Transactional
public SpendingSearchRes.Individual createSpending(Long userId, SpendingReq request) {
User user = readUserOrThrow(userId);

Spending spending = spendingSaveService.createSpending(user, request);
Spending spending = spendingSaveService.createSpending(userId, request);

return SpendingMapper.toSpendingSearchResIndividual(spending);
}

@Transactional(readOnly = true)
public SpendingSearchRes.Month getSpendingsAtYearAndMonth(Long userId, int year, int month) {
List<Spending> spendings = spendingService.readSpendings(userId, year, month).orElseThrow(
() -> new SpendingErrorException(SpendingErrorCode.NOT_FOUND_SPENDING)
);
List<Spending> spendings = spendingSearchService.readSpendingsAtYearAndMonth(userId, year, month);

return SpendingMapper.toSpendingSearchResMonth(spendings, year, month);
}

@Transactional(readOnly = true)
public SpendingSearchRes.Individual getSpedingDetail(Long spendingId) {
Spending spending = readSpendingOrThrow(spendingId);
Spending spending = spendingSearchService.readSpending(spendingId);

return SpendingMapper.toSpendingSearchResIndividual(spending);
}

@Transactional
public SpendingSearchRes.Individual updateSpending(Long spendingId, SpendingReq request) {
Spending spending = readSpendingOrThrow(spendingId);

Spending updatedSpending = spendingUpdateService.updateSpending(spending, request);
Spending updatedSpending = spendingUpdateService.updateSpending(spendingId, request);

return SpendingMapper.toSpendingSearchResIndividual(updatedSpending);
}

@Transactional
public void deleteSpending(Long spendingId) {
Spending spending = spendingService.readSpending(spendingId)
.orElseThrow(() -> new SpendingErrorException(SpendingErrorCode.NOT_FOUND_SPENDING));

spendingService.deleteSpending(spending);
}

private User readUserOrThrow(Long userId) {
return userService.readUser(userId).orElseThrow(
() -> {
throw new UserErrorException(UserErrorCode.NOT_FOUND);
}
);
}

private Spending readSpendingOrThrow(Long spendingId) {
return spendingService.readSpending(spendingId).orElseThrow(
() -> {
throw new SpendingErrorException(SpendingErrorCode.NOT_FOUND_SPENDING);
}
);
spendingDeleteService.deleteSpending(spendingId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ void testReadSpendingsLazyLoading() {
SpendingFixture.bulkInsertSpending(user, 100, true, jdbcTemplate);

// when
List<Spending> spendings = spendingService.readSpendings(user.getId(), LocalDate.now().getYear(), LocalDate.now().getMonthValue()).orElseThrow();
List<Spending> spendings = spendingService.readSpendings(user.getId(), LocalDate.now().getYear(), LocalDate.now().getMonthValue());

int size = spendings.size();
for (Spending spending : spendings) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import kr.co.pennyway.domain.domains.spending.domain.SpendingCustomCategory;
import kr.co.pennyway.domain.domains.spending.exception.SpendingErrorException;
import kr.co.pennyway.domain.domains.spending.service.SpendingCustomCategoryService;
import kr.co.pennyway.domain.domains.spending.service.SpendingService;
import kr.co.pennyway.domain.domains.spending.type.SpendingCategory;
import kr.co.pennyway.domain.domains.user.domain.User;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -28,6 +29,8 @@ public class SpendingUpdateServiceTest {
private SpendingUpdateService spendingUpdateService;
@Mock
private SpendingCustomCategoryService spendingCustomCategoryService;
@Mock
private SpendingService spendingService;

private Spending spending;
private Spending spendingWithCustomCategory;
Expand All @@ -39,7 +42,7 @@ public class SpendingUpdateServiceTest {

@BeforeEach
void setUp() {
spendingUpdateService = new SpendingUpdateService(spendingCustomCategoryService);
spendingUpdateService = new SpendingUpdateService(spendingService, spendingCustomCategoryService);

request = new SpendingReq(10000, -1L, SpendingCategory.FOOD, LocalDate.now(), "소비처", "메모");
requestWithCustomCategory = new SpendingReq(10000, 1L, SpendingCategory.CUSTOM, LocalDate.now(), "소비처", "메모");
Expand All @@ -56,11 +59,13 @@ void setUp() {
@Test
void testUpdateSpendingWithCustomCategoryNotFound() {
// given
Long spendingId = 1L;
given(spendingService.readSpending(spendingId)).willReturn(Optional.of(spending));
given(spendingCustomCategoryService.readSpendingCustomCategory(1L)).willReturn(Optional.empty());

// when - then
SpendingErrorException exception = assertThrows(SpendingErrorException.class, () -> {
spendingUpdateService.updateSpending(spending, requestWithCustomCategory);
spendingUpdateService.updateSpending(spendingId, requestWithCustomCategory);
});
log.debug(exception.getExplainError());
}
Expand All @@ -69,18 +74,24 @@ void testUpdateSpendingWithCustomCategoryNotFound() {
@Test
void testUpdateSpendingWithCustomCategory() {
// given
Long spendingId = 1L;
given(spendingService.readSpending(spendingId)).willReturn(Optional.of(spending));
given(spendingCustomCategoryService.readSpendingCustomCategory(1L)).willReturn(Optional.of(customCategory));

// when - then
assertDoesNotThrow(() -> spendingUpdateService.updateSpending(spending, requestWithCustomCategory));
assertDoesNotThrow(() -> spendingUpdateService.updateSpending(spendingId, requestWithCustomCategory));
assertNotNull(spending.getSpendingCustomCategory());
}

@DisplayName("시스템 카테고리를 사용한 지출내역으로 수정할 시, Spending 객체가 수정된다.")
@Test
void testUpdateSpendingWithNonCustomCategory() {
// given
Long spendingId = 1L;
given(spendingService.readSpending(spendingId)).willReturn(Optional.of(spending));

// when - then
assertDoesNotThrow(() -> spendingUpdateService.updateSpending(spending, request));
assertDoesNotThrow(() -> spendingUpdateService.updateSpending(spendingId, request));
assertNull(spending.getSpendingCustomCategory());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
public interface SpendingCustomRepository {
Optional<TotalSpendingAmount> findTotalSpendingAmountByUserId(Long userId, int year, int month);

Optional<List<Spending>> findByYearAndMonth(Long userId, int year, int month);
List<Spending> findByYearAndMonth(Long userId, int year, int month);
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,17 @@ public Optional<TotalSpendingAmount> findTotalSpendingAmountByUserId(Long userId
}

@Override
public Optional<List<Spending>> findByYearAndMonth(Long userId, int year, int month) {
public List<Spending> findByYearAndMonth(Long userId, int year, int month) {
Sort sort = Sort.by(Sort.Order.desc("spendAt"));
List<OrderSpecifier<?>> orderSpecifiers = QueryDslUtil.getOrderSpecifier(sort);

List<Spending> result = queryFactory.selectFrom(spending)
return queryFactory.selectFrom(spending)
.leftJoin(spending.user, user)
.leftJoin(spending.spendingCustomCategory, spendingCustomCategory).fetchJoin()
.where(spending.spendAt.year().eq(year)
.and(spending.spendAt.month().eq(month)))
.orderBy(orderSpecifiers.toArray(new OrderSpecifier[0]))
.fetch();

return Optional.ofNullable(result);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public Optional<TotalSpendingAmount> readTotalSpendingAmountByUserId(Long userId
}

@Transactional(readOnly = true)
public Optional<List<Spending>> readSpendings(Long userId, int year, int month) {
public List<Spending> readSpendings(Long userId, int year, int month) {
return spendingRepository.findByYearAndMonth(userId, year, month);
}

Expand Down

0 comments on commit 9b69bd4

Please sign in to comment.