본문 바로가기
개발

[개발] 포인트 차감

by 공덕뉸나 2024. 5. 30.

저번에 게시글을 등록하면 포인트가 적립되는 기능을 구현하였다.

이번에는 게시글을 수정하거나 삭제할 때 포인트가 차감되도록 구현 해보았다.

 

포인트 관련 테이블로는 PointHistory랑 PointHistoryDetail이 있는데 PointHistory에는 단순하게 몇 포인트가 적립되었고 사용되었는지에 대한 기록을 보여준다.

PointHistoryDetail에서는 더 세부적으로 보여지게 만들었는데, 예를 들어 게시글 등록을 2번 해서 3포인트씩 2번 6포인트가 쌓였고, 게시글 수정이나 삭제를 통해 2포인트씩 차감한다고 가정해보자.

그러면 게시글 수정이나 삭제를 할 때 첫 번째 게시글 등록에서 쌓인 2포인트와 첫 번째 게시글 등록 포인트 1 + 두 번째 게시글 등록 포인트 1 이렇게 차감 해야 한다.

따라서 PointHistoryDetail에서는 언제 적립된 포인트가 차감되었고 PointHistory에 저장된 내역 중 어떤 부분인지를 볼 수 있다.

 

PointCommonService

public Long usePoint(UsePointRequest request) {
        long amount = request.getAmount();

        checkTotal(request.getUserId(), request.getAmount());

        PointHistory pointHistory = pointHistoryRepo.save(
                PointHistory.builder()
                        .userId(request.getUserId())
                        .amount(amount * -1)
                        .pointHistoryType(request.getPointHistoryType())
                        .pointStat(PointStat.USE)
                        .remarks(request.getRemarks())
                        .build()
        );

        List<GetAvailablePointDto> list = pointHistoryDetailService.getAvailablePointList(request.getUserId());

        List<PointHistoryDetail> historyDetailList = new ArrayList<>();

        for(GetAvailablePointDto dto : list) {
            long availableAmount = dto.getAvailableAmount();
            long minusAmount = amount >= availableAmount ? availableAmount : amount;

            historyDetailList.add(
                    PointHistoryDetail.builder()
                            .pointHistoryId(pointHistory.getPointHistoryId())
                            .amount(minusAmount * -1)
                            .userId(pointHistory.getUserId())
                            .endDt(dto.getEndDt())
                            .pointAccumulateId(dto.getPointAccumulateId())
                            .build()
            );

            if(amount <= availableAmount) break;

            amount -= minusAmount;
        }

        pointHistoryDetailRepo.saveAll(historyDetailList);

        return pointHistory.getPointHistoryId();

    }

 

private void checkTotal(Long userId, Long amount) {
        GetTotalPointDto totalPointDto = pointHistoryRepoSupport.getTotalPoint(userId);

        if(totalPointDto.getTotalPoint() < amount || totalPointDto.getTotalPoint() == null) {
            throw new NotEnoughPointException("포인트가 부족합니다.");
        }
    }

 

1. checkTotal 메소드로 포인트가 부족한지 여부를 확인한다.

2. PointHistory에 차감할 포인트를 저장한다.

3. 가용포인트를 계산한다. 

앞에서 예시를 들었듯이 두 번의 게시글 등록을 통해 적립된 포인트를 나누어서 차감할 경우가 있기 때문에 List로 불러오는 것이다.

4. 차감한 포인트를 PointHistoryDetail에 저장한다.

 

PointHistoryDetailRepoSupport

public List<GetAvailablePointDto> getAvailablePoint(Long userId) {
        List<GetAvailablePointDto> pointList = jpaQueryFactory
                .select(Projections.bean(
                        GetAvailablePointDto.class,
                        POINT_HISTORY_DETAIL.pointAccumulateId,
                        POINT_HISTORY_DETAIL.endDt,
                        POINT_HISTORY_DETAIL.amount.sum().as("availableAmount"))
                )
                .from(POINT_HISTORY_DETAIL)
                .where(POINT_HISTORY_DETAIL.userId.eq(userId))
                .groupBy(
                        POINT_HISTORY_DETAIL.pointAccumulateId,
                        POINT_HISTORY_DETAIL.endDt
                )
                .having(POINT_HISTORY_DETAIL.amount.sum().gt(0))
                .orderBy(POINT_HISTORY_DETAIL.endDt.asc())
                .fetch();

        return pointList;

    }

 

사용 가능한 포인트가 0 이상이고 만료일이 더 빠른 순으로 리스트를 불러온다.

 

PointHistoryDetailService

 public List<GetAvailablePointDto> getAvailablePointList(Long userId) {
        return pointHistoryDetailRepoSupport.getAvailablePoint(userId);
 }

 

 

여기까지 구현했으면 게시글 수정과 삭제 메서드에 구현한 코드를 적용하면 된다.

 

BoardSerivce

public void updateBoard(Long bdId, Long userId, UpdateBoardRequest updateBoardRequest) {
        Board board = this.getOne(bdId);

        if(board.getUserId() != userId) {
            throw new NotAuthorizedException("수정 불가능한 계정입니다.");
        }

        Boolean flag = board.updateBoard(updateBoardRequest);

        if(flag) {
            UsePointRequest usePointRequest = new UsePointRequest(userId, 3L, PointHistoryType.MODIFY, "게시글 수정");
            pointCommonService.usePoint(usePointRequest);
        }

}

 

public void delete(Long bdId, Long userId) {
        Board board = this.getOne(bdId);

        if(board.getUserId() != userId) {
            throw new NotAuthorizedException("삭제 불가능한 계정입니다.");
        }

        boardRepo.delete(board);

        UsePointRequest usePointRequest = new UsePointRequest(userId, 2L, PointHistoryType.DELETE, "게시글 삭제");
        pointCommonService.usePoint(usePointRequest);
}

 

이렇게 적용하고 게시글 수정이나 삭제 테스트를 해보면 DB에 잘 반영되는 것을 볼 수 있다.

 

point_history

 

point_history_detail

 

여기까지 하면 포인트 차감 기능 구현이 완성된다.

 

'개발' 카테고리의 다른 글

[개발] 내 포인트 내역 조회  (0) 2024.06.04
[개발] 포인트 만료  (1) 2024.06.03
[개발] Maven 의존성 추가  (0) 2024.05.28
[개발] 총 포인트 조회  (0) 2024.04.17
[개발] 포인트 적립 구현 - 2  (0) 2024.04.16