Årsavslutning — implementasjon

Denne siden beskriver den tekniske implementasjonen av årsavslutningskalkulatoren i Finsta. Mens de øvrige sidene Skatt til Disponering dekker regnskapsreglene, fokuserer denne siden på kalkulator-pipelinen, dens input og samspillet med saldobalansen.

Oversikt

YearEndClosingCalculator orkestrerer fem delkalkulatorer som kjøres i en fast rekkefølge. Hvert steg kan avhenge av resultatet fra foregående steg.

plantuml::example$/year-end-closing/yec-pipeline.puml[]

Det endelige YearEndClosingEntity-objektet inneholder alle genererte tilleggsposteringer samt merknader og advarsler satt sammen av YearEndClosingRemarkAssembler.

Input

Kjernedata

Input Beskrivelse

TrialBalance (saldobalanse)

Kontosaldoer for regnskapsåret. Hentes via ExistingAccounts for å ekskludere eksisterende årsavslutningstransaksjoner.

FinancialStatement

Næringsoppgave-entiteten som inneholder inndataposter (parametere) lagt inn av brukeren.

BusinessInformation

Beregnede størrelser som beregnet næringsinntekt og midlertidige forskjeller.

CompanyGroupRegistryComposite

Konsernbidragsdata fra cogreg-modulen. Kun relevant når PostTrait.CompanyGroup er aktivt.

Parametere (CalculateYearEndClosingParams)

Åtte valgfrie parametere som hentes fra inndataposter lagret på næringsoppgaven. YearEndClosingParamsBuilder leser inndataposter fra næringsoppgave-entiteten og mapper dem til params-recorden. Konsernparametere er betinget av PostTrait.CompanyGroup.

Skatteparametere

Postkode Felt Beskrivelse

YECTCGCR

receivedCompanyGroupContributionsWithTaxEffect

Mottatte konsernbidrag med skatteeffekt (kun konsern)

YECT001

transferableDeficitPrevious

Fremførbart underskudd fra foregående år

YECT002

appliedDeficitFromPrevious

Andel av fremførbart underskudd benyttet i år

YECT003

alreadyRegisteredTax

Skatt allerede bokført før årsavslutning

Parametere for utsatt skatt

Postkode Felt Beskrivelse

~YECDT001~

~registeredTransferableDeficitPrevious~

Utgår. Var brukt av den delta-drevne kalkulatoren til å angi hvor mye av foregående underskudd som allerede var reflektert i IB 1070/2120. Har ingen effekt i den NRS-kanoniske, målstyrte kalkulatoren og ignoreres. Beholdt for bakoverkompatibilitet med lagrede inndataposter.

~YECDT002~

~negativelyBalancedOutPrevious~

Utgår. Pass-through-felt — leses fra params og lagres uendret på DeferredTaxBasisAntity, men inngår ikke i målstyrt beregning. Tverr-årslig overføring av ubenyttet underskudd skjer via transferableDeficitPrevious. Beholdt for bakoverkompatibilitet med lagrede inndataposter, videreføringskjeden i YearEndClosingParamsBuilder, og noterender i frontend.

YECDT003

registerDeferredTaxAdvantage

Om utsatt skattefordel skal bokføres (standard: Answer.No)

Utbytteparametere

Postkode Felt Beskrivelse

YECDV001

extraAllocatedDividendForNextYear

Ekstra utbytte avsatt for neste år utover det som allerede er bokført

ExistingAccounts-mønsteret

Alle delkalkulatorer leser kontosaldoer via ExistingAccounts, en record som slår opp saldoer i saldobalansen og samtidig ekskluderer eksisterende årsavslutningstransaksjoner.

ExistingAccounts.withoutYec(trialBalance, accountNoOrRange)

Metoden registered() returnerer:

closingBalance - excludedTransactionAmounts

Dette sikrer at kalkulatoren unngår dobbeltelling ved rekalkulering: eksisterende årsavslutningstransaksjoner strippes ut slik at beregningen alltid starter fra de samme grunnlagstallene.

Steg 1: Skatt (TaxCalculator)

Bygger en TaxBasisAntity basert på:

  • estimatedBusinessIncome — fra BusinessInformation

  • receivedCompanyGroupContributionsWithTaxEffect — fra parametere (eller overstyrt fra cogreg)

  • transferableDeficitPrevious — fra parametere eller utkast til skattemelding

  • appliedDeficitFromPrevious — fra parametere

  • alreadyRegisteredTax — fra parametere

