# Print Layout V2 — File Structure Reference

All print layout contracts use the `.printlayoutv2.xml` extension. V1 is fully deprecated.
Files live under `src/<Module>/PL/<LayoutName>/<LayoutName>.printlayoutv2.xml`.

---

## Root Element

```xml
<PrintLayout xmlns="https://www.salesforce.com/cgcloud/xsds"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             name="OrderConfirmationPDF">
```

-   `xmlns` — always `https://www.salesforce.com/cgcloud/xsds` (do not change)
-   `xmlns:xsi` — present in real files; keep it
-   `name` — unique workspace-wide; matches the filename stem

Real file: `src/Order/PL/OrderConfirmationPDF/OrderConfirmationPDF.printlayoutv2.xml`

---

## Declarations Block

Lists every input the layout reads from. Populated at runtime by a PRINTV2 process action.

```xml
<Declarations>
  <!-- BO reference -->
  <DataDeclaration name="order"      type="BoOrder" />
  <!-- LU reference -->
  <DataDeclaration name="salesOrg"   type="LuSalesOrg" />
  <!-- Image -->
  <DataDeclaration name="myImageName" type="Image" mimeType="image/png" imageId="CompanyLogo" />
  <!-- Signature (max 4 per layout) -->
  <DataDeclaration name="signature1" type="Signature" />
</Declarations>
```

| Type                          | Attributes                            | Purpose                                                 |
| ----------------------------- | ------------------------------------- | ------------------------------------------------------- |
| BO class (e.g., `BoOrder`)    | `name`, `type`                        | Business Object data                                    |
| LU class (e.g., `LuSalesOrg`) | `name`, `type`                        | Lookup reference data                                   |
| `Image`                       | `name`, `type`, `mimeType`, `imageId` | Embedded image; `imageId` matches file in `src/Images/` |
| `Signature`                   | `name`, `type`                        | Digital/scanned signature capture; max 4 per layout     |

Validation rule: Image `DataDeclaration` must have both `mimeType` and `imageId` set.

---

## ReportLayout

Wraps all visual content. Declares page margins.

```xml
<ReportLayout pageMargins="[40,40,40,40]">
  <!-- content: tables, paragraphs, headings, images -->
</ReportLayout>
```

-   `pageMargins="[top,right,bottom,left]"` — pixel values for standard PDF
-   **Do not** add `pageMargins` on thermal layouts (validation error)
-   Standard A4 page dimensions (from wiki): `pageSize="[595, 842]"` — thermal: `pageSize="[216, auto]"`

---

## Tables

Tables are the primary layout container.

```xml
<table name="ItemsTable" tableLayout="lightHorizontalLinesMainItemsOnly">
  <thead>
    <tr>
      <th width="40%">{{Labels::ProductId; defaultLabel=Product}}</th>
      <th width="20%" alignment="center">{{Labels::QtyId; defaultLabel=Qty}}</th>
      <th width="20%" alignment="right">{{Labels::PriceId; defaultLabel=Price}}</th>
      <th width="20%" alignment="right">{{Labels::AmountId; defaultLabel=Amount}}</th>
    </tr>
  </thead>
  <tbody>
    <!-- rows and iteration go here -->
  </tbody>
</table>
```

### tableLayout values (observed in `src/Order/PL/`)

| Value                               | Appearance                                                    |
| ----------------------------------- | ------------------------------------------------------------- |
| `noBorders`                         | No visible borders                                            |
| `lightHorizontalLines`              | Thin lines between all rows                                   |
| `lightHorizontalLinesMainItemsOnly` | Lines only around main `<tr>` rows (not correlation sub-rows) |
| `bordered`                          | Full border grid                                              |

### th / td attributes

| Attribute   | Purpose                                       |
| ----------- | --------------------------------------------- |
| `width`     | Pixel value or `*` (fill remaining) or `auto` |
| `alignment` | `left`, `center`, `right`                     |
| `bold`      | `"true"` for bold text                        |
| `rowSpan`   | Merge cell vertically (number of rows)        |
| `colSpan`   | Merge cell horizontally (number of columns)   |

Validation constraints:

-   `<table>` must declare `<thead>` (a single `<tr>` row only — multiple `<tr>` in thead is warned)
-   Width percentages in a `<thead>` row must sum to 100% (less than 100% is warned)
-   `<img>` may not appear inside a `<td>`

---

## Iteration — `<each>`

Loops over a ListObject (LO) associated with a BO.

```xml
<each name="itemsEach" value="{{Declarations::order.loPrintItems}}">
  <filters>
    <filter fieldName="quantity" value="0" operator="GT" compareMode="NUMBER" />
    <filter fieldName="movementDirection" value="In" operator="NE" />
  </filters>
  <orderCriteria>
    <orderCriterion fieldName="prdId" direction="ASC" compareMode="NUMBER" />
  </orderCriteria>
  <tr>
    <td>{{.prdId}}</td>
    <td>{{.text1}}</td>
    <td alignment="right">{{.valueReceipt; numberFormat=8.2}}</td>
  </tr>
</each>
```

-   `value` — macro to the LO: `{{Declarations::<var>.<loProperty>}}`
-   `<filters>` — optional; include only matching items
-   `<orderCriteria>` — optional; sort within the iteration
-   Inside `<each>`: access current item fields with `{{.<fieldName>}}`

---

## Correlation — `<correlation>`

Joins a related LO to the current iteration item (sub-rows per item).

```xml
<correlation name="cond1"
             value="{{Declarations::order.loSdoConditions}}"
             key="pKey"
             correlationKey="sdoItemPKey">
  <filters>
    <filter fieldName="cpIsPrintRelevant" value="1" operator="EQ" />
  </filters>
  <tr>
    <td />
    <td>{{.text1}} {{.conditionValue; numberFormat=8.2}}</td>
  </tr>
</correlation>
```

Column count in the `<correlation>` `<tr>` must match the host table column count (warned if off).

---

## Aggregation — `<sum>`

Computes a column total from a named table.

```xml
<sum table="OrderItemsTable" col="3" numberFormat="8.2" />
```

-   `table` — the `name` attribute of the enclosing `<table>`
-   `col` — zero-based column index
-   `numberFormat` — e.g., `"8.2"` for 2 decimal places

---

## Inline Content Elements

| Element        | Attributes                  | Notes                                                      |
| -------------- | --------------------------- | ---------------------------------------------------------- |
| `<p>`          | `bold`, `alignment`         | Paragraph                                                  |
| `<h1>`, `<h2>` | `alignment`                 | Headings                                                   |
| `<img>`        | `src`, `width`, `alignment` | Image; must declare `width`; cannot be inside `<td>`       |
| `<lineFeed/>`  | —                           | Vertical spacing — thermal layouts only                    |
| `<rule/>`      | —                           | Horizontal rule — thermal layouts only; no two consecutive |

---

## File Path Convention

```
src/<Module>/PL/<LayoutName>/<LayoutName>.printlayoutv2.xml
```

Example: `src/Order/PL/OrderConfirmationPDF/OrderConfirmationPDF.printlayoutv2.xml`

The `name` attribute on `<PrintLayout>` matches the folder name and the filename stem exactly.
