Analyze and Debug Virtual-Card Payment Rules
Capital OneSoftware Engineer · OnsiteLast updated
Implement and debug a rule-validation engine for virtual card authorization that accurately parses currency strings into integer cents and evaluates spending boundaries and merchant restrictions.
Virtual-Card Authorization Engine
Virtual card numbers (VCNs) provide enhanced security by allowing users to generate temporary, merchant-locked, or budget-constrained card credentials linked to their primary account. When an authorization request arrives, the engine must decide whether to approve or decline the charge based on configured policy rules.
Implement a function evaluate_transaction that validates an incoming transaction against a virtual card's configuration rules and updates the card's state if approved.
Requirements
- Amount Parsing & Precision: Transaction amounts are provided as string formatted currency (e.g.,
"$124.50"or"25.00"). You must parse this into an exact integer number of cents without floating-point inaccuracies. - Card Status: The card must be active (
is_active == True) and not expired. The transaction timestamp must satisfyvalid_from <= timestamp <= expires_at(epoch seconds). - Single-Use Restriction: If
single_use == True, the card can only approve a transaction iftransactions_approved == 0. - Merchant Lock: If
merchant_lockis non-null, the transaction'smerchant_idmust matchmerchant_lockexactly. - Spending Limits:
max_per_transaction_cents: The charge amount cannot strictly exceed this limit (inclusive boundary:amount <= max_per_transaction_cents).remaining_budget_cents: The charge amount cannot exceed the remaining budget.
- State Update: If the transaction is approved, return
(True, "APPROVED")and deduct the amount fromremaining_budget_centsand incrementtransactions_approvedby1. If declined, return(False, REASON)whereREASONcorresponds to the first violated rule in the order listed above.
Function Signature
def evaluate_transaction(card: dict, txn: dict) -> tuple[bool, str]:
pass
Reason Codes
"INVALID_AMOUNT""CARD_INACTIVE_OR_EXPIRED""SINGLE_USE_EXCEEDED""MERCHANT_MISMATCH""TRANSACTION_LIMIT_EXCEEDED""INSUFFICIENT_BUDGET""APPROVED"
Example
card = {
"is_active": True,
"valid_from": 1700000000,
"expires_at": 1700003600,
"single_use": False,
"merchant_lock": "M_AMZN_01",
"max_per_transaction_cents": 10000, # $100.00
"remaining_budget_cents": 15000, # $150.00
"transactions_approved": 0
}
txn1 = {
"amount": "$99.99",
"timestamp": 1700001000,
"merchant_id": "M_AMZN_01"
}
approved, reason = evaluate_transaction(card, txn1)
# approved -> True, reason -> "APPROVED"
# card["remaining_budget_cents"] is now 5001
# card["transactions_approved"] is now 1
txn2 = {
"amount": "$55.00",
"timestamp": 1700002000,
"merchant_id": "M_AMZN_01"
}
approved, reason = evaluate_transaction(card, txn2)
# approved -> False, reason -> "INSUFFICIENT_BUDGET"
Hints
Hint 1
Avoid converting the currency string to a float before converting to cents; split the string by the decimal point or use the `decimal` module to prevent rounding errors like 0.1 + 0.2 != 0.3.
Hint 2
Pay close attention to inclusive boundary conditions (<= versus <) for validity timestamps and per-transaction limits.
Hint 3
Ensure you check conditions in the strict priority order specified and only mutate card state after all checks pass.
Follow-up questions
- How would you handle concurrent authorization requests on the same virtual card in a distributed banking service?
- If currency conversions (e.g., foreign transaction fees or EUR to USD conversion) were introduced, where should the exchange rate calculation and rounding occur?
- How would you extend this logic to support recurring subscription limits (e.g., maximum $50 per calendar month)?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.