Design Credit Card Payment Processing System
Design an in-memory payment processing system that handles credit card transactions through multiple payment gateways, such as Stripe and PayPal.
The system must support registering gateways, enabling or disabling them, processing payments, issuing full refunds, and checking transaction status.
Payment Gateway Rules
- Every payment gateway has a unique, case-sensitive name.
- A newly registered gateway is enabled by default.
- Each gateway supports a list of currencies.
- An empty currency list means that the gateway supports every currency.
- Disabled gateways cannot process new payments.
Gateway Selection
- If the preferred gateway is enabled and supports the transaction currency, use it.
- Otherwise, use the lexicographically smallest enabled gateway that supports the currency.
- An empty preferred gateway name means that no gateway is preferred.
- If no eligible gateway exists, the payment fails.
Credit Card Rules
- A valid card number contains only digits.
- Its length must be between 12 and 19 characters, inclusive.
- No Luhn checksum or card-network validation is required.
- The full card number must never appear in a returned value.
Transaction Rules
- Every transaction ID is case-sensitive.
- The first call using a transaction ID creates and stores its transaction result.
- Reusing a transaction ID must not create another charge and must return its currently stored result.
- When a transaction ID already exists, all other arguments supplied to
processPayment are ignored, and the currently stored result is returned without validating the new arguments.
- Only a successful payment may be refunded.
- Only full refunds are supported.
- Disabling or removing access to a gateway does not change transactions that were processed earlier.
Constructor
PaymentProcessingSystem()
- Creates an empty payment processing system.
Methods
Add Payment Gateway
boolean addPaymentGateway(String gatewayName, List<String> supportedCurrencies)
- Registers an enabled payment gateway.
- Returns
true when the gateway is added.
- Returns
false when a gateway with the same name already exists.
Enable or Disable Payment Gateway
boolean setPaymentGatewayEnabled(String gatewayName, boolean enabled)
- Updates the enabled state of an existing gateway.
- Returns
true when the gateway exists, including when it already has the requested state.
- Returns
false when the gateway does not exist.
Process Payment
String processPayment(String transactionId, String cardNumber, int amountInCents, String currency, String preferredGateway)
- If the transaction ID already exists, returns its currently stored result, including
"REFUNDED,gatewayName" for a refunded transaction.
- Returns
"SUCCESS,gatewayName" when the payment succeeds.
- Returns
"FAILED,INVALID_CARD" when the card number is invalid.
- Returns
"FAILED,NO_AVAILABLE_GATEWAY" when no eligible gateway is available.
- The result is stored using the transaction ID.
Refund Payment
boolean refundPayment(String transactionId)
- Changes a successful transaction from
SUCCESS to REFUNDED.
- Returns
true when the refund is completed.
- Returns
false when the transaction is missing, failed, or already refunded.
Get Transaction Status
String getTransactionStatus(String transactionId)
- Returns
"SUCCESS,gatewayName" for a successful payment.
- Returns
"REFUNDED,gatewayName" for a refunded payment.
- Returns the stored failure result for a failed payment.
- Returns
"NOT_FOUND" when the transaction does not exist.
Constraints
1 ≤ gatewayName.length() ≤ 50
0 ≤ supportedCurrencies.size() ≤ 50
- Every currency is a three-character uppercase string.
1 ≤ transactionId.length() ≤ 100
1 ≤ cardNumber.length() ≤ 25
1 ≤ amountInCents ≤ 100,000,000
currency.length() = 3
preferredGateway is either an empty string or a gateway name.
- At most
100 gateways may be registered.
- At most
100,000 method calls will be made.
- No parameter value will be
null.
Examples
Example 1
PaymentProcessingSystem system = new PaymentProcessingSystem()
Output: a new empty payment processing system
system.addPaymentGateway(gatewayName = "Stripe", supportedCurrencies = ["USD", "INR"])
Output: true
system.addPaymentGateway(gatewayName = "PayPal", supportedCurrencies = ["USD"])
Output: true
system.processPayment(transactionId = "txn-201", cardNumber = "5555555555554444", amountInCents = 4599, currency = "INR", preferredGateway = "PayPal")
Output: "SUCCESS,Stripe"
PayPal does not support INR, so the payment uses Stripe.
system.refundPayment(transactionId = "txn-201")
Output: true
system.getTransactionStatus(transactionId = "txn-201")
Output: "REFUNDED,Stripe"
Example 2
PaymentProcessingSystem system = new PaymentProcessingSystem()
Output: a new empty payment processing system
system.addPaymentGateway(gatewayName = "Stripe", supportedCurrencies = ["USD"])
Output: true
system.addPaymentGateway(gatewayName = "PayPal", supportedCurrencies = ["USD"])
Output: true
system.processPayment(transactionId = "txn-305", cardNumber = "4111111111111111", amountInCents = 2500, currency = "USD", preferredGateway = "")
Output: "SUCCESS,PayPal"
Both gateways are eligible, so the lexicographically smaller name, PayPal, is selected.
Example 3
PaymentProcessingSystem system = new PaymentProcessingSystem()
Output: a new empty payment processing system
system.addPaymentGateway(gatewayName = "PayPal", supportedCurrencies = [])
Output: true
system.setPaymentGatewayEnabled(gatewayName = "PayPal", enabled = false)
Output: true
system.processPayment(transactionId = "txn-410", cardNumber = "1234-5678", amountInCents = 1800, currency = "EUR", preferredGateway = "PayPal")
Output: "FAILED,INVALID_CARD"
system.getTransactionStatus(transactionId = "missing-transaction")
Output: "NOT_FOUND"