Packages

Elixir library for Norwegian small business filings — Maskinporten auth, Altinn 3 API client, BRG XML/iXBRL generation, tax calculation (RF-1028/RF-1167), and shareholder register (RF-1086) XML generation. Ported from the Python CLI tool Wenche (https://github.com/olefredrik/Wenche).

Current section

5 Versions

Jump to

Compare versions

30 files changed
+5722 additions
-682 deletions
  @@ -5,6 +5,100 @@ All notable changes to this project will be documented in this file.
5 5 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6 6 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 7
8 + ## [0.2.0] - unreleased
9 +
10 + ### Added
11 +
12 + - **Skattemelding XML submission to Skatteetaten.** New `Wenche.SkattemeldingXml`
13 + generates `skattemeldingUpersonlig` (v5), `naeringsspesifikasjon` (v6), and the
14 + `skattemeldingOgNaeringsspesifikasjonRequest` (v2) envelope against the official
15 + Skatteetaten XSDs (vendored in `priv/xsd/`). New `Wenche.SkdSkattemeldingClient`
16 + talks directly to the SKD REST API (pre-filled draft fetch, validation), and
17 + `Wenche.Skattemelding.valider/2` and `send_inn/2` orchestrate the full Altinn 3
18 + submission flow including real `partsnummer` fetch and
19 + `dokumentreferanseTilGjeldendeDokument` chaining.
20 + - **MVA-melding (VAT return) submission.** New `Wenche.MvaMelding` and
21 + `Wenche.MvaMeldingXml` for bi-monthly VAT returns via Altinn 3. The MVA scope
22 + is opt-in via `Wenche.Systembruker.rights([:mva_melding])`. Marked experimental.
23 + - `Wenche.Skattemelding.beregn/2` for structured tax-return data and
24 + `parse_etter_beregning/1` for parsing SKD's beregningsrespons.
25 + - `Wenche.Skattemelding.beregn/2` honors `:permanent_forskjeller` on
26 + `SkattemeldingKonfig`, bypassing the global `eierandel_datterselskap` heuristic
27 + when an explicit list is supplied.
28 + - `:permanent_forskjeller` accepts `Decimal` `:beloep` for round-once cumulative
29 + semantics; integer is still accepted for backwards compatibility.
30 + - `:sum_override` field on all balance-sheet structs (`Anleggsmidler`,
31 + `Omloepmidler`, `Eiendeler`, `Egenkapital`, `LangsiktigGjeld`, `KortsiktigGjeld`,
32 + `EgenkapitalOgGjeld`) — lets callers that round once from decimal source data
33 + pin the grand total without mutating child line values.
34 + - Configurable systembruker scopes via `:features` option; skattemelding and
35 + mva_melding scopes are opt-in (revisor/regnskapsfører authorization required).
36 + - `Wenche.Systembruker.slett_system/3` for deleting a registered system.
37 + - Configurable `systemNavn` on `BrgXml.generer_hovedskjema`.
38 + - `:opprettet_av` option on skattemelding XML generators.
39 + - `:req_options` support on all HTTP client modules for custom `Req` config.
40 + - Aksjespesifikasjon forwarding through `send_inn/2` and `valider/2`, including
41 + `<spesifikasjonAvForholdRelevanteForBeskatning>` and
42 + `<forskjellMellomRegnskapsmessigOgSkattemessigVerdi>` emission.
43 + - Optional `<kontaktperson>` on `<virksomhet>`.
44 + - `Wenche.Maskinporten.get_skd_skattemelding_token/2` for direct SKD validation
45 + without Altinn exchange.
46 +
47 + ### Changed
48 +
49 + - `Wenche.AltinnClient` — the previously-labeled "Legacy API compatibility"
50 + block (`create_instance`, `update_data_element`, `complete_instance`,
51 + `get_status`) is now documented as the **token-based convenience API**.
52 + Both APIs are first-class: the struct-based functions
53 + (`opprett_instans`, …) drive Wenche's own `send_inn` flows; the token-based
54 + functions are the preferred surface for application callers that want to
55 + drive the Altinn 3 instance lifecycle themselves without constructing a
56 + client struct.
57 + - **3 % addback in `skattepliktigDelAvUtbytterOgUtdelinger` now floors** instead
58 + of `:half_up` rounding, per skatteloven § 2-38 (6) and the SKD veiledning
59 + convention used by reference implementations (Fiken).
60 + - Skattemelding XML rewritten against Skatteetaten XSDs (was a best-effort
61 + emission in 0.1.x).
62 + - BRG XML `underskjema` is now strict-XSD-valid; validation tests added.
63 + - `forekomst <id>` set to the kodeliste kode (was a generated index).
64 + - `aksjeklasse` is lowercased to match SKD's case-sensitive kodeliste.
65 + - Unknown `:aksjespesifikasjon :type` values now raise instead of being silently
66 + dropped.
67 + - Skattemelding Maskinporten scope now also includes Altinn instance scopes.
68 + - Reduced cyclomatic complexity and nesting depth across three modules; Credo
69 + strict cleanup.
70 +
71 + ### Fixed
72 +
73 + - BRG XML `orid` values rejected by Brønnøysundregistrene validation.
74 + - `406` from SKD `valider` by accepting XML responses; added
75 + `charset=UTF-8` to `valider` content-type.
76 + - Altinn 3 app slug for skattemelding submission.
77 + - Wrong MVA-melding resource ID in system user rights.
78 + - `EgenkapitalOgGjeld.sum/1` is now honored by `sumEgenkapitalGjeld` in BRG XML
79 + (was inlining child sums and ignoring `:sum_override`).
80 + - `AltinnClient.legg_til_data_element/6` now passes `client.req_options` to
81 + `Req.post` (was the only client function not honoring it, which blocked
82 + end-to-end stubbing of MVA-melding submission).
83 +
84 + ### Removed
85 +
86 + - **`Wenche.Skattemelding.generer/2`** — the human-readable text-summary
87 + renderer (and its ~250 lines of private formatting helpers). Application
88 + consumers should use `beregn/2`, which returns the same data as a
89 + structured map suitable for any rendering target. The original Python
90 + CLI tool emitted a fixed text report; in the Elixir library this concern
91 + belongs to the caller.
92 + - **`:dry_run` option on `Aarsregnskap.send_inn/3`, `Skattemelding.send_inn/2`,
93 + and `MvaMelding.send_inn/3`.** Previously, `dry_run: true` wrote XML
94 + documents to the host's current working directory via `File.write!` with
95 + synthesized filenames — a CLI ergonomic that web/embedded callers cannot
96 + use safely. To inspect XML without submitting, call the underlying
97 + generators directly: `Wenche.BrgXml.generer_hovedskjema/2` +
98 + `generer_underskjema/1`, `Wenche.SkattemeldingXml.generer_skattemelding_xml/3`
99 + + `generer_naeringsspesifikasjon_xml/2` + `generer_request_xml/3`, or
100 + `Wenche.MvaMeldingXml.generer_konvolutt_xml/1` + `generer_melding_xml/1`.
101 +
8 102 ## [0.1.1] - 2026-03-19
9 103
10 104 ### Fixed
  @@ -18,9 +18,15 @@ Ported from the Python CLI tool [Wenche](https://github.com/olefredrik/Wenche).
18 18 | `Wenche.Aarsregnskap` | Annual accounts submission flow (config, validation, submission) | `wenche/aarsregnskap.py` |
19 19 | `Wenche.BrgXml` | BRG annual statement XML (hovedskjema/underskjema) | `wenche/brg_xml.py` |
20 20 | `Wenche.Ixbrl` | Inline XBRL (iXBRL) HTML document generation | `wenche/xbrl.py` |
21 - | `Wenche.Skattemelding` | Tax calculation with fritaksmetoden (RF-1028/RF-1167) | `wenche/skattemelding.py` |
21 + | `Wenche.Noter` | Notes (noter) for small enterprises — structured XML + iXBRL text | `wenche/noter.py` |
22 + | `Wenche.Skattemelding` | Tax calculation, structured `beregn/2`, and Altinn 3 submission orchestration for skattemelding (RF-1028/RF-1167) | `wenche/skattemelding.py` |
23 + | `Wenche.SkattemeldingXml` | Skattemelding XML (`skattemeldingUpersonlig` v5, `naeringsspesifikasjon` v6, request envelope v2) against Skatteetaten XSDs | — |
24 + | `Wenche.SkdSkattemeldingClient` | Skatteetaten REST API client for skattemelding (pre-filled draft, valider) | — |
25 + | `Wenche.MvaMelding` | VAT return (MVA-melding) submission via Altinn 3. **Experimental.** | — |
26 + | `Wenche.MvaMeldingXml` | MVA-melding XML generation (`mvaMeldingInnsending` + `mvaMeldingDto`) | — |
22 27 | `Wenche.Aksjonaerregister` | RF-1086 shareholder register XML generation | `wenche/aksjonaerregister.py` |
23 - | `Wenche.Models` | Data structures (Selskap, Aarsregnskap, Resultatregnskap, Balanse, etc.) | `wenche/models.py` |
28 + | `Wenche.SkdClient` | Skatteetaten REST API client for RF-1086 (1086H / 1086U / bekreft) | — |
29 + | `Wenche.Models` | Data structures (Selskap, Aarsregnskap, Resultatregnskap, Balanse, SkattemeldingKonfig, etc.) | `wenche/models.py` |
24 30
25 31 ## Installation
26 32
  @@ -29,7 +35,7 @@ Add `wenche` to your list of dependencies in `mix.exs`:
29 35 ```elixir
30 36 def deps do
31 37 [
32 - {:wenche, "~> 0.1.1"}
38 + {:wenche, "~> 0.2.0"}
33 39 ]
34 40 end
35 41 ```
  @@ -145,6 +151,10 @@ client = Wenche.AltinnClient.new(altinn_token, env: "prod")
145 151
146 152 ### Tax Calculation
147 153
154 + `Wenche.Skattemelding.beregn/2` returns the computed tax return as a structured
155 + map (RF-1167 næringsoppgave, RF-1028 skattemelding, balance overview, equity
156 + note, sammenligning, warnings). Render it however you like.
157 +
148 158 ```elixir
149 159 alias Wenche.Models.SkattemeldingKonfig
150 160
  @@ -154,8 +164,17 @@ konfig = %SkattemeldingKonfig{
154 164 underskudd_til_fremfoering: 0
155 165 }
156 166
157 - rapport = Wenche.Skattemelding.generer(regnskap, konfig)
158 - IO.puts(rapport)
167 + beregning = Wenche.Skattemelding.beregn(regnskap, konfig)
168 + # %{
169 + # selskap: %{navn: ..., org_nummer: ...},
170 + # regnskapsaar: 2025,
171 + # rf_1167: %{driftsinntekter: %{...}, driftskostnader: %{...}, ...},
172 + # rf_1028: %{utbytte: ..., beregnet_skatt: ..., ...},
173 + # balanse: %{i_balanse: true, differanse: 0, ...},
174 + # sammenligning: %{...} | nil,
175 + # egenkapitalnote: %{...} | nil,
176 + # advarsler: [...]
177 + # }
159 178 ```
160 179
161 180 ### Shareholder Register (RF-1086)
  @@ -186,22 +205,34 @@ xml = Wenche.Aksjonaerregister.generer_xml(oppgave)
186 205
187 206 ### System User Setup (One-time)
188 207
208 + By default, the system user requests rights for årsregnskap and aksjonærregisteroppgaven.
209 + The skattemelding scope is **not included by default** because systemic submission requires
210 + being a registered revisor or regnskapsfører. Enable it explicitly via the `:features` option
211 + if you have the appropriate authorization.
212 +
189 213 ```elixir
190 214 # Get admin token
191 215 {:ok, admin_token} = Wenche.Maskinporten.get_admin_token(config)
192 216
193 - # Register system (once per vendor)
194 - {:ok, _} = Wenche.Systembruker.registrer_system(admin_token, vendor_orgnr, client_id)
217 + # Register system with default rights (årsregnskap + aksjonærregister)
218 + {:ok, _} = Wenche.Systembruker.registrer_system(admin_token, vendor_orgnr, client_id,
219 + name: "my_system", description: %{"nb" => "Mitt system", "nn" => "Mitt system", "en" => "My system"})
220 +
221 + # Or include skattemelding scope (requires revisor/regnskapsfører authorization)
222 + {:ok, _} = Wenche.Systembruker.registrer_system(admin_token, vendor_orgnr, client_id,
223 + name: "my_system", description: %{"nb" => "...", "nn" => "...", "en" => "..."},
224 + features: [:skattemelding])
195 225
196 226 # Create system user request for an organization
197 - {:ok, request} = Wenche.Systembruker.opprett_forespoersel(admin_token, vendor_orgnr, org_nummer)
198 - # User must approve at request["confirmUrl"]
227 + {:ok, request} = Wenche.Systembruker.opprett_forespoersel(admin_token, vendor_orgnr, org_nummer,
228 + name: "my_system")
199 229
200 230 # Check approval status
201 231 {:ok, status} = Wenche.Systembruker.hent_forespoersel_status(admin_token, request["id"])
202 232
203 233 # List all approved system users
204 - {:ok, users} = Wenche.Systembruker.hent_systembrukere(admin_token, vendor_orgnr)
234 + {:ok, users} = Wenche.Systembruker.hent_systembrukere(admin_token, vendor_orgnr,
235 + name: "my_system")
205 236 ```
206 237
207 238 ## License
  @@ -2,7 +2,7 @@
2 2 [{<<"GitHub">>,<<"https://github.com/jarls-side-projects/elixir-wenche">>},
3 3 {<<"Original (Python)">>,<<"https://github.com/olefredrik/Wenche">>}]}.
4 4 {<<"name">>,<<"wenche">>}.
5 - {<<"version">>,<<"0.1.1">>}.
5 + {<<"version">>,<<"0.3.0">>}.
6 6 {<<"description">>,
7 7 <<69,108,105,120,105,114,32,108,105,98,114,97,114,121,32,102,111,114,32,78,
8 8 111,114,119,101,103,105,97,110,32,115,109,97,108,108,32,98,117,115,105,110,
  @@ -22,7 +22,12 @@
22 22 {<<"app">>,<<"wenche">>}.
23 23 {<<"licenses">>,[<<"MIT">>]}.
24 24 {<<"requirements">>,
25 - [[{<<"name">>,<<"joken">>},
25 + [[{<<"name">>,<<"jason">>},
26 + {<<"app">>,<<"jason">>},
27 + {<<"optional">>,false},
28 + {<<"requirement">>,<<"~> 1.4">>},
29 + {<<"repository">>,<<"hexpm">>}],
30 + [{<<"name">>,<<"joken">>},
26 31 {<<"app">>,<<"joken">>},
27 32 {<<"optional">>,false},
28 33 {<<"requirement">>,<<"~> 2.6">>},
  @@ -53,12 +58,28 @@
53 58 {<<"requirement">>,<<"~> 2.11">>},
54 59 {<<"repository">>,<<"hexpm">>}]]}.
55 60 {<<"files">>,
56 - [<<"lib">>,<<"lib/wenche">>,<<"lib/wenche/maskinporten.ex">>,
57 - <<"lib/wenche/aksjonaerregister.ex">>,<<"lib/wenche/skattemelding.ex">>,
58 - <<"lib/wenche/ixbrl.ex">>,<<"lib/wenche/systembruker.ex">>,
59 - <<"lib/wenche/aarsregnskap.ex">>,<<"lib/wenche/skd_client.ex">>,
60 - <<"lib/wenche/noter.ex">>,<<"lib/wenche/models.ex">>,
61 - <<"lib/wenche/altinn_client.ex">>,<<"lib/wenche/brg_xml.ex">>,
62 - <<"lib/wenche.ex">>,<<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,
63 - <<"LICENSE">>,<<"CHANGELOG.md">>]}.
61 + [<<"lib">>,<<"lib/wenche">>,<<"lib/wenche/systembruker.ex">>,
62 + <<"lib/wenche/aarsregnskap.ex">>,<<"lib/wenche/altinn_client.ex">>,
63 + <<"lib/wenche/skd_client.ex">>,<<"lib/wenche/aksjonaerregister.ex">>,
64 + <<"lib/wenche/models.ex">>,<<"lib/wenche/noter.ex">>,
65 + <<"lib/wenche/skd_skattemelding_client.ex">>,
66 + <<"lib/wenche/mva_melding_xml.ex">>,<<"lib/wenche/skattemelding_xml.ex">>,
67 + <<"lib/wenche/maskinporten.ex">>,<<"lib/wenche/skattemelding.ex">>,
68 + <<"lib/wenche/ixbrl.ex">>,<<"lib/wenche/brg_xml.ex">>,
69 + <<"lib/wenche/mva_melding.ex">>,<<"lib/wenche.ex">>,<<"priv">>,
70 + <<"priv/xsd">>,<<"priv/xsd/brreg">>,<<"priv/xsd/brreg/RR-0002">>,
71 + <<"priv/xsd/brreg/RR-0002/RR-0002_1266-51820.xsd">>,
72 + <<"priv/xsd/brreg/RR-0002/RR-0002-U_758-51980.xsd">>,
73 + <<"priv/xsd/skatteetaten">>,
74 + <<"priv/xsd/skatteetaten/skattemeldingognaeringsspesifikasjonrequest_v2.xsd">>,
75 + <<"priv/xsd/skatteetaten/skattemeldingUpersonlig_v5_ekstern.xsd">>,
76 + <<"priv/xsd/skatteetaten/naeringsspesifikasjon_v6_ekstern.xsd">>,
77 + <<"priv/xsd/skatteetaten/NOTICE">>,<<"priv/xsd/skatteetaten/mva">>,
78 + <<"priv/xsd/skatteetaten/mva/no.skatteetaten.fastsetting.avgift.mva.skattemeldingformerverdiavgift.v1.0.xsd">>,
79 + <<"priv/xsd/skatteetaten/mva/no.skatteetaten.fastsetting.avgift.mva.mvameldinginnsending.v1.0.xsd">>,
80 + <<"priv/xsd/skatteetaten/mva/no.skatteetaten.fastsetting.avgift.mva.valideringsresultat.v1.xsd">>,
81 + <<"priv/xsd/skatteetaten/mva/no.skatteetaen.fastsetting.avgift.mva.mvaMeldingInnsendingStatus.v1.xsd">>,
82 + <<"priv/xsd/skatteetaten/mva/no.skatteetaten.fastsetting.avgift.mva.skattemeldingformerverdiavgift.betalingsinformasjon.v1.0.xsd">>,
83 + <<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>,
84 + <<"CHANGELOG.md">>]}.
64 85 {<<"build_tools">>,[<<"mix">>]}.
  @@ -9,21 +9,21 @@ defmodule Wenche.Aarsregnskap do
9 9
10 10 alias Wenche.Models.{
11 11 Aarsregnskap,
12 - Selskap,
13 - Resultatregnskap,
12 + Anleggsmidler,
14 13 Balanse,
15 14 Driftsinntekter,
16 15 Driftskostnader,
17 - Finansposter,
18 - Eiendeler,
19 - Anleggsmidler,
20 - Omloepmidler,
21 - EgenkapitalOgGjeld,
22 16 Egenkapital,
23 - LangsiktigGjeld,
17 + EgenkapitalOgGjeld,
18 + Eiendeler,
19 + Finansposter,
24 20 KortsiktigGjeld,
21 + LaanTilNaerstaaende,
22 + LangsiktigGjeld,
25 23 Noter,
26 - LaanTilNaerstaaende
24 + Omloepmidler,
25 + Resultatregnskap,
26 + Selskap
27 27 }
28 28
29 29 alias Wenche.{AltinnClient, BrgXml}
  @@ -49,15 +49,15 @@ defmodule Wenche.Aarsregnskap do
49 49 errors = []
50 50
51 51 errors =
52 - if not Balanse.er_i_balanse?(regnskap.balanse) do
52 + if Balanse.er_i_balanse?(regnskap.balanse) do
53 + errors
54 + else
53 55 diff = Balanse.differanse(regnskap.balanse)
54 56
55 57 [
56 58 "Balansen går ikke opp: eiendeler og egenkapital+gjeld avviker med #{diff} NOK."
57 59 | errors
58 60 ]
59 - else
60 - errors
61 61 end
62 62
63 63 org = String.replace(regnskap.selskap.org_nummer, " ", "")
  @@ -72,7 +72,8 @@ defmodule Wenche.Aarsregnskap do
72 72 noter = regnskap.noter
73 73
74 74 errors =
75 - if noter.antall_ansatte == 0 and regnskap.resultatregnskap.driftskostnader.loennskostnader > 0 do
75 + if noter.antall_ansatte == 0 and
76 + regnskap.resultatregnskap.driftskostnader.loennskostnader > 0 do
76 77 ["Advarsel: Lønnskostnader > 0 men antall ansatte er 0 i noter." | errors]
77 78 else
78 79 errors
  @@ -81,7 +82,10 @@ defmodule Wenche.Aarsregnskap do
81 82 errors =
82 83 if regnskap.balanse.egenkapital_og_gjeld.langsiktig_gjeld.laan_fra_aksjonaer > 0 and
83 84 noter.laan_til_naerstaaende == [] do
84 - ["Advarsel: Lån fra aksjonær i balansen men ingen lån til nærstående i noter (§7-45)." | errors]
85 + [
86 + "Advarsel: Lån fra aksjonær i balansen men ingen lån til nærstående i noter (§7-45)."
87 + | errors
88 + ]
85 89 else
86 90 errors
87 91 end
  @@ -92,56 +96,49 @@ defmodule Wenche.Aarsregnskap do
92 96 @doc """
93 97 Submits the annual accounts to Brønnøysundregistrene via Altinn.
94 98
95 - ## Options
96 -
97 - - `:dry_run` — if true, writes XML files locally without sending to Altinn (default: false)
99 + To inspect the generated XML without submitting, call
100 + `Wenche.BrgXml.generer_hovedskjema/2` and `Wenche.BrgXml.generer_underskjema/1`
101 + directly.
98 102
99 103 Returns `{:ok, inbox_url}` or `{:error, reason}`.
100 104 """
101 105 def send_inn(%Aarsregnskap{} = regnskap, %AltinnClient{} = client, opts \\ []) do
102 - dry_run = Keyword.get(opts, :dry_run, false)
106 + case valider(regnskap) do
107 + [] -> do_send_inn(regnskap, client, opts)
108 + errors -> {:error, {:validation_failed, errors}}
109 + end
110 + end
103 111
104 - errors = valider(regnskap)
112 + defp do_send_inn(regnskap, client, opts) do
113 + brg_opts = Keyword.take(opts, [:system_navn])
114 + hovedskjema = BrgXml.generer_hovedskjema(regnskap, brg_opts)
115 + underskjema = BrgXml.generer_underskjema(regnskap)
116 + org = regnskap.selskap.org_nummer
105 117
106 - if errors != [] do
107 - {:error, {:validation_failed, errors}}
108 - else
109 - hovedskjema = BrgXml.generer_hovedskjema(regnskap)
110 - underskjema = BrgXml.generer_underskjema(regnskap)
111 - org = regnskap.selskap.org_nummer
112 - aar = regnskap.regnskapsaar
118 + submit_to_altinn(client, org, hovedskjema, underskjema)
119 + end
113 120
114 - if dry_run do
115 - hoved_fil = "aarsregnskap_#{aar}_#{org}_hovedskjema.xml"
116 - under_fil = "aarsregnskap_#{aar}_#{org}_underskjema.xml"
117 - File.write!(hoved_fil, hovedskjema)
118 - File.write!(under_fil, underskjema)
119 -
120 - {:ok, {:dry_run, hoved_fil, under_fil}}
121 - else
122 - with {:ok, instans} <- AltinnClient.opprett_instans(client, "aarsregnskap", org),
123 - {:ok, _} <-
124 - AltinnClient.oppdater_data_element(
125 - client,
126 - "aarsregnskap",
127 - instans,
128 - "Hovedskjema",
129 - hovedskjema,
130 - "application/xml"
131 - ),
132 - {:ok, _} <-
133 - AltinnClient.oppdater_data_element(
134 - client,
135 - "aarsregnskap",
136 - instans,
137 - "Underskjema",
138 - underskjema,
139 - "application/xml"
140 - ),
141 - {:ok, inbox_url} <- AltinnClient.fullfoor_instans(client, "aarsregnskap", instans) do
142 - {:ok, inbox_url}
143 - end
144 - end
121 + defp submit_to_altinn(client, org, hovedskjema, underskjema) do
122 + with {:ok, instans} <- AltinnClient.opprett_instans(client, "aarsregnskap", org),
123 + {:ok, _} <-
124 + AltinnClient.oppdater_data_element(
125 + client,
126 + "aarsregnskap",
127 + instans,
128 + "Hovedskjema",
129 + hovedskjema,
130 + "application/xml"
131 + ),
132 + {:ok, _} <-
133 + AltinnClient.oppdater_data_element(
134 + client,
135 + "aarsregnskap",
136 + instans,
137 + "Underskjema",
138 + underskjema,
139 + "application/xml"
140 + ) do
141 + AltinnClient.fullfoor_instans(client, "aarsregnskap", instans)
145 142 end
146 143 end
147 144
  @@ -199,80 +196,109 @@ defmodule Wenche.Aarsregnskap do
199 196 end
200 197
201 198 defp les_resultat(r) do
202 - di = r["driftsinntekter"] || %{}
203 - dk = r["driftskostnader"] || %{}
204 - fp = r["finansposter"] || %{}
205 -
206 199 %Resultatregnskap{
207 - driftsinntekter: %Driftsinntekter{
208 - salgsinntekter: di["salgsinntekter"] || 0,
209 - andre_driftsinntekter: di["andre_driftsinntekter"] || 0
210 - },
211 - driftskostnader: %Driftskostnader{
212 - loennskostnader: dk["loennskostnader"] || 0,
213 - avskrivninger: dk["avskrivninger"] || 0,
214 - andre_driftskostnader: dk["andre_driftskostnader"] || 0
215 - },
216 - finansposter: %Finansposter{
217 - utbytte_fra_datterselskap: fp["utbytte_fra_datterselskap"] || 0,
218 - andre_finansinntekter: fp["andre_finansinntekter"] || 0,
219 - rentekostnader: fp["rentekostnader"] || 0,
220 - andre_finanskostnader: fp["andre_finanskostnader"] || 0
221 - }
200 + driftsinntekter: parse_driftsinntekter(r["driftsinntekter"] || %{}),
201 + driftskostnader: parse_driftskostnader(r["driftskostnader"] || %{}),
202 + finansposter: parse_finansposter(r["finansposter"] || %{})
203 + }
204 + end
205 +
206 + defp parse_driftsinntekter(di) do
207 + %Driftsinntekter{
208 + salgsinntekter: di["salgsinntekter"] || 0,
209 + andre_driftsinntekter: di["andre_driftsinntekter"] || 0
210 + }
211 + end
212 +
213 + defp parse_driftskostnader(dk) do
214 + %Driftskostnader{
215 + loennskostnader: dk["loennskostnader"] || 0,
216 + avskrivninger: dk["avskrivninger"] || 0,
217 + andre_driftskostnader: dk["andre_driftskostnader"] || 0
218 + }
219 + end
220 +
221 + defp parse_finansposter(fp) do
222 + %Finansposter{
223 + utbytte_fra_datterselskap: fp["utbytte_fra_datterselskap"] || 0,
224 + andre_finansinntekter: fp["andre_finansinntekter"] || 0,
225 + rentekostnader: fp["rentekostnader"] || 0,
226 + andre_finanskostnader: fp["andre_finanskostnader"] || 0
222 227 }
223 228 end
224 229
225 230 defp les_balanse(b) do
226 - ei = b["eiendeler"] || %{}
227 - am = ei["anleggsmidler"] || %{}
228 - om = ei["omloepmidler"] || %{}
229 - eog = b["egenkapital_og_gjeld"] || %{}
230 - ek = eog["egenkapital"] || %{}
231 - lg = eog["langsiktig_gjeld"] || %{}
232 - kg = eog["kortsiktig_gjeld"] || %{}
233 -
234 231 %Balanse{
235 - eiendeler: %Eiendeler{
236 - anleggsmidler: %Anleggsmidler{
237 - aksjer_i_datterselskap: am["aksjer_i_datterselskap"] || 0,
238 - andre_aksjer: am["andre_aksjer"] || 0,
239 - langsiktige_fordringer: am["langsiktige_fordringer"] || 0
240 - },
241 - omloepmidler: %Omloepmidler{
242 - kortsiktige_fordringer: om["kortsiktige_fordringer"] || 0,
243 - bankinnskudd: om["bankinnskudd"] || 0
244 - }
245 - },
246 - egenkapital_og_gjeld: %EgenkapitalOgGjeld{
247 - egenkapital: %Egenkapital{
248 - aksjekapital: ek["aksjekapital"] || 0,
249 - overkursfond: ek["overkursfond"] || 0,
250 - annen_egenkapital: ek["annen_egenkapital"] || 0
251 - },
252 - langsiktig_gjeld: %LangsiktigGjeld{
253 - laan_fra_aksjonaer: lg["laan_fra_aksjonaer"] || 0,
254 - andre_langsiktige_laan: lg["andre_langsiktige_laan"] || 0
255 - },
256 - kortsiktig_gjeld: %KortsiktigGjeld{
257 - leverandoergjeld: kg["leverandoergjeld"] || 0,
258 - skyldige_offentlige_avgifter: kg["skyldige_offentlige_avgifter"] || 0,
259 - annen_kortsiktig_gjeld: kg["annen_kortsiktig_gjeld"] || 0
260 - }
261 - }
232 + eiendeler: parse_eiendeler(b["eiendeler"] || %{}),
233 + egenkapital_og_gjeld: parse_egenkapital_og_gjeld(b["egenkapital_og_gjeld"] || %{})
234 + }
235 + end
236 +
237 + defp parse_eiendeler(ei) do
238 + %Eiendeler{
239 + anleggsmidler: parse_anleggsmidler(ei["anleggsmidler"] || %{}),
240 + omloepmidler: parse_omloepmidler(ei["omloepmidler"] || %{})
241 + }
242 + end
243 +
244 + defp parse_anleggsmidler(am) do
245 + %Anleggsmidler{
246 + aksjer_i_datterselskap: am["aksjer_i_datterselskap"] || 0,
247 + andre_aksjer: am["andre_aksjer"] || 0,
248 + langsiktige_fordringer: am["langsiktige_fordringer"] || 0
249 + }
250 + end
251 +
252 + defp parse_omloepmidler(om) do
253 + %Omloepmidler{
254 + kortsiktige_fordringer: om["kortsiktige_fordringer"] || 0,
255 + bankinnskudd: om["bankinnskudd"] || 0
256 + }
257 + end
258 +
259 + defp parse_egenkapital_og_gjeld(eog) do
260 + %EgenkapitalOgGjeld{
261 + egenkapital: parse_egenkapital(eog["egenkapital"] || %{}),
262 + langsiktig_gjeld: parse_langsiktig_gjeld(eog["langsiktig_gjeld"] || %{}),
263 + kortsiktig_gjeld: parse_kortsiktig_gjeld(eog["kortsiktig_gjeld"] || %{})
264 + }
265 + end
266 +
267 + defp parse_egenkapital(ek) do
268 + %Egenkapital{
269 + aksjekapital: ek["aksjekapital"] || 0,
270 + overkursfond: ek["overkursfond"] || 0,
271 + annen_egenkapital: ek["annen_egenkapital"] || 0
272 + }
273 + end
274 +
275 + defp parse_langsiktig_gjeld(lg) do
276 + %LangsiktigGjeld{
277 + laan_fra_aksjonaer: lg["laan_fra_aksjonaer"] || 0,
278 + andre_langsiktige_laan: lg["andre_langsiktige_laan"] || 0
279 + }
280 + end
281 +
282 + defp parse_kortsiktig_gjeld(kg) do
283 + %KortsiktigGjeld{
284 + leverandoergjeld: kg["leverandoergjeld"] || 0,
285 + skyldige_offentlige_avgifter: kg["skyldige_offentlige_avgifter"] || 0,
286 + annen_kortsiktig_gjeld: kg["annen_kortsiktig_gjeld"] || 0
262 287 }
263 288 end
264 289
265 290 defp les_noter(n) do
266 - laan = (n["laan_til_naerstaaende"] || [])
267 - |> Enum.map(fn l ->
268 - %LaanTilNaerstaaende{
269 - navn: l["navn"],
270 - rolle: l["rolle"],
271 - beloep: l["beloep"] || 0,
272 - rentesats: l["rentesats"],
273 - avdragsplan: l["avdragsplan"]
274 - }
275 - end)
291 + laan =
292 + (n["laan_til_naerstaaende"] || [])
293 + |> Enum.map(fn l ->
294 + %LaanTilNaerstaaende{
295 + navn: l["navn"],
296 + rolle: l["rolle"],
297 + beloep: l["beloep"] || 0,
298 + rentesats: l["rentesats"],
299 + avdragsplan: l["avdragsplan"]
300 + }
301 + end)
276 302
277 303 %Noter{
278 304 antall_ansatte: n["antall_ansatte"] || 0,
  @@ -13,7 +13,7 @@ defmodule Wenche.Aksjonaerregister do
13 13 3. POST bekreftconfirm all sub-forms submitted
14 14 """
15 15
16 - alias Wenche.Models.{Aksjonaerregisteroppgave, Aksjonaer}
16 + alias Wenche.Models.{Aksjonaer, Aksjonaerregisteroppgave}
17 17
18 18 @doc """
19 19 Generates RF-1086 Hovedskjema XML for SKD's API.
Loading more files…