Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 29 additions & 15 deletions docs/architecture/printing.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,12 @@ four whitespace-separated tokens read as a sentence.
| WebUSB | `frontend/src/lib/printer/PrinterService.ts` | Encoder output, sent over the browser's WebUSB API. |
| Delivery slip | `frontend/src/lib/printer/delivery-slip-encoder.ts` and `delivery-slip-web-print.ts` | A `DeliverySlipDocument`'s contact facts, rendered as bytes or HTML. |
| Tax bill | `frontend/src/lib/printer/tax-bill-encoder.ts` | A raw `Bill` and `Tenant`, not a document. |
| Payment ticket slip | `printPaymentTicket` in `main/printers/thermal.ts` | Order metadata, item lines, balance due, and ESC/POS QR code (`FLOCAFE-TICKET:<order_number>`) for multi-counter ordering. |
| Payment ticket slip | `printPaymentTicket` in `main/printers/thermal.ts` | Order metadata, item lines, balance due, centered `FLOCAFE-TICKET:<order_number>` text, and (when `raster.enabled` is true) an ESC/POS QR code for multi-counter ordering. |

The tax bill encoder and payment ticket slip generator are exceptions to "renderers consume
documents": the tax bill encoder reads `Bill` directly for per-component tax detail, while
`printPaymentTicket` formats a compact payment ticket slip and QR code from order items and totals.
`printPaymentTicket` formats a compact payment ticket slip and optional QR code from order items
and totals.

### Browser HTML printing

Expand All @@ -190,10 +191,12 @@ cropped content to at most 576x240 dots (384x240 for 58 mm), normalize grayscale
384- and 576-dot printers. `receipt_logo` stores an adaptively compressed data URL (`<= 200 KB`
target, `250 KB` cap) while `receipt_logo_raster` stores only the packed variants (`originalDataUrl`
is left empty in new payloads, with `parseReceiptLogoData()` accepting both empty and populated
values). Browser bills center the image above the business header. The classic and compact ESC/POS
renderers and frontend receipt encoders select a raster variant for the paper width and emit it with
`GS v 0` via `{RAW_BYTES:...}`, which the mixed-mode text rasterizer skips so non-Latin headers
never overwrite the logo bitmap. Kitchen tickets do not use the bill logo setting.
values). Browser bills center the image above the business header. When `rasterCapabilityEnabled()`
is true, the classic and compact ESC/POS renderers and frontend receipt encoders select a raster
variant for the paper width and emit it with `GS v 0` via `{RAW_BYTES:...}`, which the mixed-mode
text rasterizer skips so non-Latin headers never overwrite the logo bitmap. Profiles with
`raster.enabled: false` (such as `escpos-impact-76`) omit `{RAW_BYTES:...}` logo bitmaps. Kitchen
tickets do not use the bill logo setting.

## Transports

Expand All @@ -212,23 +215,34 @@ so it must not embed device names or user data.

## Printer profiles

`main/printers/profiles.ts` ships four profiles:
`main/printers/profiles.ts` ships five profiles:

| Id | Make and model | Paper | Font A columns |
| --- | --- | --- | --- |
| `xprinter-xp-v320m-v330m` | Xprinter XP-V320M / XP-V330M | 72 mm, `cols-48` | 48 |
| `escpos-impact-76` | Epson TM-U220 / 76mm Impact | 64 mm, `cols-32` | 32 |
| `epson-tm-series` | Epson TM Series ESC/POS | `cols-48` | 48 |
| `generic-escpos-80` | Generic ESC/POS 80 mm | `cols-42` | 42 |
| `generic-escpos-58` | Generic ESC/POS 58 mm | `cols-32` | 32 |

All four declare `raster.enabled: true` with modes `mixed` and `whole-receipt`, at 576 dots of
width except the 58 mm profile, which declares 384.

`resolvePrinterProfile()` resolves in three steps: an explicit `profile_id` if it names a known
profile, then a substring match against each profile's make, model, and aliases, then the paper
width, which selects `generic-escpos-58` for a width starting `58mm` and `generic-escpos-80`
otherwise. A name that matches nothing does not produce "generic for everything": it produces one
of the two generic profiles, chosen by paper width.
The four thermal profiles declare `raster.enabled: true` with modes `mixed` and `whole-receipt`, at
576 dots of width except the 58 mm profile, which declares 384. `escpos-impact-76` targets 76 mm
ribbon impact printers (`TM-U220`, `SRP-275`, `XP-76`) with `raster.enabled: false` (`widthDots: 0`,
`modes: []`), so bitmap logos (`GS v 0`), `GS ( k` QR codes, and text-to-bitmap raster bands are
never sent to an impact head.

