Skip to content

2025-12-29 B2B BTW Fix, Verzending Staffel & DNS Setup

Datum: 2025-12-29 Status: Completed Focus: B2B belasting berekening, verzendkosten staffel, domein configuratie

Samenvatting

Cruciale doorbraak bereikt met B2B BTW berekening: patch toegepast waardoor promoties correct worden berekend VOOR BTW in plaats van erna. Daarnaast verzendkosten staffel gebouwd met configureerbare UI voor NL/BE/wereld, en hoofddomein voedingsgeneeskunde.nl geconfigureerd voor live gang.

B2B BTW Berekening Fix

Probleem

Commerce berekende BTW incorrect voor B2B shop: - Prijs excl. BTW -> BTW toevoegen -> Promotie toepassen - Dit resulteerde in verkeerde kortingsbedragen

Correcte B2B flow: - Prijs excl. BTW -> Promotie toepassen -> BTW toevoegen

Oplossing: Patch #2982355

Issue: https://www.drupal.org/project/commerce/issues/2982355
Patch: commerce-tax_processor-2982355-61.patch (2025-10-09)

Patch splitst TaxOrderProcessor in twee processors: - EarlyTaxOrderProcessor (priority 300) - voor B2C included tax - LateTaxOrderProcessor (priority 50) - voor B2B excluded tax

Installatie:

cd /var/www/sites/dev.voedingsgeneeskunde/web/modules/contrib/commerce
wget https://www.drupal.org/files/issues/2025-10-09/commerce-tax_processor-2982355-61.patch
patch -p1 < commerce-tax_processor-2982355-61.patch

Composer integratie: Patch toegevoegd aan composer.json onder extra.patches:

"drupal/commerce": {
    "B2B tax calculation - apply promotions before tax #2982355": "https://www.drupal.org/files/issues/2025-10-09/commerce-tax_processor-2982355-61.patch"
}

Tax Type Configuratie

Kritieke instelling voor B2B:

drush config:set commerce_tax.commerce_tax_type.btw configuration.display_inclusive 0 -y
drush cr

Voor: display_inclusive: true - BTW included in prijzen (B2C)
Na: display_inclusive: false - BTW apart berekend (B2B)

Resultaat

Correcte B2B berekening nu actief:

Voorbeeld: Los nummer (€9,13) + VGBC ticket (€49,95) + Verzending (€4,10) met 33% studentkorting

Los nummer:         €9,13 excl. BTW
VGBC ticket:        €49,95 excl. BTW  
Studentkorting:     -€16,48 (33% van €49,95)
Verzending:         €4,10 excl. BTW
---
Subtotaal:          €46,70 excl. BTW
BTW 9%:             €0,82 (op €9,13)
BTW 21%:            €7,90 (op €33,47 + €4,10)
---
Totaal:             €55,42

Verificatie: - Los nummer: geen korting (correct - alleen tickets krijgen korting) - VGBC ticket: korting VOOR BTW (correct) - BTW split: 9% en 21% apart (correct) - Verzending: verschijnt in checkout (correct)

Verzendkosten Staffel

Requirement

Staffel voor losse nummers per land en aantal:

Nederland: - 1 exemplaar: €4,25 - 2-5 exemplaren: €5,95 - 6-10 exemplaren: €7,50 - Meer dan 10: €9,00

België: - 1 exemplaar: €7,95 - 2-5 exemplaren: €10,50 - 6-10 exemplaren: €13,00 - Meer dan 10: Op aanvraag

Rest van de wereld: - 1 exemplaar: €11,90 - 2-5 exemplaren: €17,00 - 6-10 exemplaren: €23,00 - Meer dan 10: Op aanvraag

Implementatie

Custom Shipping Plugin:
/web/modules/custom/vg_commerce/src/Plugin/Commerce/ShippingMethod/TieredShipping.php

Features: - Telt alleen los_nummer product variation type - Land-specifieke tarieven (NL/BE/wereld) - Configureerbare UI via shipping method form - "Op aanvraag" optie voor >10 exemplaren (retourneert NULL = geen verzending mogelijk)

