feat(templates): add the Payments paginating invoice preset - #638
Merged
DemchaAV merged 2 commits intoSep 1, 2026
Merged
Conversation
A lavender-and-navy invoice: a diagonal band crossing the masthead, a half-split issuer and metadata header, two addressed parties on discs, a marked service-line table, a settlement row pairing bank details against the totals, a note block and a two-cell document footer. Ships as invoice.presets.PaymentsInvoice on the existing StructuredInvoiceData model. It is the first preset in the family built to flow: the table's header repeats on every page it reaches, a continuation page reserves a deeper bottom margin than page one, and every page carries its number. The table is one column, not five. The design shows an outer box and a rule between rows with no interior verticals, which is exactly what a single-column table draws; the five columns are a row inside each cell. The other construction would leave every continuation page ending in an empty bordered strip, because a section's box fills its page fragment rather than hugging its rows. The lockup beside the title is the caller's — a logo drawn to the design's measured height, or the brand's name as a wordmark. Figures are written with the locale stated rather than inherited, because both the grouping of a number and the symbol for a currency code change with it. Guarded by a 15-case smoke test, an exact layout snapshot and a pixel-parity gate.
…build The committed preview was rendered against jars in the local repository that did not match this branch, so the catalogue's drift test failed on CI while passing locally — and the eleven files that appeared to drift locally were the same staleness seen from the other side. Built from source, the local drift list narrows to exactly the file CI named. Re-rendered, both lists are empty.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
stripe-invoiceis the richest bundle in the promotion queue and the first thatpaginates: the design shows six service lines, a real billing month brings dozens,
and no built-in invoice preset flows today.
It is also the first bundle whose source carries a real company's identity, so this PR
is the pattern for the thirteen like it: the layout is ported in full, the identity
is not.
What
invoice.presets.PaymentsInvoiceon the existingStructuredInvoiceDatamodel.Split as the family is:
PaymentsInvoiceroutes,PaymentsStylesholds the tokens,PaymentsTextthe figure formatting, andMasthead/Parties/Lines/Settlement/Closing/Widgets/Iconsdraw.De-branded, surgically
The bundle's branding turned out to sit in its data and in exactly one asset:
brand-lockup.svgwas the real Stripe wordmark (logos:stripe). Not ported. Thepreset reserves the design's measured 136 × 55.3 px lockup box and fills it from
InvoiceBrand— a logo drawn to that height, or the brand's name as a wordmark. Thetemplates artifact carries no mark of its own.
were product-flavoured (
item-atlas,item-radar,item-terminal), so they arerenamed to what they draw:
globe,shield,mobile.sample is neutral.
It flows
The table's header repeats on every page it reaches, a continuation page reserves a
deeper bottom margin than page one, and every page carries its number — a financial
record that runs over has to make a missing page detectable.
One column, not five. The design shows an outer box and a rule between rows with no
interior verticals, which is exactly the topology a single-column table draws: a cell
strokes all four of its own edges and a one-column table has no interior vertical. The
five columns are a row inside each cell. Built the other way round — the box from a
stroked section wrapped round the table — every continuation page would end in an empty
bordered strip, because a section's box fills its page fragment rather than hugging its
rows.
The locale is stated, never inherited
Both the grouping of a number and the symbol for a currency code change with the locale
—
USDis$in English andUS$in the root locale — so a preset that let the JVMdecide would render a different sheet on a different machine and its baselines would
move with the machine rather than with the design.
PaymentsTextpinsLocale.ENGLISH.Tests
map has exactly one band —
x 63..198, y 46..102, which is the lockup box measuredoff the design (
63..198,46.8..101.2). The diagonal band, the title, the issuerblock, the metadata grid and its divider, both parties, all six marked table rows,
the payment card, the totals, the due panel, the notes, the footer rule and both
footer cells are pixel-identical; 177 layout nodes against the bundle's 177. The
only thing that differs is the mark deliberately not shipped, and it differs inside
its own box without moving anything around it.
engine (2.2.2) and
2.2.3-SNAPSHOT, so there is no engine drift to account for.PaymentsInvoiceSmokeTest— 15 cases: the packaged marks, the unknown-mark dataerror, a line with no mark, the wordmark fallback, the currency named once and
carried, the uppercased due line, a trunk prefix printed but not dialled, the support
contacts as annotations, a missing ship-to, a missing note block, an empty document,
and a thirty-line invoice that runs on, repeats its column names on page two and
numbers its pages.
PaymentsInvoiceLayoutSnapshotTest— exact geometry, one page.PaymentsInvoiceVisualParityTest— pixel baseline; recorded without disturbing anyother baseline in the suite.
./mvnw -B -ntp clean verify -pl :graph-compose-core,:graph-compose-render-pdf,:graph-compose-render-docx,:graph-compose-render-pptx,:graph-compose-templates,:graph-compose-testing,:graph-compose-qa,:graph-compose-coverage -aminvoice-payments-v2;assets/readme/examples/invoice-payments-v2.pdfis regenerated from the committed code.