SW Shopware 6 Intermediate

DfProforma Shopware — Pro forma quotes with client acceptance and auto-conversion

Complete documentation of the Shopware 6.7 pro forma quote plugin: installation, client acceptance workflow, auto-conversion, Flow Builder and customization.

Updated Module version 1.0.6

What DfProforma does

Shopware 6.7 knows how to issue invoices, delivery notes, and credit notes — but not pro forma quotes. Yet in nearly all B2B contexts (industrial equipment, business services, public procurement, bid-based sales), the client must receive a formal document they accept before the order becomes firm.

DfProforma fills this gap without workarounds: a real native Shopware document type df_proforma, its own PF{n} number range, a branded Twig PDF template, a standalone client acceptance workflow with a public URL signed HMAC-SHA256, and automatic conversion to a firm order as soon as the underlying transaction transitions to paid.

In a nutshell: the sales rep generates a quote from the order detail in the admin, sends it by email, the client clicks the link, accepts online without a Shopware account, pays, and the quote automatically switches to Converted status. No manual click post-payment.

Requirements

  • Shopware 6.7.0 or higher (the plugin is not backward-compatible with 6.6 due to the document system refactor)
  • PHP 8.2 minimum
  • MySQL 8.0+ or MariaDB 10.6+
  • Active Shopware message workers (recommended for automatic expiration handling)
  • Configured Shopware Mail Service (working SMTP for transactional sends)

Installation

1. Upload the plugin

From the Shopware administration, go to Extensions → My extensions → Upload extension, and select the DfProforma-1.0.6.zip file.

2. Install and activate

In the extensions list, click Install then Activate. Shopware migrations run automatically and create:

  • The df_proforma SQL table with indexes on order_id, status, public_token
  • The df_proforma document type in document_type
  • The document_df_proforma number range in configurable PF{n} format
  • The base transactional email template for generation, sending, and acceptance

3. Rebuild the administration

The plugin ships a Vite admin module that extends the order detail (sw-order-detail-base). You must rebuild the global administration bundle for the Pro forma tab to appear:

bin/build-administration.sh
bin/console cache:clear
Skipping this step is the leading cause of the “Pro forma tab does not appear on the order detail” issue — remember to rebuild after every plugin update.

Configuration

Global settings

From Extensions → My extensions → DfProforma → Configure, you access the following settings:

  • Default validity — Number of days the acceptance link remains valid (30 by default). Each quote can override this value individually.
  • Auto-conversion on payment — Enabled by default. Disable it if you want to keep manual control of the Accepted → Converted transition.
  • Sender name — Name shown as sender of transactional emails (default: the sales-channel name).
  • PDF brand accent — Accent color used in the shipped PDF template (header band, separator line, status badge).

Per-sales-channel configuration

The settings above can be overridden per sales channel in Settings → Sales channels → [your channel] → Plugin configuration. Useful if you run multiple stores with different validity policies (for example 30 days for B2C, 60 days for B2B).

Generate a pro forma quote

From the order detail (admin)

  1. Open an order in Orders → Overview
  2. Click the Pro forma tab (next to Documents)
  3. Click Generate pro forma quote
  4. The PDF is created, the quote appears in the list with a PF-… number and status Draft

From the admin API

Three endpoints are exposed to integrate generation into your external workflows:

POST /api/_action/df-proforma/generate
Body: { "orderId": "…" }

POST /api/_action/df-proforma/mark-sent
Body: { "proformaId": "…" }

GET  /api/_action/df-proforma/by-order/{orderId}

Standard Shopware OAuth2 admin authentication. Useful to hook DfProforma into an external CRM or an automation pipeline.

Send a quote to the client

Transactional email

From the quote list (Pro forma tab on the order detail), click the envelope icon next to the quote. The module:

  1. Sets the quote to Sent status (with timestamp)
  2. Sends an email to the client via the Shopware Mail Service, using the df_proforma_sent template, in the sales-channel language
  3. Attaches the quote PDF and includes the public acceptance URL
  4. Emits the ProformaGeneratedEvent event (Flow Builder trigger)

Public acceptance URL

Every sent quote carries a URL of the form:

https://your-shop.com/proforma/accept/{token}

The token is encrypted and signed HMAC-SHA256 with the Shopware secret key (APP_SECRET / kernel.secret). Impossible to forge or guess. The URL expires after the quote validity (30 days by default).

Public client acceptance page

The client opens the URL — no Shopware account required (the page bypasses standard customer account authentication). They see:

  • A clean order summary: lines, prices, VAT, totals, terms
  • A primary Accept this quote button
  • A secondary Decline with reason button
  • The displayed validity (“Valid until 20/06/2026”)

On acceptance:

  • Signature timestamped to the millisecond and persisted in the database
  • Client IP address persisted as proof
  • Status changes to Accepted with the transition history marked
  • ProformaAcceptedEvent event dispatched to Flow Builder

On rejection, the Reason field is mandatory — useful for your sales reps who can reach out with a counter-proposal.

Customization: the acceptance page uses standard Storefront Twig blocks and inherits your theme. You can override @DfProforma/storefront/page/account/proforma/quote.html.twig from your theme.

Status workflow

