BFH Quote

Download

bfhquote.tgz

BFH Quote Template

A LaTeX template for quotations in the BFH corporate design. It is based on the bfhletter package of bfh-ci and KOMA-Script.

The quote positions are kept in a separate Lua data file. The package quotetable.sty reads that file, typesets the position table and calculates all line amounts, the subtotal, VAT and the total. You never edit the table itself, only the list of positions.

Requirements

  • LuaLaTeX (the table code is written in Lua; pdfLaTeX/XeLaTeX won’t work)

  • TeX Live or MiKTeX with: bfh-ci, koma-script, tabularray, siunitx, luacode, xcolor, babel, microtype

  • Optional: latexmk for one-command builds

Files

File

Purpose

bfhquote.tex

The quotation letter. Edit quote details, customer and texts here.

BFH_upn.lco

Sender data (name, function, phone, e-mail, address).

positions-quote_01.lua

Example data file: flat list of positions.

positions-quote_02.lua

Example data file: positions grouped by categories.

quotetable.sty

Package that builds the position table from the data file.

.latexmkrc

Build settings for latexmk (LuaLaTeX, output in _build/).

Quick start

  1. Enter your sender data in BFH_upn.lco. You can rename the file, e.g. to your BFH short name (BFH_abc1.lco); then change \LoadLetterOption{BFH_upn} in bfhquote.tex accordingly.

  2. In bfhquote.tex, fill in the blocks Quote configuration and Customer.

  3. Create a data file for the positions (copy one of the examples) and select it:

    \QuoteLoadItems{positions-quote_02.lua}
    
  4. Build:

    latexmk            # uses .latexmkrc, PDF ends up in _build/
    # or
    lualatex bfhquote
    

Quote positions (data file)

The data file is a plain Lua file that returns a list. Each position has these fields:

Field

Type

Meaning

Description

text

Position text; long texts wrap within the column.

Quantity

number

Quantity, e.g. 4 or 2.5.

Unit

text

Unit, e.g. "pcs.", "h", "lot".

UnitPrice

number

Price per unit, e.g. 95.00.

Category

text, optional

Key of a category (see below).

The line amount is Quantity × UnitPrice, rounded to 2 decimals.

Flat list

return {
  { Description = "Some text",  Quantity = 4,  Unit = "pcs.", UnitPrice = 95.00 },
  { Description = "Work to do", Quantity = 10, Unit = "h",    UnitPrice = 86.00 },
}

Positions are numbered 1, 2, 3, …

Grouped by categories

Define each category once with a short key and its heading (Title), then assign positions to it by key:

return {
  { Category = "M", Title = "Material & Parts" },
  { Category = "L", Title = "Labour" },

  { Category = "M", Description = "Board",    Quantity = 4,  Unit = "pcs.", UnitPrice = 95.00 },
  { Category = "L", Description = "Assembly", Quantity = 10, Unit = "h",    UnitPrice = 86.00 },
  { Category = "M", Description = "Case",     Quantity = 4,  Unit = "pcs.", UnitPrice = 354.00 },
  { Description = "Small Parts and Consumables", Quantity = 1, Unit = "lot", UnitPrice = 50.00 },
}

Result:

1    Material & Parts
1.1  Board
1.2  Case
2    Labour
2.1  Assembly
3    Small Parts and Consumables

Rules:

  • Categories are numbered in the order of their definitions. Positions are numbered in file order within their category, wherever they stand in the file.

  • Positions without Category are top-level positions at their place in the file.

  • Category heading rows are tinted and bold.

  • Typo protection: a position with an undefined key (e.g. Category = "N") stops the build with quotetable: unknown category 'N'. The position is still printed, ungrouped. A key defined twice is also an error.

  • A category without positions is left out; a warning appears in the log.

