NAV-számla guard — test-mode és saját-magamnak vásárlás esetén
Hogyan védi a PromNET a NAV-Online Számla integrációt: test-fizetésnél és admin-saját vásárlásnál nem küld auditfelelős számlát.
A NAV Online Számla rendszer minden kibocsátott számlát adatszolgáltatás-köteles módon vár: ha küldünk egy számlát, az a NAV-nál is megjelenik, és a havi ÁFA-bevallás-be belekerül. Ezért test-mode-ban és admin-saját vásárláskor a PromNET egy “guard” réteggel megakadályozza a NAV-küldést — különben fiktív, törölhetetlen számlák kerülnének a hatósági adatbázisba.
Auditfontos: ezt a guard-réteget pontosan azért építettük be, mert a NAV-számla NEM törölhető (csak storno-zható, ami szintén audit-tétel). Egyetlen test-fizetés is komoly papírmunkát okozna utólag.
1. Mikor NEM küld a PromNET NAV-számlát?
3 esetben blokkolja a nav-submit.ts modul a számla-kiküldést:
a) Stripe TEST mode
Ha az aktív Stripe-mode test (ld. Stripe TEST/LIVE súgó),
egyetlen test-fizetés sem generál NAV-számlát. A /api/stripe/webhook
megkapja a payment_intent.succeeded-eseményt, de a livemode: false
flag miatt a NAV-küldés átugorva.
A logban látod:
[nav-guard] skip: stripe TEST mode (livemode=false)
b) Admin-saját vásárlás (saját kredit-feltöltés)
Ha az admin (csiber) saját maga vásárol a saját platformon (pl. kredit-feltöltés
a tesztelés végett), a nav-submit ellenőrzi a customer_email értékét:
- ha az admin-emailje (
[email protected]), és - a Stripe
customer_idegyezik az admin-fiókkal,
akkor blokkolja a NAV-küldést. Indok: a saját magamtól venni a saját számlámra fiktív tranzakció — auditkockázatos.
A logban:
[nav-guard] skip: admin self-purchase (user_id=1, [email protected])
c) NAV_DRY_RUN=1 env-var
Fejlesztői debug-módhoz: ha a NAV_DRY_RUN env-var 1-re állítva, a
nav-submit egyetlen számlát sem küld ki, csak logolja a payload-ot.
Hasznos staging-environment-ben.
2. A guard-logika — lib/nav-submit.ts
A relevant snippet:
export async function submitNavInvoice(
env: Env,
invoice: InvoicePayload,
): Promise<NavResult> {
// 1. Stripe TEST mode → skip
if (env.STRIPE_MODE === 'test' || invoice.stripe_livemode === false) {
log('[nav-guard] skip: stripe TEST mode');
return { skipped: true, reason: 'stripe_test_mode' };
}
// 2. Admin self-purchase → skip
if (invoice.customer_email === ADMIN_EMAIL && invoice.user_id === ADMIN_USER_ID) {
log('[nav-guard] skip: admin self-purchase');
return { skipped: true, reason: 'admin_self_purchase' };
}
// 3. Dry-run env-var → skip
if (env.NAV_DRY_RUN === '1') {
log('[nav-guard] skip: NAV_DRY_RUN=1', invoice);
return { skipped: true, reason: 'dry_run' };
}
// → tényleges NAV-API hívás
return await callNavApi(env, invoice);
}
A 3 ellenőrzés AND-elve biztosítja: ha bármelyik feltétel fennáll, nem küldünk számlát.
3. Mi történik a “skipped” számlával?
Akkor sem hagyjuk veszni — a nav_invoices D1-táblába rögzítjük
status='skipped' flag-gel, hogy:
- Az audit-log látszik (ki, mikor, miért NEM ment)
- A user (admin esetén) látja a
/app/billingoldalon, hogy “ez nem ment NAV-ba” - Ha utólag manuálisan szeretnénk küldeni, a payload megvan
A status enum: pending / submitted / failed / skipped.
4. Live-mode + valódi vásárló — a teljes flow
Ha az admin-vásárlás guard-ja NEM csap be (mert valódi vevő jött):
- Stripe
payment_intent.succeededwebhook érkezik (livemode: true) - A vásárló adatai (név, cím, adószám) lekérdezve a Stripe Customer-ből
- NAV-számla payload összeállítva (XML, sertesz-keretek a részletekhez)
- A NAV adatszolgáltatás endpoint-ra POST (saját CF Worker-en át, KAU-tokennel)
- NAV visszaigazolás:
tranzakció-azonosító, az számla be van adva - PDF-letöltés generálva, email kiküldve a vevőnek
nav_invoices-rekordstatus='submitted'-re vált
A teljes flow kb. 5-15 másodperc.
5. Storno (sztornózás)
Ha mégis kellene egy számlát visszavonni (pl. manuálisan generált test-számla élesben), a /app/admin/billing oldalon “Sztornó” gomb:
- A storno-számla NAV-felé adatszolgáltatás-köteles
- Az eredeti számlára való hivatkozás kötelező
- A NAV-portálon mindkettő (eredeti + storno) megmarad audit-okból
A storno-folyamatot csak admin indíthatja. Vásárlóként, ha hibát látsz a számládon, support-ticket kell.
6. Hogyan ellenőrizd, hogy működik a guard?
Egyszerű smoke-test:
- Stripe-mode
test-be váltva - Test-card-dal vásárolj egy 100 Ft-os kredit-csomagot
- Ellenőrizd a
nav_invoicestáblát:SELECT id, status, skip_reason FROM nav_invoices ORDER BY created_at DESC LIMIT 5; - Az új sor
status='skipped',skip_reason='stripe_test_mode' - NAV-portálon ne keresd — nincs is
Ha mégis ott van — ALERT, [email protected] vagy a fejlesztői csapatnak szóljon.
7. Mit tegyél, ha mégis test-számla került a NAV-ba?
Helyzet: korábban (a guard előtt) elment egy test-fizetés a NAV-ba.
- Storno — admin-felületen sztornózd az eredeti számlát
- A storno-tranzakció ÁFA-bevallásban negatívként jön be (semlegesít)
- Mindkettő rögzítve marad a NAV-portálon
Ha tömegesen történt (pl. 50+ tételt), könyvelővel egyeztetés kell.
8. Saját ÁFA-bevallás védelme
A guard dupla védelmet ad:
- A NAV-portálon nincs fiktív tétel → a XML-bevallás tisztán generálódik
- A PromNET D1-ben látod, melyik tranzakciók valódi vásárlások és melyek skipped-ek → könyvelési reconciliation egyértelmű
A havi ÁFA-bevallásnál így kizárólag a status='submitted' rekordokat
kell összegezned.
9. Vásárlóként — mit látsz?
Vásárlóként ezt a guard-réteget nem érzed — Te a Stripe-checkout után emailen kapsz egy számlát, ami a NAV-portálon is fent van. Ha bármi furcsa (nem érkezik számla 24 órán belül), a /app/billing oldalon “Számla-letöltés”-re kattints, vagy nyiss support-ticket-et.