Beregning

  effectiveTaxBasis = estimatedBusinessIncome + receivedCGContributions

  if effectiveTaxBasis <= 0 --> tax = 0

  taxableAmount = effectiveTaxBasis - appliedDeficitFromPrevious

  if taxableAmount <= 0 --> tax = 0

  tax = taxableAmount * 0.22  (avrundet HALF_UP, 0 desimaler)

Bokføring

Table 1. Skattetransaksjon
Konto Beskrivelse

8300

Betalbar skatt (debet)

2500

Betalbar skatt, ikke utlignet (kredit)

Transaksjonsbeløp: tax - alreadyRegisteredTax.

Steg 2: Utsatt skatt (DeferredTaxCalculator)

NRS(F) Resultatskatt §2.4 / NRS 8 §10-alignert, målstyrt kalkulator. Se NRS(F) Resultatskatt 2008 og NRS 8 (des 2021).

Kalkulatoren bruker standard regnskapskonvensjon gjennomgående: positivt = forpliktelsesretning (utsatt skatt), negativt = fordelsretning (skattefordel).

Prinsipp: reelle verdier styrer grunnlaget

tempDiffCurrent (post 200DC) og transferableDeficit er de reelle inngangsstørrelsene. IB på 1070/2120 er bokføringstekniske detaljer — de påvirker ikke grunnlaget, kun transaksjonsdelta-et.

Algoritme (fem steg)

Steg 1 — Fjorårsposisjon. To halvdeler:

  • Bokført — IB på 1070/2120, strippes for årsavslutningsposteringer via ExistingAccounts.withoutYec().

  • Ikke-bokførttransferableDeficitPrevious og negativelyBalancedOutPrevious fra parametere. Når registerDeferredTaxAdvantage = No er IB på 1070 null per konstruksjon; disse parameterne er da eneste signal om at et ubenyttet underskudd/midlertidig forskjell videreføres.

Steg 2 — Årets posisjon i grunnlagsform.

ubBasis = tempDiffCurrent − transferableDeficit

der

transferableDeficit = deficitCurrent + transferableDeficitPrevious − appliedDeficitFromPrevious

Negativt ubBasis = skattefordelsretning, positivt = skatteforpliktelsesretning.

Steg 3 — Målsaldoer.

targetAdvantage   = |ubBasis| × 0.22   hvis ubBasis < 0 AND register = Yes,  ellers 0
targetObligation  = −ubBasis × 0.22    hvis ubBasis > 0,                      ellers 0

Steg 4 — Transaksjoner som delta.

Δ1070 = targetAdvantage  − IB 1070
Δ2120 = targetObligation − IB 2120

Ingen netting mellom 1070 og 2120 — eksisterende saldo fra urelaterte hendelser reverseres separat.

Steg 5 — Noteopplysning (NBO).

Table 2. Ikke-balanseført beløp (grunnlagsform, NRS(F) §2.4)
Situasjon Verdi

register = Yes (balanseført)

0 — hele fordelen er bokført

register = No og ubBasis < 0

|ubBasis| — det ikke-bokførte grunnlaget

Begge variantene (nboBasisIfBooked, nboBasisIfNotBooked) er alltid tilgjengelige på NegativelyBalancedOutAntity slik at frontend kan vise en sammenligning.

registerDeferredTaxAdvantage-bryteren

Hovedregel: Utsatt skatt (2120) SKAL alltid bokføres. Utsatt skattefordel (1070) KAN kun bokføres dersom det er sannsynlig at den kan utnyttes.

Bryteren påvirker kun målsaldoen for 1070 (steg 3) og noteopplysningen (steg 5). Den delta-drevne logikken med removeDeferredTaxAdvantage-postpasset er fjernet.

Steg 3: Årsresultat (NetProfitOrLossCalculator)

Beregner det kompenserte årsresultatet fra post 9100 (resultat før skattekostnad). Post 9100 inneholder ingen 83xx- eller 89xx-kontoer, og gir dermed et rent utgangspunkt.

kompensertÅrsresultat = post9100 - skatt - actualDeferredTax()

actualDeferredTax() returnerer P&L-effekten av utsatt skatt — beløpet som faktisk er bokført på 8321/8322 i perioden (deferredTaxPnlEffect), ikke den fulle utsatt-skatt-verdien fra grunnlaget. Når «bokfør utsatt skattefordel» er avslått, returneres i stedet nbo-verdien (tilbakeføring av eksisterende fordel).

