Prijava Probaj Space ISO 27001
10 grešaka agencija pri fiskalizaciji web shopa i kako ih ispraviti
Nazad na Novosti

Najčešće greške pri fiskalizaciji web shopa su dupli računi, ponavljanje zahteva bez ključa idempotentnosti, API ključ u pregledaču, poziv PFR-a bez reda čekanja i refundacija bez veze sa originalnim računom. Svaka od njih se ispravlja jednim pravilom u arhitekturi, a ne dodatnim kodom. U nastavku dajemo svih deset, sa posledicom i ispravkom.

Ukratko
  • Jedna porudžbina, jedan externalId, jedan fiskalni račun: to je pravilo koje otklanja polovinu grešaka sa spiska.
  • Poziv ka kasi ide sa servera i iz reda čekanja, nikad iz pregledača i nikad u istom zahtevu koji odgovara platnom procesoru.
  • Odgovor 202 nije greška: V-PFR je privremeno nedostupan, Tezga eKasa sama ponavlja, a shop čeka webhook.
  • Refundacija uvek pokazuje na original po documentId ili externalId; refundacija „iz vazduha” je greška u knjigama.
  • Test podaci ostaju na testnom nalogu, jer je okruženje osobina naloga, a ne ključa.

Zašto fiskalizacija web shopa puca na redosledu, a ne na propisu?

Zakon o fiskalizaciji je za web shop prilično jednostavan: promet na malo obuhvata i prodaju preko interneta fizičkim licima, a račun se izdaje u trenutku prometa, to jest isporuke ili naplate, šta pre nastupi. Za online prodaju sa karticom to je potvrda naplate, za uplatu na račun trenutak kad uplata legne, a za pouzeće isporuka. Tehničko uputstvo za ESIR i tumačenja Poreske uprave za daljinsku prodaju dozvoljavaju V-PFR i elektronsku dostavu računa kupcu. Ništa od toga nije teško.

Teško je ono što propis ne pominje: platni procesor koji callback pošalje tri puta, kupac koji osveži stranu „Hvala”, mreža koja prekine vezu posle nego što je račun izdat, ali pre nego što je odgovor stigao. Svaki od tih događaja u naivnoj integraciji pravi novi fiskalni račun, a svaki višak računa traži storno i objašnjenje knjigovođi. Zato je fiskalizacija pre svega pitanje redosleda i idempotentnosti, a tek onda pitanje polja u JSON-u.

Pogrešan i ispravan redosled fiskalizacije Pogrešno 1. Kupac klikne „Naruči” 2. Shop odmah zove kasu iz pregledača i šalje mejl 3. Naplata ne uspe: račun postoji, novca nema 4. Storno, objašnjenje knjigovođi Ispravno 1. Kupac klikne „Naruči”, porudžbina upisana 2. Procesor potvrdi naplatu (callback sa potpisom) 3. Server iz reda čekanja zove kasu, externalId = broj 4. Kasa fiskalizuje i šalje mejl sa računom

Levo je redosled koji pravi račune bez novca i mejlove bez računa; desno je redosled u kome kasa dobija zahtev tek posle potvrđene naplate.

Greška 1: dupli računi za istu porudžbinu

Kako nastaje. Callback procesora stigne dva puta, ili kupac osveži stranu potvrde, ili cron prođe kroz porudžbine dok je prethodni prolaz još u toku. Svaki događaj pozove kasu i svaki dobije novi račun. Kod jedne pekare koja prodaje preko sajta ovo se vidi kao dva računa za istu kutiju kolača, a u knjigama kao promet koji ne postoji.

Ispravka. Dva sloja. U shopu: pre poziva proveri da li porudžbina već ima upisan dokument, a proveru i upis uradi u transakciji sa zaključanim redom, da dva istovremena zahteva ne prođu proveru zajedno. U kasi: koristi externalId izveden iz broja porudžbine; Tezga eKasa istu porudžbinu fiskalizuje tačno jednom, čak i kad webhook i povlačenje stignu istovremeno. Ako je višak ipak izdat, ispravka je storno, ne brisanje; postupak je na strani storno i refundacija fiskalnog računa.

Greška 2: retry bez idempotentnosti

Kako nastaje. Developer ispravno doda ponavljanje zahteva posle isteka vremena, ali pri svakom pokušaju generiše nov identifikator (vreme, UUID). Kasa svaki pokušaj vidi kao novu porudžbinu. Ovo je greška 1 u drugom obliku, samo što je sada nastala iz dobre namere.

