billomat 0.1.0 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 40a474e94aa0c704209fa2ebd99a4981730be955
4
- data.tar.gz: efc188086b6124410a52c6d6796541a38fddb7af
3
+ metadata.gz: e9b1dc728272e6dca7e6fe43418c9ec7511f962b
4
+ data.tar.gz: a83499376d3e6aa576d4a9270d3d5f3bd3566199
5
5
  SHA512:
6
- metadata.gz: 11510e2136f9f04d213b44459bb9459628c67e38d5a469b9491300ad4f68faef00f8bad55817eb4e88048f4f167aa745607062c41ac15debfeaba631cb477c08
7
- data.tar.gz: cbf6cbb1066541439b77030703b2a5085f0975dbdf7a089ca46e5c0dd2ad8fb4fec789d5091af2a8b77543fa95658176a95cb82ccc41de2533a6e7bad99b0102
6
+ metadata.gz: 4387bcef030751f0147c14469d0b25fc332266c0462be814396ba749ff8ba51c2dd474437d7946d6069ca20c732f516a11bfead7fa31d69b3a4e405b4f5213ca
7
+ data.tar.gz: 7502cfd88d175ed62aa57be385c99dc00b07a03cb49f97cfed3ab6f71214944e9cb3572ee03da6ee5b43102394020a90028a993629fa589bedd01d7e00873d5e
data/.travis.yml CHANGED
@@ -1,5 +1,18 @@
1
+ env:
2
+ global:
3
+ - CC_TEST_REPORTER_ID=a77802032cccc178727a1df1ff1f283a8255959f9a175f20b73b8231ca35da2f
1
4
  sudo: false
2
5
  language: ruby
3
6
  rvm:
4
- - 2.4.1
7
+ - 2.0
8
+ - 2.1
9
+ - 2.2
10
+ - 2.3
11
+ - 2.4
5
12
  before_install: gem install bundler -v 1.15.1