Steg 4: Utbytte (DividendCalculator)

Leser eksisterende utbyttekontosaldoer:

Table 3. Utbyttekontoer
Konto Beskrivelse

8921

Tilleggsutbytte fra tidligere år

8922/8923

Ekstraordinært utbytte inneværende år

8920

Avsatt utbytte for neste år

Beregning

  sumDividend = additionalFromPreviousYear
              + extraordinaryCurrentYear
              + alreadyAllocatedForNextYear

  availableForAllocation = compensatedNetProfitOrLoss - sumDividend
                           (begrenset til annen egenkapital-saldo)

  totalAllocatedForNextYear = alreadyAllocated + extraAllocatedDividendForNextYear

Oppretter en tilleggspostering dersom ekstra utbytte avsettes: D: 8920, K: 2800. Når spesifikasjonen angir et kontointervall (f.eks. 8920-8921), brukes alltid den første kontoen i intervallet som debetkonto i tilleggsposteringen. Brukeren kan foreløpig ikke velge hvilken konto som benyttes.

Steg 5: Disponering (AllocationCalculator)

Fordeler sluttresultatet til egenkapital- eller tapskontoer.

Grunnlag

  allocationAmount = compensatedNetProfitOrLoss
                   + receivedCgOnDisponering         (kompensasjon for 8930-8934, se under)
                   - totalSubmittedCompanyGroupContributions (justert for skatteeffekt)
                   - totalDividendAllocatedForNextYear

receivedCgOnDisponering er sum av saldoer på kontoene 8930–8934 (mottatt konsernbidrag ført direkte som disponeringspost), negert. Disse kontoene inngår i POST 8999 (disponeringer) og ikke i POST 9200 (årsresultat). Uten kompensasjonen ville bokføring av konsernbidrag på 8930 (disponeringspost) gi en lavere disponering enn bokføring på 8001 (inntektskonto), selv om egenkapitaleffekten er identisk. Kompensasjonen sikrer at YEC-posteringen på 8960 → 2050 er den samme uavhengig av hvilken konto konsernbidraget er ført på.

Transaksjonsscenarioer

Table 4. Disponeringstransaksjoner
Scenario Debet Kredit

Overskudd dekker udekket tap fra tidligere

8969

2080

Overskudd overført til annen egenkapital

8960

2050

Underskudd overført fra annen egenkapital

2050

8961

Underskudd overført til udekket tap

2080

8990

Når disponeringen skifter retning (f.eks. overskudd som først må dekke tap før overføring til egenkapital), genereres to transaksjoner.

Spesifikasjonsversjonering

Årsavslutning hentes fra to separate CSV-kilder, hver med sitt eget ansvar og sin egen provider. Begge versjoneres etter samme prinsipp som postspesifikasjonene (se versjonering): versjonerte rader overstyrer uversjonerte rader for et gitt inkrement, slik at vi kan rette mappinger uten å påvirke eksisterende årsregnskap.

Table 5. YEC-CSV-kilder
Fil Provider Ansvar

yec-spec-mapping-<year>-<type>.csv

YearEndClosingSpecProviderYearEndClosingSpec

Kalkulatorens kontomapping og skattesats: hvilke kontoer skatt, utsatt skatt, utbytte og disponering bokføres på (8300/2500, 8321/8322/1070/2120, 8920–8923, 8960/8961/8969/8990/2050/2080), samt skattesatsen (0.22) og postkoder for midlertidige forskjeller (200DC/200DP/200R).

posts-spec-mapping-<year>-<type>.csv

PostsSpecProviderPostsSpec

YEC-inndataposter (input-rader): YECT001YECT003, YECDT001YECDT003, YECDV001, YECTCGCR. Disse er de brukerredigerbare parameterne som YearEndClosingParamsBuilder leser ut av næringsoppgaven og mapper til CalculateYearEndClosingParams. Inneholder også from-poster som henter resultater tilbake fra YEC-motoren (f.eks. IAD020 FROM yec-ad, IAD021 FROM yec-tdfp).

Med andre ord: yec-spec-mapping styrer hvor posteringene havner og hva skattesatsen er, mens posts-spec-mapping styrer hvilke spørsmål brukeren får og hvordan resultatene flyter videre inn i næringsspesifikasjonen.