Ispravka. Ključ idempotentnosti se računa jednom, pre prvog pokušaja, i čuva uz porudžbinu. Svaki pokušaj šalje isti externalId (do 200 znakova). Isto važi za refundaciju: kad PFR padne, POST /api/integrations/refund vraća 202, a ponovljeni zahtev ne pravi dupli dokument. Pravilo koje dajemo timovima: ako ne možeš da pokažeš odakle ključ potiče, ne šalji zahtev.

// pogrešno: nov ključ pri svakom pokušaju
externalId: "shop-" + Date.now()

// ispravno: ključ potiče iz porudžbine
externalId: "shop-" + porudzbina.id

Greška 3: poziv API-ja iz pregledača

Kako nastaje. Najbrži put do „radi” je fetch iz klijentskog koda sa ključem u konstanti. Radi na demou, a onda ključ vidi svako ko otvori alat za programere. Ključ Tezga eKase počinje sa tzg_, nosi 48 heksadecimalnih znakova i daje pravo izdavanja fiskalnih računa u ime firme klijenta. To nije podatak koji sme da putuje do pregledača.

Ispravka. Poziv ide sa servera: route handler, server action, job, hook ili n8n. Ključ živi u promenljivoj okruženja, ne u repozitorijumu. Za svaki sajt zaseban ključ (do 20 po firmi), rotacija na 90 dana, po mogućnosti vezivanje za IP servera i HMAC potpis tela kroz X-Tezga-Signature. Isečke koda za Next.js, Laravel, WordPress bez WooCommerce, Webflow i Framer ima u tekstu fiskalizacija za custom sajt.

Greška 4: PFR nedostupan, a shop nema red čekanja

Kako nastaje. V-PFR Poreske uprave povremeno nije dostupan, kao i svaki spoljni sistem. Shop koji zove kasu sinhrono, u istom zahtevu koji odgovara procesoru, u tom trenutku ili pukne ili vrati grešku procesoru, pa procesor ponovi callback, pa nastane greška 1. Tezga na nedostupnost PFR-a vraća 202: zahtev je primljen, kasa sama ponavlja. Shop koji 202 tretira kao neuspeh šalje zahtev ponovo i pravi saobraćaj bez svrhe.

Ispravka. Callback procesora samo upiše status „plaćeno” i stavi zadatak u red čekanja. Radnik iz reda zove kasu: 200 upisuje dokument, 202 upisuje „čeka PFR” i ne ponavlja (čeka odlazni webhook racun.fiskalizovan), 5xx i istek vremena idu na ponovni pokušaj sa rastućim razmakom, 400 ide na ručnu proveru jer je telo loše i biće loše i sledeći put.

Red čekanja i grananje po HTTP kodu Callback procesora Red čekanja zadatak: fiskalizuj Radnik POST order 200: upiši dokument, gotovo 202: čekaj webhook, ne ponavljaj 5xx, istek: ponovi za 30 s, 2 min, 10 min 400: ručna provera, ne ponavljaj Isti externalId u svakom pokušaju.

Radnik iz reda čekanja grana po HTTP kodu: 200 završava, 202 čeka webhook, 5xx ponavlja sa rastućim razmakom, 400 ide čoveku.

Greška 5: vremenska zona servera

Kako nastaje. Server ili n8n instanca rade na UTC-u. Porudžbina naplaćena u 00:20 po Beogradu ima u bazi datum prethodnog dana. Shop šalje kasi zahtev sa tim datumom u externalId ili u sopstvenim izveštajima, pa se dnevni promet iz shopa i iz kase ne slažu, a knjigovođa traži objašnjenje. Kad shop pravi sopstveni „dnevni izveštaj” za klijenta, razlika od jednog sata oko ponoći pravi razliku od nekoliko računa dnevno.

Ispravka. Vreme prometa određuje kasa u trenutku fiskalizacije, ne shop. Shop čuva vreme u UTC-u sa eksplicitnom zonom i prikazuje ga u Europe/Belgrade. Datum ne stavljaj u ključ idempotentnosti. Za izveštaje klijentu koristi izveštaje iz kase, koji su vezani za fiskalizovane dokumente, umesto sopstvene tabele; Tezga ih šalje knjigovođi na raspored i nudi CSV izvoz.

Greška 6: refundacija bez veze sa originalom

Kako nastaje. Shop obradi povraćaj kao „negativan račun”: pošalje nov zahtev sa negativnim iznosima ili sa napomenom „povraćaj”. Fiskalni sistem tako ne radi. Refundacija je zaseban tip dokumenta koji pokazuje na originalni račun i nosi identifikaciju kupca kome se novac vraća. Refundacija bez originala se ne uklapa u evidenciju Poreske uprave ni u knjige klijenta.

