Data-driven payslip recipe. Net pay is the reader-first visual anchor (D-11): a tinted band directly under the identity header renders "NET PAY" at the largest text size on the page.
Uses the Tiered Composition pattern, mirroring Rendro.Recipes.Invoice:
document/2— Batteries-included; returns a fully assembled`%Rendro.Document{}` ready for `Rendro.render/2`.page_template/1— Layout only; returns the%Rendro.PageTemplate{}.Geometry is derived from `Rendro.PageSize.resolve/2` (A4 default, portrait) — zero hardcoded numerics, so both A4 and US Letter render correctly (D-14).sections/2— Content only; returns a list of%Rendro.Section{}structs mapped to named regions.
Required data keys
See validate_data!/1's contract (D-15):
:employer—%{name (required), address}:employee—%{name (required), id, tax_code}:period—%{from, to}(required,Date.t()):pay_date— required,Date.t():earnings— required, non-empty list of%{description, amount, ytd}:deductions— required key, list (may be empty) of the same line shape:net_pay— requiredDecimal.t(); must equal gross earnings minustotal deductions (D-13)
Optional data keys
:totals—%{gross, deductions, net, gross_ytd, deductions_ytd, net_ytd}— caller assertions checked against derived values viaDecimal.equal?/2:payment_method— masked identifier string (e.g."···· 4321")
Jurisdiction / label / formatting overrides (D-16)
:palette, :labels, and :formatters are three orthogonal override maps
merged over recipe-shipped defaults — the same convention as
Rendro.Recipes.Invoice's palette(opts) seam. Statutory line content
(e.g. "PAYE Income Tax" vs "Federal Income Tax") is caller :description
data, never a library-enumerated jurisdiction type (D-17).
Summary
Functions
Assembles and returns a fully composed %Rendro.Document{}. Validates
data (D-15/D-13 errors-as-product) before building the template.
Returns a %Rendro.PageTemplate{} with geometry derived from the page size
option. Default is A4 portrait. Four named regions: :header (employer/
employee identity), :summary (the D-11 net-pay anchor band), :body
(anchor: :flow — combined ledger + reconciliation), :footer
(anchor: :bottom — masked payment method + page number).
Returns a list of %Rendro.Section{} structs mapping payslip content to
the :header, :summary, :body, and :footer regions. Validates data
and the :labels/:formatters opts shape (D-19) before building any
section content.
Functions
@spec document( map(), keyword() ) :: Rendro.Document.t()
Assembles and returns a fully composed %Rendro.Document{}. Validates
data (D-15/D-13 errors-as-product) before building the template.
Examples
iex> data = %{
...> employer: %{name: "Aurora Textiles Co."},
...> employee: %{name: "Jordan Rivera"},
...> period: %{from: ~D[2026-06-01], to: ~D[2026-06-30]},
...> pay_date: ~D[2026-07-05],
...> earnings: [%{description: "Base Salary", amount: Decimal.new("1000.00")}],
...> deductions: [],
...> net_pay: Decimal.new("1000.00")
...> }
iex> doc = Rendro.Recipes.Payslip.document(data)
iex> doc.page_template
:payslip
@spec page_template(keyword()) :: Rendro.PageTemplate.t()
Returns a %Rendro.PageTemplate{} with geometry derived from the page size
option. Default is A4 portrait. Four named regions: :header (employer/
employee identity), :summary (the D-11 net-pay anchor band), :body
(anchor: :flow — combined ledger + reconciliation), :footer
(anchor: :bottom — masked payment method + page number).
Options
:page_size—:a4(default),:us_letter, or{width, height}tuple:margin_top/:margin_right/:margin_bottom/:margin_left— margin in pt (default 72):name— template name atom (default:payslip)
Examples
iex> template = Rendro.Recipes.Payslip.page_template()
iex> Enum.map(template.regions, & &1.name)
[:header, :summary, :body, :footer]
@spec sections( map(), keyword() ) :: [Rendro.Section.t()]
Returns a list of %Rendro.Section{} structs mapping payslip content to
the :header, :summary, :body, and :footer regions. Validates data
and the :labels/:formatters opts shape (D-19) before building any
section content.