Inventory reconciliation report
A small warehouse receives a catalogue and a sequence of physical stock counts. Counts can repeat because different shelves hold the same product. Create a deterministic report that makes discrepancies visible before anyone orders more stock. The work runs with text input in the browser; it needs no account, network request or file access.
Skills you will practise
- dictionaries and sets
- input validation
- aggregation
- deterministic sorting
- functions
Project requirements
- Read a catalogue of SKU,minimum pairs and then stock-count SKU,quantity pairs.
- Reject malformed records, duplicate catalogue SKUs and negative numbers with a clear error instead of silently changing totals.
- Sum repeated stock counts for a known SKU.
- Report unknown counted SKUs separately; do not add them to catalogue totals.
- Show every catalogue SKU, including items with no count, sorted by SKU with a LOW or OK status.
Build it in stages
- 1
Choose a precise input contract
Use the first line for the catalogue row count, then that many SKU,minimum lines. Read a stock-count row count followed by SKU,quantity lines. Require a non-empty SKU without a comma and non-negative integer amounts. Document how invalid input is reported.
- 2
Validate the catalogue
Parse each row in a helper. Reject duplicate SKUs instead of letting a later row overwrite the minimum. Store the minimum in a dictionary keyed by SKU.
- 3
Aggregate physical counts
Add repeated known-SKU quantities. Collect unknown SKUs in a set so one unknown product appears once in the warning list. A known SKU with no count remains at zero.
- 4
Produce an audit-ready report
Sort catalogue SKUs and print SKU, counted quantity, minimum and LOW or OK. Then print the sorted unknown-SKU list. A stock quantity equal to its minimum is OK.
- 5
Test the boundaries
Check repeated counts, zero stock, the equality boundary, out-of-order rows, duplicate catalogue entries, unknown SKUs and negative or non-integer quantities.
Starter code
def parse_pair(line):
# Return (sku, non_negative_integer) or raise ValueError.
pass
def reconcile(catalogue, count_rows):
# Return totals and unknown SKUs without mutating catalogue.
pass
# Read the two sections, reconcile them, then render a sorted report.
Expected result
For catalogue A,3 / B,0 and counts A,1 / A,2 / X,4, print A 3 3 OK and B 0 0 OK in SKU order, followed by unknown SKU X. Reject a duplicate A catalogue row rather than overwriting its threshold.
Progressive hints
Hint 1
Use totals = {sku: 0 for sku in catalogue} so missing counts remain visible.
Hint 2
Use a set for unknown SKUs and sort it only when printing.
Hint 3
Compare quantity < minimum; equality is not low stock.
Solution guidance
Show the approach after you attempt the project
Separate parsing, reconciliation and display. The parser checks that each row has exactly two non-empty fields and an integer amount of at least zero. Build the catalogue only after rejecting a repeated SKU. Initialise totals for every catalogue SKU at zero; each count either increments its known SKU or adds its unknown SKU to a set. Rendering sorted dictionary keys makes the report reproducible. Raise a clear ValueError for malformed input rather than returning a plausible but wrong inventory report.