From 3890fe28fc60ffac24455fb4be3871fe463dc215 Mon Sep 17 00:00:00 2001 From: forge-bot Date: Thu, 30 Jul 2026 13:00:25 +0000 Subject: [PATCH] =?UTF-8?q?=EC=B9=B4=EB=93=9C=20=EB=A7=A4=EC=9E=85=20?= =?UTF-8?q?=EC=8A=B9=EC=9D=B8=20=EA=B2=BD=EB=A1=9C=20Spring=20Boot=203=20?= =?UTF-8?q?=EC=A0=84=ED=99=98=20(ACX-E2E-1785394564819)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/AcquisitionApprovalService.java | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 proj-acquirex/src/main/java/com/acquirex/approval/service/AcquisitionApprovalService.java diff --git a/proj-acquirex/src/main/java/com/acquirex/approval/service/AcquisitionApprovalService.java b/proj-acquirex/src/main/java/com/acquirex/approval/service/AcquisitionApprovalService.java new file mode 100644 index 0000000..1e41eec --- /dev/null +++ b/proj-acquirex/src/main/java/com/acquirex/approval/service/AcquisitionApprovalService.java @@ -0,0 +1,115 @@ +package com.acquirex.approval.service; + +import com.acquirex.approval.domain.AcquisitionApproval; +import com.acquirex.approval.domain.AcquisitionApproval.ApprovalStatus; +import com.acquirex.approval.repository.AcquisitionApprovalRepository; +import jakarta.validation.constraints.*; +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; + +/** 카드 매입 승인 서비스 - Spring Boot 3 전환 적용 */ +@Service +@Transactional(readOnly = true) +public class AcquisitionApprovalService { + + private final AcquisitionApprovalRepository repository; + + public AcquisitionApprovalService(AcquisitionApprovalRepository repository) { + this.repository = repository; + } + + /** 매입 승인 요청 처리 */ + @Transactional + public ApprovalResponse processApproval(ApprovalRequest request) { + String approvalNumber = generateApprovalNumber(); + AcquisitionApproval approval = new AcquisitionApproval( + request.merchantId, maskCardNumber(request.cardNumber), + request.approvalAmount, approvalNumber, ApprovalStatus.APPROVED, LocalDateTime.now()); + return toResponse(repository.save(approval)); + } + + /** 승인 번호로 조회 */ + public ApprovalResponse findByApprovalNumber(String approvalNumber) { + return repository.findByApprovalNumber(approvalNumber) + .map(this::toResponse) + .orElseThrow(() -> new IllegalArgumentException("승인 번호를 찾을 수 없습니다: " + approvalNumber)); + } + + /** 가맹점별 승인 목록 조회 */ + public List findByMerchantId(String merchantId, ApprovalStatus status) { + return repository.findByMerchantIdAndStatus(merchantId, status) + .stream().map(this::toResponse).collect(Collectors.toList()); + } + + /** 승인 취소 처리 */ + @Transactional + public ApprovalResponse cancelApproval(Long id) { + AcquisitionApproval approval = repository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("승인 정보를 찾을 수 없습니다: " + id)); + if (approval.getStatus() == ApprovalStatus.CANCELLED) { + throw new IllegalStateException("이미 취소된 승인입니다"); + } + approval.setStatus(ApprovalStatus.CANCELLED); + return toResponse(repository.save(approval)); + } + + private String generateApprovalNumber() { + return "AP" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 4).toUpperCase(); + } + + private String maskCardNumber(String cardNumber) { + if (cardNumber == null || cardNumber.length() < 10) return cardNumber; + return cardNumber.substring(0, 6) + "****" + cardNumber.substring(cardNumber.length() - 4); + } + + private ApprovalResponse toResponse(AcquisitionApproval a) { + return new ApprovalResponse(a.getId(), a.getMerchantId(), a.getCardNumber(), + a.getApprovalAmount(), a.getApprovalNumber(), a.getStatus(), a.getApprovalDatetime()); + } + + /** 카드 매입 승인 요청 DTO - Spring Boot 3: jakarta.validation 적용 */ + public static class ApprovalRequest { + @NotBlank(message = "가맹점 ID는 필수입니다") + @Size(max = 20) + public String merchantId; + + @NotBlank(message = "카드번호는 필수입니다") + @Pattern(regexp = "\\d{13,19}", message = "카드번호는 13~19자리 숫자입니다") + public String cardNumber; + + @NotNull(message = "승인 금액은 필수입니다") + @DecimalMin(value = "0.01", message = "승인 금액은 0보다 커야 합니다") + @DecimalMax(value = "999999999.99") + public BigDecimal approvalAmount; + + public ApprovalRequest() {} + public ApprovalRequest(String merchantId, String cardNumber, BigDecimal approvalAmount) { + this.merchantId = merchantId; this.cardNumber = cardNumber; this.approvalAmount = approvalAmount; + } + } + + /** 카드 매입 승인 응답 DTO */ + public static class ApprovalResponse { + public Long id; + public String merchantId; + public String cardNumber; + public BigDecimal approvalAmount; + public String approvalNumber; + public ApprovalStatus status; + public LocalDateTime approvalDatetime; + + public ApprovalResponse() {} + public ApprovalResponse(Long id, String merchantId, String cardNumber, BigDecimal approvalAmount, + String approvalNumber, ApprovalStatus status, LocalDateTime approvalDatetime) { + this.id = id; this.merchantId = merchantId; this.cardNumber = cardNumber; + this.approvalAmount = approvalAmount; this.approvalNumber = approvalNumber; + this.status = status; this.approvalDatetime = approvalDatetime; + } + } +} \ No newline at end of file