fakturan_nu 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f81bdfd634d37068875813a2c43c877ed859b4fb
4
+ data.tar.gz: 666f324bd953f0a55e9e6af4e8bbf70ad7405036
5
+ SHA512:
6
+ metadata.gz: c3591f8e8cb7cc5604029feec9e3a91b9e42a09fe302a97f8fe89aec1086abad8d30dafe9adee1163d330aeb7868210a3f9cc293af5ca9540b666f105e89194a
7
+ data.tar.gz: 4bd0783fff70fe74a037ee80f5a4e8df43873b6d4bb35e249775255d6cc42f789ec613386bd231d47625cd9be45c2d306d0c3d43f19b77b2c4c8d1c31738df59
data/.gitignore ADDED
@@ -0,0 +1,36 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ Gemfile.lock
30
+ .ruby-version
31
+ .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
35
+
36
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Imagineit AB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,121 @@
1
+ Ruby client for the fakturan.nu API
2
+ ==============================
3
+
4
+ API client in ruby for the Swedish web based invoicing software [fakturan.nu](https://www.fakturan.nu). The API is currently in Beta and may be subject to change without notice until final release.
5
+
6
+ ---
7
+
8
+ ## Installation
9
+
10
+ If you're using Rails/Bundler, add this to your Gemfile:
11
+
12
+ ```ruby
13
+ gem "fakturan_nu"
14
+ ```
15
+
16
+ Then create an initializer in app/initializers called ``` fakturan_nu.rb ``` (or whatever name you choose) with the following:
17
+
18
+ ```ruby
19
+ Fakturan.setup 'your api username here', 'your api key/password here'
20
+ Fakturan.use_sandbox = true # Should be true during development/testing and false in production.
21
+ ```
22
+
23
+ If you're not using Rails, just ``` require 'fakturan_nu'``` and run setup wherever you like.
24
+
25
+ ## Usage
26
+
27
+ ### General
28
+
29
+ The client attempts to provide an interface similar to ActiveRecord.
30
+
31
+ ```ruby
32
+ Fakturan::Product.all
33
+ # GET "https://fakturan.nu/api/v2/products" and return an array of product objects
34
+
35
+ Fakturan::Product.find(1)
36
+ # GET "https://fakturan.nu/api/v2/products/1" and return a product object
37
+
38
+ product = Fakturan::Product.create(name: "Shoes")
39
+ # POST "https://fakturan.nu/api/v2/products" and return the saved product object
40
+
41
+ product = Fakturan::Product.new(name: "Shoes")
42
+ product.tax = 12
43
+ product.save
44
+ # POST "https://fakturan.nu/api/v2/products" and return the saved product object
45
+
46
+ product = Fakturan::Product.find(1)
47
+ # GET "https://fakturan.nu/api/v2/products/1" and return a product object
48
+ product.name = "Blue suede shoes" # Update a property
49
+ product.save
50
+ # PUT "https://fakturan.nu/api/v2/products/1" and return the updated product object
51
+ ```
52
+
53
+ ### Invoices
54
+
55
+ For creating invoices, a date and a client is required:
56
+ ```ruby
57
+ invoice = Fakturan::Invoice.create(date: Date.today, client: { company: "Acme Inc" })
58
+ # POST "https://fakturan.nu/api/v2/invoices" # Will create a new client + invoice
59
+
60
+ invoice = Fakturan::Invoice.create(date: Date.today, client_id: 1)
61
+ # POST "https://fakturan.nu/api/v2/invoices" # Will create a new invoice for client with id: 1
62
+
63
+ ```
64
+
65
+ ### Available resources and properties
66
+
67
+ For a full list of resources and the properties of each type of resource, see the [api reference](https://sandbox.fakturan.nu/apidocs).
68
+
69
+ ## Pagination
70
+
71
+ The Fakturan.nu API paginates results. When a collection is fetched, it contains pagination information on the metadata accessor. So in order to get all results, you can do:
72
+
73
+ ```ruby
74
+ products = Fakturan::Product.all # This will give you paginated results of 30 items per page by default
75
+ products.concat(Fakturan::Product.get(products.metadata[:next])) while products.metadata[:next]
76
+ ```
77
+
78
+ You can change the default number of items per page (30) by passing in the per_page parameter:
79
+
80
+ ```ruby
81
+ products = Fakturan::Product.where(per_page: 100) # This will give you paginated results of 100 items per page
82
+ products.concat(Fakturan::Product.get(products.metadata[:next])) while products.metadata[:next]
83
+ ```
84
+
85
+ The maximum number of items per page allowed is 100.
86
+
87
+ ## Validation
88
+
89
+ Errors and validation are handled much like in ActiveRecord:
90
+
91
+ ```ruby
92
+ invoice = Fakturan::Invoice.new
93
+ invoice.save # false
94
+ invoice.errors.to_a # ["Client can't be blank", "Date can't be blank", "Date is invalid"]
95
+ ```
96
+
97
+ As with ActiveRecord, the ``` save ``` and ``` create ``` methods will return ``` true ``` or ``` false ``` depending on validations, while ``` save! ``` and ``` create! ``` will raise an error if validations fail. The error that is raised in such cases is ``` Fakturan::Error::ResourceInvalid ```.
98
+
99
+ ## Error handling
100
+
101
+ If the server responds with an error, or if the server cannot be reached, one of the following errors will be raised:
102
+
103
+ ```ruby
104
+ Fakturan::Error::AccessDenied # http status code: 401
105
+ Fakturan::Error::ResourceNotFound # http status code: 404
106
+ Fakturan::Error::ConnectionFailed # http status code: 407
107
+ Fakturan::Error::ResourceInvalid # http status code: 422
108
+ Fakturan::Error::ClientError # http status code: other in the 400-499 range
109
+ Fakturan::Error::ServerError # http status code: other in the 500-599 range
110
+ ```
111
+
112
+ These errors are all descendents of ```Fakturan::Error``` and should be caught in a begin-rescue block like so (example in a Rails-controller):
113
+
114
+ ```ruby
115
+ begin
116
+ invoice = Fakturan::Invoice.create!
117
+ rescue Fakturan::Error => error
118
+ render plain: error.message, status: error.status
119
+ end
120
+ ```
121
+
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ task default: :test
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ t.pattern = 'test/*_test.rb'
8
+ end
@@ -0,0 +1,2 @@
1
+ en:
2
+
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |s|
3
+ s.name = 'fakturan_nu'
4
+ s.version = '1.0.0'
5
+ s.date = '2014-12-17'
6
+ s.summary = 'A ruby client for the Fakturan.nu - API'
7
+ s.description = 'A ruby client for the Fakturan.nu - API. Fakturan.nu is a webbapp for billing.'
8
+ s.authors = ['Jonathan Bourque Olivegren']
9
+ s.email = 'jonathan@imagineit.se'
10
+ s.files = `git ls-files`.split("\n") # http://www.codinginthecrease.com/news_article/show/350843?referrer_id=948927
11
+ s.homepage = 'http://rubygems.org/gems/fakturan_nu'
12
+ s.license = 'MIT'
13
+
14
+ s.add_dependency 'spyke', '~> 1.8', '>= 1.8.7'
15
+ s.add_dependency 'faraday', '>= 0.8', '< 1.0'
16
+ s.add_dependency 'multi_json', '~> 1.11', '>= 1.11.0'
17
+ # So we can use model.errors.details before Rails 5.
18
+ s.add_dependency 'active_model-errors_details', '~> 1.1', '>= 1.1.1'
19
+
20
+ s.add_development_dependency 'rake'
21
+ s.add_development_dependency 'webmock'
22
+ s.add_development_dependency 'minitest'
23
+ s.add_development_dependency 'minitest-reporters'
24
+ s.add_development_dependency 'minitest-around'
25
+ s.add_development_dependency 'vcr'
26
+ end
@@ -0,0 +1,5 @@
1
+ module Fakturan
2
+ class Address < Base
3
+ uri nil
4
+ end
5
+ end
@@ -0,0 +1,88 @@
1
+ require 'fakturan_nu/error'
2
+
3
+ module Fakturan
4
+ class Base < Spyke::Base
5
+ include_root_in_json false
6
+
7
+ def self.connection
8
+ Fakturan.connection
9
+ end
10
+
11
+ def self.create!(attrs = {})
12
+ instance = self.new(attrs)
13
+ instance.save!
14
+ return instance
15
+ end
16
+
17
+ def self.create(attrs = {})
18
+ instance = self.new(attrs)
19
+ instance.save
20
+ return instance
21
+ end
22
+
23
+ def save
24
+ errors.clear
25
+ super
26
+ return !errors.any?
27
+ end
28
+
29
+ def save!
30
+ raise Fakturan::Error::ResourceInvalid, self unless self.save
31
+ end
32
+
33
+ # This is an override from: https://github.com/balvig/spyke/blob/master/lib/spyke/http.rb
34
+ # to allow for nested errors on associated objects
35
+ def add_errors_to_model(errors_hash)
36
+ errors_hash.each do |field, field_errors|
37
+ ass_name, field_name = field.split(".").map(&:to_sym)
38
+ field_name = ass_name unless field_name
39
+
40
+ if association = self.class.reflect_on_association(ass_name) # The errors are for an associatied object
41
+ if association.type == Spyke::Associations::HasMany
42
+ field_errors.each do |new_error_hash_with_index|
43
+ new_error_hash_with_index.each do |index, inner_errors_hash|
44
+ error_attribute = inner_errors_hash.keys.first.split('.').last.to_sym
45
+ self.send(ass_name)[index.to_i].add_to_errors(error_attribute, inner_errors_hash.values.last)
46
+ end
47
+ end
48
+ else # It's a belongs_to or has_one
49
+ # We add the error to the associated object
50
+ self.send(ass_name).add_to_errors(field_name, field_errors)
51
+ # and then we get the errors (with generated messages) and add them to
52
+ # the parent (but without details, like nested_attributes works)
53
+ # This only makes sense on belongs_to and has_one, since it's impossible
54
+ # to know which object is refered to on has_many
55
+ self.send(ass_name).errors.each do |attribute, message|
56
+ attribute = "#{ass_name}.#{attribute}"
57
+ errors[attribute] << message
58
+ errors[attribute].uniq!
59
+ end
60
+ end
61
+ else
62
+ self.add_to_errors(field_name.to_sym, field_errors)
63
+ end
64
+
65
+ end
66
+ end
67
+
68
+ def add_to_errors field_name, field_errors
69
+ field_errors.each do |attributes|
70
+ attributes = attributes.symbolize_keys
71
+ error_name = attributes.delete(:error).to_sym
72
+ errors.add(field_name.to_sym, error_name, attributes)
73
+ end
74
+ end
75
+
76
+ # This is an override from: https://github.com/balvig/spyke/blob/master/lib/spyke/http.rb
77
+ # In order to re-raise Faraday error as Fakturan error
78
+ def self.request(method, path, params = {})
79
+ begin
80
+ super
81
+ rescue Faraday::ConnectionFailed => e
82
+ raise Fakturan::Error::ConnectionFailed, e.message
83
+ rescue Faraday::TimeoutError => e
84
+ raise Fakturan::Error::ConnectionFailed, e.message
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,19 @@
1
+ module Fakturan
2
+ class Client < Base
3
+ uri "clients/(:id)"
4
+ has_many :invoices, uri: "clients/:id/invoices", foreign_key: 'id'
5
+ has_one :address
6
+
7
+ accepts_nested_attributes_for :address
8
+
9
+ attributes :number, :first_name, :last_name, :email, :company, :phone, :home_phone, :mobile_phone, :fax, :org_number, :private, :web, :vat_number
10
+
11
+ def address=(attrs_or_obj)
12
+ if attrs_or_obj.respond_to?(:each)
13
+ send(:address_attributes=, attrs_or_obj)
14
+ else
15
+ super
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,69 @@
1
+ require 'active_model/errors_details'
2
+
3
+ # This is just to provide a set of errors with consistent scope
4
+ # https://github.com/lostisland/faraday/blob/master/lib/faraday/error.rb
5
+ module Fakturan
6
+ class Error < StandardError; end
7
+
8
+ class WithResponse < Error
9
+ attr_reader :response
10
+
11
+ def status
12
+ response[:status]
13
+ end
14
+
15
+ def initialize(ex, response = nil)
16
+ @wrapped_exception = nil
17
+ @response = response
18
+
19
+ if ex.respond_to?(:backtrace) # If ex behaves like an Exception
20
+ super(ex.message)
21
+ @wrapped_exception = ex
22
+ elsif ex.respond_to?(:each_key) # If ex behaves like a Hash
23
+ super("the server responded with status #{ex[:status]} - #{ex[:body]}")
24
+ @response = ex
25
+ else
26
+ super(ex.to_s)
27
+ end
28
+ end
29
+
30
+ def backtrace
31
+ if @wrapped_exception
32
+ @wrapped_exception.backtrace
33
+ else
34
+ super
35
+ end
36
+ end
37
+
38
+ def inspect
39
+ %(#<#{self.class}>)
40
+ end
41
+ end
42
+
43
+ class ClientError < WithResponse; end
44
+ class ServerError < WithResponse; end
45
+ class AccessDenied < WithResponse; end
46
+ class ResourceNotFound < WithResponse; end
47
+ class ParseError < WithResponse; end
48
+
49
+ class ConnectionFailed < Error
50
+ def status; 407; end
51
+ end
52
+
53
+ class ResourceInvalid < Error
54
+ attr_reader :model
55
+
56
+ def status; 422; end
57
+
58
+ def initialize(model)
59
+ @model = model
60
+ msg = @model.errors.details #to_a.join(" ")
61
+ super(msg)
62
+ end
63
+ end
64
+
65
+ # This is just so that we can have Fakturan::Error be both a class and a "scope": Fakturan::Error::ResourceInvalid
66
+ [:WithResponse, :ClientError, :ServerError, :AccessDenied, :ResourceNotFound, :ParseError, :ConnectionFailed, :ResourceInvalid].each do |const|
67
+ Error.const_set(const, Fakturan.const_get(const))
68
+ end
69
+ end
@@ -0,0 +1,40 @@
1
+ module Fakturan
2
+ class Invoice < Base
3
+ uri "invoices/(:id)"
4
+
5
+ # The foreign_key decides which attribute will be used to set the id
6
+ belongs_to :client, uri: "clients/:id", foreign_key: 'client_id'
7
+ has_one :address, uri: nil
8
+
9
+ has_many :rows, uri: nil
10
+
11
+ accepts_nested_attributes_for :rows, :address, :client
12
+
13
+ # These create getter methods on new instances, mostly for use in forms
14
+ attributes :number, :date, :client_id, :days, :our_reference, :your_reference, :sent, :paid, :paid_at, :interval_period, :auto_send, :recurring, :last_day_of_month, :start_recurring_from, :locale, :currency
15
+
16
+ def rows=(attrs_or_obj_array)
17
+ if attrs_or_obj_array.first.respond_to?(:each)
18
+ send(:rows_attributes=, attrs_or_obj_array)
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ def address=(attrs_or_obj)
25
+ if attrs_or_obj.respond_to?(:each)
26
+ send(:address_attributes=, attrs_or_obj)
27
+ else
28
+ super
29
+ end
30
+ end
31
+
32
+ def client=(attrs_or_obj)
33
+ if attrs_or_obj.respond_to?(:each)
34
+ send(:client_attributes=, attrs_or_obj)
35
+ else
36
+ super
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ module Fakturan
2
+ module Response
3
+ class ParseJSON < Faraday::Response::Middleware
4
+ def parse(body)
5
+ json = MultiJson.load(body, symbolize_keys: true)
6
+ res = {
7
+ data: json[:data],
8
+ metadata: json[:paging],
9
+ errors: json[:errors]
10
+ }
11
+ return res
12
+ end
13
+
14
+ def on_complete(env)
15
+ begin # https://github.com/lostisland/faraday/blob/master/lib/faraday/response.rb
16
+ env.body = parse(env.body) if env.parse_body?
17
+ rescue MultiJson::ParseError => exception
18
+ raise Fakturan::Error::ParseError, {:status => env.status, :headers => env.response_headers, :body => env.body}
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ require 'fakturan_nu/error'
2
+
3
+ module Fakturan
4
+ module Response
5
+ class RaiseError < Faraday::Response::Middleware
6
+ ClientErrorStatuses = 400...499
7
+ ServerErrorStatuses = 500...599
8
+
9
+ def on_complete(env)
10
+ case env[:status]
11
+ when 401
12
+ raise Fakturan::Error::AccessDenied, response_values(env)
13
+ when 404
14
+ raise Fakturan::Error::ResourceNotFound, response_values(env)
15
+ when 407
16
+ # mimic the behavior that we get with proxy requests with HTTPS
17
+ raise Faraday::ConnectionFailed, %{407 "Proxy Authentication Required "} # We raise this instead of our own ConnectionFailed error, since Faraday::ConnectionFailed will be raise on timeouts or refused connections anyway
18
+ when 422
19
+ # We don't do anything except fallback to standard behaviour in Spyke, which is to store errors on .errors and not raise an exception
20
+ # If an exception is desirable, then use .save! on the model instead of .save.
21
+ when ClientErrorStatuses
22
+ raise Fakturan::Error::ClientError, response_values(env)
23
+ when ServerErrorStatuses
24
+ raise Fakturan::Error::ServerError, response_values(env)
25
+ end
26
+ end
27
+
28
+ def response_values(env)
29
+ {:status => env.status, :headers => env.response_headers, :body => env.body}
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,7 @@
1
+ module Fakturan
2
+ class Product < Base
3
+ uri 'products/(:id)'
4
+
5
+ attributes :name, :unit, :price, :tax, :product_code
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Fakturan
2
+ class Row < Base
3
+ uri nil
4
+
5
+ attributes :product_id, :discount, :amount, :text, :product_code, :product_name, :product_unit, :product_price, :product_tax, :text_row, :sort_order
6
+ end
7
+ end
@@ -0,0 +1,24 @@
1
+ module Spyke
2
+ class Collection
3
+ # For pagination.
4
+ # Makes it possible to do ps = Fakturan::Product.all and then
5
+ # ps.concat(Fakturan::Product.get(ps.metadata[:next])) while ps.metadata[:next])
6
+ def concat ary_or_collection
7
+ @metadata = ary_or_collection.metadata if ary_or_collection.respond_to?(:metadata)
8
+ super
9
+ end
10
+ end
11
+
12
+ class Relation
13
+ # For pagination and more array-like behaviour.
14
+ # It's very tempting to add << as well, but as I recall, it didn't behave as expected
15
+ delegate :concat, :+, :-, to: :find_some
16
+ end
17
+
18
+ module Associations
19
+ class Builder
20
+ # Allows us to do reflect_on_association(ass_name).type
21
+ attr_accessor :type
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,87 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'spyke'
3
+ #require 'active_support/json/decoding' # if we want date-strings to be typecast as DateTimes. Can be done through Faraday-middleware too.
4
+ require 'faraday_middleware'
5
+ require 'multi_json'
6
+ require 'fakturan_nu/spyke_extensions'
7
+ require 'fakturan_nu/middleware/parse_json'
8
+ require 'fakturan_nu/middleware/raise_error'
9
+
10
+ require 'fakturan_nu/base'
11
+ require 'fakturan_nu/address'
12
+ require 'fakturan_nu/product'
13
+ require 'fakturan_nu/client'
14
+ require 'fakturan_nu/row'
15
+ require 'fakturan_nu/invoice'
16
+
17
+ I18n.load_path += Dir.glob( File.dirname(__FILE__) + "lib/locales/*.{rb,yml}" )
18
+
19
+ module Fakturan
20
+ @use_sandbox = false
21
+ @api_version = 2
22
+
23
+ mattr_accessor :accept_language
24
+
25
+ def self.setup username = nil, pass = nil
26
+ #self.parse_json_times = true
27
+
28
+ @username, @pass = username, pass
29
+ self.accept_language = 'en-US'
30
+
31
+ @connection = Faraday.new(url: build_url) do |connection|
32
+ # Request
33
+ connection.request :json
34
+ connection.use Faraday::Request::BasicAuthentication, @username, @pass
35
+
36
+ # Response
37
+ connection.use Fakturan::Response::ParseJSON
38
+ connection.use Fakturan::Response::RaiseError
39
+
40
+ # Adapter should be last
41
+ connection.adapter Faraday.default_adapter
42
+ end
43
+ end
44
+
45
+ def self.connection
46
+ @connection
47
+ end
48
+
49
+ #def self.parse_json_times=(true_or_false)
50
+ # ActiveSupport.parse_json_times = true_or_false
51
+ #end
52
+
53
+ def self.use_token_auth(token)
54
+ @connection.token_auth(token)
55
+ end
56
+
57
+ def self.use_basic_auth(username = nil, pass = nil)
58
+ @username, @pass = username, pass if (username && pass)
59
+ @connection.basic_auth(@username, @pass)
60
+ end
61
+
62
+ def self.use_sandbox=(true_or_false)
63
+ @use_sandbox = true_or_false
64
+ rebuild_url
65
+ end
66
+
67
+ def self.api_version=(version_no)
68
+ @api_version = version_no
69
+ rebuild_url
70
+ end
71
+
72
+ def self.url
73
+ @connection.url_prefix.to_s
74
+ end
75
+
76
+ def self.url=(new_url)
77
+ @connection.url_prefix = new_url
78
+ end
79
+
80
+ def self.build_url
81
+ "https://#{@use_sandbox ? 'sandbox.' : ''}fakturan.nu/api/v#{@api_version}"
82
+ end
83
+
84
+ def self.rebuild_url
85
+ self.url = self.build_url
86
+ end
87
+ end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+ VCR.turn_off!
3
+
4
+ module Fakturan
5
+ class BasicsTest < MiniTest::Test
6
+
7
+ # They are not, but I dislike them jumping around in the output. Makes it harder to compare two test runs.
8
+ i_suck_and_my_tests_are_order_dependent!
9
+
10
+ def test_auth_with_token_and_back_to_basic
11
+ basic_auth_endpoint = stub_api_request(:get, '/clients/1').to_return(body: '{"data":{"id": 1, "name":"DCT"}}', status: 200)
12
+
13
+ token_endpoint = stub_request(:get, "http://#{BASE_URL}/clients/1")
14
+ .with(headers: { authorization: "Token token=\"XYZ\""})
15
+ .to_return(body: '{"data":{"id": 1, "name":"DCT"}}', status: 200)
16
+
17
+ Fakturan::Client.find(1)
18
+ Fakturan.use_token_auth('XYZ')
19
+ Fakturan::Client.find(1)
20
+ Fakturan.use_basic_auth
21
+ Fakturan::Client.find(1)
22
+ assert_requested basic_auth_endpoint, times: 2
23
+ assert_requested token_endpoint, times: 1
24
+ end
25
+ end
26
+ end