Bugnik
← All problems

03Fulfillment Inventory Reservation API

Java · Spring BootEasyBug fixSuggested time: 60 min

Inventory reservation REST API (CSV stock load)

Sign in to start

Before you start

You'll get more out of this problem if you're comfortable with:

Language

  • Java packages and imports, and reading javac / Maven compile errors
  • Java records, Optional and streams (filter, sorted, map)

Libraries and frameworks

  • Spring Boot basics: @RestController, @Service, @Repository and constructor injection
  • HTTP status codes for APIs (200, 201, 400, 404, 409) and @RestControllerAdvice
  • Bean Validation on request bodies (@Valid, @NotBlank, @Positive)

Build and test tools

  • Reading JUnit 5 / MockMvc test failures

Reasoning

  • Inclusive vs exclusive comparisons in business rules

Background

The Fulfillment Systems team at a large online retailer runs the service that promises stock to customer orders. When a customer checks out, the order service reserves units; when the warehouse ships, it commits them; when an order is cancelled, it releases them. Since the last deployment, checkouts are failing for items that are clearly in stock, and the order service is getting error codes it doesn't expect.

How the system works

Stock file

Stock is loaded from a CSV string, one sku,name,onHand row per line:

sku,name,onHand
KB-100,Mechanical keyboard,5
MS-200,Wireless mouse,12
  • If the first non-blank line starts with sku (any case), it is a header and is skipped. Blank lines are ignored, and every field is trimmed (so Windows \r\n line endings work).
  • Each row must have exactly 3 fields. The SKU must not be empty. onHand must be a whole number ≥ 0. A SKU may appear only once. Any violation throws InvalidRequestException.
  • Loading a stock file replaces all stock and clears every reservation. Reservation ids restart at R-0001.

SKUs

SKUs are case-insensitive and trimmed: " kb-100 ", "kb-100" and "KB-100" are the same SKU. SKUs are stored and returned in upper case.

Stock numbers

  • onHand: units physically in the building.
  • reserved: units promised to orders that haven't shipped.
  • available = onHand − reserved.

Reservations

OperationRule
reserve(orderId, sku, quantity)orderId must not be blank and quantity must be > 0 (else InvalidRequestException). Unknown SKU → NotFoundException. The reservation succeeds when quantity <= available (an order may take the very last units). Otherwise InsufficientStockException, and nothing changes. On success reserved grows by quantity, and a HELD reservation with the next id (R-0001, R-0002, …) is returned.
release(id)HELD → RELEASED; reserved shrinks by the quantity. Releasing a RELEASED reservation again returns it unchanged. Releasing a COMMITTED one → IllegalTransitionException.
commit(id)HELD → COMMITTED; both onHand and reserved shrink by the quantity. Committing a COMMITTED reservation again returns it unchanged. Committing a RELEASED one → IllegalTransitionException.
lowStock(threshold)SKUs whose available is at or below threshold, sorted by available ascending, then SKU ascending. A negative threshold → InvalidRequestException.

Unknown reservation ids → NotFoundException.

API

Method + pathSuccessNotes
GET /api/stock/{sku}200 + {"sku","name","onHand","reserved","available"}
GET /api/stock/low?threshold=N200 + list of the same objectsthreshold defaults to 5
POST /api/reservations with {"orderId","sku","quantity"}201 + {"id","orderId","sku","quantity","status"}body is validated
POST /api/reservations/{id}/release200 + reservation
POST /api/reservations/{id}/commit200 + reservation

Errors return {"error": "<CODE>", "message": "<detail>"}:

ExceptionHTTP statuserror
NotFoundException404NOT_FOUND
InsufficientStockException409INSUFFICIENT_STOCK
IllegalTransitionException409INVALID_TRANSITION
InvalidRequestException, or a request body failing validation400INVALID_REQUEST

Project structure

src/main/java/com/bugnik/inventory/
  InventoryApplication.java      Spring Boot entry point
  model/        StockItem, Reservation, ReservationStatus, StockView
  repository/   StockRepository, ReservationRepository (in-memory)
  service/      InventoryService (the rules above) + business exceptions
  util/         Skus (normalization), StockCsvParser (stock file)
  web/          InventoryController, ReserveRequest, ApiError, ApiExceptionHandler
src/test/java/...                unit tests and MockMvc API tests
pom.xml                          Maven build (Spring Boot 3.3, Java 17)

Your task

The order service and the warehouse team have reported problems since the last release:

  • The project no longer builds.
  • Customers can't check out the last few units of an item, even though the stock page shows them as available.
  • When an item really is out of stock, the order service receives a "bad request" error instead of a conflict, so it shows customers the wrong message.

Find and fix the defects so that all tests pass.

  • Do not modify anything in src/test/ or pom.xml.
  • Keep your changes minimal. Fix the defects; don't rewrite modules.
  • Additional hidden tests check the behaviour described in this README.