카드 매입 승인 경로 Spring Boot 3 전환 (ACX-E2E-1785394564819)
Some checks are pending
Verify / source-contract (push) Waiting to run
Some checks are pending
Verify / source-contract (push) Waiting to run
This commit is contained in:
parent
38fcb8b62f
commit
fc2e4d049c
1 changed files with 145 additions and 0 deletions
145
src/main/java/com/acquirex/service/AcquisitionService.java
Normal file
145
src/main/java/com/acquirex/service/AcquisitionService.java
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
package com.acquirex.service;
|
||||
|
||||
import com.acquirex.domain.Acquisition;
|
||||
import com.acquirex.domain.AcquisitionStatus;
|
||||
import com.acquirex.exception.AcquisitionNotFoundException;
|
||||
import com.acquirex.exception.InvalidAcquisitionStateException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
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.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 카드 매입 승인 서비스 - Spring Boot 3 트랜잭션 관리
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AcquisitionService {
|
||||
|
||||
private final AcquisitionRepository acquisitionRepository;
|
||||
|
||||
@Transactional
|
||||
public AcquisitionResponse registerAcquisition(AcquisitionRequest request) {
|
||||
log.info("매입 요청 등록: merchantId={}, amount={}", request.getMerchantId(), request.getAmount());
|
||||
String transactionId = generateTransactionId();
|
||||
|
||||
Acquisition acquisition = Acquisition.builder()
|
||||
.merchantId(request.getMerchantId())
|
||||
.cardNumber(maskCardNumber(request.getCardNumber()))
|
||||
.amount(request.getAmount())
|
||||
.transactionId(transactionId)
|
||||
.status(AcquisitionStatus.PENDING)
|
||||
.build();
|
||||
|
||||
Acquisition saved = acquisitionRepository.save(acquisition);
|
||||
log.info("매입 요청 등록 완료: transactionId={}", transactionId);
|
||||
return toResponse(saved);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public AcquisitionResponse approveAcquisition(String transactionId) {
|
||||
log.info("매입 승인 처리: transactionId={}", transactionId);
|
||||
|
||||
Acquisition acquisition = acquisitionRepository.findByTransactionId(transactionId)
|
||||
.orElseThrow(() -> new AcquisitionNotFoundException("매입 정보를 찾을 수 없습니다: " + transactionId));
|
||||
|
||||
if (acquisition.getStatus() != AcquisitionStatus.PENDING) {
|
||||
throw new InvalidAcquisitionStateException("대기 상태의 매입만 승인할 수 있습니다. 현재 상태: " + acquisition.getStatus());
|
||||
}
|
||||
|
||||
String approvalCode = generateApprovalCode();
|
||||
acquisition.approve(approvalCode);
|
||||
Acquisition saved = acquisitionRepository.save(acquisition);
|
||||
log.info("매입 승인 완료: transactionId={}, approvalCode={}", transactionId, approvalCode);
|
||||
return toResponse(saved);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public AcquisitionResponse rejectAcquisition(String transactionId, String reason) {
|
||||
log.info("매입 거절 처리: transactionId={}, reason={}", transactionId, reason);
|
||||
|
||||
Acquisition acquisition = acquisitionRepository.findByTransactionId(transactionId)
|
||||
.orElseThrow(() -> new AcquisitionNotFoundException("매입 정보를 찾을 수 없습니다: " + transactionId));
|
||||
|
||||
if (acquisition.getStatus() != AcquisitionStatus.PENDING) {
|
||||
throw new InvalidAcquisitionStateException("대기 상태의 매입만 거절할 수 있습니다. 현재 상태: " + acquisition.getStatus());
|
||||
}
|
||||
|
||||
acquisition.reject(reason);
|
||||
return toResponse(acquisitionRepository.save(acquisition));
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public AcquisitionResponse getAcquisition(String transactionId) {
|
||||
return toResponse(acquisitionRepository.findByTransactionId(transactionId)
|
||||
.orElseThrow(() -> new AcquisitionNotFoundException("매입 정보를 찾을 수 없습니다: " + transactionId)));
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<AcquisitionResponse> getAcquisitionsByMerchant(String merchantId) {
|
||||
return acquisitionRepository.findByMerchantId(merchantId).stream().map(this::toResponse).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<AcquisitionResponse> getPendingAcquisitions() {
|
||||
return acquisitionRepository.findByStatus(AcquisitionStatus.PENDING).stream().map(this::toResponse).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String generateTransactionId() {
|
||||
return "TXN" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
|
||||
}
|
||||
|
||||
private String generateApprovalCode() {
|
||||
return String.format("%06d", (int) (Math.random() * 1000000));
|
||||
}
|
||||
|
||||
private String maskCardNumber(String cardNumber) {
|
||||
if (cardNumber == null || cardNumber.length() < 10) return cardNumber;
|
||||
return cardNumber.substring(0, 6) + "****" + cardNumber.substring(cardNumber.length() - 4);
|
||||
}
|
||||
|
||||
private AcquisitionResponse toResponse(Acquisition a) {
|
||||
return AcquisitionResponse.builder()
|
||||
.id(a.getId()).transactionId(a.getTransactionId()).merchantId(a.getMerchantId())
|
||||
.cardNumber(a.getCardNumber()).amount(a.getAmount()).status(a.getStatus())
|
||||
.approvalCode(a.getApprovalCode()).approvedAt(a.getApprovedAt())
|
||||
.createdAt(a.getCreatedAt()).updatedAt(a.getUpdatedAt()).build();
|
||||
}
|
||||
}
|
||||
|
||||
/** DTOs */
|
||||
@lombok.Getter @lombok.Setter @lombok.NoArgsConstructor @lombok.AllArgsConstructor @lombok.Builder
|
||||
class AcquisitionRequest {
|
||||
@jakarta.validation.constraints.NotBlank @jakarta.validation.constraints.Size(max = 20)
|
||||
private String merchantId;
|
||||
@jakarta.validation.constraints.NotBlank @jakarta.validation.constraints.Pattern(regexp = "\\d{13,19}")
|
||||
private String cardNumber;
|
||||
@jakarta.validation.constraints.NotNull @jakarta.validation.constraints.DecimalMin("0.01")
|
||||
private BigDecimal amount;
|
||||
}
|
||||
|
||||
@lombok.Getter @lombok.Setter @lombok.NoArgsConstructor @lombok.AllArgsConstructor @lombok.Builder
|
||||
class AcquisitionResponse {
|
||||
private Long id; private String transactionId; private String merchantId;
|
||||
private String cardNumber; private BigDecimal amount; private AcquisitionStatus status;
|
||||
private String approvalCode; private LocalDateTime approvedAt;
|
||||
private LocalDateTime createdAt; private LocalDateTime updatedAt;
|
||||
}
|
||||
|
||||
/** Repository */
|
||||
@Repository
|
||||
interface AcquisitionRepository extends JpaRepository<Acquisition, Long> {
|
||||
Optional<Acquisition> findByTransactionId(String transactionId);
|
||||
List<Acquisition> findByMerchantId(String merchantId);
|
||||
List<Acquisition> findByStatus(AcquisitionStatus status);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue