Skip to main content
Alforse can print a physical label automatically when you post a receipt, split a batch, or complete a job’s first operation. The printing system consists of a print-job queue, printer routes that map location and context to a device, and renderers for thermal-label ZPL and document PDF. This system is separate from generated PDFs such as invoices, purchase orders, quotes, and job travelers. Those documents are delivered as files; printing sends output to a physical printer. Its default output is a thermal ZPL label.

Two renderers, one queue

A print job renders in one of two formats, chosen by the printer it’s routed to:
  • ZPL is the text command language thermal label printers speak. It’s the default for part and storage labels. A ZPL label needs a media size with ZPL dimensions configured, or it can’t render.
  • PDF is a real document, rendered by the same React-PDF engine that produces invoices and travelers. Kanban cards are PDF only, so a kanban card sent to a ZPL-only printer fails unless a template covers it.
Three document types exist (documentTypeRegistry in packages/web/printing/src/registry.ts): The source document is what maps to the doc types worth printing. Posting a shipment yields product labels; scanning a storage unit yields a storage label. getDocumentTypesForSource does that lookup.

Printer routes

A printer route is one physical printer, added on Settings → Printing → Printers with Add Printer. Each route carries: You manage routes under Settings → Printing. Each route has a Test action that sends a small ZPL test label straight to its printerUrl, so you can prove a printer is reachable before wiring it into a workflow. Test print only works for ZPL printers with a media size, and returns "Test label sent to printer" on success.

Assignments: which printer, in which context

A route is the printer; an assignment decides when it’s used. Assignments are set on Settings → Printing → Assignments, one block per location. Within a location you assign a printer to each context (printerContexts in packages/web/printing/src/assignments.ts): Each context row also carries an Auto-print switch. When it’s on, the matching business event prints without a click. getPrinterContextForSource maps the source document to its context, and resolveContextAssignment walks the fallback: an unassigned context uses the location’s default printer.

The print-job queue

Every print, manual or automatic, becomes a print job and moves through a fixed set of statuses:
Each job records its origin, one of auto (an automatic print behind a business event), manual (someone clicked print), or reprint (re-run from the jobs list). It also keeps the sourceDocument, sourceDocumentId, a readable id, the contentType, and the printerUrl it was sent to. You watch the queue under Settings → Printing → Print jobs. The table streams in real time and shows status, description, source, type, origin, and when. Expanding a row exposes the printer URL, attempts, timestamps, and any error. From there you can View the content (ZPL previews via Labelary, PDF via an inline frame), Reprint it (a fresh job with origin: "reprint"), or Delete it.

Auto-print behavior

After a supported business event, Alforse resolves the printer configuration for the location and context, checks autoPrint (defaults to on when unset), and enqueues a job. Printing failures do not block the receipt, shipment, or job that triggered them. The wired-in events: To stop a station auto-printing, turn off Auto-print on that location’s context row. To trigger a print by hand instead, use the Print button on the relevant screen, or send a source document to the manual print route (/x/print), which validates the request and enqueues the same kind of job. When a location has printer routes, Print opens a printer picker with the resolved default selected and enqueues a job after confirmation. With no routes, it opens a download modal for saving the label as ZPL or PDF.

Label sizes

Media sizes are a fixed catalog (packages/web/utils/src/labels.ts): label2x1, label4x2, metric label100x50mm and label50x25mm, and PDF-only avery5163. Only sizes with ZPL dimensions can print to a thermal printer; a PDF-only size like Avery can’t. Two places set a size. A printer route pins its own mediaSizeId (the size loaded in that physical printer). And the company has a default product-label size (companySettings.productLabelSize), set on the document-template screen, used by the interactive label-download routes when no route dictates one. See Company settings for where that default lives, and Documents for the customizer that styles the built-in label templates.