카드 매입 승인 경로 Spring Boot 3 전환 (ACX-E2E-1785394564819)

This commit is contained in:
forge-bot 2026-07-30 07:29:36 +00:00
parent 692278427d
commit 9e8112e4d7

View file

@ -0,0 +1,191 @@
package com.acquirex.controller;
import com.acquirex.dto.ApprovalRequest;
import com.acquirex.dto.ApprovalResponse;
import com.acquirex.exception.ApprovalProcessingException;
import com.acquirex.exception.GlobalExceptionHandler;
import com.acquirex.service.AcquisitionApprovalService;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/v1/acquisitions")
public class AcquisitionApprovalController {
private final AcquisitionApprovalService service;
public AcquisitionApprovalController(AcquisitionApprovalService service) {
this.service = service;
}
@PostMapping
public ResponseEntity<ApprovalResponse> requestApproval(@Valid @RequestBody ApprovalRequest request) {
ApprovalResponse response = service.requestApproval(request);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
@PostMapping("/{id}/approve")
public ResponseEntity<ApprovalResponse> approve(@PathVariable Long id) {
ApprovalResponse response = service.processApproval(id, true, null);
return ResponseEntity.ok(response);
}
@PostMapping("/{id}/reject")
public ResponseEntity<ApprovalResponse> reject(@PathVariable Long id, @RequestParam String reason) {
ApprovalResponse response = service.processApproval(id, false, reason);
return ResponseEntity.ok(response);
}
@GetMapping("/{id}")
public ResponseEntity<ApprovalResponse> getApproval(@PathVariable Long id) {
ApprovalResponse response = service.getApproval(id);
return ResponseEntity.ok(response);
}
@GetMapping("/pending")
public ResponseEntity<List<ApprovalResponse>> getPendingApprovals() {
List<ApprovalResponse> responses = service.getPendingApprovals();
return ResponseEntity.ok(responses);
}
@GetMapping("/merchant/{merchantId}")
public ResponseEntity<List<ApprovalResponse>> getApprovalsByMerchant(@PathVariable String merchantId) {
List<ApprovalResponse> responses = service.getApprovalsByMerchant(merchantId);
return ResponseEntity.ok(responses);
}
}
// DTOs
class ApprovalRequest {
@jakarta.validation.constraints.NotBlank(message = "Merchant ID is required")
private String merchantId;
@jakarta.validation.constraints.NotBlank(message = "Card number is required")
@jakarta.validation.constraints.Size(min = 13, max = 19, message = "Card number must be between 13 and 19 digits")
private String cardNumber;
@jakarta.validation.constraints.NotNull(message = "Amount is required")
@jakarta.validation.constraints.DecimalMin(value = "0.01", message = "Amount must be greater than zero")
private BigDecimal amount;
@jakarta.validation.constraints.NotBlank(message = "Currency is required")
@jakarta.validation.constraints.Size(min = 3, max = 3, message = "Currency must be a 3-letter code")
private String currency;
public ApprovalRequest() {}
public ApprovalRequest(String merchantId, String cardNumber, BigDecimal amount, String currency) {
this.merchantId = merchantId;
this.cardNumber = cardNumber;
this.amount = amount;
this.currency = currency;
}
public String getMerchantId() { return merchantId; }
public void setMerchantId(String merchantId) { this.merchantId = merchantId; }
public String getCardNumber() { return cardNumber; }
public void setCardNumber(String cardNumber) { this.cardNumber = cardNumber; }
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; }
}
class ApprovalResponse {
private Long id;
private String merchantId;
private String cardNumber;
private BigDecimal amount;
private String currency;
private String status;
private String approvalCode;
private String rejectionReason;
private LocalDateTime requestedAt;
private LocalDateTime processedAt;
public ApprovalResponse() {}
public ApprovalResponse(Long id, String merchantId, String cardNumber, BigDecimal amount,
String currency, String status, String approvalCode,
String rejectionReason, LocalDateTime requestedAt, LocalDateTime processedAt) {
this.id = id;
this.merchantId = merchantId;
this.cardNumber = cardNumber;
this.amount = amount;
this.currency = currency;
this.status = status;
this.approvalCode = approvalCode;
this.rejectionReason = rejectionReason;
this.requestedAt = requestedAt;
this.processedAt = processedAt;
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getMerchantId() { return merchantId; }
public void setMerchantId(String merchantId) { this.merchantId = merchantId; }
public String getCardNumber() { return cardNumber; }
public void setCardNumber(String cardNumber) { this.cardNumber = cardNumber; }
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 String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getApprovalCode() { return approvalCode; }
public void setApprovalCode(String approvalCode) { this.approvalCode = approvalCode; }
public String getRejectionReason() { return rejectionReason; }
public void setRejectionReason(String rejectionReason) { this.rejectionReason = rejectionReason; }
public LocalDateTime getRequestedAt() { return requestedAt; }
public void setRequestedAt(LocalDateTime requestedAt) { this.requestedAt = requestedAt; }
public LocalDateTime getProcessedAt() { return processedAt; }
public void setProcessedAt(LocalDateTime processedAt) { this.processedAt = processedAt; }
}
// Exceptions
class ApprovalProcessingException extends RuntimeException {
public ApprovalProcessingException(String message) {
super(message);
}
}
@RestControllerAdvice
class GlobalExceptionHandler {
@org.springframework.web.bind.annotation.ExceptionHandler(ApprovalProcessingException.class)
public ResponseEntity<Map<String, Object>> handleApprovalProcessingException(ApprovalProcessingException ex) {
Map<String, Object> body = new HashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("status", HttpStatus.BAD_REQUEST.value());
body.put("error", "Approval Processing Error");
body.put("message", ex.getMessage());
return ResponseEntity.badRequest().body(body);
}
@org.springframework.web.bind.annotation.ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, Object> body = new HashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("status", HttpStatus.BAD_REQUEST.value());
body.put("error", "Validation Error");
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach(error -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
body.put("errors", errors);
return ResponseEntity.badRequest().body(body);
}
}