PaymentService.java
package com.testforge.mockbank.service;
import com.testforge.mockbank.dto.CreatePaymentRequest;
import com.testforge.mockbank.dto.RefundRequest;
import com.testforge.mockbank.exception.PaymentNotFoundException;
import com.testforge.mockbank.exception.PaymentNotRefundableException;
import com.testforge.mockbank.model.Payment;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class PaymentService {
private final Map<String, Payment> store = new ConcurrentHashMap<>();
public Payment createPayment(CreatePaymentRequest req) {
String id = "pay_" + UUID.randomUUID().toString().replace("-", "").substring(0, 12);
Instant now = Instant.now();
Payment payment = Payment.builder()
.id(id)
.merchantId(req.getMerchantId())
.customerId(req.getCustomerId())
.amount(req.getAmount())
.currency(req.getCurrency())
.description(req.getDescription())
.status(Payment.PaymentStatus.COMPLETED)
.createdAt(now)
.updatedAt(now)
.build();
store.put(id, payment);
return payment;
}
public Payment getPayment(String id) {
Payment payment = store.get(id);
if (payment == null) {
throw new PaymentNotFoundException(id);
}
return payment;
}
public Payment refundPayment(String id, RefundRequest req) {
Payment payment = getPayment(id);
if (payment.getStatus() != Payment.PaymentStatus.COMPLETED) {
throw new PaymentNotRefundableException(id, payment.getStatus());
}
BigDecimal refundAmount = req.getAmount() != null ? req.getAmount() : payment.getAmount();
if (refundAmount.compareTo(payment.getAmount()) > 0) {
throw new IllegalArgumentException(
"Refund amount " + refundAmount + " exceeds original payment amount " + payment.getAmount());
}
Payment.PaymentStatus newStatus = refundAmount.compareTo(payment.getAmount()) == 0
? Payment.PaymentStatus.REFUNDED
: Payment.PaymentStatus.PARTIALLY_REFUNDED;
Payment updated = Payment.builder()
.id(payment.getId())
.merchantId(payment.getMerchantId())
.customerId(payment.getCustomerId())
.amount(payment.getAmount())
.currency(payment.getCurrency())
.description(payment.getDescription())
.status(newStatus)
.refundReason(req.getReason())
.createdAt(payment.getCreatedAt())
.updatedAt(Instant.now())
.build();
store.put(id, updated);
return updated;
}
}