Payment receipt and tabular report recipe using the Tiered Composition pattern.
A single-page receipt and a multi-page tabular "report" are the same recipe —
multi-page is just a receipt whose line items overflow one page. Column headers
repeat on every page via per-page table blocks; "Page X of Y" appears in the
footer via Rendro.page_number/1.
Exposes three levels of composability:
document/2— Batteries-included; accepts a receipt data map andreturns a fully assembled `%Rendro.Document{}` ready for `Rendro.render/1`. No template authoring required.page_template/1— Layout only; returns the%Rendro.PageTemplate{}.sections/2— Content only; returns a list of%Rendro.Section{}structs mapped to named regions.
Data contract
Required keys in data:
:title—String.t()(e.g. "Payment Receipt").:date—Date.t()(issue date).:customer—%{name: String.t()}(customer information).:lines—[%{description: String.t(), amount: Decimal.t()}](line items; amounts must be Decimal, not Float).
Optional keys:
:totals—%{subtotal: Decimal.t(), total: Decimal.t()}(caller assertions;subtotalis validated against the sum of line amounts viaDecimal.equal?/2when present).
Usage
Zero-to-one (just works)
data = %{
title: "Payment Receipt",
date: ~D[2026-05-29],
customer: %{name: "Acme Corp"},
lines: [
%{description: "Widget A", amount: Decimal.new("29.99")},
%{description: "Widget B", amount: Decimal.new("49.99")}
],
totals: %{subtotal: Decimal.new("79.98"), total: Decimal.new("79.98")}
}
doc = Rendro.Recipes.Receipt.document(data)
{:ok, pdf} = Rendro.render(doc)Escape hatch — inject a custom template
template = Rendro.Recipes.Receipt.page_template(name: :my_receipt)
sections = Rendro.Recipes.Receipt.sections(data)
doc =
Rendro.Document.new()
|> Rendro.Document.add_template(template)
|> Rendro.Document.set_template(:my_receipt)
|> then(fn d -> Enum.reduce(sections, d, &Rendro.Document.add_section(&2, &1)) end)Formatting
Default formatting is provided by Rendro.Format (pure, locale-free, deterministic):
money as $1,234.50 (parentheses for negatives) and dates as YYYY-MM-DD.
Override defaults via opts:
Rendro.Recipes.Receipt.document(data,
formatters: [
amount: fn %Decimal{} = d -> MyApp.Money.format(d) end,
date: fn %Date{} = d -> MyApp.Locale.format_date(d) end
]
)
Summary
Functions
Assembles and returns a fully composed %Rendro.Document{} from a receipt
data map.
Returns a %Rendro.PageTemplate{} with three named regions: :header,
:body, and :footer.
Returns a list of %Rendro.Section{} structs mapping receipt content to
the :header, :body, and :footer regions.
Functions
@spec document( map(), keyword() ) :: Rendro.Document.t()
Assembles and returns a fully composed %Rendro.Document{} from a receipt
data map.
Validates data via validate_data!/1, then builds the page template and
sections, reducing them through the Document builder API.
Examples
iex> data = %{
...> title: "Payment Receipt",
...> date: ~D[2026-05-29],
...> customer: %{name: "Acme Corp"},
...> lines: []
...> }
iex> doc = Rendro.Recipes.Receipt.document(data)
iex> doc.page_template
:receipt
@spec page_template(keyword()) :: Rendro.PageTemplate.t()
Returns a %Rendro.PageTemplate{} with three named regions: :header,
:body, and :footer.
The footer region has a non-zero height so body_capacity reserves space for
the "Page X of Y" page-number text (PAGE-03).
Options
All options are forwarded to %Rendro.PageTemplate{} as keyword overrides.
The name defaults to :receipt.
Examples
iex> t = Rendro.Recipes.Receipt.page_template()
iex> t.name
:receipt
iex> footer = Enum.find(t.regions, & &1.role == :footer)
iex> footer.height > 0
true
@spec sections( map(), keyword() ) :: [Rendro.Section.t()]
Returns a list of %Rendro.Section{} structs mapping receipt content to
the :header, :body, and :footer regions.
Validates data via validate_data!/1 before building sections.
Examples
iex> data = %{
...> title: "Payment Receipt",
...> date: ~D[2026-05-29],
...> customer: %{name: "Acme Corp"},
...> lines: []
...> }
iex> [header, body, footer] = Rendro.Recipes.Receipt.sections(data)
iex> header.region
:header
iex> footer.region
:footer