statements 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +22 -0
- data/bin/statements +8 -0
- data/lib/html/css/main.css +115 -0
- data/lib/html/css/main.css.map +7 -0
- data/lib/html/css/main.scss +173 -0
- data/lib/html/index.html +94 -0
- data/lib/html/js/main.coffee +146 -0
- data/lib/html/js/main.js +174 -0
- data/lib/html/js/main.js.map +10 -0
- data/lib/html/vendor/bootstrap/css/bootstrap-theme.css +469 -0
- data/lib/html/vendor/bootstrap/css/bootstrap.css +6331 -0
- data/lib/html/vendor/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/html/vendor/bootstrap/fonts/glyphicons-halflings-regular.svg +229 -0
- data/lib/html/vendor/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/html/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/html/vendor/bootstrap/js/bootstrap.js +2320 -0
- data/lib/html/vendor/bootstrap-datepicker.js +1681 -0
- data/lib/html/vendor/datepicker3.css +786 -0
- data/lib/html/vendor/jquery-2.1.3.js +9205 -0
- data/lib/html/vendor/underscore.js +1416 -0
- data/lib/statements/cli.rb +17 -0
- data/lib/statements/database.rb +22 -0
- data/lib/statements/migrations/00_alpha.rb +43 -0
- data/lib/statements/models/account.rb +9 -0
- data/lib/statements/models/document.rb +29 -0
- data/lib/statements/models/transaction.rb +43 -0
- data/lib/statements/pdf_reader.rb +34 -0
- data/lib/statements/reader/common/st_george.rb +31 -0
- data/lib/statements/reader/st_george_credit_card.rb +53 -0
- data/lib/statements/reader/st_george_savings.rb +95 -0
- data/lib/statements/reader.rb +76 -0
- data/lib/statements/search.rb +48 -0
- data/lib/statements/server.rb +69 -0
- data/lib/statements/version.rb +3 -0
- data/lib/statements/views/footer.erb +6 -0
- data/lib/statements/views/row.erb +16 -0
- data/lib/statements/views/search.erb +25 -0
- data/lib/statements.rb +17 -0
- metadata +141 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ff2b7e3e918329fc0e03bec9e77b195c3843fda6
|
4
|
+
data.tar.gz: 42b4173c2c664d3e510d90946875b7ea0a028772
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9e4050e7a812a5e0fa47ffd4441f9949e96f78b866b3aadf69547345bc0455c0b70671371e35e68a4b98f293be67874e2d8f956a8cbf8000cc341b01b157ed7b
|
7
|
+
data.tar.gz: 3f5c9a2c5abe973b48468fa660623c8d66de92f987c6168322cbd6ccaf41d163ee3df2a394bca7526ab7781a69b32d9f4fb91a7337ed203d0f3f24cb4543562a
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Neil E. Pearson
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Statements
|
2
|
+
|
3
|
+
Builds a database of bank account transaction history by reading PDF bank statements, and provides a simple web interface for browsing data.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```bash
|
8
|
+
$ gem install statements
|
9
|
+
```
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
1. `cd` to a directory containing all your bank statements.
|
14
|
+
2. Run `statements` and wait for new statements to be parsed.
|
15
|
+
3. Open `http://localhost:57473` in a browser.
|
16
|
+
|
17
|
+
## Supported banks
|
18
|
+
|
19
|
+
- St. George Credit Cards
|
20
|
+
- St. George Cash Accounts
|
21
|
+
|
22
|
+
The list is small. Want it to grow? Send a pull request!
|
data/bin/statements
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
.container-fluid {
|
2
|
+
padding-top: 15px; }
|
3
|
+
|
4
|
+
#colour a:before {
|
5
|
+
content: "";
|
6
|
+
border: 1px solid transparent;
|
7
|
+
padding: 6px;
|
8
|
+
display: block;
|
9
|
+
border-radius: 15px; }
|
10
|
+
#colour a.colour-white:before {
|
11
|
+
background: white; }
|
12
|
+
#colour a.colour-red:before {
|
13
|
+
background: #a13f3e; }
|
14
|
+
#colour a.colour-yellow:before {
|
15
|
+
background: #e9d543; }
|
16
|
+
#colour a.colour-green:before {
|
17
|
+
background: #3f9d5a; }
|
18
|
+
#colour a.colour-cyan:before {
|
19
|
+
background: #99d7ff; }
|
20
|
+
#colour a.colour-blue:before {
|
21
|
+
background: #48609d; }
|
22
|
+
#colour a.colour-magenta:before {
|
23
|
+
background: #af6bd7; }
|
24
|
+
|
25
|
+
#content thead th {
|
26
|
+
padding-top: 0; }
|
27
|
+
#content td p {
|
28
|
+
margin: 0; }
|
29
|
+
#content td p.small {
|
30
|
+
color: #666; }
|
31
|
+
#content .amount,
|
32
|
+
#content tfoot tr > * {
|
33
|
+
text-align: right; }
|
34
|
+
#content .credit .amount:before {
|
35
|
+
content: "($"; }
|
36
|
+
#content .credit .amount:after {
|
37
|
+
content: ")"; }
|
38
|
+
#content .debit .amount:before,
|
39
|
+
#content tfoot td:before {
|
40
|
+
content: "$"; }
|
41
|
+
#content tr.colour-white {
|
42
|
+
background: white; }
|
43
|
+
#content tr.colour-red {
|
44
|
+
background: #ffefef; }
|
45
|
+
#content tr.colour-yellow {
|
46
|
+
background: #ffffd7; }
|
47
|
+
#content tr.colour-green {
|
48
|
+
background: #e9fce7; }
|
49
|
+
#content tr.colour-blue {
|
50
|
+
background: #ebeffd; }
|
51
|
+
#content tr.colour-cyan {
|
52
|
+
background: #e1f7f7; }
|
53
|
+
#content tr.colour-magenta {
|
54
|
+
background: #fbefff; }
|
55
|
+
#content tr > td,
|
56
|
+
#content tr > th {
|
57
|
+
background: inherit; }
|
58
|
+
#content tr.colour-white a.picker,
|
59
|
+
#content li.colour-white a {
|
60
|
+
background: white; }
|
61
|
+
#content tr.colour-red a.picker,
|
62
|
+
#content li.colour-red a {
|
63
|
+
background: #a13f3e; }
|
64
|
+
#content tr.colour-green a.picker,
|
65
|
+
#content li.colour-green a {
|
66
|
+
background: #3f9d5a; }
|
67
|
+
#content tr.colour-blue a.picker,
|
68
|
+
#content li.colour-blue a {
|
69
|
+
background: #48609d; }
|
70
|
+
#content tr.colour-cyan a.picker,
|
71
|
+
#content li.colour-cyan a {
|
72
|
+
background: #99d7ff; }
|
73
|
+
#content tr.colour-magenta a.picker,
|
74
|
+
#content li.colour-magenta a {
|
75
|
+
background: #af6bd7; }
|
76
|
+
#content tr.colour-yellow a.picker,
|
77
|
+
#content li.colour-yellow a {
|
78
|
+
background: #e9d543; }
|
79
|
+
#content td.colour {
|
80
|
+
width: 20px;
|
81
|
+
position: relative; }
|
82
|
+
#content td.colour a {
|
83
|
+
display: block;
|
84
|
+
border: 1px solid #eee;
|
85
|
+
border-radius: 10px;
|
86
|
+
width: 20px;
|
87
|
+
height: 20px; }
|
88
|
+
#content td.colour a:hover {
|
89
|
+
border-color: #ddd; }
|
90
|
+
#content td.colour ul {
|
91
|
+
list-style: none;
|
92
|
+
position: absolute;
|
93
|
+
display: block;
|
94
|
+
right: 100%;
|
95
|
+
top: 1px;
|
96
|
+
margin-bottom: 0;
|
97
|
+
width: 167px;
|
98
|
+
text-align: right;
|
99
|
+
background: white;
|
100
|
+
border: 1px solid #eee;
|
101
|
+
border-radius: 50px;
|
102
|
+
padding: 3px;
|
103
|
+
height: 28px; }
|
104
|
+
#content td.colour ul li {
|
105
|
+
display: inline-block;
|
106
|
+
margin-right: 3px; }
|
107
|
+
#content td.colour ul li:last-child {
|
108
|
+
margin-right: 0; }
|
109
|
+
|
110
|
+
footer {
|
111
|
+
font-size: .8em;
|
112
|
+
text-align: center;
|
113
|
+
padding: 20px 0; }
|
114
|
+
|
115
|
+
/*# sourceMappingURL=main.css.map */
|
@@ -0,0 +1,7 @@
|
|
1
|
+
{
|
2
|
+
"version": 3,
|
3
|
+
"mappings": "AASA,gBAAiB;EACf,WAAW,EAAE,IAAI;;AAKf,gBAAS;EACP,OAAO,EAAE,EAAE;EACX,MAAM,EAAE,qBAAqB;EAC7B,OAAO,EAAC,GAAG;EACX,OAAO,EAAE,KAAK;EACd,aAAa,EAAE,IAAI;AAErB,6BAAsB;EAAE,UAAU,EArB9B,KAAK;AAsBT,2BAAoB;EAAE,UAAU,EArB9B,OAAO;AAsBT,8BAAuB;EAAE,UAAU,EArB9B,OAAO;AAsBZ,6BAAsB;EAAE,UAAU,EArB9B,OAAO;AAsBX,4BAAqB;EAAE,UAAU,EApB9B,OAAO;AAqBV,4BAAqB;EAAE,UAAU,EAtB9B,OAAO;AAuBV,+BAAwB;EAAE,UAAU,EArB9B,OAAO;;AA2Bf,iBAAS;EACP,WAAW,EAAE,CAAC;AAGhB,aAAK;EACH,MAAM,EAAE,CAAC;EAET,mBAAQ;IACN,KAAK,EAAE,IAAI;AAIf;qBACa;EACX,UAAU,EAAE,KAAK;AAIjB,+BAAS;EAAE,OAAO,EAAE,IAAI;AACxB,8BAAQ;EAAE,OAAO,EAAE,GAAG;AAKtB;wBAAS;EAAE,OAAO,EAAE,GAAG;AAIvB,wBAAe;EACb,UAAU,EA9DkB,KAAK;AAgEnC,sBAAa;EACX,UAAU,EAhEgB,OAAO;AAkEnC,yBAAgB;EACd,UAAU,EAlEmB,OAAO;AAoEtC,wBAAe;EACb,UAAU,EApEkB,OAAO;AAsErC,uBAAc;EACZ,UAAU,EAtEiB,OAAO;AAwEpC,uBAAc;EACZ,UAAU,EAxEiB,OAAO;AA0EpC,0BAAiB;EACf,UAAU,EA1EoB,OAAO;AA4EvC;gBACK;EACH,UAAU,EAAE,OAAO;AAIvB;0BACkB;EAChB,UAAU,EA1FN,KAAK;AA6FX;wBACgB;EACd,UAAU,EA9FR,OAAO;AAiGX;0BACkB;EAChB,UAAU,EAjGN,OAAO;AAoGb;yBACiB;EACf,UAAU,EArGP,OAAO;AAwGZ;yBACiB;EACf,UAAU,EAzGP,OAAO;AA4GZ;4BACoB;EAClB,UAAU,EA7GJ,OAAO;AAgHf;2BACmB;EACjB,UAAU,EAtHL,OAAO;AAyHd,kBAAU;EACR,KAAK,EAAE,IAAI;EACX,QAAQ,EAAE,QAAQ;EAElB,oBAAE;IACA,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,cAAc;IACtB,aAAa,EAAE,IAAI;IACnB,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IAEZ,0BAAQ;MACN,YAAY,EAAE,IAAI;EAItB,qBAAG;IACD,UAAU,EAAE,IAAI;IAChB,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,IAAI;IACX,GAAG,EAAE,GAAG;IACR,aAAa,EAAE,CAAC;IAChB,KAAK,EAAE,KAAK;IACZ,UAAU,EAAE,KAAK;IACjB,UAAU,EAAE,KAAK;IACjB,MAAM,EAAE,cAAc;IACtB,aAAa,EAAE,IAAI;IACnB,OAAO,EAAE,GAAG;IACZ,MAAM,EAAE,IAAI;IAEZ,wBAAG;MACD,OAAO,EAAE,YAAY;MACrB,YAAY,EAAE,GAAG;MAEjB,mCAAa;QACX,YAAY,EAAE,CAAC;;AAQzB,MAAO;EACL,SAAS,EAAE,IAAI;EACf,UAAU,EAAE,MAAM;EAClB,OAAO,EAAE,MAAM",
|
4
|
+
"sources": ["main.scss"],
|
5
|
+
"names": [],
|
6
|
+
"file": "main.css"
|
7
|
+
}
|
@@ -0,0 +1,173 @@
|
|
1
|
+
// Colours
|
2
|
+
$white: white; $light-white: white;
|
3
|
+
$red: #a13f3e; $light-red: #ffefef;
|
4
|
+
$yellow: #e9d543; $light-yellow: #ffffd7;
|
5
|
+
$green: #3f9d5a; $light-green: #e9fce7;
|
6
|
+
$blue: #48609d; $light-blue: #ebeffd;
|
7
|
+
$cyan: #99d7ff; $light-cyan: #e1f7f7;
|
8
|
+
$magenta: #af6bd7; $light-magenta: #fbefff;
|
9
|
+
|
10
|
+
.container-fluid {
|
11
|
+
padding-top: 15px;
|
12
|
+
}
|
13
|
+
|
14
|
+
#colour {
|
15
|
+
a {
|
16
|
+
&:before {
|
17
|
+
content: "";
|
18
|
+
border: 1px solid transparent;
|
19
|
+
padding:6px;
|
20
|
+
display: block;
|
21
|
+
border-radius: 15px;
|
22
|
+
}
|
23
|
+
&.colour-white:before { background: $white; }
|
24
|
+
&.colour-red:before { background: $red; }
|
25
|
+
&.colour-yellow:before { background: $yellow; }
|
26
|
+
&.colour-green:before { background: $green; }
|
27
|
+
&.colour-cyan:before { background: $cyan; }
|
28
|
+
&.colour-blue:before { background: $blue; }
|
29
|
+
&.colour-magenta:before { background: $magenta; }
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
#content {
|
34
|
+
|
35
|
+
thead th {
|
36
|
+
padding-top: 0;
|
37
|
+
}
|
38
|
+
|
39
|
+
td p {
|
40
|
+
margin: 0;
|
41
|
+
|
42
|
+
&.small {
|
43
|
+
color: #666;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
.amount,
|
48
|
+
tfoot tr > * {
|
49
|
+
text-align: right;
|
50
|
+
}
|
51
|
+
|
52
|
+
.credit .amount {
|
53
|
+
&:before { content: "($"; }
|
54
|
+
&:after { content: ")"; }
|
55
|
+
}
|
56
|
+
|
57
|
+
.debit .amount,
|
58
|
+
tfoot td {
|
59
|
+
&:before { content: "$"; }
|
60
|
+
}
|
61
|
+
|
62
|
+
tr {
|
63
|
+
&.colour-white {
|
64
|
+
background: $light-white;
|
65
|
+
}
|
66
|
+
&.colour-red {
|
67
|
+
background: $light-red;
|
68
|
+
}
|
69
|
+
&.colour-yellow {
|
70
|
+
background: $light-yellow;
|
71
|
+
}
|
72
|
+
&.colour-green {
|
73
|
+
background: $light-green;
|
74
|
+
}
|
75
|
+
&.colour-blue {
|
76
|
+
background: $light-blue;
|
77
|
+
}
|
78
|
+
&.colour-cyan {
|
79
|
+
background: $light-cyan;
|
80
|
+
}
|
81
|
+
&.colour-magenta {
|
82
|
+
background: $light-magenta;
|
83
|
+
}
|
84
|
+
> td,
|
85
|
+
> th {
|
86
|
+
background: inherit;
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
tr.colour-white a.picker,
|
91
|
+
li.colour-white a {
|
92
|
+
background: $white;
|
93
|
+
}
|
94
|
+
|
95
|
+
tr.colour-red a.picker,
|
96
|
+
li.colour-red a {
|
97
|
+
background: $red;
|
98
|
+
}
|
99
|
+
|
100
|
+
tr.colour-green a.picker,
|
101
|
+
li.colour-green a {
|
102
|
+
background: $green;
|
103
|
+
}
|
104
|
+
|
105
|
+
tr.colour-blue a.picker,
|
106
|
+
li.colour-blue a {
|
107
|
+
background: $blue;
|
108
|
+
}
|
109
|
+
|
110
|
+
tr.colour-cyan a.picker,
|
111
|
+
li.colour-cyan a {
|
112
|
+
background: $cyan;
|
113
|
+
}
|
114
|
+
|
115
|
+
tr.colour-magenta a.picker,
|
116
|
+
li.colour-magenta a {
|
117
|
+
background: $magenta;
|
118
|
+
}
|
119
|
+
|
120
|
+
tr.colour-yellow a.picker,
|
121
|
+
li.colour-yellow a {
|
122
|
+
background: $yellow;
|
123
|
+
}
|
124
|
+
|
125
|
+
td.colour {
|
126
|
+
width: 20px;
|
127
|
+
position: relative;
|
128
|
+
|
129
|
+
a {
|
130
|
+
display: block;
|
131
|
+
border: 1px solid #eee;
|
132
|
+
border-radius: 10px;
|
133
|
+
width: 20px;
|
134
|
+
height: 20px;
|
135
|
+
|
136
|
+
&:hover {
|
137
|
+
border-color: #ddd;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
ul {
|
142
|
+
list-style: none;
|
143
|
+
position: absolute;
|
144
|
+
display: block;
|
145
|
+
right: 100%;
|
146
|
+
top: 1px;
|
147
|
+
margin-bottom: 0;
|
148
|
+
width: 167px;
|
149
|
+
text-align: right;
|
150
|
+
background: white;
|
151
|
+
border: 1px solid #eee;
|
152
|
+
border-radius: 50px;
|
153
|
+
padding: 3px;
|
154
|
+
height: 28px;
|
155
|
+
|
156
|
+
li {
|
157
|
+
display: inline-block;
|
158
|
+
margin-right: 3px;
|
159
|
+
|
160
|
+
&:last-child {
|
161
|
+
margin-right: 0;
|
162
|
+
}
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
}
|
168
|
+
|
169
|
+
footer {
|
170
|
+
font-size: .8em;
|
171
|
+
text-align: center;
|
172
|
+
padding: 20px 0;
|
173
|
+
}
|
data/lib/html/index.html
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<title>Statements</title>
|
5
|
+
<meta charset="UTF-8">
|
6
|
+
<link rel="stylesheet" href="vendor/bootstrap/css/bootstrap.css"/>
|
7
|
+
<link rel="stylesheet" href="vendor/bootstrap/css/bootstrap-theme.css"/>
|
8
|
+
<link rel="stylesheet" href="vendor/datepicker3.css"/>
|
9
|
+
<link rel="stylesheet" href="css/main.css"/>
|
10
|
+
<script src="q/accounts.js"></script>
|
11
|
+
<script src="vendor/jquery-2.1.3.js"></script>
|
12
|
+
<script src="vendor/underscore.js"></script>
|
13
|
+
<script src="vendor/bootstrap/js/bootstrap.js"></script>
|
14
|
+
<script src="vendor/bootstrap-datepicker.js"></script>
|
15
|
+
<script src="js/main.js"></script>
|
16
|
+
</head>
|
17
|
+
<body>
|
18
|
+
<div class="container-fluid">
|
19
|
+
<div class="row">
|
20
|
+
<div class="col-sm-3 sidebar">
|
21
|
+
<form>
|
22
|
+
<div class="form-group">
|
23
|
+
<label for="order">Order</label>
|
24
|
+
<select id="order" name="order" class="form-control">
|
25
|
+
<option selected value="posted_at desc, document_line desc">Newest first</option>
|
26
|
+
<option value="posted_at asc, document_line desc">Oldest first</option>
|
27
|
+
<option value="description asc, posted_at asc, document_line asc">Alphabetical</option>
|
28
|
+
<option value="abs(amount) desc, description asc, posted_at asc, document_line asc">High value first</option>
|
29
|
+
<option value="abs(amount) asc, description asc, posted_at asc, document_line asc">Low value first</option>
|
30
|
+
</select>
|
31
|
+
</div>
|
32
|
+
<div class="form-group">
|
33
|
+
<label for="date-start">Period</label>
|
34
|
+
<div class="input-daterange input-group" id="date-range">
|
35
|
+
<input type="text" class="input-sm form-control" name="date-start" id="date-start" placeholder="Start"/>
|
36
|
+
<span class="input-group-addon">to</span>
|
37
|
+
<input type="text" class="input-sm form-control" name="date-end" id="date-end" placeholder="Finish"/>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
<div class="form-group">
|
41
|
+
<label for="text">Search</label>
|
42
|
+
<input type="text"
|
43
|
+
class="form-control"
|
44
|
+
name="text"
|
45
|
+
id="text"
|
46
|
+
placeholder="Partial description"/>
|
47
|
+
</div>
|
48
|
+
<div class="form-group">
|
49
|
+
<label>Type</label>
|
50
|
+
<div id="type" class="btn-group btn-group-justified" role="group">
|
51
|
+
<a role="button" class="btn btn-default" data-type="credits">Credits</a>
|
52
|
+
<a role="button" class="btn btn-default active" data-type="both">Both</a>
|
53
|
+
<a role="button" class="btn btn-default" data-type="debits">Debits</a>
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
<div class="form-group">
|
57
|
+
<label>Colour</label>
|
58
|
+
<div id="colour" class="btn-group btn-group-justified" role="group" data-toggle="buttons">
|
59
|
+
<a role="button" class="btn btn-default active colour-white"></a>
|
60
|
+
<a role="button" class="btn btn-default active colour-red"></a>
|
61
|
+
<a role="button" class="btn btn-default active colour-yellow"></a>
|
62
|
+
<a role="button" class="btn btn-default active colour-green"></a>
|
63
|
+
<a role="button" class="btn btn-default active colour-cyan"></a>
|
64
|
+
<a role="button" class="btn btn-default active colour-blue"></a>
|
65
|
+
<a role="button" class="btn btn-default active colour-magenta"></a>
|
66
|
+
</div>
|
67
|
+
</div>
|
68
|
+
<div class="form-group">
|
69
|
+
<label>Accounts</label>
|
70
|
+
<div id="account-buttons"
|
71
|
+
class="btn-group-vertical btn-group-xs"
|
72
|
+
role="group"
|
73
|
+
style="width:100%"
|
74
|
+
data-toggle="buttons"></div>
|
75
|
+
<script>populate_accounts('#account-buttons')</script>
|
76
|
+
</div>
|
77
|
+
<div>
|
78
|
+
<div id="account-button-bulk" class="btn-group btn-group-justified" role="group">
|
79
|
+
<a role="button" class="btn btn-default" data-set="on">All</a>
|
80
|
+
<a role="button" class="btn btn-default" data-set="off">None</a>
|
81
|
+
</div>
|
82
|
+
</div>
|
83
|
+
</form>
|
84
|
+
<footer>
|
85
|
+
<p>For my Anna ❤️</p>
|
86
|
+
</footer>
|
87
|
+
</div>
|
88
|
+
<div id="content" class="col-sm-9 content">
|
89
|
+
|
90
|
+
</div>
|
91
|
+
</div>
|
92
|
+
</div>
|
93
|
+
</body>
|
94
|
+
</html>
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# List of colour literals
|
2
|
+
COLOURS = 'white red yellow green cyan blue magenta'.split ' '
|
3
|
+
|
4
|
+
# Populates the list of bank accounts in the sidebar
|
5
|
+
window.populate_accounts = (id) ->
|
6
|
+
$el = $(id)
|
7
|
+
for account in accounts
|
8
|
+
a = $('<a role="button" class="btn btn-default active" />')
|
9
|
+
a.text account.name
|
10
|
+
a.append '<br/>'
|
11
|
+
a.append $('<span class="small">').text(account.number)
|
12
|
+
a.data id: account.id
|
13
|
+
$el.append a
|
14
|
+
|
15
|
+
# AJAX layer
|
16
|
+
post = (page, data) -> $.ajax
|
17
|
+
url: "q/#{page}"
|
18
|
+
method: 'post'
|
19
|
+
contentType: 'application/json; charset=UTF-8'
|
20
|
+
dataType: page.match(/[^.]+$/)[0]
|
21
|
+
data: JSON.stringify data
|
22
|
+
|
23
|
+
# Method to query the database
|
24
|
+
querying = false
|
25
|
+
query_again = false
|
26
|
+
query = ->
|
27
|
+
|
28
|
+
# Handle interrupts
|
29
|
+
if querying
|
30
|
+
query_again = true
|
31
|
+
return
|
32
|
+
querying = true
|
33
|
+
query_again = false
|
34
|
+
|
35
|
+
# Clear content
|
36
|
+
$('#content').html 'One moment...'
|
37
|
+
|
38
|
+
# Submit data
|
39
|
+
req = post 'search.html',
|
40
|
+
order: $('#order').val()
|
41
|
+
date_start: $('#date-start').val()
|
42
|
+
date_end: $('#date-end').val()
|
43
|
+
search: $('#text').val()
|
44
|
+
type: $('#type .active').data 'type'
|
45
|
+
accounts: $('#account-buttons .active').map(-> $(@).data 'id').toArray()
|
46
|
+
colours: $('#colour .active').map(-> @className.match(/colour-(\w+)/)[1]).toArray()
|
47
|
+
|
48
|
+
# On success
|
49
|
+
req.done (result) -> $('#content').html result
|
50
|
+
|
51
|
+
# On fail
|
52
|
+
req.fail -> alert 'Query failed'
|
53
|
+
|
54
|
+
# Clean up
|
55
|
+
req.always ->
|
56
|
+
querying = false
|
57
|
+
query() if query_again
|
58
|
+
|
59
|
+
# Pad querying out a bit
|
60
|
+
query = _.debounce(query, 300)
|
61
|
+
|
62
|
+
# Method to change a transaction's colour
|
63
|
+
setColour = (transactionId, colour) -> post 'colour.json',
|
64
|
+
id: transactionId
|
65
|
+
colour: colour
|
66
|
+
|
67
|
+
$ ->
|
68
|
+
# Set the date range to last financial year
|
69
|
+
months = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split ' '
|
70
|
+
range = end: new Date
|
71
|
+
range.end.setDate 1
|
72
|
+
range.end.setMonth range.end.getMonth() - 1 until range.end.getMonth() is 6
|
73
|
+
range.start = new Date(range.end)
|
74
|
+
range.start.setFullYear range.start.getFullYear() - 1
|
75
|
+
range.end.setDate range.end.getDate() - 1
|
76
|
+
|
77
|
+
$("#date-#{k}").val "#{i.getDate()} #{months[i.getMonth()]} #{i.getFullYear()}" for k, i of range
|
78
|
+
|
79
|
+
# Set up the date picker
|
80
|
+
$('.input-daterange').datepicker
|
81
|
+
format: "d M yyyy"
|
82
|
+
startView: 2
|
83
|
+
todayBtn: 'linked'
|
84
|
+
autoclose: true
|
85
|
+
.on 'changeDate', query
|
86
|
+
|
87
|
+
# Order
|
88
|
+
$('#order').on 'change', query
|
89
|
+
|
90
|
+
# Dates
|
91
|
+
$('date-range').on 'change', 'input', query
|
92
|
+
|
93
|
+
# Search
|
94
|
+
$('#text').on 'change keyup', query
|
95
|
+
|
96
|
+
# Colours
|
97
|
+
$('#colour').on 'click', 'a', query
|
98
|
+
|
99
|
+
# Account buttons
|
100
|
+
$accountButtons = $('#account-buttons a')
|
101
|
+
$accountButtons.on 'click', query
|
102
|
+
|
103
|
+
# Account select all/none buttons
|
104
|
+
$('#account-button-bulk').on 'click', 'a', (e) ->
|
105
|
+
set = $(e.currentTarget).data('set')
|
106
|
+
$accountButtons.toggleClass 'active', set is 'on'
|
107
|
+
query()
|
108
|
+
|
109
|
+
# Radio button behaviour for transaction types
|
110
|
+
$typeButtons = $('#type a')
|
111
|
+
$('#type').on 'click', 'a', (e) ->
|
112
|
+
return if $(e.currentTarget).hasClass 'active'
|
113
|
+
$typeButtons.each -> $(this).toggleClass 'active', this is e.currentTarget
|
114
|
+
query()
|
115
|
+
|
116
|
+
# Handler for blurring colour pickers
|
117
|
+
$picker = null
|
118
|
+
$('body').on 'click', (e) ->
|
119
|
+
target = e.currentTarget
|
120
|
+
closePicker() unless $picker and (target is $picker[0] or $picker.find(target)[0])
|
121
|
+
|
122
|
+
# Method to remove colour picker
|
123
|
+
closePicker = ->
|
124
|
+
$picker.remove() if $picker
|
125
|
+
$picker = null
|
126
|
+
|
127
|
+
# Handlers for clicks on colour pickers
|
128
|
+
$('#content').on 'click', 'td.colour a.picker', (e) ->
|
129
|
+
e.stopPropagation()
|
130
|
+
closePicker()
|
131
|
+
$tr = $(e.currentTarget).parents('tr').first()
|
132
|
+
$td = $tr.find('td.colour')
|
133
|
+
$picker = $('<ul class="colours">')
|
134
|
+
$picker.append $('<li>').addClass("colour-#{i}").append('<a href="javascript:">') for i in COLOURS
|
135
|
+
$picker.appendTo $td
|
136
|
+
$picker.on 'click', 'a', (e) ->
|
137
|
+
$li = $(e.currentTarget).parents('li').first()
|
138
|
+
colour = $li[0].className.match(/colour-(\w+)/)[1]
|
139
|
+
op = setColour $tr.data('id'), colour
|
140
|
+
op.fail -> alert 'Something went wrong. Try reloading?'
|
141
|
+
op.done -> $tr[0].className = $tr[0].className.replace /colour-\w+/, "colour-#{colour}"
|
142
|
+
closePicker()
|
143
|
+
|
144
|
+
|
145
|
+
# Do an initial query
|
146
|
+
query()
|