Ispravka. POST /api/integrations/refund sa vrsta: refundacija (ili storno kad je račun izdat greškom pre isporuke) i originalom po documentId ili externalId porudžbine. Delimičan povraćaj ide po stavkama; ako original nema kupca, refundacija traži kupacIdBroj. Po Zakonu o zaštiti potrošača (Sl. glasnik RS 35/2026) kupac na daljinu ima pravo na odustanak u roku od 14 dana, pa je refundacija redovan deo posla, a ne izuzetak. Razliku između storna i refundacije autor kase objašnjava u tekstu storno ili refundacija, šta je razlika.

Greška 7: test podaci u produkciji

Kako nastaje. Tim testira integraciju na pravom nalogu klijenta „samo da vidi da radi”. Svaki test je pravi fiskalni račun u evidenciji Poreske uprave, a svaki storno posle testa je još jedan dokument. Klijent na kraju dana ima desetak dokumenata koji ne odgovaraju nijednoj prodaji. Obrnuta varijanta je gora: sajt pušten u rad sa ključem testnog naloga, pa prve prave porudžbine odu u sandbox i ostanu bez fiskalnog računa.

Ispravka. Okruženje je osobina naloga, ne ključa. Testni nalog šalje račune u sandbox Poreske uprave, gde nisu fiskalni; Go Simple ga integratoru otvara na zahtev. Kad je nalog već pravi, za probu služi tip računa „Обука”, koji nosi napomenu „ОВО НИЈЕ ФИСКАЛНИ РАЧУН”. Ključ testnog i produkcionog naloga drži u odvojenim okruženjima sa različitim imenima, a pri predaji prođi kontrolnu listu iz teksta sandbox za fiskalizaciju.

Testni i produkcioni nalog: isti kod, drugi ključ Testni nalog TEZGA_API_KEY=tzg_test... sandbox Poreske uprave, nije fiskalno koristi se za razvoj i prihvatno testiranje Produkcioni nalog TEZGA_API_KEY=tzg_prod... V-PFR, pravi fiskalni računi proba samo tipom računa „Обука” isti kod Okruženje je osobina naloga, ne ključa: prelazak u produkciju = zamena ključa u okruženju.

Testni nalog i produkcioni nalog dele isti kod; prelazak je zamena ključa u okruženju, a ne izmena integracije.

Greška 8: PIB bez validacije

Kako nastaje. Forma na sajtu ima polje „PIB (opciono)” bez ikakve provere. Kupac unese matični broj, broj telefona ili PIB sa slovnom greškom. Kasa račun sa unetim PIB-om vodi kao B2B (Id kupca 10:PIB), a ako je tok podešen na SEF, e-faktura ode ka pogrešnom ili nepostojećem primaocu. Klijent onda ima dokument koji ne može da se uruči i kupca koji nije dobio ono što je tražio.

Ispravka. Tri provere pre slanja. Oblik: tačno 9 cifara. Postojanje: za nove B2B kupce proveri firmu u registru APR-a pre prvog računa. Namera: polje PIB prikaži tek kad kupac izabere „kupujem kao firma”, da fizička lica ne unose brojeve bez potrebe. Ako je kupac firma, a plaća karticom kao potrošač, ne mora svaki takav promet u SEF; koji tok (fiskalni, sef, fiskalni_i_sef) klijent koristi za B2B, dogovorite sa njegovim knjigovođom, a pravila sistema e-faktura su na efaktura.mfin.gov.rs.

Greška 9: dostava bez stavke na računu

Kako nastaje. Shop naplati robu i dostavu, a kasi pošalje samo robu, jer „dostava nije proizvod”. Iznos na fiskalnom računu je manji od iznosa koji je kupac platio, a razlika se nigde ne vidi. Pri poređenju izvoda i računa knjigovođa nalazi manjak na svakoj porudžbini sa dostavom.

Ispravka. Dostava je stavka sa svojom šifrom, količinom, cenom i poreskom oznakom, kao i svaka druga usluga. Tezga u vezi sa WooCommerce i Shopify ima prekidač „prikaz troška dostave kao stavke”, a u custom integraciji dostavu dodaješ u niz stavke. Poresku oznaku za dostavu uzmi iz GET /api/integrations/tax-labels, jer ona za firmu van PDV-a nije ista kao za obveznika PDV-a. Kad je dostava besplatna za kupca, stavke nema; kad kupac plaća dostavu, ona mora na račun.

Greška 10: mejl kupcu pre potvrde fiskalizacije

