=== Arvas Product Sync ===
Contributors: arvas
Donate link: https://arvashosting.eu
Tags: woocommerce, import, voorraad, variaties, kassa
Requires at least: 6.4
Tested up to: 7.1
Requires PHP: 7.4
WC requires at least: 8.0
WC tested up to: 11.0
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Synchroniseert een kassa-export naar WooCommerce als variabele producten met kleur, maat en lengte als variaties.


== Description ==

Dit is de gratis LITE-editie. Die bevat de volledige import: ophalen bij de
kassaserver, variabele producten met kleur, maat en lengte, merken, dry-run,
diagnose, batchverwerking en de bescherming tegen halve downloads.

De PRO-editie voegt daaraan toe:

* Fotokoppeling via een leveranciersexport met foto's en CSV
* Categorie-afdelingen (Dames > T-shirt, Heren > T-shirt)
* Merken en categorieen uitsluiten
* Knop om de categorie-indeling opnieuw op te bouwen
* GTIN/EAN-controle en herstelfunctie
* Servercron-script voor volautomatische sync
* Een jaar updates en support

Eenmalig 99 euro. Zie https://verkoop.arvashosting.eu

De kassa draait vrijwel nooit op dezelfde server als de webshop. Deze plugin is
daarop gebouwd: hij haalt de export op bij de kassaserver, controleert de
download, en schrijft de producten native in WooCommerce (geen REST-API).

Wat de plugin doet:

* Leest een kassa-export (CSV/TXT zonder kopregel, 73 kolommen)
* Filtert op locatie (standaard alleen locatie 1)
* Bouwt per merk + modelnaam een variabel product met Kleur, Maat en - waar van
  toepassing - Lengte als variatie-assen
* Maakt categorieen aan als boom: afdeling (Dames/Heren/Geuren) op basis van de
  categoriecode, met de categorienaam eronder
* Schrijft merken naar alle actieve merk-taxonomieen (WooCommerce core en/of een
  thema-eigen variant zoals XStore)
* Vult EAN's in het GTIN-veld
* Werkt bestaande producten bij in plaats van duplicaten te maken
* Draait automatisch in blokken, met een tijdsbudget tegen timeouts

== 1. De verbinding met de kassaserver ==

Ga naar WooCommerce > Arvas Sync en kies bij "Waar staat het bestand?":

= A. Op DEZE server (lokaal pad) =

Alleen als de webshop draait op dezelfde machine waar de kassa de export
neerzet. Vul het absolute pad in, bijvoorbeeld /home/gebruiker/winstore. Het pad
mag een MAP of een BESTAND zijn; bij een map pakt de plugin het nieuwste bestand,
ook zonder extensie.

Werkt het pad niet, dan verschijnt een diagnose-tabel met wat PHP werkelijk ziet.
Veelvoorkomende oorzaken: open_basedir (PHP mag niet buiten de webroot lezen) of
onvoldoende rechten (map 755, bestand 644).

= B. Op een ANDERE server (gebruikelijk) =

De plugin haalt het bestand op, bewaart het in een afgeschermde cachemap en
verwerkt het daarna lokaal.

Vul in: protocol, host, poort, pad naar het bestand (GEEN URL), gebruiker en
wachtwoord. Het URL-veld is alleen voor de HTTPS-modus.

Protocolkeuze, in deze volgorde:

1. SFTP (poort 22, versleuteld). De plugin probeert de PHP ssh2-extensie en valt
   terug op cURL met sftp-ondersteuning. Een gebruikersnaam in e-mailvorm is
   meestal een FTP-account zonder SSH; SFTP loopt dan in een timeout.
2. FTPS (poort 21, versleuteld). Meestal de juiste keuze bij een FTP-account.
3. FTP (onversleuteld). Alleen als het niet anders kan.
4. HTTPS, als de export via een webadres bereikbaar is.

Onder "Mogelijkheden van deze server" staat welke routes beschikbaar zijn.

= Het juiste pad vinden =

FTP-accounts zijn bijna altijd opgesloten in hun eigen thuismap. Wat de server
intern kent als /home/gebruiker/winstore/Export.txt is voor het FTP-account vaak
gewoon /Export.txt. Gebruik "Externe map bekijken": vul / in en klik op "Map
tonen" om te zien waar het account uitkomt en hoe de bestanden heten
(hoofdletters tellen mee).

= Wachtwoord =

Het invulveld volstaat. Wil je het wachtwoord niet in de database, zet het dan in
wp-config.php:

    define( 'ARVAS_WOO_SYNC_REMOTE_PASS', 'het-wachtwoord' );

Die constante heeft voorrang op het invoerveld.

= Beveiliging tegen kapotte downloads =

Een half opgehaald bestand is gevaarlijk: ontbrekende artikelen zouden als "weg
uit de feed" gelden en hun voorraad op nul krijgen. De plugin haalt daarom eerst
op naar een tijdelijk bestand en neemt dat pas in gebruik na controle. De import
breekt af als het bestand kleiner is dan 1 kB, minder dan 10 regels heeft, of
meer dan de ingestelde veiligheidsdrempel (standaard 40%) gekrompen is ten
opzichte van de vorige geslaagde run.

== 2. Draaien ==

= Eerste import =

1. Laat Dry-run AAN. Er wordt dan niets weggeschreven.
2. Vul bij "Alleen deze artikelnummers" een handvol nummers in.
3. Klik "Test import nu" en controleer het rapport.
4. Klopt het? Zet Dry-run uit en klik "Nu echt importeren" voor diezelfde nummers.
5. Controleer het resultaat in WooCommerce, leeg daarna het testveld.

= Batches en tijdsbudget =

Een volledige catalogus past niet in een PHP-request. De plugin verwerkt per run
een blok producten (standaard 40) en stopt zichzelf na het tijdsbudget
(standaard 20 seconden), ruim onder de timeout van de webserver. De positie
wordt bewaard; de volgende run gaat verder waar deze ophield. Na een onvolledige
ronde plant de plugin zelf een vervolgrun in.

De voortgangsbalk toont welk product aan de beurt is. "Ronde afgerond" betekent
dat de hele catalogus is langsgeweest.

= Automatisch draaien =

De plugin plant een WP-Cron van 30 minuten. WP-Cron draait echter alleen als
iemand de site bezoekt, dus op een rustige webshop kan een sync uitblijven.

De Pro-editie bevat een kant-en-klaar servercron-script met slot en logboek, dat
buiten de webroot draait.

= Snelheid =

Producten waarvan voorraad, prijs, naam, EAN en attributen ongewijzigd zijn,
worden overgeslagen. Na de eerste volledige ronde zijn de runs daardoor kort.

== 3. Productstructuur ==

= Variabele producten =

Alles wordt een variabel product: per merk + modelnaam een product met Kleur,
Maat en (bij jeans) Lengte als variatie-assen. Er worden geen gegroepeerde
producten aangemaakt.

Dragen twee artikelnummers binnen hetzelfde model dezelfde kleurnaam - twee
bruintinten, of hetzelfde model uit twee seizoenen - dan verduidelijkt de plugin
het label automatisch: eerst met de leverancierskleur ("Bruin (Camel)") en zo
nodig met het artikelnummer erachter. Zonder die verduidelijking zou WooCommerce
de tweede variatie weigeren.

De parent-SKU is standaard de modelnaam uit de feed. De variatie-SKU is de
interne barcode; die is altijd gevuld en uniek.

= Categorieen =

Producten komen in de categorie die de kassafeed aangeeft.

In Pro wordt daar een afdeling boven gezet op basis van de categoriecode, zodat
je Dames > T-shirt en Heren > T-shirt krijgt in plaats van twee losse
categorieen. Pro voegt ook het uitsluiten van merken en categorieen toe, en een
knop om de indeling volledig opnieuw op te bouwen.

= Merken =

De plugin schrijft naar alle actieve merk-taxonomieen. Draait er een thema met
eigen merken (zoals XStore) naast de WooCommerce-core, dan worden beide gevuld,
zodat het merk zowel in Woo als in het thema klopt.

= Uitsluiten =

Merken en categorieen die niet in de webshop horen, vul je in bij "Merken
uitsluiten" en "Categorieen uitsluiten". Reeds bestaande producten blijven
staan; die verwijder je zelf.

= Handmatige aanpassingen =

De producttitel wordt alleen gezet bij nieuwe producten, zodat handmatig
aangepaste titels blijven staan. Categorieen volgen wel de kassafeed; zet
"Categorieen beschermen" aan als je de indeling zelf beheert. Voorraad, prijs en
variaties worden altijd bijgewerkt.

== 4. GTIN / EAN ==

