package com.sb.web.account.service; import com.sb.web.account.domain.BudgetOnetime; import com.sb.web.account.dto.BudgetOnetimeRequest; import com.sb.web.account.dto.BudgetOnetimeResponse; import com.sb.web.account.mapper.BudgetOnetimeMapper; import com.sb.web.common.exception.ApiException; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @RequiredArgsConstructor public class BudgetOnetimeService { private final BudgetOnetimeMapper mapper; public List list(Long memberId) { return mapper.findByMember(memberId).stream() .map(b -> { long spent = mapper.sumExpenseInRange( memberId, b.getStartDate(), b.getEndDate(), b.getCategory()); return BudgetOnetimeResponse.from(b, spent); }) .toList(); } @Transactional public BudgetOnetimeResponse create(BudgetOnetimeRequest req, Long memberId) { validate(req); BudgetOnetime b = BudgetOnetime.builder() .memberId(memberId) .title(req.getTitle().trim()) .category(blankToNull(req.getCategory())) .amount(req.getAmount()) .startDate(req.getStartDate()) .endDate(req.getEndDate()) .build(); mapper.insert(b); long spent = mapper.sumExpenseInRange(memberId, b.getStartDate(), b.getEndDate(), b.getCategory()); return BudgetOnetimeResponse.from(b, spent); } @Transactional public BudgetOnetimeResponse update(Long id, BudgetOnetimeRequest req, Long memberId) { validate(req); BudgetOnetime b = mustFind(id, memberId); b.setTitle(req.getTitle().trim()); b.setCategory(blankToNull(req.getCategory())); b.setAmount(req.getAmount()); b.setStartDate(req.getStartDate()); b.setEndDate(req.getEndDate()); mapper.update(b); long spent = mapper.sumExpenseInRange(memberId, b.getStartDate(), b.getEndDate(), b.getCategory()); return BudgetOnetimeResponse.from(b, spent); } @Transactional public void delete(Long id, Long memberId) { mustFind(id, memberId); mapper.delete(id, memberId); } private void validate(BudgetOnetimeRequest req) { if (req.getEndDate().isBefore(req.getStartDate())) { throw new ApiException(HttpStatus.BAD_REQUEST, "종료일이 시작일보다 빠를 수 없습니다."); } } private BudgetOnetime mustFind(Long id, Long memberId) { BudgetOnetime b = mapper.findByIdAndMember(id, memberId); if (b == null) throw new ApiException(HttpStatus.NOT_FOUND, "1회성 예산을 찾을 수 없습니다."); return b; } private String blankToNull(String s) { return (s == null || s.isBlank()) ? null : s.trim(); } }