Tim Silver logo
Menu
All case studies

Cutting dispatch time by 75% with a lightweight Python production system

A direct-to-garment manufacturing operation was losing hours every day to manual picking lists, bulk invoice matching, and shipping labels entered by hand into carrier websites. I architected and built a lightweight Python system that introduced scan-driven item identity, automated print file queuing, and dispatch pods that generated invoices and labels from a single scan. The result: production time halved and dispatch time reduced by 75%.

PythonPandasTKinterAeoonWindowsStorefeederZebraAPI's

How a simple system that took a month to build, saved a company 10's of thousands in cost for staff hours and production issues.

Snapshot

Client / company: Manufacturing business (direct-to-garment printing)
Role: Technical lead / architect & implementer
Scope: Production workflow automation (order ingestion → picking → print queue → collation → dispatch)
Stack: Python, pandas, filesystem-based orchestration, Tkinter UI
Outcome: Production times halved; dispatch time reduced by ~75%


The situation

This was a direct-to-garment printing operation - mostly clothing - where the actual printing wasn’t the bottleneck. The bottleneck was everything around it.

Before we built anything, the workflow looked roughly like this:

  • Daily orders would come in and get turned into print lists and picking lists by hand.
  • Those lists would get reconciled daily, manually.
  • Then came the part everyone dreaded: invoices were printed in bulk, and staff had to match them up with hundreds of items that had inevitably become mixed up in the flow of the day.
  • Shipping labels were even worse: staff spent hours every day entering shipment details into carrier websites, one parcel at a time, printing labels manually.

The business actually had a WMS in place, but in practice the operation still relied on manual work and human memory. It worked… until it didn’t. Volume increased, errors increased, and “end of day” became a recurring fire drill.

The goal wasn’t to build something pretty. It was to build something that could survive a busy factory floor.


The problem we were really solving

On paper, this sounds like “automate shipping labels”. But the deeper issue was traceability and flow.

In a manufacturing environment like this, if you can’t reliably answer these questions at speed, you’re in trouble:

  • What is this item?
  • Which order does it belong to?
  • Has it been printed?
  • Is it the right print file, and is it the latest version?
  • Is it ready to ship, and if so, what label should be on it?

When those answers live in spreadsheets and in people’s heads, the system doesn’t scale. You just add labour. And that’s expensive, slow, and error-prone.

So the real product requirement was: create a simple, scan-driven workflow that makes the state of each item obvious, and removes manual re-entry wherever possible.


Constraints and design principles

We had some very real constraints:

  • The “UI” would be used by production staff, in a noisy environment, often wearing gloves, under time pressure.
  • Hardware was a mix of practical things (label printers, barcode scanners, print servers, machines with file-drop queues).
  • The system needed to be fast, robust, and recoverable when something inevitably went sideways (printer jam, network blip, file missing, scanner misread).
  • It didn’t need to look fancy. In fact, “fancy” was a risk.

So the design principles were simple:

  1. Optimise for throughput and clarity, not aesthetics.
  2. Use barcodes as the truth on the factory floor.
  3. Make each step idempotent (rescanning shouldn’t create duplicates or corrupt state).
  4. Keep dependencies minimal and operationally understandable.
  5. Prefer filesystem and batch operations where they fit the environment (printing and production often already revolves around files).

The solution (high-level)

I architected and implemented a Python-based backend system that turned the production line into a scan-driven, stateful flow.

It had three big parts:

1) Order ingestion and heat-proof reel labels (the “identity layer”)

Each day, the system pulled the daily orders and produced individual heat-proof labels (on a reel) — one per item.

Each label acted as the item’s passport:

  • order reference
  • SKU / variant
  • barcode identifier
  • any production-relevant metadata (what needs printing, size/colour, etc.)

The operational flow became:

  • Staff picks a blank garment.
  • Scans it / attaches the label.
  • From that point on, the label ties the physical item to the digital job.

This alone removed a ton of ambiguity. It also killed the “mixed up pile of items” problem, because the item now carried its identity with it.

2) Print file staging and scan-to-queue (the “print automation”)

Alongside the label generation, we ran a daily job that placed the required print files onto a server attached to the print machines.

Print operators could:

  • scan the item label
  • the system would move the correct print file into the machine’s queue (file-drop model)

That meant:

  • fewer manual searches for files
  • less chance of printing the wrong version
  • less time wasted babysitting the queue

In practice, it made printing boring — and boring is good.

3) Dispatch pods: scan one item → print invoice + generate label (the “shipping automation”)

The dispatch stage was where the biggest pain lived, so we designed it to be brutally simple.

At the dispatch pods, a user would scan the item barcode and the system would:

  • determine if it was a single-item order (fast path)
  • print the invoice
  • generate the shipping label automatically
  • mark the shipment as processed so it couldn’t be duplicated accidentally

Then the packer could:

  • pack the item
  • attach the invoice and label
  • dispatch

The big win here was eliminating the hours of re-keying data into carrier websites. Shipping became a scan-and-go operation.


Tech approach (and why it worked)

The system itself was intentionally straightforward:

  • Python as the backbone
  • pandas for handling daily order data and reconciliation logic cleanly
  • filesystem orchestration (stable, debuggable, fits manufacturing realities)
  • Tkinter for the front-end UI, because:
    • it’s lightweight
    • it starts fast
    • it works on modest machines
    • it’s easy to make “big button, simple workflow” interfaces without overengineering

This wasn’t a “microservices and Kubernetes” problem. It was an “operations and flow” problem. The simplest workable architecture was the best architecture.


What changed operationally

Before:

  • bulk invoices, manually matched to items
  • manual shipping label entry
  • lots of end-of-day reconciliation
  • high cognitive load (“where is this item in the process?”)

After:

  • each item had a scannable identity from the start
  • print operators scanned to queue the correct file
  • dispatch scanned to generate invoice + shipping label
  • state was visible, repeatable, and much harder to mess up accidentally

Results

This is the part that still makes me proud, because it wasn’t a marginal improvement.

  • Production times were halved
  • Dispatch time reduced by ~75%

And beyond the headline numbers, the less measurable improvements mattered too:

  • fewer errors
  • less reliance on tribal knowledge
  • far less “we’ll stay late and fix it”
  • a calmer floor during peak volume

Lessons I’d carry into the next one

A few things this reinforced for me:

  1. Barcode-driven workflows are a superpower in physical operations.
    Once the physical item carries identity, everything downstream gets easier.

  2. Manufacturing systems don’t need polish - they need resilience.
    Fast start-up, obvious states, recoverable steps, minimal fuss.

  3. The best automation removes re-entry, not just clicks.
    If people still have to type addresses into carrier sites, you haven’t solved the real problem.

  4. File-based integration is not “hacky” when it matches the environment.
    A print server with a watched folder is effectively an API in a factory context.