Kako nastaje. Shop šalje mejl „Vaš račun” odmah po naplati, sa sopstvenim PDF-om koji nije fiskalni račun, ili sa praznim prilogom, jer kasa još nije vratila dokument (202, čekanje PFR-a). Kupac dobije dokument bez QR koda i broja računa, a posle i pravi račun, pa ima dva različita dokumenta za jednu kupovinu. Po Tehničkom uputstvu za ESIR svaki dokument koji nije fiskalni račun nosi napomenu „ОВО НИЈЕ ФИСКАЛНИ РАЧУН”, a improvizovani PDF iz shopa je nema.

Ispravka. Mejl sa računom šalje kasa, posle uspešne fiskalizacije, sa PDF-om i QR kodom; u Tezga eKasi je to prekidač posaljiMejl. Shop šalje samo potvrdu porudžbine, bez reči „račun”. Ako klijent hoće račun i u svom mejlu, sačekaj webhook racun.fiskalizovan, pa iz GET /api/integrations/documents/{id} uzmi javniPdfUrl i ubaci link. Prema tumačenju Poreske uprave za daljinsku prodaju, elektronska dostava uz saglasnost kupca je dovoljna, štampani primerak u paketu nije obavezan; detalji na purs.gov.rs.

Tabela: greška, posledica, ispravka

#GreškaPosledicaIspravka
1Dupli računiPromet koji ne postoji, storno za svaki višakProvera u transakciji + externalId iz broja porudžbine
2Retry bez idempotentnostiSvaki pokušaj je nova porudžbinaKljuč se računa jednom i čuva uz porudžbinu
3Ključ u pregledačuSvako može da izdaje račune u ime klijentaPoziv sa servera, ključ u okruženju, rotacija, IP, HMAC
4Bez reda čekanjaPad pri nedostupnom PFR-u, ponavljanje callbackaRed čekanja, 202 čeka webhook, 5xx ponavlja, 400 čoveku
5Vremenska zonaPromet oko ponoći u pogrešnom danuUTC u bazi, prikaz Europe/Belgrade, izveštaji iz kase
6Refundacija bez originalaDokument koji se ne uklapa u evidencijurefund sa documentId ili externalId, po stavkama
7Test u produkcijiLažni promet ili prave porudžbine bez računaTestni nalog u sandboxu, odvojeni ključevi, račun „Обука”
8PIB bez validacijeB2B dokument ka pogrešnom primaocu9 cifara, provera u APR-u, polje samo za firme
9Dostava bez stavkeRačun manji od naplateDostava kao stavka sa poreskom oznakom
10Mejl pre fiskalizacijeDva dokumenta za jednu kupovinuMejl šalje kasa posle uspeha, shop šalje samo potvrdu

Kako mi u Go Simple proveravamo integraciju pre predaje?

Svaku integraciju, bilo da smo je gradili mi ili je preuzimamo od druge agencije, prođemo kroz isti niz proba na testnom nalogu. Probe su namerno ružne, jer proizvodnja jeste ružna.

  1. Pošaljemo isti callback procesora tri puta u istoj sekundi. Očekujemo tačno jedan dokument.
  2. Isključimo mrežu ka kasi usred zahteva i pustimo red čekanja da ponovi. Očekujemo jedan dokument sa istim externalId.
  3. Pretražimo klijentski bundle i repozitorijum za niz tzg_. Očekujemo nula pogodaka.
  4. Simuliramo 202 i proverimo da shop ne šalje novi zahtev, nego čeka webhook racun.fiskalizovan.
  5. Naplatimo porudžbinu u 23:58 i 00:02 po Beogradu i uporedimo dan u shopu i u kasi.
  6. Vratimo jednu od tri stavke i proverimo da je refundacija vezana za original i da je iznos tačan.
  7. Unesemo PIB sa 8 cifara i očekujemo da forma odbije, a ne kasa.
  8. Porudžbina sa plaćenom dostavom: iznos na računu jednak iznosu naplate.
  9. Proverimo da kupac dobija tačno jedan mejl sa računom, i to od kase.
  10. Zamenimo ključ testnog naloga produkcionim i ponovimo prvu probu tipom računa „Обука”.

Kad sve prođe, integracija ide klijentu sa dokumentom koji opisuje gde je ključ, kako se rotira i koga zvati kad stigne 401 ili 402. Za shopove na WooCommerce ili Shopify većina ovih grešaka je već rešena u dvosmernoj vezi Tezga eKase, o čemu piše autor kase u tekstu fiskalizacija web shopa: WooCommerce i API; za headless i custom shopove koristimo referentnu arhitekturu iz teksta headless web shop na Next.js sa fiskalizacijom. Pregled svega što kasa nudi agencijama je na strani fiskalna kasa za klijente agencije, a ostali tekstovi na našem blogu. Kad porudžbina ide pouzećem, trenutak izdavanja računa ima svoje zamke, opisane na Treku u tekstu fiskalna kasa i pouzeće.

