Wenche.Skattemelding (wenche v0.3.0)

Copy Markdown View Source

Tax return computation and submission for Norwegian AS (RF-1028 and RF-1167).

Ported from wenche/skattemelding.py in the original Python Wenche project.

  • beregn/2 returns the computed tax return as a structured map suitable for rendering in a UI or further processing.
  • valider/2 and send_inn/2 orchestrate validation and submission via Skatteetaten / Altinn 3.

Supports:

  • Standard 22 % corporate tax calculation
  • Fritaksmetoden (participation exemption) for subsidiary dividends
  • Loss carryforward deduction
  • Caller-supplied :permanent_forskjeller on SkattemeldingKonfig
  • Prior year comparison figures and equity reconciliation note (via beregn/2)

Authentication

Validation and submission use different auth flows:

  • Validation (valider/3SkdSkattemeldingClient) works with a Maskinporten + systemuser token, obtained via Wenche.Maskinporten.get_skd_skattemelding_token/2. The altinn:instances.read/.write scopes in that token are required so Skatteetaten can resolve the systemuser → executor trace via Altinn.
  • Submission (send_inn/4AltinnClient) requires an Altinn platform token obtained from ID-porten (end-user authentication + Altinn token exchange). Skatteetaten does not accept a system user for the submission step. Wenche does not provide an ID-porten flow — callers must obtain the Altinn token themselves and pass it via AltinnClient.new/2.

Experimental: Systemic submission

Systemic submission of the skattemelding via Altinn 3 (send_inn/4) is untested and highly experimental. It also requires the submitting end-user to be a registered revisor or regnskapsfører. Enable Wenche.Systembruker.rights([:skattemelding]) for the validation flow; it has no effect on submission since that goes through ID-porten.

Summary

Functions

Computes the tax return as a structured map.

Builds the data needed for <egenkapitalavstemming> in næringsspesifikasjonen.

Computes the skattepliktig næringsinntekt brutto (the "skattemessig resultat") for a given regnskap and permanent_forskjeller list.

Parses Skatteetaten's /valider response and extracts the SKD-computed values from the embedded skattemeldingUpersonligEtterBeregning document.

Returns {sum_tillegg, sum_fradrag} as positive integers from a list of permanent forskjeller. Used by the XML emitter to populate the derived <sumTilleggINaeringsinntekt> / <sumFradragINaeringsinntekt> elements Skatteetaten flags as missing.

Submits the tax return to Skatteetaten via Altinn 3.

Validates the tax return against Skatteetaten's validation API.

Functions

beregn(regnskap, konfig)

Computes the tax return as a structured map.

Returns a map with all computed values for RF-1167 and RF-1028, suitable for rendering in a UI or further processing.

beregn_egenkapitalavstemming(regnskap)

@spec beregn_egenkapitalavstemming(Wenche.Models.Aarsregnskap.t()) :: %{
  inngaaende_ek: integer(),
  utgaaende_ek: integer(),
  endringer: [map()],
  sum_tillegg: integer(),
  sum_fradrag: integer()
}

Builds the data needed for <egenkapitalavstemming> in næringsspesifikasjonen.

Returns a map with:

  • :inngaaende_ek — IB total egenkapital in whole kroner.
  • :utgaaende_ek — UB total egenkapital in whole kroner.
  • :endringer — list of %{id, type, kategori, beloep} rows describing each årets endring. beloep is always emitted as a positive integer; kategori (:tillegg or :fradrag) tells the consumer which sign to apply. type is a kode from the 2025_egenkapitalendringstype kodeliste.
  • :sum_tillegg, :sum_fradrag — derived sums for the optional XSD elements.

When the regnskap has no fjoraar data, IB is 0 and årsresultat is treated as the entire build-up of EK.

derive_skattepliktig_brutto(regnskap, permanent_forskjeller)

Computes the skattepliktig næringsinntekt brutto (the "skattemessig resultat") for a given regnskap and permanent_forskjeller list.

Used by the XML emitter to populate <beregnetNaeringsinntekt> / <skattemessigResultat> and the underskudd-derived elements Skatteetaten flags as missing. Mirrors what beregn/2 already computes internally for rf_1028.skattepliktig_inntekt_brutto.

parse_etter_beregning(body)

@spec parse_etter_beregning(binary()) :: map()

Parses Skatteetaten's /valider response and extracts the SKD-computed values from the embedded skattemeldingUpersonligEtterBeregning document.

SKD echoes back the skattemelding with derived (skatt:erAvledet="true") elements populated — those are the numbers callers want to display alongside a successful validation, since they're what Skatteetaten will use for tax assessment.

Returns a map with the extracted fields. Fields that aren't present in the response (which is normal — many are optional and only emitted when applicable) come back as nil.

Extracted fields

  • :partsnummer — SKD's resolved partsnummer
  • :inntektsaar
  • :inntekt_foer_fradrag_for_eventuelt_avgitt_konsernbidrag — taxable income before group contribution deduction (negative on a loss year)
  • :samlet_inntekt — total income after deductions (zero on a loss year)
  • :samlet_underskudd — year-loss
  • :fremfoert_underskudd_fra_tidligere_aar — prior-year carryforward used
  • :fremfoerbart_underskudd_i_inntekt — total loss available for future carryforward (prior + this year's added)
  • :netto_formue — net wealth
  • :samlet_formuesverdi_etter_verdsettingsrabatt
  • :samlet_gjeld

Pass the raw response body from valider/4's {:ok, body} tuple.

permanent_forskjeller_tillegg_fradrag(pf)

Returns {sum_tillegg, sum_fradrag} as positive integers from a list of permanent forskjeller. Used by the XML emitter to populate the derived <sumTilleggINaeringsinntekt> / <sumFradragINaeringsinntekt> elements Skatteetaten flags as missing.

send_inn(regnskap, konfig, client, opts \\ [])

Submits the tax return to Skatteetaten via Altinn 3.

Generates XML documents from the given Aarsregnskap and SkattemeldingKonfig, then submits via the Altinn 3 skattemelding app.

To inspect the generated XML without submitting, call Wenche.SkattemeldingXml.generer_skattemelding_xml/3, generer_naeringsspesifikasjon_xml/2, and generer_request_xml/3 directly.

Options

  • :skd_clientSkdSkattemeldingClient used to fetch the real partsnummer and dokumentreferanse from SKD. Strongly recommended; without it the request envelope falls back to using the org number as partsnummer and emits no <dokumentreferanseTilGjeldendeDokument>, which causes SKD to reject the submission with innkommendeForespoerselManglerSporTilUtfoerende.
  • :dokumentidentifikator — reference to draft (from hent_utkast); used only when :skd_client is not supplied.
  • :opprettet_av — text emitted in <opprettetAv> to identify the originating end-user system (default "Wenche").
  • :innsendingstype, :innsendingsformaal — envelope overrides; see SkattemeldingXml.generer_request_xml/3.

Returns {:ok, inbox_url} or {:error, reason}.

valider(regnskap, konfig, skd_client, opts \\ [])

Validates the tax return against Skatteetaten's validation API.

Generates XML documents and sends them to the validation endpoint.

Returns {:ok, validation_result} or {:error, reason}.