13 // hardcoded account ids we have to look at
16 // wareneingang 19% and 7%
17 const pid_buy_n = string("8e3b7c42e3173ed85f3d4736e82afb4d")
18 const pid_buy_s = string("0cfd2ceb45fff89b9d1b7ce3af66cdf3")
19 const pid_misc = string("e3acc2865dbf931e41cf2b90240de5c2")
20 const pid_rep = string("b1d04ad157cac569f4299d4ddf94ed6f")
21 const pid_room = string("4394ed4ffa7266f8f8731080926a7a61")
22 const pid_cap = string("4196ee026d1bdb785df2c975fca91ae0")
23 // abziehbare vst 19% and 7%
24 const aid_vst_n = string("7c449e13125d6b93043f963628106db2")
25 const aid_vst_s = string("006643c1c0a91f2b40614c75a49c6295")
28 const aid_rec_n = string("f3e905732b729ba096a50dab60559ce7")
29 const aid_rec_s = string("66c1b04bd897766cb2be538094e1db6a")
30 const aid_tip = string("1d20024badc11a99a8e1cf3a9a64a501")
31 const aid_dep = string("9772f4e231f6f5e3100132cc53eb3447")
33 const aid_ust_n = string("e4bd6ff52408be8076f24aeb105893d9")
34 const aid_ust_s = string("38bf40d16529f2a1e611c073c6c1dc9c")
38 pid string // parent id
39 num int // account number
41 buy bool // buy or sales
42 tax bool // tax or non-tax(=goods) account
43 rid []string // required transaction account(s)
48 XMLName xml.Name `xml:"account"`
49 Name string `xml:"name"`
50 AccountId string `xml:"id"`
51 ParentId string `xml:"parent"`
54 XMLName xml.Name `xml:"split"`
56 Value string `xml:"value"`
57 Quantity string `xml:"quantity"`
58 AccountId string `xml:"account"`
60 type Transaction struct {
61 XMLName xml.Name `xml:"transaction"`
63 Date string `xml:"date-posted>date"`
64 Description string `xml:"description"`
65 Spl []Split `xml:"splits>split"`
67 type ParsedData struct {
68 XMLName xml.Name `xml:"gnc-v2"`
69 DataCnt []string `xml:"count-data"`
70 Accnt []Account `xml:"book>account"`
71 Trn []Transaction `xml:"book>transaction"`
80 file, err := os.Open("c13_skr03.gnucash")
82 fmt.Println("Error opening file:", err)
88 xmldata, err := ioutil.ReadAll(file)
90 fmt.Println("Error reading file:", err)
95 err = xml.Unmarshal(xmldata,&data)
97 fmt.Println("Error unmarshaling xml data:", err)
101 // whooha, this is our data!
102 fmt.Println("Parsed accounts:",len(data.Accnt))
103 fmt.Println("Parsed transactions:",len(data.Trn))
105 accnt := make(map[string]amap)
107 for ac := range data.Accnt {
108 aid := data.Accnt[ac].AccountId
109 pid := data.Accnt[ac].ParentId
111 rid := make ([]string,10,10)
113 pid,ac,0,false,false,rid,
120 case pid == pid_buy_n || pid == pid_misc || pid == pid_rep || pid == pid_room || pid == pid_cap:
125 case pid == pid_buy_s:
131 case aid == aid_vst_n:
135 rid=[]string{pid_buy_n,pid_misc,pid_rep,pid_room,pid_cap,}
137 case aid == aid_vst_s:
145 case aid == aid_rec_n || aid == aid_tip || aid == aid_dep:
149 case aid == aid_rec_s:
154 case aid == aid_ust_n:
157 rid=[]string{aid_rec_n,aid_tip,aid_dep,}
159 case aid == aid_ust_s:
167 // check transactions ...
168 for tc := range data.Trn {
169 // ... and all the accounts involved
170 for tsc := range data.Trn[tc].Spl {
171 aid := data.Trn[tc].Spl[tsc].AccountId
172 if check_trn(&data.Trn[tc],accnt,aid) == false {
174 fmt.Println(" ",data.Trn[tc].Date)
175 fmt.Println(" ",data.Trn[tc].Description)
176 fmt.Println(" ",data.Accnt[ac].Name)
184 func check_trn(ta *Transaction,accnt map[string]amap,aid string) bool {
185 //ac := accnt[aid].num
186 if accnt[aid].rid[0]=="NONE" {
189 for ra := range accnt[aid].rid {
190 for ea := range ta.Spl {
191 oaid := ta.Spl[ea].AccountId
193 case accnt[aid].tax && accnt[aid].buy:
195 if accnt[oaid].pid == accnt[aid].rid[ra] {
196 return check_vals(accnt,aid,oaid,ta)
200 if ta.Spl[ea].AccountId == accnt[aid].rid[ra] {
201 return check_vals(accnt,aid,oaid,ta)
204 //fmt.Println(data.Accnt[accnt[oaid].num].Name)
208 // some exceptions - transaction description
209 desclist := []string{
213 "Gesundheitsbelehrung",
214 "Gewerbezentralregister",
215 "Entgeltabrechnung siehe Anlage",
219 for dc := range desclist {
220 if strings.Contains(ta.Description,desclist[dc]){
224 // some exceptions - account name
225 accountlist := []string{
226 "4970 Nebenkosten des",
228 anum := accnt[aid].num
229 for ac := range accountlist {
230 if strings.Contains(data.Accnt[anum].Name,accountlist[ac]){
235 fmt.Println("E: No correpsonding account!")
240 func check_vals(accnt map[string]amap,aid string,oaid string,ta *Transaction) bool {
241 qa, _ := strconv.Atoi(get_val(ta,aid))
242 qb, _ := strconv.Atoi(get_val(ta,oaid))
249 // aid = taxval * oaid / 100
250 val = int((qb*accnt[aid].taxval)/100.0)
253 // oaid = taxval * aid / 100
254 val = int((qa*accnt[aid].taxval)/100.0)
258 if cmp >= val-1 && cmp <= val+1 {
261 fmt.Println("E:",qa,qb,"<- ",accnt[aid].taxval,"->",cmp,val)
266 func get_val(ta *Transaction,aid string) string {
267 for sc := range ta.Spl {
268 if ta.Spl[sc].AccountId == aid {
269 return strings.TrimSuffix(ta.Spl[sc].Value,"/100")
275 func round(v float64) int {