Wenche.SkattemeldingXml (wenche v0.3.0)

Copy Markdown View Source

XML generation for skattemelding (corporate tax return) submission to Skatteetaten.

Generates three XML documents:

  1. skattemeldingUpersonlig (v5) — minimal: partsnummer, inntektsaar, and optionally inntektOgUnderskudd/underskuddTilFremfoering/fremfoertUnderskuddFraTidligereAar. Other fields (income, formue, deductions) are derived by Skatteetaten from the næringsspesifikasjon. Per skattemeldingUpersonlig_v5_ekstern.xsd.

  2. naeringsspesifikasjon (v6) — resultatregnskap, balanseregnskap, virksomhet, skalBekreftesAvRevisor. Sum/derived fields (erAvledet="true") are computed by Skatteetaten and not emitted. Per naeringsspesifikasjon_v6_ekstern.xsd.

  3. skattemeldingOgNaeringsspesifikasjonRequest (v2) — envelope wrapping both inner documents base64-encoded. Per skattemeldingognaeringsspesifikasjonrequest_v2.xsd.

Ported from wenche/skattemelding_xml.py, wenche/naeringsspesifikasjon_xml.py, and wenche/skattemelding_konvolutt.py in the Python Wenche project.

Partsnummer

partsnummer (and partsreferanse in næringsspesifikasjon) is Skatteetaten's internal integer ID for the company. It must be fetched from the pre-filled draft API (GET /api/skattemelding/v2/{år}/{orgnr}) before generating the XML for actual submission.

When called without :partsnummer in opts, the generators fall back to aarsregnskap.selskap.org_nummer as a placeholder. This passes XSD validation (org_nummer fits xsd:long) but Skatteetaten will reject the actual submission unless replaced with the real partsnummer.

Summary

Functions

Calculates {samletVerdiFoerEventuellVerdsettingsrabatt, samletGjeld} for <formueOgGjeld>.

Returns net value behind the shares, floored at zero, for display/control.

Generates the naeringsspesifikasjon XML document (v6).

Generates a <forskjellMellomRegnskapsmessigOgSkattemessigVerdi> block from a list of permanent-forskjell maps. Returns "" for an empty list.

Generates the request envelope wrapping skattemelding + naeringsspesifikasjon.

Generates the skattemeldingUpersonlig XML document (v5).

Generates a <spesifikasjonAvForholdRelevanteForBeskatning> block from a list of holding maps. Returns an empty string for an empty list.

Extracts the partsnummer from a skattemeldingUpersonlig XML document.

Functions

beregn_formue_inputs(regnskap, konfig)

Calculates {samletVerdiFoerEventuellVerdsettingsrabatt, samletGjeld} for <formueOgGjeld>.

samlet_verdi_bak_aksjene is treated as an explicit net override and takes precedence. Otherwise, formuesverdi_aksjer replaces the book value of share/fund holdings while bank deposits and receivables are included at face value. Returns {nil, nil} when no valuation input is present.

beregn_verdi_bak_aksjene(regnskap, konfig)

Returns net value behind the shares, floored at zero, for display/control.

generer_naeringsspesifikasjon_xml(regnskap, opts \\ [])

@spec generer_naeringsspesifikasjon_xml(
  Wenche.Models.Aarsregnskap.t(),
  keyword()
) :: String.t()

Generates the naeringsspesifikasjon XML document (v6).

Options

  • :partsnummer — Skatteetaten's integer ID. Defaults to aarsregnskap.selskap.org_nummer.
  • :permanent_forskjeller — list of maps emitted as <forskjellMellomRegnskapsmessigOgSkattemessigVerdi><permanentForskjell>…. Required for SKD to apply fritaksmetoden — without these explicit "tilbakeføring av utbytte" / "treprosent" / "gevinst-fradrag" / "tap-tillegg" declarations, SKD taxes the full regnskapsmessig income. See generer_permanent_forskjell_block/1 for the expected shape.
  • :kontaktperson — map with :navn (required), :telefonnummer (optional), :epostadresse (optional). Emitted as <kontaktperson> inside <virksomhet>. SKD's post-acceptance audit appears to read this as the "spor til utførende" (named human to contact about the submission); omitting it has been observed to cause SKD to return innkommendeForespoerselManglerSporTilUtfoerende in the tilbakemelding after a successful Altinn signing.

generer_permanent_forskjell_block(entries)

@spec generer_permanent_forskjell_block([map()]) :: String.t()

Generates a <forskjellMellomRegnskapsmessigOgSkattemessigVerdi> block from a list of permanent-forskjell maps. Returns "" for an empty list.

