diff --git a/.wordlist.txt b/.wordlist.txt index c1c9880664..6e17ab7f34 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -131,6 +131,7 @@ BuyButton CDN CDNs CHANGELOG +CII CKEditor CLI CMS @@ -350,6 +351,7 @@ Dockerfile Dockware DomainException DomainExceptions +Dompdf Dotenv DynamoDB ECDSA @@ -1172,6 +1174,7 @@ XLIFF XMLHttpRequest XPath XQuartz +XRechnung XSS XVFB Xdebug @@ -1181,6 +1184,7 @@ XorRule YYYY YamlFileLoader ZSH +ZUGFeRD accel acl aclfacade @@ -2174,3 +2178,4 @@ zipignore zlib zsh zstd +zugferd diff --git a/concepts/commerce/checkout-concept/document/architecture.md b/concepts/commerce/checkout-concept/document/architecture.md new file mode 100644 index 0000000000..bb81de561b --- /dev/null +++ b/concepts/commerce/checkout-concept/document/architecture.md @@ -0,0 +1,132 @@ +--- +nav: + title: Architecture + position: 20 +--- + +# Document generation architecture + +::: warning This page documents the new Document System (v2) +The reworked document generation is an experimental feature. Activate it with the `DOCUMENT_GENERATION_REWORK` feature flag. Its API can change until it becomes the default with Shopware 6.8. +::: + +## The generation pipeline + +```mermaid +flowchart TD + A["Generation request
orderId, documentType, formats"] --> B[DocumentGenerator] + B --> C["DocumentDependencyResolver
sorts requested formats into a render plan"] + B --> D["Data providers
every provider supporting the type"] + D --> E["Typed render data
one entry per provider key"] + C --> F["Render loop
one renderer per planned format"] + E --> F + F --> G["RenderState
collects one result per format"] + G --> H["DocumentPersister
document + document_file + media"] +``` + +A generation request carries an order ID, a document type, and the requested formats. `DocumentGenerator` orchestrates the rest. It loads the order once, with every matching data provider's search criteria merged in. + +The `DocumentDependencyResolver` turns the requested formats into a render plan, an ordered list that includes any formats other formats depend on. In parallel, `DocumentGenerator` asks every data provider (`AbstractDocumentDataProvider`) that supports the document type for its typed render data, keyed by provider key. + +The render loop then runs each renderer (`AbstractDocumentRenderer`) in the plan, writing its result into `RenderState`. Finally, `DocumentPersister` stores the document together with one `document_file` and one media entry per requested format. + +The document number comes from the number range type `document_`, unless the caller passes one explicitly. + +## Registries + +Three registries form the backbone of the domain. Each one is built from tagged services, so code defines what the system can generate. + +| Registry | Service tag | Resolution rule | +| ------------------------------ | ------------------------------- | --------------------------------------------------------------------------------------- | +| `DocumentTypeRegistry` | `shopware.document_v2.type` | One type per technical name. Validates that requested formats are supported by the type | +| `DocumentDataProviderRegistry` | `shopware.document_v2.provider` | All providers whose `supports()` matches the type run. Duplicate provider keys throw | +| `DocumentRendererRegistry` | `shopware.document_v2.renderer` | First renderer per format wins, ordered by tag priority | + +The renderer rule doubles as the override mechanism: register a renderer for an existing format with a higher tag priority, and it replaces the built-in one. + +## Render plans and format dependencies + +Renderers declare the formats they need through `getDependencies()`. A PDF renderer, for example, depends on the HTML renderer it prints from. The `DocumentDependencyResolver` reads these declarations and topologically sorts them into a render plan, so every prerequisite renders before the format that consumes it. + +```mermaid +flowchart LR + subgraph Requested + REQ[zugferd_embedded_pdf] + end + subgraph Render plan + H1["1 — html"] --> P1["2 — pdf"] + X1["3 — zugferd_xml"] + P1 --> Z1["4 — zugferd_embedded_pdf"] + X1 --> Z1 + end + REQ -. resolves to .-> H1 +``` + +## Render state + +Each generation run owns one `RenderState`. Every renderer in the plan writes exactly one result into it and reads its declared dependencies from it. + +The state lives only for the duration of the run: `DocumentPersister` copies the requested formats out of it, and dependency only intermediates are discarded with it. + +## Order versions and referenced documents + +Generating a document creates a new order version, which freezes the order state the document was generated from. A preview skips this and renders against the live version instead. + +Some document types render against another document rather than the current order. Credit notes and cancellation invoices reference an existing invoice through `referencedDocumentId` in the generation request. Their data providers declare this by implementing the `ReferencesDocument` marker interface. + +The `RendersReferencedSnapshot` interface goes one step further: a provider implementing it renders against the order version the referenced invoice was generated from. A cancellation invoice must invert exactly what the invoice billed, even if the order changed since. + +## Document types and formats + +Every document type supports a fixed set of formats. `storno` is the technical name for the cancellation invoice type: + +| Document type | Purpose | Formats | +| --------------- | ----------------------------------------------------------------------------- | -------------------------------------------- | +| `invoice` | Bills the order | html, pdf, zugferd_xml, zugferd_embedded_pdf | +| `delivery_note` | Accompanies the shipment. Requires a delivery date in the generation request | html, pdf | +| `credit_note` | Credits the credit line items of a referenced invoice | html, pdf, zugferd_xml, zugferd_embedded_pdf | +| `storno` | Cancels a referenced invoice by inverting its amounts | html, pdf, zugferd_xml, zugferd_embedded_pdf | + +`DocumentTypeRegistry` in code is the source of truth for this table and is the successor to the `document_type` database row for a type that remains to satisfy the foreign key. + +The formats build on each other. `html` is the base: a Twig template rendered with the document data. `pdf` prints that HTML through Dompdf. + +`zugferd_xml` is a structured e-invoice (EN 16931 CII syntax, XRechnung profile), meant for accounting software instead of human readers. `zugferd_embedded_pdf` combines both: a PDF/A-3 file with the ZUGFeRD XML embedded, readable as a normal PDF by humans and through the attached XML by machines. + +## Templates + +Every format that renders from a template does so through Twig. HTML templates live at `@Framework/documents/.html.twig`, with shared partials under `@Framework/documents/includes/`. + +The ZUGFeRD XML has its own template set at `@Framework/documents/zugferd/.xml.twig`. + +Both template sets are overridable with `sw_extends`, like any other template in Shopware. + +## Configuration + +`DocumentConfigLoader` builds the configuration a document is rendered with. It merges the global `document_base_config` row, the sales-channel override for the same row, and the company data from the `core.basicInformation` system config, then returns a typed `DocumentConfigBundle`. The loader reads the typed columns on `document_base_config` first and falls back to the legacy JSON `config` blob. + +## Storage + +```mermaid +erDiagram + document ||--o{ document_file : "one row per format" + document_file ||--|| media : "file content" + document { + uuid order_id + uuid order_version_id + string document_number + } + document_file { + uuid document_id + uuid media_id + string document_format + } +``` + +A `document` row represents one logical document: one order, one order version, one document number. Each requested format becomes its own `document_file` row, linked to the media entry that holds the actual file content. + +## Next steps + + + + diff --git a/concepts/commerce/checkout-concept/document/extension-points.md b/concepts/commerce/checkout-concept/document/extension-points.md new file mode 100644 index 0000000000..b19a48e426 --- /dev/null +++ b/concepts/commerce/checkout-concept/document/extension-points.md @@ -0,0 +1,47 @@ +--- +nav: + title: Extension Points + position: 30 +--- + +# Document extension points + +::: warning This page documents the new Document System (v2) +The reworked document generation is an experimental feature. Activate it with the `DOCUMENT_GENERATION_REWORK` feature flag. Its API can change until it becomes the default with Shopware 6.8. +::: + +Document System (v2) extends through three tagged Symfony services and Twig template overrides. There is no service decoration. + +| You want to | Mechanism | +| -------------------------------- | ----------------------------- | +| Change how a document looks | Override a document template | +| Add data to an existing document | Enrich document data | +| Change how a format is produced | Override a built-in renderer | +| Output a new file format | Add a document format | +| Create a new kind of document | Add a document type | + +```mermaid +flowchart TD + A[Generation request] --> B[Render plan] + B --> C[Data providers] + C --> D[Renderers] + D --> E[Persistence] + T1(["Add a document type
shopware.document_v2.type"]) -.-> B + T2(["Enrich or provide data
shopware.document_v2.provider"]) -.-> C + T3(["Add or override a format
shopware.document_v2.renderer"]) -.-> D + T4(["Override Twig templates"]) -.-> D +``` + +Each extension point attaches to one stage of the pipeline: a document type shapes the render plan, a data provider feeds the render loop, and a renderer or a template override changes what that loop produces. + +## Extend with a plugin + +Plugins register the tagged services and override the templates directly: + + + +## Extend with an app + +Apps extend documents declaratively: the manifest registers a document type, Twig templates render it, and the `document-generation` script hook provides the data. Apps cannot add custom formats, renderers, or typed data providers, those stay plugin-only. + + diff --git a/concepts/commerce/checkout-concept/document/index.md b/concepts/commerce/checkout-concept/document/index.md new file mode 100644 index 0000000000..14be60fd78 --- /dev/null +++ b/concepts/commerce/checkout-concept/document/index.md @@ -0,0 +1,49 @@ +--- +nav: + title: Document (v2) + position: 40 +--- + +# Document (v2) + +::: warning This page documents the new Document System (v2) +The reworked document generation is an experimental feature. Activate it with the `DOCUMENT_GENERATION_REWORK` feature flag. Its API can change until it becomes the default with Shopware 6.8. +::: + +## What it is + +The Document System (v2) generates order related business documents: invoices, delivery notes, credit notes, and cancellation invoices. + +Each document can be generated in one or more file formats: HTML, PDF, ZUGFeRD XML, or ZUGFeRD-embedded PDF. Shopware stores the generated files per order. + +## Why a rewrite + +The legacy document system coupled document type and file format, so every combination of type and format needed its own renderer. Adding a format meant touching every type, and adding a type meant touching every format. + +The Document System (v2) splits generation into three independent axes instead: + +```mermaid +flowchart TB + T["Document type
defines what is generated"] --> G[DocumentGenerator] + P["Data provider
defines which data goes in"] --> G + R["Renderer
defines which file format comes out"] --> G + G --> O["Stored document
one file per format"] +``` + +## Availability + +The Document System (v2) rolls out over three releases: it starts as an opt-in feature, becomes the default, and finally replaces the legacy system. + +```mermaid +flowchart LR + A["6.7 — Opt-in
enable DOCUMENT_GENERATION_REWORK
legacy stays the default"] --> B["6.8 — Default
flag on by default, API stabilizes
legacy still available"] --> C["6.9 — Only system
legacy removed"] +``` + +The [migration strategy ADR](../../../../resources/references/adr/2026-08-05-document-generation-v1-to-v2-migration-strategy.md) covers how the legacy system and v2 coexist during this window. + +## ADRs + +- [Refactor of document generation](../../../../resources/references/adr/2026-03-17-refactor-of-document-generation.md): why the legacy system needed a rewrite and the goals for the new implementation. +- [New document generation architecture](../../../../resources/references/adr/2026-03-18-new-document-generation-architecture.md): the entity model and generation flow behind the v2 architecture. +- [New document generation extension points](../../../../resources/references/adr/2026-03-19-new-document-generation-extension-points.md): how plugins and apps add document types, data providers, and renderers. +- [Document generation v1 to v2 migration strategy](../../../../resources/references/adr/2026-08-05-document-generation-v1-to-v2-migration-strategy.md): how the two systems coexist until the legacy one is removed in Shopware 6.9. diff --git a/guides/plugins/apps/checkout/document.md b/guides/plugins/apps/checkout/document.md new file mode 100644 index 0000000000..82b3bdc056 --- /dev/null +++ b/guides/plugins/apps/checkout/document.md @@ -0,0 +1,117 @@ +--- +nav: + title: Document (v2) + position: 120 +--- + +# Documents (v2) in apps + +::: warning This page documents the new Document System (v2) +The reworked document generation is an experimental feature. Activate it with the `DOCUMENT_GENERATION_REWORK` feature flag. Its API can change until it becomes the default with Shopware 6.8. +::: + +Apps extend the Document System (v2) declaratively: the manifest registers a document type, Twig templates render it, and an app script provides the data. + +**Prerequisites**: a running app (see the [app base guide](../app-base-guide)) and the `DOCUMENT_GENERATION_REWORK` feature flag enabled for testing. + +## Register a document type + +Declare the document type in the manifest. `identifier`, `label`, and `formats` are required. `config` is optional and falls back to defaults. + +```xml + + + swag_warranty + + + + html + pdf + + + a4 + portrait + 10 + true + true + + + +``` + +`formats` accepts the built-in formats only: `html`, `pdf`, `zugferd_xml`, and `zugferd_embedded_pdf`. + +Installing the app merges the type into the document type registry and seeds a number range of type `document_`. On update, changed manifest declarations are synchronized. Removed ones are deleted. + +The identifier is globally unique across all apps, installing an app that claims an identifier another app already registered fails. + +## Add the templates + +Templates ship with the app, in the same locations plugins use. The HTML template renders the `html`, `pdf`, and `zugferd_embedded_pdf` formats: + +::: code-group + +```twig [Resources/views/documents/swag_warranty.html.twig] +{% sw_extends '@Framework/documents/base.html.twig' %} + +{% block document_headline %} +

