This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-05-03
Channels
- # aleph (62)
- # announcements (44)
- # babashka (2)
- # beginners (72)
- # biff (16)
- # calva (3)
- # clj-commons (4)
- # clj-kondo (2)
- # clojure (217)
- # clojure-brasil (2)
- # clojure-europe (21)
- # clojure-nl (1)
- # clojure-norway (12)
- # clojure-sweden (15)
- # clojure-uk (15)
- # clojuredesign-podcast (14)
- # clojurescript (21)
- # cursive (1)
- # datalevin (1)
- # datascript (4)
- # emacs (13)
- # gratitude (2)
- # helix (7)
- # integrant (5)
- # jobs-discuss (116)
- # lsp (4)
- # overtone (7)
God afton, Skulle vilja leka med min bokföringsdata i Clojure. Är det någon som har kod för att läsa / skriva SIE4 filer?
Though I can't share it as is since it's a hodge podge of various imports of transactions from stripe to produce my own sie4 file..
Basically there is some metadata, a list of transactions, and some data like year results which can be entirely derived from the list of transactions
Nice! Yeah I think it looks kind of fun to go for it myself. I wonder if a grammar and instaparse is a good approach for reading.
The format is pretty regular, every line is a tag and a sequence of possibly escaped strings
(def parser (insta/parser "
SIE = STMT (<NL> STMT)* <NL>
<STMT> = flag | format | sie-type | program | generated-at | organization-name
| program-organization-id | organization-id | address | financial-year
| tax-year | currency | chart-of-accounts-type | account | account-type
| account-sru | dimension | closing-balance | opening-balance | verification
flag = <'#FLAGGA'> <SPACE> INT
format = <'#FORMAT'> <SPACE> 'PC8'
sie-type = <'#SIETYP'> <SPACE> INT
program = <'#PROGRAM'> <SPACE> STR <SPACE> STR
organization-name = <'#FNAMN'> <SPACE> STR
organization-id = <'#ORGNR'> <SPACE> STR
address = <'#ADRESS'> <SPACE> STR <SPACE> STR <SPACE> STR <SPACE> STR
financial-year = <'#RAR'> <SPACE> INT <SPACE> DATE <SPACE> DATE
program-organization-id = <'#FNR'> <SPACE> STR
generated-at = <'#GEN'> <SPACE> DATE
tax-year = <'#TAXAR'> <SPACE> INT
currency = <'#VALUTA'> <SPACE> STR
chart-of-accounts-type = <'#KPTYP'> <SPACE> STR
account = <'#KONTO'> <SPACE> INT <SPACE> STR
account-type = <'#KTYP'> <SPACE> INT <SPACE> ('T'|'S'|'K'|'I')
account-sru = <'#SRU'> <SPACE> INT <SPACE> INT
dimension = <'#DIM'> <SPACE> INT <SPACE> STR
closing-balance = (<'#UB'>|<'#RES'>) <SPACE> INT <SPACE> INT <SPACE> QTY
opening-balance = <'#IB'> <SPACE> INT <SPACE> INT <SPACE> QTY
verification = <'#VER'> <SPACE> STR <SPACE> INT_STR <SPACE> DATE <SPACE> STR <SPACE> DATE
<NL> <'{'>
(<NL> <SPACE>? TRANS)*
<NL> <'}'>
TRANS = <'#TRANS'> <SPACE> INT <SPACE> <STR> <SPACE> QTY
QTY = #'-?\\d+(\\.\\d+)?'
SPACE = #'\\s+'
INT = #'-?\\d+'
<STR> = UNESCAPED_STRING | ESCAPED_STRING
DATE = STR
INT_STR = STR
<UNESCAPED_STRING> = #'[^\\s^\"]+'
ESCAPED_STRING = #'\"[^\"]*\"'
NL = #'\\s*\\r?\\n'"))
(defn- convert [ret]
(reduce
(fn [acc [k & args :as v]]
(case k
(:flag :format :chart-of-accounts-type :sie-type :generated-at
:program-organization-id :tax-year :currency) (apply assoc acc v)
:program (assoc acc k (zipmap [:name :version] args))
:address (assoc acc k (zipmap [:contact :distribution :postal :phone] args))
:organization-id (assoc-in acc [:organization :id] (first args))
:organization-name (assoc-in acc [:organization :name] (first args))
:financial-year (let [[id started-at ended-at] args]
(assoc-in acc [:financial-year id] {:started-at started-at
:ended-at ended-at}))
:account (let [[id label] args]
(assoc-in acc [:account id :label] label))
:account-type (let [[id type] args]
(assoc-in acc [:account id :type] type))
:account-sru (let [[id sru] args]
(assoc-in acc [:account id :sru] sru))
:opening-balance (let [[year-id account-id value] args]
(assoc-in acc [:balance year-id account-id :opening] value))
:closing-balance (let [[year-id account-id value] args]
(assoc-in acc [:balance year-id account-id :closing] value))
:verification (let [[series num ver-date label reg-date & txs] args]
(update acc :verifications (fnil conj [])
{:series series
:number num
:created-at ver-date
:label label
:registered-at reg-date
:transactions (mapv (fn [[_ account quantity]]
[account quantity])
txs)}))
:dimension (apply update acc k assoc args)
(do
(tap> {:acc acc :val v})
(throw (Exception. (str k))))))
{}
(rest (insta/transform
{:INT #(Integer/parseInt ^String %)
:INT_STR #(Integer/parseInt ^String %)
:QTY #(BigDecimal. ^String %)
:DATE parse-date
:ESCAPED_STRING #(str/replace (subs % 1 (dec (count %))) #"\\(\"|\\)" "$1")}
ret))))
(defn parse-sie [sie-str]
(let [ret (insta/parse parser sie-str)]
(if (insta/failure? ret)
(throw (ex-info (pr-str ret) {:failure ret}))
(convert ret))))