ifin24-client 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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README +54 -0
- data/README.rdoc +17 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/bin/ifin24 +21 -0
- data/config.yml.example +3 -0
- data/lib/ifin24/client.rb +131 -0
- data/lib/ifin24/commands/add_expense.rb +109 -0
- data/lib/ifin24/commands/base.rb +8 -0
- data/lib/ifin24/commands/list_accounts.rb +9 -0
- data/lib/ifin24/commands/list_entries.rb +42 -0
- data/lib/ifin24/commands.rb +8 -0
- data/lib/ifin24/configuration.rb +20 -0
- data/lib/ifin24/console.rb +44 -0
- data/lib/ifin24/helpers/printer.rb +32 -0
- data/lib/ifin24/helpers.rb +5 -0
- data/lib/ifin24/models/account.rb +6 -0
- data/lib/ifin24/models/base.rb +11 -0
- data/lib/ifin24/models/category.rb +15 -0
- data/lib/ifin24/models/entry.rb +14 -0
- data/lib/ifin24/models.rb +8 -0
- data/lib/ifin24.rb +11 -0
- data/spec/ifin24-client_spec.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- metadata +140 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2009 Łukasz Bandzarewicz
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Sample session:
|
|
2
|
+
|
|
3
|
+
ruby-1.9.1-p378$ ./ifin24-client.rb
|
|
4
|
+
a) Dodaj wydatek
|
|
5
|
+
b) Lista transakcji
|
|
6
|
+
c) Koniec
|
|
7
|
+
? a
|
|
8
|
+
Nazwa: Obiad
|
|
9
|
+
Data: |2010-08-08|
|
|
10
|
+
1. eKONTO / 50 PLN
|
|
11
|
+
2. Gotówka / 100 PLN
|
|
12
|
+
3. Konto oszczędnościowe / 3 000 PLN
|
|
13
|
+
4. PKO Bank Polski / 2 000,00 PLN
|
|
14
|
+
Wybierz rachunek: 2
|
|
15
|
+
1. Dom
|
|
16
|
+
2. Bieżące wydatki
|
|
17
|
+
3. Multimedia
|
|
18
|
+
4. Transport
|
|
19
|
+
5. Odzież i dodatki
|
|
20
|
+
6. Dla innych
|
|
21
|
+
7. Sport
|
|
22
|
+
8. Edukacja
|
|
23
|
+
9. Zdrowie/Ubezpieczenia
|
|
24
|
+
10. Rozrywka/ Wypoczynek
|
|
25
|
+
11. Zainteresowania
|
|
26
|
+
12. Zobowiązania finansowe
|
|
27
|
+
13. Inwestycje
|
|
28
|
+
14. Transfer środków
|
|
29
|
+
Wybierz kategorię: 2
|
|
30
|
+
1. Żywność
|
|
31
|
+
2. Stołówka/ posiłki poza domem
|
|
32
|
+
3. Kosmetyki i Chemia
|
|
33
|
+
4. Fryzjer/ kosmetyczka
|
|
34
|
+
5. Alkohol
|
|
35
|
+
6. Papierosy
|
|
36
|
+
Wybierz podkategorię: 2
|
|
37
|
+
Kwota: 15
|
|
38
|
+
Tagi:
|
|
39
|
+
Opis:
|
|
40
|
+
================
|
|
41
|
+
Nazwa: Obiad
|
|
42
|
+
Data: 2010-08-08
|
|
43
|
+
Rachunek: Gotówka / 100 PLN
|
|
44
|
+
Kwota: 15
|
|
45
|
+
Kategoria: Bieżące wydatki / Stołówka/ posiłki poza domem
|
|
46
|
+
Tagi:
|
|
47
|
+
Opis:
|
|
48
|
+
================
|
|
49
|
+
Dane poprawne? y
|
|
50
|
+
Wysyłanie danych...
|
|
51
|
+
a) Dodaj wydatek
|
|
52
|
+
b) Lista transakcji
|
|
53
|
+
c) Koniec
|
|
54
|
+
? c
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
= ifin24-client.1
|
|
2
|
+
|
|
3
|
+
Description goes here.
|
|
4
|
+
|
|
5
|
+
== Note on Patches/Pull Requests
|
|
6
|
+
|
|
7
|
+
* Fork the project.
|
|
8
|
+
* Make your feature addition or bug fix.
|
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
|
10
|
+
future version unintentionally.
|
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
|
12
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
|
13
|
+
* Send me a pull request. Bonus points for topic branches.
|
|
14
|
+
|
|
15
|
+
== Copyright
|
|
16
|
+
|
|
17
|
+
Copyright (c) 2010 Łukasz Bandzarewicz. See LICENSE for details.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'rake'
|
|
5
|
+
|
|
6
|
+
begin
|
|
7
|
+
require 'jeweler'
|
|
8
|
+
Jeweler::Tasks.new do |gem|
|
|
9
|
+
gem.name = "ifin24-client"
|
|
10
|
+
gem.summary = %Q{Console for iFIN24}
|
|
11
|
+
gem.description = %Q{Console for iFIN24}
|
|
12
|
+
gem.email = "lucassus@gmail.com"
|
|
13
|
+
gem.homepage = "http://github.com/lucassus/ifin24-client"
|
|
14
|
+
gem.authors = ["Łukasz Bandzarewicz"]
|
|
15
|
+
|
|
16
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
|
17
|
+
|
|
18
|
+
gem.add_dependency "mechanize"
|
|
19
|
+
gem.add_dependency "highline"
|
|
20
|
+
|
|
21
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
|
22
|
+
end
|
|
23
|
+
Jeweler::GemcutterTasks.new
|
|
24
|
+
rescue LoadError
|
|
25
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
require 'spec/rake/spectask'
|
|
29
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
|
30
|
+
spec.libs << 'lib' << 'spec'
|
|
31
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
|
35
|
+
spec.libs << 'lib' << 'spec'
|
|
36
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
|
37
|
+
spec.rcov = true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
task :spec => :check_dependencies
|
|
41
|
+
|
|
42
|
+
task :default => :spec
|
|
43
|
+
|
|
44
|
+
require 'rake/rdoctask'
|
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
|
46
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
|
47
|
+
|
|
48
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
49
|
+
rdoc.title = "ifin24-client.1 #{version}"
|
|
50
|
+
rdoc.rdoc_files.include('README*')
|
|
51
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
52
|
+
end
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.0
|
data/bin/ifin24
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
5
|
+
|
|
6
|
+
require 'rubygems'
|
|
7
|
+
|
|
8
|
+
require 'yaml'
|
|
9
|
+
require 'mechanize'
|
|
10
|
+
require 'highline/import'
|
|
11
|
+
|
|
12
|
+
require 'ifin24'
|
|
13
|
+
|
|
14
|
+
def main
|
|
15
|
+
config = Ifin24::Configuration.instance
|
|
16
|
+
client = Ifin24::Client.new(config[:login], config[:password])
|
|
17
|
+
console = Ifin24::Console.new(client)
|
|
18
|
+
console.main_menu
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
main
|
data/config.yml.example
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
class Ifin24::Client
|
|
2
|
+
|
|
3
|
+
LOGIN_FORM_URL = 'https://www.ifin24.pl/logowanie'
|
|
4
|
+
ENTRY_FORM_URL = 'https://www.ifin24.pl/zarzadzanie-finansami/transakcje/dodaj-wydatek'
|
|
5
|
+
LIST_URL = 'https://www.ifin24.pl/zarzadzanie-finansami/transakcje/lista'
|
|
6
|
+
LIST_PAGE_PARAM = '?pageNumber='
|
|
7
|
+
|
|
8
|
+
def initialize(login, password)
|
|
9
|
+
@agent = Mechanize.new
|
|
10
|
+
login(login, password)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def categories
|
|
14
|
+
@categories ||= fetch_categories
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def accounts
|
|
18
|
+
fetch_accounts
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def send_entry(entry)
|
|
22
|
+
page = @agent.get(ENTRY_FORM_URL)
|
|
23
|
+
form = page.forms.first
|
|
24
|
+
|
|
25
|
+
form['entry.title'] = entry.title.to_s
|
|
26
|
+
form['entry.date'] = entry.date.to_s
|
|
27
|
+
form['selectedBankAccount'] = entry.account.id.to_s
|
|
28
|
+
form['entry.entryCategory.id'] = entry.sub_category.id.to_s
|
|
29
|
+
form['entry.amount'] = entry.amount.to_s
|
|
30
|
+
form['value'] = entry.tags.to_s
|
|
31
|
+
form['entry.note'] = entry.note.to_s
|
|
32
|
+
|
|
33
|
+
form.submit
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def fetch_entries(curr_page = 1)
|
|
37
|
+
page = @agent.get(LIST_URL + LIST_PAGE_PARAM + curr_page.to_s)
|
|
38
|
+
total_pages = extract_entries_total_pages(page)
|
|
39
|
+
entry_row_elements = page.search('table tbody tr')
|
|
40
|
+
|
|
41
|
+
entries = []
|
|
42
|
+
|
|
43
|
+
entry_row_elements.each do |entry_row_element|
|
|
44
|
+
entry_elements = entry_row_element.search('td')
|
|
45
|
+
next if entry_elements.size != 5
|
|
46
|
+
|
|
47
|
+
entry = Ifin24::Models::Entry.new
|
|
48
|
+
|
|
49
|
+
title_column = entry_elements[2]
|
|
50
|
+
entry.title = title_column.children[0].text.strip
|
|
51
|
+
entry.note = title_column.search('span').text.strip
|
|
52
|
+
|
|
53
|
+
date_column = entry_elements[1]
|
|
54
|
+
entry.date = date_column.text.strip
|
|
55
|
+
|
|
56
|
+
category_column = entry_elements[3]
|
|
57
|
+
sub_category = Ifin24::Models::Category.new(:name => category_column.children[0].text.strip)
|
|
58
|
+
entry.sub_category = sub_category
|
|
59
|
+
|
|
60
|
+
entry.tags = category_column.search('span').text.strip
|
|
61
|
+
amount_column = entry_elements[4]
|
|
62
|
+
entry.amount = amount_column.text.strip
|
|
63
|
+
|
|
64
|
+
entries << entry
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
return entries, total_pages
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def login(login, password)
|
|
73
|
+
page = @agent.get(LOGIN_FORM_URL)
|
|
74
|
+
form = page.forms.first
|
|
75
|
+
|
|
76
|
+
form['login'] = login
|
|
77
|
+
form['password'] = password
|
|
78
|
+
|
|
79
|
+
form.submit
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def fetch_categories
|
|
83
|
+
page = @agent.get(ENTRY_FORM_URL)
|
|
84
|
+
categories_element = page.search('ul.expenseCombo>li')
|
|
85
|
+
|
|
86
|
+
categories = []
|
|
87
|
+
categories_element[1..-1].each do |category_elem|
|
|
88
|
+
category_without_children = category_elem.children[1].nil?
|
|
89
|
+
next if category_without_children
|
|
90
|
+
|
|
91
|
+
category_name = category_elem.children[0].text.strip
|
|
92
|
+
category = Ifin24::Models::Category.new(:name => category_name)
|
|
93
|
+
children_element = category_elem.children[1].children.search('li')
|
|
94
|
+
|
|
95
|
+
children_element.each do |child_elem|
|
|
96
|
+
child_id = child_elem.attributes['rel'].value
|
|
97
|
+
child_name = child_elem.text.strip
|
|
98
|
+
|
|
99
|
+
child = Ifin24::Models::Category.new(:id => child_id, :name => child_name)
|
|
100
|
+
category.children << child
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
categories << category
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
return categories
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def fetch_accounts
|
|
110
|
+
page = @agent.get(ENTRY_FORM_URL)
|
|
111
|
+
accounts_element = page.search('ul#bankAccountCombo>li')
|
|
112
|
+
|
|
113
|
+
accounts = []
|
|
114
|
+
accounts_element.each do |account_elem|
|
|
115
|
+
id = account_elem.attributes['rel'].value
|
|
116
|
+
next if id == '0' # skip the prompt
|
|
117
|
+
name = account_elem.text.strip
|
|
118
|
+
|
|
119
|
+
accounts << Ifin24::Models::Account.new(:id => id, :name => name)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
return accounts
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# TODO implement
|
|
126
|
+
def extract_entries_total_pages(page)
|
|
127
|
+
# page.search('div.pager a')
|
|
128
|
+
3
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
class Ifin24::Commands::AddExpense < Ifin24::Commands::Base
|
|
4
|
+
|
|
5
|
+
def execute
|
|
6
|
+
entry = get_entry
|
|
7
|
+
|
|
8
|
+
catch :all_ok do
|
|
9
|
+
loop do
|
|
10
|
+
choose do |menu|
|
|
11
|
+
menu.index = :letter
|
|
12
|
+
menu.index_suffix = ") "
|
|
13
|
+
|
|
14
|
+
menu.choice("Nazwa: #{entry.title}") { get_title(entry) }
|
|
15
|
+
menu.choice("Data: #{entry.date}") { get_date(entry) }
|
|
16
|
+
menu.choice("Konto: #{entry.account.name}") { get_account(entry) }
|
|
17
|
+
menu.choice("Kategoria: #{entry.category_full_name}") { get_category(entry) }
|
|
18
|
+
menu.choice("Kwota: #{entry.amount}") { get_amount(entry) }
|
|
19
|
+
menu.choice("Tagi: #{entry.tags}") { get_tags(entry) }
|
|
20
|
+
menu.choice("Opis: #{entry.note}") { get_note(entry) }
|
|
21
|
+
|
|
22
|
+
menu.choice("Powrót do głównego menu") do
|
|
23
|
+
throw :all_ok
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
menu.choice("Wyślij") do
|
|
27
|
+
puts "Wysyłanie danych..."
|
|
28
|
+
@client.send_entry(entry)
|
|
29
|
+
throw :all_ok
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def get_entry
|
|
39
|
+
entry = Ifin24::Models::Entry.new
|
|
40
|
+
|
|
41
|
+
get_title(entry)
|
|
42
|
+
get_date(entry)
|
|
43
|
+
get_account(entry)
|
|
44
|
+
get_category(entry)
|
|
45
|
+
get_amount(entry)
|
|
46
|
+
get_tags(entry)
|
|
47
|
+
get_note(entry)
|
|
48
|
+
|
|
49
|
+
return entry
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def get_title(entry)
|
|
53
|
+
entry.title = ask('Nazwa: ')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def get_date(entry)
|
|
57
|
+
curr_date = Date.today
|
|
58
|
+
entry.date = ask('Data: ') do |q|
|
|
59
|
+
q.default = curr_date
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def get_account(entry)
|
|
64
|
+
choose do |menu|
|
|
65
|
+
menu.prompt = 'Wybierz rachunek: '
|
|
66
|
+
|
|
67
|
+
@client.accounts.each do |account|
|
|
68
|
+
menu.choice(account.name) do
|
|
69
|
+
entry.account = account
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def get_category(entry)
|
|
76
|
+
choose do |menu|
|
|
77
|
+
menu.prompt = 'Wybierz kategorię: '
|
|
78
|
+
|
|
79
|
+
@client.categories.each do |category|
|
|
80
|
+
menu.choice(category.name) do
|
|
81
|
+
entry.category = category
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
choose do |menu|
|
|
87
|
+
menu.prompt = 'Wybierz podkategorię: '
|
|
88
|
+
|
|
89
|
+
entry.category.children.each do |child|
|
|
90
|
+
menu.choice(child.name) do
|
|
91
|
+
entry.sub_category = child
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def get_amount(entry)
|
|
98
|
+
entry.amount = eval ask('Kwota: ')
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def get_tags(entry)
|
|
102
|
+
entry.tags = ask('Tagi: ')
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def get_note(entry)
|
|
106
|
+
entry.note = ask('Opis: ')
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
class Ifin24::Commands::ListEntries < Ifin24::Commands::Base
|
|
4
|
+
|
|
5
|
+
def execute
|
|
6
|
+
current_page = 1
|
|
7
|
+
list, pages = @client.fetch_entries(current_page)
|
|
8
|
+
print_entries(list)
|
|
9
|
+
|
|
10
|
+
catch :exit do
|
|
11
|
+
loop do
|
|
12
|
+
choose do |menu|
|
|
13
|
+
menu.index = :letter
|
|
14
|
+
menu.index_suffix = ") "
|
|
15
|
+
|
|
16
|
+
menu.choice("Poprzednia strona") do
|
|
17
|
+
current_page -= 1 if current_page > 1
|
|
18
|
+
|
|
19
|
+
list, pages = @client.fetch_entries(current_page)
|
|
20
|
+
print_entries(list)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
menu.choice("Następna strona") do
|
|
24
|
+
current_page += 1 if current_page < pages
|
|
25
|
+
|
|
26
|
+
list, pages = @client.fetch_entries(current_page)
|
|
27
|
+
print_entries(list)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
menu.choice("Powrót do głównego menu") { throw :exit }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def print_entries(list)
|
|
39
|
+
print_list(list, :date, :title, :sub_category, :tags, :amount)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
|
|
3
|
+
class Ifin24::Configuration
|
|
4
|
+
include Singleton
|
|
5
|
+
|
|
6
|
+
attr_reader :config
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@config = {}
|
|
10
|
+
|
|
11
|
+
config_file_name = File.join(ENV['HOME'], '.ifin24-client', 'config.yml')
|
|
12
|
+
if File.exist?(config_file_name)
|
|
13
|
+
@config = YAML.load_file(config_file_name) rescue {}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def [](index)
|
|
18
|
+
@config[index]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
class Ifin24::Console
|
|
4
|
+
|
|
5
|
+
def initialize(client)
|
|
6
|
+
@client = client
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def main_menu
|
|
10
|
+
catch :exit do
|
|
11
|
+
loop do
|
|
12
|
+
choose do |menu|
|
|
13
|
+
menu.index = :letter
|
|
14
|
+
menu.index_suffix = ") "
|
|
15
|
+
|
|
16
|
+
menu.choice("Dodaj wydatek") { add_expense }
|
|
17
|
+
menu.choice("Lista kont") { list_accounts }
|
|
18
|
+
menu.choice("Lista ostatnich transakcji") { list_entries }
|
|
19
|
+
|
|
20
|
+
menu.choice("Koniec") { throw :exit }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def add_expense
|
|
27
|
+
execute_command(Ifin24::Commands::AddExpense)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def list_accounts
|
|
31
|
+
execute_command(Ifin24::Commands::ListAccounts)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def list_entries
|
|
35
|
+
execute_command(Ifin24::Commands::ListEntries)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def execute_command(command)
|
|
41
|
+
command.new(@client).execute
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Ifin24::Helpers
|
|
2
|
+
module Printer
|
|
3
|
+
|
|
4
|
+
def print_list(items, *fields)
|
|
5
|
+
# find max length for each field; start with the field names themselves
|
|
6
|
+
fields = items.first.class.column_names unless fields.any?
|
|
7
|
+
max_len = Hash[*fields.map { |f| [f, f.to_s.length] }.flatten]
|
|
8
|
+
items.each do |item|
|
|
9
|
+
fields.each do |field|
|
|
10
|
+
len = item.send(field).to_s.length
|
|
11
|
+
max_len[field] = len if len > max_len[field]
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
border = '+-' + fields.map { |f| '-' * max_len[f] }.join('-+-') + '-+'
|
|
16
|
+
title_row = '| ' + fields.map { |f| sprintf("%-#{max_len[f]}s", f.to_s) }.join(' | ') + ' |'
|
|
17
|
+
|
|
18
|
+
puts border
|
|
19
|
+
puts title_row
|
|
20
|
+
puts border
|
|
21
|
+
|
|
22
|
+
items.each do |item|
|
|
23
|
+
row = '| ' + fields.map { |f| sprintf("%-#{max_len[f]}s", item.send(f)) }.join(' | ') + ' |'
|
|
24
|
+
puts row
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
puts border
|
|
28
|
+
puts "#{items.length} rows in set\n"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class Ifin24::Models::Entry < Ifin24::Models::Base
|
|
2
|
+
|
|
3
|
+
# TODO Add validations
|
|
4
|
+
attr_accessor :title, :date, :amount, :tags, :note
|
|
5
|
+
attr_accessor :account
|
|
6
|
+
|
|
7
|
+
attr_accessor :category
|
|
8
|
+
attr_accessor :sub_category
|
|
9
|
+
|
|
10
|
+
def category_full_name
|
|
11
|
+
"#{category.name} | #{sub_category.name}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
data/lib/ifin24.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module Ifin24
|
|
2
|
+
|
|
3
|
+
autoload :Client, 'ifin24/client'
|
|
4
|
+
autoload :Commands, 'ifin24/commands'
|
|
5
|
+
autoload :Configuration, 'ifin24/configuration'
|
|
6
|
+
autoload :Console, 'ifin24/console'
|
|
7
|
+
autoload :Helpers, 'ifin24/helpers'
|
|
8
|
+
autoload :Models, 'ifin24/models'
|
|
9
|
+
|
|
10
|
+
end
|
|
11
|
+
|
data/spec/spec.opts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ifin24-client
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 27
|
|
5
|
+
prerelease: false
|
|
6
|
+
segments:
|
|
7
|
+
- 0
|
|
8
|
+
- 1
|
|
9
|
+
- 0
|
|
10
|
+
version: 0.1.0
|
|
11
|
+
platform: ruby
|
|
12
|
+
authors:
|
|
13
|
+
- "\xC5\x81ukasz Bandzarewicz"
|
|
14
|
+
autorequire:
|
|
15
|
+
bindir: bin
|
|
16
|
+
cert_chain: []
|
|
17
|
+
|
|
18
|
+
date: 2010-08-28 00:00:00 +02:00
|
|
19
|
+
default_executable: ifin24
|
|
20
|
+
dependencies:
|
|
21
|
+
- !ruby/object:Gem::Dependency
|
|
22
|
+
name: rspec
|
|
23
|
+
prerelease: false
|
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
hash: 13
|
|
30
|
+
segments:
|
|
31
|
+
- 1
|
|
32
|
+
- 2
|
|
33
|
+
- 9
|
|
34
|
+
version: 1.2.9
|
|
35
|
+
type: :development
|
|
36
|
+
version_requirements: *id001
|
|
37
|
+
- !ruby/object:Gem::Dependency
|
|
38
|
+
name: mechanize
|
|
39
|
+
prerelease: false
|
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ">="
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
hash: 3
|
|
46
|
+
segments:
|
|
47
|
+
- 0
|
|
48
|
+
version: "0"
|
|
49
|
+
type: :runtime
|
|
50
|
+
version_requirements: *id002
|
|
51
|
+
- !ruby/object:Gem::Dependency
|
|
52
|
+
name: highline
|
|
53
|
+
prerelease: false
|
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
|
55
|
+
none: false
|
|
56
|
+
requirements:
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
hash: 3
|
|
60
|
+
segments:
|
|
61
|
+
- 0
|
|
62
|
+
version: "0"
|
|
63
|
+
type: :runtime
|
|
64
|
+
version_requirements: *id003
|
|
65
|
+
description: Console for iFIN24
|
|
66
|
+
email: lucassus@gmail.com
|
|
67
|
+
executables:
|
|
68
|
+
- ifin24
|
|
69
|
+
extensions: []
|
|
70
|
+
|
|
71
|
+
extra_rdoc_files:
|
|
72
|
+
- LICENSE
|
|
73
|
+
- README
|
|
74
|
+
- README.rdoc
|
|
75
|
+
files:
|
|
76
|
+
- .document
|
|
77
|
+
- .gitignore
|
|
78
|
+
- LICENSE
|
|
79
|
+
- README
|
|
80
|
+
- README.rdoc
|
|
81
|
+
- Rakefile
|
|
82
|
+
- VERSION
|
|
83
|
+
- bin/ifin24
|
|
84
|
+
- config.yml.example
|
|
85
|
+
- lib/ifin24.rb
|
|
86
|
+
- lib/ifin24/client.rb
|
|
87
|
+
- lib/ifin24/commands.rb
|
|
88
|
+
- lib/ifin24/commands/add_expense.rb
|
|
89
|
+
- lib/ifin24/commands/base.rb
|
|
90
|
+
- lib/ifin24/commands/list_accounts.rb
|
|
91
|
+
- lib/ifin24/commands/list_entries.rb
|
|
92
|
+
- lib/ifin24/configuration.rb
|
|
93
|
+
- lib/ifin24/console.rb
|
|
94
|
+
- lib/ifin24/helpers.rb
|
|
95
|
+
- lib/ifin24/helpers/printer.rb
|
|
96
|
+
- lib/ifin24/models.rb
|
|
97
|
+
- lib/ifin24/models/account.rb
|
|
98
|
+
- lib/ifin24/models/base.rb
|
|
99
|
+
- lib/ifin24/models/category.rb
|
|
100
|
+
- lib/ifin24/models/entry.rb
|
|
101
|
+
- spec/ifin24-client_spec.rb
|
|
102
|
+
- spec/spec.opts
|
|
103
|
+
- spec/spec_helper.rb
|
|
104
|
+
has_rdoc: true
|
|
105
|
+
homepage: http://github.com/lucassus/ifin24-client
|
|
106
|
+
licenses: []
|
|
107
|
+
|
|
108
|
+
post_install_message:
|
|
109
|
+
rdoc_options:
|
|
110
|
+
- --charset=UTF-8
|
|
111
|
+
require_paths:
|
|
112
|
+
- lib
|
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
114
|
+
none: false
|
|
115
|
+
requirements:
|
|
116
|
+
- - ">="
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
hash: 3
|
|
119
|
+
segments:
|
|
120
|
+
- 0
|
|
121
|
+
version: "0"
|
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
|
+
none: false
|
|
124
|
+
requirements:
|
|
125
|
+
- - ">="
|
|
126
|
+
- !ruby/object:Gem::Version
|
|
127
|
+
hash: 3
|
|
128
|
+
segments:
|
|
129
|
+
- 0
|
|
130
|
+
version: "0"
|
|
131
|
+
requirements: []
|
|
132
|
+
|
|
133
|
+
rubyforge_project:
|
|
134
|
+
rubygems_version: 1.3.7
|
|
135
|
+
signing_key:
|
|
136
|
+
specification_version: 3
|
|
137
|
+
summary: Console for iFIN24
|
|
138
|
+
test_files:
|
|
139
|
+
- spec/ifin24-client_spec.rb
|
|
140
|
+
- spec/spec_helper.rb
|