Print Documents
Every GarmentFlow document can be printed, and every printed layout is a Print Format record you can copy, edit or replace. Cutting sheets for the table, packing lists for the box, a tech pack for a customer — all the same mechanism.
GarmentFlow ships standard formats for Tech Pack, Production Order, Production Batch, Cutting Order, Marker Order, Sample, Pattern, QC Inspection and Operation Ledger Entry. Duplicating one of those is usually faster than starting from scratch.
Three ways to build one
| Way | Effort | Use when |
|---|---|---|
| Print Format Builder | Drag and drop, no code | Most documents |
| Custom HTML (Jinja) | HTML + a template language | Precise layouts, labels, anything the builder can't express |
| Print Designer | Visual, pixel-positioned | Available if the Print Designer app is installed on your site |
Start with the builder. Move to HTML when it stops being enough.
Print Format Builder
Creating a format
- Open any record of the DocType — say a Production Order.
- Press Ctrl/Cmd + P, or Menu → Print.
- In the print preview, open the format selector and choose + New Format (or Edit Format to duplicate the current one).
- Name it —
Production Order — Floor Copy— and it opens in the builder.
Using the builder
The builder shows your document's fields on the left and the page on the right.
- Drag a field onto the page to add it.
- Drag a section to group fields into a row of columns.
- Remove a field with the × on it.
- Child tables drop in as tables; click one to pick which columns show and in what order.
- Custom HTML blocks can be dropped in for anything not covered by a field.
Save, then print again and pick your format.
Making it the default
So users don't have to choose every time:
- Awesome Bar →
print format→ open yours. - Tick Default.
Or set it per DocType: Customize Form → Default Print Format.
Custom HTML with Jinja
For a cutting sheet or a box label, the builder's row-and-column model gets in the way. Untick Standard on the Print Format and write the HTML yourself.
Frappe renders it with Jinja, a template language: your HTML, with {{ }} for values and {% %} for logic.
The basics
<h2>{{ doc.name }}</h2>
<p>
<b>Style:</b> {{ doc.model_name }}<br>
<b>Quantity:</b> {{ doc.total_planned_qty }}<br>
<b>Due:</b> {{ frappe.format(doc.end_date, {"fieldtype": "Date"}) }}
</p>
docis the document being printed.doc.<fieldname>is any field — use the fieldname, not the label.frappe.format(value, {"fieldtype": "Date"})renders in the user's date format. Do this for dates, currency and floats rather than printing raw values.
Looping over child tables
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>Operation</th>
<th>Unit</th>
<th class="text-right">Qty</th>
</tr>
</thead>
<tbody>
{% for row in doc.operation_plan %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ row.operation }}</td>
<td>{{ row.production_unit or "" }}</td>
<td class="text-right">{{ row.qty or 0 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% for row in doc.<table_fieldname> %}…{% endfor %}loops the rows.loop.indexis the 1-based row number.or ""guards an empty value — Jinja printsNoneotherwise.
Conditions
{% if doc.status == "On Hold" %}
<div style="border: 2px solid #b00; padding: 8px; color: #b00;">
ON HOLD — {{ doc.custom_hold_reason or "no reason given" }}
</div>
{% endif %}
Pulling in other records
{% set tp = frappe.get_doc("Tech Pack", doc.tech_pack) %}
<p><b>Fabric:</b> {{ tp.fabric }} — {{ tp.width }} cm</p>
frappe.get_doc fetches a full document. For a single value, frappe.db.get_value("Tech Pack", doc.tech_pack, "fabric") is lighter.
Images and barcodes
{% if doc.image %}
<img src="{{ doc.image }}" style="max-height: 120px;">
{% endif %}
Attach-Image fields hold a URL, so they print directly. For barcodes and QR codes, generate the image and store it on the document — Jinja is not the place to compute one.
Page control
<div style="page-break-after: always;"></div>
And in the Print Format's own fields: Page Number, Margin Top/Bottom/Left/Right, and orientation via the print dialog.
For a repeating header on every page, use a Letter Head rather than putting it in your HTML.
Styling
The CSS field on the Print Format holds styles for that format only:
.print-format { font-family: "Helvetica Neue", Arial, sans-serif; font-size: 10pt; }
table { width: 100%; border-collapse: collapse; }
th, td { border: 1px solid #999; padding: 4px 6px; }
th { background: #f2f2f2; }
.text-right { text-align: right; }
@media print {
.no-print { display: none; }
}
Bootstrap's grid and table classes are available, which is why class="table table-bordered" works above.
Letter heads
A Letter Head is your header and footer — logo, address, registration numbers — applied to any print format.
- Awesome Bar →
letter head→ + Add Letter Head. - Name it, tick Default if it should apply everywhere.
- Paste HTML into the header and footer, or tick Image and upload one.
Keeping it separate means changing your address once updates every document.
Labels and unusual page sizes
For a box or asset label, set the page size in your CSS:
@page { size: 100mm 75mm; margin: 4mm; }
Then keep the content inside a fixed-size wrapper. This is exactly how GarmentFlow's own packing label works, and it prints through the browser's normal dialog with an ordinary thermal-printer driver — no print server needed.
Multiple languages
Print formats respect the Print Language chosen in the print dialog. To translate your own wording, wrap it:
<b>{{ _("Delivery Date") }}</b>
_() looks the string up in the site's translations. Field labels translate automatically; your literal text does not, unless you wrap it.
Printing from a script
To add a print button that opens a specific format, in a client script:
frappe.ui.form.on("Production Order", {
refresh(frm) {
frm.add_custom_button(__("Floor Copy"), () => {
const params = new URLSearchParams({
doctype: frm.doc.doctype,
name: frm.doc.name,
format: "Production Order — Floor Copy",
trigger_print: "1",
});
window.open(`/printview?${params.toString()}`, "_blank");
}, __("Print"));
},
});
Testing
- Preview against real documents, including the awkward ones: forty child rows, an empty table, a very long style name.
- Print to PDF first. The browser's PDF output is what the server generates; if it looks right there it will print right.
- Check page breaks on a long document — a table splitting across a page is the most common complaint.
Troubleshooting
| Symptom | Cause |
|---|---|
| A field prints empty | Wrong fieldname — you used the label. Check in Customize Form |
None appears |
Missing or "" on an empty value |
| Format not in the dropdown | Its DocType is wrong, or Disabled is ticked |
| Edits don't show | It is a Standard format — duplicate it and edit the copy |
| Layout right on screen, wrong on paper | Styles outside a @media print block, or a fixed pixel width |
What to do next
Continue to Creating reports.