Designing a Centralised Inventory Transfer System
Replacing spreadsheet-based operations with a centralised, multi-team inventory platform
The system worked. Until it didn’t.
Here’s the story of a team that slowly slipped into inefficiency because their inventory process was giving them a hard time.
The team started with using Google Sheets and that enabled them to have shared access, real-time updates, and the ability to work from the same file. And for a while, that was genuinely enough.
It was simple, familiar, and easy to manage. Different teams could update what they needed, keep track of transfers, and move work along without needing a dedicated platform.
But as the business grew, the sheet started getting complicated. It became bulkier and that made auditing harder. What used to feel manageable started taking more time and more effort to maintain. And because different teams depended on inventory data in different ways, the same spreadsheet started meaning different things to different people.
Afterwards, they realised they needed more than a spreadsheet. They needed a system that could bring structure to the process, coordinate multiple teams properly, and serve as a source of truth as operations continued to grow.
And that was where I came in.

My role
I was the sole product designer on this. I worked directly with the operations and engineering teams from the early research conversations through to shipping. Everything from mapping the system architecture to designing the individual screens and the physical label system was my responsibility.
Understanding what I was actually building
I came in thinking this was a stock transfer feature. A few conversations later it was clear it was much bigger than that.
The system needed to handle stock requests, support procurement, manage pricing across locations, monitor inventory across multiple warehouses, and power fulfilment for both the USSD platform and the web app all at the same time, for Sales, Finance, Store Managers, Customer Support, and Management.
So before opening Figma I sat down with each team and asked them to walk me through how they actually worked. How they recorded stock coming in. How they tracked sales. How they physically moved inventory between branches. Those conversations shaped everything that came after including catching a mistake I’d already made.

The assumption I got wrong
Early on I assumed prices were consistent across all branches. That assumption made it into my initial designs, and I carried it further than I should have before catching it.
When I asked the teams to walk me through how stock actually moved between locations, I found out transfers weren’t free internal movements. The donor store sold the stock to the receiving branch at market price. By the time that stock arrived at its destination, it was carrying a different cost basis than it had at the source: same physical product, different financial reality.
My original design kept the same stock IDs across locations, which would have made that price change invisible. A single record for what was actually two separate financial events in two different stores.
That conversation changed the whole data model. And it’s the reason I now think talking to users before designing anything isn’t just good practice. It’s how you avoid building the wrong thing confidently.
Designing the data model
Two things needed to be resolved before any UI work made sense: how requests move through the system, and how stock changes identity when it moves.
On requests: a request being approved didn’t mean it had been fulfilled. But nothing in the existing process made that distinction, so different teams were treating them as the same thing. Finance assumed approved meant shipped. Store managers assumed dispatched meant received. That single blur was causing real errors across teams.
The fix was to separate it into two explicit layers:
Approval Status (the decision side): Pending Approval, Approved, Part Approved, Over Approved, Rejected, Not in Stock, Confirmed, Alternative
Fulfilment Status (the execution side): Processing, Dispatched, Delivered, Fulfilled, Part Fulfilled, Over Fulfilled, No Item, Issue Reported, Rejected
Once those were separate, each team could ask the right question at the right time. What was planned? What actually happened? Where did the two diverge?
When stock is dispatched for a transfer, the original stock IDs at the donor store are consumed and closed off. They’re done. The transfer request itself becomes the source of truth for what’s in transit. When the receiving store confirms the stock and sets the new price, new stock records are created with new IDs. The stock carries the right cost at the right location, and the full trail is captured cleanly.


Designing the allocation flow
In practice, a single donor store rarely had enough stock to fill a request on its own.
A request for 100 units might come back as 60 from Store A and 40 from Store B. The system needed to support that: track each store’s contribution separately, manage partial dispatches, and still give the requester one coherent view of where their order stood.
When a request comes in for approval, the manager sees all available stores and their stock side by side. Each store can be expanded to show individual stock IDs with quantities and expiry dates. The expiry dates are colour-coded (red for nearest, amber for approaching, green for comfortably far) and the system pre-selects the earliest-expiry stock automatically. FIFO by default, but overridable. There’s also a Nearest filter that narrows the list to stores closest to the requesting location, useful when you want to prioritise transport distance over raw stock volume.
The request became a coordination layer across multiple inventory sources, with expiry awareness built in so stock rotation happens naturally rather than as a separate task.

Designing the confirmation flow
The confirmation screen is where the new stock record actually gets created.
The receiving store manager goes through each incoming stock ID one by one, confirms the units received, and sets the new selling price for that batch. The modal shows the previous selling price as a reference so there’s a benchmark to work from, and flags in real time if the price entered is above market price. Profit and margin calculate live as you type. If all the incoming stock is being priced the same, one checkbox applies it across the board.
Before this, pricing decisions at the receiving end were made from memory or a quick WhatsApp message to someone more senior. Now the information is right there at the moment you need it.
The system also handles the messy reality of operations: partial approvals, partial dispatches, over-fulfilment, issue reporting. If the units received don’t match what was dispatched, the system flags it automatically and prompts the receiver to attach a note explaining the discrepancy. The donor store and lead sales manager get notified. The full timeline captures every action across every team so anyone can understand the history of a request without chasing anyone.


The part that lives outside the software
At some point I realised the system wasn’t going to break in the interface. It was going to break during transport.
Boxes from different requests getting mixed up in transit. Items losing their context the moment they left the warehouse. Labels becoming outdated before stock arrived. The software could be accurate while the physical reality was not, and that gap is where real operational errors happen.
So I designed a label system tied directly to the stock lifecycle. Three types, each active at a different stage:
Inbound: printed when stock arrives from a supplier. Shows the stock ID, product, quantity, source, expiry, and date received. Goes on the box as soon as it’s shelved.
Transfer: printed when stock is dispatched. Shows which stock IDs are being consumed, where the stock is going, and the transfer request reference. Replaces the inbound label during transit so anyone who picks up that box knows exactly what it is and where it’s headed.
Inventory: printed after the receiving manager confirms the stock and inputs the new price. New stock ID, confirmed location, confirmed cost. That’s the stock’s identity from here.
Only one label is active at any time. I added a print date to each so staff could identify the most recent valid label without opening the system. We also introduced branded packaging tape to group boxes visually and reduce mix-ups during transport.
The label system covers two formats: a larger label for bulk packaging and pallets, and a smaller one for individual units. Both carry the same information hierarchy so warehouse staff are reading the same layout regardless of what they’re looking at.


Outcome
The system replaced a spreadsheet-based, mostly ad-hoc process with something that held up under real conditions.
Stock movements are traceable end-to-end. Each team has visibility into the parts of the process that affect them without having to interpret data that wasn’t meant for them. Finance has a real audit trail. Management has approval controls. Warehouse staff have labels that mean something when they’re standing in front of a shelf.
It connected inventory to procurement, pricing, and fulfilment in a way the Google Sheets setup never could, and gave the business something it didn’t have before: a single version of the truth.