`resolvePrinterProfile()` resolves in three steps: an explicit `profile_id` persisted on `printers`
(exposed as `configured_profile_id` alongside the resolved `profile_id` on `/api/printers`
responses) if it names a known profile, then a substring match against each profile's make, model,
and aliases, then the paper width, which selects `generic-escpos-58` for a width starting `58mm` and
`generic-escpos-80` otherwise. A name that matches nothing does not produce "generic for
everything": it produces one of the two generic profiles, chosen by paper width. OS printer
detection (`detectConnectedPrinters()`) also annotates each queue with
`compatibility: 'escpos_thermal' | 'escpos_impact' | 'driver_only'` via
`classifyDetectedPrinterCompatibility()`, keeping driver-only queues (such as Star `TSP100` /
`TSP143` / `SP700` / `mC-Print`, Epson `EcoTank` / `WorkForce` / `Stylus` inkjets, label printers,
and PDF queues) visible in Settings with a browser-print switch instead of misclassifying them as
raw ESC/POS thermal printers.

`capabilitiesForPrinter()` then caps the profile's raster width to the configured paper width when
that width is narrower than the profile's hardware, so a 42-column configuration on 80 mm hardware
Expand Down
20 changes: 9 additions & 11 deletions docs/guides/testing-printers.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,20 @@ npm run test:raster

## Which profile applies to a printer

`main/printers/profiles.ts` ships four profiles: `xprinter-xp-v320m-v330m`, `epson-tm-series`,
`generic-escpos-80`, and `generic-escpos-58`. A printer with no matching profile is not
unsupported; it runs on one of the two generic profiles, chosen by paper width.
See [printer profiles](../architecture/printing.md#printer-profiles) for the shipped profiles in
`main/printers/profiles.ts`, their raster capabilities, and the resolution order. A printer with no
matching name alias runs on one of the two generic profiles chosen by paper width, or on an explicit
`profile_id` selected in **Settings -> Printers**.

To determine which profile a printer actually resolves to:

1. In FloCafe, open **Settings -> Printers**, add the printer, and save it.
2. Read the resolved `profile_id` from the stored printer row, or call the profile listing endpoint
that the printer settings page uses.
2. Read the resolved `profile_id` (and optional `configured_profile_id`) from the stored printer
row, or call the profile listing endpoint that the printer settings page uses.
3. If it resolved to a generic profile but you expected a specific one, the name did not match any
alias. `matchSupportedPrinterProfile()` substring-matches the lower-cased make, model, and alias
list, so the stored name has to contain one of the profile's tokens. Recording the name string
you entered is part of the report.

Every profile declares raster capability. The 58 mm profile declares 384 dots of width; the other
three declare 576.
alias and no explicit profile was selected. `matchSupportedPrinterProfile()` substring-matches
the lower-cased make, model, and alias list, so an auto-detected name has to contain one of the
profile's tokens. Recording the name string you entered is part of the report.

## Test 1: chunked network printing

Expand Down
36 changes: 15 additions & 21 deletions docs/printers.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,27 +66,21 @@ rendered.

## Printer profiles and paper width

FloCafe resolves a printer to a capability profile in three steps, in order:

1. An explicitly selected profile id on the configured printer, if one is set.
2. A match against the printer's name, make, or model. Matching is a case-insensitive substring
test against each profile's make, model, and alias list, in profile order.
3. The paper width, which selects a generic profile: `58mm` selects the 58 mm generic, anything
else selects the 80 mm generic.

Four profiles ship. Detection does **not** return the generic profile for everything: a name
containing an Xprinter XP-V320M or XP-V330M, or a string containing `v320m` or `v330m`, resolves
to the Xprinter profile. A name containing `epson tm`, `tm-t88`, `tm-t82`, `tm-t20`, or `tm-m30`
resolves to the Epson TM series profile. Only a name that matches nothing falls through to the
generic profile chosen by paper width.

The generic profiles are the conservative ones for native text encoding (ASCII-only, with no text
shaping), while the Xprinter and Epson profiles add the Latin code pages and Latin script
representability. All four shipped profiles enable the capability-gated
[raster printing](architecture/printing.md#raster-printing) path, so lines containing characters
outside the printer's native code pages are rendered as raster bands. If raster rendering is
unavailable or fails on a financial row, FloCafe refuses the print rather than omitting an amount,
reporting `Receipt not printed: ...` with the affected row and next steps.
When adding or editing a printer in **Settings > Printers**, choose a **Printer Type / Profile** or
leave it on **Auto-detect from printer name**, and set the printable column width (`32`, `42`, or
`48` columns). Selecting a profile sets its default column width unless you override it manually.
The `76mm Impact / Dot-Matrix (Epson TM-U220, Bixolon SRP-275)` profile (`escpos-impact-76`) uses
32-column text mode and omits bitmap logos, QR graphics, and raster bands.

When **Settings > Printers** detects OS queues that do not accept raw ESC/POS commands (such as Star
`TSP100` / `TSP143` / `SP700` / `mC-Print`, Epson `EcoTank` / `WorkForce` / `Stylus` inkjets, label
printers, and PDF queues), it marks them **Driver / Browser print only** and offers a **Use Browser
Print** button instead of adding them as raw thermal printers.

For the shipped profile table, profile resolution order, native code-page vs.
[raster printing](architecture/printing.md#raster-printing) capabilities, and
[financial-row refusal](architecture/printing.md#capabilities-and-refusal), see
[printer profiles](architecture/printing.md#printer-profiles).

## Arabic-script text

Expand Down
Loading
Loading