Each entry must include:

  • :typetekniskNavn from the 2025 permanentForskjellstype kodeliste. Examples relevant to fritaksmetoden: :tilbakefoeringAvInntektsfoertUtbytte (0815, fradrag), :skattepliktigDelAvUtbytterOgUtdelinger (0653, tillegg = 3 %), :regnskapsmessigGevinstVedRealisasjonAvFinansielleInstrumenter (0833, fradrag), :regnskapsmessigTapVedRealisasjonAvFinansielleInstrumenter (0633, tillegg).
  • :beloepDecimal.t or integer NOK (always positive; the kodeliste's kategori determines whether SKD treats it as tillegg or fradrag). Decimal beloep is rounded per line for emission as an integer. Rounding mode is :half_up for most types; the 3 % addback (:skattepliktigDelAvUtbytterOgUtdelinger) floors instead, per skatteloven § 2-38 (6) and the SKD veiledning convention.
  • :beskrivelse — optional free text.

Entries with :beloep <= 0 (after rounding) are dropped — SKD rejects zero-valued permanent forskjeller as invalid.

generer_request_xml(skattemelding_xml, naeringsspesifikasjon_xml, opts \\ [])

Generates the request envelope wrapping skattemelding + naeringsspesifikasjon.

Both inner documents are base64-encoded into <dokument><content> entries.

Options

  • :inntektsaar — required for the envelope element.
  • :tin — TIN/organisasjonsnummer (recommended).
  • :innsendingstype"komplett" (default) or "ikkeKomplett".
  • :innsendingsformaal"egenfastsetting" (default), "klage", or "endringsanmodning".
  • :dokumentreferanse — optional list of {dokumenttype, dokumentidentifikator} pairs to emit as <dokumentreferanseTilGjeldendeDokument> entries.
  • :opprettet_av — text used for <opprettetAv> (default "Wenche"). Override to identify the originating end-user system.

generer_skattemelding_xml(regnskap, konfig, opts \\ [])

Generates the skattemeldingUpersonlig XML document (v5).

Options

  • :partsnummer — Skatteetaten's integer ID for the company. Defaults to aarsregnskap.selskap.org_nummer.
  • :fremfoert_underskudd — loss carryforward from prior years (integer kroner). Defaults to konfig.underskudd_til_fremfoering. Element is emitted only when value is > 0.
  • :aksjespesifikasjon — list of holding maps emitted as <spesifikasjonAvForholdRelevanteForBeskatning>. See generer_spesifikasjon_av_forhold_relevante_for_beskatning/1 for the expected map shape. Required for SKD to apply fritaksmetoden to dividends and gains on aksje/verdipapir holdings — without it, SKD taxes the full income.
  • konfig.formuesverdi_aksjer — summed formuesverdi of share/fund holdings. When present, emits <formueOgGjeld> with XSD-backed overstyring fields so SKD can derive value behind the company's shares.
  • konfig.samlet_verdi_bak_aksjene — explicit net value behind the shares. When present, this override takes precedence over :formuesverdi_aksjer.

generer_spesifikasjon_av_forhold_relevante_for_beskatning(holdings)

Generates a <spesifikasjonAvForholdRelevanteForBeskatning> block from a list of holding maps. Returns an empty string for an empty list.

Each holding map must include :type, which selects the forekomst variant:

  • :aksje_i_aksjonaerregisteret — Norwegian AS in aksjonærregisteret. Expected keys: :selskapets_navn, :selskapets_organisasjonsnummer, :landkode, :er_omfattet_av_fritaksmetoden, :aksjeklasse, :isinnummer, :antall_aksjer, :utbytte, :gevinst_ved_realisasjon_av_aksje, :tap_ved_realisasjon_av_aksje.

  • :aksje_ikke_i_aksjonaerregisteret — foreign shares held via custodian. Adds :kontofoerers_navn, :kontonummer, :finansproduktidentifikator, :finansproduktidentifikatortype.

  • :verdipapirfond — mutual fund. Expected keys: :fondets_navn, :fondets_organisasjonsnummer, :landkode, :er_omfattet_av_fritaksmetoden, :isinnummer, :antall_andeler, :utbytte, :renteinntekt, :gevinst_ved_realisasjon_av_andel_i_aksjedel, :tap_ved_realisasjon_av_andel_i_aksjedel, :gevinst_ved_realisasjon_av_andel_i_rentedel, :tap_ved_realisasjon_av_andel_i_rentedel.

All numeric fields are emitted only when non-nil. id is assigned by index (1-based) in the order received.

hent_partsnummer(xml)

Extracts the partsnummer from a skattemeldingUpersonlig XML document.

Used after fetching the pre-filled draft from GET /api/skattemelding/v2/{år}/{orgnr} to learn Skatteetaten's internal ID for the company.

Returns {:ok, integer} or {:error, :partsnummer_not_found}.