fakturan_nu 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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