badbill 0.0.1
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/CONTRIBUTING.md +34 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +21 -0
- data/README.md +92 -0
- data/Rakefile +85 -0
- data/lib/badbill/base_resource.rb +118 -0
- data/lib/badbill/client.rb +32 -0
- data/lib/badbill/forward_methods.rb +30 -0
- data/lib/badbill/invoice.rb +106 -0
- data/lib/badbill/resource.rb +34 -0
- data/lib/badbill.rb +152 -0
- data/spec/badbill/base_resource_spec.rb +12 -0
- data/spec/badbill/client_spec.rb +98 -0
- data/spec/badbill/invoice_spec.rb +228 -0
- data/spec/badbill_spec.rb +89 -0
- data/spec/helper.rb +24 -0
- metadata +161 -0
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# How to contribute
|
|
2
|
+
|
|
3
|
+
This API client is implemented for my own use, so I will only work on the parts I need for myself.
|
|
4
|
+
Additional improvements, comments on code and implementation and bug fixes are very welcome.
|
|
5
|
+
|
|
6
|
+
## Report bugs, improvements or feature requests
|
|
7
|
+
|
|
8
|
+
* Submit a ticket for your issue, assuming one does not already exist.
|
|
9
|
+
* Clearly describe the issue including steps to reproduce when it is a bug.
|
|
10
|
+
* Make sure you fill in the earliest version that you know has the issue.
|
|
11
|
+
|
|
12
|
+
## Making Changes
|
|
13
|
+
|
|
14
|
+
* Fork the repository on GitHub.
|
|
15
|
+
* Create a topic branch from where you want to base your work.
|
|
16
|
+
* Make commits of logical units.
|
|
17
|
+
* Check for unnecessary whitespace with `git diff --check` before committing.
|
|
18
|
+
* Make sure your commit messages are in the proper format.
|
|
19
|
+
* Run _all_ the tests to assure nothing else was accidentally broken.
|
|
20
|
+
* Include tests for new features and bug fixes (if you don't know how to do that, feel free to ask, I will help).
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## Submitting Changes
|
|
24
|
+
|
|
25
|
+
* Push your changes to a topic branch in your fork of the repository.
|
|
26
|
+
* Submit a pull request to the repository.
|
|
27
|
+
* Wait for my response.
|
|
28
|
+
|
|
29
|
+
# Contact
|
|
30
|
+
|
|
31
|
+
Feel free to contact me with any issues or questions.
|
|
32
|
+
|
|
33
|
+
* Mail: badboy@archlinux.us
|
|
34
|
+
* Twitter: [@badboy_](https://twitter.com/badboy_)
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
badbill (0.0.1)
|
|
5
|
+
faraday
|
|
6
|
+
faraday_middleware
|
|
7
|
+
hashie
|
|
8
|
+
yajl-ruby
|
|
9
|
+
|
|
10
|
+
GEM
|
|
11
|
+
remote: https://rubygems.org/
|
|
12
|
+
specs:
|
|
13
|
+
addressable (2.3.2)
|
|
14
|
+
crack (0.3.1)
|
|
15
|
+
diff-lcs (1.1.3)
|
|
16
|
+
faraday (0.8.4)
|
|
17
|
+
multipart-post (~> 1.1)
|
|
18
|
+
faraday_middleware (0.8.8)
|
|
19
|
+
faraday (>= 0.7.4, < 0.9)
|
|
20
|
+
hashie (1.2.0)
|
|
21
|
+
multi_json (1.3.6)
|
|
22
|
+
multipart-post (1.1.5)
|
|
23
|
+
redcarpet (2.1.1)
|
|
24
|
+
rspec (2.11.0)
|
|
25
|
+
rspec-core (~> 2.11.0)
|
|
26
|
+
rspec-expectations (~> 2.11.0)
|
|
27
|
+
rspec-mocks (~> 2.11.0)
|
|
28
|
+
rspec-core (2.11.1)
|
|
29
|
+
rspec-expectations (2.11.3)
|
|
30
|
+
diff-lcs (~> 1.1.3)
|
|
31
|
+
rspec-mocks (2.11.3)
|
|
32
|
+
simplecov (0.6.4)
|
|
33
|
+
multi_json (~> 1.0)
|
|
34
|
+
simplecov-html (~> 0.5.3)
|
|
35
|
+
simplecov-html (0.5.3)
|
|
36
|
+
webmock (1.8.10)
|
|
37
|
+
addressable (>= 2.2.7)
|
|
38
|
+
crack (>= 0.1.7)
|
|
39
|
+
yajl-ruby (1.1.0)
|
|
40
|
+
yard (0.8.2.1)
|
|
41
|
+
|
|
42
|
+
PLATFORMS
|
|
43
|
+
ruby
|
|
44
|
+
|
|
45
|
+
DEPENDENCIES
|
|
46
|
+
badbill!
|
|
47
|
+
redcarpet
|
|
48
|
+
rspec
|
|
49
|
+
simplecov
|
|
50
|
+
webmock
|
|
51
|
+
yard
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Copyright (c) 2012 Jan-Erik Rediger <http://fnordig.de/about/>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person ob-
|
|
4
|
+
taining a copy of this software and associated documentation
|
|
5
|
+
files (the "Software"), to deal in the Software without restric-
|
|
6
|
+
tion, including without limitation the rights to use, copy, modi-
|
|
7
|
+
fy, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
the Software, and to permit persons to whom the Software is fur-
|
|
9
|
+
nished to do so, subject to 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
|
|
16
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONIN-
|
|
17
|
+
FRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
19
|
+
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
BadBill - Billomat API Client
|
|
2
|
+
===================
|
|
3
|
+
|
|
4
|
+
Simple but working API client for the [Billomat API][apidocu].
|
|
5
|
+
|
|
6
|
+
See the [API documentation][apidocu] for full documentation of all resources.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
* Fast and easy access to all resources the API provides
|
|
11
|
+
(not all resources are Ruby classes, yet)
|
|
12
|
+
* Full documentation.
|
|
13
|
+
* Test coverage as best as I can.
|
|
14
|
+
* Production-ready (it's for a job project).
|
|
15
|
+
|
|
16
|
+
## What's working right now
|
|
17
|
+
|
|
18
|
+
The basic BadBill class allows access to all resources. It includes no syntactic sugar to work with, instead it just returns the data as a hash. This works for basic usage.
|
|
19
|
+
|
|
20
|
+
The following resources are currently implemented as its own class:
|
|
21
|
+
|
|
22
|
+
* [clients](http://www.billomat.com/en/api/invoices/) (`BadBill::Client`)
|
|
23
|
+
* [invoices](http://www.billomat.com/en/api/invoices/) (`BadBill::Invoices`)
|
|
24
|
+
|
|
25
|
+
These are the two I need right now.
|
|
26
|
+
Implementing new resources is easy. Pull Requests for others are welcome.
|
|
27
|
+
|
|
28
|
+
## Requirements
|
|
29
|
+
|
|
30
|
+
* [yajl-ruby](https://github.com/brianmario/yajl-ruby)
|
|
31
|
+
* [faraday](https://github.com/technoweenie/faraday)
|
|
32
|
+
* [faraday_middleware](https://github.com/pengwynn/faraday_middleware)
|
|
33
|
+
* [hashie](https://github.com/intridea/hashie)
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
BadBill is just a `gem install badbill` away. Get an API key for the Billomat API on your profile page.
|
|
38
|
+
|
|
39
|
+
## Examples
|
|
40
|
+
|
|
41
|
+
### Basic Usage
|
|
42
|
+
|
|
43
|
+
bill = BadBill.new "billo", "18e40e14"
|
|
44
|
+
# => #<BadBill:0x00000001319d30 ...>
|
|
45
|
+
bill.get 'settings'
|
|
46
|
+
# => {"settings"=>
|
|
47
|
+
# {"invoice_intro"=>"",
|
|
48
|
+
# "invoice_note"=>"",
|
|
49
|
+
# ...}}
|
|
50
|
+
bill.put 'settings', settings: { invoice_intro: "Intro" }
|
|
51
|
+
# => {"settings"=>
|
|
52
|
+
# {"invoice_intro"=>"Intro",
|
|
53
|
+
# "invoice_note"=>"",
|
|
54
|
+
# ...}}
|
|
55
|
+
|
|
56
|
+
### Using defined resource classes
|
|
57
|
+
|
|
58
|
+
BadBill.new "billo", "18e40e14"
|
|
59
|
+
|
|
60
|
+
BadBill::Invoice.all
|
|
61
|
+
# => [#<BadBill::Invoice:0x000000024caf98 @id="1" @data={...}>], ...]
|
|
62
|
+
|
|
63
|
+
invoice = BadBill::Invoice.find(1)
|
|
64
|
+
invoice.pdf
|
|
65
|
+
# => {"id"=>"1",
|
|
66
|
+
# "created"=>"2012-09-17T13:58:42+02:00",
|
|
67
|
+
# "invoice_id"=>"322791",
|
|
68
|
+
# "filename"=>"Invoice 322791.pdf",
|
|
69
|
+
# "mimetype"=>"application/pdf",
|
|
70
|
+
# "filesize"=>"90811",
|
|
71
|
+
# "base64file"=>"JVBERi0xLjM..."}
|
|
72
|
+
invoice.delete
|
|
73
|
+
# => true
|
|
74
|
+
|
|
75
|
+
BadBill::Invoice.create client_id: 1, date: "2012-09-18", note: "Thank you for your order", ...
|
|
76
|
+
|
|
77
|
+
## Documentation
|
|
78
|
+
|
|
79
|
+
Documentation is online at [rubydoc.info](http://rubydoc.info/github/badboy/badbill/master/frames).
|
|
80
|
+
|
|
81
|
+
Generate locale documentation with `rake doc` ([yard](http://yardoc.org/) required).
|
|
82
|
+
Required Parameters and possible values won't be documentated here. See the [API documentation][apidocu] for that.
|
|
83
|
+
|
|
84
|
+
## Contribute
|
|
85
|
+
|
|
86
|
+
See [CONTRIBUTING.md](/badboy/badbill/blob/master/CONTRIBUTING.md) for info.
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
See [LICENSE](/badboy/badbill/blob/master/LICENSE) for info.
|
|
91
|
+
|
|
92
|
+
[apidocu]: http://www.billomat.com/en/api/
|
data/Rakefile
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'rspec/core/rake_task'
|
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
require 'yard'
|
|
8
|
+
YARD::Rake::YardocTask.new do |t|
|
|
9
|
+
t.files = ['lib/**/*.rb']
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
task :default => :spec
|
|
13
|
+
task :doc => :yard
|
|
14
|
+
|
|
15
|
+
## helper functions
|
|
16
|
+
|
|
17
|
+
def name
|
|
18
|
+
@name ||= Dir['*.gemspec'].first.split('.').first
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def version
|
|
22
|
+
line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
|
|
23
|
+
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def gemspec_file
|
|
27
|
+
"#{name}.gemspec"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def gem_file
|
|
31
|
+
"#{name}-#{version}.gem"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def replace_header(head, header_name)
|
|
35
|
+
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc "Open an irb session preloaded with this library"
|
|
39
|
+
task :console do
|
|
40
|
+
sh "irb -rubygems -r ./lib/#{name}.rb"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
## release management tasks
|
|
44
|
+
|
|
45
|
+
desc "Commit, create tag v#{version} and build and push #{gem_file} to Rubygems"
|
|
46
|
+
task :release => :build do
|
|
47
|
+
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
|
48
|
+
sh "git tag v#{version}"
|
|
49
|
+
sh "git push origin"
|
|
50
|
+
sh "git push origin v#{version}"
|
|
51
|
+
sh "gem push pkg/#{gem_file}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
desc "Build #{gem_file} into the pkg directory"
|
|
55
|
+
task :build => :gemspec do
|
|
56
|
+
FileUtils.mkdir_p 'pkg'
|
|
57
|
+
sh "gem build #{gemspec_file}"
|
|
58
|
+
sh "mv #{gem_file} pkg"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
desc "Generate #{gemspec_file}"
|
|
62
|
+
task :gemspec do
|
|
63
|
+
# read spec file and split out manifest section
|
|
64
|
+
spec = File.read(gemspec_file)
|
|
65
|
+
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
|
66
|
+
|
|
67
|
+
# replace name version and date
|
|
68
|
+
replace_header(head, :name)
|
|
69
|
+
replace_header(head, :version)
|
|
70
|
+
|
|
71
|
+
# determine file list from git ls-files
|
|
72
|
+
files = `git ls-files`.
|
|
73
|
+
split("\n").
|
|
74
|
+
sort.
|
|
75
|
+
reject { |file| file =~ /^\./ }.
|
|
76
|
+
reject { |file| file =~ /^(doc|coverage|pkg)/ }.
|
|
77
|
+
map { |file| " ./#{file}" }.
|
|
78
|
+
join("\n")
|
|
79
|
+
|
|
80
|
+
# piece file back together and write
|
|
81
|
+
manifest = " s.files = %w[\n#{files}\n ]\n"
|
|
82
|
+
spec = [head, manifest, tail].join(" # = MANIFEST =\n")
|
|
83
|
+
File.open(gemspec_file, 'w') { |io| io.write(spec) }
|
|
84
|
+
puts "Updated #{gemspec_file}"
|
|
85
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
class BadBill
|
|
4
|
+
class BaseResource
|
|
5
|
+
include BadBill::Resource
|
|
6
|
+
extend BadBill::Resource
|
|
7
|
+
|
|
8
|
+
include BadBill::ForwardMethods
|
|
9
|
+
|
|
10
|
+
# ID of the resource.
|
|
11
|
+
attr_reader :id
|
|
12
|
+
# All data in a Hash.
|
|
13
|
+
attr_accessor :data
|
|
14
|
+
|
|
15
|
+
# Public: Create new resource object.
|
|
16
|
+
#
|
|
17
|
+
# @param [String,Integer] id The ID of the resource.
|
|
18
|
+
# @param [Hashie::Mash] data Resource data.
|
|
19
|
+
#
|
|
20
|
+
# All resources have an ID and data. Methods are proxied to the data object.
|
|
21
|
+
#
|
|
22
|
+
# @return [Resource] A new resource.
|
|
23
|
+
def initialize id, data
|
|
24
|
+
@id = id
|
|
25
|
+
@data = data
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Get all resources of this type.
|
|
29
|
+
#
|
|
30
|
+
# @param [Hash] filter An Hash of filter parameters,
|
|
31
|
+
# see the online documentation for allowed values.
|
|
32
|
+
#
|
|
33
|
+
# @return [Array<Resource>] All found resources.
|
|
34
|
+
def self.all filter={}
|
|
35
|
+
all = get resource_name, filter
|
|
36
|
+
all.__send__(resource_name).__send__(resource_name_singular).map do |res|
|
|
37
|
+
new res.id, res
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Get the resource with the given ID.
|
|
42
|
+
#
|
|
43
|
+
# @param [String,Integer] id ID of the resource.
|
|
44
|
+
#
|
|
45
|
+
# @return [Resource] New resource with id and data set.
|
|
46
|
+
def self.find id
|
|
47
|
+
c = get resource_name, id
|
|
48
|
+
new id, c.__send__(resource_name_singular)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Create a new resource with the given parameters.
|
|
52
|
+
#
|
|
53
|
+
# @param [Hash] params A Hash-like object of data.
|
|
54
|
+
# See the online documentation for allowed values.
|
|
55
|
+
#
|
|
56
|
+
# @return [Resource] New resource with id and data set.
|
|
57
|
+
def self.create params
|
|
58
|
+
res = post(resource_name, {resource_name_singular => params})
|
|
59
|
+
res_data = res.__send__(resource_name_singular)
|
|
60
|
+
new res_data.id, res_data
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Save any changed data.
|
|
64
|
+
#
|
|
65
|
+
# @return [Boolean] True if successfull, false otherwise.
|
|
66
|
+
def save
|
|
67
|
+
@data.id = id
|
|
68
|
+
resp = put resource_name, id, {resource_name_singular => @data}
|
|
69
|
+
!resp
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Delete this resource.
|
|
73
|
+
#
|
|
74
|
+
# @return [Boolean] True if successfull, false otherwise.
|
|
75
|
+
def delete
|
|
76
|
+
# Hack: We can't call #delete here, because we ARE #delete
|
|
77
|
+
resp = call resource_name, id, nil, :delete
|
|
78
|
+
!resp
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Protect overriding of the ID.
|
|
82
|
+
#
|
|
83
|
+
# @raise [NoMethodError] because the ID may not be overwritten.
|
|
84
|
+
def id= *args
|
|
85
|
+
raise NoMethodError, "undefined method `id=' for '#{self.inspect.sub(/ .+/, '>')}`"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def resource_name_singular
|
|
91
|
+
self.class.resource_name_singular
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def resource_name
|
|
95
|
+
self.class.resource_name
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# The singular resource name for use with the API.
|
|
99
|
+
#
|
|
100
|
+
# By default this is just the Class name, but it may be overridden.
|
|
101
|
+
# Make sure to overwrite resource_name, too.
|
|
102
|
+
#
|
|
103
|
+
# @return [String] The singular resource name.
|
|
104
|
+
def self.resource_name_singular
|
|
105
|
+
@resource_name_singular ||= self.name.split(/::/).last.downcase
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# The resource name (plural) for use with the API.
|
|
109
|
+
#
|
|
110
|
+
# By default this is just the `resource_name_singular` with an appended 's'
|
|
111
|
+
# See #resource_name_singular
|
|
112
|
+
#
|
|
113
|
+
# @return [String] The resource name.
|
|
114
|
+
def self.resource_name
|
|
115
|
+
@resource_name ||= "#{resource_name_singular}s"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
class BadBill
|
|
4
|
+
# The clients resource handles all clients.
|
|
5
|
+
#
|
|
6
|
+
# See http://www.billomat.com/en/api/clients/
|
|
7
|
+
class Client < BaseResource
|
|
8
|
+
attr_writer :myself
|
|
9
|
+
|
|
10
|
+
def initialize id, data
|
|
11
|
+
super
|
|
12
|
+
@myself = false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Fetch information about yourself.
|
|
16
|
+
#
|
|
17
|
+
# @return [Client] A new resource.
|
|
18
|
+
def self.myself
|
|
19
|
+
c = get 'clients', 'myself'
|
|
20
|
+
client = new c.client.id, c.client
|
|
21
|
+
client.myself = true
|
|
22
|
+
client
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Indicates wether this resource is yourself or not.
|
|
26
|
+
#
|
|
27
|
+
# @return [Boolean] Wether or not this resource is yourself.
|
|
28
|
+
def myself?
|
|
29
|
+
@myself
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
class BadBill
|
|
4
|
+
# Forward all methods to an underlying object called data.
|
|
5
|
+
#
|
|
6
|
+
# This acts like a proxy object.
|
|
7
|
+
module ForwardMethods
|
|
8
|
+
# Respond to method_missing to send down the line.
|
|
9
|
+
#
|
|
10
|
+
# As Hashie::Mash#method_missing does not respond with true to an
|
|
11
|
+
# assignment request, we only check for the method name without the equal sign.
|
|
12
|
+
def method_missing(method_name, *arguments, &block)
|
|
13
|
+
if data.respond_to?(method_name.to_s.sub(/=$/, ''))
|
|
14
|
+
data.send(method_name, *arguments, &block)
|
|
15
|
+
else
|
|
16
|
+
super
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Proxy respond_to? to the underlying object if needed.
|
|
21
|
+
#
|
|
22
|
+
# If playing with method_missing define respond_to? too.
|
|
23
|
+
# See http://robots.thoughtbot.com/post/28335346416/always-define-respond-to-missing-when-overriding
|
|
24
|
+
#
|
|
25
|
+
# @return [Boolean] True if the class itself or the proxied object responds to the given method.
|
|
26
|
+
def respond_to?(method_name, include_private = false)
|
|
27
|
+
super || data.respond_to?(method_name, include_private)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
|
|
5
|
+
class BadBill
|
|
6
|
+
# The resource handles all invoices.
|
|
7
|
+
#
|
|
8
|
+
# See http://www.billomat.com/en/api/invoices
|
|
9
|
+
class Invoice < BaseResource
|
|
10
|
+
# Get the PDF invoice.
|
|
11
|
+
#
|
|
12
|
+
#
|
|
13
|
+
# @return [Hashie::Mash] Hash containing the ID, filesize, base64file and
|
|
14
|
+
# other parameters.
|
|
15
|
+
# See http://www.billomat.com/en/api/invoices for
|
|
16
|
+
# all parameters.
|
|
17
|
+
def pdf
|
|
18
|
+
resp = get resource_name, "#{id}/pdf"
|
|
19
|
+
resp.pdf
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Closes a statement in the draft status (DRAFT). Here, the
|
|
23
|
+
# status of open (OPEN) or overdue (OVERDUE) is set and a PDF is
|
|
24
|
+
# generated and stored in the file system.
|
|
25
|
+
#
|
|
26
|
+
# @param [String,Integer] template_id ID of the Template used to create pdf,
|
|
27
|
+
# If not set, default template is used.
|
|
28
|
+
#
|
|
29
|
+
# @return [Boolean] Wether or not the call was successfull.
|
|
30
|
+
def complete template_id=nil
|
|
31
|
+
data = { complete: {} }
|
|
32
|
+
data[:complete] = { template_id: template_id } if template_id
|
|
33
|
+
resp = put resource_name, "#{id}/complete", data
|
|
34
|
+
|
|
35
|
+
!resp
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Cancel an invoice.
|
|
39
|
+
#
|
|
40
|
+
# @return [Boolean] Wether or not the call was successfull.
|
|
41
|
+
def cancel
|
|
42
|
+
resp = put resource_name, "#{id}/cancel"
|
|
43
|
+
!resp
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Sends an invoice by email.
|
|
47
|
+
#
|
|
48
|
+
# @param [String] to Recipient of the email.
|
|
49
|
+
# cc and bcc can be set in the `more` Hash.
|
|
50
|
+
# @param [String] from Sender email address.
|
|
51
|
+
# @param [String] subject Subject for the email.
|
|
52
|
+
# @param [String] body Body for the email.
|
|
53
|
+
# @param [Hash] more Hash-like object including more options.
|
|
54
|
+
# See online documentation for all allowed parameters.
|
|
55
|
+
#
|
|
56
|
+
# from, subject or body can be replaced by more.
|
|
57
|
+
#
|
|
58
|
+
# @return [Boolean] Wether or not the call was successfull.
|
|
59
|
+
def email to, from=nil, subject=nil, body=nil, more={}
|
|
60
|
+
data = { recipients: {} }
|
|
61
|
+
|
|
62
|
+
if more.empty? && from.kind_of?(Hash)
|
|
63
|
+
more = from
|
|
64
|
+
from = nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if more.empty? && subject.kind_of?(Hash)
|
|
68
|
+
more = subject
|
|
69
|
+
subject = nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
if more.empty? && body.kind_of?(Hash)
|
|
73
|
+
more = body
|
|
74
|
+
body = nil
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
data[:from] = from if from
|
|
78
|
+
data[:subject] = subject if subject
|
|
79
|
+
data[:body] = body if body
|
|
80
|
+
|
|
81
|
+
data.merge! more
|
|
82
|
+
data[:recipients][:to] = to
|
|
83
|
+
|
|
84
|
+
resp = post resource_name, "#{id}/email", email: data
|
|
85
|
+
!resp
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Uploads a digital signature for a given invoice.
|
|
89
|
+
#
|
|
90
|
+
# The status of the invoice may not be DRAFT.
|
|
91
|
+
#
|
|
92
|
+
# @param [String,#read] file file name or a object responding to #read.
|
|
93
|
+
# This will be base64-encoded before send.
|
|
94
|
+
#
|
|
95
|
+
# @return [Boolean] false if status is DRAFT or another error occured. true if everything was successfull.
|
|
96
|
+
def upload_signature file
|
|
97
|
+
return false if data.status == 'DRAFT'
|
|
98
|
+
|
|
99
|
+
file = File.open(file, 'r') unless file.respond_to?(:read)
|
|
100
|
+
|
|
101
|
+
base64 = Base64.encode64 file.read
|
|
102
|
+
put resource_name, "#{id}/upload-signature", { signature: { base64file: base64 } }
|
|
103
|
+
true
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
class BadBill
|
|
4
|
+
# Forward requests to the underlying connection object.
|
|
5
|
+
#
|
|
6
|
+
# This module is included in BadBill::BaseResource.
|
|
7
|
+
module Resource
|
|
8
|
+
# @param (see BadBill#get)
|
|
9
|
+
def get resource, id='', options=nil
|
|
10
|
+
call resource, id, options, :get
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @param (see BadBill#post)
|
|
14
|
+
def post resource, id='', options=nil
|
|
15
|
+
call resource, id, options, :post
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @param (see BadBill#put)
|
|
19
|
+
def put resource, id='', options=nil
|
|
20
|
+
call resource, id, options, :put
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @param (see BadBill#delete)
|
|
24
|
+
def delete resource, id='', options=nil
|
|
25
|
+
call resource, id, options, :delete
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @param (see BadBill#call)
|
|
29
|
+
def call resource, id='', options=nil, method=:get
|
|
30
|
+
raise BadBill::NoConnection, "No connection. Use BadBill.new first." if BadBill.connection.nil?
|
|
31
|
+
BadBill.connection.call resource, id, options, method
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|