statements 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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()
         |