Extension points
Vavang Invoice is designed to be adapted through explicit Symfony contracts before considering a fork. This page identifies the extension points that are actually wired by the plugin today and separates them from implementation details.
Stability model
Treat the interfaces and tags documented here as the supported integration surface for the current major version. A minor upgrade can add methods only when the compatibility policy allows it, but application code should still run its integration tests when upgrading.
Concrete implementation classes, constructor signatures, Doctrine listeners and entity internals are not extension contracts unless another page explicitly says otherwise. Prefer an interface, service decoration or a tagged implementation over subclassing a concrete Vavang class.
Replaceable or decoratable service contracts
The bundle aliases these interfaces to default implementations:
SyliusInvoicePlugin\FacturX\FacturXGeneratorInterface— build the Factur-X document from the electronic invoice and source PDF bytes;SyliusInvoicePlugin\Validation\ElectronicDocumentValidatorInterface— validate structured electronic-invoice XML;SyliusInvoicePlugin\Generation\ComplianceDocumentStoreInterface— find and save compliance documents;SyliusInvoicePlugin\Seller\SellerCompanyProviderInterface— resolve seller company data;SyliusInvoicePlugin\Product\VariantProductNatureResolverInterface— resolve the product nature for a Sylius variant.
Other internal aliases exist, but their presence in the container alone does not make every implementation detail a recommended customization point. Start with the contracts documented here.
Collection extension points
Three platform families are registered for Symfony autoconfiguration by the bundle extension, so host-application implementations are tagged automatically when autoconfiguration is enabled:
PlatformConnectorInterface→sylius_invoice.platform_connector;PlatformSendOperationInterface→sylius_invoice.platform_send_operation;PlatformStatusPollingOperationInterface→sylius_invoice.platform_status_polling_operation.
The following families are collected by tagged iterators too, but the bundle’s _instanceof rules live in its own service file and do not globally tag services declared by the host application. Host implementations must therefore be tagged explicitly:
ElectronicInvoiceBusinessRuleInterface→sylius_invoice.business_rule;TransmissionConnectorInterface→sylius_invoice.transmission_connector;PaymentReportingConnectorInterface→sylius_invoice.payment_reporting_connector;ProviderWebhookAuthenticatorInterface→sylius_invoice.webhook_authenticator;ProviderWebhookDecoderInterface→sylius_invoice.webhook_decoder.
For these explicit-tag families, declare the matching tag in the host application even when Symfony autoconfiguration is enabled. This avoids relying on _instanceof rules that apply only to services loaded by the plugin configuration itself.
Events and UI hooks
Initial compliance processing dispatches SyliusInvoicePlugin\Invoice\InvoiceCreated on the sylius.event_bus. It carries a SourceInvoiceReference and an ActionOrigin. This is a message-bus event, not a Symfony EventDispatcherInterface event.
The admin integration also exposes Sylius Twig Hook names. Prefer overriding a hook contribution over copying a complete plugin template. See Events and Templates.
Explicit responsibility boundaries
Vavang Invoice does not expose its own invoice-numbering strategy. The invoice number comes from the source Sylius InvoicingPlugin invoice. See Numbering.
Vavang also does not render the original visual invoice PDF. The source PDF bytes are obtained from Sylius InvoicingPlugin and then embedded into the Factur-X result. See PDF generation.
The default compliance-document storage is Doctrine-backed. An interface exists for controlled decoration or replacement, but there is no built-in S3/filesystem switch. See Storage and integrity.
Before extending
- Prefer configuration when the existing behavior is sufficient.
- Prefer a tagged implementation when the plugin intentionally aggregates multiple implementations.
- Prefer decoration when you need to observe or augment an existing single service.
- Replace an interface implementation only when you can preserve its invariants and have integration tests.
- Fork only when the required change cannot be expressed through the supported contracts.