billtrap 0.0.2
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/.gitignore +21 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +218 -0
- data/Rakefile +21 -0
- data/billtrap.gemspec +35 -0
- data/bin/bt +12 -0
- data/bin/dev_b +6 -0
- data/lib/billtrap.rb +56 -0
- data/lib/billtrap/adapters.rb +12 -0
- data/lib/billtrap/adapters/ooffice.rb +27 -0
- data/lib/billtrap/cli.rb +73 -0
- data/lib/billtrap/cmd/client.rb +50 -0
- data/lib/billtrap/cmd/configure.rb +8 -0
- data/lib/billtrap/cmd/entry.rb +45 -0
- data/lib/billtrap/cmd/export.rb +32 -0
- data/lib/billtrap/cmd/import.rb +47 -0
- data/lib/billtrap/cmd/in.rb +16 -0
- data/lib/billtrap/cmd/new.rb +28 -0
- data/lib/billtrap/cmd/payment.rb +45 -0
- data/lib/billtrap/cmd/set.rb +46 -0
- data/lib/billtrap/cmd/show.rb +87 -0
- data/lib/billtrap/cmd/usage.rb +80 -0
- data/lib/billtrap/config.rb +68 -0
- data/lib/billtrap/helpers.rb +17 -0
- data/lib/billtrap/models.rb +239 -0
- data/lib/billtrap/version.rb +3 -0
- data/lib/serenity/LICENSE +22 -0
- data/lib/serenity/serenity.rb +9 -0
- data/lib/serenity/serenity/debug.rb +19 -0
- data/lib/serenity/serenity/escape_xml.rb +18 -0
- data/lib/serenity/serenity/generator.rb +18 -0
- data/lib/serenity/serenity/line.rb +68 -0
- data/lib/serenity/serenity/node_type.rb +7 -0
- data/lib/serenity/serenity/odteruby.rb +90 -0
- data/lib/serenity/serenity/template.rb +31 -0
- data/lib/serenity/serenity/xml_reader.rb +31 -0
- data/migrations/001_base.rb +48 -0
- data/spec/billtrap_spec.rb +283 -0
- metadata +285 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Oliver Guenther
|
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,218 @@
|
|
1
|
+
# Billtrap
|
2
|
+
|
3
|
+
|
4
|
+
Billtrap is a command line invoice management tool in ruby.
|
5
|
+
It allows creation and monitoring of invoices and exporting data using template formatters.
|
6
|
+
|
7
|
+
Billtrap is based on the time tracking tool [Timetrap](https://github.com/samg/timetrap) by Sam Goldstein, and allows importing time entries from Timetrap into invoices.
|
8
|
+
However, Billtrap can be used to create invoices manually without data from Timetrap.
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
To install, use rubygems:
|
14
|
+
|
15
|
+
gem install billtrap
|
16
|
+
|
17
|
+
This will place the Billtrap executable `bt` in your path.
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
If you call Billtrap without any argument (or using --help) will
|
22
|
+
display usage information:
|
23
|
+
|
24
|
+
$ bt --help
|
25
|
+
|
26
|
+
### Configuring BillTrap
|
27
|
+
|
28
|
+
Use `bt configure` to write a config file to `HOME/.billtrap/billtrap.yml` (Override by setting BILLTRAP_HOME in env)
|
29
|
+
|
30
|
+
The following options are supported
|
31
|
+
|
32
|
+
- **database**: Sequel Databsae identifier, defaults to `sqlite://<BILLTRAP_HOME>/.billtrap.db`
|
33
|
+
- **timetrap_database**: Timetrap database, used to import Entries
|
34
|
+
- **round_in_seconds** => 900,
|
35
|
+
- **currency**: Currency to use (see [RubyMoney.format](http://rubydoc.info/gems/money/Money/Formatting:format) for options)
|
36
|
+
- **default_rate**: Default rate in the above currency
|
37
|
+
- **invoice_number_format**: Invoice numbering format. Expands [Date.strftime directives](http://ruby-doc.org/stdlib-2.0/libdoc/date/rdoc/Date.html#method-i-strftime) and `%{invoice_id}`, `%{client_id}` upon export of the invoice (e.g., `%Y%m%d_%{invoice_id}`)
|
38
|
+
- **currency_format**: Money formatter, see <http://rubydoc.info/gems/money/Money/Formatting> for output options
|
39
|
+
- **date_format**: date format
|
40
|
+
- **billtrap_archive**: Output path for exported invoices
|
41
|
+
- **serenity_template**: OOffice adapter: Path to invoice template
|
42
|
+
|
43
|
+
### Adding invoices
|
44
|
+
|
45
|
+
Add a **new** invoice with the title *Some important project* to Billtrap and activate it:
|
46
|
+
|
47
|
+
$ bt new --name 'Some important project'
|
48
|
+
|
49
|
+
You can also specify a certain date (using [Chronic keywords](https://github.com/mojombo/chronic)) to use with the invoice:
|
50
|
+
|
51
|
+
# Adds an unnamed invoice, dated yesterday
|
52
|
+
$ bt new --date yesterday
|
53
|
+
|
54
|
+
### Switching between invoices
|
55
|
+
|
56
|
+
To display the current set of open invoices, use `bt show`.
|
57
|
+
|
58
|
+
$ bt show
|
59
|
+
Showing open invoices
|
60
|
+
ID Name Client Created Payments / Total
|
61
|
+
1 Some important project - 2013-04-12 0,00 EUR / 0,00 EUR
|
62
|
+
>>2 - - 2013-04-11 0.00 USD / 0.00 USD
|
63
|
+
|
64
|
+
Billtrap manages a set of invoices, and allows you to focus on one invoice at a time.
|
65
|
+
The "**>>**" marks the current active invoice (ID 2), which we just added with `--date yesterday`.
|
66
|
+
|
67
|
+
To switch between invoices, use the `in` comand with the ID of the invoice to switch to.
|
68
|
+
Now, to switch to the 'Some important project' invoice, enter:
|
69
|
+
|
70
|
+
$ bt in 1
|
71
|
+
Activating invoice #1
|
72
|
+
|
73
|
+
The active invoice is persisted between calls, i.e., you always
|
74
|
+
edit the latest invoice until `bt in` or `bt new` is called.
|
75
|
+
|
76
|
+
### Editing the active invoice
|
77
|
+
Let's add some entries to the important project by executing
|
78
|
+
`bt entry --add`. This will read the entry from STDIN.
|
79
|
+
|
80
|
+
$ bt entry --add
|
81
|
+
Entry title: Programming
|
82
|
+
Entry date (YYYY-MM-DD): 2013-04-10
|
83
|
+
Displayed unit (Defaults to 'h' for hours):
|
84
|
+
Quantity (Numeric): 2.5
|
85
|
+
Price in USD per unit (Numeric): 20
|
86
|
+
Optional Notes: (Multiline input, type Ctrl-D or insert END and return to exit)
|
87
|
+
^D
|
88
|
+
|
89
|
+
Added entry (#1) to current invoice (ID 1)
|
90
|
+
|
91
|
+
Lets check the values we entered with `bt show --detail 1`,
|
92
|
+
which displays details for the invoice with ID 1.
|
93
|
+
|
94
|
+
$ bt show --detail 1
|
95
|
+
|
96
|
+
Invoice: Some important project (#1)
|
97
|
+
Created on: 2013-04-13
|
98
|
+
----------------------
|
99
|
+
Invoice entries
|
100
|
+
Title Date Quantity Price Notes
|
101
|
+
Programming 2013-04-10 2.5h 50.00 USD
|
102
|
+
|
103
|
+
### Importing data from Timetrap
|
104
|
+
If you manage your time using Timetrap, you can use the `import` command to import entries to the current invoice.
|
105
|
+
|
106
|
+
Assume you have a sheet called *test* with three entries.
|
107
|
+
|
108
|
+
$ t display test
|
109
|
+
Day Start End Duration Notes
|
110
|
+
Sat Oct 29, 2011 22:42:36 - 23:13:02 0:30:26 Foo
|
111
|
+
0:30:26
|
112
|
+
Sat Nov 17, 2012 23:13:57 - 23:14:07 24:00:10 Bar
|
113
|
+
24:00:10
|
114
|
+
Sun Nov 18, 2012 22:26:00 - 22:31:20 0:05:20 Moo
|
115
|
+
|
116
|
+
You can import the whole sheet into BillTrap using the following command:
|
117
|
+
|
118
|
+
$ dbt impoort --sheet test
|
119
|
+
|
120
|
+
Imported 0.51 hours from sheet test as entry #2
|
121
|
+
Imported 0.09 hours from sheet test as entry #3
|
122
|
+
Imported 24.0 hours from sheet test as entry #4
|
123
|
+
|
124
|
+
You could also import single IDs into the current invoice:
|
125
|
+
|
126
|
+
$ dbt import --entry 1 2
|
127
|
+
Imported 0.51 hours from sheet test as entry #5
|
128
|
+
Imported 0.09 hours from sheet test as entry #6
|
129
|
+
|
130
|
+
|
131
|
+
If you wish to clear all entries *prior* to the import,
|
132
|
+
use the `--clear` flag:
|
133
|
+
|
134
|
+
$ dbt import --entry 1 2
|
135
|
+
Imported 0.51 hours from sheet test as entry #1
|
136
|
+
Imported 0.09 hours from sheet test as entry #2
|
137
|
+
|
138
|
+
**Beware:** Using the `--clear` flag does not ask for confirmation prior to deleting all entries of the current invoice.
|
139
|
+
|
140
|
+
|
141
|
+
### Setting a client
|
142
|
+
|
143
|
+
BillTrap allows you to add and manage clients.
|
144
|
+
**Note**: This feature is still rudimentary and subject to change.
|
145
|
+
|
146
|
+
Use `bt client --add` to add a client from STDIN:
|
147
|
+
|
148
|
+
$ bt client --add
|
149
|
+
First name: John
|
150
|
+
Surname: Doe
|
151
|
+
Company: Doemasters Inc.
|
152
|
+
Address: (Multiline input, type Ctrl-D or insert END and return to exit)
|
153
|
+
Somestreet 12
|
154
|
+
12345 Sometown^D
|
155
|
+
Mail: mail@example.com
|
156
|
+
Hourly rate: 25
|
157
|
+
Use non-standard Currency? [Leave empty for USD]: EUR
|
158
|
+
|
159
|
+
Client John Doe was created with id 1
|
160
|
+
|
161
|
+
Let's set *John Doe* as the client for our important project.
|
162
|
+
|
163
|
+
# Equivalent to 'bt set client 1'
|
164
|
+
$ bt set client Doe
|
165
|
+
|
166
|
+
SET client to John Doe (#1)
|
167
|
+
|
168
|
+
**Note**: The client currency setting overrides BillTrap's default setting, thus the currency for all entries of invoice #1
|
169
|
+
have changed to EUR.
|
170
|
+
|
171
|
+
### Exporting invoices
|
172
|
+
Let's review our changes to the Invoice #1:
|
173
|
+
|
174
|
+
$ bt show
|
175
|
+
Showing open invoices
|
176
|
+
ID Name Client Created Payments / Total
|
177
|
+
>>1 Some important project John Doe 2013-04-13 0,00 EUR / 50,00 EUR
|
178
|
+
2 - - 2013-04-12 0.00 USD / 0.00 USD
|
179
|
+
|
180
|
+
To export the invoice:
|
181
|
+
|
182
|
+
$ bt export
|
183
|
+
|
184
|
+
Generated invoice has been output to: /Users/oliver/Documents/billtrap/invoices/2013/4/13/1.odt
|
185
|
+
|
186
|
+
Currently, the only working adapter uses the [serenity gem](https://github.com/kremso/serenity) to populate a Open/LibreOffice template of your choosing and renders an ODT.
|
187
|
+
|
188
|
+
**Note**: Have a look at the config (see *configuring BillTrap*) to change invoice numbering, output paths et cetera.
|
189
|
+
|
190
|
+
I'm working on creating more adapters. If you want to participate in the discussion, I suggest opening an issue on the [Github tracker](http://github.com/oliverguenther/Billtrap/issues).
|
191
|
+
|
192
|
+
### Abbreviating commands
|
193
|
+
All commands and their paremeters can be abbreviated.
|
194
|
+
For example, instead of `bt new --date yesterday`, you could also enter with same result:
|
195
|
+
|
196
|
+
$ bt n -d yesterday
|
197
|
+
|
198
|
+
BillTrap warns you about ambiguous command abbreviations, e.g.,
|
199
|
+
|
200
|
+
$ bt s
|
201
|
+
Error: Ambiguous command 's'
|
202
|
+
Matching commands are: set, show
|
203
|
+
|
204
|
+
## Special Thanks
|
205
|
+
|
206
|
+
I'd like to thank Sam Goldstein for his work on Timetrap, which motivated me to improve on my time management and to start this project.
|
207
|
+
|
208
|
+
Billtrap intentionally borrows heavily from Timetrap, which is available at <https://github.com/samg/timetrap>.
|
209
|
+
|
210
|
+
--------
|
211
|
+
|
212
|
+
## Bugs and Feature Requests
|
213
|
+
|
214
|
+
Billtrap is still under heavy development.
|
215
|
+
|
216
|
+
If you have feature requests or found a bug, please file an issue on the Github tracker:
|
217
|
+
|
218
|
+
<http://github.com/oliverguenther/Billtrap/issues>
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rake'
|
3
|
+
require 'rdoc/task'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new
|
6
|
+
|
7
|
+
desc 'Default: run spec.'
|
8
|
+
task :default => :spec
|
9
|
+
|
10
|
+
lib = File.expand_path('../lib/', __FILE__)
|
11
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
12
|
+
require 'billtrap/version'
|
13
|
+
Rake::RDocTask.new do |rdoc|
|
14
|
+
version = BillTrap::VERSION
|
15
|
+
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = "BillTrap #{version}"
|
18
|
+
rdoc.rdoc_files.include('README*')
|
19
|
+
rdoc.rdoc_files.include('lib/billtrap/**/*.rb')
|
20
|
+
rdoc.rdoc_files.include('lib/billtrap.rb')
|
21
|
+
end
|
data/billtrap.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib/', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'billtrap/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "billtrap"
|
8
|
+
spec.version = BillTrap::VERSION
|
9
|
+
spec.authors = ["Oliver Günther"]
|
10
|
+
spec.email = ["mail@oliverguenther.de"]
|
11
|
+
spec.summary = "Command line invoice management."
|
12
|
+
spec.description = "This gem provides invoice management with imported time slices from the Timetrap gem."
|
13
|
+
spec.homepage = "http://github.com/oliverguenther/billtrap/"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.bindir = "bin"
|
18
|
+
spec.executables = ['bt']
|
19
|
+
spec.test_files = ['spec/']
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_dependency "sequel", ">= 3.9.0"
|
23
|
+
spec.add_dependency "sqlite3", ">= 1.3.3"
|
24
|
+
spec.add_dependency "chronic", ">= 0.6.4"
|
25
|
+
spec.add_dependency "json", ">= 1.4.6"
|
26
|
+
spec.add_dependency "trollop", ">= 2.0"
|
27
|
+
spec.add_dependency "money", ">= 5.0"
|
28
|
+
spec.add_dependency "timetrap", ">= 1.5"
|
29
|
+
spec.add_dependency "rubyzip"
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
32
|
+
spec.add_development_dependency "rake"
|
33
|
+
spec.add_development_dependency 'rspec', '~> 2'
|
34
|
+
spec.add_development_dependency 'fakefs'
|
35
|
+
end
|
data/bin/bt
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
begin
|
3
|
+
require 'billtrap'
|
4
|
+
rescue LoadError
|
5
|
+
if File.symlink? __FILE__
|
6
|
+
require File.dirname(File.readlink(__FILE__)) + '/../lib/billtrap'
|
7
|
+
else
|
8
|
+
require File.dirname(__FILE__) + '/../lib/billtrap'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
BillTrap::CLI.args = Array.new(ARGV)
|
12
|
+
BillTrap::CLI.invoke
|
data/bin/dev_b
ADDED
data/lib/billtrap.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "rubygems"
|
3
|
+
require 'sequel'
|
4
|
+
# Load migrations
|
5
|
+
Sequel.extension :migration, :core_extensions
|
6
|
+
# Load inflector (String.classify)
|
7
|
+
Sequel.extension :inflector
|
8
|
+
|
9
|
+
require 'chronic'
|
10
|
+
require 'money'
|
11
|
+
require 'yaml'
|
12
|
+
require 'erb'
|
13
|
+
require 'trollop'
|
14
|
+
require 'pathname'
|
15
|
+
|
16
|
+
# require serenity 0.2.2
|
17
|
+
require File.join(File.dirname(__FILE__), 'serenity', 'serenity')
|
18
|
+
|
19
|
+
# Set billtrap home
|
20
|
+
BILLTRAP_HOME = ENV['BILLTRAP_HOME'] || File.join(ENV['HOME'], '.billtrap')
|
21
|
+
|
22
|
+
|
23
|
+
BILLTRAP_PATH = Pathname.new(__FILE__).realpath.dirname.to_s
|
24
|
+
$:.unshift(BILLTRAP_PATH + '/billtrap')
|
25
|
+
require 'version'
|
26
|
+
require 'config'
|
27
|
+
require 'helpers'
|
28
|
+
require 'cli'
|
29
|
+
require 'adapters'
|
30
|
+
module BillTrap
|
31
|
+
# Force encoding to utf-8
|
32
|
+
Encoding.default_internal= Encoding::UTF_8
|
33
|
+
Sequel::Model.plugin :force_encoding, Encoding::UTF_8
|
34
|
+
|
35
|
+
|
36
|
+
unless File.directory? BILLTRAP_HOME
|
37
|
+
FileUtils.mkdir BILLTRAP_HOME
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# We need to inclue spec testing here, as RSpec doesn't allow
|
42
|
+
# stubs in around blocks, but we need around blocks for Sequel transactions
|
43
|
+
DB_NAME = defined?(SPEC_RUNNING) ? "sqlite://test.db" : BillTrap::Config['database']
|
44
|
+
DB = Sequel.connect(DB_NAME)
|
45
|
+
|
46
|
+
# Update to latest migration, if necessary
|
47
|
+
unless (Sequel::Migrator.is_current? DB, File.dirname(__FILE__) + '/../migrations/')
|
48
|
+
Sequel::Migrator.run(DB, File.dirname(__FILE__) + '/../migrations/')
|
49
|
+
end
|
50
|
+
|
51
|
+
# Open TT timetrap_databasee
|
52
|
+
TT_DB_NAME = defined?(SPEC_RUNNING) ? "sqlite://testTT.db" : BillTrap::Config['timetrap_database']
|
53
|
+
TT_DB = Sequel.connect(TT_DB_NAME)
|
54
|
+
|
55
|
+
end
|
56
|
+
require 'models'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module BillTrap
|
2
|
+
module Adapters
|
3
|
+
class Ooffice
|
4
|
+
# uses Serenity for ODT output
|
5
|
+
include ::Serenity::Generator
|
6
|
+
include BillTrap::Helpers
|
7
|
+
attr_reader :id
|
8
|
+
|
9
|
+
def initialize attributes
|
10
|
+
attributes.each do |key, val|
|
11
|
+
# slurp attributes into instances variables
|
12
|
+
instance_variable_set("@#{key}", val)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate
|
17
|
+
date = @invoice[:created]
|
18
|
+
output_path = "#{Config['billtrap_archive']}/#{date.year}/#{date.month}/#{date.mday}"
|
19
|
+
FileUtils.mkpath(output_path)
|
20
|
+
|
21
|
+
render_odt Config['serenity_template'], "#{output_path}/#{@invoice.id}.odt"
|
22
|
+
puts "Generated invoice has been output to: #{output_path}/#{@invoice.id}.odt"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|