Izvori: Zakon o fiskalizaciji (Sl. glasnik RS 153/2020, 96/2021, 138/2022); Pravilnik o vrstama fiskalnih računa, tipovima transakcija, načinima plaćanja; Tehničko uputstvo za ESIR i tumačenja Poreske uprave za daljinsku prodaju (purs.gov.rs); Zakon o zaštiti potrošača (Sl. glasnik RS 35/2026); Sistem e-faktura (efaktura.mfin.gov.rs); registar APR-a (apr.gov.rs); uputstvo za integratore i OpenAPI opis Tezga eKase (odobreni ESIR, ИБ 1597). Tekst nije pravni savet; za konkretan slučaj klijenta proverite sa njegovim knjigovođom.

Česta pitanja

Ne brišu se, jer fiskalni račun ne može da se obriše. Za svaki višak se izdaje storno (ako roba nije isporučena) ili refundacija (ako je novac vraćen), sa vezom na original. Napravite spisak parova original i višak, prođite ga sa knjigovođom klijenta i tek onda šaljite dokumente, da ne biste stornirali pogrešan račun.

Ne. Dovoljna je tabela porudžbina sa kolonom stanja i cron koji svakih par minuta prođe kroz one bez dokumenta, uz zaključavanje reda dok traje obrada. Laravel ima ugrađene redove, Next.js na hostingu sa pozadinskim funkcijama takođe. Bitno je da poziv ka kasi ne bude u istom zahtevu koji odgovara procesoru.

Kao „primljeno, čeka Poresku”. V-PFR je trenutno nedostupan, kasa je zahtev sačuvala i sama ga ponavlja; kad uspe, stiže webhook i mejl kupcu. Klijent ne treba ništa da radi, a u kasi porudžbinu vidi sa stanjem čekanja. Shop ne šalje novi zahtev.

Obveznik fiskalizacije je klijent, on odgovara pred Poreskom upravom. Agencija odgovara klijentu po ugovoru. Zato u ugovor o izradi shopa unesite šta integracija garantuje (jedan račun po porudžbini, refundacija sa originalom, mejl posle fiskalizacije) i šta klijent održava (ključ, nalog, paket kase). Ovo nije pravni savet; ugovor proverite sa pravnikom.

Ne. Ključ pripada firmi klijenta, do 20 ključeva po firmi. Svaki klijent ima svoj nalog i svoje ključeve, a agencija u svom okruženju drži ključ po projektu. Za agencije koje naplaćuju po obimu postoji paket „Po računu” sa 4 RSD po fiskalnom računu i refundaciji, sa dopunom unapred.

U svom kodu: ubacite prekidač koji radniku umesto pravog odgovora vrati 202 ili istek vremena, pa proverite da se porudžbina ne duplira i da 202 ne pokreće novi zahtev. Testirate svoje ponašanje, ne ponašanje kase. Ista proba se ponavlja pre svake veće izmene integracije.

Za prodaju na licu mesta u objektu Zakon o fiskalizaciji traži L-PFR, dok je V-PFR dozvoljen za online prodaju i prodaju na daljinu. Integracija iz ovog teksta pokriva online deo. Sopstveni L-PFR Tezge je u pripremi, bez obećanog datuma; za radnju se sa klijentom dogovara zasebno rešenje.

Ako želite da vaš sledeći web shop krene bez ovih deset grešaka, pogledajte API za fiskalizaciju, otvorite nalog na strani probaj fiskalnu kasu i zatražite testni nalog, ili nam pišite na [email protected] da zajedno prođemo kontrolnu listu pre predaje.

Šta nudi Tezga eKasa

  • API za fiskalizaciju sa jednim računom po porudžbini (externalId)
  • Odgovor 202 i automatsko ponavljanje kad V-PFR ne odgovara
  • Webhook nazad u shop kad je račun fiskalizovan
  • Testni nalog sa sandbox računima, odvojen od produkcije
Saznaj više o alatu Tezga eKasa

Pročitaj još

Prodaja bez web shopa: naplata linkom, IPS QR i narudžbine iz poruka Sandbox za fiskalizaciju: od testnog naloga do produkcije za jedan dan Headless web shop na Next.js sa fiskalizacijom: referentna arhitektura

Probaj Tezga eKasa besplatno

Fiskalni računi i e-fakture za uslužne delatnosti - kasa koja ne komplikuje.

Korisni vodiči za male firme - jednom mesečno, bez spama.

Pogledaj cene Piši nam