diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..afcab6c
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,57 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.5
+
+
+
+ com.acquirex
+ proj-acquirex
+ 1.0.0-SNAPSHOT
+ proj-acquirex
+ Card Acquisition Approval System - Spring Boot 3
+
+
+ 17
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ com.h2database
+ h2
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/acquirex/AcquirexApplication.java b/src/main/java/com/acquirex/AcquirexApplication.java
new file mode 100644
index 0000000..dedeed3
--- /dev/null
+++ b/src/main/java/com/acquirex/AcquirexApplication.java
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/acquirex/controller/AcquisitionApprovalController.java b/src/main/java/com/acquirex/controller/AcquisitionApprovalController.java
new file mode 100644
index 0000000..866a558
--- /dev/null
+++ b/src/main/java/com/acquirex/controller/AcquisitionApprovalController.java
@@ -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 requestApproval(@Valid @RequestBody ApprovalRequest request) {
+ ApprovalResponse response = service.requestApproval(request);
+ return ResponseEntity.status(HttpStatus.CREATED).body(response);
+ }
+
+ @PostMapping("/{id}/approve")
+ public ResponseEntity approve(@PathVariable Long id) {
+ ApprovalResponse response = service.processApproval(id, true, null);
+ return ResponseEntity.ok(response);
+ }
+
+ @PostMapping("/{id}/reject")
+ public ResponseEntity reject(@PathVariable Long id, @RequestParam String reason) {
+ ApprovalResponse response = service.processApproval(id, false, reason);
+ return ResponseEntity.ok(response);
+ }
+
+ @GetMapping("/{id}")
+ public ResponseEntity getApproval(@PathVariable Long id) {
+ ApprovalResponse response = service.getApproval(id);
+ return ResponseEntity.ok(response);
+ }
+
+ @GetMapping("/pending")
+ public ResponseEntity> getPendingApprovals() {
+ List responses = service.getPendingApprovals();
+ return ResponseEntity.ok(responses);
+ }
+
+ @GetMapping("/merchant/{merchantId}")
+ public ResponseEntity> getApprovalsByMerchant(@PathVariable String merchantId) {
+ List 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