diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ef738a58..89c1ee8e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,6 +84,46 @@ follow semantic versioning; release dates are ISO 8601. ### Templates +- **The first invoice preset that paginates what it ports: `LumaStudioInvoice`.** A + studio invoice built around a cream sidebar — the two-line monogram and the wordmark + on a terracotta block at its head, a tinted quarter-disc, an arch and a sprig running + down the rest of it — beside a billing sheet that reads sender, title and metadata, + the billed-to and shipped-to pair across a rule, the priced service lines with a VAT + column, the totals stack closing on a filled total-due band, and the notes and bank + details above a dark sign-off band. Ships as `invoice.presets.LumaStudioInvoice` on + the structured invoice model, porting the rendered layout of the published standalone + `luma-co-studio-invoice` template. Unlike the CV presets promoted before it this one + flows: the line-items table repeats its dark header on the next page, the totals stack + and each closing block stay whole, and the paper tint, the sidebar column and the dark + foot band are page backgrounds, so every page carries the same frame and the folio + always has a dark ground. **The sign-off carries its own strip, which is where the + preset deliberately departs from the sheet it ports.** On the published template the + words rely on that background band, which is pinned to the paper's edge — right on a + one-page invoice, and white-on-cream in the middle of the last page of a longer one, + where the flow ends well above the paper's foot. Drawing the strip with the words + fixes it wherever they land; the cost is 7 440 of 2 173 720 pixels on the reference + sheet, where the strip starts three points above the background band it sits on, and + one extra layout node. It is flow content only because footer chrome carries text + today — one size, one colour, no glyph, where this band needs two faces and a disc — + so once a footer zone can hold a node the sign-off belongs in one and the strip goes + away. Its geometry is not a set of round numbers: the design was drawn + on a pixel grid, so the preset carries that grid as page ratios and states every + vertical gap as the white the drawing shows, subtracting the blank a line box already + carries — per family, because the three faces it sets fill different line boxes at the + same size. Letter-spaced runs are written letter by letter with an invisible inline + rectangle between the pairs, since a text style carries no tracking; the six spacings + are frozen constants rather than a measurement, because measuring at compose time + would tie the preset to the font artifact's resource layout. Amounts take their mark + from `StructuredInvoiceData.currencyCode()` — the code is the authority, so the sheet + cannot contradict itself — and the contact channels carry `tel:`, `mailto:` and + `https:` targets derived from their values, with a parenthesised trunk prefix dropped + from the dial target the way a caller dialling from abroad drops it. Guarded by a + smoke test (including the empty document, an unknown and a blank currency code, a + supplier with one registration and with none, the link targets, the repeated header + and folio on a continuation page, and the sign-off landing on its own ground), an + exact layout snapshot over both a one-page and a three-page invoice, and a + pixel-parity gate; the examples showcase gains `invoice-luma-studio-v2`. + - **`SerifHeadline` links its titles and lets its bands breathe.** Every title the preset draws — a role, a project, a degree, an achievement — is now a link when its entry carries one. And a band column keeps a gutter at its right edge, so its text diff --git a/assets/readme/examples/invoice-luma-studio-v2.pdf b/assets/readme/examples/invoice-luma-studio-v2.pdf new file mode 100644 index 000000000..35493c777 Binary files /dev/null and b/assets/readme/examples/invoice-luma-studio-v2.pdf differ diff --git a/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java b/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java index 6452c2d30..55bb1da8a 100644 --- a/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java +++ b/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java @@ -102,6 +102,7 @@ import com.demcha.examples.templates.cv.v2.SerifHeadlineExample; import com.demcha.examples.templates.invoice.ClassicInvoiceV2Example; import com.demcha.examples.templates.invoice.ConsultingInvoiceV2Example; +import com.demcha.examples.templates.invoice.LumaStudioInvoiceV2Example; import com.demcha.examples.templates.invoice.InvoiceCinematicFileExample; import com.demcha.examples.templates.invoice.ModernInvoiceV2Example; import com.demcha.examples.templates.proposal.CinematicProposalFileExample; @@ -176,6 +177,7 @@ public static void main(String[] args) throws Exception { System.out.println("Generated: " + ModernInvoiceV2Example.generate()); System.out.println("Generated: " + ClassicInvoiceV2Example.generate()); System.out.println("Generated: " + ConsultingInvoiceV2Example.generate()); + System.out.println("Generated: " + LumaStudioInvoiceV2Example.generate()); // Proposals System.out.println("Generated: " + ProposalCinematicFileExample.generate()); diff --git a/examples/src/main/java/com/demcha/examples/support/LumaStudioInvoiceSampleData.java b/examples/src/main/java/com/demcha/examples/support/LumaStudioInvoiceSampleData.java new file mode 100644 index 000000000..175b40c11 --- /dev/null +++ b/examples/src/main/java/com/demcha/examples/support/LumaStudioInvoiceSampleData.java @@ -0,0 +1,108 @@ +package com.demcha.examples.support; + +import com.demcha.compose.document.templates.data.invoice.InvoiceBrand; +import com.demcha.compose.document.templates.data.invoice.InvoiceContactBlock; +import com.demcha.compose.document.templates.data.invoice.InvoiceMasthead; +import com.demcha.compose.document.templates.data.invoice.InvoiceNotesBlock; +import com.demcha.compose.document.templates.data.invoice.InvoicePaymentBlock; +import com.demcha.compose.document.templates.data.invoice.InvoiceRecipient; +import com.demcha.compose.document.templates.data.invoice.InvoiceServiceLines; +import com.demcha.compose.document.templates.data.invoice.InvoiceTotalsBlock; +import com.demcha.compose.document.templates.data.invoice.StructuredInvoiceData; +import com.demcha.compose.document.templates.data.invoice.StructuredInvoiceDocumentSpec; + +import java.math.BigDecimal; +import java.util.List; + +/** + * Shared sample data for the Luma Studio Invoice example. + * + *

The sample is the preset's reference content: a design studio's + * invoice with a monogram lockup, five labelled masthead metadata rows, + * a billed-to and a shipped-to party, five priced service lines with a VAT + * column, a subtotal / VAT stack closing on the total-due band, five bank + * fields, two closing notes and the sign-off band.

+ * + *

Kept in lockstep with the qa module's + * {@code LumaStudioInvoiceFixtures} — the two modules cannot share a source + * file, so a content change here belongs there too.

