MentorSettlementService.java
package com.newbit.settlement.service;
import com.newbit.common.dto.Pagination;
import com.newbit.common.exception.BusinessException;
import com.newbit.common.exception.ErrorCode;
import com.newbit.purchase.command.domain.aggregate.SaleHistory;
import com.newbit.purchase.command.domain.repository.SaleHistoryRepository;
import com.newbit.settlement.dto.response.MentorSettlementDetailResponseDto;
import com.newbit.settlement.dto.response.MentorSettlementListResponseDto;
import com.newbit.settlement.dto.response.MentorSettlementSummaryDto;
import com.newbit.settlement.entity.MonthlySettlementHistory;
import com.newbit.settlement.repository.MonthlySettlementHistoryRepository;
import com.newbit.user.entity.Mentor;
import com.newbit.user.entity.User;
import com.newbit.user.service.MentorService;
import com.newbit.user.support.MailServiceSupport;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class MentorSettlementService {
private final SaleHistoryRepository saleHistoryRepository;
private final MonthlySettlementHistoryRepository monthlySettlementHistoryRepository;
private final MentorService mentorService;
private final MailServiceSupport mailServiceSupport;
@Transactional
public void generateMonthlySettlements(int year, int month) {
// 해당 월의 시작과 끝
LocalDateTime start = LocalDate.of(year, month, 1).atStartOfDay();
LocalDateTime end = start.plusMonths(1).minusNanos(1);
// 아직 정산되지 않은 판매 내역 가져오기
List<SaleHistory> unsettledSales = saleHistoryRepository
.findAllByIsSettledFalseAndCreatedAtBetween(start, end);
// 멘토별로 그룹화하여 정산금액 계산
Map<Long, List<SaleHistory>> groupedByMentor = new HashMap<>();
for (SaleHistory sale : unsettledSales) {
groupedByMentor.computeIfAbsent(sale.getMentorId(), k -> new ArrayList<>()).add(sale);
}
for (Map.Entry<Long, List<SaleHistory>> entry : groupedByMentor.entrySet()) {
Long mentorId = entry.getKey();
List<SaleHistory> sales = entry.getValue();
BigDecimal totalAmount = sales.stream()
.map(SaleHistory::getSaleAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
Mentor mentor = mentorService.getMentorEntityByUserId(mentorId);
MonthlySettlementHistory settlement = MonthlySettlementHistory.of(mentor, year, month, totalAmount);
monthlySettlementHistoryRepository.save(settlement);
// 해당 판매내역 정산처리
sales.forEach(SaleHistory::markAsSettled);
}
}
@Transactional(readOnly = true)
public MentorSettlementListResponseDto getMySettlements(Long mentorId, int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "settledAt"));
Page<MonthlySettlementHistory> resultPage =
monthlySettlementHistoryRepository.findAllByMentor_MentorId(mentorId, pageable);
List<MentorSettlementSummaryDto> content = resultPage.getContent().stream()
.map(MentorSettlementSummaryDto::from)
.collect(Collectors.toList());
return MentorSettlementListResponseDto.builder()
.settlements(content)
.pagination(Pagination.builder()
.currentPage(page)
.totalPage(resultPage.getTotalPages())
.totalItems(resultPage.getTotalElements())
.build())
.build();
}
@Transactional(readOnly = true)
public MentorSettlementDetailResponseDto getSettlementDetail(Long settlementId) {
MonthlySettlementHistory history = monthlySettlementHistoryRepository.findById(settlementId)
.orElseThrow(() -> new BusinessException(ErrorCode.SETTLEMENT_NOT_FOUND));
return MentorSettlementDetailResponseDto.from(history);
}
@Transactional(readOnly = true)
public void sendSettlementEmail(Long mentorId, Long settlementId) {
MonthlySettlementHistory history = monthlySettlementHistoryRepository.findById(settlementId)
.orElseThrow(() -> new BusinessException(ErrorCode.SETTLEMENT_NOT_FOUND));
if(!history.getMentor().getMentorId().equals(mentorId)) {
throw new BusinessException(ErrorCode.SETTLEMENT_NOT_FOUND);
}
User user = history.getMentor().getUser();
String toEmail = user.getEmail();
String subject = "[Newbit] 월별 정산 내역 안내";
String content = String.format("""
<h3>안녕하세요, %s님</h3>
<p>%d년 %d월 정산 내역을 안내드립니다.</p>
<ul>
<li><strong>정산 금액:</strong> %s원</li>
<li><strong>정산 완료일:</strong> %s</li>
</ul>
<p>감사합니다.</p>
""",
user.getNickname(),
history.getSettlementYear(),
history.getSettlementMonth(),
history.getSettlementAmount().toPlainString(),
history.getSettledAt().toString()
);
mailServiceSupport.sendMailSupport(toEmail, subject, content);
}
}