packages = ["pandas", "matplotlib"] [[runtimes]] src = "static/pyodide/pyodide.js" name = "pyodide-0.22.1" lang = "python" [[fetch]] from = "static/python/" files = ["saft2dataframe.py", "analyse.py", "request.py"]

Analyse av SAF-T-fil i nettleseren

Denne nettsiden lar deg åpne en SAF-T-fil, og bruke Python og pandas til å gjøre analyser av innholdet, uten at du trenger å ha Python installert på PC-en, alt kjører i nettleseren.

Du kan bruke noen av de forhåndsdefinerte spørringene/analysene, enten direkte eller med egne tilpasninger, eller du kan skrive din egen kode

I variabelen saft ligger det en pandas dataframe som inneholder alle transaksjonene fra SAF-T-fila. Prøv f.eks. saft.info() eller saft.describe() for å få litt informasjon om datasettet

Aller først: Last opp SAF-T-fil



Dersom du ikke har en egen SAF-T-fil, kan du kjøre koden nedenfor for å laste en eksempelfil fra Skatteetaten, slik at du kan teste de andre funksjonene her. NB! Merk at koden nedenfor bare er testet på Skatteetatens eksempelfil.

url = ( "static/testdata/saft.xml" ) saft = saft2dataframe(open_url(url)) main_element = document.getElementsByTagName('main') # nå kan vi hente frem eksemplene main_element[0].style.display = 'block' f'Variabelen "saft" er nå av typen {type(saft)} og er {len(saft)} rader lang'

Omsetningstall for en måned

Bytt ut datoene for å få den aktuelle tidsperioden. Dette er omsetningstallene SSB ber om dersom du er trukket ut til å besvare spørreskjema for varehandelsindeksen.

resultat = saft.loc[ ( # filtering transactions: saft['Transaction.TransactionDate'] >= '2017-01-01') & (saft['Transaction.TransactionDate'] < '2017-02-01') & (saft['Line.AccountID'] >= 3000) & (saft['Line.AccountID'] < 4000)] \ [[ 'Line.DebitAmount.Amount', # selecting the amount-columns 'Line.TaxAmount.Amount', 'Line.CreditAmount.Amount',]].sum() f'''Resultatet: Debit: {resultat['Line.DebitAmount.Amount']} | Skatt: {resultat['Line.TaxAmount.Amount']} | Kredit: {resultat[ 'Line.CreditAmount.Amount']}'''

Resultat

Omsetningstall for en måned - alternativ løsning

Her er den samme koden som i eksempelet over, lagt inn i en funksjon kalt omsetning som kan kalles med parametrene år og måned. Da slipper brukeren å se all koden, hvis de ikke er interessert, men kan samtidig enkelt få tilgang til den ved å se i kildekoden til dokumentet.

En åpenbar fordel med denne tilnærmingen er at funksjonen kan suppleres med kode for å gjøre den mer robust, fange opp feil og gi bedre tilbakemeldinger, for eksempel hvis brukeren ber om omsetning for perioder det ikke finnes data for. (Men det er ikke lagt inn i eksempelet, altså ...)

def omsetning(år: int, måned: int) -> str: fra = f'{år}-{måned}-01' til = f'{år}-{måned + 1}-01' resultat = saft.loc[ ( # filtering transactions: saft['Transaction.TransactionDate'] >= fra) & (saft['Transaction.TransactionDate'] < til) & (saft['Line.AccountID'] >= 3000) & (saft['Line.AccountID'] < 4000)] \ [[ 'Line.DebitAmount.Amount', # selecting the amount-columns 'Line.TaxAmount.Amount', 'Line.CreditAmount.Amount',]].sum() return f'''Resultatet: Debit: {resultat['Line.DebitAmount.Amount']} | Skatt: {resultat['Line.TaxAmount.Amount']} | Kredit: {resultat[ 'Line.CreditAmount.Amount']}''' omsetning(2017, 1)

Resultat

Info om dataene

print(saft.info()) # gir informasjon om alle kolonnene saft.describe() # beregner statistiske nøkkeltall for de numeriske dataene

Resultat

(Se resultatet i terminalvinduet nederst på siden.)

Omsetning pr måned

Måned angis som tallene 1-12. Testdataen fra Skatteetaten har bare tall for perioden januar til april (1-4)

saft.loc[( # filtrerer på relevante konti saft['Line.AccountID'] >= 3000) & (saft['Line.AccountID'] < 4000 )]\ [[ # velger relevante kolonner 'Transaction.TransactionDate', 'Line.DebitAmount.Amount', 'Line.TaxAmount.Amount', 'Line.CreditAmount.Amount' ]]\ .set_index('Transaction.TransactionDate',)\ .groupby([lambda x: x.month])\ .sum()

Resultat

Graf for omsetning pr måned

Måned angis som tallene 1-12. Testdataen fra Skatteetaten har bare tall for perioden januar til april (1-4).

Merk at det kan ta et par sekunder før grafen dukker opp.

import matplotlib.pyplot as plt df = saft.loc[( # filtrerer på relevante konti saft['Line.AccountID'] >= 3000) & (saft['Line.AccountID'] < 4000 )]\ [[ # velger relevante kolonner 'Transaction.TransactionDate', 'Line.DebitAmount.Amount', 'Line.TaxAmount.Amount', 'Line.CreditAmount.Amount' ]]\ .set_index('Transaction.TransactionDate',)\ .groupby([lambda x: x.month])\ .sum() fig, ax = plt.subplots() df.plot(ax=ax) display(fig)

Resultat

Rapportering - til mottakers API

Sender omsetningstall for en spesifikk måned til et dummy-API

async def rapporter(data, baseurl): headers = {"Content-type": "application/json"} new_post = await request(f"{baseurl}/posts", body=data, method="POST", headers=headers) print(f"Har POSTet følgende json: {await new_post.json()}, status ble: {new_post.status}") baseurl = "https://jsonplaceholder.typicode.com" data = saft.loc[ ( # filtering transactions: saft['Transaction.TransactionDate'] >= '2017-01-01') & (saft['Transaction.TransactionDate'] < '2017-02-01') & (saft['Line.AccountID'] >= 3000) & (saft['Line.AccountID'] < 4000)] \ [[ 'Line.DebitAmount.Amount', # selecting the amount-columns 'Line.TaxAmount.Amount', 'Line.CreditAmount.Amount',]].sum().to_json() asyncio.ensure_future(rapporter(data, baseurl))

Resultat

(Se resultatet i terminalvinduet nederst på siden.)

Demo av http-forespørsler

Se main.py for selve koden, nedenfor er kallet som kjører demo-funksjonen

asyncio.ensure_future(http_request_demo())

Resultat

(Se resultatet i terminalvinduet nederst på siden.)