Print Prima — Print Shop Management SaaS
Quote-to-Cash, Production Queues & Printer Audit for Large-Format Print Shops
Print Prima is a cloud SaaS that runs an entire large-format print business from one dashboard: quotes and invoices, order and job flow, inventory and stores, fixed assets, payroll, expenses, staff permissions, and a print audit that reads job data straight from the printers. It is built for shops ranging from a few machines to multi-branch operations, with Nigeria-ready taxes and NGN pricing alongside USD, and is sold on tiered plans gated by the number of printers monitored.
Architecture & System Design
Built on Laravel with Livewire-driven dashboards. Every shop is an isolated account with its own branches, staff roles, and plan limits. A quote becomes an invoice, then a production job that moves through a machine queue; material usage is deducted from inventory as the job runs, and what the printer actually reports is reconciled against what was invoiced to surface unbilled prints.
- Role-based views for Front Desk, Production, Finance, and Management over the same underlying job data
- Print audit capturing dimensions, bitmaps, status, and timings from each printer for every job
- Plan-level feature gating — printer monitoring limits of 3, 6, 10, or unlimited per subscription tier
- Multi-branch access with activity trails and KPI roll-ups across locations
Engineering Challenges
Catching Unbilled Prints (Theft Prevention)
In a print shop, staff can run jobs on a machine that never appear on an invoice. Owners had no way to compare what was printed with what was sold.
Built a print audit pipeline that records dimensions, preview bitmaps, status, and timings from each printer, then matches every captured print against an invoiced job. Prints with no matching job, or with a size that doesn't match the order, are flagged as anomalies for management.
Owners get a real-time view of every print per machine, with unmatched jobs surfaced instead of discovered at stock-take.
One Workflow from Quote to Cash
Quotes, production, stock, and payments typically live in separate spreadsheets and paper job tickets, so invoices get re-typed and jobs get lost between front desk and production.
Modelled the order as a single record that changes state — quote, invoice, proof approval, queued, printing, done, paid — so each team works on the same job from its own role-based view, with automated follow-ups on unpaid invoices.
Shops on the platform report 98% fewer invoice errors and 50%+ faster job turnaround.
Subscription Tiers with Hard Limits
Plans differ by printers monitored and feature set (Base Pack has no monitoring; Starter, Pro, and Pro Plus allow 3, 6, and 10 printers), billed monthly, quarterly, or yearly in USD or NGN.
Centralised plan entitlements in one service that every module checks before enabling a feature or registering a printer, so limits are enforced server-side rather than hidden in the UI.
Five tiers and three billing cycles run from a single entitlement layer, and upgrading a plan unlocks capacity immediately.
Core Features
Invoices & Quotes
Quote-to-invoice conversion with automated follow-ups, collections tracking, and Nigerian tax and NGN support.
Clean Code
1<?php23namespace App\Services;45use App\Events\PrintAnomalyDetected;6use App\Models\PrintJob;7use App\Models\PrintLog;89class PrintAuditService10{11 private const AREA_TOLERANCE = 0.05; // 5% over the invoiced size1213 public function reconcile(PrintLog $log): void14 {15 $job = PrintJob::where('printer_id', $log->printer_id)16 ->where('file_name', $log->file_name)17 ->whereIn('status', ['queued', 'printing'])18 ->first();1920 if (! $job) {21 $this->flag($log, 'unbilled_print');22 return;23 }2425 $allowedArea = $job->width * $job->height * (1 + self::AREA_TOLERANCE);2627 if ($log->width * $log->height > $allowedArea) {28 $this->flag($log, 'oversized_print', $job);29 }3031 $log->update(['print_job_id' => $job->id]);32 }3334 private function flag(PrintLog $log, string $reason, ?PrintJob $job = null): void35 {36 $log->update(['anomaly' => $reason]);3738 event(new PrintAnomalyDetected($log, $job));39 }40}