Compare commits
8 commits
main
...
forge/ACX-
| Author | SHA1 | Date | |
|---|---|---|---|
| 39da577136 | |||
| fbfedacd2d | |||
| ed01b7c89f | |||
| 669cdbb6c2 | |||
| 33c469025d | |||
| 6ede413ce7 | |||
| ae3098fd0f | |||
| 6fb9c086ce |
8 changed files with 582 additions and 0 deletions
57
pom.xml
Normal file
57
pom.xml
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.2.5</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.acquirex</groupId>
|
||||
<artifactId>proj-acquirex</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<name>proj-acquirex</name>
|
||||
<description>카드 매입 승인 시스템 - Spring Boot 3</description>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
12
src/main/java/com/acquirex/AcquirexApplication.java
Normal file
12
src/main/java/com/acquirex/AcquirexApplication.java
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package com.acquirex;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class AcquirexApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AcquirexApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.acquirex.controller;
|
||||
|
||||
import com.acquirex.dto.AcquisitionDto.Request;
|
||||
import com.acquirex.dto.AcquisitionDto.Response;
|
||||
import com.acquirex.entity.CardAcquisition;
|
||||
import com.acquirex.service.CardAcquisitionService;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 카드 매입 승인 REST API 컨트롤러
|
||||
* Spring Boot 3: @RestController, @RequestMapping 유지
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/acquisitions")
|
||||
public class CardAcquisitionController {
|
||||
|
||||
private final CardAcquisitionService acquisitionService;
|
||||
|
||||
public CardAcquisitionController(CardAcquisitionService acquisitionService) {
|
||||
this.acquisitionService = acquisitionService;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Response> requestAcquisition(@Valid @RequestBody Request request) {
|
||||
Response response = acquisitionService.processAcquisition(request);
|
||||
if ("APPROVED".equals(response.getStatus())) {
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(response);
|
||||
}
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<CardAcquisition> getAcquisition(@PathVariable Long id) {
|
||||
return ResponseEntity.ok(acquisitionService.findById(id));
|
||||
}
|
||||
|
||||
@GetMapping("/approval/{approvalCode}")
|
||||
public ResponseEntity<CardAcquisition> getByApprovalCode(@PathVariable String approvalCode) {
|
||||
return ResponseEntity.ok(acquisitionService.findByApprovalCode(approvalCode));
|
||||
}
|
||||
}
|
||||
88
src/main/java/com/acquirex/dto/AcquisitionDto.java
Normal file
88
src/main/java/com/acquirex/dto/AcquisitionDto.java
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
package com.acquirex.dto;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 카드 매입 요청/응답 DTO
|
||||
* Spring Boot 3: javax.validation → jakarta.validation
|
||||
*/
|
||||
public class AcquisitionDto {
|
||||
|
||||
// ========== Request DTO ==========
|
||||
public static class Request {
|
||||
@NotBlank(message = "카드번호는 필수입니다")
|
||||
@Size(min = 13, max = 19, message = "카드번호 길이가 올바르지 않습니다")
|
||||
private String cardNumber;
|
||||
|
||||
@NotBlank(message = "가맹점ID는 필수입니다")
|
||||
private String merchantId;
|
||||
|
||||
@NotNull(message = "금액은 필수입니다")
|
||||
@DecimalMin(value = "0.01", message = "금액은 0보다 커야 합니다")
|
||||
@Digits(integer = 13, fraction = 2, message = "금액 형식이 올바르지 않습니다")
|
||||
private BigDecimal amount;
|
||||
|
||||
@NotBlank(message = "통화는 필수입니다")
|
||||
@Size(min = 3, max = 3, message = "통화 코드는 3자리입니다")
|
||||
private String currency;
|
||||
|
||||
public String getCardNumber() { return cardNumber; }
|
||||
public void setCardNumber(String cardNumber) { this.cardNumber = cardNumber; }
|
||||
public String getMerchantId() { return merchantId; }
|
||||
public void setMerchantId(String merchantId) { this.merchantId = merchantId; }
|
||||
public BigDecimal getAmount() { return amount; }
|
||||
public void setAmount(BigDecimal amount) { this.amount = amount; }
|
||||
public String getCurrency() { return currency; }
|
||||
public void setCurrency(String currency) { this.currency = currency; }
|
||||
}
|
||||
|
||||
// ========== Response DTO ==========
|
||||
public static class Response {
|
||||
private Long id;
|
||||
private String approvalCode;
|
||||
private String status;
|
||||
private String message;
|
||||
private BigDecimal amount;
|
||||
private String currency;
|
||||
private LocalDateTime approvalTime;
|
||||
|
||||
public Response() {}
|
||||
|
||||
public static Response success(Long id, String approvalCode, BigDecimal amount, String currency) {
|
||||
Response response = new Response();
|
||||
response.setId(id);
|
||||
response.setApprovalCode(approvalCode);
|
||||
response.setStatus("APPROVED");
|
||||
response.setMessage("매입 승인이 완료되었습니다");
|
||||
response.setAmount(amount);
|
||||
response.setCurrency(currency);
|
||||
response.setApprovalTime(LocalDateTime.now());
|
||||
return response;
|
||||
}
|
||||
|
||||
public static Response rejected(Long id, String reason) {
|
||||
Response response = new Response();
|
||||
response.setId(id);
|
||||
response.setStatus("REJECTED");
|
||||
response.setMessage(reason);
|
||||
return response;
|
||||
}
|
||||
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public String getApprovalCode() { return approvalCode; }
|
||||
public void setApprovalCode(String approvalCode) { this.approvalCode = approvalCode; }
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
public BigDecimal getAmount() { return amount; }
|
||||
public void setAmount(BigDecimal amount) { this.amount = amount; }
|
||||
public String getCurrency() { return currency; }
|
||||
public void setCurrency(String currency) { this.currency = currency; }
|
||||
public LocalDateTime getApprovalTime() { return approvalTime; }
|
||||
public void setApprovalTime(LocalDateTime approvalTime) { this.approvalTime = approvalTime; }
|
||||
}
|
||||
}
|
||||
89
src/main/java/com/acquirex/entity/CardAcquisition.java
Normal file
89
src/main/java/com/acquirex/entity/CardAcquisition.java
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
package com.acquirex.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 카드 매입 승인 엔티티 및 리포지토리
|
||||
* Spring Boot 3: javax.persistence → jakarta.persistence
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "card_acquisitions")
|
||||
public class CardAcquisition {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "card_number", nullable = false, length = 16)
|
||||
private String cardNumber;
|
||||
|
||||
@Column(name = "merchant_id", nullable = false)
|
||||
private String merchantId;
|
||||
|
||||
@Column(name = "amount", nullable = false, precision = 15, scale = 2)
|
||||
private BigDecimal amount;
|
||||
|
||||
@Column(name = "currency", nullable = false, length = 3)
|
||||
private String currency;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "status", nullable = false, length = 20)
|
||||
private AcquisitionStatus status;
|
||||
|
||||
@Column(name = "approval_code", length = 12)
|
||||
private String approvalCode;
|
||||
|
||||
@Column(name = "request_time", nullable = false)
|
||||
private LocalDateTime requestTime;
|
||||
|
||||
@Column(name = "approval_time")
|
||||
private LocalDateTime approvalTime;
|
||||
|
||||
@Column(name = "reject_reason", length = 255)
|
||||
private String rejectReason;
|
||||
|
||||
public enum AcquisitionStatus {
|
||||
PENDING, APPROVED, REJECTED, CANCELLED
|
||||
}
|
||||
|
||||
public CardAcquisition() {
|
||||
this.requestTime = LocalDateTime.now();
|
||||
this.status = AcquisitionStatus.PENDING;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public String getCardNumber() { return cardNumber; }
|
||||
public void setCardNumber(String cardNumber) { this.cardNumber = cardNumber; }
|
||||
public String getMerchantId() { return merchantId; }
|
||||
public void setMerchantId(String merchantId) { this.merchantId = merchantId; }
|
||||
public BigDecimal getAmount() { return amount; }
|
||||
public void setAmount(BigDecimal amount) { this.amount = amount; }
|
||||
public String getCurrency() { return currency; }
|
||||
public void setCurrency(String currency) { this.currency = currency; }
|
||||
public AcquisitionStatus getStatus() { return status; }
|
||||
public void setStatus(AcquisitionStatus status) { this.status = status; }
|
||||
public String getApprovalCode() { return approvalCode; }
|
||||
public void setApprovalCode(String approvalCode) { this.approvalCode = approvalCode; }
|
||||
public LocalDateTime getRequestTime() { return requestTime; }
|
||||
public void setRequestTime(LocalDateTime requestTime) { this.requestTime = requestTime; }
|
||||
public LocalDateTime getApprovalTime() { return approvalTime; }
|
||||
public void setApprovalTime(LocalDateTime approvalTime) { this.approvalTime = approvalTime; }
|
||||
public String getRejectReason() { return rejectReason; }
|
||||
public void setRejectReason(String rejectReason) { this.rejectReason = rejectReason; }
|
||||
|
||||
@Repository
|
||||
public interface CardAcquisitionRepository extends JpaRepository<CardAcquisition, Long> {
|
||||
List<CardAcquisition> findByStatus(AcquisitionStatus status);
|
||||
Optional<CardAcquisition> findByApprovalCode(String approvalCode);
|
||||
List<CardAcquisition> findByMerchantId(String merchantId);
|
||||
}
|
||||
}
|
||||
116
src/main/java/com/acquirex/service/CardAcquisitionService.java
Normal file
116
src/main/java/com/acquirex/service/CardAcquisitionService.java
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
package com.acquirex.service;
|
||||
|
||||
import com.acquirex.dto.AcquisitionDto.Request;
|
||||
import com.acquirex.dto.AcquisitionDto.Response;
|
||||
import com.acquirex.entity.CardAcquisition;
|
||||
import com.acquirex.entity.CardAcquisition.AcquisitionStatus;
|
||||
import com.acquirex.entity.CardAcquisition.CardAcquisitionRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Random;
|
||||
|
||||
@Service
|
||||
public class CardAcquisitionService {
|
||||
|
||||
private static final BigDecimal MAX_APPROVAL_AMOUNT = new BigDecimal("10000000");
|
||||
private static final BigDecimal SUSPICIOUS_AMOUNT_THRESHOLD = new BigDecimal("5000000");
|
||||
|
||||
private final CardAcquisitionRepository repository;
|
||||
private final Random approvalCodeGenerator = new Random();
|
||||
|
||||
public CardAcquisitionService(CardAcquisitionRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Response processAcquisition(Request request) {
|
||||
CardAcquisition acquisition = createAcquisition(request);
|
||||
CardAcquisition saved = repository.save(acquisition);
|
||||
|
||||
if (!validateCardNumber(request.getCardNumber())) {
|
||||
return rejectAcquisition(saved, "유효하지 않은 카드번호입니다");
|
||||
}
|
||||
|
||||
if (request.getAmount().compareTo(MAX_APPROVAL_AMOUNT) > 0) {
|
||||
return rejectAcquisition(saved, "승인 한도를 초과했습니다");
|
||||
}
|
||||
|
||||
if (isSuspiciousTransaction(request)) {
|
||||
return rejectAcquisition(saved, "의심스러운 거래로 거부되었습니다");
|
||||
}
|
||||
|
||||
return approveAcquisition(saved);
|
||||
}
|
||||
|
||||
private CardAcquisition createAcquisition(Request request) {
|
||||
CardAcquisition acquisition = new CardAcquisition();
|
||||
acquisition.setCardNumber(maskCardNumber(request.getCardNumber()));
|
||||
acquisition.setMerchantId(request.getMerchantId());
|
||||
acquisition.setAmount(request.getAmount());
|
||||
acquisition.setCurrency(request.getCurrency());
|
||||
acquisition.setStatus(AcquisitionStatus.PENDING);
|
||||
return acquisition;
|
||||
}
|
||||
|
||||
private boolean validateCardNumber(String cardNumber) {
|
||||
if (cardNumber == null || cardNumber.length() < 13) return false;
|
||||
int sum = 0;
|
||||
boolean alternate = false;
|
||||
for (int i = cardNumber.length() - 1; i >= 0; i--) {
|
||||
int digit = Character.getNumericValue(cardNumber.charAt(i));
|
||||
if (alternate) {
|
||||
digit *= 2;
|
||||
if (digit > 9) digit -= 9;
|
||||
}
|
||||
sum += digit;
|
||||
alternate = !alternate;
|
||||
}
|
||||
return sum % 10 == 0;
|
||||
}
|
||||
|
||||
private boolean isSuspiciousTransaction(Request request) {
|
||||
return request.getAmount().compareTo(SUSPICIOUS_AMOUNT_THRESHOLD) >= 0
|
||||
&& request.getCardNumber().startsWith("9999");
|
||||
}
|
||||
|
||||
private String generateApprovalCode() {
|
||||
return String.format("%06d", approvalCodeGenerator.nextInt(999999));
|
||||
}
|
||||
|
||||
private String maskCardNumber(String cardNumber) {
|
||||
if (cardNumber == null || cardNumber.length() < 8) return cardNumber;
|
||||
return cardNumber.substring(0, 4) + "****" + cardNumber.substring(cardNumber.length() - 4);
|
||||
}
|
||||
|
||||
private Response approveAcquisition(CardAcquisition acquisition) {
|
||||
String approvalCode = generateApprovalCode();
|
||||
acquisition.setStatus(AcquisitionStatus.APPROVED);
|
||||
acquisition.setApprovalCode(approvalCode);
|
||||
acquisition.setApprovalTime(LocalDateTime.now());
|
||||
repository.save(acquisition);
|
||||
return Response.success(acquisition.getId(), approvalCode, acquisition.getAmount(), acquisition.getCurrency());
|
||||
}
|
||||
|
||||
private Response rejectAcquisition(CardAcquisition acquisition, String reason) {
|
||||
acquisition.setStatus(AcquisitionStatus.REJECTED);
|
||||
acquisition.setRejectReason(reason);
|
||||
acquisition.setApprovalTime(LocalDateTime.now());
|
||||
repository.save(acquisition);
|
||||
return Response.rejected(acquisition.getId(), reason);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public CardAcquisition findById(Long id) {
|
||||
return repository.findById(id)
|
||||
.orElseThrow(() -> new IllegalArgumentException("매입 정보를 찾을 수 없습니다: " + id));
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public CardAcquisition findByApprovalCode(String approvalCode) {
|
||||
return repository.findByApprovalCode(approvalCode)
|
||||
.orElseThrow(() -> new IllegalArgumentException("승인코드를 찾을 수 없습니다: " + approvalCode));
|
||||
}
|
||||
}
|
||||
31
src/main/resources/application.yml
Normal file
31
src/main/resources/application.yml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
spring:
|
||||
application:
|
||||
name: proj-acquirex
|
||||
|
||||
datasource:
|
||||
url: jdbc:h2:mem:acquirexdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
||||
driver-class-name: org.h2.Driver
|
||||
username: sa
|
||||
password:
|
||||
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: create-drop
|
||||
show-sql: true
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: true
|
||||
dialect: org.hibernate.dialect.H2Dialect
|
||||
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
path: /h2-console
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
logging:
|
||||
level:
|
||||
com.acquirex: DEBUG
|
||||
org.hibernate.SQL: DEBUG
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
package com.acquirex.service;
|
||||
|
||||
import com.acquirex.dto.AcquisitionDto.Request;
|
||||
import com.acquirex.dto.AcquisitionDto.Response;
|
||||
import com.acquirex.entity.CardAcquisition;
|
||||
import com.acquirex.entity.CardAcquisition.CardAcquisitionRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class CardAcquisitionServiceTest {
|
||||
|
||||
@Mock
|
||||
private CardAcquisitionRepository repository;
|
||||
|
||||
private CardAcquisitionService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new CardAcquisitionService(repository);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("유효한 카드로 정상 승인 처리")
|
||||
void processAcquisition_ValidCard_ShouldApprove() {
|
||||
Request request = new Request();
|
||||
request.setCardNumber("4532015112830366");
|
||||
request.setMerchantId("MERCHANT001");
|
||||
request.setAmount(new BigDecimal("100000"));
|
||||
request.setCurrency("KRW");
|
||||
|
||||
when(repository.save(any(CardAcquisition.class)))
|
||||
.thenAnswer(invocation -> {
|
||||
CardAcquisition acq = invocation.getArgument(0);
|
||||
acq.setId(1L);
|
||||
return acq;
|
||||
});
|
||||
|
||||
Response response = service.processAcquisition(request);
|
||||
|
||||
assertEquals("APPROVED", response.getStatus());
|
||||
assertNotNull(response.getApprovalCode());
|
||||
assertEquals(6, response.getApprovalCode().length());
|
||||
assertEquals(new BigDecimal("100000"), response.getAmount());
|
||||
assertEquals("KRW", response.getCurrency());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("유효하지 않은 카드번호 거부")
|
||||
void processAcquisition_InvalidCardNumber_ShouldReject() {
|
||||
Request request = new Request();
|
||||
request.setCardNumber("1234567890123456");
|
||||
request.setMerchantId("MERCHANT001");
|
||||
request.setAmount(new BigDecimal("50000"));
|
||||
request.setCurrency("KRW");
|
||||
|
||||
when(repository.save(any(CardAcquisition.class)))
|
||||
.thenAnswer(invocation -> {
|
||||
CardAcquisition acq = invocation.getArgument(0);
|
||||
acq.setId(1L);
|
||||
return acq;
|
||||
});
|
||||
|
||||
Response response = service.processAcquisition(request);
|
||||
|
||||
assertEquals("REJECTED", response.getStatus());
|
||||
assertNull(response.getApprovalCode());
|
||||
assertTrue(response.getMessage().contains("유효하지 않은"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("한도 초과 거래 거부")
|
||||
void processAcquisition_ExceedLimit_ShouldReject() {
|
||||
Request request = new Request();
|
||||
request.setCardNumber("4532015112830366");
|
||||
request.setMerchantId("MERCHANT001");
|
||||
request.setAmount(new BigDecimal("15000000"));
|
||||
request.setCurrency("KRW");
|
||||
|
||||
when(repository.save(any(CardAcquisition.class)))
|
||||
.thenAnswer(invocation -> {
|
||||
CardAcquisition acq = invocation.getArgument(0);
|
||||
acq.setId(1L);
|
||||
return acq;
|
||||
});
|
||||
|
||||
Response response = service.processAcquisition(request);
|
||||
|
||||
assertEquals("REJECTED", response.getStatus());
|
||||
assertTrue(response.getMessage().contains("한도"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("의심스러운 거래 거부 (9999 시작 + 고액)")
|
||||
void processAcquisition_SuspiciousTransaction_ShouldReject() {
|
||||
Request request = new Request();
|
||||
request.setCardNumber("9999123456789012");
|
||||
request.setMerchantId("MERCHANT001");
|
||||
request.setAmount(new BigDecimal("6000000"));
|
||||
request.setCurrency("KRW");
|
||||
|
||||
when(repository.save(any(CardAcquisition.class)))
|
||||
.thenAnswer(invocation -> {
|
||||
CardAcquisition acq = invocation.getArgument(0);
|
||||
acq.setId(1L);
|
||||
return acq;
|
||||
});
|
||||
|
||||
Response response = service.processAcquisition(request);
|
||||
|
||||
assertEquals("REJECTED", response.getStatus());
|
||||
assertTrue(response.getMessage().contains("의심스러운"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("카드번호 마스킹 처리 확인")
|
||||
void processAcquisition_CardNumberMasked() {
|
||||
Request request = new Request();
|
||||
request.setCardNumber("4532015112830366");
|
||||
request.setMerchantId("MERCHANT001");
|
||||
request.setAmount(new BigDecimal("100000"));
|
||||
request.setCurrency("KRW");
|
||||
|
||||
when(repository.save(any(CardAcquisition.class)))
|
||||
.thenAnswer(invocation -> {
|
||||
CardAcquisition acq = invocation.getArgument(0);
|
||||
acq.setId(1L);
|
||||
return acq;
|
||||
});
|
||||
|
||||
service.processAcquisition(request);
|
||||
|
||||
verify(repository, times(2)).save(argThat(acq -> acq.getCardNumber().equals("4532****0366")));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue