카드 매입 승인 경로 Spring Boot 3 전환 #11

Closed
forge-bot wants to merge 8 commits from forge/ACX-E2E-1785394564819-attempt-12-run-b7ea35c12b16 into main
Showing only changes of commit 0d4a244b56 - Show all commits

View file

@ -0,0 +1,106 @@
package com.acquirex.cardacquisition.service;
import com.acquirex.cardacquisition.entity.CardAcquisition;
import com.acquirex.cardacquisition.repository.CardAcquisitionRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
public class CardAcquisitionService {
private static final BigDecimal MAX_SINGLE_TRANSACTION = new BigDecimal("10000000");
private static final BigDecimal DAILY_LIMIT = new BigDecimal("50000000");
private final CardAcquisitionRepository repository;
public CardAcquisitionService(CardAcquisitionRepository repository) {
this.repository = repository;
}
@Transactional
public AcquisitionResponse requestAcquisition(AcquisitionRequest request) {
validateRequest(request);
CardAcquisition acquisition = new CardAcquisition(
request.getMerchantId(), request.getCardNumber(), request.getAmount(), request.getCurrency());
CardAcquisition saved = repository.save(acquisition);
String approvalCode = generateApprovalCode();
saved.approve(approvalCode);
AcquisitionResponse response = AcquisitionResponse.fromEntity(repository.save(saved));
response.setMessage("매입 승인이 완료되었습니다");
return response;
}
@Transactional(readOnly = true)
public AcquisitionResponse getAcquisition(Long id) {
CardAcquisition acquisition = repository.findById(id)
.orElseThrow(() -> new AcquisitionNotFoundException("매입 정보를 찾을 수 없습니다: " + id));
AcquisitionResponse response = AcquisitionResponse.fromEntity(acquisition);
response.setMessage("매입 정보를 조회했습니다");
return response;
}
@Transactional(readOnly = true)
public List<AcquisitionResponse> getAcquisitionsByMerchant(String merchantId) {
return repository.findByMerchantId(merchantId).stream()
.map(AcquisitionResponse::fromEntity).collect(Collectors.toList());
}
@Transactional(readOnly = true)
public List<AcquisitionResponse> getPendingAcquisitions() {
return repository.findByStatus(CardAcquisition.AcquisitionStatus.PENDING).stream()
.map(AcquisitionResponse::fromEntity).collect(Collectors.toList());
}
@Transactional
public AcquisitionResponse cancelAcquisition(Long id) {
CardAcquisition acquisition = repository.findById(id)
.orElseThrow(() -> new AcquisitionNotFoundException("매입 정보를 찾을 수 없습니다: " + id));
if (acquisition.getStatus() == CardAcquisition.AcquisitionStatus.CANCELLED) {
throw new IllegalStateException("이미 취소된 매입입니다");
}
acquisition.setStatus(CardAcquisition.AcquisitionStatus.CANCELLED);
acquisition.setApprovalTime(LocalDateTime.now());
AcquisitionResponse response = AcquisitionResponse.fromEntity(repository.save(acquisition));
response.setMessage("매입이 취소되었습니다");
return response;
}
private void validateRequest(AcquisitionRequest request) {
if (request.getAmount().compareTo(MAX_SINGLE_TRANSACTION) > 0) {
throw new InvalidAcquisitionException("단일 거래 한도를 초과했습니다");
}
LocalDateTime startOfDay = LocalDateTime.now().toLocalDate().atStartOfDay();
BigDecimal todayTotal = repository.findByRequestTimeBetween(startOfDay, startOfDay.plusDays(1)).stream()
.filter(a -> a.getMerchantId().equals(request.getMerchantId()))
.map(CardAcquisition::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
if (todayTotal.add(request.getAmount()).compareTo(DAILY_LIMIT) > 0) {
throw new InvalidAcquisitionException("일일 한도를 초과했습니다");
}
}
private String generateApprovalCode() {
return "APR" + UUID.randomUUID().toString().substring(0, 12).toUpperCase();
}
public static class AcquisitionNotFoundException extends RuntimeException {
public AcquisitionNotFoundException(String message) { super(message); }
}
public static class InvalidAcquisitionException extends RuntimeException {
public InvalidAcquisitionException(String message) { super(message); }
}
}