Text and numbers

  • Special characters in texts (& % $ # _ { } ~ ^ \) are escaped automatically. Write "R&D", not "R\\&D".

  • Write Quantity and UnitPrice as numbers (95.00). A value that isn’t a number (e.g. "95.-") counts as 0.

  • Lua comments start with --. Every entry ends with a comma.

Customising the table

All settings go into the preamble of bfhquote.tex, after \usepackage{quotetable}.

Currency and VAT are set in the Quote configuration block (\QuoteCurrency, \QuoteVatRate in percent).

Colours. The defaults follow the BFH table colours; override any of them:

\colorlet{QuoteTableHead}{BFH-MediumBlue!35}  % header row
\colorlet{QuoteTableFill}{BFH-MediumBlue!7}   % position rows
\colorlet{QuoteGroupFill}{BFH-MediumBlue!20}  % category heading rows
\colorlet{QuoteTotalFill}{BFH-MediumBlue!15}  % total row

Column widths. The description column takes the remaining width:

\renewcommand\QuoteColPos{0.7cm}         % position, flat list
\renewcommand\QuoteColPosGrouped{1.0cm}  % position, grouped (1.10)
\renewcommand\QuoteColQty{1.0cm}
\renewcommand\QuoteColUnit{1.25cm}
\renewcommand\QuoteColPrice{1.9cm}
\renewcommand\QuoteColAmount{2.1cm}
\renewcommand\QuoteColSep{4pt}           % space between columns

Font of category headings: \renewcommand\QuoteGroupFont{\bfseries}

Additional tabularray options for one table go into the optional argument:

\QuoteTable[row{even} = {bg=white}]

Language of the table texts

The column headings, Subtotal, VAT, Total and the page-break texts follow the babel language of the document, just like \contentsname or \tablename. Set the language in the class options of bfhquote.tex:

\documentclass[ngerman]{scrartcl}        % or nswissgerman, french, italian, ...

Included translations:

Macro

English

German

Swiss German

French

Italian

\QuotePosName

Pos.

Pos.

Pos.

Pos.

Pos.

\QuoteDescriptionName

Description

Beschreibung

Beschreibung

Désignation

Descrizione

\QuoteQuantityName

Qty.

Menge

Menge

Qté

Qtà

\QuoteUnitName

Unit

Einheit

Einheit

Unité

Unità

\QuoteUnitPriceName

Unit price

Einzelpreis

Einzelpreis

Prix unitaire

Prezzo unitario

\QuoteAmountName

Amount

Betrag

Betrag

Montant

Importo

\QuoteSubtotalName

Subtotal

Zwischensumme

Zwischensumme

Sous-total

Subtotale

\QuoteVatName

VAT

MwSt.

MWST

TVA

IVA

\QuoteTotalName

Total

Gesamtbetrag

Total

Total

Totale

\QuoteContinuedName

(Continued)

(Fortsetzung)

(Fortsetzung)

(suite)

(continua)

\QuoteContinuedNextName

Continued on next page

Fortsetzung auf der nächsten Seite

…

Suite à la page suivante

Continua alla pagina successiva

Language names covered: english, british, UKenglish, american, USenglish, canadian, australian, newzealand; german, ngerman; austrian, naustrian (VAT: USt.); swissgerman, nswissgerman; french, francais, acadian, canadien; italian. Without babel, or for any other language, the English texts are used.

Change a text for one language the babel way, in the preamble:

\addto\captionsngerman{\renewcommand\QuoteDescriptionName{Leistung}}
\addto\captionsenglish{\renewcommand\QuoteQuantityName{Quantity}}

Without babel, use \renewcommand directly.

Add a language with \QuoteTableTranslation (after \usepackage{quotetable}):

\QuoteTableTranslation{spanish}{%
  \def\QuotePosName{Pos.}%
  \def\QuoteDescriptionName{Descripción}%
  \def\QuoteQuantityName{Cant.}%
  \def\QuoteUnitName{Unidad}%
  \def\QuoteUnitPriceName{Precio unitario}%
  \def\QuoteAmountName{Importe}%
  \def\QuoteSubtotalName{Subtotal}%
  \def\QuoteVatName{IVA}%
  \def\QuoteTotalName{Total}%
  \def\QuoteContinuedName{(continuación)}%
  \def\QuoteContinuedNextName{Continúa en la página siguiente}%
}

The other texts of the letter (Quotation details, Payment terms, …) are written directly in bfhquote.tex; translate them there.

Page breaks

The table may break across pages; the header row is repeated and the continuation is marked. Two places never break:

  • between a category heading and its first position

  • between the last position and the subtotal/VAT/total block

Build notes

  • .latexmkrc builds with LuaLaTeX into _build/. To get a copy of the PDF in _output/, enable one of the $success_cmd lines.

  • .latexmkrc also enables --shell-escape. The template itself doesn’t need it; remove the set_tex_cmds line if you don’t use packages like svg.

  • The data file is recorded as a dependency, so latexmk rebuilds the PDF when only the positions change.

Troubleshooting

Message

Cause / fix

This package requires LuaLaTeX

Compile with lualatex (or latexmk, which uses .latexmkrc).

quotetable: could not load quote items from …

File name in \QuoteLoadItems is wrong, or the Lua file has a syntax error (missing comma, unclosed quote, brace). The help text shows the Lua error with line number.

quotetable: unknown category 'X'

A position uses a key that has no { Category = "X", Title = "…" } definition.

quotetable: category 'X' is defined twice

Remove the duplicate definition.

Amount shows 0.00

Quantity or UnitPrice is missing, misspelled (field names are case-sensitive) or not a number.

Preview