Betalingen¶
De webshop verwerkt online betalingen via Pay.nl. De integratie steunt op de
officiële SDK paynl/sdk (zie composer.json:58). Niet elke bestelling loopt over
Pay.nl: een deel van de B2B-betaalmethodes (op factuur, SEPA, bij levering, cash) wordt
buiten de gateway om afgehandeld. Deze pagina beschrijft welke betaalmethodes er zijn,
hoe de betaalflow loopt en hoe de bestelstatus wordt bijgewerkt.
Betaalmethodes¶
Een betaalmethode is een CountryPaymentCost-record
(_core/model/classes/atx/orders/CountryPaymentCost.php). Naast eventuele kosten legt
dit record vast om wat voor soort betaling het gaat
(CountryPaymentCost.php:30-34):
| Type | Constante | Betekenis |
|---|---|---|
0 |
TYPE_PAYNL |
Online betaling via de Pay.nl-gateway |
1 |
TYPE_SEPA |
SEPA-domiciliëring (incasso) |
2 |
TYPE_INVOICE |
Betaling op factuur |
3 |
TYPE_DELIVERY |
Betaling bij levering |
4 |
CASH |
Contant |
Alleen methodes die isAcquiredByGateway() zijn én een paynlId != 0 hebben, lopen
daadwerkelijk via Pay.nl (CountryPaymentCost.php:482, :575). De koppeling tussen
een betaalmethode en de Pay.nl-betaaloptie gebeurt via het veld paynlId. Dit veld
wordt beheerd in de backoffice (_admin/controller/classes/atx/orders/AdminPaymentController.php).
De lijst met beschikbare Pay.nl-betaaloptiess wordt live bij Pay.nl opgehaald per
land via PaynlService::getPaymentMethods()
(Paymentmethods::getList(['country' => $country])). Drie methodes worden manueel van
een leesbare naam voorzien: 706 → Visa and Mastercard, 710 → Carte Bleue,
138 → PAYPAL.
Configuratie¶
De Pay.nl-credentials staan in de setting-tabel onder de namespace atx\paynl
(keys paynl_id = Service ID en paynl_token = API-token). De SDK draait automatisch
in testmode zolang is_prod() onwaar is
($this->testMode = !is_prod(), _core/model/classes/atx/paynl/PaynlService.php).
Betaalflow¶
De volledige flow van checkout tot betaalde bestelling:
sequenceDiagram
participant K as Klant
participant CC as CartController
participant PS as PaynlService
participant PAY as Pay.nl
participant EX as ExchangeController
K->>CC: createOrder() (paymentMethod gekozen)
CC->>CC: Order aanmaken via OrderBuilder (Paymentmethod = 'Q')
Note over CC: gateway-check: isAcquiredByGateway() && getPaynlId() != 0
CC->>PS: getPaymentUriForOrder(order, paymentMethod)
PS->>PAY: Transaction::start([...])
PAY-->>PS: TransactionId + redirect-URL
PS->>PS: TransactionId op order (Pay.nl); PaymentId = lokaal DB-id betaalmethode
CC-->>K: redirect document.location = Pay.nl-URL
K->>PAY: betaalt op Pay.nl
PAY->>EX: server-to-server callback (exchangeUrl /exchange)
EX->>EX: CheckPaymentStatus → orderstatus bijwerken
PAY-->>K: redirect terug naar returnUrl (pagina 'bestelling')
K->>CC: orderCallback() → winkelwagen leegmaken + UI tonen
1. Bestelling en transactie starten¶
De checkout-submit komt binnen in CartController::createOrder()
(_core/controller/classes/atx/customers/cart/CartController.php). De gekozen
betaalmethode wordt opgezocht (CountryPaymentCostDAO::getById()) en de bestelling
wordt opgebouwd via OrderBuilder (src/Atraxion/Order/Builder/OrderBuilder.php).
Zolang de betaling nog niet rond is, krijgt de order voorlopig Paymentmethod = 'Q'.
Bij de gateway-check (CartController.php:1388) wordt voor een Pay.nl-methode
PaynlService::getPaymentUriForOrder() aangeroepen (CartController.php:1394). Daarin
gebeurt de SDK-aanroep Transaction::start([...])
(PaynlService.php:148) met onder meer:
amount=$order->getRealTotalPrice();paymentMethod=$paymentMethod->getPaynlId();orderNumber= het ordernummer;returnUrl= de paginabestelling(waar de klant naar terugkeert,PaynlService.php:162);exchangeUrl=/exchange(de server-to-server callback,PaynlService.php:163);expireDate=+1 week,testmode, taal, en klantgegevens alsextra-velden.
De ontvangen TransactionId wordt op de order gezet via $result->getTransactionId().
Het veld PaymentId wordt niet uit de Pay.nl-respons gehaald; het wordt gevuld via
$order->setPaymentId($paymentMethod->getId()) — dat is het lokale DB-id van de
CountryPaymentCost-rij (PaynlService.php:169). Beide velden worden daarna
opgeslagen via OrderDAO::updateObject(). De view voert vervolgens een
document.location = url uit om de klant naar Pay.nl te sturen
(CartView.php rond regel 1701).
2. Retour-URL (klant keert terug)¶
Na betalen stuurt Pay.nl de klant terug naar de pagina bestelling, afgehandeld door
CartController::orderCallback() (CartController.php rond regel 1821). Hier wordt de
transactiestatus rechtstreeks opgevraagd (Transaction::status($transactionId)) en
wordt — als de betaling betaald of geautoriseerd is — de winkelwagen leeggemaakt
(CartArticleDAO::deleteCart()) en de bevestigings- of annuleringspagina getoond.
Let op: de retour-URL werkt de orderstatus niet zelf bij — dat doet uitsluitend de exchange-callback. De retour-handler dient alleen voor het opruimen van de winkelwagen en de UI.
3. Exchange-callback (statusverwerking)¶
De feitelijke statusverwerking gebeurt server-to-server via de route
GET|POST /exchange → ExchangeController::index()
(_core/config/router.php:87). De controller:
- schrijft
TRUE|naar de response-body (vereiste van Pay.nl); - valideert het bron-IP via
Validate::isPayServerIp()in productie (in dev wordt het Pay.nl-test-IP toegelaten); - haalt de transactie op (
Transaction::status()enTransaction::get()); - zoekt de order via het ordernummer en slaat over als de order niet bestaat, geen
TransactionIdheeft of al betaald is; - delegeert naar
CheckPaymentStatus::checkPaymentStatus()(src/Atraxion/Exchange/Service/CheckPaymentStatus.php).
Statusafhandeling¶
CheckPaymentStatus vertaalt de Pay.nl-status naar de betaal- en orderstatus
(CheckPaymentStatus.php):
| Pay.nl-status | Orderstatus | Acties |
|---|---|---|
isBeingVerified() |
STATUS_PENDING |
interne notitie + verificatiemail (VerifyOrder) naar office@atraxion.com, in CC naar logs@atraxion.com en ignace.knops@gmail.com (VerifyOrder.php:17–19) |
isPaid() |
STATUS_NEW |
setIsPaid(), betaalkostenregel toevoegen, orderbevestiging mailen, naar ERP sturen, loyaliteitspunten bevestigen |
isAuthorized() |
STATUS_NEW |
eerst Transaction::capture(), daarna identiek aan isPaid() |
isCancelled() |
STATUS_CANCELLED |
order opslaan |
| overig | ongewijzigd | status UNKNOWN |
De betaalmethodenaam, het betaalde bedrag en de munteenheid worden altijd uit de
transactie overgenomen (getPaymentMethodName(), getAmountPaid(),
getAmountPaidCurrency()).
Bij een succesvolle betaling worden in dezelfde stap ook de geautomatiseerde
vervolgacties uitgevoerd: de orderbevestiging (zie
Notificaties & e-mails), het doorsturen naar Odoo (ERP)
inclusief eventuele Transsmart-boeking (zie Verzending) en het
bevestigen van de loyaliteitspunten via
loyaltyPointsService->confirmByOrder() (CheckPaymentStatus.php:117).
De mogelijke betaalstatussen zelf staan in
_core/model/classes/atx/orders/OrderPaymentStatus.php: REQUESTED, PENDING,
PAID, CANCELED, REFUNDED, AUTHORIZED, BEING_VERIFIED, UNKNOWN.
Inzicht in de backoffice¶
Bij het openen van een bestelling met een TransactionId haalt de backoffice de
actuele Pay.nl-transactiegegevens op via Transaction::get()
(src/Atraxion/Admin/Controller/OrderController.php rond regel 108), zodat de
betaalstatus naast de order zichtbaar is.
Zie ook¶
- Winkelwagen & checkout — waar de betaalmethode wordt gekozen.
- Bestellingen & orderverwerking — de orderstatussen.
- Integraties — de Pay.nl-koppeling technisch.