# DfProforma Shopware: proforma offertes met klantacceptatie en automatische omzetting

> Wat DfProforma doet Shopware 6.7 kan facturen, pakbonnen en creditnota's uitgeven, maar geen proforma offertes. In vrijwel elke B2B-context (industriële uitrusting, zakelijke dienstverlening, overheidsaankopen, verkoop via aanbestedingen) moet de klant…

- Pagina: <https://www.datafirefly.com/nl/documentation/dfproforma-devis-shopware/>
- Taal: nl
- Bijgewerkt op: 2026-08-19
- Andere talen: [fr](https://www.datafirefly.com/documentation/dfproforma-devis-shopware/index.md), [en](https://www.datafirefly.com/en/documentation/dfproforma-shopware-pro-forma-quote/index.md), [es](https://www.datafirefly.com/es/documentation/dfproforma-shopware-presupuesto-proforma/index.md), [de](https://www.datafirefly.com/de/documentation/dfproforma-shopware-proforma-angebot/index.md), [it](https://www.datafirefly.com/it/documentation/dfproforma-shopware-preventivo-proforma/index.md), [pl](https://www.datafirefly.com/pl/documentation/dfproforma-devis-shopware/index.md), [pt](https://www.datafirefly.com/pt/documentation/dfproforma-devis-shopware/index.md)
- Index: <https://www.datafirefly.com/nl/documentation/llms.txt>

## Wat DfProforma doet

Shopware 6.7 kan facturen, pakbonnen en creditnota's uitgeven, maar geen proforma offertes. In vrijwel elke B2B-context (industriële uitrusting, zakelijke dienstverlening, overheidsaankopen, verkoop via aanbestedingen) moet de klant echter een formeel document ontvangen dat hij aanvaardt _voordat_ de bestelling definitief wordt.

DfProforma vult dat gat zonder omwegen: een echt native Shopware-documenttype `df_proforma`, een eigen nummerreeks `PF{n}`, een eigen PDF-sjabloon in Twig met uw huisstijl, een zelfstandige acceptatieworkflow voor de klant met een publieke URL ondertekend met HMAC-SHA256, en een automatische omzetting in een bestelling zodra de onderliggende transactie de status betaald krijgt.

**Samengevat:** de verkoper genereert een offerte vanaf de bestelkaart in de admin, stuurt die per e-mail, de klant klikt op de link, aanvaardt online zonder Shopware-account, betaalt, en de offerte gaat automatisch naar de status _Omgezet_. Geen enkele handmatige klik na de betaling.

## Vereisten

- **Shopware** 6.7.0 of hoger (de plugin is niet achterwaarts compatibel met 6.6 vanwege de herzieningen van het documentsysteem)
- **PHP** 8.2 minimaal
- **MySQL** 8.0+ of **MariaDB** 10.6+
- Actieve Shopware message workers (aanbevolen voor het automatisch beheer van vervaldata)
- Geconfigureerde Shopware-maildienst (werkende SMTP voor transactionele verzendingen)

## Installatie

### 1. De plugin uploaden

Ga in de Shopware-administration naar _Extensies → Mijn extensies → Extensie uploaden_ en selecteer het bestand `DfProforma-1.0.6.zip`.

### 2. Installeren en activeren

Klik in de lijst met extensies op _Installeren_ en daarna op _Activeren_. De Shopware-migraties draaien automatisch en maken het volgende aan:

- De SQL-tabel `df_proforma` en haar indexen op `order_id`, `status` en `public_token`
- Het documenttype `df_proforma` in `document_type`
- De nummerreeks `document_df_proforma` in het formaat `PF{n}`, configureerbaar
- Het transactionele e-mailsjabloon voor de generatie, de verzending en de acceptatie

### 3. De administration opnieuw compileren

De plugin levert een Vite-adminmodule die de bestelkaart uitbreidt (`sw-order-detail-base`). U moet de globale administratiebundel opnieuw compileren zodat het tabblad _Proforma_ verschijnt:

```
bin/build-administration.sh
bin/console cache:clear
```

**Deze stap overslaan** is de belangrijkste oorzaak van "het tabblad Proforma verschijnt niet op de bestelkaart". Denk eraan opnieuw te compileren na elke update van de plugin.

## Configuratie

### Globale instellingen

Via _Extensies → Mijn extensies → DfProforma → Configureren_ krijgt u toegang tot de volgende instellingen:

- **Standaardgeldigheid**: aantal dagen dat de acceptatielink geldig blijft (standaard 30). Elke offerte kan deze waarde afzonderlijk overschrijven.
- **Automatische omzetting bij betaling**: standaard ingeschakeld. Schakel dit uit als u de overgang _Aanvaard → Omgezet_ handmatig wilt sturen.
- **Naam van de afzender**: de naam die als afzender van de transactionele e-mails wordt getoond (standaard: de naam van het sales channel).
- **Merkaccent van de PDF**: de accentkleur die in het meegeleverde PDF-sjabloon wordt gebruikt (kopbalk, scheidingslijn, statusbadge).

### Configuratie per sales channel

Bovenstaande instellingen kunnen per sales channel worden overschreven via _Instellingen → Sales channels → [uw kanaal] → Pluginconfiguratie_. Handig als u meerdere shops beheert met een verschillend geldigheidsbeleid (bijvoorbeeld 30 dagen voor B2C en 60 dagen voor B2B).

## Een proforma offerte genereren

### Vanuit de bestelkaart (admin)

1. Open een bestelling via _Bestellingen → Overzicht_
2. Klik op het tabblad _Proforma_ (naast _Documenten_)
3. Klik op _Proforma offerte genereren_
4. De PDF wordt aangemaakt en de offerte verschijnt in de lijst met een nummer `PF-…` en de status _Concept_

### Vanuit de admin-API

Er zijn drie endpoints beschikbaar om de generatie in uw externe workflows te integreren:

```
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}
```

Standaard OAuth2-authenticatie van de Shopware-admin. Handig om DfProforma aan een extern CRM of een automatiseringspijplijn te koppelen.

## Een offerte naar de klant sturen

### Transactionele e-mail

Klik in de lijst met offertes (tabblad Proforma van de bestelkaart) op het envelopicoon naast de offerte. De module:

1. Zet de offerte op de status _Verzonden_ (met tijdstempel)
2. Stuurt een e-mail naar de klant via de Shopware Mail Service, met het sjabloon `df_proforma_sent`, in de taal van het sales channel
3. Voegt de PDF van de offerte toe en neemt de publieke acceptatie-URL op
4. Vuurt het event `ProformaGeneratedEvent` af (trigger voor de Flow Builder)

### Publieke acceptatie-URL

Elke verzonden offerte draagt een URL in de vorm:

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

Het token is versleuteld en ondertekend met HMAC-SHA256 met de geheime sleutel van Shopware (`APP_SECRET` / `kernel.secret`). Het is onmogelijk te vervalsen of te raden. De URL verloopt na de geldigheidsduur van de offerte (standaard 30 dagen).

## Publieke acceptatiepagina voor de klant

De klant opent de URL, **zonder dat een Shopware-account nodig is** (de pagina omzeilt de standaardauthenticatie van het klantaccount). Hij ziet:

- Een net overzicht van de bestelling: regels, prijzen, btw, totalen, voorwaarden
- Een hoofdknop _Deze offerte aanvaarden_
- Een secundaire knop _Weigeren met reden_
- De weergegeven geldigheid ("Geldig tot 20-06-2026")

Bij aanvaarding:

- Handtekening met tijdstempel tot op de milliseconde, opgeslagen in de database
- IP-adres van de klant opgeslagen als bewijs
- De status gaat naar _Aanvaard_ met de overgang in de geschiedenis vastgelegd
- Het event `ProformaAcceptedEvent` wordt naar de Flow Builder gestuurd

Bij een weigering is het veld _Reden_ verplicht, nuttig voor uw verkopers die de klant met een tegenvoorstel kunnen benaderen.

**Aanpassing:** de acceptatiepagina gebruikt de standaard Twig-blokken van de Storefront en erft van uw thema. U kunt `@DfProforma/storefront/page/account/proforma/quote.html.twig` vanuit uw thema overschrijven.

## Statusworkflow

Zes statussen dekken de volledige levenscyclus van een offerte:

- **Concept**: offerte aangemaakt maar nog niet naar de klant verzonden
- **Verzonden**: e-mail verstuurd, in afwachting van het antwoord van de klant
- **Aanvaard**: de klant heeft op de publieke pagina op _Aanvaarden_ geklikt
- **Geweigerd**: de klant heeft op _Weigeren_ geklikt en een reden opgegeven
- **Verlopen**: geldigheid verstreken zonder antwoord (automatische overgang via een scheduled task)
- **Omgezet**: de onderliggende bestelling is betaald, automatische omzetting

Elke overgang wordt opgeslagen met de datum tot op de seconde, de identificatie van de actor, het type trigger (_verkoper_, _klant_, _systeem_, _betaling_) en een JSON-payload voor vrije metadata. U kunt op elk moment de exacte geschiedenis van een offerte reconstrueren.

## Automatische omzetting bij betaling

De module registreert een subscriber op het event `order_transaction.state.paid` van de Shopware-statusmachine. Wanneer een transactie naar _betaald_ gaat (Stripe, overschrijving, PayPal en dergelijke), doet de subscriber het volgende:

1. Hij zoekt alle proforma offertes met de status _Aanvaard_ die aan de bestelling gekoppeld zijn
2. Hij zet ze op de status _Omgezet_
3. Hij legt de overgang in de geschiedenis vast met het triggertype _betaling_

Geen menselijke tussenkomst, geen cron, geen vertraging. Uw verkooprapporten blijven moeiteloos consistent.

Om de automatische omzetting uit te schakelen (als uw team liever handmatig stuurt), vinkt u de optie uit onder _Pluginconfiguratie → Automatische omzetting bij betaling_.

## Flow Builder, business events

De module zendt twee standaard Shopware-events uit:

- `ProformaGeneratedEvent`: bij het genereren van een offerte (implementeert `BusinessEventInterface`)
- `ProformaAcceptedEvent`: bij de aanvaarding door de klant (implementeert `BusinessEventInterface`)

Beide verschijnen automatisch in de lijst met triggers van de native Shopware Flow Builder. U kunt er elke Flow-actie aan koppelen:

- Slack-melding aan het verkoopteam bij aanvaarding
- Interne overzichtsmail naar de verantwoordelijke verkoper
- Webhook naar uw CRM (HubSpot, Salesforce, Pipedrive en andere)
- Bijwerken van een aangepast veld op de klant (bijvoorbeeld de tag `quote-accepted`)
- Mobiele pushmelding via een externe dienst

Er is geen ingreep in de code van de module nodig, alles wordt geconfigureerd via _Instellingen → Shop → Flow Builder_.

## Aanpassing van het PDF-sjabloon

De PDF van de offerte wordt gerenderd via `DocumentFileRendererRegistry` (het nieuwe systeem voor bestandsweergave van Shopware 6.7), op basis van het Twig-sjabloon `@DfProforma/documents/proforma.html.twig` dat in de module wordt meegeleverd.

Om het aan te passen maakt u een eigen plugin of overschrijft u het vanuit uw thema, met respect voor de standaard Twig-sjabloonhiërarchie van Shopware:

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

Het meegeleverde sjabloon biedt deze benoemde Twig-blokken:

- Koptekst met logo en bedrijfsgegevens
- Klantblok
- Overzicht van de bestelregels
- Totalen exclusief en inclusief btw met btw-uitsplitsing
- Samenvattende balk in de voettekst (PF-nummer, uitgifte- en vervaldatum)
- Watermerk _PRO FORMA_
- Merkaccent instelbaar via `config.accentColor`

Beschikbare variabelen in het sjabloon: `order` (de OrderEntity geladen met al haar associaties), `config` (documentconfiguratie met onder meer `documentNumber`, `documentDate`, `validUntil`, `validityDays`) en `context`.

## Meertaligheid

FR, EN, DE en ES worden standaard meegeleverd, met snippets voor Storefront en Admin. Om andere talen toe te voegen, maakt u per locale een snippetbestand aan in `src/Resources/snippet/` volgens de standaardconventie van Shopware.

De transactionele e-mailsjablonen zijn eveneens meertalig: het juiste sjabloon wordt automatisch gekozen op basis van de taal van het sales channel van de klant op het moment van verzending. U kunt de sjablonen per taal aanpassen via _Instellingen → Shop → E-mailsjablonen_.

## API, beschikbare admin-endpoints

```
POST   /api/_action/df-proforma/generate         # Genereert een offerte voor een bestelling
POST   /api/_action/df-proforma/mark-sent        # Markeert als verzonden (handmatige overgang)
GET    /api/_action/df-proforma/by-order/{id}    # Toont de offertes van een bestelling
```

De entiteiten `df_proforma` zijn ook bereikbaar via de standaard DAL-API van Shopware (`/api/df-proforma`) voor zoekopdrachten, exports of geavanceerde integraties.

## Verwijderen

Standaard blijven de bedrijfsgegevens bij het verwijderen bewaard (de optie _Keep User Data_ staat aan). Zo behoudt u de auditgeschiedenis van de uitgegeven offertes, nuttig voor compliance en commerciële traceerbaarheid.

Om een volledige verwijdering af te dwingen (tabel `df_proforma`, documenttype, nummerreeks, e-mailsjabloon), schakelt u de optie _Keep User Data_ uit in het verwijderscherm.

**Aanbeveling:** behoud standaard de gegevens. Forceer de verwijdering alleen als u zeker weet dat u de geschiedenis van de offertes nooit meer nodig hebt om commerciële, boekhoudkundige of juridische redenen.

## Probleemoplossing

### Het tabblad Proforma verschijnt niet op de bestelkaart

De administratiebundel is na de installatie niet opnieuw gecompileerd. Voer `bin/build-administration.sh` uit en daarna `bin/console cache:clear`.

### Fout "Unable to find a document generator with type df_proforma"

De servicetag van de renderer klopt niet; deze bug is sinds 1.0.2 opgelost. Gebruik een versie ≥ 1.0.2 van de plugin.

### Fout "Call to undefined method Context::getSalesChannelId()"

Historische oorzaak: de oude constructorhandtekening van `RenderedDocument`. Opgelost in 1.0.4. Werk bij naar 1.0.6.

### Twig-fout "Cannot rewind a generator that was already run"

Opgelost in 1.0.6, het sjabloon is aangepast zodat het een generator uit `|filter()` niet twee keer verbruikt.

### De klant ontvangt de e-mail maar de acceptatie-URL geeft een 404-fout

Controleer of het Storefront sales channel daadwerkelijk als domein is geregistreerd voor het verkoopkanaal van de bestelling. De publieke route `/proforma/accept/{token}` is op de Storefront geregistreerd en werkt niet als u de URL via het admindomein benadert.

### De automatische vervaldatum werkt niet

Controleer of de Shopware _message workers_ op de achtergrond draaien (`bin/console messenger:consume` of via een supervisor zoals systemd of supervisord). Het verlopen verloopt via de standaard berichtenwachtrij van Shopware.

## Support en updates

12 maanden updates inbegrepen (Shopware-compatibiliteit, bugfixes, kleine functionele toevoegingen). E-mailsupport in het Frans en het Engels binnen 24 werkuren. De PHP-broncode wordt open geleverd, conform PSR-4, controleerbaar en aanpasbaar.

Voor vragen of meldingen: [contact@datafirefly.com](https://www.datafirefly.com/nl/contact/).