Configuratie UI elementen:

Per land 4 velden: - 1 exemplaar (required) - 2-5 exemplaren (required) - 6-10 exemplaren (required) - Meer dan 10 (conditional - alleen zichtbaar als checkbox "Op aanvraag" uit staat)

Checkbox "Op aanvraag": - Aangevinkt: geen verzending mogelijk voor >10, klant moet contact opnemen - Uitgevinkt: toont prijsveld voor >10 exemplaren

Aanpassen prijzen: Shop managers kunnen tarieven wijzigen via:
/admin/commerce/config/shipping-methods/1/edit

Geen code wijzigingen nodig - alles via UI configureerbaar.

DNS & Domain Setup

Domein Migratie

Hoofddomein voedingsgeneeskunde.nl vrijgemaakt van oude site en gekoppeld aan nieuwe Drupal 11 platform.

Apache Configuratie

Nieuwe vhost: voedingsgeneeskunde.nl.conf

<VirtualHost *:80>
    ServerName voedingsgeneeskunde.nl
    ServerAlias www.voedingsgeneeskunde.nl
    DocumentRoot /var/www/sites/live.voedingsgeneeskunde.nl/web

    # Redirect to HTTPS
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =voedingsgeneeskunde.nl [OR]
    RewriteCond %{SERVER_NAME} =www.voedingsgeneeskunde.nl
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

SSL certificaat:

sudo certbot --apache -d voedingsgeneeskunde.nl -d www.voedingsgeneeskunde.nl

Drupal Trusted Hosts

settings.php aangepast:

$settings['trusted_host_patterns'] = [
  '^d8dev\.voedingsgeneeskunde\.nl$',
  '^nieuw\.voedingsgeneeskunde\.nl$',
  '^voedingsgeneeskunde\.nl$',
  '^www\.voedingsgeneeskunde\.nl$',
];

Subdomain Redirect

nieuw.voedingsgeneeskunde.nl redirect permanent naar hoofddomein voor consistentie.

Nieuwe configs: - nieuw.voedingsgeneeskunde-redirect.conf (HTTP) - nieuw.voedingsgeneeskunde-redirect-ssl.conf (HTTPS)

Conflict opgelost: Oude d8_dev-le-ssl.conf had ook ServerName voor nieuw subdomain. Deze disabled:

sudo a2dissite d8_dev-le-ssl.conf
sudo a2dissite d8_live-le-ssl.conf

DNS Propagatie

DNS wijziging doorgevoerd:
voedingsgeneeskunde.nl A-record -> 37.97.221.249 (VPS IP)

Propagatietijd: 24-48 uur (afhankelijk van TTL en DNS caching)

Gebruikersbeheer

User Profile Issue

User 46 (Joost Angemelt) had geen toegang tot profiel paginas na aanmaken via admin UI.

Diagnose: - Geen customer profile (ID 166) - Geen openbaar profile (ID 167) - Profile hooks werden niet getriggerd bij admin user creation

Oplossing: Profielen handmatig aangemaakt via Drush:

drush php:eval "
\$profile_storage = \Drupal::entityTypeManager()->getStorage('profile');
\$customer = \$profile_storage->create([
  'type' => 'customer',
  'uid' => 46,
  'is_default' => TRUE,
  'status' => TRUE,
]);
\$customer->save();
"

Field Beroep Locatie

Context

field_beroep (beroep field) staat nu in openbaar profile maar moet naar customer profile.

Redenen: 1. Gebruikt voor StudentProfessionCondition (33% korting) 2. Marketing/business data, niet publieke info 3. StudentProfessionCondition checkt al beide profile types

Actiepunt: Collega zal field migratie handmatig uitvoeren (field verplaatsen van openbaar -> customer profile).

Inzichten & Technische Details

Commerce Tax Calculation Order

Standaard Commerce flow (B2C): 1. Product base price 2. Tax toevoegen (included) 3. Promotions toepassen

B2B flow (met patch): 1. Product base price 2. Promotions toepassen 3. Tax toevoegen (excluded)