Six statuses cover the entire lifecycle of a quote:

  • Draft — Quote created but not yet sent to the client
  • Sent — Email sent, awaiting client response
  • Accepted — Client clicked Accept on the public page
  • Declined — Client clicked Decline with a reason
  • Expired — Validity exceeded without response (automatic transition via scheduled task)
  • Converted — Underlying order paid, automatic conversion

Each transition is persisted with second-level timestamp, actor identifier, trigger type (sales rep, client, system, payment) and JSON payload for free metadata. You can reconstruct the exact history of any quote at any time.

Auto-conversion on payment

The module registers a Subscriber on the order_transaction.state.paid event from Shopware’s state machine. When a transaction transitions to paid (Stripe, bank transfer, PayPal, etc.), the Subscriber:

  1. Finds all pro forma quotes in Accepted status attached to the order
  2. Switches them to Converted status
  3. Marks the transition history with trigger type payment

No human intervention, no cron, no delay. Your sales reports remain consistent effortlessly.

To disable auto-conversion (if your team prefers manual control), uncheck the option in Plugin configuration → Auto-conversion on payment.

Flow Builder — Business Events

Two standard Shopware Business Events are emitted by the module:

  • ProformaGeneratedEvent — On quote generation (implements BusinessEventInterface)
  • ProformaAcceptedEvent — On client acceptance (implements BusinessEventInterface)

Both appear automatically in the native Shopware Flow Builder trigger list. You can hook any Flow action onto them:

  • Slack notification to the sales team on acceptance
  • Internal summary email to the responsible sales rep
  • Webhook to your CRM (HubSpot, Salesforce, Pipedrive…)
  • Custom field update on the customer (for example, quote-accepted tag)
  • Mobile push notification via a third-party service

No intervention in the module’s code required — everything is configured from Settings → Shop → Flow Builder.

PDF template customization

The quote PDF is rendered via DocumentFileRendererRegistry (Shopware 6.7’s new file rendering system), from the Twig template @DfProforma/documents/proforma.html.twig shipped with the module.

To customize it, create a custom plugin or override it from your theme following Shopware’s standard Twig template hierarchy:

custom/plugins/YourTheme/src/Resources/views/documents/proforma.html.twig

The shipped template exposes these identified Twig blocks:

  • Header with logo and company details
  • Customer block
  • Order line items summary
  • HT/TTC totals with VAT breakdown
  • Summary strip at the bottom (PF number, issue and expiry dates)
  • PRO FORMA watermark
  • Brand accent configurable via config.accentColor

Variables available in the template: order (OrderEntity loaded with all its associations), config (document config including documentNumber, documentDate, validUntil, validityDays), context.

Multilingual

FR, EN, DE, and ES are shipped by default, storefront and admin snippets. To add more languages, create a snippet file per locale in src/Resources/snippet/ following Shopware’s standard convention.

The transactional email templates are also multilingual: the correct template is selected automatically based on the customer’s sales-channel language at send time. You can customize templates per language from Settings → Shop → Email templates.

API — available admin endpoints

POST   /api/_action/df-proforma/generate         # Generate a quote for an order
POST   /api/_action/df-proforma/mark-sent        # Mark as sent (manual transition)
GET    /api/_action/df-proforma/by-order/{id}    # List an order's quotes

df_proforma entities are also accessible via the standard Shopware DAL API (/api/df-proforma) for search, export, or advanced integrations.

Uninstall

By default, business data is preserved on uninstall (Keep User Data option enabled). You thus preserve the audit history of issued quotes, useful for compliance and commercial traceability.

To force complete removal (df_proforma table, document type, number range, email template), disable the Keep User Data option in the uninstall prompt.

Recommendation: keep data by default. Only force removal if you’re certain you’ll never need to access quote history for commercial, accounting, or legal reasons.

Troubleshooting

The Pro forma tab doesn’t appear on the order detail

The administration bundle was not rebuilt after installation. Run bin/build-administration.sh then bin/console cache:clear.

Error “Unable to find a document generator with type df_proforma”

The renderer’s service tag is not correct — this bug was fixed since 1.0.2. Make sure you’re using a plugin version ≥ 1.0.2.

Error “Call to undefined method Context::getSalesChannelId()”

Historical cause: old signature of the RenderedDocument constructor. Fixed in 1.0.4. Update to 1.0.6.

Twig error “Cannot rewind a generator that was already run”

Fixed in 1.0.6 — the template was adapted to not consume a |filter()-generated generator twice.

The client receives the email but the acceptance URL returns a 404

Verify that the Storefront sales-channel is properly registered as a domain of the sales channel used for the order. The public route /proforma/accept/{token} is registered on the Storefront — it does not work if you access the URL via the admin domain.

Automatic expiration doesn’t work

Verify that Shopware message workers are running in the background (bin/console messenger:consume or via a supervisor like systemd/supervisord). Expiration goes through the standard Shopware message queue.

Support and updates

12 months of updates included (Shopware compatibility, bug fixes, minor feature additions). Email support in French and English within 24 business hours. PHP source code delivered as plain text, PSR-4 compliant, auditable and modifiable.

For any question or report: contact@datafirefly.com.

Was this page helpful?

Still stuck? Contact support