Warranty for order {{ order.orderNumber }}

+{% endblock %} +``` + +::: + +If the type offers `zugferd_xml` or `zugferd_embedded_pdf`, add the XML template as well: + +::: code-group + +```twig [Resources/views/documents/zugferd/swag_warranty.xml.twig] + + + {{ order.orderNumber }} + {{ meta.documentNumber }} + +``` + +::: + +App document types have no typed render data. Templates work with the loaded `order`, the shared document meta data, and whatever the app's script attaches to the order (next section). + +## Provide data with the document-generation script + +The `document-generation` script hook fires once per generation, after the order is loaded and the document number is allocated, before rendering starts. It exposes `order`, `documentType`, `documentNumber`, `formats`, and `context`, plus the `repository` and `config` facades for loading additional data. + +The script attaches data to the order as an extension: + +::: code-group + +```twig [Resources/scripts/document-generation/document-data.twig] +{% set order = hook.order %} + +{% do order.addArrayExtension('swag_warranty_data', { + 'warrantyEnd': order.orderDate|date_modify('+2 years')|date('Y-m-d'), + 'documentNumber': hook.documentNumber +}) %} +``` + +::: + +The document template reads the extension: + +```twig +

Warranty valid until {{ order.extensions.swag_warranty_data.get('warrantyEnd') }}