+ */ +public final class LumaStudioInvoiceSampleData { + + /** The break the sheet stacks its multi-line notes on. */ + private static final String NEWLINE = String.valueOf((char) 10); + + private LumaStudioInvoiceSampleData() { + } + + /** The single-page reference invoice. */ + public static StructuredInvoiceDocumentSpec sample() { + return StructuredInvoiceDocumentSpec.from(StructuredInvoiceData.builder() + .brand(new InvoiceBrand(null, "LUMA & CO. STUDIO", null, + "Branding. Design. Digital.", "L", "&Co.")) + .supplier(new InvoiceContactBlock("LUMA & CO. STUDIO", + List.of("Studio 3.02, The Loom", "14 Gower Street", + "London WC1E 6BT", "United Kingdom"), + "+44 (0)20 7946 0832", "hello@lumaandco.studio", + "www.lumaandco.studio", + "Company No.", "12578934", "VAT No.", "369 4567 89")) + .masthead(new InvoiceMasthead("INVOICE", List.of( + new InvoiceMasthead.Entry("INVOICE NO.", "INV-2024-0587", false), + new InvoiceMasthead.Entry("ISSUE DATE", "20 May 2024", false), + new InvoiceMasthead.Entry("DUE DATE", "19 June 2024", false), + new InvoiceMasthead.Entry("PAYMENT TERMS", "30 Days", false), + new InvoiceMasthead.Entry("CURRENCY", "GBP", false)))) + .billTo(new InvoiceRecipient("BILL TO", "Northfield Consulting Ltd", + "Attn: Sarah Mitchell", + List.of("21 Jubilee Way", "London SE1 3SS", "United Kingdom"), "", "")) + .shipTo(new InvoiceRecipient("SHIP TO", "Northfield Consulting Ltd", "", + List.of("The Foundry, 2nd Floor", "17-19 Great Suffolk Street", + "London SE1 0NS", "United Kingdom"), "", "")) + .serviceLines(serviceLines()) + .totals(new InvoiceTotalsBlock(List.of( + new InvoiceTotalsBlock.Row("SUBTOTAL", new BigDecimal("8500.00")), + new InvoiceTotalsBlock.Row("VAT (20%)", new BigDecimal("1700.00"))), + "TOTAL DUE", new BigDecimal("10200.00"))) + .notes(new InvoiceNotesBlock("NOTES", List.of( + "Thank you for your business." + NEWLINE + + "If you have any questions regarding" + NEWLINE + + "this invoice, please get in touch.", + "All work remains the intellectual property" + NEWLINE + + "of LUMA & CO. STUDIO until payment" + NEWLINE + + "has been received in full."), "", "")) + .payment(new InvoicePaymentBlock("PAYMENT DETAILS", List.of( + new InvoicePaymentBlock.Field("BANK", "Starling Bank"), + new InvoicePaymentBlock.Field("SORT CODE", "60-83-71"), + new InvoicePaymentBlock.Field("ACCOUNT NO.", "98765432"), + new InvoicePaymentBlock.Field("IBAN", "GB36 SRLG 6083 7198 7654 32"), + new InvoicePaymentBlock.Field("BIC", "SRLGGB2L")), + "Please make payment by bank transfer to:", + "Payment is due by 19 June 2024.", "", + "LUMA & CO. STUDIO LTD", + "Thank you for choosing LUMA & CO. STUDIO.")) + .currencyCode("GBP") + .build()); + } + + private static InvoiceServiceLines serviceLines() { + return new InvoiceServiceLines( + new InvoiceServiceLines.Columns("", "DESCRIPTION", "", "QTY", "UNIT PRICE", + "AMOUNT", "VAT"), + List.of( + line(1, "Brand Strategy Workshop", + "Discovery session, research & brand positioning.", "1200.00"), + line(2, "Visual Identity Design", + "Logo suite, colour palette, typography & guidelines.", "2650.00"), + line(3, "Website Design (Up to 8 pages)", + "UX/UI design for desktop and mobile.", "3200.00"), + line(4, "Copywriting", "Website copy & key messaging.", "850.00"), + line(5, "Project Management", + "Planning, coordination & client liaison.", "600.00"))); + } + + private static InvoiceServiceLines.Line line(int number, String title, String description, + String price) { + return new InvoiceServiceLines.Line(number, title, description, "", BigDecimal.ONE, "", + new BigDecimal(price), new BigDecimal(price), "20%"); + } +} diff --git a/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java b/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java index f47ae6666..da69b14cf 100644 --- a/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java +++ b/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java @@ -92,6 +92,7 @@ record Entry(String title, String description, List tags, String codeUrl // ===== Templates / Invoice ===== invoice("invoice-cinematic", "InvoiceCinematicFileExample", "Cinematic Invoice", "Layered ModernInvoice preset with theme-driven layout, advanced tables, and totals.", "invoice", "cinematic"); invoice("invoice-consulting-v2", "v2/ConsultingInvoiceV2Example", "Consulting Invoice", "The ConsultingInvoice preset on the structured invoice model — brand lockup with the caller's logo, labelled masthead metadata, priced service lines with service periods, a totals stack and bank payment fields.", "invoice"); + invoice("invoice-luma-studio-v2", "v2/LumaStudioInvoiceV2Example", "Luma Studio Invoice", "The LumaStudioInvoice preset on the structured invoice model — a cream sidebar carrying the brand lockup and its ornament, a billed-to / shipped-to pair, priced service lines with a VAT column, and the notes and bank details above a sign-off band.", "invoice"); invoice("invoice-modern-v2", "v2/ModernInvoiceV2Example", "Modern Invoice", "The ModernInvoice preset composed straight from an InvoiceDocumentSpec — line items, totals and payment block driven by the BrandTheme rather than per-document styling.", "invoice"); invoice("invoice-classic-v2", "v2/ClassicInvoiceV2Example", "Classic Invoice", "The ClassicInvoice preset — letterhead header band, TOTAL DUE hero strip, BILL TO / FROM columns, and a dedicated Summary table after the line items.", "invoice"); diff --git a/examples/src/main/java/com/demcha/examples/templates/invoice/v2/LumaStudioInvoiceV2Example.java b/examples/src/main/java/com/demcha/examples/templates/invoice/v2/LumaStudioInvoiceV2Example.java new file mode 100644 index 000000000..1b8b84336 --- /dev/null +++ b/examples/src/main/java/com/demcha/examples/templates/invoice/v2/LumaStudioInvoiceV2Example.java @@ -0,0 +1,54 @@ +package com.demcha.examples.templates.invoice; + +import com.demcha.compose.GraphCompose; +import com.demcha.compose.document.api.DocumentSession; +import com.demcha.compose.document.templates.api.DocumentTemplate; +import com.demcha.compose.document.templates.data.invoice.StructuredInvoiceDocumentSpec; +import com.demcha.compose.document.templates.invoice.presets.LumaStudioInvoice; +import com.demcha.examples.support.ExampleOutputPaths; +import com.demcha.examples.support.LumaStudioInvoiceSampleData; + +import java.nio.file.Path; + +/** + * Renders the layered {@code invoice.v2} Luma Studio Invoice preset against + * the shared structured invoice sample data. + * + *

Output: + * {@code examples/target/generated-pdfs/templates/invoice/invoice-luma-studio-v2.pdf}.

+ * + *

The preset owns its page geometry — size, margins, the paper tint, the + * cream sidebar column and the sign-off band — so the session starts + * unconfigured. The lockup is drawn from the brand's monogram and wordmark, + * and the amounts take their mark from the data's currency code.

+ */ +public final class LumaStudioInvoiceV2Example { + + private LumaStudioInvoiceV2Example() { + } + + /** + * @return absolute path of the rendered PDF + * @throws Exception if rendering fails + */ + public static Path generate() throws Exception { + Path outputFile = ExampleOutputPaths.prepare( + "templates/invoice", "invoice-luma-studio-v2.pdf"); + StructuredInvoiceDocumentSpec spec = LumaStudioInvoiceSampleData.sample(); + DocumentTemplate template = LumaStudioInvoice.create(); + + try (DocumentSession document = GraphCompose.document(outputFile).create()) { + template.compose(document, spec); + document.buildPdf(); + } + return outputFile; + } + + /** + * @param args ignored + * @throws Exception if rendering fails + */ + public static void main(String[] args) throws Exception { + System.out.println("Generated: " + generate()); + } +} diff --git a/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceFixtures.java b/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceFixtures.java new file mode 100644 index 000000000..b0115f9bb --- /dev/null +++ b/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceFixtures.java @@ -0,0 +1,130 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.document.templates.data.invoice.InvoiceBrand; +import com.demcha.compose.document.templates.data.invoice.InvoiceContactBlock; +import com.demcha.compose.document.templates.data.invoice.InvoiceMasthead; +import com.demcha.compose.document.templates.data.invoice.InvoiceNotesBlock; +import com.demcha.compose.document.templates.data.invoice.InvoicePaymentBlock; +import com.demcha.compose.document.templates.data.invoice.InvoiceRecipient; +import com.demcha.compose.document.templates.data.invoice.InvoiceServiceLines; +import com.demcha.compose.document.templates.data.invoice.InvoiceTotalsBlock; +import com.demcha.compose.document.templates.data.invoice.StructuredInvoiceData; +import com.demcha.compose.document.templates.data.invoice.StructuredInvoiceDocumentSpec; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * Shared fixture data for the {@link LumaStudioInvoice} gates — the SAME + * specs feed the pixel parity test and the layout snapshot test, so a + * geometry shift the pixel budget absorbs still trips the exact snapshot, + * and vice versa. + */ +final class LumaStudioInvoiceFixtures { + + /** The break the sheet stacks its multi-line notes on. */ + private static final String NEWLINE = String.valueOf((char) 10); + + private LumaStudioInvoiceFixtures() { + } + + /** + * Canonical studio invoice — five priced service lines on one page, + * exercising the sidebar lockup, both party blocks, the VAT column, the + * total-due band, the notes and payment pair, and the sign-off band. + */ + static StructuredInvoiceDocumentSpec canonicalInvoice() { + return StructuredInvoiceDocumentSpec.from(base().build()); + } + + /** + * Overflow studio invoice — the same sheet billed phase by phase, so the + * table paginates over three pages and the repeated header, the per-page + * chrome, a middle page carrying nothing but table, and the whole-block + * closing all become part of the frozen contract. No manual page breaks. + */ + static StructuredInvoiceDocumentSpec overflowInvoice() { + List lines = new ArrayList<>(); + for (int phase = 1; phase <= 4; phase++) { + for (InvoiceServiceLines.Line line : serviceLines().lines()) { + lines.add(new InvoiceServiceLines.Line(lines.size() + 1, line.title(), + line.description() + " Phase " + phase + ".", line.servicePeriod(), + line.quantity(), line.unit(), line.unitPrice(), line.amount(), + line.vatRate())); + } + } + return StructuredInvoiceDocumentSpec.from(base() + .serviceLines(new InvoiceServiceLines(serviceLines().columns(), lines)) + .build()); + } + + private static StructuredInvoiceData.Builder base() { + return StructuredInvoiceData.builder() + .brand(new InvoiceBrand(null, "LUMA & CO. STUDIO", null, + "Branding. Design. Digital.", "L", "&Co.")) + .supplier(new InvoiceContactBlock("LUMA & CO. STUDIO", + List.of("Studio 3.02, The Loom", "14 Gower Street", + "London WC1E 6BT", "United Kingdom"), + "+44 (0)20 7946 0832", "hello@lumaandco.studio", + "www.lumaandco.studio", + "Company No.", "12578934", "VAT No.", "369 4567 89")) + .masthead(new InvoiceMasthead("INVOICE", List.of( + new InvoiceMasthead.Entry("INVOICE NO.", "INV-2024-0587", false), + new InvoiceMasthead.Entry("ISSUE DATE", "20 May 2024", false), + new InvoiceMasthead.Entry("DUE DATE", "19 June 2024", false), + new InvoiceMasthead.Entry("PAYMENT TERMS", "30 Days", false), + new InvoiceMasthead.Entry("CURRENCY", "GBP", false)))) + .billTo(new InvoiceRecipient("BILL TO", "Northfield Consulting Ltd", + "Attn: Sarah Mitchell", + List.of("21 Jubilee Way", "London SE1 3SS", "United Kingdom"), "", "")) + .shipTo(new InvoiceRecipient("SHIP TO", "Northfield Consulting Ltd", "", + List.of("The Foundry, 2nd Floor", "17-19 Great Suffolk Street", + "London SE1 0NS", "United Kingdom"), "", "")) + .serviceLines(serviceLines()) + .totals(new InvoiceTotalsBlock(List.of( + new InvoiceTotalsBlock.Row("SUBTOTAL", new BigDecimal("8500.00")), + new InvoiceTotalsBlock.Row("VAT (20%)", new BigDecimal("1700.00"))), + "TOTAL DUE", new BigDecimal("10200.00"))) + .notes(new InvoiceNotesBlock("NOTES", List.of( + "Thank you for your business." + NEWLINE + + "If you have any questions regarding" + NEWLINE + + "this invoice, please get in touch.", + "All work remains the intellectual property" + NEWLINE + + "of LUMA & CO. STUDIO until payment" + NEWLINE + + "has been received in full."), "", "")) + .payment(new InvoicePaymentBlock("PAYMENT DETAILS", List.of( + new InvoicePaymentBlock.Field("BANK", "Starling Bank"), + new InvoicePaymentBlock.Field("SORT CODE", "60-83-71"), + new InvoicePaymentBlock.Field("ACCOUNT NO.", "98765432"), + new InvoicePaymentBlock.Field("IBAN", "GB36 SRLG 6083 7198 7654 32"), + new InvoicePaymentBlock.Field("BIC", "SRLGGB2L")), + "Please make payment by bank transfer to:", + "Payment is due by 19 June 2024.", "", + "LUMA & CO. STUDIO LTD", + "Thank you for choosing LUMA & CO. STUDIO.")) + .currencyCode("GBP"); + } + + private static InvoiceServiceLines serviceLines() { + return new InvoiceServiceLines( + new InvoiceServiceLines.Columns("", "DESCRIPTION", "", "QTY", "UNIT PRICE", + "AMOUNT", "VAT"), + List.of( + line(1, "Brand Strategy Workshop", + "Discovery session, research & brand positioning.", "1200.00"), + line(2, "Visual Identity Design", + "Logo suite, colour palette, typography & guidelines.", "2650.00"), + line(3, "Website Design (Up to 8 pages)", + "UX/UI design for desktop and mobile.", "3200.00"), + line(4, "Copywriting", "Website copy & key messaging.", "850.00"), + line(5, "Project Management", + "Planning, coordination & client liaison.", "600.00"))); + } + + private static InvoiceServiceLines.Line line(int number, String title, String description, + String price) { + return new InvoiceServiceLines.Line(number, title, description, "", BigDecimal.ONE, "", + new BigDecimal(price), new BigDecimal(price), "20%"); + } +} diff --git a/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceLayoutSnapshotTest.java b/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceLayoutSnapshotTest.java new file mode 100644 index 000000000..73077112e --- /dev/null +++ b/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceLayoutSnapshotTest.java @@ -0,0 +1,46 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.GraphCompose; +import com.demcha.compose.document.api.DocumentSession; +import com.demcha.compose.document.templates.TemplateTestSupport; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Exact layout snapshot gate for {@link LumaStudioInvoice} — freezes the + * resolved geometry the pixel budget cannot see (a small column or spacing + * shift stays under the visual-diff budget but changes the snapshot), and + * the pagination contract of the overflow invoice: the service lines flow + * onto further pages while the totals stack and each closing block stay + * whole. + * + *

Refresh with {@code -Dgraphcompose.updateSnapshots=true} after a + * deliberate layout change, and commit the JSON with the change.

+ */ +class LumaStudioInvoiceLayoutSnapshotTest { + + @Test + void canonicalInvoiceMatchesLayoutSnapshot() throws Exception { + try (DocumentSession session = GraphCompose.document().create()) { + LumaStudioInvoice.create().compose( + session, LumaStudioInvoiceFixtures.canonicalInvoice()); + assertThat(session.layoutSnapshot().totalPages()).isEqualTo(1); + TemplateTestSupport.assertCanonicalSnapshot( + session, "luma_studio_invoice_layout", "invoice"); + } + } + + @Test + void overflowInvoicePaginatesOverThreePages() throws Exception { + try (DocumentSession session = GraphCompose.document().create()) { + LumaStudioInvoice.create().compose( + session, LumaStudioInvoiceFixtures.overflowInvoice()); + // Three pages exactly: the table spans the first two, and the + // closing blocks move whole onto the third rather than splitting. + assertThat(session.layoutSnapshot().totalPages()).isEqualTo(3); + TemplateTestSupport.assertCanonicalSnapshot( + session, "luma_studio_invoice_overflow_layout", "invoice"); + } + } +} diff --git a/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceSmokeTest.java b/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceSmokeTest.java new file mode 100644 index 000000000..3ca52c7d8 --- /dev/null +++ b/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceSmokeTest.java @@ -0,0 +1,251 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.GraphCompose; +import com.demcha.compose.document.api.DocumentSession; +import com.demcha.compose.document.snapshot.LayoutNodeSnapshot; +import com.demcha.compose.document.templates.api.DocumentTemplate; +import com.demcha.compose.document.templates.data.invoice.InvoiceContactBlock; +import com.demcha.compose.document.templates.data.invoice.StructuredInvoiceData; +import com.demcha.compose.document.templates.data.invoice.StructuredInvoiceDocumentSpec; +import org.apache.pdfbox.Loader; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink; +import org.apache.pdfbox.text.PDFTextStripper; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Smoke test for {@link LumaStudioInvoice} — proves the preset renders a + * {@link StructuredInvoiceDocumentSpec} end-to-end with its packaged icon + * set, renders an empty document through its guards, writes the currency + * mark its data's code names, puts the priced figures on the text layer + * where the layout snapshot cannot see inside the table, and carries the + * contact channels as link annotations — which move no pixel and no layout + * node, so neither gate would notice them going missing. + */ +class LumaStudioInvoiceSmokeTest { + + private static byte[] render(StructuredInvoiceDocumentSpec spec) throws Exception { + // The preset owns its page geometry, so the session starts unconfigured. + try (DocumentSession session = GraphCompose.document().create()) { + LumaStudioInvoice.create().compose(session, spec); + assertThat(session.roots()).isNotEmpty(); + byte[] pdfBytes = session.toPdfBytes(); + assertThat(pdfBytes).isNotEmpty(); + return pdfBytes; + } + } + + private static String textOf(byte[] pdfBytes) throws Exception { + try (PDDocument document = Loader.loadPDF(pdfBytes)) { + return new PDFTextStripper().getText(document); + } + } + + /** + * The text with its spaces removed. The sheet's headings and labels are + * letter-spaced runs, so the extractor can report a gap between each pair + * of letters; what is being asserted is the wording, not the tracking. + */ + private static String compact(String text) { + return text.replace(" ", ""); + } + + /** The text as one run, so an assertion need not know where a line broke. */ + private static String unwrapped(String text) { + return text.replace(String.valueOf((char) 13), "") + .replace(String.valueOf((char) 10), " "); + } + + private static List linkTargets(byte[] pdfBytes) throws Exception { + List targets = new ArrayList<>(); + try (PDDocument document = Loader.loadPDF(pdfBytes)) { + for (PDPage page : document.getPages()) { + for (PDAnnotation annotation : page.getAnnotations()) { + if (annotation instanceof PDAnnotationLink link + && link.getAction() instanceof PDActionURI uri) { + targets.add(uri.getURI()); + } + } + } + } + return targets; + } + + @Test + void exposesStableIdentity() { + DocumentTemplate template = LumaStudioInvoice.create(); + assertThat(template.id()).isEqualTo(LumaStudioInvoice.ID); + assertThat(template.displayName()).isEqualTo(LumaStudioInvoice.DISPLAY_NAME); + } + + @Test + void rendersCanonicalInvoiceWithPackagedIcons() throws Exception { + render(LumaStudioInvoiceFixtures.canonicalInvoice()); + } + + @Test + void rendersEmptyInvoice() throws Exception { + // Exercises the empty-collection paths through full layout and render: + // no metadata rows, no service lines, no totals rows, no bank fields, + // no notes, and a brand with neither monogram nor wordmark. + render(StructuredInvoiceDocumentSpec.from(StructuredInvoiceData.builder().build())); + } + + @Test + void canonicalRenderCarriesTheTableTotalsAndBankText() throws Exception { + // The line-items table, the totals bands and the bank rows are leaf + // nodes in the layout snapshot, so their content is asserted here. + String text = textOf(render(LumaStudioInvoiceFixtures.canonicalInvoice())); + assertThat(text) + .contains("Brand Strategy Workshop") + .contains("1,200.00") + .contains("10,200.00") + .contains("GB36 SRLG 6083 7198 7654 32") + .contains("Starling Bank"); + // The description wraps inside its cell, so it is asserted unwrapped. + assertThat(unwrapped(text)) + .contains("Discovery session, research & brand positioning."); + assertThat(compact(text)) + .contains("TOTALDUE") + .contains("INV-2024-0587") + .contains("PAYMENTDETAILS"); + } + + @Test + void amountsCarryTheMarkOfTheStatedCurrency() throws Exception { + String text = textOf(render(LumaStudioInvoiceFixtures.canonicalInvoice())); + assertThat(text).contains("£10,200.00"); + } + + @Test + void anUnknownCurrencyCodePrintsItselfRatherThanNothing() throws Exception { + StructuredInvoiceData data = rebuild( + LumaStudioInvoiceFixtures.canonicalInvoice().invoice()) + .currencyCode("ZZZ") + .build(); + + String text = textOf(render(StructuredInvoiceDocumentSpec.from(data))); + assertThat(text).contains("ZZZ10,200.00"); + } + + @Test + void aDocumentWithoutACurrencyLeavesTheFiguresBare() throws Exception { + StructuredInvoiceData data = rebuild( + LumaStudioInvoiceFixtures.canonicalInvoice().invoice()) + .currencyCode("") + .build(); + + String text = textOf(render(StructuredInvoiceDocumentSpec.from(data))); + assertThat(text).contains("10,200.00").doesNotContain("£10,200.00"); + } + + @Test + void contactChannelsAreClickable() throws Exception { + List targets = linkTargets(render(LumaStudioInvoiceFixtures.canonicalInvoice())); + assertThat(targets) + .contains("tel:+442079460832") + .contains("mailto:hello@lumaandco.studio") + .contains("https://www.lumaandco.studio"); + } + + @Test + void aSupplierWithoutRegistrationsPrintsNoDanglingSeparator() throws Exception { + StructuredInvoiceData canonical = + LumaStudioInvoiceFixtures.canonicalInvoice().invoice(); + InvoiceContactBlock supplier = canonical.supplier(); + StructuredInvoiceData data = rebuild(canonical) + .supplier(new InvoiceContactBlock(supplier.legalName(), supplier.addressLines(), + supplier.phone(), supplier.email(), supplier.website(), + "", "", "", "")) + .build(); + + String text = textOf(render(StructuredInvoiceDocumentSpec.from(data))); + assertThat(text).contains("Studio 3.02, The Loom").doesNotContain("|"); + } + + @Test + void aSupplierWithOneRegistrationPrintsNoSeparator() throws Exception { + StructuredInvoiceData canonical = + LumaStudioInvoiceFixtures.canonicalInvoice().invoice(); + InvoiceContactBlock supplier = canonical.supplier(); + StructuredInvoiceData data = rebuild(canonical) + .supplier(new InvoiceContactBlock(supplier.legalName(), supplier.addressLines(), + supplier.phone(), supplier.email(), supplier.website(), + supplier.registrationLabel(), supplier.registrationNumber(), "", "")) + .build(); + + String text = textOf(render(StructuredInvoiceDocumentSpec.from(data))); + assertThat(text).contains("Company No. 12578934").doesNotContain("|"); + } + + @Test + void overflowInvoiceRepeatsTheTableHeaderAndTheFolioOnTheSecondPage() throws Exception { + byte[] pdfBytes = render(LumaStudioInvoiceFixtures.overflowInvoice()); + try (PDDocument document = Loader.loadPDF(pdfBytes)) { + assertThat(document.getNumberOfPages()).isGreaterThan(1); + PDFTextStripper stripper = new PDFTextStripper(); + stripper.setStartPage(2); + stripper.setEndPage(2); + String secondPage = compact(stripper.getText(document)); + assertThat(secondPage).contains("DESCRIPTION").contains("UNITPRICE"); + assertThat(secondPage).contains("Page2of"); + } + } + + @Test + void overflowInvoicePricesEveryLine() throws Exception { + String text = textOf(render(LumaStudioInvoiceFixtures.overflowInvoice())); + int occurrences = text.split("Project Management", -1).length - 1; + assertThat(occurrences).isEqualTo(4); + } + + @Test + void theSignOffLandsOnItsOwnDarkGroundOnTheLastPage() throws Exception { + // The words are white. The dark foot band is a page background pinned + // to the paper's edge, and on a multi-page invoice the flow ends well + // above it — so the sign-off carries its own strip, and this is what + // says the strip is still under the words rather than the page's. + try (DocumentSession session = GraphCompose.document().create()) { + LumaStudioInvoice.create().compose( + session, LumaStudioInvoiceFixtures.overflowInvoice()); + LayoutNodeSnapshot band = node(session, "BannerBand"); + LayoutNodeSnapshot signOff = node(session, "SignOff"); + + assertThat(signOff.startPage()).isEqualTo(band.startPage()); + assertThat(signOff.placementY()).isGreaterThanOrEqualTo(band.placementY()); + assertThat(signOff.placementY() + signOff.placementHeight()) + .isLessThanOrEqualTo(band.placementY() + band.placementHeight()); + } + } + + private static LayoutNodeSnapshot node(DocumentSession session, String entityName) { + return session.layoutSnapshot().nodes().stream() + .filter(candidate -> entityName.equals(candidate.entityName())) + .findFirst() + .orElseThrow(() -> new AssertionError("No node named " + entityName)); + } + + /** Copies every component of a spec so one of them can be replaced. */ + private static StructuredInvoiceData.Builder rebuild(StructuredInvoiceData data) { + return StructuredInvoiceData.builder() + .brand(data.brand()) + .supplier(data.supplier()) + .masthead(data.masthead()) + .billTo(data.billTo()) + .shipTo(data.shipTo()) + .summary(data.summary()) + .serviceLines(data.serviceLines()) + .totals(data.totals()) + .payment(data.payment()) + .notes(data.notes()) + .currencyCode(data.currencyCode()); + } +} diff --git a/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceVisualParityTest.java b/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceVisualParityTest.java new file mode 100644 index 000000000..5f470eb41 --- /dev/null +++ b/qa/src/test/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoiceVisualParityTest.java @@ -0,0 +1,42 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.GraphCompose; +import com.demcha.compose.document.api.DocumentSession; +import com.demcha.compose.testing.visual.PdfVisualRegression; +import org.junit.jupiter.api.Test; + +import java.nio.file.Path; + +/** + * Pixel-diff visual parity gate for {@link LumaStudioInvoice}. Budget and + * tolerance mirror the other structured-invoice parity gates. + * + *

Re-blessing baselines — after a deliberate visual + * change, re-run with {@code -Dgraphcompose.visual.approve=true} and + * commit the updated PNGs with the change. Baselines live under + * {@code src/test/resources/visual-baselines/invoice-v2-layered/}.

+ */ +class LumaStudioInvoiceVisualParityTest { + + private static final Path BASELINE_ROOT = Path.of( + "src", "test", "resources", "visual-baselines", "invoice-v2-layered"); + + private static final long PIXEL_DIFF_BUDGET = 50_000L; + private static final int PER_PIXEL_TOLERANCE = 8; + + @Test + void rendersWithinPixelDiffBudget() throws Exception { + byte[] pdfBytes; + try (DocumentSession document = GraphCompose.document().create()) { + LumaStudioInvoice.create().compose( + document, LumaStudioInvoiceFixtures.canonicalInvoice()); + pdfBytes = document.toPdfBytes(); + } + + PdfVisualRegression.standard() + .baselineRoot(BASELINE_ROOT) + .perPixelTolerance(PER_PIXEL_TOLERANCE) + .mismatchedPixelBudget(PIXEL_DIFF_BUDGET) + .assertMatchesBaseline("luma_studio_invoice", pdfBytes); + } +} diff --git a/qa/src/test/resources/layout-snapshots/canonical-templates/invoice/luma_studio_invoice_layout.json b/qa/src/test/resources/layout-snapshots/canonical-templates/invoice/luma_studio_invoice_layout.json new file mode 100644 index 000000000..129d7aebb --- /dev/null +++ b/qa/src/test/resources/layout-snapshots/canonical-templates/invoice/luma_studio_invoice_layout.json @@ -0,0 +1,3677 @@ +{ + "formatVersion" : "2.0", + "canvas" : { + "pageWidth" : 595.276, + "pageHeight" : 841.89, + "innerWidth" : 402.871, + "innerHeight" : 732.911, + "margin" : { + "top" : 46.3, + "right" : 38.931, + "bottom" : 62.679, + "left" : 153.474 + } + }, + "totalPages" : 1, + "nodes" : [ { + "path" : "LumaStudioInvoice[0]", + "entityName" : "LumaStudioInvoice", + "entityKind" : "ContainerNode", + "parentPath" : null, + "childIndex" : 0, + "depth" : 1, + "layer" : 1, + "computedX" : 153.474, + "computedY" : 65.475, + "placementX" : 153.474, + "placementY" : 65.475, + "placementWidth" : 402.871, + "placementHeight" : 730.115, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 402.871, + "contentHeight" : 730.115, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]", + "entityName" : "Sidebar", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 0, + "depth" : 2, + "layer" : 2, + "computedX" : 0.0, + "computedY" : 841.49, + "placementX" : 0.0, + "placementY" : 841.49, + "placementWidth" : 132.032, + "placementHeight" : 0.4, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 132.032, + "contentHeight" : 0.4, + "margin" : { + "top" : -46.3, + "right" : 0.0, + "bottom" : 45.9, + "left" : -153.474 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]", + "entityName" : "SidebarOrnament", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 0.0, + "computedY" : 0.0, + "placementX" : 0.0, + "placementY" : 0.0, + "placementWidth" : 132.032, + "placementHeight" : 634.667, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 132.032, + "contentHeight" : 634.667, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]/OrnamentDisc[0]", + "entityName" : "OrnamentDisc", + "entityKind" : "EllipseNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 17.489, + "computedY" : 527.868, + "placementX" : 17.489, + "placementY" : 527.868, + "placementWidth" : 205.382, + "placementHeight" : 205.382, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 205.382, + "contentHeight" : 205.382, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]/OrnamentArch[1]", + "entityName" : "OrnamentArch", + "entityKind" : "ShapeNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 15.799, + "computedY" : 0.0, + "placementX" : 15.799, + "placementY" : 0.0, + "placementWidth" : 116.234, + "placementHeight" : 236.588, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 116.234, + "contentHeight" : 236.588, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]/SvgIcon[2]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 12.977, + "computedY" : 282.647, + "placementX" : 12.977, + "placementY" : 282.647, + "placementWidth" : 95.244, + "placementHeight" : 95.244, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 95.244, + "contentHeight" : 95.244, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]/SvgIcon[2]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]/SvgIcon[2]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 12.977, + "computedY" : 282.647, + "placementX" : 12.977, + "placementY" : 282.647, + "placementWidth" : 95.244, + "placementHeight" : 95.244, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 95.244, + "contentHeight" : 95.244, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandBlock[1]", + "entityName" : "BrandBlock", + "entityKind" : "ShapeNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 0.0, + "computedY" : 634.667, + "placementX" : 0.0, + "placementY" : 634.667, + "placementWidth" : 132.032, + "placementHeight" : 207.223, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 132.032, + "contentHeight" : 207.223, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "entityName" : "BrandLockup", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]", + "childIndex" : 2, + "depth" : 3, + "layer" : 3, + "computedX" : 0.0, + "computedY" : 634.667, + "placementX" : 0.0, + "placementY" : 634.667, + "placementWidth" : 132.032, + "placementHeight" : 207.223, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 132.032, + "contentHeight" : 207.223, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 33.288, + "computedY" : 715.218, + "placementX" : 33.288, + "placementY" : 715.218, + "placementWidth" : 36.655, + "placementHeight" : 88.273, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 36.655, + "contentHeight" : 88.273, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 33.288, + "computedY" : 705.462, + "placementX" : 33.288, + "placementY" : 705.462, + "placementWidth" : 68.585, + "placementHeight" : 47.212, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 68.585, + "contentHeight" : 47.212, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]/LockupRule[2]", + "entityName" : "LockupRule", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 33.288, + "computedY" : 704.671, + "placementX" : 33.288, + "placementY" : 704.671, + "placementWidth" : 20.311, + "placementHeight" : 1.7, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.311, + "contentHeight" : 1.7, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]/Wordmark[3]", + "entityName" : "Wordmark", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "childIndex" : 3, + "depth" : 4, + "layer" : 4, + "computedX" : 33.288, + "computedY" : 675.395, + "placementX" : 33.288, + "placementY" : 675.395, + "placementWidth" : 82.984, + "placementHeight" : 9.524, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 82.984, + "contentHeight" : 9.524, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]/ParagraphNode[4]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "childIndex" : 4, + "depth" : 4, + "layer" : 4, + "computedX" : 33.288, + "computedY" : 661.626, + "placementX" : 33.288, + "placementY" : 661.626, + "placementWidth" : 77.712, + "placementHeight" : 8.047, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 77.712, + "contentHeight" : 8.047, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]", + "entityName" : "Masthead", + "entityKind" : "RowNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 1, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 647.091, + "placementX" : 153.474, + "placementY" : 647.091, + "placementWidth" : 402.871, + "placementHeight" : 148.499, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 402.871, + "contentHeight" : 148.499, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]", + "entityName" : "SupplierHeader", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 153.474, + "computedY" : 655.01, + "placementX" : 153.474, + "placementY" : 655.01, + "placementWidth" : 236.404, + "placementHeight" : 140.58, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 236.404, + "contentHeight" : 140.58, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 7.334 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/SupplierName[0]", + "entityName" : "SupplierName", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 782.164, + "placementX" : 160.808, + "placementY" : 782.164, + "placementWidth" : 94.638, + "placementHeight" : 13.425, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 94.638, + "contentHeight" : 13.425, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/SupplierAddress[1]", + "entityName" : "SupplierAddress", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 727.228, + "placementX" : 160.808, + "placementY" : 727.228, + "placementWidth" : 85.39, + "placementHeight" : 48.726, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 85.39, + "contentHeight" : 48.726, + "margin" : { + "top" : 6.21, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]", + "entityName" : "ContactRows", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 674.232, + "placementX" : 160.808, + "placementY" : 674.232, + "placementWidth" : 229.071, + "placementHeight" : 43.184, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 229.071, + "contentHeight" : 43.184, + "margin" : { + "top" : 9.812, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]", + "entityName" : "ContactRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 160.808, + "computedY" : 703.022, + "placementX" : 160.808, + "placementY" : 703.022, + "placementWidth" : 229.071, + "placementHeight" : 14.395, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 229.071, + "contentHeight" : 14.395, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 160.808, + "computedY" : 705.919, + "placementX" : 160.808, + "placementY" : 705.919, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 160.808, + "computedY" : 705.919, + "placementX" : 160.808, + "placementY" : 705.919, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 181.808, + "computedY" : 704.482, + "placementX" : 181.808, + "placementY" : 704.482, + "placementWidth" : 78.706, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 78.706, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]", + "entityName" : "ContactRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 160.808, + "computedY" : 688.627, + "placementX" : 160.808, + "placementY" : 688.627, + "placementWidth" : 229.071, + "placementHeight" : 14.395, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 229.071, + "contentHeight" : 14.395, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 160.808, + "computedY" : 691.524, + "placementX" : 160.808, + "placementY" : 691.524, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 160.808, + "computedY" : 691.524, + "placementX" : 160.808, + "placementY" : 691.524, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 181.808, + "computedY" : 690.087, + "placementX" : 181.808, + "placementY" : 690.087, + "placementWidth" : 95.852, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 95.852, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]", + "entityName" : "ContactRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]", + "childIndex" : 2, + "depth" : 5, + "layer" : 5, + "computedX" : 160.808, + "computedY" : 674.232, + "placementX" : 160.808, + "placementY" : 674.232, + "placementWidth" : 229.071, + "placementHeight" : 14.395, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 229.071, + "contentHeight" : 14.395, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 160.808, + "computedY" : 677.129, + "placementX" : 160.808, + "placementY" : 677.129, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 160.808, + "computedY" : 677.129, + "placementX" : 160.808, + "placementY" : 677.129, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 181.808, + "computedY" : 675.692, + "placementX" : 181.808, + "placementY" : 675.692, + "placementWidth" : 91.105, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 91.105, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/Registration[3]", + "entityName" : "Registration", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]", + "childIndex" : 3, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 655.01, + "placementX" : 160.808, + "placementY" : 655.01, + "placementWidth" : 148.091, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 148.091, + "contentHeight" : 8.79, + "margin" : { + "top" : 10.433, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "entityName" : "InvoiceHeader", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 389.878, + "computedY" : 647.091, + "placementX" : 389.878, + "placementY" : 647.091, + "placementWidth" : 166.466, + "placementHeight" : 148.499, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 148.499, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/InvoiceTitleBlock[0]", + "entityName" : "InvoiceTitleBlock", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 749.89, + "placementX" : 389.878, + "placementY" : 749.89, + "placementWidth" : 166.466, + "placementHeight" : 45.7, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 45.7, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 15.3, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/InvoiceTitleBlock[0]/InvoiceTitle[0]", + "entityName" : "InvoiceTitle", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/InvoiceTitleBlock[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 736.636, + "placementX" : 389.878, + "placementY" : 736.636, + "placementWidth" : 164.751, + "placementHeight" : 55.553, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 164.751, + "contentHeight" : 55.553, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/InvoiceTitleBlock[0]/TitleRule[1]", + "entityName" : "TitleRule", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/InvoiceTitleBlock[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 749.89, + "placementX" : 389.878, + "placementY" : 749.89, + "placementWidth" : 58.7, + "placementHeight" : 1.7, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 58.7, + "contentHeight" : 1.7, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[1]", + "entityName" : "MetadataRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 717.09, + "placementX" : 389.878, + "placementY" : 717.09, + "placementWidth" : 166.466, + "placementHeight" : 17.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 17.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[1]/MetaLabel[0]", + "entityName" : "MetaLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 720.957, + "placementX" : 389.878, + "placementY" : 720.957, + "placementWidth" : 57.062, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 57.062, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 491.989, + "computedY" : 720.103, + "placementX" : 491.989, + "placementY" : 720.103, + "placementWidth" : 57.65, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 57.65, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[2]", + "entityName" : "MetadataRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 699.59, + "placementX" : 389.878, + "placementY" : 699.59, + "placementWidth" : 166.466, + "placementHeight" : 17.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 17.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[2]/MetaLabel[0]", + "entityName" : "MetaLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[2]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 703.458, + "placementX" : 389.878, + "placementY" : 703.458, + "placementWidth" : 51.552, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 51.552, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[2]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[2]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 491.989, + "computedY" : 702.603, + "placementX" : 491.989, + "placementY" : 702.603, + "placementWidth" : 49.641, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 49.641, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[3]", + "entityName" : "MetadataRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 3, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 682.09, + "placementX" : 389.878, + "placementY" : 682.09, + "placementWidth" : 166.466, + "placementHeight" : 17.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 17.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[3]/MetaLabel[0]", + "entityName" : "MetaLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[3]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 685.958, + "placementX" : 389.878, + "placementY" : 685.958, + "placementWidth" : 43.963, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 43.963, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[3]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[3]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 491.989, + "computedY" : 685.103, + "placementX" : 491.989, + "placementY" : 685.103, + "placementWidth" : 50.393, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 50.393, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[4]", + "entityName" : "MetadataRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 4, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 664.591, + "placementX" : 389.878, + "placementY" : 664.591, + "placementWidth" : 166.466, + "placementHeight" : 17.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 17.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[4]/MetaLabel[0]", + "entityName" : "MetaLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[4]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 668.458, + "placementX" : 389.878, + "placementY" : 668.458, + "placementWidth" : 75.89, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 75.89, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[4]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[4]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 491.989, + "computedY" : 667.603, + "placementX" : 491.989, + "placementY" : 667.603, + "placementWidth" : 29.873, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 29.873, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[5]", + "entityName" : "MetadataRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 5, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 647.091, + "placementX" : 389.878, + "placementY" : 647.091, + "placementWidth" : 166.466, + "placementHeight" : 17.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 17.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[5]/MetaLabel[0]", + "entityName" : "MetaLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[5]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 650.958, + "placementX" : 389.878, + "placementY" : 650.958, + "placementWidth" : 46.267, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 46.267, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[5]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[5]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 491.989, + "computedY" : 650.103, + "placementX" : 491.989, + "placementY" : 650.103, + "placementWidth" : 15.905, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 15.905, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/HeaderRule[2]", + "entityName" : "HeaderRule", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 2, + "depth" : 2, + "layer" : 2, + "computedX" : 160.808, + "computedY" : 633.091, + "placementX" : 160.808, + "placementY" : 633.091, + "placementWidth" : 395.537, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 395.537, + "contentHeight" : 1.0, + "margin" : { + "top" : 13.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 7.334 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]", + "entityName" : "Parties", + "entityKind" : "RowNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 3, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 532.149, + "placementX" : 153.474, + "placementY" : 532.149, + "placementWidth" : 402.871, + "placementHeight" : 88.942, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 402.871, + "contentHeight" : 88.942, + "margin" : { + "top" : 12.0, + "right" : 0.0, + "bottom" : 12.9, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/BILLTO[0]", + "entityName" : "BILLTO", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 153.474, + "computedY" : 532.149, + "placementX" : 153.474, + "placementY" : 532.149, + "placementWidth" : 103.12, + "placementHeight" : 88.942, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 103.12, + "contentHeight" : 88.942, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 7.334 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/BILLTO[0]/PartyHeading[0]", + "entityName" : "PartyHeading", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]/BILLTO[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 611.326, + "placementX" : 160.808, + "placementY" : 611.326, + "placementWidth" : 33.342, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 33.342, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/BILLTO[0]/PartyAddress[1]", + "entityName" : "PartyAddress", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]/BILLTO[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 532.149, + "placementX" : 160.808, + "placementY" : 532.149, + "placementWidth" : 95.786, + "placementHeight" : 70.235, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 95.786, + "contentHeight" : 70.235, + "margin" : { + "top" : 8.942, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/SHIPTO[1]", + "entityName" : "SHIPTO", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 344.757, + "computedY" : 532.149, + "placementX" : 344.757, + "placementY" : 532.149, + "placementWidth" : 133.88, + "placementHeight" : 88.942, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 133.88, + "contentHeight" : 88.942, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 34.4 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/SHIPTO[1]/PartyHeading[0]", + "entityName" : "PartyHeading", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]/SHIPTO[1]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 379.157, + "computedY" : 611.326, + "placementX" : 379.157, + "placementY" : 611.326, + "placementWidth" : 35.173, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 35.173, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/SHIPTO[1]/PartyAddress[1]", + "entityName" : "PartyAddress", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]/SHIPTO[1]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 379.157, + "computedY" : 532.149, + "placementX" : 379.157, + "placementY" : 532.149, + "placementWidth" : 99.48, + "placementHeight" : 70.235, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 99.48, + "contentHeight" : 70.235, + "margin" : { + "top" : 8.942, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/LineItems[4]", + "entityName" : "LineItems", + "entityKind" : "TableNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 4, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 268.127, + "placementX" : 153.474, + "placementY" : 268.127, + "placementWidth" : 402.871, + "placementHeight" : 251.122, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 402.871, + "contentHeight" : 251.122, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]", + "entityName" : "Totals", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 5, + "depth" : 2, + "layer" : 2, + "computedX" : 306.404, + "computedY" : 197.553, + "placementX" : 306.404, + "placementY" : 197.553, + "placementWidth" : 249.941, + "placementHeight" : 66.174, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 249.941, + "contentHeight" : 66.174, + "margin" : { + "top" : 4.4, + "right" : 0.0, + "bottom" : 0.0, + "left" : 152.93 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[0]", + "entityName" : "TotalsRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 306.404, + "computedY" : 245.619, + "placementX" : 306.404, + "placementY" : 245.619, + "placementWidth" : 249.941, + "placementHeight" : 18.108, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 249.941, + "contentHeight" : 18.108, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[0]/TotalsLabel[0]", + "entityName" : "TotalsLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 348.204, + "computedY" : 248.821, + "placementX" : 348.204, + "placementY" : 248.821, + "placementWidth" : 46.299, + "placementHeight" : 11.704, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 46.299, + "contentHeight" : 11.704, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[0]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 293.404, + "computedY" : 248.821, + "placementX" : 293.404, + "placementY" : 248.821, + "placementWidth" : 249.941, + "placementHeight" : 11.704, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 249.941, + "contentHeight" : 11.704, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[1]", + "entityName" : "TotalsRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 306.404, + "computedY" : 227.51, + "placementX" : 306.404, + "placementY" : 227.51, + "placementWidth" : 249.941, + "placementHeight" : 18.108, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 249.941, + "contentHeight" : 18.108, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[1]/TotalsLabel[0]", + "entityName" : "TotalsLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[1]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 348.204, + "computedY" : 230.712, + "placementX" : 348.204, + "placementY" : 230.712, + "placementWidth" : 45.982, + "placementHeight" : 11.704, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 45.982, + "contentHeight" : 11.704, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[1]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 293.404, + "computedY" : 230.712, + "placementX" : 293.404, + "placementY" : 230.712, + "placementWidth" : 249.941, + "placementHeight" : 11.704, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 249.941, + "contentHeight" : 11.704, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalDueBand[2]", + "entityName" : "TotalDueBand", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]", + "childIndex" : 2, + "depth" : 3, + "layer" : 3, + "computedX" : 306.404, + "computedY" : 197.553, + "placementX" : 306.404, + "placementY" : 197.553, + "placementWidth" : 249.941, + "placementHeight" : 27.1, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 249.941, + "contentHeight" : 27.1, + "margin" : { + "top" : 2.857, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalDueBand[2]/TotalsLabel[0]", + "entityName" : "TotalsLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalDueBand[2]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 348.204, + "computedY" : 204.85, + "placementX" : 348.204, + "placementY" : 204.85, + "placementWidth" : 52.971, + "placementHeight" : 12.507, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 52.971, + "contentHeight" : 12.507, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalDueBand[2]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalDueBand[2]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 293.404, + "computedY" : 199.812, + "placementX" : 293.404, + "placementY" : 199.812, + "placementWidth" : 249.941, + "placementHeight" : 22.582, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 249.941, + "contentHeight" : 22.582, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/FooterRule[6]", + "entityName" : "FooterRule", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 6, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 194.553, + "placementX" : 153.474, + "placementY" : 194.553, + "placementWidth" : 402.871, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 402.871, + "contentHeight" : 1.0, + "margin" : { + "top" : 2.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]", + "entityName" : "Closing", + "entityKind" : "RowNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 7, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 74.375, + "placementX" : 153.474, + "placementY" : 74.375, + "placementWidth" : 402.871, + "placementHeight" : 108.178, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 402.871, + "contentHeight" : 108.178, + "margin" : { + "top" : 12.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]", + "entityName" : "Notes", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 153.474, + "computedY" : 86.272, + "placementX" : 153.474, + "placementY" : 86.272, + "placementWidth" : 167.03, + "placementHeight" : 96.281, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 167.03, + "contentHeight" : 96.281, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]", + "entityName" : "SectionHead", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 153.474, + "computedY" : 157.753, + "placementX" : 153.474, + "placementY" : 157.753, + "placementWidth" : 167.03, + "placementHeight" : 24.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 167.03, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]", + "entityName" : "Disc-notes", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 153.474, + "computedY" : 157.753, + "placementX" : 153.474, + "placementY" : 157.753, + "placementWidth" : 24.8, + "placementHeight" : 24.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 24.8, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]/DiscFill[0]", + "entityName" : "DiscFill", + "entityKind" : "EllipseNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 153.474, + "computedY" : 157.753, + "placementX" : 153.474, + "placementY" : 157.753, + "placementWidth" : 24.8, + "placementHeight" : 24.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 24.8, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]/SvgIcon[1]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 159.874, + "computedY" : 164.153, + "placementX" : 159.874, + "placementY" : 164.153, + "placementWidth" : 12.0, + "placementHeight" : 12.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 12.0, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]/SvgIcon[1]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]/SvgIcon[1]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 159.874, + "computedY" : 164.153, + "placementX" : 159.874, + "placementY" : 164.153, + "placementWidth" : 12.0, + "placementHeight" : 12.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 12.0, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/SectionHeading[1]", + "entityName" : "SectionHeading", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 188.974, + "computedY" : 165.271, + "placementX" : 188.974, + "placementY" : 165.271, + "placementWidth" : 28.177, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 28.177, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/NotesBody[1]", + "entityName" : "NotesBody", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 153.474, + "computedY" : 86.272, + "placementX" : 153.474, + "placementY" : 86.272, + "placementWidth" : 156.503, + "placementHeight" : 69.245, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 156.503, + "contentHeight" : 69.245, + "margin" : { + "top" : 2.236, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 35.5 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/NotesBody[1]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/NotesBody[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 188.974, + "computedY" : 125.552, + "placementX" : 188.974, + "placementY" : 125.552, + "placementWidth" : 103.794, + "placementHeight" : 29.965, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 103.794, + "contentHeight" : 29.965, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/NotesBody[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/NotesBody[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 188.974, + "computedY" : 86.272, + "placementX" : 188.974, + "placementY" : 86.272, + "placementWidth" : 121.003, + "placementHeight" : 29.965, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 121.003, + "contentHeight" : 29.965, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]", + "entityName" : "PaymentDetails", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 320.504, + "computedY" : 74.375, + "placementX" : 320.504, + "placementY" : 74.375, + "placementWidth" : 235.84, + "placementHeight" : 108.178, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 235.84, + "contentHeight" : 108.178, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 24.3 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]", + "entityName" : "SectionHead", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 344.804, + "computedY" : 157.753, + "placementX" : 344.804, + "placementY" : 157.753, + "placementWidth" : 211.54, + "placementHeight" : 24.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 211.54, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]", + "entityName" : "Disc-bank", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 344.804, + "computedY" : 157.753, + "placementX" : 344.804, + "placementY" : 157.753, + "placementWidth" : 24.8, + "placementHeight" : 24.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 24.8, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]/DiscFill[0]", + "entityName" : "DiscFill", + "entityKind" : "EllipseNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 344.804, + "computedY" : 157.753, + "placementX" : 344.804, + "placementY" : 157.753, + "placementWidth" : 24.8, + "placementHeight" : 24.8, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 24.8, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]/SvgIcon[1]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 351.204, + "computedY" : 164.153, + "placementX" : 351.204, + "placementY" : 164.153, + "placementWidth" : 12.0, + "placementHeight" : 12.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 12.0, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]/SvgIcon[1]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]/SvgIcon[1]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 351.204, + "computedY" : 164.153, + "placementX" : 351.204, + "placementY" : 164.153, + "placementWidth" : 12.0, + "placementHeight" : 12.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 12.0, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/SectionHeading[1]", + "entityName" : "SectionHeading", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 165.271, + "placementX" : 380.304, + "placementY" : 165.271, + "placementWidth" : 82.727, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 82.727, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "entityName" : "PaymentBody", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 344.804, + "computedY" : 74.375, + "placementX" : 344.804, + "placementY" : 74.375, + "placementWidth" : 211.54, + "placementHeight" : 81.143, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 211.54, + "contentHeight" : 81.143, + "margin" : { + "top" : 2.236, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 35.5 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentInstruction[0]", + "entityName" : "PaymentInstruction", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 147.544, + "placementX" : 380.304, + "placementY" : 147.544, + "placementWidth" : 121.183, + "placementHeight" : 7.974, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 121.183, + "contentHeight" : 7.974, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/AccountHolder[1]", + "entityName" : "AccountHolder", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 132.19, + "placementX" : 380.304, + "placementY" : 132.19, + "placementWidth" : 83.026, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 83.026, + "contentHeight" : 9.765, + "margin" : { + "top" : 5.589, + "right" : 0.0, + "bottom" : 6.831, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]", + "entityName" : "PaymentField", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 2, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 115.162, + "placementX" : 380.304, + "placementY" : 115.162, + "placementWidth" : 176.04, + "placementHeight" : 10.197, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 176.04, + "contentHeight" : 10.197, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 380.304, + "computedY" : 115.866, + "placementX" : 380.304, + "placementY" : 115.866, + "placementWidth" : 17.087, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 17.087, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]/BankPipe[1]", + "entityName" : "BankPipe", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 433.904, + "computedY" : 116.895, + "placementX" : 433.904, + "placementY" : 116.895, + "placementWidth" : 1.0, + "placementHeight" : 6.73, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 1.0, + "contentHeight" : 6.73, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]", + "childIndex" : 2, + "depth" : 6, + "layer" : 6, + "computedX" : 444.104, + "computedY" : 115.866, + "placementX" : 444.104, + "placementY" : 115.866, + "placementWidth" : 38.198, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 38.198, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]", + "entityName" : "PaymentField", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 3, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 104.965, + "placementX" : 380.304, + "placementY" : 104.965, + "placementWidth" : 176.04, + "placementHeight" : 10.197, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 176.04, + "contentHeight" : 10.197, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 380.304, + "computedY" : 105.669, + "placementX" : 380.304, + "placementY" : 105.669, + "placementWidth" : 34.245, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 34.245, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]/BankPipe[1]", + "entityName" : "BankPipe", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 433.904, + "computedY" : 106.699, + "placementX" : 433.904, + "placementY" : 106.699, + "placementWidth" : 1.0, + "placementHeight" : 6.73, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 1.0, + "contentHeight" : 6.73, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]", + "childIndex" : 2, + "depth" : 6, + "layer" : 6, + "computedX" : 444.104, + "computedY" : 105.669, + "placementX" : 444.104, + "placementY" : 105.669, + "placementWidth" : 26.31, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 26.31, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]", + "entityName" : "PaymentField", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 4, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 94.768, + "placementX" : 380.304, + "placementY" : 94.768, + "placementWidth" : 176.04, + "placementHeight" : 10.197, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 176.04, + "contentHeight" : 10.197, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 380.304, + "computedY" : 95.472, + "placementX" : 380.304, + "placementY" : 95.472, + "placementWidth" : 43.022, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 43.022, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]/BankPipe[1]", + "entityName" : "BankPipe", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 433.904, + "computedY" : 96.502, + "placementX" : 433.904, + "placementY" : 96.502, + "placementWidth" : 1.0, + "placementHeight" : 6.73, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 1.0, + "contentHeight" : 6.73, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]", + "childIndex" : 2, + "depth" : 6, + "layer" : 6, + "computedX" : 444.104, + "computedY" : 95.472, + "placementX" : 444.104, + "placementY" : 95.472, + "placementWidth" : 29.205, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 29.205, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]", + "entityName" : "PaymentField", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 5, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 84.571, + "placementX" : 380.304, + "placementY" : 84.571, + "placementWidth" : 176.04, + "placementHeight" : 10.197, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 176.04, + "contentHeight" : 10.197, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 380.304, + "computedY" : 85.275, + "placementX" : 380.304, + "placementY" : 85.275, + "placementWidth" : 15.07, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 15.07, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]/BankPipe[1]", + "entityName" : "BankPipe", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 433.904, + "computedY" : 86.305, + "placementX" : 433.904, + "placementY" : 86.305, + "placementWidth" : 1.0, + "placementHeight" : 6.73, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 1.0, + "contentHeight" : 6.73, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]", + "childIndex" : 2, + "depth" : 6, + "layer" : 6, + "computedX" : 444.104, + "computedY" : 85.275, + "placementX" : 444.104, + "placementY" : 85.275, + "placementWidth" : 89.789, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 89.789, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]", + "entityName" : "PaymentField", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 6, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 74.375, + "placementX" : 380.304, + "placementY" : 74.375, + "placementWidth" : 176.04, + "placementHeight" : 10.197, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 176.04, + "contentHeight" : 10.197, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 380.304, + "computedY" : 75.078, + "placementX" : 380.304, + "placementY" : 75.078, + "placementWidth" : 9.771, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 9.771, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]/BankPipe[1]", + "entityName" : "BankPipe", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 433.904, + "computedY" : 76.108, + "placementX" : 433.904, + "placementY" : 76.108, + "placementWidth" : 1.0, + "placementHeight" : 6.73, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 1.0, + "contentHeight" : 6.73, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]", + "childIndex" : 2, + "depth" : 6, + "layer" : 6, + "computedX" : 444.104, + "computedY" : 75.078, + "placementX" : 444.104, + "placementY" : 75.078, + "placementWidth" : 29.918, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 29.918, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]", + "entityName" : "ClosingBanner", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 8, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 65.475, + "placementX" : 153.474, + "placementY" : 65.475, + "placementWidth" : 402.871, + "placementHeight" : 0.3, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 402.871, + "contentHeight" : 0.3, + "margin" : { + "top" : 8.6, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]", + "entityName" : "BannerContent", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 0.0, + "computedY" : 3.096, + "placementX" : 0.0, + "placementY" : 3.096, + "placementWidth" : 595.276, + "placementHeight" : 62.679, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 595.276, + "contentHeight" : 62.679, + "margin" : { + "top" : 0.0, + "right" : -38.931, + "bottom" : -62.379, + "left" : -153.474 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerBand[0]", + "entityName" : "BannerBand", + "entityKind" : "ShapeNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 0.0, + "computedY" : 3.096, + "placementX" : 0.0, + "placementY" : 3.096, + "placementWidth" : 595.276, + "placementHeight" : 62.679, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 595.276, + "contentHeight" : 62.679, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]", + "entityName" : "Disc-heart", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 32.728, + "computedY" : 17.485, + "placementX" : 32.728, + "placementY" : 17.485, + "placementWidth" : 33.9, + "placementHeight" : 33.9, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 33.9, + "contentHeight" : 33.9, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]/DiscFill[0]", + "entityName" : "DiscFill", + "entityKind" : "EllipseNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 32.728, + "computedY" : 17.485, + "placementX" : 32.728, + "placementY" : 17.485, + "placementWidth" : 33.9, + "placementHeight" : 33.9, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 33.9, + "contentHeight" : 33.9, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]/SvgIcon[1]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 41.678, + "computedY" : 26.435, + "placementX" : 41.678, + "placementY" : 26.435, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]/SvgIcon[1]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]/SvgIcon[1]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 41.678, + "computedY" : 26.435, + "placementX" : 41.678, + "placementY" : 26.435, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerLines[2]", + "entityName" : "BannerLines", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 80.628, + "computedY" : 21.357, + "placementX" : 80.628, + "placementY" : 21.357, + "placementWidth" : 179.909, + "placementHeight" : 26.156, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 179.909, + "contentHeight" : 26.156, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerLines[2]/SignOff[0]", + "entityName" : "SignOff", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerLines[2]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 80.628, + "computedY" : 35.809, + "placementX" : 80.628, + "placementY" : 35.809, + "placementWidth" : 179.909, + "placementHeight" : 11.704, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 179.909, + "contentHeight" : 11.704, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerLines[2]/DueNotice[1]", + "entityName" : "DueNotice", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerLines[2]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 80.628, + "computedY" : 21.357, + "placementX" : 80.628, + "placementY" : 21.357, + "placementWidth" : 135.165, + "placementHeight" : 11.347, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 135.165, + "contentHeight" : 11.347, + "margin" : { + "top" : 3.105, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + } ] +} diff --git a/qa/src/test/resources/layout-snapshots/canonical-templates/invoice/luma_studio_invoice_overflow_layout.json b/qa/src/test/resources/layout-snapshots/canonical-templates/invoice/luma_studio_invoice_overflow_layout.json new file mode 100644 index 000000000..7592ce06c --- /dev/null +++ b/qa/src/test/resources/layout-snapshots/canonical-templates/invoice/luma_studio_invoice_overflow_layout.json @@ -0,0 +1,3677 @@ +{ + "formatVersion" : "2.0", + "canvas" : { + "pageWidth" : 595.276, + "pageHeight" : 841.89, + "innerWidth" : 402.871, + "innerHeight" : 732.911, + "margin" : { + "top" : 46.3, + "right" : 38.931, + "bottom" : 62.679, + "left" : 153.474 + } + }, + "totalPages" : 3, + "nodes" : [ { + "path" : "LumaStudioInvoice[0]", + "entityName" : "LumaStudioInvoice", + "entityKind" : "ContainerNode", + "parentPath" : null, + "childIndex" : 0, + "depth" : 1, + "layer" : 1, + "computedX" : 153.474, + "computedY" : -695.368, + "placementX" : 153.474, + "placementY" : -695.368, + "placementWidth" : 402.871, + "placementHeight" : 1490.957, + "startPage" : 0, + "endPage" : 2, + "contentWidth" : 402.871, + "contentHeight" : 1490.957, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]", + "entityName" : "Sidebar", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 0, + "depth" : 2, + "layer" : 2, + "computedX" : 0.0, + "computedY" : 841.49, + "placementX" : 0.0, + "placementY" : 841.49, + "placementWidth" : 132.032, + "placementHeight" : 0.4, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 132.032, + "contentHeight" : 0.4, + "margin" : { + "top" : -46.3, + "right" : 0.0, + "bottom" : 45.9, + "left" : -153.474 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]", + "entityName" : "SidebarOrnament", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 0.0, + "computedY" : 0.0, + "placementX" : 0.0, + "placementY" : 0.0, + "placementWidth" : 132.032, + "placementHeight" : 634.667, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 132.032, + "contentHeight" : 634.667, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]/OrnamentDisc[0]", + "entityName" : "OrnamentDisc", + "entityKind" : "EllipseNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 17.489, + "computedY" : 527.868, + "placementX" : 17.489, + "placementY" : 527.868, + "placementWidth" : 205.382, + "placementHeight" : 205.382, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 205.382, + "contentHeight" : 205.382, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]/OrnamentArch[1]", + "entityName" : "OrnamentArch", + "entityKind" : "ShapeNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 15.799, + "computedY" : 0.0, + "placementX" : 15.799, + "placementY" : 0.0, + "placementWidth" : 116.234, + "placementHeight" : 236.588, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 116.234, + "contentHeight" : 236.588, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]/SvgIcon[2]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 12.977, + "computedY" : 282.647, + "placementX" : 12.977, + "placementY" : 282.647, + "placementWidth" : 95.244, + "placementHeight" : 95.244, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 95.244, + "contentHeight" : 95.244, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]/SvgIcon[2]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/SidebarOrnament[0]/SvgIcon[2]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 12.977, + "computedY" : 282.647, + "placementX" : 12.977, + "placementY" : 282.647, + "placementWidth" : 95.244, + "placementHeight" : 95.244, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 95.244, + "contentHeight" : 95.244, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandBlock[1]", + "entityName" : "BrandBlock", + "entityKind" : "ShapeNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 0.0, + "computedY" : 634.667, + "placementX" : 0.0, + "placementY" : 634.667, + "placementWidth" : 132.032, + "placementHeight" : 207.223, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 132.032, + "contentHeight" : 207.223, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "entityName" : "BrandLockup", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]", + "childIndex" : 2, + "depth" : 3, + "layer" : 3, + "computedX" : 0.0, + "computedY" : 634.667, + "placementX" : 0.0, + "placementY" : 634.667, + "placementWidth" : 132.032, + "placementHeight" : 207.223, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 132.032, + "contentHeight" : 207.223, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 33.288, + "computedY" : 715.218, + "placementX" : 33.288, + "placementY" : 715.218, + "placementWidth" : 36.655, + "placementHeight" : 88.273, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 36.655, + "contentHeight" : 88.273, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 33.288, + "computedY" : 705.462, + "placementX" : 33.288, + "placementY" : 705.462, + "placementWidth" : 68.585, + "placementHeight" : 47.212, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 68.585, + "contentHeight" : 47.212, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]/LockupRule[2]", + "entityName" : "LockupRule", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 33.288, + "computedY" : 704.671, + "placementX" : 33.288, + "placementY" : 704.671, + "placementWidth" : 20.311, + "placementHeight" : 1.7, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 20.311, + "contentHeight" : 1.7, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]/Wordmark[3]", + "entityName" : "Wordmark", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "childIndex" : 3, + "depth" : 4, + "layer" : 4, + "computedX" : 33.288, + "computedY" : 675.395, + "placementX" : 33.288, + "placementY" : 675.395, + "placementWidth" : 82.984, + "placementHeight" : 9.524, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 82.984, + "contentHeight" : 9.524, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]/ParagraphNode[4]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Sidebar[0]/BrandLockup[2]", + "childIndex" : 4, + "depth" : 4, + "layer" : 4, + "computedX" : 33.288, + "computedY" : 661.626, + "placementX" : 33.288, + "placementY" : 661.626, + "placementWidth" : 77.712, + "placementHeight" : 8.047, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 77.712, + "contentHeight" : 8.047, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]", + "entityName" : "Masthead", + "entityKind" : "RowNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 1, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 647.091, + "placementX" : 153.474, + "placementY" : 647.091, + "placementWidth" : 402.871, + "placementHeight" : 148.499, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 402.871, + "contentHeight" : 148.499, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]", + "entityName" : "SupplierHeader", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 153.474, + "computedY" : 655.01, + "placementX" : 153.474, + "placementY" : 655.01, + "placementWidth" : 236.404, + "placementHeight" : 140.58, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 236.404, + "contentHeight" : 140.58, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 7.334 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/SupplierName[0]", + "entityName" : "SupplierName", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 782.164, + "placementX" : 160.808, + "placementY" : 782.164, + "placementWidth" : 94.638, + "placementHeight" : 13.425, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 94.638, + "contentHeight" : 13.425, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/SupplierAddress[1]", + "entityName" : "SupplierAddress", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 727.228, + "placementX" : 160.808, + "placementY" : 727.228, + "placementWidth" : 85.39, + "placementHeight" : 48.726, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 85.39, + "contentHeight" : 48.726, + "margin" : { + "top" : 6.21, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]", + "entityName" : "ContactRows", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 674.232, + "placementX" : 160.808, + "placementY" : 674.232, + "placementWidth" : 229.071, + "placementHeight" : 43.184, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 229.071, + "contentHeight" : 43.184, + "margin" : { + "top" : 9.812, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]", + "entityName" : "ContactRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 160.808, + "computedY" : 703.022, + "placementX" : 160.808, + "placementY" : 703.022, + "placementWidth" : 229.071, + "placementHeight" : 14.395, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 229.071, + "contentHeight" : 14.395, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 160.808, + "computedY" : 705.919, + "placementX" : 160.808, + "placementY" : 705.919, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 160.808, + "computedY" : 705.919, + "placementX" : 160.808, + "placementY" : 705.919, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[0]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 181.808, + "computedY" : 704.482, + "placementX" : 181.808, + "placementY" : 704.482, + "placementWidth" : 78.706, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 78.706, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]", + "entityName" : "ContactRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 160.808, + "computedY" : 688.627, + "placementX" : 160.808, + "placementY" : 688.627, + "placementWidth" : 229.071, + "placementHeight" : 14.395, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 229.071, + "contentHeight" : 14.395, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 160.808, + "computedY" : 691.524, + "placementX" : 160.808, + "placementY" : 691.524, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 160.808, + "computedY" : 691.524, + "placementX" : 160.808, + "placementY" : 691.524, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[1]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 181.808, + "computedY" : 690.087, + "placementX" : 181.808, + "placementY" : 690.087, + "placementWidth" : 95.852, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 95.852, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]", + "entityName" : "ContactRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]", + "childIndex" : 2, + "depth" : 5, + "layer" : 5, + "computedX" : 160.808, + "computedY" : 674.232, + "placementX" : 160.808, + "placementY" : 674.232, + "placementWidth" : 229.071, + "placementHeight" : 14.395, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 229.071, + "contentHeight" : 14.395, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]/SvgIcon[0]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 160.808, + "computedY" : 677.129, + "placementX" : 160.808, + "placementY" : 677.129, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]/SvgIcon[0]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]/SvgIcon[0]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 160.808, + "computedY" : 677.129, + "placementX" : 160.808, + "placementY" : 677.129, + "placementWidth" : 8.6, + "placementHeight" : 8.6, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 8.6, + "contentHeight" : 8.6, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/ContactRows[2]/ContactRow[2]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 181.808, + "computedY" : 675.692, + "placementX" : 181.808, + "placementY" : 675.692, + "placementWidth" : 91.105, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 91.105, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]/Registration[3]", + "entityName" : "Registration", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/SupplierHeader[0]", + "childIndex" : 3, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 655.01, + "placementX" : 160.808, + "placementY" : 655.01, + "placementWidth" : 148.091, + "placementHeight" : 8.79, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 148.091, + "contentHeight" : 8.79, + "margin" : { + "top" : 10.433, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "entityName" : "InvoiceHeader", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 389.878, + "computedY" : 647.091, + "placementX" : 389.878, + "placementY" : 647.091, + "placementWidth" : 166.466, + "placementHeight" : 148.499, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 148.499, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/InvoiceTitleBlock[0]", + "entityName" : "InvoiceTitleBlock", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 749.89, + "placementX" : 389.878, + "placementY" : 749.89, + "placementWidth" : 166.466, + "placementHeight" : 45.7, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 45.7, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 15.3, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/InvoiceTitleBlock[0]/InvoiceTitle[0]", + "entityName" : "InvoiceTitle", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/InvoiceTitleBlock[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 736.636, + "placementX" : 389.878, + "placementY" : 736.636, + "placementWidth" : 164.751, + "placementHeight" : 55.553, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 164.751, + "contentHeight" : 55.553, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/InvoiceTitleBlock[0]/TitleRule[1]", + "entityName" : "TitleRule", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/InvoiceTitleBlock[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 749.89, + "placementX" : 389.878, + "placementY" : 749.89, + "placementWidth" : 58.7, + "placementHeight" : 1.7, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 58.7, + "contentHeight" : 1.7, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[1]", + "entityName" : "MetadataRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 717.09, + "placementX" : 389.878, + "placementY" : 717.09, + "placementWidth" : 166.466, + "placementHeight" : 17.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 17.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[1]/MetaLabel[0]", + "entityName" : "MetaLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 720.957, + "placementX" : 389.878, + "placementY" : 720.957, + "placementWidth" : 57.062, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 57.062, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 491.989, + "computedY" : 720.103, + "placementX" : 491.989, + "placementY" : 720.103, + "placementWidth" : 57.65, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 57.65, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[2]", + "entityName" : "MetadataRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 699.59, + "placementX" : 389.878, + "placementY" : 699.59, + "placementWidth" : 166.466, + "placementHeight" : 17.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 17.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[2]/MetaLabel[0]", + "entityName" : "MetaLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[2]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 703.458, + "placementX" : 389.878, + "placementY" : 703.458, + "placementWidth" : 51.552, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 51.552, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[2]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[2]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 491.989, + "computedY" : 702.603, + "placementX" : 491.989, + "placementY" : 702.603, + "placementWidth" : 49.641, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 49.641, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[3]", + "entityName" : "MetadataRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 3, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 682.09, + "placementX" : 389.878, + "placementY" : 682.09, + "placementWidth" : 166.466, + "placementHeight" : 17.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 17.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[3]/MetaLabel[0]", + "entityName" : "MetaLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[3]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 685.958, + "placementX" : 389.878, + "placementY" : 685.958, + "placementWidth" : 43.963, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 43.963, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[3]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[3]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 491.989, + "computedY" : 685.103, + "placementX" : 491.989, + "placementY" : 685.103, + "placementWidth" : 50.393, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 50.393, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[4]", + "entityName" : "MetadataRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 4, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 664.591, + "placementX" : 389.878, + "placementY" : 664.591, + "placementWidth" : 166.466, + "placementHeight" : 17.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 17.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[4]/MetaLabel[0]", + "entityName" : "MetaLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[4]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 668.458, + "placementX" : 389.878, + "placementY" : 668.458, + "placementWidth" : 75.89, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 75.89, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[4]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[4]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 491.989, + "computedY" : 667.603, + "placementX" : 491.989, + "placementY" : 667.603, + "placementWidth" : 29.873, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 29.873, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[5]", + "entityName" : "MetadataRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]", + "childIndex" : 5, + "depth" : 4, + "layer" : 4, + "computedX" : 389.878, + "computedY" : 647.091, + "placementX" : 389.878, + "placementY" : 647.091, + "placementWidth" : 166.466, + "placementHeight" : 17.5, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 166.466, + "contentHeight" : 17.5, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[5]/MetaLabel[0]", + "entityName" : "MetaLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[5]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 389.878, + "computedY" : 650.958, + "placementX" : 389.878, + "placementY" : 650.958, + "placementWidth" : 46.267, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 46.267, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[5]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Masthead[1]/InvoiceHeader[1]/MetadataRow[5]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 491.989, + "computedY" : 650.103, + "placementX" : 491.989, + "placementY" : 650.103, + "placementWidth" : 15.905, + "placementHeight" : 11.475, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 15.905, + "contentHeight" : 11.475, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/HeaderRule[2]", + "entityName" : "HeaderRule", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 2, + "depth" : 2, + "layer" : 2, + "computedX" : 160.808, + "computedY" : 633.091, + "placementX" : 160.808, + "placementY" : 633.091, + "placementWidth" : 395.537, + "placementHeight" : 1.0, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 395.537, + "contentHeight" : 1.0, + "margin" : { + "top" : 13.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 7.334 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]", + "entityName" : "Parties", + "entityKind" : "RowNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 3, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 532.149, + "placementX" : 153.474, + "placementY" : 532.149, + "placementWidth" : 402.871, + "placementHeight" : 88.942, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 402.871, + "contentHeight" : 88.942, + "margin" : { + "top" : 12.0, + "right" : 0.0, + "bottom" : 12.9, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/BILLTO[0]", + "entityName" : "BILLTO", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 153.474, + "computedY" : 532.149, + "placementX" : 153.474, + "placementY" : 532.149, + "placementWidth" : 103.12, + "placementHeight" : 88.942, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 103.12, + "contentHeight" : 88.942, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 7.334 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/BILLTO[0]/PartyHeading[0]", + "entityName" : "PartyHeading", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]/BILLTO[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 611.326, + "placementX" : 160.808, + "placementY" : 611.326, + "placementWidth" : 33.342, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 33.342, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/BILLTO[0]/PartyAddress[1]", + "entityName" : "PartyAddress", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]/BILLTO[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 160.808, + "computedY" : 532.149, + "placementX" : 160.808, + "placementY" : 532.149, + "placementWidth" : 95.786, + "placementHeight" : 70.235, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 95.786, + "contentHeight" : 70.235, + "margin" : { + "top" : 8.942, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/SHIPTO[1]", + "entityName" : "SHIPTO", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 344.757, + "computedY" : 532.149, + "placementX" : 344.757, + "placementY" : 532.149, + "placementWidth" : 133.88, + "placementHeight" : 88.942, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 133.88, + "contentHeight" : 88.942, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 34.4 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/SHIPTO[1]/PartyHeading[0]", + "entityName" : "PartyHeading", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]/SHIPTO[1]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 379.157, + "computedY" : 611.326, + "placementX" : 379.157, + "placementY" : 611.326, + "placementWidth" : 35.173, + "placementHeight" : 9.765, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 35.173, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Parties[3]/SHIPTO[1]/PartyAddress[1]", + "entityName" : "PartyAddress", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Parties[3]/SHIPTO[1]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 379.157, + "computedY" : 532.149, + "placementX" : 379.157, + "placementY" : 532.149, + "placementWidth" : 99.48, + "placementHeight" : 70.235, + "startPage" : 0, + "endPage" : 0, + "contentWidth" : 99.48, + "contentHeight" : 70.235, + "margin" : { + "top" : 8.942, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/LineItems[4]", + "entityName" : "LineItems", + "entityKind" : "TableNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 4, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 99.964, + "placementX" : 153.474, + "placementY" : 99.964, + "placementWidth" : 402.871, + "placementHeight" : 1011.964, + "startPage" : 0, + "endPage" : 1, + "contentWidth" : 402.871, + "contentHeight" : 1011.964, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]", + "entityName" : "Totals", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 5, + "depth" : 2, + "layer" : 2, + "computedX" : 306.404, + "computedY" : 108.172, + "placementX" : 306.404, + "placementY" : 108.172, + "placementWidth" : 249.941, + "placementHeight" : 66.174, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 249.941, + "contentHeight" : 66.174, + "margin" : { + "top" : 4.4, + "right" : 0.0, + "bottom" : 0.0, + "left" : 152.93 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[0]", + "entityName" : "TotalsRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 306.404, + "computedY" : 156.237, + "placementX" : 306.404, + "placementY" : 156.237, + "placementWidth" : 249.941, + "placementHeight" : 18.108, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 249.941, + "contentHeight" : 18.108, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[0]/TotalsLabel[0]", + "entityName" : "TotalsLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 348.204, + "computedY" : 159.439, + "placementX" : 348.204, + "placementY" : 159.439, + "placementWidth" : 46.299, + "placementHeight" : 11.704, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 46.299, + "contentHeight" : 11.704, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[0]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 293.404, + "computedY" : 159.439, + "placementX" : 293.404, + "placementY" : 159.439, + "placementWidth" : 249.941, + "placementHeight" : 11.704, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 249.941, + "contentHeight" : 11.704, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[1]", + "entityName" : "TotalsRow", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 306.404, + "computedY" : 138.129, + "placementX" : 306.404, + "placementY" : 138.129, + "placementWidth" : 249.941, + "placementHeight" : 18.108, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 249.941, + "contentHeight" : 18.108, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[1]/TotalsLabel[0]", + "entityName" : "TotalsLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[1]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 348.204, + "computedY" : 141.331, + "placementX" : 348.204, + "placementY" : 141.331, + "placementWidth" : 45.982, + "placementHeight" : 11.704, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 45.982, + "contentHeight" : 11.704, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalsRow[1]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 293.404, + "computedY" : 141.331, + "placementX" : 293.404, + "placementY" : 141.331, + "placementWidth" : 249.941, + "placementHeight" : 11.704, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 249.941, + "contentHeight" : 11.704, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalDueBand[2]", + "entityName" : "TotalDueBand", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]", + "childIndex" : 2, + "depth" : 3, + "layer" : 3, + "computedX" : 306.404, + "computedY" : 108.172, + "placementX" : 306.404, + "placementY" : 108.172, + "placementWidth" : 249.941, + "placementHeight" : 27.1, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 249.941, + "contentHeight" : 27.1, + "margin" : { + "top" : 2.857, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalDueBand[2]/TotalsLabel[0]", + "entityName" : "TotalsLabel", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalDueBand[2]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 348.204, + "computedY" : 115.468, + "placementX" : 348.204, + "placementY" : 115.468, + "placementWidth" : 52.971, + "placementHeight" : 12.507, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 52.971, + "contentHeight" : 12.507, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Totals[5]/TotalDueBand[2]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Totals[5]/TotalDueBand[2]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 293.404, + "computedY" : 110.431, + "placementX" : 293.404, + "placementY" : 110.431, + "placementWidth" : 249.941, + "placementHeight" : 22.582, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 249.941, + "contentHeight" : 22.582, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/FooterRule[6]", + "entityName" : "FooterRule", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 6, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 105.172, + "placementX" : 153.474, + "placementY" : 105.172, + "placementWidth" : 402.871, + "placementHeight" : 1.0, + "startPage" : 1, + "endPage" : 1, + "contentWidth" : 402.871, + "contentHeight" : 1.0, + "margin" : { + "top" : 2.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]", + "entityName" : "Closing", + "entityKind" : "RowNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 7, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 675.411, + "placementX" : 153.474, + "placementY" : 675.411, + "placementWidth" : 402.871, + "placementHeight" : 108.178, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 402.871, + "contentHeight" : 108.178, + "margin" : { + "top" : 12.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]", + "entityName" : "Notes", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 153.474, + "computedY" : 687.309, + "placementX" : 153.474, + "placementY" : 687.309, + "placementWidth" : 167.03, + "placementHeight" : 96.281, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 167.03, + "contentHeight" : 96.281, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]", + "entityName" : "SectionHead", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 153.474, + "computedY" : 758.79, + "placementX" : 153.474, + "placementY" : 758.79, + "placementWidth" : 167.03, + "placementHeight" : 24.8, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 167.03, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]", + "entityName" : "Disc-notes", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 153.474, + "computedY" : 758.79, + "placementX" : 153.474, + "placementY" : 758.79, + "placementWidth" : 24.8, + "placementHeight" : 24.8, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 24.8, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]/DiscFill[0]", + "entityName" : "DiscFill", + "entityKind" : "EllipseNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 153.474, + "computedY" : 758.79, + "placementX" : 153.474, + "placementY" : 758.79, + "placementWidth" : 24.8, + "placementHeight" : 24.8, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 24.8, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]/SvgIcon[1]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 159.874, + "computedY" : 765.19, + "placementX" : 159.874, + "placementY" : 765.19, + "placementWidth" : 12.0, + "placementHeight" : 12.0, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 12.0, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]/SvgIcon[1]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/Disc-notes[0]/SvgIcon[1]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 159.874, + "computedY" : 765.19, + "placementX" : 159.874, + "placementY" : 765.19, + "placementWidth" : 12.0, + "placementHeight" : 12.0, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 12.0, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]/SectionHeading[1]", + "entityName" : "SectionHeading", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/SectionHead[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 188.974, + "computedY" : 766.307, + "placementX" : 188.974, + "placementY" : 766.307, + "placementWidth" : 28.177, + "placementHeight" : 9.765, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 28.177, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/NotesBody[1]", + "entityName" : "NotesBody", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 153.474, + "computedY" : 687.309, + "placementX" : 153.474, + "placementY" : 687.309, + "placementWidth" : 156.503, + "placementHeight" : 69.245, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 156.503, + "contentHeight" : 69.245, + "margin" : { + "top" : 2.236, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 35.5 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/NotesBody[1]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/NotesBody[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 188.974, + "computedY" : 726.589, + "placementX" : 188.974, + "placementY" : 726.589, + "placementWidth" : 103.794, + "placementHeight" : 29.965, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 103.794, + "contentHeight" : 29.965, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/NotesBody[1]/ParagraphNode[1]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/Notes[0]/NotesBody[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 188.974, + "computedY" : 687.309, + "placementX" : 188.974, + "placementY" : 687.309, + "placementWidth" : 121.003, + "placementHeight" : 29.965, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 121.003, + "contentHeight" : 29.965, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]", + "entityName" : "PaymentDetails", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]", + "childIndex" : 1, + "depth" : 3, + "layer" : 3, + "computedX" : 320.504, + "computedY" : 675.411, + "placementX" : 320.504, + "placementY" : 675.411, + "placementWidth" : 235.84, + "placementHeight" : 108.178, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 235.84, + "contentHeight" : 108.178, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 24.3 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]", + "entityName" : "SectionHead", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 344.804, + "computedY" : 758.79, + "placementX" : 344.804, + "placementY" : 758.79, + "placementWidth" : 211.54, + "placementHeight" : 24.8, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 211.54, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]", + "entityName" : "Disc-bank", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 344.804, + "computedY" : 758.79, + "placementX" : 344.804, + "placementY" : 758.79, + "placementWidth" : 24.8, + "placementHeight" : 24.8, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 24.8, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]/DiscFill[0]", + "entityName" : "DiscFill", + "entityKind" : "EllipseNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 344.804, + "computedY" : 758.79, + "placementX" : 344.804, + "placementY" : 758.79, + "placementWidth" : 24.8, + "placementHeight" : 24.8, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 24.8, + "contentHeight" : 24.8, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]/SvgIcon[1]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 351.204, + "computedY" : 765.19, + "placementX" : 351.204, + "placementY" : 765.19, + "placementWidth" : 12.0, + "placementHeight" : 12.0, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 12.0, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]/SvgIcon[1]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/Disc-bank[0]/SvgIcon[1]", + "childIndex" : 0, + "depth" : 7, + "layer" : 7, + "computedX" : 351.204, + "computedY" : 765.19, + "placementX" : 351.204, + "placementY" : 765.19, + "placementWidth" : 12.0, + "placementHeight" : 12.0, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 12.0, + "contentHeight" : 12.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]/SectionHeading[1]", + "entityName" : "SectionHeading", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/SectionHead[0]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 766.307, + "placementX" : 380.304, + "placementY" : 766.307, + "placementWidth" : 82.727, + "placementHeight" : 9.765, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 82.727, + "contentHeight" : 9.765, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "entityName" : "PaymentBody", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 344.804, + "computedY" : 675.411, + "placementX" : 344.804, + "placementY" : 675.411, + "placementWidth" : 211.54, + "placementHeight" : 81.143, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 211.54, + "contentHeight" : 81.143, + "margin" : { + "top" : 2.236, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 35.5 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentInstruction[0]", + "entityName" : "PaymentInstruction", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 748.58, + "placementX" : 380.304, + "placementY" : 748.58, + "placementWidth" : 121.183, + "placementHeight" : 7.974, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 121.183, + "contentHeight" : 7.974, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/AccountHolder[1]", + "entityName" : "AccountHolder", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 733.226, + "placementX" : 380.304, + "placementY" : 733.226, + "placementWidth" : 83.026, + "placementHeight" : 9.765, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 83.026, + "contentHeight" : 9.765, + "margin" : { + "top" : 5.589, + "right" : 0.0, + "bottom" : 6.831, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]", + "entityName" : "PaymentField", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 2, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 716.199, + "placementX" : 380.304, + "placementY" : 716.199, + "placementWidth" : 176.04, + "placementHeight" : 10.197, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 176.04, + "contentHeight" : 10.197, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 380.304, + "computedY" : 716.902, + "placementX" : 380.304, + "placementY" : 716.902, + "placementWidth" : 17.087, + "placementHeight" : 8.79, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 17.087, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]/BankPipe[1]", + "entityName" : "BankPipe", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 433.904, + "computedY" : 717.932, + "placementX" : 433.904, + "placementY" : 717.932, + "placementWidth" : 1.0, + "placementHeight" : 6.73, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 1.0, + "contentHeight" : 6.73, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[2]", + "childIndex" : 2, + "depth" : 6, + "layer" : 6, + "computedX" : 444.104, + "computedY" : 716.902, + "placementX" : 444.104, + "placementY" : 716.902, + "placementWidth" : 38.198, + "placementHeight" : 8.79, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 38.198, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]", + "entityName" : "PaymentField", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 3, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 706.002, + "placementX" : 380.304, + "placementY" : 706.002, + "placementWidth" : 176.04, + "placementHeight" : 10.197, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 176.04, + "contentHeight" : 10.197, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 380.304, + "computedY" : 706.705, + "placementX" : 380.304, + "placementY" : 706.705, + "placementWidth" : 34.245, + "placementHeight" : 8.79, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 34.245, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]/BankPipe[1]", + "entityName" : "BankPipe", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 433.904, + "computedY" : 707.735, + "placementX" : 433.904, + "placementY" : 707.735, + "placementWidth" : 1.0, + "placementHeight" : 6.73, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 1.0, + "contentHeight" : 6.73, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[3]", + "childIndex" : 2, + "depth" : 6, + "layer" : 6, + "computedX" : 444.104, + "computedY" : 706.705, + "placementX" : 444.104, + "placementY" : 706.705, + "placementWidth" : 26.31, + "placementHeight" : 8.79, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 26.31, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]", + "entityName" : "PaymentField", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 4, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 695.805, + "placementX" : 380.304, + "placementY" : 695.805, + "placementWidth" : 176.04, + "placementHeight" : 10.197, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 176.04, + "contentHeight" : 10.197, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 380.304, + "computedY" : 696.509, + "placementX" : 380.304, + "placementY" : 696.509, + "placementWidth" : 43.022, + "placementHeight" : 8.79, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 43.022, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]/BankPipe[1]", + "entityName" : "BankPipe", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 433.904, + "computedY" : 697.538, + "placementX" : 433.904, + "placementY" : 697.538, + "placementWidth" : 1.0, + "placementHeight" : 6.73, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 1.0, + "contentHeight" : 6.73, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[4]", + "childIndex" : 2, + "depth" : 6, + "layer" : 6, + "computedX" : 444.104, + "computedY" : 696.509, + "placementX" : 444.104, + "placementY" : 696.509, + "placementWidth" : 29.205, + "placementHeight" : 8.79, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 29.205, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]", + "entityName" : "PaymentField", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 5, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 685.608, + "placementX" : 380.304, + "placementY" : 685.608, + "placementWidth" : 176.04, + "placementHeight" : 10.197, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 176.04, + "contentHeight" : 10.197, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 380.304, + "computedY" : 686.312, + "placementX" : 380.304, + "placementY" : 686.312, + "placementWidth" : 15.07, + "placementHeight" : 8.79, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 15.07, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]/BankPipe[1]", + "entityName" : "BankPipe", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 433.904, + "computedY" : 687.342, + "placementX" : 433.904, + "placementY" : 687.342, + "placementWidth" : 1.0, + "placementHeight" : 6.73, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 1.0, + "contentHeight" : 6.73, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[5]", + "childIndex" : 2, + "depth" : 6, + "layer" : 6, + "computedX" : 444.104, + "computedY" : 686.312, + "placementX" : 444.104, + "placementY" : 686.312, + "placementWidth" : 89.789, + "placementHeight" : 8.79, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 89.789, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]", + "entityName" : "PaymentField", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]", + "childIndex" : 6, + "depth" : 5, + "layer" : 5, + "computedX" : 380.304, + "computedY" : 675.411, + "placementX" : 380.304, + "placementY" : 675.411, + "placementWidth" : 176.04, + "placementHeight" : 10.197, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 176.04, + "contentHeight" : 10.197, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]/ParagraphNode[0]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 380.304, + "computedY" : 676.115, + "placementX" : 380.304, + "placementY" : 676.115, + "placementWidth" : 9.771, + "placementHeight" : 8.79, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 9.771, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]/BankPipe[1]", + "entityName" : "BankPipe", + "entityKind" : "LineNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]", + "childIndex" : 1, + "depth" : 6, + "layer" : 6, + "computedX" : 433.904, + "computedY" : 677.145, + "placementX" : 433.904, + "placementY" : 677.145, + "placementWidth" : 1.0, + "placementHeight" : 6.73, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 1.0, + "contentHeight" : 6.73, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]/ParagraphNode[2]", + "entityName" : null, + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/Closing[7]/PaymentDetails[1]/PaymentBody[1]/PaymentField[6]", + "childIndex" : 2, + "depth" : 6, + "layer" : 6, + "computedX" : 444.104, + "computedY" : 676.115, + "placementX" : 444.104, + "placementY" : 676.115, + "placementWidth" : 29.918, + "placementHeight" : 8.79, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 29.918, + "contentHeight" : 8.79, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]", + "entityName" : "ClosingBanner", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]", + "childIndex" : 8, + "depth" : 2, + "layer" : 2, + "computedX" : 153.474, + "computedY" : 666.511, + "placementX" : 153.474, + "placementY" : 666.511, + "placementWidth" : 402.871, + "placementHeight" : 0.3, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 402.871, + "contentHeight" : 0.3, + "margin" : { + "top" : 8.6, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]", + "entityName" : "BannerContent", + "entityKind" : "ShapeContainerNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]", + "childIndex" : 0, + "depth" : 3, + "layer" : 3, + "computedX" : 0.0, + "computedY" : 604.133, + "placementX" : 0.0, + "placementY" : 604.133, + "placementWidth" : 595.276, + "placementHeight" : 62.679, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 595.276, + "contentHeight" : 62.679, + "margin" : { + "top" : 0.0, + "right" : -38.931, + "bottom" : -62.379, + "left" : -153.474 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerBand[0]", + "entityName" : "BannerBand", + "entityKind" : "ShapeNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]", + "childIndex" : 0, + "depth" : 4, + "layer" : 4, + "computedX" : 0.0, + "computedY" : 604.133, + "placementX" : 0.0, + "placementY" : 604.133, + "placementWidth" : 595.276, + "placementHeight" : 62.679, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 595.276, + "contentHeight" : 62.679, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]", + "entityName" : "Disc-heart", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]", + "childIndex" : 1, + "depth" : 4, + "layer" : 4, + "computedX" : 32.728, + "computedY" : 618.522, + "placementX" : 32.728, + "placementY" : 618.522, + "placementWidth" : 33.9, + "placementHeight" : 33.9, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 33.9, + "contentHeight" : 33.9, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]/DiscFill[0]", + "entityName" : "DiscFill", + "entityKind" : "EllipseNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 32.728, + "computedY" : 618.522, + "placementX" : 32.728, + "placementY" : 618.522, + "placementWidth" : 33.9, + "placementHeight" : 33.9, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 33.9, + "contentHeight" : 33.9, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]/SvgIcon[1]", + "entityName" : "SvgIcon", + "entityKind" : "LayerStackNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 41.678, + "computedY" : 627.472, + "placementX" : 41.678, + "placementY" : 627.472, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]/SvgIcon[1]/SvgLayer0[0]", + "entityName" : "SvgLayer0", + "entityKind" : "Path", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/Disc-heart[1]/SvgIcon[1]", + "childIndex" : 0, + "depth" : 6, + "layer" : 6, + "computedX" : 41.678, + "computedY" : 627.472, + "placementX" : 41.678, + "placementY" : 627.472, + "placementWidth" : 16.0, + "placementHeight" : 16.0, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 16.0, + "contentHeight" : 16.0, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerLines[2]", + "entityName" : "BannerLines", + "entityKind" : "SectionNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]", + "childIndex" : 2, + "depth" : 4, + "layer" : 4, + "computedX" : 80.628, + "computedY" : 622.394, + "placementX" : 80.628, + "placementY" : 622.394, + "placementWidth" : 179.909, + "placementHeight" : 26.156, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 179.909, + "contentHeight" : 26.156, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerLines[2]/SignOff[0]", + "entityName" : "SignOff", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerLines[2]", + "childIndex" : 0, + "depth" : 5, + "layer" : 5, + "computedX" : 80.628, + "computedY" : 636.846, + "placementX" : 80.628, + "placementY" : 636.846, + "placementWidth" : 179.909, + "placementHeight" : 11.704, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 179.909, + "contentHeight" : 11.704, + "margin" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + }, { + "path" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerLines[2]/DueNotice[1]", + "entityName" : "DueNotice", + "entityKind" : "ParagraphNode", + "parentPath" : "LumaStudioInvoice[0]/ClosingBanner[8]/BannerContent[0]/BannerLines[2]", + "childIndex" : 1, + "depth" : 5, + "layer" : 5, + "computedX" : 80.628, + "computedY" : 622.394, + "placementX" : 80.628, + "placementY" : 622.394, + "placementWidth" : 135.165, + "placementHeight" : 11.347, + "startPage" : 2, + "endPage" : 2, + "contentWidth" : 135.165, + "contentHeight" : 11.347, + "margin" : { + "top" : 3.105, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + }, + "padding" : { + "top" : 0.0, + "right" : 0.0, + "bottom" : 0.0, + "left" : 0.0 + } + } ] +} diff --git a/qa/src/test/resources/visual-baselines/invoice-v2-layered/luma_studio_invoice-page-0.png b/qa/src/test/resources/visual-baselines/invoice-v2-layered/luma_studio_invoice-page-0.png new file mode 100644 index 000000000..05eeaea9b Binary files /dev/null and b/qa/src/test/resources/visual-baselines/invoice-v2-layered/luma_studio_invoice-page-0.png differ diff --git a/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioClosing.java b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioClosing.java new file mode 100644 index 000000000..aed7054c3 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioClosing.java @@ -0,0 +1,269 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.document.dsl.LineBuilder; +import com.demcha.compose.document.dsl.SectionBuilder; +import com.demcha.compose.document.dsl.ShapeBuilder; +import com.demcha.compose.document.node.DocumentNode; +import com.demcha.compose.document.node.LayerAlign; +import com.demcha.compose.document.node.TextAlign; +import com.demcha.compose.document.style.ClipPolicy; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.templates.data.invoice.InvoiceNotesBlock; +import com.demcha.compose.document.templates.data.invoice.InvoicePaymentBlock; +import com.demcha.compose.document.templates.data.invoice.InvoiceTotalsBlock; + +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ACCENT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANK_LABEL; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANK_PIPE_OFFSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANK_ROW_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANK_VALUE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANK_VALUE_OFFSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANNER_CONTENT_INSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANNER_DISC_ICON_SIZE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANNER_DISC_SIZE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANNER_DUE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANNER_FLOW_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANNER_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANNER_SIGN_OFF; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANNER_TEXT_OFFSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.CLOSING_DIVIDER_INSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.CLOSING_LEFT_WEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.CONTENT_WIDTH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.HAIRLINE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.HAIRLINE_QUIET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.INK_SURFACE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.LINE_PITCH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.NOTE_TEXT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAGE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAGE_MARGIN_LEFT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAGE_MARGIN_RIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PANEL_HIGHLIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAPER; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.RULE_THICKNESS; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SECTION_HEADING_OFFSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SMALL_BOLD; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TABLE_TO_TOTALS; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TOTALS_AMOUNT_INSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TOTALS_LABEL_INSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TOTALS_ROW_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TOTALS_TO_RULE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TOTALS_WIDTH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TOTAL_AMOUNT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TOTAL_DUE_AMOUNT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TOTAL_DUE_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TOTAL_DUE_LABEL; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TOTAL_LABEL; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TRACK_TOTAL_LABEL; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.leading; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.money; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioWidgets.disc; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioWidgets.paragraph; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioWidgets.sectionHead; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioWidgets.tracked; + +/** + * What closes the sheet: the totals stack, the notes and payment pair, and + * the sign-off band. + */ +final class LumaStudioClosing { + + private LumaStudioClosing() { + } + + // -- totals ---------------------------------------------------------- + + /** + * The totals stack, right-aligned by its own left margin, closing on the + * filled total-due band. + */ + static void renderTotals(SectionBuilder section, InvoiceTotalsBlock totals, + String currencySymbol) { + section.name("Totals") + .keepTogether() + .spacing(0) + .margin(new DocumentInsets( + TABLE_TO_TOTALS, 0, 0, CONTENT_WIDTH - TOTALS_WIDTH)); + for (InvoiceTotalsBlock.Row row : totals.rows()) { + totalsRow(section, row.label(), money(currencySymbol, row.amount()), false); + } + totalsRow(section, totals.totalLabel(), + money(currencySymbol, totals.totalAmount()), true); + } + + private static void totalsRow(SectionBuilder section, String label, String amount, + boolean emphasised) { + section.addContainer(container -> { + container.name(emphasised ? "TotalDueBand" : "TotalsRow") + .rectangle(TOTALS_WIDTH, emphasised ? TOTAL_DUE_HEIGHT : TOTALS_ROW_HEIGHT) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE) + .position(tracked("TotalsLabel", label, + emphasised ? TOTAL_DUE_LABEL : TOTAL_LABEL, + TRACK_TOTAL_LABEL, + emphasised ? PANEL_HIGHLIGHT : PAPER), + TOTALS_LABEL_INSET, 0, LayerAlign.CENTER_LEFT) + .position(paragraph(amount, + emphasised ? TOTAL_DUE_AMOUNT : TOTAL_AMOUNT, + TextAlign.RIGHT), + -TOTALS_AMOUNT_INSET, 0, LayerAlign.CENTER_RIGHT); + if (emphasised) { + container.fillColor(PANEL_HIGHLIGHT) + .margin(new DocumentInsets(LINE_PITCH * 0.23, 0, 0, 0)); + } + }); + } + + /** The hairline that closes the totals and opens the pair below. */ + static void renderFooterRule(LineBuilder line) { + line.name("FooterRule") + .horizontal(CONTENT_WIDTH) + .thickness(RULE_THICKNESS) + .color(HAIRLINE) + .margin(new DocumentInsets(TOTALS_TO_RULE, 0, 0, 0)); + } + + // -- notes and payment ----------------------------------------------- + + /** The notes column: the disc heading, then the paragraphs under it. */ + static void renderNotes(SectionBuilder section, InvoiceNotesBlock notes) { + section.name("Notes").keepTogether().spacing(0); + sectionHead(section, LumaStudioIcons.NOTES, notes.heading(), + CONTENT_WIDTH * CLOSING_LEFT_WEIGHT); + SectionBuilder body = new SectionBuilder() + .name("NotesBody") + .spacing(LINE_PITCH * 0.75) + .padding(new DocumentInsets(0, 0, 0, SECTION_HEADING_OFFSET)) + .margin(new DocumentInsets(LINE_PITCH * 0.18, 0, 0, 0)); + for (String note : notes.paragraphs()) { + body.addParagraph(p -> p + .text(note) + .textStyle(NOTE_TEXT) + .lineSpacing(leading(LINE_PITCH * 0.91, NOTE_TEXT)) + .margin(DocumentInsets.zero())); + } + section.add(body.build()); + } + + /** + * The payment column: the disc heading, the instruction, who is paid, and + * the bank fields as label / pipe / value on one axis. + * + *

The divider between the two columns is this column's own left + * border, so it takes its height from what this column holds.

+ */ + static void renderPayment(SectionBuilder section, InvoicePaymentBlock payment) { + section.name("PaymentDetails") + .keepTogether() + .spacing(0) + .accentLeft(HAIRLINE_QUIET, RULE_THICKNESS) + .padding(new DocumentInsets(0, 0, 0, CLOSING_DIVIDER_INSET)); + double blockWidth = CONTENT_WIDTH * (1.0 - CLOSING_LEFT_WEIGHT) - CLOSING_DIVIDER_INSET; + sectionHead(section, LumaStudioIcons.BANK, payment.heading(), blockWidth); + + SectionBuilder body = new SectionBuilder() + .name("PaymentBody") + .spacing(0) + .padding(new DocumentInsets(0, 0, 0, SECTION_HEADING_OFFSET)) + .margin(new DocumentInsets(LINE_PITCH * 0.18, 0, 0, 0)); + body.addParagraph(p -> p + .name("PaymentInstruction") + .text(payment.instruction()) + .textStyle(NOTE_TEXT) + .lineSpacing(0) + .margin(DocumentInsets.zero())) + .addParagraph(p -> p + .name("AccountHolder") + .text(payment.accountHolder()) + .textStyle(SMALL_BOLD) + .lineSpacing(0) + .margin(new DocumentInsets( + LINE_PITCH * 0.45, 0, LINE_PITCH * 0.55, 0))); + + double fieldWidth = blockWidth - SECTION_HEADING_OFFSET; + for (InvoicePaymentBlock.Field field : payment.fields()) { + body.addContainer(container -> container + .name("PaymentField") + .rectangle(fieldWidth, BANK_ROW_HEIGHT) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE) + .centerLeft(paragraph(field.label(), BANK_LABEL, TextAlign.LEFT)) + .position(pipe(), BANK_PIPE_OFFSET, 0, LayerAlign.CENTER_LEFT) + .position(paragraph(field.value(), BANK_VALUE, TextAlign.LEFT), + BANK_VALUE_OFFSET, 0, LayerAlign.CENTER_LEFT)); + } + section.add(body.build()); + } + + private static DocumentNode pipe() { + return new LineBuilder() + .name("BankPipe") + .vertical(BANK_ROW_HEIGHT * 0.66) + .thickness(0.8) + .color(ACCENT) + .margin(DocumentInsets.zero()) + .build(); + } + + // -- the closing band ------------------------------------------------ + + /** + * The sign-off band: the dark strip, the heart on its disc, and the two + * closing lines. + * + *

