0ca0fdf4c0213899624e139dc45ef5b16e257359
[outofuni/gocash.git] / gocash.go
1 package main
2
3 import (
4         "encoding/xml"
5         "fmt"
6         "io/ioutil"
7         "os"
8 )
9
10 type Account struct {
11         XMLName xml.Name `xml:"account"`
12         Name string `xml:"name"`
13         AccountId string `xml:"id"`
14         ParentId string `xml:"parent"`
15 }
16
17 type Split struct {
18         XMLName xml.Name `xml:"split"`
19         Id string `xml:"id"`
20         Value string `xml:"value"`
21         Quantity string `xml:"quantity"`
22         AccountId string `xml:"account"`
23 }
24
25 type Transaction struct {
26         XMLName xml.Name `xml:"transaction"`
27         Id string `xml:"id"`
28         Date string `xml:"date-posted>date"`
29         Description string `xml:"description"`
30         Spl []Split `xml:"splits>split"`
31 }
32
33 type ParsedData struct {
34         XMLName xml.Name `xml:"gnc-v2"`
35         DataCnt []string `xml:"count-data"`
36         Accnt []Account `xml:"book>account"`
37         Trn []Transaction `xml:"book>transaction"`
38 }
39
40 // 'global' data
41 var data ParsedData
42
43 func main() {
44
45         // open xml file
46         file, err := os.Open("c13_skr03.gnucash")
47         if err != nil {
48                 fmt.Println("Error opening file:", err)
49                 return
50         }
51         defer file.Close()
52
53         // read xml file
54         xmldata, err := ioutil.ReadAll(file)
55         if err != nil {
56                 fmt.Println("Error reading file:", err)
57                 return
58         }
59
60         // unmarshal xml data
61         err = xml.Unmarshal(xmldata,&data)
62         if err != nil {
63                 fmt.Println("Error unmarshaling xml data:", err)
64                 return
65         }
66
67         // whooha, this is our data!
68         fmt.Println("Parsed accounts:",len(data.Accnt))
69         fmt.Println("Parsed transactions:",len(data.Trn))
70
71         //
72         // hardcoded account ids we have to look at
73         //
74         // --- buy
75         // wareneingang 19% and 7%
76         pid_buy_n := string("8e3b7c42e3173ed85f3d4736e82afb4d")
77         pid_buy_s := string("0cfd2ceb45fff89b9d1b7ce3af66cdf3")
78         pid_misc  := string("e3acc2865dbf931e41cf2b90240de5c2")
79         pid_rep   := string("b1d04ad157cac569f4299d4ddf94ed6f")
80         pid_room  := string("4394ed4ffa7266f8f8731080926a7a61")
81         pid_cap   := string("4196ee026d1bdb785df2c975fca91ae0")
82         // abziehbare vst 19% and 7%
83         aid_vst_n := string("7c449e13125d6b93043f963628106db2")
84         aid_vst_s := string("006643c1c0a91f2b40614c75a49c6295")
85         // --- sales
86         // receipts
87 /*
88         aid_rec_n := string("f3e905732b729ba096a50dab60559ce7")
89         aid_rec_s := string("66c1b04bd897766cb2be538094e1db6a")
90         aid_tip   := string("1d20024badc11a99a8e1cf3a9a64a501")
91         aid_dep   := string("9772f4e231f6f5e3100132cc53eb3447")
92 */
93         // ust
94         aid_ust_n := string("e4bd6ff52408be8076f24aeb105893d9")
95         aid_ust_s := string("38bf40d16529f2a1e611c073c6c1dc9c")
96
97         // account maps
98         type amap struct {
99                 pid string
100                 num int
101                 taxval int
102                 buy bool
103                 tax bool
104         }
105         accnt := make(map[string]amap)
106
107         for ac := range data.Accnt {
108                 aid := data.Accnt[ac].AccountId
109                 pid := data.Accnt[ac].ParentId
110                 // general map
111                 accnt[aid]=amap{
112                         pid,ac,0,false,false,
113                 }
114                 tmp := accnt[aid]
115                 switch {
116                 // ---- buy
117                 //   -- goods
118                 case pid == pid_buy_n || pid == pid_misc || pid == pid_rep || pid == pid_room || pid == pid_cap:
119                         tmp.taxval=19
120                         tmp.buy=true
121                         accnt[aid]=tmp
122                 case pid == pid_buy_s:
123                         tmp.taxval=7
124                         tmp.buy=true
125                         accnt[aid]=tmp
126                 // mathc pid: verschiedene kosten, reparatur/instandhaltung
127                 //            raumkosten + anlage/kapitalkonten
128                 //         -> buy, 19, notax
129                 //
130                 //   -- tax
131                 case aid == aid_vst_n:
132                         tmp.taxval=19
133                         tmp.buy=true
134                         tmp.tax=true
135                         accnt[aid]=tmp
136                 case aid == aid_vst_s:
137                         tmp.taxval=7
138                         tmp.buy=true
139                         tmp.tax=true
140                         accnt[aid]=tmp
141                 // ---- sales ----
142                 //   -- receipts
143                 //      match pid: erloeskonten
144                 //   -- tax
145                 case aid == aid_ust_n:
146                         tmp.taxval=19
147                         tmp.tax=true
148                         accnt[aid]=tmp
149                 case aid == aid_ust_s:
150                         tmp.taxval=7
151                         tmp.tax=true
152                         accnt[aid]=tmp
153                 }
154         }
155
156         // check transactions
157         for tc := range data.Trn {
158                 for tsc := range data.Trn[tc].Spl {
159                         aid := data.Trn[tc].Spl[tsc].AccountId
160                         switch {
161                         case accnt[aid].buy:
162                                 var ret bool
163                                 switch accnt[aid].taxval {
164                                 case 19:
165                                         ret=check_buy(&data.Trn[tc],aid_vst_n)
166                                 case 7:
167                                         ret=check_buy(&data.Trn[tc],aid_vst_s)
168                                 }
169                                 anum := accnt[aid].num
170                                 if ret == false {
171                                         fmt.Println("Problem:", data.Accnt[anum].Name,data.Trn[tc].Date)
172                                 }
173                         }
174                 }
175         }
176
177 }
178
179 func check_buy(ta *Transaction,id string) bool {
180         for  sc := range ta.Spl {
181                 if ta.Spl[sc].AccountId == id {
182                         return true
183                 }
184         }
185         return false
186 }
187