Table 6. Viktige kildefiler
Komponent Sti

YearEndClosingSpecProvider

finsta-csv-parser/…​/spec/YearEndClosingSpecProvider.java

YearEndClosingSpec

finsta-api/…​/api/spec/yeaclo/YearEndClosingSpec.java

PostsSpecProvider

finsta-csv-parser/…​/parser/posts/PostsSpecProvider.java

Kalkulator-CSV

finsta-csv-parser/…​/csv/<year>/yec-spec-mapping-<year>-AS.csv

Inndataposter-CSV

finsta-csv-parser/…​/csv/<year>/posts-spec-mapping-<year>-AS.csv

YEC-versjonering (YecVersion)

YecVersion er en enum som stempler hver YearEndClosingEntity med hvilken kalkulator-kontrakt raden ble produsert under. Mønsteret speiler AssregVersion i aktivaregisteret.

Hvorfor versjonering trengs

Kalkulatoren gikk fra en delta-drevet modell — "bokfør differansen mellom det vi vil ha og det som allerede ligger i alreadyRegistered*`" — til en target-drevet modell: for hver bokføringsakse beregner kalkulatoren år-slutt-målbalansen (med Finstas egne YEC-transaksjoner strippet ut av eksisterende posisjon), og utleder bokføringen som `target − existing.

De fire aksene:

Akse Kontoer Eksisterende posisjon på grunnlaget

Skatt

2500 ↔ 8300

alreadyRegisteredTax (skyldig betalbar skatt med YEC strippet)

Utsatt skatt

1070 ↔ 2120

existingAdvantage / existingObligation

Utbytte

2800 ↔ 8920

alreadyAllocatedForNextYear (8920-posisjon med YEC strippet)

Disponering

2050 ↔ 2080

existingOtherEquity / existingUncoveredLoss

Dette er en semantisk endring i hvordan YEC-bokføringer regnes ut, ikke bare et tillegg av felter. Rader produsert under V0 følger andre regler enn V1-rader, og resten av systemet (frontend-rendering, framtidige kalkulatorer, revisjoner) må kunne resonnere om det eksplisitt.

Verdiene

Verdi Beskrivelse

V0_PreVersioning

YEC beregnet under den delta-drevne modellen. Null på entiteten normaliseres til denne verdien av mapperen.

V1_TargetDrivenCalc

Target-drevet kalkulasjon (gjeldende). existing*-feltene på hvert grunnlag er kundens løpende posisjon med Finstas egen YEC-transaksjon strippet.

YecVersion.CURRENT peker på den nyeste verdien (i dag: V1_TargetDrivenCalc).

Når blir versjonen stemplet

Versjonen settes til YecVersion.CURRENT inne i YearEndClosingEntity.withData(…​) — kalkulatorens ene innstegspunkt for å skrive nye data. Det betyr at:

  • Levende årsregnskap får CURRENT ved neste SynchronizationService-kjøring.

  • Frosne årsregnskap blir værende på sin frys-tids-versjon. Frosset betyr frosset — ingen resync — og versjonen reflekterer reglene de ble beregnet under.

Migrasjonen V2_3_0_1190 legger til kolonnen yec_version uten backfill: null = V0_PreVersioning, som er korrekt semantikk for eldre rader.

Vedlikeholdsregel

YecVersion.CURRENT skal bumpes hver gang kalkulatorens kontrakt endres på en måte som gjør at eldre rader følger andre regler enn nye:

  • Ny bokføringsakse (eller endret kontomapping for en eksisterende akse).

  • Semantisk endring i hvordan existing* utledes (f.eks. ny strip-strategi).

  • Endring i hvilken delkalkulator som eier hvilken transaksjon.

Å glemme bumpen er et stille feilmodus — samme risikomodell som for AssregVersion. Frontenden bruker for eksempel yecVersion === V1_TargetDrivenCalc til å gate den per-undertema kalkulasjonsdetalj-panelen; uten en bump ville V0-data feilrenderes som om den fulgte V1-kontrakten.

Table 7. Viktige kildefiler
Komponent Sti

YecVersion

finsta-api/…​/api/yeaclo/YecVersion.java

YearEndClosingEntity#withData

finsta-domain/…​/domain/yeaclo/YearEndClosingEntity.java

YearEndClosingMapper

finsta-domain/…​/domain/yeaclo/YearEndClosingMapper.groovy

Migrasjon

finsta-db/…​/tenant/V2_3_0_1190__alter_table_year_end_closing_add_yec_version.sql

Tilleggsposteringer

Alle tilleggsposteringer opprettes via YearEndClosingMethods.createYecAtx():

  1. Oppretter debet- og kredit-TransactionLineAntity

  2. Søker etter eksisterende årsavslutningstransaksjoner på de samme kontoene

  3. Gjenbruker eksisterende transaksjons-UUID dersom funnet (idempotente oppdateringer)

  4. Daterer transaksjonen til period.getEndsAt() (slutten av regnskapsåret)

  5. Setter opprinnelse til TransactionOriginAntity.of(Finsta, YearEndClosing)

Konsernbidrag

Når PostTrait.CompanyGroup er aktivt, påvirker konsernbidrag flere steg:

  • Skatt: mottatte bidrag med skatteeffekt LEGGES TIL beregnet næringsinntekt

  • Utsatt skatt: mottatte bidrag påvirker beregningen av fremførbart underskudd

  • Disponering: avgitte bidrag (justert med faktor 1 - skattesats) TREKKES FRA disponeringsbeløpet

Data hentes fra CompanyGroupRegistryComposite (cogreg-modulen).

Merknader

YearEndClosingRemarkAssembler delegerer til BusinessInformationEntity.toInfo().assembleYecRemarks() for å generere advarsler og merknader som returneres sammen med beregningsresultatet.

Planlagte merknader for utsatt skatt (ikke implementert — Phase 5)

Følgende merkander er identifisert men ikke implementert ennå. De skal legges til i YearEndClosingRemarkAssembler og/eller DeferredTaxCalculator når utsatt-skatt-løsningen er stabilisert.

Table 8. Planlagte merknader
Trigger Alvorlighet Merknad

IB på 1070 er positiv (kredittsaldo — feil fortegn for en eiendel)

Advarsel

Eksisterende saldo på konto 1070 har feil fortegn. Sjekk om årsavslutningstransaksjoner er korrekt stripset, eller om det er en manuell bokføringsfeil.

IB på 2120 er positiv (debetsaldo — feil fortegn for en forpliktelse)

Advarsel

Eksisterende saldo på konto 2120 har feil fortegn. Sjekk om årsavslutningstransaksjoner er korrekt stripset, eller om det er en manuell bokføringsfeil.

appliedDeficitFromPrevious > transferableDeficitPrevious + deficitCurrent

Feil

Anvendt fremført underskudd overstiger tilgjengelig underskudd. Parametrene for YECT001/YECT002 er inkonsistente.

registerDeferredTaxAdvantage endret fra YesNo sammenlignet med fjorårets YEC

Info

Bokføring av utsatt skattefordel er slått av. Eksisterende saldo på 1070 reverseres.

registerDeferredTaxAdvantage endret fra NoYes sammenlignet med fjorårets YEC

Info

Bokføring av utsatt skattefordel er slått på. Fordelen balanseføres for første gang dette året.

registerDeferredTaxAdvantage = No og ubBasis < 0 med IB 1070 > 0

Info

Utsatt skattefordel vil ikke bokføres, men det er en eksisterende saldo på 1070. Saldoen reverseres.

Viktige kildefiler

Komponent Sti

YearEndClosingCalculator

finsta-service/…​/yeaclo/YearEndClosingCalculator.java

TaxCalculator

finsta-service/…​/yeaclo/TaxCalculator.java

DeferredTaxCalculator

finsta-service/…​/yeaclo/DeferredTaxCalculator.java

NetProfitOrLossCalculator

finsta-service/…​/yeaclo/NetProfitOrLossCalculator.java

DividendCalculator

finsta-service/…​/yeaclo/DividendCalculator.java

AllocationCalculator

finsta-service/…​/yeaclo/AllocationCalculator.java

ExistingAccounts

finsta-service/…​/yeaclo/ExistingAccounts.java

YearEndClosingMethods

finsta-service/…​/yeaclo/YearEndClosingMethods.java

YearEndClosingParamsBuilder

finsta-domain/…​/yeaclo/YearEndClosingParamsBuilder.java

YearEndClosingServiceBean

finsta-service/…​/yeaclo/YearEndClosingServiceBean.java

YearEndClosingController

finsta-service-app/…​/yeaclo/YearEndClosingController.java