Skip to content

Rishab-Kumar-R/multi-topup-deduction-engine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Multi-TopUp Deduction Engine

A Spring Boot service that deducts an amount from a client's balance, where the balance is split across multiple top-ups (each with its own remaining amount and expiry date), rather than a single wallet.

Problem

A client's funds are not one number - they are a stack of top-ups, each independently credited with its own remaining balance and expiry date. When a deduction is requested, the amount must be drawn across these top-ups in order of soonest-expiring-first, partially draining each one as needed, until either the full amount is collected or the client runs out of usable top-ups.

If the full amount cannot be collected, none of it should go through - every top-up touched during the attempt must be restored to its original balance.

Stack

  • Java 21
  • Spring Boot 4.1
  • Spring Data JPA
  • H2 (in-memory)
  • Maven

Running

./mvnw spring-boot:run

The app starts on http://localhost:8080. H2 console (if enabled) is at /h2-console.

API

Create a top-up

POST /topups
Content-Type: application/json

{
  "clientId": 1,
  "amount": 30.00,
  "expiryDate": "2026-08-10"
}

expiryDate must be today or later - past dates are rejected by the deduction query as already-expired.

Response 201 Created:

{
  "topUpId": 1,
  "balance": 30.00,
  "expiryDate": "2026-08-10"
}

View a client's top-up balances

GET /topups/{clientId}

Response 200 OK:

[
  {
    "topUpId": 1,
    "balance": 30.00,
    "expiryDate": "2026-08-10"
  },
  {
    "topUpId": 2,
    "balance": 50.00,
    "expiryDate": "2026-08-20"
  }
]

Deduct an amount

POST /deductions
Content-Type: application/json

{
  "clientId": 1,
  "amount": 65.00
}

Success - 200 OK, full amount collected across one or more top-ups:

{
  "success": true,
  "message": "Deduction successful",
  "breakdown": [
    {
      "topUpId": 1,
      "amountTaken": 30.00
    },
    {
      "topUpId": 2,
      "amountTaken": 35.00
    }
  ]
}

Failure - 422 Unprocessable Content, insufficient total balance across all unexpired top-ups; nothing is deducted, every touched top-up is restored to its pre-request balance:

{
  "success": false,
  "message": "Insufficient funds. No amount was deducted; all top-up balances remain unchanged.",
  "breakdown": []
}

Error responses

  • 400 Bad Request - validation failure (e.g. non-positive amount, missing field)
  • 404 Not Found - unknown clientId

About

Spring Boot backend that deducts an amount across a client's multiple top-ups (earliest-expiry-first), with manual track-and-restore rollback on insufficient funds.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages