Szolgáltatások
Miért Qavlar Tech Stack Projektek Rólunk
Termékek
Blog Kapcsolat
AUTOMATIZÁCIÓ · SHOPIFY · ÉLESBEN FUT

Kassen-Dashboard: pénztárgép szinkronizálása a Shopifyhoz

Egy kozmetikai kiskereskedőnek automatizáltam a készletegyeztetést a bolti pénztár és a webshop között. A lényeg nem a funkciólista, hanem az, ami a valódi katalógussal és a tulajdonos valódi gépével találkozva kiderült.

~285Valódi SKU a katalógusban
PercekPDF-től a Shopify készletig
2Engedélyezett cím, jelszó nélkül
0Titok az ügyfél gépén
Kassen-Dashboard
Az áttekintő: utolsó futás, módosult termékek, készletriasztások és PDF-feltöltés. A terméknevek és SKU-k el vannak mosva.

Két rendszer, amely nem beszélt egymással

Egy kozmetikai kiskereskedő a bcassa nevű német pénztárrendszert használta a boltban, és a Shopifyt a webshophoz. Minden bolti eladás csak a bcassában módosította a készletet. A tulajdonos egyetlen módja, hogy ezt a Shopifyban is átvezesse, az volt, hogy átnézett egy PDF készletexportot, és kézzel frissítette a termékeket.

A meglévő eszköz csak rontott a helyzeten: egy script úgy olvasta ki a PDF-et, hogy találgatta, melyik szám melyik oszlop. Ha egy beszállító neve számjegyet tartalmazott, csendben megsérültek a terméknevek.

Amit megépítettem

Egy végponttól végpontig működő szinkronrendszer, plusz egy átadási mód, amelyet nem fejlesztőnek, hanem egy nem technikai tulajdonosnak terveztem.

Valódi PDF-parserAz oszlopkinyerés minden szó tényleges x/y koordinátáját használja, és a fejléc saját elrendezéséből építi vissza az oszlopokat. Attól függetlenül helyes, hogy mi van bennük, és a valódi exportformátum elleni regressziós teszt védi.
Költségtudatos Shopify-szinkron~285 SKU mellett naponta csak néhány mozog, ezért egy gyorsítótár a változatlan termékeknél kihagyja a Shopify API-t. Minden valódi írás előtt lekéri az élő mennyiséget és a Shopify compare-and-set-jét használja, így egy párhuzamos online eladást sosem lehet felülírni.
Dashboard az ügyfél arculatábanNémet nyelvű, a tulajdonos saját arculatában: legutóbbi futások, módosult termékek, alacsony készlet riasztások, keresletugrások, valamint legjobban és legrosszabbul fogyó termékek a Shopify rendelési adataiból.
Jelszó nélküli belépésEgyszer használatos e-mailes link, két címre korlátozva, sebességkorláttal és hosszú életű munkamenetekkel.
Öntelepítő Windows-kliensGoogle Drive helyett (olyan biztonsági felülvizsgálat, amelyen egyik fél sem tudott túljutni) egy háttérprogram figyel egy mappát a gépén. CI-ben épül Windows-gép nélkül, a hozzáférési adatokat buildkor egy GitHub Actions secretből kapja, maga hozza létre a mappát, és bejelentkezéskor elindul.
Telepítés, amit nem lehet elrontaniEgyetlen script: git pull, Docker újraépítés, újraindítás, idempotens adatbázis-migráció. Minden sémaváltozás automatikusan kikerül, kézi SQL soha.

Ami valójában elromlott

A projekt különlegessége nem a funkciólista, hanem az, ami a valódi katalógussal és a valódi géppel találkozva kiderült, és az, hogyan jártam utána mindegyiknek.

504-es hiba az első teljes katalógus feltöltésekor. Nem kódhiba volt: a VPS reverse proxyja időtúllépéssel szakította meg a jogosan hosszú szinkront. Először azt kellett felfedeznem, hogy a szerver egyáltalán nem szabványos nginx elrendezést használ. aaPanel kezeli, és a valódi konfiguráció egy panel által generált proxy könyvtárban van, amit egy grep az /etc/nginx alatt sosem talált volna meg. Csak ezután lehetett alkalmazni a javítást: egy célzott timeout-felülírást olyan fájlban, amelyet a panel saját felülete nem ír felül.

Három Shopify Admin API szerződésváltozás egymás után. Egy mező, amely a dokumentáció szerint jónak tűnt (ignoreCompareQuantity), az input típuson egyáltalán nem létezett. A helyére lépő mező (changeFromQuantity) kötelező compare-and-set előfeltétel, nem opcionális metaadat. Ezután a mutation minden kérést elutasított, mert hiányzott egy újonnan kötelezővé tett @idempotent direktíva. Mindegyiket a nyers GraphQL hibaüzenetből és a Shopify changelogjából diagnosztizáltam. A második javítása maga is defenzív tervezés: a szinkron közvetlenül írás előtt lekéri az élő mennyiséget a helyi gyorsítótár helyett, ami véd a közben történt eladás felülírása ellen is.

Egy gyorsítótár, amely egy terméket örökre hibássá tehetett. Egy terméket töröltek és újra létrehoztak a Shopifyban, ami rutin, és új belső azonosítót kap. A szinkronnak nem volt visszaútja a „a gyorsítótárazott azonosító már nem létezik” állapotból, csak az, hogy minden későbbi futásnál hibát dob arra az SKU-ra. Mostantól öngyógyító: a „nem található” törli az elavult gyorsítótárat, és friss SKU-keresésre vált, így egy rossz azonosító nem válik tartós, csendes lyukká a katalógusban.

Sikert jelenteni egy meg nem történt írásra. Egy sikertelen Shopify-írás egy pillanatra mégis eltárolta helyben a szándékolt új készletet, még mielőtt az írás megerősítést kapott volna. Egy átmeneti hiba miatt a következő futás gyorsítótár-ellenőrzése hamis egyezést láthatott, kihagyta az újrapróbálkozást, és „Erfolg”-ot jelentett olyan készletre, amelyet a Shopify sosem kapott meg. Javítva: a helyi állapot csak megerősített távoli írás után kerül mentésre.

Windows SmartScreen egy nem technikai felhasználó gépén. Az .exe első átadásakor az a súrlódás jött elő, amit egy aláíratlan program előre jelez: blokkoló biztonsági ablakot látott, úgy értelmezte, hogy „a gép nem engedi”, és bezárta. Az ablakot vakon diagnosztizálni, egy kétsoros magyar üzenetből, a programot magam nem futtathatva, azt jelentette, hogy az útmutatót az ő nyelvén és az ő konkrét képernyőjére kellett megírnom, nem általános hibaelhárítási dokumentumként.

Kassen-Dashboard
Az utolsó frissítések naplója állapottal, módosított és kihagyott termékekkel.

Tech stack

FastAPIPostgreSQLSQLAlchemyDocker ComposeShopify Admin GraphQL APIMailjetPyInstallerGitHub Actionsnginx / aaPanelVanilla HTML, CSS, JS

Hol tart most

Felügyelet nélkül fut élesben: a tulajdonos ledob egy PDF-et egy mappába, a Shopify készlete perceken belül frissül, és minden hiba, nem csak azok, amelyeket észrevesz, automatikusan e-mailt küld a fejlesztőnek.

Ami a specifikáláskor egyszerűnek tűnt, a gyakorlatban főleg azokról a részekről szólt, amelyek nem egyszerűek: egy proxy réteg, amelyet egyikünk sem állított be kézzel, egy API, amely építés közben háromszor változtatta a szerződését, és egy szoftver, amelynek elég megbízhatónak kell lennie valakinek, aki sosem fog stacktrace-t olvasni.

Két rendszer, amely nem beszél egymással?

Meséld el egy ingyenes 30 perces hívásban, hol másoltok még kézzel.

A Qavlar.tech projektje, Saarbrückenben fejlesztve.