13
+ before_script:
14
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
15
+ - chmod +x ./cc-test-reporter
16
+ - ./cc-test-reporter before-build
17
+ after_script:
18
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Billomat
2
2
  [![Build Status](https://travis-ci.org/hausgold/billomat.svg?branch=master)](https://travis-ci.org/hausgold/billomat)
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/49baf848f42a2e5b95db/maintainability)](https://codeclimate.com/github/hausgold/billomat/maintainability)
4
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/49baf848f42a2e5b95db/test_coverage)](https://codeclimate.com/github/hausgold/billomat/test_coverage)
3
5
 
4
6
  This gem provides a Ruby API for [billomat.com](https://billomat.com) - an online accounting service.
5
7
 
@@ -13,11 +15,15 @@ gem 'billomat'
13
15
 
14
16
  And then execute:
15
17
 
16
- $ bundle
18
+ ```bash
19
+ $ bundle
20
+ ```
17
21
 
18
22
  Or install it yourself as:
19
23
 
20
- $ gem install billomat
24
+ ```bash
25
+ $ gem install billomat
26
+ ```
21
27
 
22
28
  ## Usage
23
29
 
@@ -25,7 +31,7 @@ Or install it yourself as:
25
31
 
26
32
  The configuration takes two settings: `api_key` and `subdomain`. The latter is e.g. the name of your organization.
27
33
 
28
- ```
34
+ ```ruby
29
35
  Billomat.configure do |config|
30
36
  config.subdomain = 'your-company'
31
37
  config.api_key = 'a3b148a61cb642389b4f9953f6233f20'
@@ -36,7 +42,7 @@ end
36
42
 
37
43
  Currently there is basic support for the models `Invoice`, `Client`, `InvoicePayment`, `InvoiceItem`
38
44
 
39
- ```
45
+ ```ruby
40
46
  Billomat::Models::Invoice.where(invoice_number: 'RE1234')
41
47
  => [#<Billomat::Models::Invoice:0x005574b58d6510 ...]
42
48
 
@@ -51,7 +57,6 @@ client.delete
51
57
  => true
52
58
  ```
53
59
 
54
-
55
60
  ## Development
56
61
 
57
62
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -2,17 +2,26 @@
2
2
 
3
3
  module Billomat
4
4
  module Actions
5
+ ##
6
+ # This actions cancels an invoice
5
7
  class Cancel
8
+ # @param [String] invoice_id The invoice ID
9
+ # @return [Billomat::Actions::Cancel]
6
10
  def initialize(invoice_id)
7
11
  @invoice_id = invoice_id
8
12
  end
9
13
 
14
+ ##
15
+ # Calls the gateway
16
+ #
17
+ # @return [TrueClass]
10
18
  def call
11
19
  Billomat::Gateway.new(:put, path).run
12
20
 
13
21
  true
14
22
  end
15
23
 
24
+ # @return [String] The cancel path with the invoice_id
16
25
  def path
17
26
  "/invoices/#{@invoice_id}/cancel"
18
27
  end
@@ -2,22 +2,42 @@
2
2
 
3
3
  module Billomat
4
4
  module Actions
5
+ ##
6
+ # Completes an invoice by calling the /complete path on a resource
5
7
  class Complete
8
+ ##
9
+ # Returns a Complete object
10
+ #
11
+ # @param [String] invoice_id The ID of the invoice
12
+ # @param [Hash] opts The options for this request
13
+ # @return [Billomat::Actions::Complete]
14
+ #
15
+ # @example
16
+ # Billomat::Actions::Complete('12345', { template_id: '10231' })
6
17
  def initialize(invoice_id, opts = {})
7
18
  @invoice_id = invoice_id
8
19
  @opts = opts
9
20
  end
10
21
 
22
+ ##
23
+ # Calls the gateway
24
+ #
25
+ # @return [TrueClass]
11
26
  def call
12
27
  Billomat::Gateway.new(:put, path, wrapped_data).run
13
28
 
14
29
  true
15
30
  end
16
31
 
32
+ ##
33
+ # The given options have to be wrapped
34
+ #
35
+ # @return [Hash] The payload for the complete request
17
36
  def wrapped_data
18
37
  { complete: @opts }
19
38
  end
20
39
 
40
+ # @return [String] The complete path with the invoice_id
21
41
  def path
22
42
  "/invoices/#{@invoice_id}/complete"
23
43
  end
@@ -1,27 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # This actions sends an invoice email
4
- # Recipients must be passed like this:
5
- # { recipients: { to: 'bob@example.org' } }
6
-
7
3
  module Billomat
8
4
  module Actions
5
+ ##
6
+ # This actions sends an invoice email.
7
+ # Recipients must be passed like this:
8
+ # { recipients: { to: 'bob@example.org' } }
9
+ #
10
+ # @example
11
+ # Billomat::Actions::Email.new('1235', { recipiens: { to: 'a@b.org' } })
9
12
  class Email
13
+ # @param [String] invoice_id The invoice ID
14
+ # @param [Hash] opts The options for this action
15
+ #
16
+ # @return [Billomat::Actions::Email]
10
17
  def initialize(invoice_id, opts = {})
11
18
  @invoice_id = invoice_id
12
19
  @opts = opts
13
20
  end
14
21
 
22
+ ##
23
+ # Calls the gateway
24
+ #
25
+ # @return [TrueClass]
15
26
  def call
16
27
  Billomat::Gateway.new(:post, path, wrapped_data).run
17
28
 
18
29
  true
19
30
  end
20
31
 
32
+ ##
33
+ # Wraps the options
34
+ #
35
+ # @return [Hash] The wrapped email options
21
36
  def wrapped_data
22
37
  { email: @opts }
23
38
  end
24
39
 
40
+ # @return [String] The path for the email action
25
41
  def path
26
42
  "/invoices/#{@invoice_id}/email"
27
43
  end
@@ -2,17 +2,32 @@
2
2
 
3
3
  module Billomat
4
4
  module Actions
5
+ ##
6
+ # This class allows to download the invoice as a pdf.
7
+ # The PDF comes in a base64 encoded string in the response body.
5
8
  class Pdf
9
+ # @param [String] invoice_id The invoice ID
10
+ # @param [Hash] opts The options for this action
11
+ #
12
+ # @return [Billomat::Actions::Pdf]
6
13
  def initialize(invoice_id, opts = {})
7
14
  @invoice_id = invoice_id
8
15
  @opts = opts
9
16
  end
10
17
 
18
+ ##
19
+ # Calls the gateway
20
+ #
21
+ # @return [TrueClass]
11
22
  def call
12
23
  resp = Billomat::Gateway.new(:get, path).run
13
24
  resp['pdf']
14
25
  end
15
26
 
27
+ ##
28
+ # Wraps the options
29
+ #
30
+ # @return [Hash] The wrapped email options
16
31
  def path
17
32
  "/invoices/#{@invoice_id}/pdf"
18
33
  end
@@ -2,17 +2,30 @@
2
2
 
3
3
  module Billomat
4
4
  module Actions
5
+ ##
6
+ # This actions uncancels an canceld invoice.
7
+ #
8
+ # @example
9
+ # Billomat::Actions::Uncancel.new('1235')
5
10
  class Uncancel
11
+ # @param [String] invoice_id The invoice ID
12
+ #
13
+ # @return [Billomat::Actions::Uncancel]
6
14
  def initialize(invoice_id)
7
15
  @invoice_id = invoice_id
8
16
  end
9
17
 
18
+ ##
19
+ # Calls the gateway
20
+ #
21
+ # @return [TrueClass]
10
22
  def call
11
23
  Billomat::Gateway.new(:put, path).run
12
24
 
13
25
  true
14
26
  end
15
27
 
28
+ # @return [String] The path for the uncancel action
16
29
  def path
17
30
  "/invoices/#{@invoice_id}/uncancel"
18
31
  end
@@ -7,5 +7,8 @@ require 'billomat/actions/cancel'
7
7
  require 'billomat/actions/uncancel'
8
8
 
9
9
  module Billomat
10
+ ##
11
+ # Actions are API calls that do not directly represent a resource.
12
+ # They are mostly non-RESTful actions that are called on a resources.
10
13
  module Actions; end
11
14
  end
@@ -4,17 +4,34 @@ require 'rest-client'
4
4
  require 'json'
5
5
 
6
6
  module Billomat
7
+ ##
8
+ # Raised if something goes wrong during an API call
7
9
  class GatewayError < StandardError; end
8
10
 
11
+ ##
12
+ # This class can be used by the gem to communicate with the API
9
13
  class Gateway
10
14
  attr_reader :method, :path, :body
11
15
 
16
+ ##
17
+ # Creates a new Gateway
18
+ #
19
+ # @param [Symbol] method The HTTP verb
20
+ # @param [String] path The path of the resource
21
+ # @param [Hash] body The payload for the request
22
+ #
23
+ # @example
24
+ # Billomat::Gateway.new(:get, '/invoices')
25
+ # Billomat::Gateway.new(:post, '/invoices', { 'invoice' => { ... } })
12
26
  def initialize(method, path, body = {})
13
27
  @method = method.to_sym
14
28
  @path = path
15
29
  @body = body
16
30
  end
17
31
 
32
+ ##
33
+ # Executes the API call
34
+ # @return [Hash] The response body
18
35
  def run
19
36
  resp = RestClient::Request.execute(
20
37
  method: method,
@@ -30,14 +47,17 @@ module Billomat
30
47
  JSON.parse(resp.body)
31
48
  end
32
49
 
50
+ # @return [String] The complete URL for the request
33
51
  def url
34
52
  "https://#{config.subdomain}.billomat.net/api#{path}"
35
53
  end
36
54
 
55
+ # @return [Integer]
37
56
  def timeout
38
57
  5
39
58
  end
40
59
 
60
+ # @return [Hash] The headers for the request.
41
61
  def headers
42
62
  {
43
63
  'Accept' => 'application/json',
@@ -46,6 +66,7 @@ module Billomat
46
66
  }
47
67
  end
48
68
 
69
+ # @return [Billomat::Configuration] The global gem configuration
49
70
  def config
50
71
  Billomat.configuration
51
72
  end
@@ -4,28 +4,52 @@ require 'ostruct'
4
4
 
5
5
  module Billomat
6
6
  module Models
7
+ ##
8
+ # This class is the base for all other models (resources).
9
+ # It handles the communication with the gateway to talk to the API.
7
10
  class Base
8
11
  attr_accessor :data
9
12
 
13
+ ##
14
+ # Tries to find the resource for the given id
15
+ #
16
+ # @param [String] id The resource id
17
+ # @return [Billomat::Models::Base, nil] The found resource or nil
10
18
  def self.find(id)
11
19
  return nil if id.nil?
12
20
  resp = Billomat::Gateway.new(:get, "#{base_path}/#{id}").run
13
21
  new(resp[resource_name])
14
22
  end
15
23
 
24
+ ##
25
+ # Allows to query for a record
26
+ #
27
+ # @param [Hash] hash The query parameters
28
+ # @return [Array<Billomat::Models::Base>] The found records
16
29
  def self.where(hash = {})
17
30
  Billomat::Search.new(self, hash).run
18
31
  end
19
32
 
33
+ ##
34
+ # Initializes a new model
35
+ #
36
+ # @param [Hash] data The attributes of the object
37
+ # @return [Billomat::Models::Base] The record as an object
20
38
  def initialize(data = {})
21
39
  @data = OpenStruct.new(data)
22
40
  end
23
41
 
42
+ ##
43
+ # Persists the current object in the API.
44
+ # When record is new it calls create, otherwise it saves the object.
45
+ #
46
+ # @return [TrueClass]
24
47
  def save
25
48
  return create if id.blank?
26
49
  update
27
50
  end
28
51
 
52
+ # @return [TrueClass]
29
53
  def create
30
54
  resp = Billomat::Gateway.new(
31
55
  :post, self.class.base_path, wrapped_data
@@ -36,6 +60,7 @@ module Billomat
36
60
  true
37
61
  end
38
62
 
63
+ # @return [TrueClass]
39
64
  def update
40
65
  path = "#{self.class.base_path}/#{id}"
41
66
  resp = Billomat::Gateway.new(:put, path, wrapped_data).run
@@ -44,6 +69,7 @@ module Billomat
44
69
  true
45
70
  end
46
71
 
72
+ # @return [TrueClass]
47
73
  def delete
48
74
  path = "#{self.class.base_path}/#{id}"
49
75
  Billomat::Gateway.new(:delete, path).run
@@ -51,19 +77,41 @@ module Billomat
51
77
  true
52
78
  end
53
79
 
80
+ # @return [String, nil] The object's ID
54
81
  def id
55
82
  @data['id'] || nil
56
83
  end
57
84
 
85
+ ##
86
+ # Wraps the data so the API accepts the request
87
+ #
88
+ # @example
89
+ # some_invoice.wrapped_data
90
+ # #=> { "invoice" => { "id" => "12345" } }
91
+ #
92
+ # @return [Hash] The wrapped data
58
93
  def wrapped_data
59
94
  { self.class.resource_name => @data.to_h }
60
95
  end
61
96
 
97
+ ##
98
+ # All values in the @data hash can be accessed like a 'normal' method
99
+ #
100
+ # @example
101
+ # invoice = Billomat::Models::Invoice.new(invoice_number: '123')
102
+ # invoice.invoice_number
103
+ # #=> '123'
62
104
  def method_missing(method, *args, &block)
63
105
  return @data[method] if @data.to_h.keys.include?(method)
64
106
  super
65
107
  end
66
108
 
109
+ ##
110
+ # Necessary for method_missing
111
+ #
112
+ # @param [Symbol] method The method name
113
+ # @param [TrueClass, FalseClass] include_privat
114
+ # @return [TrueClass, FalseClass]
67
115
  def respond_to_missing?(method, include_privat = false)
68
116
  @data.to_h.keys.include?(method.to_s) || super
69
117
  end
@@ -2,11 +2,15 @@
2
2
 
3
3
  module Billomat
4
4
  module Models
5
+ ##
6
+ # Representation of the client resource
5
7
  class Client < Base
8
+ # @return [String] The resource's base path
6
9
  def self.base_path
7
10
  '/clients'
8
11
  end
9
12
 
13
+ # @return [String] The resource's name
10
14
  def self.resource_name
11
15
  'client'
12
16
  end
@@ -2,29 +2,43 @@
2
2
 
3
3
  module Billomat
4
4
  module Models
5
+ ##
6
+ # Representation of the invoice resource
5
7
  class Invoice < Base
8
+ # @return [String] The resource's base path
6
9
  def self.base_path
7
10
  '/invoices'
8
11
  end
9
12
 
13
+ # @return [String] The resource's name
10
14
  def self.resource_name
11
15
  'invoice'
12
16
  end
13
17
 
18
+ ##
19
+ # Completes the invoice by calling the Complete action
14
20
  def complete!
15
21
  Billomat::Actions::Complete.new(id).call
16
22
  end
17
23
 
24
+ ##
25
+ # Cancels the invoice by calling the Cancel action
18
26
  def cancel!
19
27
  Billomat::Actions::Cancel.new(id).call
20
28
  end
21
29
 
30
+ ##
31
+ # Sends the invoice as an email to the given recipient
32
+ #
33
+ # @param [String] recipient The email address of the recipient
22
34
  def send_email(recipient)
23
35
  email_params = { recipients: { to: recipient } }
24
36
 
25
37
  Billomat::Actions::Email.new(id, email_params).call
26
38
  end
27
39
 
40
+ ##
41
+ # Allows to download the invoice as an PDF
28
42
  def to_pdf
29
43
  Billomat::Actions::Pdf.new(id).call
30
44
  end
@@ -2,11 +2,15 @@
2
2
 
3
3
  module Billomat
4
4
  module Models
5
+ ##
6
+ # Representation of the invoice item resource
5
7
  class InvoiceItem < Base
8
+ # @return [String] The resource's base path
6
9
  def self.base_path
7
10
  '/invoice-items'
8
11
  end
9
12
 
13
+ # @return [String] The resource's name
10
14
  def self.resource_name
11
15
  'invoice-item'
12
16
  end
@@ -2,11 +2,15 @@
2
2
 
3
3
  module Billomat
4
4
  module Models
5
+ ##
6
+ # Representation of the invoice payment resource
5
7
  class InvoicePayment < Base
8
+ # @return [String] The resource's base path
6
9
  def self.base_path
7
10
  '/invoice-payments'
8
11
  end
9
12
 
13
+ # @return [String] The resource's name
10
14
  def self.resource_name
11
15
  'invoice-payment'
12
16
  end
@@ -7,5 +7,7 @@ require 'billomat/models/invoice_item'
7
7
  require 'billomat/models/invoice_payment'
8
8
 
9
9
  module Billomat
10
+ ##
11
+ # Models represent a resource in the API, e.g. invoices, clients
10
12
  module Models; end
11
13
  end
@@ -3,21 +3,41 @@
3
3
  require 'uri'
4
4
 
5
5
  module Billomat
6
+ ##
7
+ # This class provides the possibility to query the resources
6
8
  class Search
9
+ ##
10
+ # Creates a new search object
11
+ #
12
+ # @param [Class] resource The resource class to be queried
13
+ # @param [Hash] hash The query
7
14
  def initialize(resource, hash)
8
15
  @resource = resource
9
16
  @hash = hash
10
17
  end
11
18
 
19
+ # @return [String] The path including the query
12
20
  def path
13
21
  "#{@resource.base_path}?#{hash_to_query}"
14
22
  end
15
23
 
24
+ ##
25
+ # Runs the query and calls the gateway
26
+ #
27
+ # @return [Array<Billomat::Model::Base>]
16
28
  def run
17
- return [] if @hash.compact.empty?
29
+ return [] if @hash.reject { |k, v| v.nil? }.empty?
18
30
  to_array(Billomat::Gateway.new(:get, path).run)
19
31
  end
20
32
 
33
+ ##
34
+ # Corrects the response to always return an array
35
+ #
36
+ # @todo Due to a strange API behaviour we have to fix the reponse here.
37
+ # This may be fixed in a new API version.
38
+ #
39
+ # @param [Hash] resp The response from the gateway
40
+ # @return [Array<Billomat::Model::Base>]
21
41
  def to_array(resp)
22
42
  case count(resp)
23
43
  when 0
@@ -32,10 +52,13 @@ module Billomat
32
52
  end
33
53
  end
34
54
 
55
+ # @return [String] The name of the resource
35
56
  def name
36
57
  @resource.resource_name
37
58
  end
38
59
 
60
+ # @param [Hash] resp The response from the gateway
61
+ # @return [Integer] The number of records found
39
62
  def count(resp)
40
63
  return 0 if resp.nil?
41
64
  resp["#{name}s"]['@total'].to_i
@@ -43,6 +66,7 @@ module Billomat
43
66
 
44
67
  private
45
68
 
69
+ # @return [String] The query as www encoded string
46
70
  def hash_to_query
47
71
  URI.encode_www_form(@hash)
48
72
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Billomat
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/billomat.rb CHANGED
@@ -7,15 +7,27 @@ require 'billomat/actions'
7
7
  require 'billomat/search'
8
8
  require 'billomat/gateway'
9
9
 
10
+ ##
11
+ # An wrapper for the
12
+ # <a href="https://billomat.com">Billomat</a>
13
+ # API
10
14
  module Billomat
11
15
  class << self
12
16
  attr_writer :configuration
13
17
  end
14
18
 
19
+ # @return [Billomat::Configuration] The global billomat configuration
15
20
  def self.configuration
16
21
  @configuration ||= Billomat::Configuration.new
17
22
  end
18
23
 
24
+ # Class method to set and change the global configuration
25
+ #
26
+ # @example
27
+ # Billomat.configure do |config|
28
+ # config.subdomain = 'your-business-name'
29
+ # config.api_key = 'a3b148a61cb642389b4f9953f6233f20'
30
+ # end
19
31
  def self.configure
20
32
  yield(configuration)
21
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: billomat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henning Vogt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-05 00:00:00.000000000 Z
11
+ date: 2017-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client