저번에 게시글을 등록하면 포인트가 적립되는 기능을 구현하였다.
이번에는 게시글을 수정하거나 삭제할 때 포인트가 차감되도록 구현 해보았다.
포인트 관련 테이블로는 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 |