EAN's uit de feed komen in het GTIN-veld van de variatie. WooCommerce staat een
GTIN maar bij een product toe; houdt een ouder product de code nog vast, dan
slaat de plugin het veld over en meldt dat in het rapport - de variatie zelf
wordt gewoon opgeslagen.

In Pro zit een controle die laat zien hoeveel variaties een GTIN hebben, met een
knop om ontbrekende codes alsnog aan te vullen.

Levert de kassa voor bepaalde artikelen geen EAN, dan blijft het GTIN-veld leeg.
Dat is een gegevensprobleem in de kassa, geen importfout.


== 5. Bestaande catalogus ==

Bij activatie bepaalt de plugin de modus: fresh (geen producten) of migrate (er
zijn al producten). Bestaande producten worden herkend via SKU, een eigen
duurzame sleutel, en anders op titel - ook onder concepten. Zo ontstaan er geen
duplicaten, ook niet als SKU's of titels intussen zijn gewijzigd.

Ziet een run alleen nieuwe producten en niets bijgewerkt, terwijl de catalogus al
gevuld is, dan waarschuwt de plugin: dat wijst op duplicaten.

Producten uit een eerdere opzet (SKU begint met ART- of GRP-) zet je met
"Restanten opruimen" op concept; hun SKU en GTIN komen dan vrij. Er wordt niets
verwijderd.

== 6. Taal ==

De plugin bevat een Engelse vertaling van de beheerinterface
(languages/arvas-woo-sync-en_US.mo). WordPress kiest die automatisch op basis
van de sitetaal onder Instellingen > Algemeen.

De brontaal is Nederlands. Voor een andere taal gebruik je
languages/arvas-woo-sync.pot als startpunt; plaats het resulterende .mo-bestand
in wp-content/languages/plugins/ zodat het een plugin-update overleeft.

== Frequently Asked Questions ==

= Overschrijft de plugin mijn eigen producttitels? =

Nee. De titel wordt alleen gezet bij nieuwe producten. Zet "Titels
overschrijven" aan als je juist wilt dat de feed leidend is.

= Wat gebeurt er als de leverancier een half bestand aanlevert? =

De import wordt afgebroken. De plugin controleert de omvang en het aantal
regels, en vergelijkt met de vorige geslaagde run. Bij een verdachte krimp
verandert er niets in de webshop.

= Werkt dit als de kassa op een andere server draait? =

Ja, dat is de gebruikelijke situatie. De plugin haalt het bestand op via SFTP,
FTPS, FTP of HTTPS, bewaart het in een afgeschermde map en verwerkt het daarna
lokaal.

= Mijn thema heeft een eigen merken-systeem. Werkt dat samen? =

Ja. De plugin herkent alle actieve merk-taxonomieen en schrijft naar allemaal,
zodat het merk zowel in WooCommerce als in het thema klopt.

= Waarom staat de import stil bij een grote catalogus? =

Dat is geen storing. De plugin werkt in blokken en stopt zichzelf voor de
timeout van de webserver. De voortgang wordt bewaard en de volgende run gaat
verder. Volg de voortgangsbalk in plaats van het rapport.

= Waarom blijven sommige GTIN-velden leeg? =

Dan levert de kassa voor die artikelen geen EAN aan. Dat is een gegeven in de
kassa, geen fout in de import.

== Screenshots ==

1. Instellingen: verbinding met de kassaserver, met testknop en diagnose.
2. Omgevingsscan: WooCommerce-versie, merk-taxonomieen en bestaande attributen.
3. Voortgangsbalk en de telling per run, met de reden als een run vroeg stopt.
4. Rapport van een import: aantallen, voorgenomen acties en gevonden conflicten.

== Changelog ==

= 1.0.0 =
* Eerste volledige versie.
* Kassa-export via SFTP/FTPS/FTP/HTTPS of lokaal pad, met downloadcontrole.
* Variabele producten met Kleur, Maat en Lengte; automatische verduidelijking van
  dubbele kleurnamen.
* Categorieboom op basis van de categoriecode, met instelbare afdelingsreeksen.
* Merken naar alle actieve merk-taxonomieen.
* GTIN/EAN met conflictafhandeling en een aparte herstelfunctie.
* Batchverwerking met tijdsbudget, voortgangsbalk en zelf doorketenen.
* Uitsluiten van merken en categorieen; bescherming van handmatige titels.
* Engelse vertaling van de beheerinterface, met een .pot-bestand voor andere
  talen.

== Upgrade Notice ==

= 1.0.0 =
Eerste openbare versie.
