Bestellingen & orderverwerking¶
Een bestelling in de Atraxion-webshop doorloopt een vaste lifecycle van aanmaak tot facturatie. De centrale klasse is Order (_core/model/classes/atx/orders/Order.php); de verwerking loopt via OrderService (_core/model/classes/atx/orders/OrderService.php) en de koppeling met het ERP via Odoo\Service\UploadOrders (src/Odoo/).
Orderstatussen¶
| Status | Constante | Waarde | Betekenis |
|---|---|---|---|
| In afwachting | Order::STATUS_PENDING |
99 |
Bestelling aangemaakt, wacht op betaling (Pay.nl) |
| Nieuw | Order::STATUS_NEW |
0 |
Bestelling bevestigd, klaar voor verwerking |
| Reservering | Order::STATUS_RESERVATION |
1 |
Artikel gereserveerd bij leverancier |
| Gefactureerd | Order::STATUS_INVOICE |
2 |
Verzonden en gefactureerd vanuit Odoo |
| Geannuleerd | Order::STATUS_CANCELLED |
3 |
Bestelling geannuleerd |
| Voltooid | Order::STATUS_COMPLETE |
10 |
Order volledig afgehandeld |
Referentie: Order.php:44-55.
Stroomschema¶
flowchart LR
A[Bestelling aangemaakt] --> B{Betaalmethode}
B -->|Pay.nl| P[STATUS_PENDING\nbetaling via gateway]
B -->|Op rekening / domiciliëring| N[STATUS_NEW]
P -->|Betaling geslaagd\ncallback| N
P -->|Betaling mislukt / verlopen| C[STATUS_CANCELLED]
N --> R[STATUS_RESERVATION\nreservering leverancier]
R --> I[STATUS_INVOICE\nverzonden + factuur Odoo]
I --> D[STATUS_COMPLETE]
N --> C
Order lifecycle¶
1. Aanmaak¶
Nadat de klant de checkout bevestigt, maakt CartController::doCreateOrder() (CartController.php:1460) een Order-object aan met:
- Klantgegevens (
Klantnr,Username) - Orderartikelen (
OrderArticle[]) met prijs, leverancier, leveringsdagen - Leveringsadres(sen) (
OrderAddress[]) - Transportkosten, betalingskosten
- Orderhash (deduplicatie via twee lagen,
CartController.php:1302–1351): - Als
$_SESSION['order_id']aanwezig is: de bijbehorende order wordt opgehaald. Als de hash overeenkomt → hergebruikt. Als de hash niet overeenkomt → de bestaande order wordt geannuleerd en de sessie wordt gewist. - Als er geen sessie-order is: hash-gebaseerde lookup. Als er een
STATUS_PENDING-order met dezelfde hash bestaat → hergebruikt in plaats van een nieuwe aan te maken.
De order en de bijbehorende artikelen en adressen worden via OrderDAO, OrderArticleDAO en OrderAddressDAO opgeslagen.
2. Bevestiging & e-mail¶
OrderService::sendOrderMail() (OrderService.php:227) verstuurt:
- Interne bevestiging — e-mail naar Atraxion-medewerkers met inkoopprijs-referentie (
createInternalOrderMail) - Klantbevestiging — e-mail naar de klant op basis van de
orderconfirmation-template
3. Doorsturen naar Odoo ERP¶
OrderService::sendOrderToErp() (OrderService.php:1126) roept UploadOrders::uploadSingle() (OrderService.php:1150) aan om de order te synchroniseren met het Odoo ERP-systeem. Dit gebeurt alleen in productie en alleen als zowel de klant als de logingebruiker geaccepteerd zijn (OrderService.php:1149):
if ($customer->isAccepted() && (!$login || $login->isAccepted()))
Een geaccepteerde klant wiens logingebruiker nog niet geaccepteerd is, triggert dus geen ERP-upload.
Odoo ontvangt de order als verkooporder (SO) en verwerkt de leveranciersinkoop, de reservering bij de leverancier en de facturatie. Odoo-ID's worden teruggeschreven naar Order::OdooId en Order::SaleOrderName.
Zie Integraties voor de technische details van de Odoo-koppeling.
4. Facturatie¶
Wanneer een bestelling door Odoo wordt gefactureerd en verzonden, wordt de status bijgewerkt naar STATUS_INVOICE. De bijbehorende factuurgegevens (Invoice) en zendingstracking (ShipmentTracking) worden teruggekoppeld vanuit Odoo naar de webshop-database en zijn zichtbaar in de klantomgeving.
Gesplitste bestellingen¶
Splitsing per voertuigchassis ("te monteren")¶
Wanneer de winkelwagen artikelen bevat die te monteren zijn bij een specifiek voertuigchassis, splitst CartController::splitCart() de bestelling op per chassis-nummer. Elk deelorder wordt afzonderlijk opgeslagen, bevestigd en naar Odoo gestuurd. De klant ontvangt bevestigingen per deelorder.
Splitsing op productcategorie¶
Voor bepaalde klanten (gemarkeerd via CustomerTag) kan de bestelling worden gesplitst op productcategorie. OrderSplittingService::shouldSplitOrdersByCategory() controleert dit en stuurt zo nodig door naar splitCartByProductCategories(). Bij categorie-splitsing wordt de factuur op een andere facturatierelatie gelegd (InvoiceCustomer).
Orderdocumenten¶
Klanten kunnen PDF-bestanden koppelen aan een order via het document-portaal (DocumentPortalController, route /order-documents/{hash}/{token}/upload). De upload-aanroep binnen DocumentPortalController::uploadDocument() zet uploadedBy altijd op 'customer' hardgecodeerd (DocumentPortalController.php:88) — er is geen aparte admin-upload. Atraxion-medewerkers kunnen de portaallink vanuit de backoffice delen of bekijken, maar uploaden via diezelfde portal-URL als de klant. De verdere verwerking loopt via de OrderDocumentService (src/Atraxion/Module/OrderDocuments/Service/OrderDocumentService.php).
Upload & opslag¶
Bij upload (OrderDocumentService::uploadDocument(), OrderDocumentService.php:41):
- Validatie: alleen PDF, maximaal 5 MB, extensie en MIME-type worden gecontroleerd
- Bestand wordt opgeslagen in
APP_STATIC_PATH/order_documents/{jaar}/{maand}/{orderId}/ - Bestandsnaam is uniek (
{orderId}_{random}_{timestamp}.pdf) - Een
OrderDocument-entity (src/Atraxion/Module/OrderDocuments/Model/OrderDocument.php) wordt aangemaakt in de database
Virusscan (VirusTotal)¶
Na upload wordt het bestand asynchroon gescand via de VirusTotal-API (VirusScannerInterface, src/VirusTotal/). Het scanproces:
virusScanner->scanFile($filePath)dient het bestand in en geeft eenanalysisIdterug- De
OrderDocumentkrijgt statusVIRUS_SCAN_STATUS_SCANNING - Bij voltooiing wordt de status bijgewerkt naar
VIRUS_SCAN_STATUS_CLEAN,VIRUS_SCAN_STATUS_INFECTEDofVIRUS_SCAN_STATUS_ERROR - Geïnfecteerde bestanden worden in quarantaine geplaatst (
isQuarantined = true)
Een document is alleen toegankelijk als het de status clean heeft en niet in quarantaine zit (OrderDocument::isSafeToAccess(), OrderDocument.php:277).
De viruscan mislukt niet de upload: als de scan-API niet beschikbaar is, wordt het document toch opgeslagen maar blijft de status op pending (OrderDocumentService.php:105-111).
Odoo-upload¶
Na een geslaagde viruscan worden documenten asynchroon doorgestuurd naar Odoo — niet synchroon bij de upload zelf. Het CLI-command order-documents:check-virus-scans (CheckVirusScanResultsCommand.php) pollt de VirusTotal-resultaten en start de Odoo-upload bij een schone scan. Bij fouten herprobeert order-documents:retry-odoo-uploads (RetryOdooUploadsCommand.php) de upload. Beide commands draaien via cron. Zie ook Crons & queue.
Het OrderDocument houdt bij:
odooUploadStatus:pending,uploadedoffailedodooSaleOrderAttachmentId— attachment-ID bij de Odoo-verkooporderodooStockPickingAttachmentId— attachment-ID bij de Odoo-pakbon
Via OdooDocumentUploadService (src/Atraxion/Module/OrderDocuments/Service/OdooDocumentUploadService.php) worden de PDF's als bijlage aan de relevante Odoo-objecten gekoppeld.
Orderstatussen van documenten¶
| Status | Constante | Betekenis |
|---|---|---|
| In afwachting | VIRUS_SCAN_STATUS_PENDING |
Nog niet gescand |
| Aan het scannen | VIRUS_SCAN_STATUS_SCANNING |
Scan in uitvoering bij VirusTotal |
| Veilig | VIRUS_SCAN_STATUS_CLEAN |
Geen malware gevonden |
| Besmet | VIRUS_SCAN_STATUS_INFECTED |
Malware gedetecteerd, in quarantaine |
| Fout | VIRUS_SCAN_STATUS_ERROR |
Scan kon niet worden voltooid |
Referentie: OrderDocument.php:15-19.
Orderreferenties en deduplicatie¶
Elke order heeft een OrderHash die berekend wordt op basis van de winkelwageninhoud. Bij aanmaak gebruikt de checkout een twee-laagse deduplicatiecontrole (CartController.php:1302–1351):
- Sessie-laag: als
$_SESSION['order_id']bestaat, wordt die order opgehaald. Als de hash overeenkomt → hergebruikt. Als de hash niet overeenkomt → de bestaande pending order wordt geannuleerd en de sessie wordt gewist. - Hash-laag: als er geen sessie-order is, wordt gezocht op
OrderHash. Als er eenSTATUS_PENDING-order met dezelfde hash bestaat (bijv. bij dubbelklikken of pagina-verversing) → hergebruikt in plaats van een nieuwe aan te maken.
Leveringsopties¶
Bij aanmaak van een order kiest de klant een leveringsvoorkeur:
| Optie | Constante | Waarde |
|---|---|---|
| Zo snel mogelijk | Order::DELIVERY_ASAP |
1 |
| Alles samen | Order::DELIVERY_TOGETHER |
2 |
| Vaste leveringsdatum | Order::DELIVERY_FIXED_DELIVERYDAY |
3 |
| Neutraal (dropship) | Order::DELIVERY_NEUTRAL |
4 |
Referentie: Order.php:39-42.
Gerelateerde pagina's¶
- Winkelwagen & checkout — aanmaak van een bestelling vanuit de winkelwagen
- Betalingen — Pay.nl callback en statusverwerking
- Verzending — Transsmart en transportprijzen
- Integraties — Odoo ERP- en VirusTotal-koppeling
- EDI / B2B — orders via EDI/XML