Voorraadimport¶
Atraxion betrekt banden, velgen en accessoires bij meerdere leveranciers. Elke leverancier levert periodiek een stockbestand (CSV via FTP of HTTP-download). De import-pipeline leest dat bestand, koppelt elke regel aan een intern artikel, berekent de verkoopprijs en schrijft het resultaat naar article_stock — de tabel die de webshop gebruikt voor voorraadweergave en bestelbaarheid.
Architectuur¶
flowchart TD
A[Leverancier stockbestand\nCSV op FTP of HTTP-URL] -->|Download| B[_externestock/]
B --> C[UpdatingSupplierStockController\n::importStock]
C --> D{Guard-checks\nbestand aanwezig?\noud genoeg?\nProcessFile aan?}
D -- Nee --> E[Stock op 0 zetten\nAlert mail logs@atraxion.com]
D -- Ja --> F[Parse CSV\nAdminSupplierStockDAO\n::getInfoFromFile]
F --> G[Batch upsert\nsupplier_stock]
G --> H[Artikel-koppeling\nAdminLinkSupplierDAO]
H --> I[Marge/prijs berekening\nAdminMarginDAO]
I --> J[Batch upsert\narticle_stock]
J --> K[Validatie-flag\nprijswijziging > drempel?]
K -- Ja --> L[Validated=0\nReview-wachtrij]
K -- Nee --> M[Validated=1\nOnmiddellijk zichtbaar]
Hoofdscripts:
| Script | Doel |
|---|---|
_shopupdating/index_checkAllLevs.php |
Alias → checkAllSupplierStock.php |
_shopupdating/cronjobs/atx/suppliers/stock/checkAllSupplierStock.php |
Alle actieve leveranciers verwerken |
_shopupdating/cronjobs/atx/suppliers/stock/checkSupplierStock.php |
Één leverancier ($argv[1] = Levnr, $argv[2] = updateAnyway) |
_shopupdating/index_checkLevFile.php |
Alias → checkSupplierStock.php |
_shopupdating/cronjobs/atx/articles/stock/export.php |
Verwerkte stock exporteren naar channels/platformen |
Stap 1 — Instellingen laden¶
UpdatingSupplierStockController::importStock leest supplier_import_settings (joined aan supplier) via AdminSupplierImportSettingsDAO::getImportSettings().
Belangrijkste instellingen per leverancier:
| Instelling | Betekenis |
|---|---|
ProcessFile |
Schakelaar — als false: bestaande stock verwijderen en alert sturen |
File |
Pad relatief aan _externestock/ |
SourceFile / SourcePriceFile |
Externe URL om het bestand van te downloaden |
MaxLifeTime |
Maximale bestandsleeftijd in uren (productie only) |
Encoding |
Bestandscodering (standaard ISO-8859-1) |
Delimiter / Enclosure / Escape |
CSV-parseerinstellingen |
CountColumnHeadings |
Aantal headerrijen om over te slaan |
Lev_fabpos / Lev_fabpos2 |
CSV-kolom voor fabrikantcode (primair/secundair) |
Lev_eanpos / Lev_eanpos2 |
CSV-kolom voor EAN (primair/secundair) |
Lev_tyre24pos |
CSV-kolom voor Tyre24-identificator |
Lev_artnrpos |
CSV-kolom voor eigen artikelnummer van de leverancier |
Prijspos / Stockpos |
CSV-kolom voor inkoopprijs respectievelijk voorraadaantal |
CheckSizes |
Valideer maten bij Fabcode-koppeling |
ProductGroups |
JSON-array om te beperken tot bepaalde productgroepen |
odooEdiRelay |
Odoo EDI-relay-vlag |
Stap 2 — Bestand downloaden¶
DownloadRemoteStockFiles::downloadFiles() (_core/model/classes/atx/suppliers/stock/DownloadRemoteStockFiles.php) controleert SourceFile/SourcePriceFile. Als ingesteld: downloaden via file_get_contents (HTTP, time-out 10 s) naar _externestock/<File>.
Stap 3 — Guard-controles¶
Vóór verwerking worden vier controles uitgevoerd. Bij mislukking: stock op 0, alert e-mail naar logs@atraxion.com:
| Conditie | Gevolg |
|---|---|
ProcessFile = false |
Stock verwijderen, alert |
Bestand bestaat niet op APP_EXTERNESTOCK_PATH/<File> |
Stock verwijderen, alert |
Bestandsleeftijd > MaxLifeTime uur (prod. only) |
Stock verwijderen, alert |
Bestand-mtime ≤ supplier.StockUpdated én geen updateAnyway |
Stilzwijgend overslaan |
Stap 4 — CSV parsen¶
AdminSupplierStockDAO::getInfoFromFile (_admin/model/dbclasses/atx/suppliers/stock/AdminSupplierStockDAO.php)
Bestand openen met fgetcsv. Codering naar UTF-8 omzetten indien nodig.
Als PriceFile is ingesteld, wordt dit bestand als eerste geparsed in drie opzoektabellen (EAN / Fabcode / leverancierartikelnummer → prijs).
Per CSV-rij maakt newObject() een SupplierStock-object aan met:
Levartnr(extern ID): leverancierartikelnummer → EAN → Fabcode → Tyre24Ident (volgorde)EancodeuitLev_eanposFabcodeuitLev_fabpos(ofLev_fabpos2)Tyre24IdentuitLev_tyre24posAkprijsuitPrijspos(overschreven door prijsbestand indien aanwezig)StockuitStockpos(tekens<,>,+en spaties worden verwijderd)- Maatgegevens uit hun respectieve kolomposities
Demo-vlag uitDemopos(positieve waarden:y,j,yes,ja,x,1)
Leveranciersspecifieke uitzonderingen (hardgecodeerd op Levnr in fillSizes()):
| Levnr | Uitzondering |
|---|---|
| 3 (TD) | Bandenmaat parsen uit omschrijvingsstring |
| 6 | x/bla opschonen in gaataantal |
| 7 (DELDO) | Omschrijving opbouwen uit meerdere kolommen |
| 11 | PCD-formaat splitsen (5x130+5x112) |
| 12 | Omschrijving verdubbelen |
| 14 | / verwijderen uit serie-veld |
Stap 5 — Upsert in supplier_stock¶
AdminSupplierStockDAO::addMultipleRecords — enkele batch INSERT IGNORE … ON DUPLICATE KEY UPDATE. Na de insert zet setStockToZero() alle rijen met importVersion < huidig op Stock = 0, IsDeleted = 1 (rijen die in het huidige bestand niet voorkwamen).
Stap 6 — Artikel-koppeling¶
AdminLinkSupplierDAO (_admin/model/dbclasses/atx/suppliers/stock/AdminLinkSupplierDAO.php)
Bestaande koppelingen worden eerst gewist: DELETE FROM supplier_link WHERE Levnr = :Levnr.
Koppeling gebeurt via INSERT IGNORE in de volgende prioriteitsvolgorde (de eerste match wint):
| Prioriteit | Match-type | Veld | GekoppeldOp |
|---|---|---|---|
| 1 | Fabcode2 | article.Fabcode2 = supplier_stock.Fabcode |
'f' |
| 2 | Fabcode | article.Fabcode = supplier_stock.Fabcode |
'f' |
| 3 | EAN2 | article.Eancode2 = supplier_stock.Eancode |
'e' |
| 4 | EAN | article.Eancode = supplier_stock.Eancode |
'e' |
| 5 | Tyre24Ident | article_tyre.Tyre24Ident = supplier_stock.Tyre24Ident |
't' |
Bij Fabcode-koppeling worden maten gevalideerd als CheckSizes = 1:
- Banden: Breedte, Serie en Inch moeten overeenkomen.
- Velgen: Velgbreedte, Velginch, Gaten, DiamGaten, Et en CTR moeten overeenkomen.
Alle koppelvragen bevatten de filter: article.Active = TRUE, article.CanBeSold = TRUE, article.Dot IS NULL, supplier_stock.IsDeleted = 0.
Na koppeling ruimt deleteRemovedStockLinks verouderde supplier_link-rijen op.
Stap 7 — Marge- en prijsberekening¶
AdminLinkSupplierDAO::getExtArticlesWithStock haalt gekoppelde artikelen op met Stock >= MinimumStock (uit supplier.MinimumStock). Per artikel:
netMarginsuitarticle_stock_margin WHERE Marge > 0 OR Nettoprijs > 0tarifMarginsuitarticle_stock_margin WHERE VasteKorting > 0Netprijsberekend als:- Inkoopprijs > 0 + nettomarge gevonden:
Akprijs × marge + cte - Anders tariefmarge:
(StandardPrice − StandardPrice × VasteKorting%) + cte - Speciale regel: als
Akprijs = 0énPrijspos > 0, wordt de voorraad geforceerd op 0 (Latexhurt-workaround). - Gewichtsgebaseerde toeslagen worden op prijs opgeteld als er overeenkomende
WeightBasedPrice-regels bestaan.
Stap 8 — Upsert in article_stock¶
AdminStockDAO::addMultipleRecords (_admin/model/dbclasses/atx/articles/stock/AdminStockDAO.php)
Batch INSERT … ON DUPLICATE KEY UPDATE naar article_stock:
- Velden:
ArtnrLevnr, Artnr, Levnr, HasStock, Stock, Akprijs, PurchasePrice, Netprijs, Updated, Validated, LastValidatedPrice.
Prijsvalidatiemechanisme:
Het veld Validated bepaalt of een artikel direct zichtbaar is of in de review-wachtrij belandt:
ATX_PERCENTAGE_CHANGE(nieuwe_prijs, LastValidatedPrice) <= AllowedPercentageChange→Validated = 1(direct zichtbaar).- Prijssprong te groot →
Validated = 0→ artikel belandt in de review-wachtrij; een medewerker beoordeelt de prijs manueel.
Auto-validatie cross-check: na de upsert valideert een tweede query ongevalideerde rijen waarbij een gevalideerde concurrent een prijs heeft binnen −15%.
setStockToZero zet article_stock-rijen op nul die hun koppeling verloren of onder MinimumStock zijn gezakt.
Stap 9 — Tijdstempel bijwerken¶
AdminSupplierDAO::saveFileTime($supplierNumber, $dtFile) schrijft de mtime van het bestand naar supplier.StockUpdated.
Datamodel¶
| Tabel | Inhoud |
|---|---|
supplier |
Leverancier-stamdata: Levnr, Levnaam, MinimumStock, MaxAllowedPriceDifference, StockUpdated, importVersion |
supplier_import_settings |
Import-instellingen per leverancier: bestandspaden, CSV-kolomposities, drempelwaarden |
supplier_stock |
Ruwe importregels per leverancier (staging) |
supplier_link |
Koppeling supplier_stock.Levartnr → article.Artnr (veld GekoppeldOp: f/e/t) |
article_stock |
Definitieve voorraad + prijs per artikel per leverancier (gebruikt door de webshop) |
article_stock_margin |
Margeregels per leverancier, categorie, merk, type en maat |
article_stock_history |
Historische snapshots per leverancier en artikelnummer |
Stockbestanden staan op schijf in _externestock/ (APP_EXTERNESTOCK_PATH).
Belangrijkste klassen¶
| Klasse | Locatie |
|---|---|
UpdatingSupplierStockController |
_admin/controller/classes/atx/suppliers/stock/ |
UpdatingSupplierStockWorker |
_admin/controller/classes/atx/suppliers/stock/ |
AdminSupplierImportSettingsDAO |
_admin/model/dbclasses/atx/suppliers/stock/ |
AdminSupplierStockDAO |
_admin/model/dbclasses/atx/suppliers/stock/ |
AdminLinkSupplierDAO |
_admin/model/dbclasses/atx/suppliers/stock/ |
AdminStockDAO |
_admin/model/dbclasses/atx/articles/stock/ |
AdminMarginDAO |
_admin/model/dbclasses/atx/articles/stock/ |
SupplierImportSettings |
_core/model/classes/atx/suppliers/stock/SupplierImportSettings.php |
SupplierStock |
_core/model/classes/atx/suppliers/stock/SupplierStock.php |
DownloadRemoteStockFiles |
_core/model/classes/atx/suppliers/stock/DownloadRemoteStockFiles.php |
Kruislinks¶
- Externe platformen — verwerkte stock wordt daarna geëxporteerd naar platform-channels
- Productcatalogus —
article_stockbepaalt wat zichtbaar en bestelbaar is in de catalogus - Crons & queue — cron-frequentie en queue-verwerking voor importscripts
- Admin & backoffice — validatie-review en prijsbeheer in
AdminSupplierControllerenAdminStockController