One page set a CPA can read: what was checked, through which day and state of the books, every finding with its code and severity. No clock and no random id, so the same findings give the same bytes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
78 lines
2.4 KiB
Typst
78 lines
2.4 KiB
Typst
// An audit workpaper: what was checked, through which date and which
|
|
// books' state, and every finding with its code and severity.
|
|
//
|
|
// Everything arrives as data in sys.inputs.data (JSON), built by
|
|
// ledger-import::workpaper. The template only typesets: no arithmetic, and
|
|
// no text is ever parsed as markup. It holds no clock: the same data gives
|
|
// the same bytes.
|
|
//
|
|
// Shape: { company, title, scope, through, through_seq, program_version,
|
|
// tb_hash, findings_sha256, summary: str,
|
|
// findings: [{ severity, code, subject, message }],
|
|
// checks: [{ code, severity, predicate }] }
|
|
|
|
#let d = json(bytes(sys.inputs.data))
|
|
#let ink = luma(25)
|
|
#let quiet = luma(110)
|
|
#let hair = 0.5pt + luma(160)
|
|
|
|
#set document(title: d.company + " — " + d.title, author: d.company)
|
|
#set text(font: ("Inter", "Noto Sans CJK SC", "Noto Sans Arabic UI", "Noto Sans Hebrew", "Noto Sans Thai", "Noto Sans Devanagari"), size: 9pt, fill: ink, number-width: "tabular", hyphenate: false)
|
|
#set page(
|
|
paper: "us-letter",
|
|
margin: (x: 0.8in, top: 0.8in, bottom: 0.8in),
|
|
footer: context {
|
|
set text(7.5pt, fill: quiet)
|
|
grid(
|
|
columns: (1fr, auto),
|
|
[#d.program_version · head #d.through_seq],
|
|
align(right)[Page #counter(page).display() of #counter(page).final().first()],
|
|
)
|
|
},
|
|
)
|
|
|
|
#align(center)[
|
|
#text(15pt, fill: luma(45), d.company) \
|
|
#v(4pt)
|
|
#text(10.5pt, weight: "bold", d.title) \
|
|
#v(2pt)
|
|
Through #d.through · scope #d.scope
|
|
]
|
|
#v(12pt)
|
|
|
|
#grid(
|
|
columns: (auto, 1fr),
|
|
row-gutter: 5pt,
|
|
column-gutter: 12pt,
|
|
text(fill: quiet)[Books' figure head], [#d.through_seq],
|
|
text(fill: quiet)[Trial balance hash], text(size: 7.5pt)[#d.tb_hash],
|
|
text(fill: quiet)[Findings hash], text(size: 7.5pt)[#d.findings_sha256],
|
|
text(fill: quiet)[Result], [#d.summary],
|
|
)
|
|
#v(12pt)
|
|
|
|
#text(10pt, weight: "bold")[Findings]
|
|
#v(4pt)
|
|
#if d.findings.len() == 0 [
|
|
No findings.
|
|
] else [
|
|
#table(
|
|
columns: (auto, auto, auto, 1fr),
|
|
stroke: (x: none, y: hair),
|
|
inset: (x: 4pt, y: 4pt),
|
|
table.header([*Severity*], [*Code*], [*About*], [*Finding*]),
|
|
..d.findings.map(f => (f.severity, f.code, f.subject, f.message)).flatten(),
|
|
)
|
|
]
|
|
#v(14pt)
|
|
|
|
#text(10pt, weight: "bold")[What was checked]
|
|
#v(4pt)
|
|
#table(
|
|
columns: (auto, auto, 1fr),
|
|
stroke: (x: none, y: hair),
|
|
inset: (x: 4pt, y: 4pt),
|
|
table.header([*Code*], [*Severity*], [*True when it is reported*]),
|
|
..d.checks.map(c => (c.code, c.severity, c.predicate)).flatten(),
|
|
)
|