Key config: - display_inclusive: false zorgt dat tax niet in unit_price wordt gebakken - Patch zorgt voor juiste processor volgorde via priority settings - EarlyTaxOrderProcessor: priority 300 (hoog = vroeg) - LateTaxOrderProcessor: priority 50 (laag = laat)

Shipping Method Architecture

Standard Drupal Commerce shipping methods: - flat_rate - vast tarief - flat_rate_per_item - per item tarief - Geen out-of-the-box support voor tiered pricing

Custom plugin extends: - ShippingMethodBase - Implementeert calculateRates(ShipmentInterface $shipment) - Haalt country code uit shipping profile address - Telt quantity van specifieke variation type

Plugin discovery: - Annotatie: @CommerceShippingMethod - PSR-4 autoloading via namespace - Cache clear nodig na nieuwe plugin

DNS & Hosting

IP adres: 37.97.221.249 (TransIP VPS)

Subdomains actief: - dev.voedingsgeneeskunde.nl - development - design.voedingsgeneeskunde.nl - design mockups - docs.voedingsgeneeskunde.nl - documentatie (deze site) - joost.voedingsgeneeskunde.nl - test environment - redactie.voedingsgeneeskunde.nl - redactie backend - voedingsgeneeskunde.nl - live production (nieuw) - nieuw.voedingsgeneeskunde.nl - redirect naar main (backwards compatibility)

Oude subdomains verwijderd: - d8dev.voedingsgeneeskunde.nl - d8live.voedingsgeneeskunde.nl

Bestanden Gewijzigd

Core Files

  • /web/modules/contrib/commerce/ - patch toegepast
  • composer.json - patch referentie toegevoegd

Custom Code

  • /web/modules/custom/vg_commerce/src/Plugin/Commerce/ShippingMethod/TieredShipping.php - NEW

Configuration

  • /web/sites/default/settings.php - trusted_host_patterns
  • Commerce tax type BTW: display_inclusive: false

Apache

  • /etc/apache2/sites-available/voedingsgeneeskunde.nl.conf - NEW
  • /etc/apache2/sites-available/voedingsgeneeskunde.nl-le-ssl.conf - NEW (Certbot)
  • /etc/apache2/sites-available/nieuw.voedingsgeneeskunde-redirect.conf - NEW
  • /etc/apache2/sites-available/nieuw.voedingsgeneeskunde-redirect-ssl.conf - NEW

Testing Checklist

  • B2B BTW berekening correct (korting voor BTW)
  • BTW split 9%/21% werkt
  • Los nummer: geen korting
  • VGBC ticket: wel korting
  • Verzending verschijnt in checkout
  • Verzending staffel configureerbaar via UI
  • Hoofddomein voedingsgeneeskunde.nl bereikbaar
  • SSL certificaat actief
  • Subdomain nieuw redirect naar main
  • Trusted hosts ingesteld
  • DNS propagatie voltooid (in progress - 24-48u)

Volgende Stappen

Prioriteit 1: Testing

  1. VGBC Fase 2 testing (4 scenarios)
  2. BTW verificatie op orders >=56
  3. Views configuratie review winkel
  4. Verzending staffel testen met verschillende landen/aantallen

Prioriteit 2: Cleanup

  1. Hardcoded waarden check (StandhouderQuotaValidator)
  2. Field_partner verificatie op customer profiles

Prioriteit 3: Live Migration

Webshop gaat morgen/overmorgen live: 1. Config export 2. Database backup 3. Oude test orders opschonen 4. Productieconfiguratie Mollie 5. DNS check (voedingsgeneeskunde.nl propagatie)

Toekomst: Fase 3

  • Multi-ticket checkout (meerdere attendees)
  • QR codes + commerce_license integratie
  • Student korting per attendee (niet per order)
  • TicketAssignmentPane voor attendee gegevens

Drupal.org Issues: - Commerce #2982355 - B2B Tax Calculation

Related Sessions: - 2025-12-28 BTW Prijsweergave Fix - 2025-12-16 Fase 2 Testing Checklist

Documentation: - Commerce Overview - Patches Overview

Tags

commerce tax btw b2b shipping dns apache ssl patch tiered-pricing