Verificeret mod app@9d146f9 · , 16 skal genverificeres · , 0 brudt
Bogføring til regnskab
Alt på siden er læst på origin/main af payfriend på SHA e99eb6a. Bogføringen er delt op i app/Services/Ap/Booking/*, og ankrene peger derhen. Domænet hører til side.kvitteringer.
Auto-bogfør OCR-bilagkun PayFriendNår fluebenet og det globale kill switch begge er tændt, bogfører politikken bilag over konfidens-tærsklen uden et klik.
Konfidens for auto-bogføringkun PayFriendPolitikken bogfører ikke, når bilagets OCR-konfidens ligger under tallet.
ACCOUNT_SUGGESTION_MIN_CONFIDENCEkun PayFriendMindste konfidens før et kontoforslag må følge med i bogføringen, og kun PayFriend kan ændre den.
ACCOUNTING_AUTO_BOOK_ENABLEDkun PayFriendGlobalt kill switch for auto-bogføring af bilag, og kun PayFriend kan ændre det.
ACCOUNTING_VOUCHER_PRUNE_ENABLEDkun PayFriendOm synk må slette lokale bogførte bilag som regnskabet ikke længere har, og kun PayFriend kan ændre det.
Et bilag bliver bogført, når et menneske trykker Bogfør, eller når kunden vælger AI Bogføring eller Auto bogfør. Der findes også en vej, hvor robotten bogfører et bilag uden at nogen trykker på noget, men den kræver, at PayFriend har slået den til for selskabet. Målt 2026-10-01 er den ikke slået til hos nogen selskaber, se faelde.kvitteringer.auto-bogfoering-aldrig-brugt.
Før noget sendes til regnskabet, tjekker PayFriend en lang række vagter: er bilaget allerede bogført, ligger banklinjen allerede i regnskabet, og er der en kladde, der ligner. Bogfører et menneske, kan de bløde vagter tvinges igennem. De hårde vagter kan ingen tvinge.
Er bilaget først bogført, er det låst. Vejen tilbage er Tilbagefør, som laver en modpostering i regnskabet. Intet slettes.
1
Typiske spørgsmål
For alle
Kunden har trykket Bogfør, men intet sker i e-conomic. Hvor kigger jeg?
Status Bogfører. Jobbet ligger i køen eller hænger. Efter 60 minutter flytter PayFriend det selv til Fejlet. Fejlteksten siger, at posteringen kan være oprettet alligevel, så kig i e-conomic, før der bogføres igen.
Status Fejlet. Teksten i bilagets booking_error er årsagen. Se tilstand.voucher.book-blocker for de tekster, brugeren kan se.
Status Afventer med en tekst. En vagt har sendt bilaget tilbage. Teksten forklarer hvorfor.
Status Bogført, men posteringen ligger i kassekladden. Integrationen står på kladde, og journal_state er Draft. Posteringen er oprettet, men ikke bogført. Se regel.bogfoering.kladde-tilstand.
Status Bogført og journal_state Unconfirmed. Kladden findes, men bogføringstrinnet fejlede. Et nyt tryk på Bogfør genoptager den samme kladde.
Der kom en bekræftelsesdialog. Så blev intet sendt. PayFriend fandt en lignende postering i regnskabet og venter på, at et menneske bekræfter.
Robotten bogfører kun, når alle tolv betingelser i afsnit 2 (Auto-book-politikken) herunder er opfyldt. De vigtigste er: både det globale flag og selskabets eget flueben er tændt, OCR-sikkerheden er mindst 0,95, banklinjen er bekræftet matchet, og hver linje har en konto. Kun PayFriend kan slå selskabets flueben til.
Ja, så længe bilaget er Bogført og har en reference til udbyderen. Tilbagefør poster en modpostering med modsat fortegn, så hver konto, også momsen, går i nul. Revisoren ser både det oprindelige bilag og modposteringen, hvis tekst starter med "Modpostering af:", og bilagsfilen følger med modposteringen. Bilaget i PayFriend bliver Tilbageført og kan ikke bogføres igen.
Er posteringen hos Dinero eller Billy kun en ubogført kladde, sletter PayFriend kladden i stedet, og bilaget kan bogføres igen. Hos e-conomic findes den sletning ikke, så en e-conomic-kladde får også en modpostering, se faelde.bogfoering.economic-kladde-tilbagefoeres-med-modpostering.
Der er fire kendte veje: et hængende job, hvor udbyderens kald alligevel lykkedes, et kald uden idempotensnøgle, en bogholder der selv havde lavet posteringen, og to hurtige klik på Tilbagefør. Se faelde.bogfoering.bogfoert-to-gange. Genrejsningen af hængende bilag sender aldrig et bilag igen, netop for at undgå den første.
Fem veje ender alle i job.book-voucher. Hvilken vej, der er brugt, afgør, om jobbet sendes med force, og dermed hvilke vagter der gælder. Begrebet står i begreb.bogfoering.force.
Vej
Udløser
Route
force
Stemples Booking først
Kilde
Enkelt Bogfør
Knappen på bilaget
vouchers.book
ja
ja
VoucherBookRequest::book
Bulk Bogfør og AI Bogføring
Valgte bilag i listen, valgfrit med et journal_number
vouchers.batch-book
ja, og med autoSuggestAccount
ja
VoucherBatchBooking::batchBook
Auto bogfør-knappen
Operatøren, for alle kvalificerede bilag
vouchers.auto-book
nej
ja
VoucherController::autoBook
Bank, Bogfør fra afstemning
Match-panelet, og start af bogføring efter et bekræftet match
Bulk og AI Bogføring er samme route. UI'et sender journal_number med, når brugeren har valgt en journal. Komponenten JournalPicker er e-conomic-vælgeren, og dens kontekst er indstillinger eller onboarding. Hvor præcis vælgeren sidder i bulk-dialogen, er ikke læst her.
Bulk springer over, hvad den ikke må bogføre: dubletter, lønbilag, bilag med ubekræftet moms, bilag uden bankmatch og bilag matchet til en reservation. Resten sendes med force og AI-kontoforslag. Forslaget bruges kun, hvis konfidensen er mindst regel.kontoforslag.min-confidence.
Før en menneskelig vej stempler Booking, afviser VoucherBookRequest::refuseIfUnbookable allerede tydelige tilfælde: en suspenderet konto, en status der ikke er bogførbar, en dublet, et lønbilag, en reservation og et bilag uden beløb. Samme afvisninger står som vagter længere nede, fordi den uovervågede vej ikke går gennem controlleren.
VoucherAutoBookPolicy::shouldAutoBook er den uovervågede vej. Hver betingelse nedenfor skal være opfyldt. En falsk kortslutter til manuel gennemgang. Rækkefølgen er kodens.
Tre ting er lette at overse. For det første kræver politikken et bekræftet bankmatch: en række i bank_transaction_matches for netop dette bilag. At bank_transaction_id er sat, er ikke nok. ScanVoucherJob laver sin automatiske match først, så en upload kan matche og blive bogført i samme kørsel. For det andet skal både det globale env-flag og selskabets eget flueben være tændt. Flaget kan kun PayFriend ændre ved at ændre miljøet. Fluebenet voucher_auto_book_enabled har kun PayFriend-admin som skriver, se indstilling.company.voucher-auto-book-enabled. Appen har ingen side, der gemmer det. For det tredje bruger operatørknappen Auto bogførqualifiesForOperatorAutoBook. Den kræver status Afventer, et bekræftet match, en konto på hver linje, linjesummen og et grønt bogførbarhedstjek, men ikke de to flag. Den stempler ikke auto_booked_at.
BookVoucherJob::handle kører først sin egen dublet-vagt. Derefter kalder den VoucherBookingService::book, som kører vagterne herunder. Vagt 1 til 11 ligger i VoucherBookingGate::refuse, og vagt 13 til 15 ligger i VoucherBookingService::book. "Også manuel" betyder, at vagten står foran force, så en menneskelig Bogfør ikke kan tvinge den igennem.
"Ingen modkonto (bankkonto) konfigureret. Gå til Indstillinger → Integrationer for at konfigurere din bankkonto." eller "Vælg bogføringskonto på bankforbindelsen"
Fejlet
ja
Hver vagts VoucherBookBlocker-case og dens fulde tekst står i tilstand.voucher.book-blocker. Vagt 1 kører før alle de andre, også før vagt 2, fordi et bilag med en uafsluttet kladde ofte står som Bogført. Recon-listen fra 2026-10-01 har samme rækkefølge, men mangler vagt 11 og dublet-vagten i jobbet.
Alt i tabellen er vores egen kode. Udbyderens egne grænser og regler er ikke påstået her, fordi de kræver udbyder-doc eller live-probe, som kataloget ikke har for bogføring.
Udbyder
Kald i rækkefølge
Hvad vi sender
Hvad vi gemmer
Bilagsfilen
e-conomic
1. find journal. 2. POST /journals/{n}/vouchers. 3. upload fil. 4. valgfri periodisering. 5. slå kladdelinjer op og bookdraftentries. 6. fallback til dato-kaldet
En financeVoucher pr. linje, eller én samlet, med konto, moms, afdeling, projekt og valuta. Kurs sættes, når en udenlandsk valuta er afregnet af en kronebevægelse
external_voucher_id som år-bilagsnummer, external_voucher_number, accounting_year, journal_number, journal_state
Lægges på kladden, før den bogføres. Fejler det, sendes PushVoucherDocumentToEconomic efter bogføringen
Dinero
1. upload fil. 2. createManualVoucher. 3. bookManualVoucher med Timestamp. 4. læs bilaget tilbage og kontrollér
Lines, VoucherDate, ExternalReferencepf_voucher_{id} og FileGuid
Bilagets Guid i external_voucher_id, posted_amount_dkk, posted_vat_codes, journal_state
FileGuid i selve oprettelsen
Billy
1. find næste bilagsnummer. 2. opret kassekladde-transaktion som draft. 3. læg bilag ved. 4. godkend transaktionen
Kolonnen svarer på et andet spørgsmål end status. Status er Bogført, så snart en postering findes hos udbyderen. journal_state siger, om den nåede regnskabet: Kladde, Bogført, Fejlet eller Ubekræftet. Null betyder, at spørgsmålet aldrig blev besvaret. Alle overgange står i tilstand.voucher.journal-state. Statusmaskinen står i tilstand.voucher.status.
Alt, der poster til et regnskab, skal læse null som "gør ingenting". Unconfirmed er værdien for "tjek først".
failed() gør tre ting. Har bilaget allerede nået regnskabet (status Bogført eller Tilbageført, booked_at eller journal_state Bogført), skriver den kun en log og rører ikke bilaget, så en timeout efter en lykket postering ikke ender som en Fejlet-markering på et bilag, der står i regnskabet. Ellers rapporterer den en AutoBookFailedException, hvis jobbet var en auto-bogføring. Til sidst sætter den status Fejlet og gemmer undtagelsens tekst i booking_error.
vouchers:recover-stuck-booking (job.vouchers-recover-stuck-booking, schedule.recover-stuck-booking) flytter bilag, der har stået i Booking i over 60 minutter (regel.bogfoering.hang-graense), til Fejlet. Den bogfører ikke igen. book() er ikke idempotent mod regnskabet: e-conomic-kaldet har ingen idempotensnøgle, og døde jobbet efter udbyderens svar, men før stemplingen, ville et nyt kald bogføre to gange. Uret er updated_at, som sættes ved afsendelse, så tid i køen tæller med. En betinget opdatering sikrer, at et bilag, der blev bogført midt i kørslen, ikke overskrives.
Bagefter skal brugeren kigge i regnskabet efter en allerede oprettet postering. Teksten i booking_error siger det. Er der ingen, kan bilaget bogføres igen, for Fejlet er bogførbart.
Selskabets kolonne accounting_writes_paused_at stopper automatiske skrivninger til regnskabet. Kunden sætter den og fjerner den i automatiseringsoversigten, og ruten kræver automation.edit. Hvem og hvorfor gemmes i accounting_writes_paused_by og accounting_writes_pause_reason, og begge handlinger skrives til AdminActionLog. Se indstilling.company.accounting-writes-paused-at.
Pausen virker to steder. job.middleware.defer-when-accounting-writes-paused holder et ledger-job tilbage og gemmer det som en DeferredAccountingWrite. Og AccountingWriteGate står som første sætning i hver skrivende metode i udbyderklienterne og afviser det, som middleware ikke fangede.
Pausen stopper robotten, Auto bogfør-knappen, lønjournaler, betalinger, kreditnotaer og abonnementsfakturaer. Den stopper ikke en skrivning, som et menneske har bedt om. BookVoucherJob markerer sig som brugerinitieret, når force er sand. Markeringen følger ikke med ind i et job, og en skrivning, ingen har markeret, tæller som automatisk.
Resume sender ikke de ventende skrivninger. Kunden vælger Send eller Kassér i oversigten, fordi en resume, der sendte to ugers bogføringer ind i et levende regnskab, ville være en overraskelse. Fælden står i faelde.bogfoering.glemt-pause-slukker-automatik, og samspillet med oprydning i faelde.bogfoering.oprydning-og-skrivepause. Samme gate afviser også selskaber med abonnementsgæld, og det hjælper ikke at være brugerinitieret.
Et bilag kan tilbageføres, når status er Bogført, reversed_at er tom, og bilaget har en udbyder og en reference til udbyderens bilag. Det kræver også en modkonto, med undtagelse af et Dinero-bilag, der er importeret fra kundens eget regnskab. Se regel.bogfoering.tilbagefoer-kun-bogfoert.
Rækkefølgen er: tag kravet reversal_claimed_at med en betinget opdatering (regel.bogfoering.tilbagefoer-claim), kald udbyderen, og gem derefter Reversed lokalt. Den lokale skrivning forsøges tre gange, og kun den, aldrig udbyderkaldet. Lykkes udbyderen, men ikke den lokale skrivning, bliver kravet stående, og svaret er "Tilbagefør IKKE igen" og ikke en ny modpostering.
Hos udbyderen:
e-conomic: de samme financeVoucher-linjer, hver negeret, i samme journal, bilagsfilen lagt ved, periodiseringen spejlet, og derefter bogføring. Tekst: "Modpostering af:".
Dinero: en spejlvoucher med konto og modkonto byttet. En ubogført kladde slettes i stedet.
Billy: en ubogført kladde slettes, en bogført transaktion annulleres.
Business Central: en modpostering af kladdelinjerne.
Efter en tilbageføring er journal_state null, og modposteringens eget udfald ligger i booking_error, hvis den ikke nåede at blive bogført. Efter Dinero- eller Billy-sletningen er bilaget Afventer, og alle bogføringsstempler er nulstillet, men kontiene beholdes.
Hvad låses: et bogført bilag kan ikke slettes, for sletningen afviser, når status er Bogført og bilaget har en reference. Det kan ikke redigeres eller scannes igen, og det kan ikke få en ny fil. Et tilbageført bilag er lige så låst. Se regel.bogfoering.laast-efter-bogfoering.
To vagter går efter dubletter, og de ser forskelligt. Vagt 10 (regel.bogfoering.vagt-bankpostering-allerede-bogfoert) søger den spejlede accounting_entries på bankforbindelsens afstemningskonto, bankliniens dato og beløb. Spejlet hentes hver time. Vagt 11 (regel.bogfoering.vagt-lignende-live-postering) læser kladder og bogførte poster live hos udbyderen og matcher på dato, beløb og bankkonto. En vagt-10-afvisning kan ingen tvinge igennem. En vagt-11-afvisning kan et menneske bekræfte, når begge sider er vist. Robotten bekræfter aldrig.
Bogføringen er envejs. Hvad regnskabet siger bagefter, hentes af to synkroniseringer.
job.sync-accounting-vouchers henter bilag fra udbyderen ind i vouchers. Det kører som en fase i den synk-kæde, som schedule.sync-accounting-data starter hver time, på køen koe.accounting-sync, og er unikt pr. selskab og tilstand i 3600 sekunder, forsøger tre gange og kan slås fra med accounting.voucher_sync_enabled. Første import og fuld synk henter fra starten af det regnskabsårsvindue, AccountingSyncService::fiscalYearWindow giver. En almindelig synk henter siden sidste synk minus en dag. Oprydning af forældede bogførte bilag kører kun i en fuld synk, kun for e-conomic og kun med indstilling.env.accounting-voucher-prune-enabled.