PromNET

SÚGÓ Számlázás

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_id egyezik 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/billing oldalon, 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):

  1. Stripe payment_intent.succeeded webhook érkezik (livemode: true)
  2. A vásárló adatai (név, cím, adószám) lekérdezve a Stripe Customer-ből
  3. NAV-számla payload összeállítva (XML, sertesz-keretek a részletekhez)
  4. A NAV adatszolgáltatás endpoint-ra POST (saját CF Worker-en át, KAU-tokennel)
  5. NAV visszaigazolás: tranzakció-azonosító, az számla be van adva
  6. PDF-letöltés generálva, email kiküldve a vevőnek
  7. nav_invoices-rekord status='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:

  1. Stripe-mode test-be váltva
  2. Test-card-dal vásárolj egy 100 Ft-os kredit-csomagot
  3. Ellenőrizd a nav_invoices táblát:
    SELECT id, status, skip_reason FROM nav_invoices ORDER BY created_at DESC LIMIT 5;
  4. Az új sor status='skipped', skip_reason='stripe_test_mode'
  5. 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.

  1. Storno — admin-felületen sztornózd az eredeti számlát
  2. A storno-tranzakció ÁFA-bevallásban negatívként jön be (semlegesít)
  3. 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.


← Számlázás Frissítve: 2026. 05. 08.