+``` + +## Enrich built-in documents + +The same combination works for documents the app did not register: the script's `supports` check is up to you, `hook.documentType` tells you which type is being generated, and the visual side is a regular Twig override of the built-in template. + +## Limits + +**No custom formats or renderers.** Apps choose from the four built-in formats. + +**No typed data providers.** The script hook and order extensions replace the plugin-side `AbstractDocumentDataProvider`. + +**No configuration UI.** The `config` block in the manifest is the only configuration surface for app document types. + +**Number ranges persist.** Uninstalling the app deletes its document types, but never the number ranges, reinstalling must not reuse document numbers. diff --git a/guides/plugins/plugins/checkout/document/index.md b/guides/plugins/plugins/checkout/document/index.md deleted file mode 100644 index fc78c14fb5..0000000000 --- a/guides/plugins/plugins/checkout/document/index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -nav: - title: Document - position: 20 - ---- - -# Document - -Document as a plugin in Shopware refers to the essential capabilities of generating and managing documents within the e-commerce platform. These functions are typically part of the core Shopware system but can be extended or customized using plugins. diff --git a/guides/plugins/plugins/checkout/documents/index.md b/guides/plugins/plugins/checkout/documents/index.md new file mode 100644 index 0000000000..52421b0b81 --- /dev/null +++ b/guides/plugins/plugins/checkout/documents/index.md @@ -0,0 +1,13 @@ +--- +nav: + title: Documents + position: 20 +--- + +# Documents + +Shopware is moving from the legacy document system to the reworked Document System (v2). Pick the guide for the system you target. + + + + diff --git a/guides/plugins/plugins/checkout/document/add-custom-document-type.md b/guides/plugins/plugins/checkout/documents/legacy/add-custom-document-type.md similarity index 96% rename from guides/plugins/plugins/checkout/document/add-custom-document-type.md rename to guides/plugins/plugins/checkout/documents/legacy/add-custom-document-type.md index 078c0a84ea..bbde92e560 100644 --- a/guides/plugins/plugins/checkout/document/add-custom-document-type.md +++ b/guides/plugins/plugins/checkout/documents/legacy/add-custom-document-type.md @@ -7,13 +7,17 @@ nav: # Add Custom Document Type +::: warning Deprecated for 6.9 +This page documents the legacy document system. It is deprecated and will be removed with Shopware 6.9. Its successor, the Document System (v2), is available as an experimental feature since Shopware 6.7. See the [Document System (v2) concept](../../../../../../concepts/commerce/checkout-concept/document/) and the [v2 guides](../v2/). +::: + ## Overview This guide will show you how to add a custom document type to your plugin. This includes adding a new document type to the database, creating a renderer for it, and adding a number range. ## Prerequisites -Reviewing the [plugin base guide](../../plugin-base-guide) and the guide on [plugin database migrations](../../database/database-migrations.md) is advisable. +Reviewing the [plugin base guide](../../../plugin-base-guide) and the guide on [plugin database migrations](../../../database/database-migrations.md) is advisable. ## Adding a custom document type and its own base configuration to the database @@ -164,7 +168,7 @@ Your custom document renderer has to implement the `Shopware\Core\Checkout\Docum * `supports`: Has to return a string of the document type it supports. We named our document type "**example**", so our renderer has to return "**example**". * `render`: This needs to return the instance `Shopware\Core\Checkout\Document\Renderer\RendererResult`, which will contain the instance of `Shopware\Core\Checkout\Document\Renderer\RenderedDocument` based on each `orderId`. You will have access to the array of `DocumentGenerateOperation` which contains all respective orderIds, the context and the instance of `Shopware\Core\Checkout\Document\Renderer\DocumentRendererConfig` (additional configuration). -Furthermore, your renderer has to be registered to the [service container](../../services/dependency-injection.md) using the tag `document.renderer`. +Furthermore, your renderer has to be registered to the [service container](../../../services/dependency-injection.md) using the tag `document.renderer`. An example renderer: @@ -413,13 +417,13 @@ In there, you should extend from the default document base template: ::: -The [base.html.twig](https://github.com/shopware/shopware/blob/v6.3.4.1/src/Core/Framework/Resources/views/documents/base.html.twig) template comes with a default templating, which you can now override by using blocks. The guide on [customizing templates](../../storefront/templates/customize-templates.md) provides more details. +The [base.html.twig](https://github.com/shopware/shopware/blob/v6.3.4.1/src/Core/Framework/Resources/views/documents/base.html.twig) template comes with a default templating, which you can now override by using blocks. The guide on [customizing templates](../../../storefront/templates/customize-templates.md) provides more details. ## Adding a number range You are almost done here. You have a new document type in the database, a renderer for your new document type, and it even uses a custom template. However, you also need to add a new number range for your documents; otherwise, a new number wouldn't be generated for your documents. -Adding a new number range is also done by using a [plugin database migration](../../database/database-migrations.md). +Adding a new number range is also done by using a [plugin database migration](../../../database/database-migrations.md). For this we need a few more things: diff --git a/guides/plugins/plugins/checkout/document/add-custom-document.md b/guides/plugins/plugins/checkout/documents/legacy/add-custom-document.md similarity index 89% rename from guides/plugins/plugins/checkout/document/add-custom-document.md rename to guides/plugins/plugins/checkout/documents/legacy/add-custom-document.md index 246ea2cdb0..f1ef7bddb8 100644 --- a/guides/plugins/plugins/checkout/document/add-custom-document.md +++ b/guides/plugins/plugins/checkout/documents/legacy/add-custom-document.md @@ -7,13 +7,17 @@ nav: # Add Custom Document +::: warning Deprecated for 6.9 +This page documents the legacy document system. It is deprecated and will be removed with Shopware 6.9. Its successor, the Document System (v2), is available as an experimental feature since Shopware 6.7. See the [Document System (v2) concept](../../../../../../concepts/commerce/checkout-concept/document/) and the [v2 guides](../v2/). +::: + ## Overview Using the Shopware Administration, you can easily create new documents. This guide explains how to create a new document using a plugin. ## Prerequisites -Reviewing the [plugin base guide](../../plugin-base-guide) and the guide on [plugin database migrations](../../database/database-migrations.md) is advisable. +Reviewing the [plugin base guide](../../../plugin-base-guide) and the guide on [plugin database migrations](../../../database/database-migrations.md) is advisable. ## Adding a custom document diff --git a/guides/plugins/plugins/checkout/documents/legacy/index.md b/guides/plugins/plugins/checkout/documents/legacy/index.md new file mode 100644 index 0000000000..f97720b346 --- /dev/null +++ b/guides/plugins/plugins/checkout/documents/legacy/index.md @@ -0,0 +1,12 @@ +--- +nav: + title: Legacy + position: 20 + +--- + +# Legacy document system + +::: warning Deprecated for 6.9 +This page documents the legacy document system. It is deprecated and will be removed with Shopware 6.9. Its successor, the Document System (v2), is available as an experimental feature since Shopware 6.7. See the [Document System (v2) concept](../../../../../../concepts/commerce/checkout-concept/document/) and the [v2 guides](../v2/). +::: diff --git a/guides/plugins/plugins/checkout/documents/v2/add-a-document-type.md b/guides/plugins/plugins/checkout/documents/v2/add-a-document-type.md new file mode 100644 index 0000000000..4e1d76d68f --- /dev/null +++ b/guides/plugins/plugins/checkout/documents/v2/add-a-document-type.md @@ -0,0 +1,161 @@ +--- +nav: + title: Add a Document Type + position: 20 +--- + +# Add a document type + +::: warning This page documents the new Document System (v2) +The reworked document generation is an experimental feature. Activate it with the `DOCUMENT_GENERATION_REWORK` feature flag. Its API can change until it becomes the default with Shopware 6.8. +::: + +You define the type, provide the data it renders, register both as services and add a template. + +## Create the document type + +A document type declares its technical name and the formats it can be rendered in. + +::: code-group + +```php [PLUGIN_ROOT/src/Core/Checkout/Document/ExampleDocumentType.php] +addAssociation('lineItems'); + } + + public function provideRenderingData(ProviderInput $input, Context $context): AbstractRenderData + { + return new ExampleRenderData( + noteText: 'Thank you for your order!', + ); + } +} +``` + +::: + +## Register the services + +Tag the type and the provider so the registries in Document v2 pick them up. + +::: code-group + +```php [PLUGIN_ROOT/src/Resources/config/services.php] +services(); + + $services->set(ExampleDocumentType::class) + ->tag('shopware.document_v2.type'); + + $services->set(ExampleDocumentDataProvider::class) + ->tag('shopware.document_v2.provider'); +}; +``` + +::: + +## Add the template + +The HTML renderer resolves `@Framework/documents/.html.twig` for the technical name you declared. The DTOs `noteText` from above renders as `config.noteText`. + +::: code-group + +```twig [PLUGIN_ROOT/src/Resources/views/documents/example_document.html.twig] +{% sw_extends '@Framework/documents/base.html.twig' %} + +{% block document_headline %} +

Example document {{ documentNumber }}

+

{{ config.noteText }}

+{% endblock %} +``` + +::: + +Types that offer the `zugferd_xml` format additionally need an XML template at `PLUGIN_ROOT/src/Resources/views/documents/zugferd/example_document.xml.twig`, resolved the same way. + +## Create the database entries + +Two database rows are still required outside of the code above: a `document_type` row whose `technical_name` matches your type, since the `document` table has a foreign key on it, and a number range of type `document_example_document` to number the generated documents. + +The migration code is identical to the legacy system. Reuse the [document type migration](../legacy/add-custom-document-type#adding-a-custom-document-type-and-its-own-base-configuration-to-the-database) and the [number range migration](../legacy/add-custom-document-type#adding-a-number-range) from the legacy guide, and swap in your own technical name. diff --git a/guides/plugins/plugins/checkout/documents/v2/add-a-format-renderer.md b/guides/plugins/plugins/checkout/documents/v2/add-a-format-renderer.md new file mode 100644 index 0000000000..c7b75facdb --- /dev/null +++ b/guides/plugins/plugins/checkout/documents/v2/add-a-format-renderer.md @@ -0,0 +1,93 @@ +--- +nav: + title: Add a Format Renderer + position: 30 +--- + +# Add a format renderer + +::: warning This page documents the new Document System (v2) +The reworked document generation is an experimental feature. Activate it with the `DOCUMENT_GENERATION_REWORK` feature flag. Its API can change until it becomes the default with Shopware 6.8. +::: + +## Add a new format + +A renderer produces exactly one format. `getDependencies()` lists the formats that must render first, so their results are available in `RenderState` when your renderer runs. + +The example below adds a plain-text format. It depends on `html` and derives its content by stripping tags from the already-rendered HTML result. + +::: code-group + +```php [PLUGIN_ROOT/src/Core/Checkout/Document/TextRenderer.php] +require('html'); + + return new RenderResult( + $this->getFormat(), + strip_tags($html->content), + sprintf('%s_txt', $input->documentNumber), + $this->getFileExtension(), + 'text/plain', + ); + } +} +``` + +```php [PLUGIN_ROOT/src/Resources/config/services.php] +services() + ->set(TextRenderer::class) + ->tag('shopware.document_v2.renderer'); +}; +``` + +::: + +A format only becomes selectable once a document type lists it in `getSupportedFormats()`. See [add a document type](./add-a-document-type) for that step. + +## Override a built-in renderer + +The renderer registry keeps the first renderer registered per format. Renderers are ordered by tag priority. Register your renderer for the same format string with a higher priority to replace a built-in one. + +This replaces the legacy system's `getDecorated()` decoration chains. + +```php +$container->services() + ->set(CustomPdfRenderer::class) + ->tag('shopware.document_v2.renderer', ['priority' => 100]); +``` + +`CustomPdfRenderer` extends `AbstractDocumentRenderer` with `getFormat()` returning `pdf`. It fully replaces the built-in `PdfRenderer`, including its `html` dependency declaration. diff --git a/guides/plugins/plugins/checkout/documents/v2/customize-document-data-and-templates.md b/guides/plugins/plugins/checkout/documents/v2/customize-document-data-and-templates.md new file mode 100644 index 0000000000..356f884ca8 --- /dev/null +++ b/guides/plugins/plugins/checkout/documents/v2/customize-document-data-and-templates.md @@ -0,0 +1,110 @@ +--- +nav: + title: Customize Document Data and Templates + position: 40 +--- + +# Customize document data and templates + +::: warning This page documents the new Document System (v2) +The reworked document generation is an experimental feature. Activate it with the `DOCUMENT_GENERATION_REWORK` feature flag. Its API can change until it becomes the default with Shopware 6.8. +::: + +## Add data to an existing document + +Any number of providers can support the same document type. Each provider stores its render data DTO under its own key, and public fields on that DTO are flattened onto the template's `config` variable. + +If a key is already used by another provider for the same document type, generation throws an exception. + +The example below adds a note to the built-in invoice. + +::: code-group + +```php [PLUGIN_ROOT/src/Core/Checkout/Document/InvoiceNoteRenderData.php] +order; + + return new InvoiceNoteRenderData( + invoiceNote: sprintf('Please quote order %s in all correspondence.', $order->getOrderNumber()), + ); + } +} +``` + +```php [PLUGIN_ROOT/src/Resources/config/services.php] +services() + ->set(InvoiceNoteDataProvider::class) + ->tag('shopware.document_v2.provider'); +}; +``` + +::: + +## Override a document template + +Templates live at `@Framework/documents/` and are overridden with `sw_extends`, the same mechanism used everywhere else in Shopware. The invoice template exposes blocks from `base.html.twig` and the `includes/` partials, so overriding `invoice.html.twig` gives access to all of them. + +The same templates render for every format that needs HTML, so a change to `invoice.html.twig` reaches the HTML, PDF, and ZUGFeRD-embedded-PDF output alike. + +The example below appends the note from the provider above to the invoice footer. + +::: code-group + +```twig [PLUGIN_ROOT/src/Resources/views/documents/invoice.html.twig] +{% sw_extends '@Framework/documents/invoice.html.twig' %} + +{% block document_footer %} + {{ parent() }} +

