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

Closed
forge-bot wants to merge 11 commits from forge/ACX-E2E-1785394564819-attempt-3-run-6ffc72749088 into main
Showing only changes of commit ec34b302cf - Show all commits

View file

@ -0,0 +1,118 @@
package com.acquirex.approval.service;
import com.acquirex.approval.domain.ApprovalStatus;
import com.acquirex.approval.domain.CardAcquisitionApproval;
import com.acquirex.approval.dto.ApprovalRequest;
import com.acquirex.approval.dto.ApprovalResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.UUID;
/**
* Service for card acquisition approval processing.
* Migrated to Spring Boot 3 with Jakarta EE 9+ compatibility.
*/
@Service
public class CardAcquisitionApprovalService {
private static final Logger log = LoggerFactory.getLogger(CardAcquisitionApprovalService.class);
private static final BigDecimal MAX_APPROVAL_AMOUNT = new BigDecimal("1000000.00");
private static final BigDecimal HIGH_RISK_THRESHOLD = new BigDecimal("500000.00");
/**
* Process a card acquisition approval request.
* @param request the approval request
* @return the approval response
*/
public ApprovalResponse processApproval(ApprovalRequest request) {
log.info("Processing approval request: {}", request.getRequestId());
validateRequest(request);
ApprovalStatus status = determineApprovalStatus(request.getAmount());
String approvedBy = determineApprover(status);
CardAcquisitionApproval approval = createApproval(request, status, approvedBy);
log.info("Approval processed: requestId={}, status={}, amount={}",
request.getRequestId(), status, request.getAmount());
return buildResponse(approval, status);
}
/**
* Validate the approval request.
* @param request the request to validate
* @throws IllegalArgumentException if validation fails
*/
void validateRequest(ApprovalRequest request) {
if (request.getCardNumber() == null || request.getCardNumber().length() < 13) {
throw new IllegalArgumentException("Invalid card number format");
}
if (request.getMerchantId() == null || request.getMerchantId().isBlank()) {
throw new IllegalArgumentException("Merchant ID is required");
}
}
/**
* Determine approval status based on amount.
* @param amount the transaction amount
* @return the determined status
*/
ApprovalStatus determineApprovalStatus(BigDecimal amount) {
if (amount.compareTo(MAX_APPROVAL_AMOUNT) > 0) return ApprovalStatus.REJECTED;
if (amount.compareTo(HIGH_RISK_THRESHOLD) > 0) return ApprovalStatus.PENDING;
return ApprovalStatus.APPROVED;
}
/**
* Determine the approver based on status.
* @param status the approval status
* @return the approver identifier
*/
String determineApprover(ApprovalStatus status) {
return switch (status) {
case APPROVED, REJECTED -> "SYSTEM";
case PENDING -> "MANUAL_REVIEW";
case CANCELLED -> "CANCELLED";
};
}
/**
* Create the approval record.
*/
CardAcquisitionApproval createApproval(ApprovalRequest request, ApprovalStatus status, String approvedBy) {
LocalDateTime now = LocalDateTime.now();
return new CardAcquisitionApproval(
generateId(), request.getRequestId(), maskCardNumber(request.getCardNumber()),
request.getMerchantId(), request.getAmount(), status, now, now, approvedBy);
}
/**
* Build the approval response.
*/
ApprovalResponse buildResponse(CardAcquisitionApproval approval, ApprovalStatus status) {
String message = switch (status) {
case APPROVED -> "Card acquisition approved successfully";
case REJECTED -> "Card acquisition rejected: amount exceeds limit";
case PENDING -> "Card acquisition pending manual review";
case CANCELLED -> "Card acquisition cancelled";
};
return new ApprovalResponse(approval.getId(), approval.getRequestId(), status,
approval.getAmount(), approval.getUpdatedAt(), message);
}
/**
* Mask card number for logging/security.
*/
String maskCardNumber(String cardNumber) {
if (cardNumber == null || cardNumber.length() < 4) return "****";
return "****-****-****-" + cardNumber.substring(cardNumber.length() - 4);
}
/**
* Generate unique ID for approval records.
*/
Long generateId() {
return UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE;
}
}