// A builders' merchant's counter: invoices on pre-printed three-part forms (11-inch pin-fed
// paper) in an Epson LQ dot-matrix printer, and the day's dispatch list as a report.
//
//   quillo run escp.qwe      then open http://localhost:8080/invoice and http://localhost:8080/dispatch
//   PRINTER_HOST=192.168.1.69 quillo run escp.qwe      and http://localhost:8080/print

use "escp.qwer"

let INVOICE = { no: "INV-26-10417", date: "29/10/2026", customer: "Hollis & Sons Ltd", address: "Unit 4, Mill Lane, Bristol BS3 1QT",
    lines: [{ code: "CEM25", what: "Cement 25 kg", qty: 40, price: 6.35 }, { code: "SND850", what: "Sharp sand 850 kg bag", qty: 2, price: 54.0 }, { code: "TIE-3", what: "Wall ties (250) — stainless", qty: 1, price: 38.9 }] }

fn gbp(x) = format_number(x, "en-GB", 2)

// The form's boxes are printed on the paper: only the data goes where they are.
fn invoice_form(inv) {
    let head = [
        { line: 6, col: 58, text: inv.no, bold: true },
        { line: 7, col: 58, text: inv.date },
        { line: 10, col: 8, text: inv.customer, double_width: true },
        { line: 11, col: 8, text: inv.address },
    ]
    let rows = map(range(len(inv.lines)), (i) => [
        { line: 16 + i, col: 3, text: inv.lines[i].code },
        { line: 16 + i, col: 12, text: inv.lines[i].what, width: 36 },
        { line: 16 + i, col: 50, text: str(inv.lines[i].qty), width: 5, align: "right" },
        { line: 16 + i, col: 57, text: gbp(inv.lines[i].price), width: 9, align: "right" },
        { line: 16 + i, col: 68, text: gbp(inv.lines[i].qty * inv.lines[i].price), width: 10, align: "right" },
    ])
    let total = sum(map(inv.lines, (l) => l.qty * l.price))
    head + flatten(rows) + [{ line: 40, col: 68, text: gbp(total), width: 10, align: "right", bold: true, double_strike: true }]
}

let FORM = { cpi: 10, lpi: 6, page_inches: 11 }

route GET /invoice = respond(200, escp_form(invoice_form(INVOICE), FORM)?, { "content-type": "text/plain; charset=utf-8" })

route GET /dispatch = respond(200, escp_document([
    { text: "DISPATCH LIST  29/10/2026", align: "center", double_width: true, bold: true },
    { divider: "═" },
    { columns: ["INV-26-10417  Hollis & Sons", "Van 2  08:30"] },
    { columns: ["INV-26-10418  Avon Roofing", "Van 1  09:15"] },
    { divider: "─" },
    { text: "Drivers: sign every delivery note.", condensed: true },
], { cpi: 10, width: 80, page_lines: 66 })?, { "content-type": "text/plain; charset=utf-8" })

route GET /print {
    let host = env("PRINTER_HOST", null) ?? reply 503 "set PRINTER_HOST to the printer's address, or a print server's (host:9100)"
    { sent: escp_print("form", invoice_form(INVOICE), FORM, host, 5000)?, start: slice(escp_job("form", invoice_form(INVOICE), FORM)?, 0, 16) }
}