The strip is drawn by this block rather than left to the page + * background that closes every page. On a one-page invoice the two + * coincide exactly — the flow ends at the foot, so the block lands on the + * background band and nothing about the sheet changes. On a longer one the + * flow ends wherever the closing blocks end, and a block that relied on the + * background would set white words on pale paper. Carrying its own ground + * is what makes the sign-off legible on whatever page it lands.

+ * + *

The strip bleeds to both paper edges through negative side margins, + * and the ground is a layer rather than the container's fill: a container's + * own fill is dropped under a large negative margin. The block's height in + * the flow is almost nothing — it reaches down into the margin the page + * reserves for the band instead of pushing the flow.

+ * + *

It is flow content only because footer chrome carries text today: one + * size and one colour across three slots, and no glyph, where this band + * needs two faces and a disc. Once a footer zone can hold a node, the + * sign-off belongs in one — pinned to the foot of the last page, where the + * design draws it — and this block and its strip go away.

+ */ + static void renderBanner(SectionBuilder section, InvoicePaymentBlock payment) { + section.name("ClosingBanner").keepTogether().spacing(0); + SectionBuilder lines = new SectionBuilder().name("BannerLines").spacing(0); + lines.addParagraph(p -> p + .name("SignOff") + .text(payment.signOff()) + .textStyle(BANNER_SIGN_OFF) + .lineSpacing(0) + .margin(DocumentInsets.zero())) + .addParagraph(p -> p + .name("DueNotice") + .text(payment.dueNotice()) + .textStyle(BANNER_DUE) + .lineSpacing(0) + .margin(new DocumentInsets(LINE_PITCH * 0.25, 0, 0, 0))); + section.addContainer(container -> container + .name("BannerContent") + .rectangle(PAGE.width(), BANNER_HEIGHT) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE) + .margin(new DocumentInsets( + 0, -PAGE_MARGIN_RIGHT, BANNER_FLOW_HEIGHT - BANNER_HEIGHT, + -PAGE_MARGIN_LEFT)) + .position(band(), 0, 0, LayerAlign.TOP_LEFT, 0) + .position(disc(BANNER_DISC_SIZE, LumaStudioIcons.HEART, BANNER_DISC_ICON_SIZE), + BANNER_CONTENT_INSET, 0, LayerAlign.CENTER_LEFT, 1) + .position(lines.build(), BANNER_CONTENT_INSET + BANNER_TEXT_OFFSET, 0, + LayerAlign.CENTER_LEFT, 1)); + } + + /** The strip the sign-off is set on, paper edge to paper edge. */ + private static DocumentNode band() { + return new ShapeBuilder() + .name("BannerBand") + .size(PAGE.width(), BANNER_HEIGHT) + .fillColor(INK_SURFACE) + .margin(DocumentInsets.zero()) + .build(); + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioIcons.java b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioIcons.java new file mode 100644 index 000000000..671fbdfc2 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioIcons.java @@ -0,0 +1,65 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.document.node.DocumentNode; +import com.demcha.compose.document.svg.SvgIcon; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Classpath loader for the Luma Studio invoice marks: the three contact + * glyphs, the two section discs, the closing heart and the sidebar sprig. + * + *

They ship inside the templates artifact under + * {@code templates/invoice/luma-studio/icons/} as SVG, so they scale with the + * box they are drawn into rather than being resampled. Parsed icons are + * cached per token, so a repeated mark reads its file once per JVM.

+ * + *

Every mark here is chrome rather than data — this sheet draws the same + * ones whatever the invoice says — so the tokens are constants and no + * document names one.

+ */ +final class LumaStudioIcons { + + static final String PHONE = "phone"; + static final String EMAIL = "email"; + static final String WEBSITE = "website"; + static final String NOTES = "notes"; + static final String BANK = "bank"; + static final String HEART = "heart"; + static final String SPRIG = "sprig"; + + private static final String ICON_ROOT = "/templates/invoice/luma-studio/icons/"; + private static final Map CACHE = new ConcurrentHashMap<>(); + + private LumaStudioIcons() { + } + + /** + * Builds one mark at a given width; the height follows its ratio. + * + * @param token one of the constants on this class + * @param width the drawn width + * @return the icon node + */ + static DocumentNode icon(String token, double width) { + return CACHE.computeIfAbsent(token, LumaStudioIcons::read).node(width); + } + + private static SvgIcon read(String token) { + String resourcePath = ICON_ROOT + token + ".svg"; + try (InputStream input = LumaStudioIcons.class.getResourceAsStream(resourcePath)) { + if (input == null) { + throw new IllegalStateException("Missing luma studio invoice icon: " + resourcePath); + } + return SvgIcon.parse(new String(input.readAllBytes(), StandardCharsets.UTF_8)); + } catch (IOException e) { + throw new UncheckedIOException( + "Failed to read luma studio invoice icon: " + resourcePath, e); + } + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoice.java b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoice.java new file mode 100644 index 000000000..f951ab8c9 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioInvoice.java @@ -0,0 +1,223 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.document.api.DocumentSession; +import com.demcha.compose.document.api.PageBackgroundFill; +import com.demcha.compose.document.output.DocumentHeaderFooter; +import com.demcha.compose.document.output.DocumentHeaderFooterZone; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.templates.api.DocumentTemplate; +import com.demcha.compose.document.templates.data.invoice.StructuredInvoiceData; +import com.demcha.compose.document.templates.data.invoice.StructuredInvoiceDocumentSpec; + +import java.util.Currency; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANNER_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BANNER_HEIGHT_RATIO; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.CLOSING_LEFT_WEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.CLOSING_TO_BANNER; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.FOLIO_ZONE_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.INK_SURFACE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.MASTHEAD_LEFT_WEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.MASTHEAD_RIGHT_WEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.MICRO_SIZE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ON_DARK; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAGE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAGE_MARGIN_LEFT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAGE_MARGIN_RIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAGE_MARGIN_TOP; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAPER; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PARTIES_LEFT_WEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PARTIES_TO_TABLE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.RULE_TO_CLOSING; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.RULE_TO_PARTIES; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SIDEBAR_SURFACE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SIDEBAR_WIDTH_RATIO; + +/** + * Luma Studio Invoice — a studio invoice built around a cream sidebar: the + * brand lockup sits on a terracotta block at the top of that column, an + * ornament runs down the rest of it, and the billing sheet is set in the + * page beside them. + * + *

The sheet reads top to bottom: the sender over the document title and + * its metadata, the two parties across a rule, the priced service lines, the + * totals stack closing on a filled total-due band, and the notes and payment + * details side by side above the sign-off band at the foot.

+ * + *

Long invoices flow. The line-items table repeats its dark header on the + * next page, the totals stack and each closing block stay whole, and the paper + * tint, the cream sidebar column and the dark foot band are page backgrounds, + * so every page carries the same frame and the folio always has a dark ground. + * Every page reserves the band's height as bottom margin, so no row runs under + * it.

+ * + *

The sign-off carries its own strip rather than relying on that foot band. + * On a one-page invoice the two land together; on a longer one the flow ends + * where the closing blocks end, and a sign-off that relied on the background + * would set white words on pale paper. It is flow content only because footer + * chrome carries text today and this band needs two faces and a disc — once a + * footer zone can hold a node, the sign-off belongs in one.

+ * + *

The preset owns its session geometry — A4, the margins, the page fills + * and the folio zone — so callers leave the session unconfigured; a margin + * set by the caller is overwritten. It consumes the structured invoice model + * ({@link StructuredInvoiceDocumentSpec}): every heading, label and column + * title is content, so the same composition prints an invoice in another + * studio's wording without a fork. Amounts are prefixed with the mark of the + * data's own currency code. The preset draws in Carlito, Spectral and Tinos; + * its marks — the contact icons, the two closing-block badges, the heart on + * the band and the sidebar sprig — are template chrome and ship inside the + * artifact.

+ * + * @since 2.2.3 + */ +public final class LumaStudioInvoice { + + /** + * Stable template identifier. + */ + public static final String ID = "invoice-luma-studio"; + + /** + * Human-readable display name. + */ + public static final String DISPLAY_NAME = "Luma Studio Invoice"; + + private LumaStudioInvoice() { + } + + /** + * Builds the preset. + * + * @return ready-to-use template + */ + public static DocumentTemplate create() { + return new Template(); + } + + private record Template() implements DocumentTemplate { + + @Override + public String id() { + return ID; + } + + @Override + public String displayName() { + return DISPLAY_NAME; + } + + @Override + public void compose(DocumentSession document, StructuredInvoiceDocumentSpec spec) { + Objects.requireNonNull(document, "document"); + StructuredInvoiceData data = Objects.requireNonNull(spec, "spec").invoice(); + String currency = currencyMark(data.currencyCode()); + + renderChrome(document); + + document.pageFlow(page -> { + page.name("LumaStudioInvoice").spacing(0).padding(DocumentInsets.zero()); + + page.add(LumaStudioSidebar.render(data.brand())); + + page.addRow("Masthead", row -> row + .spacing(0) + .gap(0) + .weights(MASTHEAD_LEFT_WEIGHT, MASTHEAD_RIGHT_WEIGHT) + .addSection("SupplierHeader", + section -> LumaStudioMasthead.renderSupplier(section, data.supplier())) + .addSection("InvoiceHeader", + section -> LumaStudioMasthead.renderTitle(section, data.masthead()))); + + page.addLine(LumaStudioMasthead::renderRule); + + // The gap down to the table is this row's bottom margin rather + // than a spacer: a block of its own would take the parties' + // place at a page break and leave the gap stranded. + page.addRow("Parties", row -> row + .spacing(0) + .gap(0) + .weights(PARTIES_LEFT_WEIGHT, 1.0 - PARTIES_LEFT_WEIGHT) + .margin(new DocumentInsets(RULE_TO_PARTIES, 0, PARTIES_TO_TABLE, 0)) + .addSection("BillTo", + section -> LumaStudioMasthead.renderParty(section, data.billTo(), false)) + .addSection("ShipTo", + section -> LumaStudioMasthead.renderParty(section, data.shipTo(), true))); + + LumaStudioLines.render(page, data.serviceLines(), currency); + + page.addSection("Totals", + section -> LumaStudioClosing.renderTotals(section, data.totals(), currency)); + + page.addLine(LumaStudioClosing::renderFooterRule); + + page.addRow("Closing", row -> row + .spacing(0) + .gap(0) + .weights(CLOSING_LEFT_WEIGHT, 1.0 - CLOSING_LEFT_WEIGHT) + .margin(new DocumentInsets(RULE_TO_CLOSING, 0, 0, 0)) + .addSection("Notes", + section -> LumaStudioClosing.renderNotes(section, data.notes())) + .addSection("PaymentDetails", + section -> LumaStudioClosing.renderPayment(section, data.payment()))); + + page.addSection("ClosingBannerBlock", block -> { + block.spacing(0).margin(new DocumentInsets(CLOSING_TO_BANNER, 0, 0, 0)); + LumaStudioClosing.renderBanner(block, data.payment()); + }); + }); + } + + /** + * The page frame: the paper tint, the cream sidebar column and the + * dark foot band are page-ratio background fills, and the folio is + * FOOTER-zone chrome, so all four repeat on every page. + * + *

The bottom margin is the band's height, so the last row on a page + * stops above it rather than running underneath, and the sign-off block + * reaches down into that reserved space by its own negative bottom + * margin rather than pushing the flow onto another page.

+ */ + private static void renderChrome(DocumentSession document) { + document.pageSize(PAGE) + .margin(new DocumentInsets( + PAGE_MARGIN_TOP, PAGE_MARGIN_RIGHT, BANNER_HEIGHT, PAGE_MARGIN_LEFT)) + .pageBackgrounds(List.of( + PageBackgroundFill.fullPage(PAPER), + PageBackgroundFill.leftColumn(SIDEBAR_WIDTH_RATIO, SIDEBAR_SURFACE), + PageBackgroundFill.bottomBand(BANNER_HEIGHT_RATIO, INK_SURFACE))) + .footer(DocumentHeaderFooter.builder() + .zone(DocumentHeaderFooterZone.FOOTER) + .height((float) FOLIO_ZONE_HEIGHT) + .rightText("Page {page} of {pages}") + .fontSize((float) MICRO_SIZE) + .textColor(ON_DARK) + .showSeparator(false) + .build()); + } + + /** + * The mark amounts are written with, for the currency the data states. + * + *

The model carries the ISO code, and this sheet prints a symbol + * against every figure, so the code is the authority and the symbol is + * derived from it — two stated fields could disagree, and then the + * document would contradict itself. A code the platform does not know + * prints as itself rather than as nothing, so an amount is never left + * bare.

+ */ + private static String currencyMark(String currencyCode) { + if (currencyCode.isBlank()) { + return ""; + } + try { + return Currency.getInstance(currencyCode).getSymbol(Locale.ENGLISH); + } catch (IllegalArgumentException unknownCode) { + return currencyCode; + } + } + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioLines.java b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioLines.java new file mode 100644 index 000000000..d1a2fc6d3 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioLines.java @@ -0,0 +1,182 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.document.dsl.PageFlowBuilder; +import com.demcha.compose.document.dsl.SectionBuilder; +import com.demcha.compose.document.dsl.TableBuilder; +import com.demcha.compose.document.node.DocumentNode; +import com.demcha.compose.document.node.TextAlign; +import com.demcha.compose.document.node.TextVerticalAlign; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.style.DocumentStroke; +import com.demcha.compose.document.style.DocumentTextDecoration; +import com.demcha.compose.document.table.DocumentTableCell; +import com.demcha.compose.document.table.DocumentTableColumn; +import com.demcha.compose.document.table.DocumentTableStyle; +import com.demcha.compose.document.table.DocumentTableTextAnchor; +import com.demcha.compose.document.templates.data.invoice.InvoiceServiceLines; + +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BODY; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BODY_BOLD; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.CONTENT_WIDTH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.HAIRLINE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.INK_SURFACE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ITEM_DESC; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ITEM_INDEX; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ITEM_TITLE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.LINE_PITCH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAD_AMOUNT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAD_DESCRIPTION; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAD_HEADER_CENTRE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAD_HEADER_LEFT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAD_HEADER_RIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAD_INDEX; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAD_NUMERIC; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TABLE_HEADER; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TABLE_RATIOS; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TABLE_RULE_THICKNESS; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TRACK_TABLE_HEADER; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.cellStyle; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.headerStyle; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.leading; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.money; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.sans; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioWidgets.tracked; + +/** + * The line-items table: a dark header band, one row per service line, and a + * hairline row between neighbours. + */ +final class LumaStudioLines { + + private LumaStudioLines() { + } + + static void render(PageFlowBuilder page, InvoiceServiceLines serviceLines, + String currencySymbol) { + page.addTable(table -> { + compose(table, serviceLines, currencySymbol); + // The dark header band is the region a continuation page needs: + // without this a second page carries five unlabelled money columns. + table.repeatHeader(); + }); + } + + private static void compose(TableBuilder table, InvoiceServiceLines serviceLines, + String currencySymbol) { + InvoiceServiceLines.Columns columns = serviceLines.columns(); + DocumentTableStyle centred = headerStyle( + DocumentTableTextAnchor.CENTER, PAD_HEADER_CENTRE); + table.name("LineItems") + .columns(column(0), column(1), column(2), column(3), column(4), column(5)) + .headerCells( + headerCell(columns.description(), TextAlign.LEFT) + .withStyle(headerStyle( + DocumentTableTextAnchor.CENTER_LEFT, PAD_HEADER_LEFT)) + .colSpan(2), + headerCell(columns.quantity(), TextAlign.CENTER), + headerCell(columns.unitPrice(), TextAlign.CENTER), + headerCell(columns.vat(), TextAlign.CENTER), + headerCell(columns.amount(), TextAlign.RIGHT) + .withStyle(headerStyle( + DocumentTableTextAnchor.CENTER_RIGHT, PAD_HEADER_RIGHT))) + .headerStyle(centred) + .padding(DocumentInsets.zero()) + .margin(DocumentInsets.zero()); + + for (InvoiceServiceLines.Line line : serviceLines.lines()) { + table.rowCells( + DocumentTableCell.text(String.format("%02d", line.lineNumber())) + .withStyle(cellStyle(ITEM_INDEX, + DocumentTableTextAnchor.CENTER_LEFT, PAD_INDEX)), + DocumentTableCell.node(description(line)) + .withStyle(cellStyle(BODY, + DocumentTableTextAnchor.CENTER_LEFT, PAD_DESCRIPTION)), + DocumentTableCell.text(quantity(line)) + .withStyle(cellStyle(BODY, + DocumentTableTextAnchor.CENTER, PAD_NUMERIC)), + DocumentTableCell.text(money(currencySymbol, line.unitPrice())) + .withStyle(cellStyle(BODY, + DocumentTableTextAnchor.CENTER, PAD_NUMERIC)), + DocumentTableCell.text(line.vatRate()) + .withStyle(cellStyle(BODY, + DocumentTableTextAnchor.CENTER, PAD_NUMERIC)), + DocumentTableCell.text(money(currencySymbol, line.amount())) + .withStyle(cellStyle(BODY_BOLD, + DocumentTableTextAnchor.CENTER_RIGHT, PAD_AMOUNT))); + itemRule(table); + } + } + + private static DocumentTableColumn column(int index) { + return DocumentTableColumn.fixed(CONTENT_WIDTH * TABLE_RATIOS[index]); + } + + /** + * A tracked header cell, written run by run like every other tracked line + * on the sheet — its gaps painted in the band's own dark, not the paper's. + */ + private static DocumentTableCell headerCell(String text, TextAlign align) { + return DocumentTableCell.node(tracked("HeaderCell", text, TABLE_HEADER, + TRACK_TABLE_HEADER, INK_SURFACE, align, TextVerticalAlign.DEFAULT)); + } + + /** + * A line's title over its description, as one node so the index cell has + * a single thing to centre against. + * + *

They are two paragraphs in a block rather than two runs of one + * paragraph: a single paragraph would need an invisible spacer sized to + * the remaining width to break after the title, and there is no + * compose-time text measurement to size one with. The block puts the + * same leading between them and lands in the same place.

+ */ + private static DocumentNode description(InvoiceServiceLines.Line line) { + double gap = leading(LINE_PITCH * 0.83, ITEM_DESC); + SectionBuilder block = new SectionBuilder(); + block.name("ItemDescription").spacing(0) + .padding(DocumentInsets.zero()) + .margin(DocumentInsets.zero()); + block.addParagraph(p -> p + .name("ItemTitle") + .text(line.title()) + .textStyle(ITEM_TITLE) + .align(TextAlign.LEFT) + .lineSpacing(gap) + .margin(DocumentInsets.zero())); + block.addParagraph(p -> p + .name("ItemBody") + .text(line.description()) + .textStyle(ITEM_DESC) + .align(TextAlign.LEFT) + .lineSpacing(gap) + .margin(new DocumentInsets(gap, 0, 0, 0))); + return block.build(); + } + + /** + * How much was delivered, written plainly: a whole number loses its + * decimals, because a sheet that says "1" should not say "1.00". + */ + private static String quantity(InvoiceServiceLines.Line line) { + return line.quantity().stripTrailingZeros().toPlainString(); + } + + /** The hairline under a row, drawn as a row of its own. */ + private static void itemRule(TableBuilder table) { + DocumentTableStyle rule = DocumentTableStyle.builder() + .padding(DocumentInsets.zero()) + .fillColor(HAIRLINE) + .stroke(DocumentStroke.of(HAIRLINE, 0)) + .textStyle(sans(TABLE_RULE_THICKNESS, DocumentTextDecoration.DEFAULT, HAIRLINE)) + .textAnchor(DocumentTableTextAnchor.CENTER) + .lineSpacing(0) + .build(); + table.rowCells( + DocumentTableCell.text("").withStyle(rule), + DocumentTableCell.text("").withStyle(rule), + DocumentTableCell.text("").withStyle(rule), + DocumentTableCell.text("").withStyle(rule), + DocumentTableCell.text("").withStyle(rule), + DocumentTableCell.text("").withStyle(rule)); + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioMasthead.java b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioMasthead.java new file mode 100644 index 000000000..c1dfb32d0 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioMasthead.java @@ -0,0 +1,276 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.document.dsl.LineBuilder; +import com.demcha.compose.document.dsl.SectionBuilder; +import com.demcha.compose.document.node.LayerAlign; +import com.demcha.compose.document.node.TextAlign; +import com.demcha.compose.document.node.TextVerticalAlign; +import com.demcha.compose.document.style.ClipPolicy; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.templates.data.invoice.InvoiceContactBlock; +import com.demcha.compose.document.templates.data.invoice.InvoiceMasthead; +import com.demcha.compose.document.templates.data.invoice.InvoiceRecipient; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ACCENT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.BODY; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.CONTACT_ICON_SIZE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.CONTACT_ROW_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.CONTACT_TEXT_OFFSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.HAIRLINE_QUIET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.INVOICE_TITLE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.LINE_PITCH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.META_LABEL; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.META_ROW_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.META_VALUE_SPLIT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.META_WIDTH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.MASTHEAD_TO_RULE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.MICRO_MUTED; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAPER; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PARTIES_DIVIDER_INSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.RULE_THICKNESS; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SECTION_HEADING; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SUPPLIER_NAME; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SUPPLIER_WIDTH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TEXT_INSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TEXT_WIDTH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TITLE_BLOCK_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TITLE_CAP_INSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TITLE_RULE_THICKNESS; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TITLE_RULE_TO_METADATA; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TITLE_RULE_WIDTH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TRACK_META_LABEL; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TRACK_SECTION_HEADING; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TRACK_TITLE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.leading; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioWidgets.linkedParagraph; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioWidgets.paragraph; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioWidgets.tracked; + +/** + * The top of the sheet: the sender's block on the left, the title and its + * metadata on the right, and the two party blocks below the rule. + */ +final class LumaStudioMasthead { + + /** The break this sheet stacks address lines on. */ + private static final String NEWLINE = String.valueOf((char) 10); + + /** A parenthesised trunk prefix, which an international dial target drops. */ + private static final Pattern TRUNK_PREFIX = Pattern.compile("\\(0+\\)"); + + private LumaStudioMasthead() { + } + + // -- supplier -------------------------------------------------------- + + /** + * The sender: the legal name, the address, the contact rows behind their + * marks, and the registration line. + * + *

The channels carry {@code tel:} and {@code mailto:} targets built + * from the values, and the website its own {@code https:} — so a reader + * can act on them and the document does not carry each address twice.

+ */ + static void renderSupplier(SectionBuilder section, InvoiceContactBlock supplier) { + section.name("SupplierHeader") + .spacing(0) + .padding(new DocumentInsets(0, 0, 0, TEXT_INSET)); + section.addParagraph(p -> p + .name("SupplierName") + .text(supplier.legalName()) + .textStyle(SUPPLIER_NAME) + .lineSpacing(0) + .margin(DocumentInsets.zero())); + section.addParagraph(p -> p + .name("SupplierAddress") + .text(String.join(NEWLINE, supplier.addressLines())) + .textStyle(BODY) + .lineSpacing(leading(LINE_PITCH, BODY)) + .margin(new DocumentInsets(LINE_PITCH * 0.50, 0, 0, 0))); + + SectionBuilder contacts = new SectionBuilder() + .name("ContactRows") + .spacing(0) + .margin(new DocumentInsets(LINE_PITCH * 0.79, 0, 0, 0)); + contactRow(contacts, LumaStudioIcons.PHONE, supplier.phone(), + telUri(supplier.phone())); + contactRow(contacts, LumaStudioIcons.EMAIL, supplier.email(), + supplier.email().isBlank() ? null : "mailto:" + supplier.email()); + contactRow(contacts, LumaStudioIcons.WEBSITE, supplier.website(), + webUri(supplier.website())); + section.add(contacts.build()); + + section.addParagraph(p -> p + .name("Registration") + .text(registrationLine(supplier)) + .textStyle(MICRO_MUTED) + .lineSpacing(0) + .margin(new DocumentInsets(LINE_PITCH * 0.84, 0, 0, 0))); + } + + private static void contactRow(SectionBuilder section, String iconToken, + String value, String href) { + section.addContainer(container -> container + .name("ContactRow") + .rectangle(SUPPLIER_WIDTH, CONTACT_ROW_HEIGHT) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE) + .centerLeft(LumaStudioIcons.icon(iconToken, CONTACT_ICON_SIZE)) + .position(linkedParagraph(value, href, BODY), CONTACT_TEXT_OFFSET, 0, + LayerAlign.CENTER_LEFT)); + } + + /** + * The registration line: one labelled number, or both behind a pale pipe + * when the sender carries a tax registration as well. + */ + private static String registrationLine(InvoiceContactBlock supplier) { + String first = pair(supplier.registrationLabel(), supplier.registrationNumber()); + String second = pair(supplier.taxRegistrationLabel(), supplier.taxRegistrationNumber()); + if (first.isBlank()) { + return second; + } + return second.isBlank() ? first : first + " | " + second; + } + + private static String pair(String label, String value) { + if (label.isBlank() && value.isBlank()) { + return ""; + } + return label.isBlank() ? value : label + " " + value; + } + + /** + * The dial target for a phone number: its digits, keeping a leading + * {@code +} so an international number stays international. + * + *

A parenthesised trunk prefix — the {@code (0)} in + * {@code +44 (0)20 7946 0832} — is the digit a caller drops when dialling + * from abroad, so it is dropped here too. A parenthesised area code is + * not, which is why only an all-zero group goes.

+ */ + private static String telUri(String phone) { + String dialled = TRUNK_PREFIX.matcher(phone).replaceAll(""); + String digits = dialled.replaceAll("[^0-9]", ""); + return digits.isEmpty() + ? null + : "tel:" + (phone.trim().startsWith("+") ? "+" : "") + digits; + } + + /** A website target: what the document wrote, given a scheme if it has none. */ + private static String webUri(String website) { + if (website.isBlank()) { + return null; + } + return website.startsWith("http") ? website : "https://" + website; + } + + // -- title and metadata ---------------------------------------------- + + /** + * The document title over its accent rule, and the metadata rows beneath. + * + *

The title and the rule share a band so the rule sits at the block's + * foot whatever the title measures: the title is seated to the top of the + * band and the rule anchored to its bottom.

+ */ + static void renderTitle(SectionBuilder section, InvoiceMasthead masthead) { + section.name("InvoiceHeader").spacing(0); + section.addContainer(container -> container + .name("InvoiceTitleBlock") + .rectangle(META_WIDTH, TITLE_BLOCK_HEIGHT) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE) + .position(tracked("InvoiceTitle", masthead.title(), INVOICE_TITLE, + TRACK_TITLE, PAPER, TextVerticalAlign.TOP), + 0, TITLE_CAP_INSET, LayerAlign.TOP_LEFT) + .position(new LineBuilder() + .name("TitleRule") + .horizontal(TITLE_RULE_WIDTH) + .thickness(TITLE_RULE_THICKNESS) + .color(ACCENT) + .margin(DocumentInsets.zero()) + .build(), + 0, 0, LayerAlign.BOTTOM_LEFT) + .margin(new DocumentInsets(0, 0, TITLE_RULE_TO_METADATA, 0))); + for (InvoiceMasthead.Entry entry : masthead.entries()) { + section.addContainer(container -> container + .name("MetadataRow") + .rectangle(META_WIDTH, META_ROW_HEIGHT) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE) + .centerLeft(tracked("MetaLabel", entry.label(), META_LABEL, + TRACK_META_LABEL, PAPER)) + .position(paragraph(entry.value(), BODY, TextAlign.LEFT), + META_WIDTH * META_VALUE_SPLIT, 0, LayerAlign.CENTER_LEFT)); + } + } + + // -- the rule between the masthead and the parties --------------------- + + /** + * The masthead rule, which stops at the text column rather than running + * to the table's edge — the only rule on the sheet that does. + * + * @param line the rule to draw + */ + static void renderRule(LineBuilder line) { + line.name("HeaderRule") + .horizontal(TEXT_WIDTH) + .thickness(RULE_THICKNESS) + .color(HAIRLINE_QUIET) + .margin(new DocumentInsets(MASTHEAD_TO_RULE, 0, 0, TEXT_INSET)); + } + + // -- parties --------------------------------------------------------- + + /** + * One party block: the tracked heading over its address. + * + * @param section the host column + * @param party the recipient to draw + * @param divided true for the right-hand block, which carries the + * hairline between the two as its own left border + */ + static void renderParty(SectionBuilder section, InvoiceRecipient party, boolean divided) { + // Named after the heading it draws, so the two columns are told apart + // in a layout snapshot; a party that states no heading still needs a + // name, so it falls back to its role. + String heading = party.heading(); + section.name(heading.isBlank() + ? (divided ? "ShipTo" : "BillTo") + : heading.replace(" ", "")).spacing(0); + if (divided) { + section.accentLeft(HAIRLINE_QUIET, RULE_THICKNESS) + .padding(new DocumentInsets(0, 0, 0, PARTIES_DIVIDER_INSET)); + } else { + section.padding(new DocumentInsets(0, 0, 0, TEXT_INSET)); + } + section.add(tracked("PartyHeading", heading, SECTION_HEADING, + TRACK_SECTION_HEADING, PAPER)) + .addParagraph(p -> p + .name("PartyAddress") + .text(String.join(NEWLINE, addressOf(party))) + .textStyle(BODY) + .lineSpacing(leading(LINE_PITCH * 1.183, BODY)) + .margin(new DocumentInsets(LINE_PITCH * 0.72, 0, 0, 0))); + } + + /** + * The lines a party is drawn as: the name, the subline when it carries + * one, then the address. This design sets them as one block, so a + * recipient that names an attention line gets it on the second line. + */ + private static List addressOf(InvoiceRecipient party) { + List lines = new ArrayList<>(); + if (!party.name().isBlank()) { + lines.add(party.name()); + } + if (!party.subline().isBlank()) { + lines.add(party.subline()); + } + lines.addAll(party.addressLines()); + return lines; + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioSidebar.java b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioSidebar.java new file mode 100644 index 000000000..4d3d39b2b --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioSidebar.java @@ -0,0 +1,170 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.document.dsl.EllipseBuilder; +import com.demcha.compose.document.dsl.LineBuilder; +import com.demcha.compose.document.dsl.ParagraphBuilder; +import com.demcha.compose.document.dsl.ShapeBuilder; +import com.demcha.compose.document.dsl.ShapeContainerBuilder; +import com.demcha.compose.document.node.DocumentNode; +import com.demcha.compose.document.node.LayerAlign; +import com.demcha.compose.document.node.TextAlign; +import com.demcha.compose.document.node.TextVerticalAlign; +import com.demcha.compose.document.style.ClipPolicy; +import com.demcha.compose.document.style.DocumentCornerRadius; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.style.DocumentTextStyle; +import com.demcha.compose.document.templates.data.invoice.InvoiceBrand; + +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ACCENT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.LOCKUP_LEFT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.LOCKUP_RULE_THICKNESS; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.LOCKUP_RULE_WIDTH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.LOCKUP_RULE_Y; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.MONOGRAM_BOTTOM; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.MONOGRAM_BOTTOM_Y; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.MONOGRAM_TOP; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.MONOGRAM_TOP_Y; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ON_ACCENT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ORNAMENT_ARCH_HEIGHT_RATIO; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ORNAMENT_ARCH_LEFT_RATIO; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ORNAMENT_ARCH_WIDTH_RATIO; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ORNAMENT_DISC_LEFT_RATIO; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ORNAMENT_DISC_RATIO; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ORNAMENT_DISC_TOP_FACTOR; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ORNAMENT_SPRIG_LEFT_RATIO; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ORNAMENT_SPRIG_TOP_RATIO; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ORNAMENT_SPRIG_WIDTH_RATIO; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ORNAMENT_TINT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAGE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAGE_MARGIN_LEFT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAGE_MARGIN_TOP; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SIDEBAR_BRAND_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SIDEBAR_STUB_HEIGHT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SIDEBAR_WIDTH; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TAGLINE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TAGLINE_Y; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TRACK_WORDMARK; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.WORDMARK; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.WORDMARK_Y; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioWidgets.tracked; + +/** + * The sidebar: one node with one negative margin. + * + *

The body flow's left margin excludes the column, so the lockup and the + * ornament are composed into a single overflowing stub pulled back over the + * margin — both of its offsets are the page margins themselves. The + * terracotta brand block is content rather than a page background, painted + * above the ornament in the stub's z-order, because the ornament's disc is a + * circle far larger than the column and the block has to cover its top.

+ */ +final class LumaStudioSidebar { + + private LumaStudioSidebar() { + } + + static DocumentNode render(InvoiceBrand brand) { + return new ShapeContainerBuilder() + .name("Sidebar") + .rectangle(SIDEBAR_WIDTH, SIDEBAR_STUB_HEIGHT) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE) + .margin(new DocumentInsets( + -PAGE_MARGIN_TOP, 0, PAGE_MARGIN_TOP - SIDEBAR_STUB_HEIGHT, + -PAGE_MARGIN_LEFT)) + .position(ornament(), 0, SIDEBAR_BRAND_HEIGHT, LayerAlign.TOP_LEFT, 0) + .position(brandBlock(), 0, 0, LayerAlign.TOP_LEFT, 1) + .position(lockup(brand), 0, 0, LayerAlign.TOP_LEFT, 2) + .build(); + } + + private static DocumentNode brandBlock() { + return new ShapeBuilder() + .name("BrandBlock") + .size(SIDEBAR_WIDTH, SIDEBAR_BRAND_HEIGHT) + .fillColor(ACCENT) + .margin(DocumentInsets.zero()) + .build(); + } + + /** + * The lockup: the two monogram lines, a short rule, the tracked wordmark + * and the tagline, each seated at its own measured height. + */ + private static DocumentNode lockup(InvoiceBrand brand) { + return new ShapeContainerBuilder() + .name("BrandLockup") + .rectangle(SIDEBAR_WIDTH, SIDEBAR_BRAND_HEIGHT) + .clipPolicy(ClipPolicy.CLIP_PATH) + .position(seated(brand.monogramTop(), MONOGRAM_TOP), + LOCKUP_LEFT, MONOGRAM_TOP_Y, LayerAlign.TOP_LEFT) + .position(seated(brand.monogramBottom(), MONOGRAM_BOTTOM), + LOCKUP_LEFT, MONOGRAM_BOTTOM_Y, LayerAlign.TOP_LEFT) + .position(new LineBuilder() + .name("LockupRule") + .horizontal(LOCKUP_RULE_WIDTH) + .thickness(LOCKUP_RULE_THICKNESS) + .color(ON_ACCENT) + .margin(DocumentInsets.zero()) + .build(), + LOCKUP_LEFT, LOCKUP_RULE_Y, LayerAlign.TOP_LEFT) + .position(tracked("Wordmark", brand.name(), WORDMARK, + TRACK_WORDMARK, ACCENT, TextVerticalAlign.TOP), + LOCKUP_LEFT, WORDMARK_Y, LayerAlign.TOP_LEFT) + .position(seated(brand.tagline(), TAGLINE), + LOCKUP_LEFT, TAGLINE_Y, LayerAlign.TOP_LEFT) + .build(); + } + + private static DocumentNode seated(String text, DocumentTextStyle style) { + return new ParagraphBuilder() + .text(text) + .textStyle(style) + .align(TextAlign.LEFT) + .verticalAlign(TextVerticalAlign.TOP) + .lineSpacing(0) + .margin(DocumentInsets.zero()) + .build(); + } + + /** + * The art below the brand block: a tinted quarter-disc, an arch at the + * foot, and the sprig between them. + * + *

The container clips to its bounds rather than to its path: the disc + * is a circle far wider than the column, and a rectangular container's + * path clip does not cut its positioned layers.

+ */ + private static DocumentNode ornament() { + double columnHeight = PAGE.height() - SIDEBAR_BRAND_HEIGHT; + double discDiameter = PAGE.width() * ORNAMENT_DISC_RATIO; + double archWidth = PAGE.width() * ORNAMENT_ARCH_WIDTH_RATIO; + + DocumentNode disc = new EllipseBuilder() + .name("OrnamentDisc") + .circle(discDiameter) + .fillColor(ORNAMENT_TINT) + .margin(DocumentInsets.zero()) + .build(); + DocumentNode arch = new ShapeBuilder() + .name("OrnamentArch") + .size(archWidth, PAGE.height() * ORNAMENT_ARCH_HEIGHT_RATIO) + .cornerRadius(DocumentCornerRadius.top(archWidth / 2.0)) + .fillColor(ACCENT) + .margin(DocumentInsets.zero()) + .build(); + + return new ShapeContainerBuilder() + .name("SidebarOrnament") + .rectangle(SIDEBAR_WIDTH, columnHeight) + .clipPolicy(ClipPolicy.CLIP_BOUNDS) + .position(disc, PAGE.width() * ORNAMENT_DISC_LEFT_RATIO, + discDiameter * ORNAMENT_DISC_TOP_FACTOR, LayerAlign.TOP_LEFT) + .position(arch, PAGE.width() * ORNAMENT_ARCH_LEFT_RATIO, 0, + LayerAlign.BOTTOM_LEFT) + .position(LumaStudioIcons.icon(LumaStudioIcons.SPRIG, + PAGE.width() * ORNAMENT_SPRIG_WIDTH_RATIO), + PAGE.width() * ORNAMENT_SPRIG_LEFT_RATIO, + PAGE.height() * ORNAMENT_SPRIG_TOP_RATIO, LayerAlign.TOP_LEFT) + .build(); + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioStyles.java b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioStyles.java new file mode 100644 index 000000000..bbc203b99 --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioStyles.java @@ -0,0 +1,356 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.document.api.DocumentPageSize; +import com.demcha.compose.document.style.DocumentColor; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.style.DocumentStroke; +import com.demcha.compose.document.style.DocumentTextDecoration; +import com.demcha.compose.document.style.DocumentTextStyle; +import com.demcha.compose.document.table.DocumentTableStyle; +import com.demcha.compose.document.table.DocumentTableTextAnchor; +import com.demcha.compose.document.templates.core.text.TextStyles; +import com.demcha.compose.font.FontName; + +import java.math.BigDecimal; +import java.text.NumberFormat; +import java.util.Locale; + +/** + * The measured geometry, palette and type scale of the Luma Studio invoice. + * + *

Two left edges, and that is deliberate

+ * + *

The body text column starts further in than the line-item table, the two + * rules that bracket the closing block and the notes disc. The table's own + * first-cell padding brings its text back onto the text edge, so the text runs + * straight down the page while the table and its rules sit one cell padding + * wider. {@link #PAGE_MARGIN_LEFT} is therefore the table's edge, and + * every text block carries {@link #TEXT_INSET} as its left padding — one + * property per block rather than an inset restated on every paragraph.

+ * + *

Leading is authored as a pitch

+ * + *

{@link #leading} takes the distance the design draws between line tops + * and subtracts the line box the type already fills. The ratio is per family, + * because the three faces here set different line boxes at the same size — + * one shared constant would be wrong by a line per block on two of them.

+ */ +final class LumaStudioStyles { + + private LumaStudioStyles() { + } + + // -- page ------------------------------------------------------------ + + static final DocumentPageSize PAGE = DocumentPageSize.A4; + + static final double SIDEBAR_WIDTH_RATIO = 0.2218; + static final double SIDEBAR_WIDTH = PAGE.width() * SIDEBAR_WIDTH_RATIO; + static final double SIDEBAR_BRAND_HEIGHT_RATIO = 0.24614; + static final double SIDEBAR_BRAND_HEIGHT = PAGE.height() * SIDEBAR_BRAND_HEIGHT_RATIO; + + static final double PAGE_MARGIN_LEFT = PAGE.width() * 0.25782; + static final double PAGE_MARGIN_RIGHT = PAGE.width() * 0.0654; + static final double PAGE_MARGIN_TOP = 46.3; + static final double CONTENT_WIDTH = PAGE.width() - PAGE_MARGIN_LEFT - PAGE_MARGIN_RIGHT; + static final double TEXT_INSET = PAGE.width() * 0.01232; + static final double TEXT_WIDTH = CONTENT_WIDTH - TEXT_INSET; + + /** The stub the sidebar is drawn from: it carries art, not height. */ + static final double SIDEBAR_STUB_HEIGHT = 0.4; + static final double BANNER_FLOW_HEIGHT = 0.3; + static final double BANNER_HEIGHT_RATIO = 0.07445; + static final double BANNER_HEIGHT = PAGE.height() * BANNER_HEIGHT_RATIO; + static final double FOLIO_ZONE_HEIGHT = 30.5; + + // -- block rhythm ---------------------------------------------------- + + static final double MASTHEAD_TO_RULE = 13.0; + static final double RULE_TO_PARTIES = 12.0; + static final double PARTIES_TO_TABLE = 12.9; + static final double TABLE_TO_TOTALS = 4.4; + static final double TOTALS_TO_RULE = 2.0; + static final double RULE_TO_CLOSING = 12.0; + static final double CLOSING_TO_BANNER = 8.6; + + // -- the column grid ------------------------------------------------- + + static final double MASTHEAD_LEFT_WEIGHT = 0.5868; + static final double MASTHEAD_RIGHT_WEIGHT = 1.0 - MASTHEAD_LEFT_WEIGHT; + static final double SUPPLIER_WIDTH = CONTENT_WIDTH * MASTHEAD_LEFT_WEIGHT - TEXT_INSET; + static final double META_WIDTH = CONTENT_WIDTH * MASTHEAD_RIGHT_WEIGHT; + static final double PARTIES_LEFT_WEIGHT = 0.4748; + static final double CLOSING_LEFT_WEIGHT = 0.4146; + static final double[] TABLE_RATIOS = {0.0630, 0.3124, 0.0980, 0.2395, 0.0742, 0.2129}; + static final double TOTALS_WIDTH = CONTENT_WIDTH * 0.6204; + + // -- type ------------------------------------------------------------ + + static final FontName SANS = FontName.CARLITO; + static final FontName DISPLAY_SERIF = FontName.SPECTRAL; + static final FontName TEXT_SERIF = FontName.TINOS; + + static final double BODY_SIZE = 9.4; + static final double LINE_PITCH = 12.42; + static final double SMALL_SIZE = BODY_SIZE * 0.851; + static final double MICRO_SIZE = BODY_SIZE * 0.766; + static final double SUPPLIER_NAME_SIZE = BODY_SIZE * 1.170; + static final double TITLE_SIZE = BODY_SIZE * 3.883; + static final double TOTAL_DUE_SIZE = BODY_SIZE * 1.968; + static final double MONOGRAM_TOP_SIZE = BODY_SIZE * 6.170; + static final double MONOGRAM_BOTTOM_SIZE = BODY_SIZE * 3.300; + static final double WORDMARK_SIZE = BODY_SIZE * 0.830; + static final double TAGLINE_SIZE = BODY_SIZE * 0.773; + + // -- band heights ---------------------------------------------------- + + static final double CONTACT_ROW_HEIGHT = LINE_PITCH * 1.159; + static final double META_ROW_HEIGHT = LINE_PITCH * 1.409; + static final double TOTALS_ROW_HEIGHT = LINE_PITCH * 1.458; + static final double TOTAL_DUE_HEIGHT = LINE_PITCH * 2.182; + static final double BANK_ROW_HEIGHT = LINE_PITCH * 0.821; + + // -- ornaments and offsets ------------------------------------------- + + static final double CONTACT_ICON_SIZE = 8.6; + static final double CONTACT_TEXT_OFFSET = 21.0; + static final double META_VALUE_SPLIT = 0.6134; + static final double SECTION_DISC_SIZE = 24.8; + static final double SECTION_DISC_ICON_SIZE = 12.0; + static final double SECTION_HEADING_OFFSET = 35.5; + static final double BANK_PIPE_OFFSET = 53.6; + static final double BANK_VALUE_OFFSET = 63.8; + static final double PARTIES_DIVIDER_INSET = 34.4; + static final double CLOSING_DIVIDER_INSET = 24.3; + static final double TITLE_RULE_WIDTH = 58.7; + static final double TITLE_RULE_THICKNESS = 1.7; + static final double TITLE_BLOCK_HEIGHT = 45.7; + static final double TITLE_CAP_INSET = 3.4; + static final double TITLE_RULE_TO_METADATA = 15.3; + static final double TOTALS_LABEL_INSET = 41.8; + static final double TOTALS_AMOUNT_INSET = 13.0; + static final double RULE_THICKNESS = 0.56; + static final double TABLE_RULE_THICKNESS = 0.62; + + static final double LOCKUP_LEFT = PAGE.width() * 0.05592; + static final double LOCKUP_RULE_WIDTH = PAGE.width() * 0.03412; + static final double LOCKUP_RULE_THICKNESS = 1.7; + static final double MONOGRAM_TOP_Y = PAGE.height() * 0.04561; + static final double MONOGRAM_BOTTOM_Y = PAGE.height() * 0.10597; + static final double LOCKUP_RULE_Y = PAGE.height() * 0.16097; + static final double WORDMARK_Y = PAGE.height() * 0.18645; + static final double TAGLINE_Y = PAGE.height() * 0.20456; + + static final double ORNAMENT_DISC_RATIO = 0.34502; + static final double ORNAMENT_DISC_LEFT_RATIO = 0.02938; + static final double ORNAMENT_DISC_TOP_FACTOR = -0.48; + static final double ORNAMENT_ARCH_WIDTH_RATIO = 0.19526; + static final double ORNAMENT_ARCH_HEIGHT_RATIO = 0.28102; + static final double ORNAMENT_ARCH_LEFT_RATIO = 0.02654; + static final double ORNAMENT_SPRIG_WIDTH_RATIO = 0.16000; + static final double ORNAMENT_SPRIG_LEFT_RATIO = 0.02180; + static final double ORNAMENT_SPRIG_TOP_RATIO = 0.30500; + + static final double BANNER_CONTENT_INSET = PAGE.width() * 0.05498; + static final double BANNER_DISC_SIZE = 33.9; + static final double BANNER_DISC_ICON_SIZE = 16.0; + static final double BANNER_TEXT_OFFSET = 47.9; + + // -- table padding --------------------------------------------------- + + static final double TABLE_CELL_PAD_X = 7.33; + static final double TABLE_CELL_PAD_Y = 9.3; + static final double TABLE_HEADER_PAD_Y = 7.2; + static final double TABLE_TIGHT_PAD_X = 2.0; + static final double TABLE_AMOUNT_PAD_RIGHT = 15.2; + + static final DocumentInsets PAD_INDEX = new DocumentInsets( + TABLE_CELL_PAD_Y, TABLE_TIGHT_PAD_X, TABLE_CELL_PAD_Y, TABLE_CELL_PAD_X); + static final DocumentInsets PAD_DESCRIPTION = new DocumentInsets( + TABLE_CELL_PAD_Y, TABLE_TIGHT_PAD_X, TABLE_CELL_PAD_Y, TABLE_CELL_PAD_X * 0.93); + static final DocumentInsets PAD_NUMERIC = DocumentInsets.symmetric( + TABLE_CELL_PAD_Y, TABLE_TIGHT_PAD_X); + static final DocumentInsets PAD_AMOUNT = new DocumentInsets( + TABLE_CELL_PAD_Y, TABLE_AMOUNT_PAD_RIGHT, TABLE_CELL_PAD_Y, TABLE_TIGHT_PAD_X); + static final DocumentInsets PAD_HEADER_LEFT = new DocumentInsets( + TABLE_HEADER_PAD_Y, TABLE_TIGHT_PAD_X, TABLE_HEADER_PAD_Y, TABLE_CELL_PAD_X); + static final DocumentInsets PAD_HEADER_CENTRE = DocumentInsets.symmetric( + TABLE_HEADER_PAD_Y, TABLE_TIGHT_PAD_X); + static final DocumentInsets PAD_HEADER_RIGHT = new DocumentInsets( + TABLE_HEADER_PAD_Y, TABLE_AMOUNT_PAD_RIGHT, TABLE_HEADER_PAD_Y, TABLE_TIGHT_PAD_X); + + // -- palette --------------------------------------------------------- + + static final DocumentColor ACCENT = DocumentColor.rgb(163, 78, 51); + static final DocumentColor INK_SURFACE = DocumentColor.rgb(46, 46, 46); + static final DocumentColor INK = DocumentColor.rgb(51, 51, 51); + static final DocumentColor MUTED = DocumentColor.rgb(90, 87, 80); + static final DocumentColor SIDEBAR_SURFACE = DocumentColor.rgb(243, 236, 224); + static final DocumentColor ORNAMENT_TINT = DocumentColor.rgb(219, 199, 182); + static final DocumentColor PAPER = DocumentColor.rgb(251, 250, 249); + static final DocumentColor PANEL_HIGHLIGHT = DocumentColor.rgb(232, 222, 213); + static final DocumentColor HAIRLINE = DocumentColor.rgb(221, 212, 202); + static final DocumentColor HAIRLINE_QUIET = DocumentColor.rgb(211, 202, 189); + static final DocumentColor ON_DARK = DocumentColor.WHITE; + static final DocumentColor ON_ACCENT = DocumentColor.rgb(247, 240, 231); + + // -- text styles ----------------------------------------------------- + + static final DocumentTextStyle BODY = sans(BODY_SIZE, DocumentTextDecoration.DEFAULT, INK); + static final DocumentTextStyle BODY_BOLD = sans(BODY_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle SMALL_BOLD = + sans(SMALL_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle MICRO_MUTED = + sans(MICRO_SIZE, DocumentTextDecoration.DEFAULT, MUTED); + static final DocumentTextStyle SUPPLIER_NAME = + sans(SUPPLIER_NAME_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle META_LABEL = + sans(SMALL_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle SECTION_HEADING = + sans(SMALL_SIZE, DocumentTextDecoration.BOLD, ACCENT); + static final DocumentTextStyle TABLE_HEADER = + sans(SMALL_SIZE, DocumentTextDecoration.BOLD, ON_DARK); + static final DocumentTextStyle ITEM_INDEX = + sans(BODY_SIZE * 1.15, DocumentTextDecoration.DEFAULT, ACCENT); + static final DocumentTextStyle ITEM_TITLE = + sans(BODY_SIZE * 0.875, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle ITEM_DESC = + serif(BODY_SIZE * 0.780, DocumentTextDecoration.ITALIC, MUTED); + static final DocumentTextStyle TOTAL_LABEL = + sans(BODY_SIZE * 1.02, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle TOTAL_AMOUNT = + sans(BODY_SIZE * 1.02, DocumentTextDecoration.DEFAULT, INK); + static final DocumentTextStyle TOTAL_DUE_LABEL = + sans(BODY_SIZE * 1.09, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle TOTAL_DUE_AMOUNT = + sans(TOTAL_DUE_SIZE, DocumentTextDecoration.BOLD, ACCENT); + static final DocumentTextStyle NOTE_TEXT = + serif(BODY_SIZE * 0.766, DocumentTextDecoration.ITALIC, INK); + static final DocumentTextStyle BANK_LABEL = + sans(MICRO_SIZE, DocumentTextDecoration.BOLD, INK); + static final DocumentTextStyle BANK_VALUE = + sans(MICRO_SIZE, DocumentTextDecoration.DEFAULT, MUTED); + static final DocumentTextStyle INVOICE_TITLE = + display(TITLE_SIZE, DocumentTextDecoration.DEFAULT, INK_SURFACE); + static final DocumentTextStyle MONOGRAM_TOP = + display(MONOGRAM_TOP_SIZE, DocumentTextDecoration.DEFAULT, ON_ACCENT); + static final DocumentTextStyle MONOGRAM_BOTTOM = + display(MONOGRAM_BOTTOM_SIZE, DocumentTextDecoration.DEFAULT, ON_ACCENT); + static final DocumentTextStyle WORDMARK = + sans(WORDMARK_SIZE, DocumentTextDecoration.BOLD, ON_ACCENT); + static final DocumentTextStyle TAGLINE = + serif(TAGLINE_SIZE, DocumentTextDecoration.ITALIC, ON_ACCENT); + static final DocumentTextStyle BANNER_SIGN_OFF = + sans(BODY_SIZE * 1.02, DocumentTextDecoration.BOLD, ON_DARK); + static final DocumentTextStyle BANNER_DUE = + serif(BODY_SIZE * 1.09, DocumentTextDecoration.ITALIC, ON_DARK); + + // -- tracking -------------------------------------------------------- + + /** + * The letter-spacing each tracked run is set with, in points. + * + *

A text style carries no tracking, so a tracked run is written letter + * by letter with an invisible inline rectangle between the pairs, and + * these are its widths. They are frozen constants rather than a + * measurement: the design derived each by measuring the face and dividing + * the difference from a target width across the gaps, which would tie the + * preset to the font artifact's own resource layout at compose time. The + * numbers are what that measurement produced, and the pixel-parity gate + * is what proves they are still the right ones.

+ */ + static final double TRACK_TITLE = 0.059021; + static final double TRACK_META_LABEL = 1.462532; + static final double TRACK_SECTION_HEADING = 1.462576; + static final double TRACK_TABLE_HEADER = 1.525822; + static final double TRACK_TOTAL_LABEL = 0.612126; + static final double TRACK_WORDMARK = 0.990497; + + // -- helpers --------------------------------------------------------- + + static DocumentTextStyle sans(double size, DocumentTextDecoration decoration, + DocumentColor color) { + return TextStyles.of(SANS, size, decoration, color); + } + + static DocumentTextStyle display(double size, DocumentTextDecoration decoration, + DocumentColor color) { + return TextStyles.of(DISPLAY_SERIF, size, decoration, color); + } + + static DocumentTextStyle serif(double size, DocumentTextDecoration decoration, + DocumentColor color) { + return TextStyles.of(TEXT_SERIF, size, decoration, color); + } + + /** + * The leading to author so lines land on a given pitch. + * + * @param targetPitch the distance the design draws between line tops + * @param style the style of the lines + * @return the extra leading, never negative + */ + static double leading(double targetPitch, DocumentTextStyle style) { + return Math.max(0, targetPitch - style.size() * lineBoxRatio(style.fontName())); + } + + /** + * How tall a line box is as a share of its type size, per family. The + * three faces differ enough that one shared ratio would be wrong by a + * line per block on two of them. + */ + private static double lineBoxRatio(FontName fontName) { + if (fontName.sameFamily(DISPLAY_SERIF)) { + return 1.522; + } + if (fontName.sameFamily(TEXT_SERIF)) { + return 1.150; + } + return 1.221; + } + + static DocumentTableStyle cellStyle(DocumentTextStyle textStyle, + DocumentTableTextAnchor anchor, + DocumentInsets padding) { + return DocumentTableStyle.builder() + .padding(padding) + .fillColor(PAPER) + .stroke(DocumentStroke.of(PAPER, 0)) + .textStyle(textStyle) + .textAnchor(anchor) + .lineSpacing(0) + .build(); + } + + static DocumentTableStyle headerStyle(DocumentTableTextAnchor anchor, + DocumentInsets padding) { + return DocumentTableStyle.builder() + .padding(padding) + .fillColor(INK_SURFACE) + .stroke(DocumentStroke.of(INK_SURFACE, 0)) + .textStyle(TABLE_HEADER) + .textAnchor(anchor) + .lineSpacing(0) + .build(); + } + + /** + * A figure written the way this sheet writes money: the currency mark, + * then grouped digits to two places. + * + *

The formatter is built per call rather than shared: {@link NumberFormat} + * is not thread-safe, and a document is cheap to format beside a static + * monitor every render on every thread would queue behind.

+ * + * @param currencySymbol the mark to prefix + * @param value the figure + * @return the formatted amount + */ + static String money(String currencySymbol, BigDecimal value) { + NumberFormat format = NumberFormat.getNumberInstance(Locale.ENGLISH); + format.setGroupingUsed(true); + format.setMinimumFractionDigits(2); + format.setMaximumFractionDigits(2); + return currencySymbol + format.format(value); + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioWidgets.java b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioWidgets.java new file mode 100644 index 000000000..ce754986a --- /dev/null +++ b/templates/src/main/java/com/demcha/compose/document/templates/invoice/presets/LumaStudioWidgets.java @@ -0,0 +1,172 @@ +package com.demcha.compose.document.templates.invoice.presets; + +import com.demcha.compose.document.dsl.EllipseBuilder; +import com.demcha.compose.document.dsl.LayerStackBuilder; +import com.demcha.compose.document.dsl.ParagraphBuilder; +import com.demcha.compose.document.dsl.SectionBuilder; +import com.demcha.compose.document.node.DocumentLinkOptions; +import com.demcha.compose.document.node.DocumentNode; +import com.demcha.compose.document.node.LayerAlign; +import com.demcha.compose.document.node.TextAlign; +import com.demcha.compose.document.node.TextVerticalAlign; +import com.demcha.compose.document.style.ClipPolicy; +import com.demcha.compose.document.style.DocumentColor; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.style.DocumentTextStyle; +import com.demcha.compose.document.style.ShapeOutline; + +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.ACCENT; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.PAPER; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SECTION_DISC_ICON_SIZE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SECTION_DISC_SIZE; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SECTION_HEADING; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.SECTION_HEADING_OFFSET; +import static com.demcha.compose.document.templates.invoice.presets.LumaStudioStyles.TRACK_SECTION_HEADING; + +/** + * The idioms this sheet repeats: the tracked run, the mark on its accent + * disc, the plain node-shaped paragraph, and the heading that pairs the two. + */ +final class LumaStudioWidgets { + + private LumaStudioWidgets() { + } + + /** + * A run of letter-spaced text. + * + *

A text style carries no tracking, so the gap between letters is an + * inline rectangle of the ground colour — invisible, and exactly as wide + * as the spacing asks for. The rectangle is 0.05pt tall so it takes no + * part in the line box.

+ * + * @param name the node name + * @param text the text to space out + * @param style the style of the letters + * @param tracking the gap in points; zero or less writes the text plainly + * @param ground the colour behind the run, which the gaps are painted in + * @return the paragraph node + */ + static DocumentNode tracked(String name, String text, DocumentTextStyle style, + double tracking, DocumentColor ground) { + return tracked(name, text, style, tracking, ground, TextVerticalAlign.DEFAULT); + } + + /** + * The same, seated to a given vertical alignment. + * + * @param name the node name + * @param text the text to space out + * @param style the style of the letters + * @param tracking the gap in points + * @param ground the colour the gaps are painted in + * @param verticalAlign where the text sits in its box + * @return the paragraph node + */ + static DocumentNode tracked(String name, String text, DocumentTextStyle style, + double tracking, DocumentColor ground, + TextVerticalAlign verticalAlign) { + return tracked(name, text, style, tracking, ground, TextAlign.LEFT, verticalAlign); + } + + /** + * The same, aligned across the box it is drawn in — which the table + * headers need and the rest of the sheet does not. + * + * @param name the node name + * @param text the text to space out + * @param style the style of the letters + * @param tracking the gap in points + * @param ground the colour the gaps are painted in + * @param align where the run sits across its box + * @param verticalAlign where the text sits in its box + * @return the paragraph node + */ + static DocumentNode tracked(String name, String text, DocumentTextStyle style, + double tracking, DocumentColor ground, TextAlign align, + TextVerticalAlign verticalAlign) { + ParagraphBuilder paragraph = new ParagraphBuilder() + .name(name) + .textStyle(style) + .align(align) + .verticalAlign(verticalAlign) + .lineSpacing(0) + .margin(DocumentInsets.zero()); + if (tracking <= 0) { + return paragraph.text(text).build(); + } + return paragraph.rich(rich -> { + for (int index = 0; index < text.length(); index++) { + if (index > 0) { + rich.shape(new ShapeOutline.Rectangle(tracking, 0.05), ground); + } + rich.style(String.valueOf(text.charAt(index)), style); + } + }).build(); + } + + /** A plain paragraph as a node, for anchoring inside a container. */ + static DocumentNode paragraph(String text, DocumentTextStyle style, TextAlign align) { + return new ParagraphBuilder() + .text(text) + .textStyle(style) + .align(align) + .lineSpacing(0) + .margin(DocumentInsets.zero()) + .build(); + } + + /** The same, carrying a link when one is given. */ + static DocumentNode linkedParagraph(String text, String href, DocumentTextStyle style) { + ParagraphBuilder paragraph = new ParagraphBuilder() + .text(text) + .textStyle(style) + .align(TextAlign.LEFT) + .lineSpacing(0) + .margin(DocumentInsets.zero()); + if (href != null && !href.isBlank()) { + paragraph.link(new DocumentLinkOptions(href)); + } + return paragraph.build(); + } + + /** + * A mark centred on an accent disc. + * + *

A layer stack over an ellipse rather than a filled shape container: + * a container's own fill is dropped when it sits inside a parent carrying + * a large negative margin, which is where the closing banner puts it.

+ */ + static DocumentNode disc(double diameter, String iconToken, double iconSize) { + return new LayerStackBuilder() + .name("Disc-" + iconToken) + .back(new EllipseBuilder() + .name("DiscFill") + .circle(diameter) + .fillColor(ACCENT) + .margin(DocumentInsets.zero()) + .build()) + .layer(LumaStudioIcons.icon(iconToken, iconSize), LayerAlign.CENTER) + .build(); + } + + /** + * A closing-block heading: the disc, and the tracked words on its axis. + * + * @param section the host block + * @param iconToken the mark on the disc + * @param heading the heading text + * @param width the band's width + */ + static void sectionHead(SectionBuilder section, String iconToken, String heading, + double width) { + section.addContainer(container -> container + .name("SectionHead") + .rectangle(width, SECTION_DISC_SIZE) + .clipPolicy(ClipPolicy.OVERFLOW_VISIBLE) + .centerLeft(disc(SECTION_DISC_SIZE, iconToken, SECTION_DISC_ICON_SIZE)) + .position(tracked("SectionHeading", heading, SECTION_HEADING, + TRACK_SECTION_HEADING, PAPER), + SECTION_HEADING_OFFSET, 0, LayerAlign.CENTER_LEFT)); + } +} diff --git a/templates/src/main/resources/templates/invoice/luma-studio/icons/bank.svg b/templates/src/main/resources/templates/invoice/luma-studio/icons/bank.svg new file mode 100644 index 000000000..ea87a64fb --- /dev/null +++ b/templates/src/main/resources/templates/invoice/luma-studio/icons/bank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/src/main/resources/templates/invoice/luma-studio/icons/email.svg b/templates/src/main/resources/templates/invoice/luma-studio/icons/email.svg new file mode 100644 index 000000000..13dc2974c --- /dev/null +++ b/templates/src/main/resources/templates/invoice/luma-studio/icons/email.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/src/main/resources/templates/invoice/luma-studio/icons/heart.svg b/templates/src/main/resources/templates/invoice/luma-studio/icons/heart.svg new file mode 100644 index 000000000..24d90b97a --- /dev/null +++ b/templates/src/main/resources/templates/invoice/luma-studio/icons/heart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/src/main/resources/templates/invoice/luma-studio/icons/notes.svg b/templates/src/main/resources/templates/invoice/luma-studio/icons/notes.svg new file mode 100644 index 000000000..a91fe98cf --- /dev/null +++ b/templates/src/main/resources/templates/invoice/luma-studio/icons/notes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/src/main/resources/templates/invoice/luma-studio/icons/phone.svg b/templates/src/main/resources/templates/invoice/luma-studio/icons/phone.svg new file mode 100644 index 000000000..b2a8bfc1b --- /dev/null +++ b/templates/src/main/resources/templates/invoice/luma-studio/icons/phone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/src/main/resources/templates/invoice/luma-studio/icons/sprig.svg b/templates/src/main/resources/templates/invoice/luma-studio/icons/sprig.svg new file mode 100644 index 000000000..ea5849182 --- /dev/null +++ b/templates/src/main/resources/templates/invoice/luma-studio/icons/sprig.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/src/main/resources/templates/invoice/luma-studio/icons/website.svg b/templates/src/main/resources/templates/invoice/luma-studio/icons/website.svg new file mode 100644 index 000000000..d2929ac57 --- /dev/null +++ b/templates/src/main/resources/templates/invoice/luma-studio/icons/website.svg @@ -0,0 +1 @@ + \ No newline at end of file