{{ config.invoiceNote }}

+{% endblock %} +``` + +::: + +The ZUGFeRD XML templates under `@Framework/documents/zugferd/` are overridden the same way. + +Templates are shared with the legacy document system during the transition, overrides apply to both systems. diff --git a/guides/plugins/plugins/checkout/documents/v2/index.md b/guides/plugins/plugins/checkout/documents/v2/index.md new file mode 100644 index 0000000000..d850cc3a24 --- /dev/null +++ b/guides/plugins/plugins/checkout/documents/v2/index.md @@ -0,0 +1,33 @@ +--- +nav: + title: v2 + position: 10 +--- + +# Document System (v2) + +::: warning This page documents the new Document System (v2) +The reworked document generation is an experimental feature. Activate it with the `DOCUMENT_GENERATION_REWORK` feature flag. Its API can change until it becomes the default with Shopware 6.8. +::: + +These guides show how to extend the Document System (v2) as a plugin developer. + +**Prerequisites**: a running plugin (see the [plugin base guide](../../../plugin-base-guide)) and the `DOCUMENT_GENERATION_REWORK` feature flag enabled for testing. + +## Add a document type + +Create a new kind of document: a type class, a data provider, a Twig template, and the number range that numbers it. + + + +## Add a format renderer + +Output a new file format, or replace a built-in renderer through tag priority. + + + +## Customize document data and templates + +Add data to documents you did not create, and override the Twig templates that render them. + +