Gå til indhold

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.

Nordstjernen

domaene.bogfoering

Faste regler 45

Vis alle 45

Eksterne services 9

  • AiiaHenter konti og transaktioner for en samtykket bankforbindelse.
  • AnthropicOCR af bilag, filter-AI på indgående mail og kontoforslag på bilag og leverandørfakturaer.
  • BillyBogføring, spejling af posteringer og kortet over Billy-vedhæftninger.
  • Business CentralBogføring, spejling af finansposter, bilagskort og fornyelse af change-notification-abonnementer.
  • DineroBogføring, spejling af poster og kortet fra bilagsnummer til fil.
  • e-conomicBogføring af bilag, spejling af poster, kontoplan, kassekladde-kladder og dokumentkortet economic_documents.
Vis alle 9
  • OverførselsserviceAfsender leverancer og henter kvitteringsfiler over SFTP.
  • RevolutHenter transaktioner og, for Revolut Business, udgiftsbilag.
  • YapilyHenter konti og transaktioner for en samtykket bankforbindelse.

Faste regler: regel.bogfoering.vagt-allerede-bogfoert, regel.bogfoering.vagt-bankpostering-allerede-bogfoert, regel.bogfoering.laast-efter-bogfoering og de øvrige regel.bogfoering.*. Indstillinger: indstilling.company.accounting-writes-paused-at kan kunden sætte i appen. indstilling.company.voucher-auto-book-enabled og indstilling.env.accounting-auto-book-enabled kan kun PayFriend ændre. Eksterne services: integration.economic, integration.dinero, integration.billy og integration.business-central.

0

På 30 sekunder

For alle

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?

Sektion kaldt “Kunden har trykket Bogfør, men intet sker i e-conomic. Hvor kigger jeg?”

Kig på bilaget i denne rækkefølge.

  1. 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.
  2. Status Fejlet. Teksten i bilagets booking_error er årsagen. Se tilstand.voucher.book-blocker for de tekster, brugeren kan se.
  3. Status Afventer med en tekst. En vagt har sendt bilaget tilbage. Teksten forklarer hvorfor.
  4. 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.
  5. Status Bogført og journal_state Unconfirmed. Kladden findes, men bogføringstrinnet fejlede. Et nyt tryk på Bogfør genoptager den samme kladde.
  6. Der kom en bekræftelsesdialog. Så blev intet sendt. PayFriend fandt en lignende postering i regnskabet og venter på, at et menneske bekræfter.
  7. Skrivepause eller abonnementsgæld. Se regel.bogfoering.skrivepause og regel.bogfoering.betalingsgaeld-stopper-skrivning. Kundens egen manuelle Bogfør går forbi pausen, men ikke forbi abonnementsgæld.

Hele rækken står i faelde.bogfoering.intet-sker-i-economic.

Hvorfor bogførte robotten dette bilag uden at spørge?

Sektion kaldt “Hvorfor bogførte robotten dette bilag uden at spørge?”

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.

Sporet er auto_booked_at på bilaget og en række i aktivitetsloggen. Er et bilag bogført af Auto bogfør-knappen, har det ikke auto_booked_at. Se faelde.bogfoering.robotten-bogfoerte-uden-at-spoerge.

Kan jeg fortryde en bogføring, og hvad ser revisoren så?

Sektion kaldt “Kan jeg fortryde en bogføring, og hvad ser revisoren så?”

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.

Herfra er det teknisk

2

Bogføring i ti dele

Teknisk

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.

VejUdløserRouteforceStemples Booking førstKilde
Enkelt BogførKnappen på bilagetvouchers.bookjajaVoucherBookRequest::book
Bulk Bogfør og AI BogføringValgte bilag i listen, valgfrit med et journal_numbervouchers.batch-bookja, og med autoSuggestAccountjaVoucherBatchBooking::batchBook
Auto bogfør-knappenOperatøren, for alle kvalificerede bilagvouchers.auto-booknejjaVoucherController::autoBook
Bank, Bogfør fra afstemningMatch-panelet, og start af bogføring efter et bekræftet matchbank.reconciliation.book-voucherjajaReconciliationVoucherActions::bookVoucher, VoucherBookingStarter::startForVoucher
UovervågetScanVoucherJob, når politikken siger jaingennej, men autoBook er sandnejScanVoucherJob::handle

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ør qualifiesForOperatorAutoBook. 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.

#VagtBrugeren serBilaget bagefterOgså manuel
0regel.bogfoering.vagt-dublet-i-jobbet"Kan ikke bogføre: bilaget er markeret som muligt dublet – risiko for dobbeltbetaling. Gennemgå bilaget og vælg "Ikke en dublet" først."Afventerja
1regel.bogfoering.vagt-genoptag-kladde"Bilag bogført i e-conomic (bilagsnr. N)." eller en kladde-beskedBogførtja
2regel.bogfoering.vagt-allerede-bogfoert"Bilaget er allerede bogført."uændretja
3regel.bogfoering.vagt-tilbagefoert"Bilaget er tilbageført og kan ikke bogføres igen."uændretja
4regel.bogfoering.vagt-konverteret"Bilaget er konverteret til en regning og bogføres derfra."Konverteretja
5regel.bogfoering.vagt-foer-skaeringsdatoTeksten for already_booked_pre_cutoverAfventerja
6regel.bogfoering.vagt-dokumenterer-eksisterendeTeksten for documents_existing_entryAfventerja
7regel.bogfoering.vagt-mangler-beloebTeksten for missing_amountAfventerja
8regel.bogfoering.vagt-afventende-reservationTeksten for pending_settlementAfventerja
9regel.bogfoering.vagt-loenbilag"Lønbilag bogføres som en opdelt kassekladde og kan ikke bogføres som et almindeligt bilag. Godkend lønbilaget under Løn."Fejletja
10regel.bogfoering.vagt-bankpostering-allerede-bogfoertTeksten for bank_ledger_already_postedAfventerja
11regel.bogfoering.vagt-lignende-live-posteringEn bekræftelsesdialog med begge siderAfventerja, men et menneske kan bekræfte
12regel.bogfoering.vagt-bogfoerbarhed"Bilaget kan ikke bogføres endnu: " og blokeringernes teksterAfventernej
13regel.bogfoering.vagt-ingen-integration"Ingen aktiv regnskabsintegration fundet. Forbind e-conomic eller Dinero under Indstillinger → Integrationer."Fejletja
14regel.bogfoering.vagt-ingen-linjer"Bilaget har ingen linjer. Tilføj mindst én linje før bogføring." eller "Ingen udgiftskonto er valgt. Kontér bilaget først."Afventer, hvis det stod i Booking, ellers Fejletja
15regel.bogfoering.vagt-modkonto"Ingen modkonto (bankkonto) konfigureret. Gå til Indstillinger → Integrationer for at konfigurere din bankkonto." eller "Vælg bogføringskonto på bankforbindelsen"Fejletja

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.

UdbyderKald i rækkefølgeHvad vi senderHvad vi gemmerBilagsfilen
e-conomic1. find journal. 2. POST /journals/{n}/vouchers. 3. upload fil. 4. valgfri periodisering. 5. slå kladdelinjer op og bookdraftentries. 6. fallback til dato-kaldetEn 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ægelseexternal_voucher_id som år-bilagsnummer, external_voucher_number, accounting_year, journal_number, journal_stateLægges på kladden, før den bogføres. Fejler det, sendes PushVoucherDocumentToEconomic efter bogføringen
Dinero1. upload fil. 2. createManualVoucher. 3. bookManualVoucher med Timestamp. 4. læs bilaget tilbage og kontrollérLines, VoucherDate, ExternalReference pf_voucher_{id} og FileGuidBilagets Guid i external_voucher_id, posted_amount_dkk, posted_vat_codes, journal_stateFileGuid i selve oprettelsen
Billy1. find næste bilagsnummer. 2. opret kassekladde-transaktion som draft. 3. læg bilag ved. 4. godkend transaktionenLinjer med konto, beløb og moms, state draftTransaktionens id, journal_state, posted_amount_dkkEfter oprettelsen, fordi filen hænges på en eksisterende transaktion
Business Central1. læg bilag ved kladdelinjerne. 2. send kladden gennem BusinessCentralJournalPoster::postJournallinjer med dokumentnummer V{id}, konto, moms og dimensionerDokumentnummeret, journal_stateFør posten, via BusinessCentralBookTimeAttachment

Referencen pf_voucher_{id} sendes kun til Dinero, se faelde.bogfoering.pf-voucher-reference-er-kun-dinero. Kladdetilstanden regel.bogfoering.kladde-tilstand fjerner det sidste trin hos alle fire.

Sekvensdiagram for e-conomic, enkelt Bogfør:

e-conomicVoucherBookingService::bookBookVoucherJobVoucherController::bookBrugere-conomicVoucherBookingService::bookBookVoucherJobVoucherController::bookBrugerPUT vouchers.bookstempler Bookingdispatch med forcebookvagt 2 til 15POST /journals/n/vouchersbilagsnummer og regnskabsårupload bilagsfil på kladdenslå kladdelinjer opPOST /journals/n/bookdraftentriesokstempler Booked og journal_stateBilag bogført

Alle skrivende kald går gennem AccountingWriteGate. e-conomic-bogføringen sendes uden HTTP-genforsøg, fordi et gensendt kald kan bogføre to gange.

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".

job.book-voucher er unikt pr. bilag (book-voucher:{id}, 600 sekunder, se regel.bogfoering.unik-laas), har ét forsøg (regel.bogfoering.ingen-genforsoeg) og et timeout på 120 sekunder. Klassen kalder ikke onQueue, så den ligger på Redis-forbindelsens standardkø, se koe.default.

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.

Handlingerne er handling.kvitteringer.bogfoer og handling.kvitteringer.tilbagefoer.

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.

Fælden om kladdeførende bogholdere står i faelde.bogfoering.kladdefoerende-bogholder-giver-dubletter. Fælden om, at robotten var blind for kassekladden, står i faelde.bogfoering.auto-book-blind-for-kassekladden. På main er den lukket for e-conomic, Billy og Business Central, men ikke hos Dinero, hvis opslag returnerer en tom kladdeliste. Vagt 11 kræver også en bekræftet banklinje med en afstemningskonto. Dato-fallbacken er beskrevet i faelde.bogfoering.dato-fallback-er-ikke-bilagsafgraenset.

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.

job.sync-accounting-entries spejler e-conomics finansposter ind i tabel.accounting-entries. Rækken er unik på selskab, udbyder, regnskabsår, bilagsnummer og linjenummer, så en kørsel to gange giver de samme rækker. SyncAccountingEntriesService::flushBatch upserter på præcis de fem kolonner. Dinero, Billy og Business Central har egne jobs, se job.sync-dinero-accounting-entries, job.sync-billy-accounting-entries og job.sync-business-central-accounting-entries.

Herfra er det teknisk

10

Kendte fælder

Teknisk