fortnox-api 0.1.0 → 0.2.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 +4 -4
- data/.codeclimate.yml +3 -2
- data/.env.test +3 -0
- data/.rubocop.yml +32 -23
- data/.travis.yml +3 -2
- data/Guardfile +2 -2
- data/LICENSE.txt +165 -22
- data/README.md +56 -37
- data/fortnox-api.gemspec +9 -6
- data/lib/fortnox/api.rb +18 -2
- data/lib/fortnox/api/base.rb +5 -3
- data/lib/fortnox/api/environment_validation.rb +51 -6
- data/lib/fortnox/api/mappers.rb +49 -0
- data/lib/fortnox/api/mappers/base.rb +47 -0
- data/lib/fortnox/api/mappers/base/from_json.rb +78 -0
- data/lib/fortnox/api/mappers/base/to_json.rb +65 -0
- data/lib/fortnox/api/mappers/customer.rb +27 -0
- data/lib/fortnox/api/mappers/default_delivery_types.rb +13 -0
- data/lib/fortnox/api/mappers/default_templates.rb +15 -0
- data/lib/fortnox/api/mappers/edi_information.rb +22 -0
- data/lib/fortnox/api/mappers/email_information.rb +18 -0
- data/lib/fortnox/api/mappers/invoice.rb +27 -0
- data/lib/fortnox/api/mappers/invoice_row.rb +20 -0
- data/lib/fortnox/api/mappers/order.rb +23 -0
- data/lib/fortnox/api/mappers/order_row.rb +16 -0
- data/lib/fortnox/api/models.rb +2 -0
- data/lib/fortnox/api/models/base.rb +56 -13
- data/lib/fortnox/api/models/customer.rb +112 -101
- data/lib/fortnox/api/models/document_base.rb +189 -0
- data/lib/fortnox/api/models/invoice.rb +29 -195
- data/lib/fortnox/api/models/label.rb +17 -0
- data/lib/fortnox/api/models/order.rb +27 -0
- data/lib/fortnox/api/repositories.rb +2 -0
- data/lib/fortnox/api/repositories/base.rb +4 -5
- data/lib/fortnox/api/repositories/base/loaders.rb +22 -14
- data/lib/fortnox/api/repositories/base/savers.rb +30 -16
- data/lib/fortnox/api/repositories/customer.rb +3 -25
- data/lib/fortnox/api/repositories/invoice.rb +3 -22
- data/lib/fortnox/api/repositories/order.rb +16 -0
- data/lib/fortnox/api/request_handling.rb +3 -3
- data/lib/fortnox/api/types.rb +44 -0
- data/lib/fortnox/api/types/default_delivery_types.rb +20 -0
- data/lib/fortnox/api/types/default_templates.rb +23 -0
- data/lib/fortnox/api/types/defaulted.rb +11 -0
- data/lib/fortnox/api/types/document_row.rb +65 -0
- data/lib/fortnox/api/types/edi_information.rb +29 -0
- data/lib/fortnox/api/types/email_information.rb +26 -0
- data/lib/fortnox/api/types/enums.rb +75 -0
- data/lib/fortnox/api/types/invoice_row.rb +19 -0
- data/lib/fortnox/api/types/model.rb +40 -0
- data/lib/fortnox/api/types/nullable.rb +21 -0
- data/lib/fortnox/api/types/order_row.rb +16 -0
- data/lib/fortnox/api/types/required.rb +13 -0
- data/lib/fortnox/api/types/sized.rb +25 -0
- data/lib/fortnox/api/version.rb +1 -1
- data/spec/fortnox/api/base_spec.rb +85 -14
- data/spec/fortnox/api/mappers/base/from_json_spec.rb +70 -0
- data/spec/fortnox/api/mappers/base/to_json_spec.rb +76 -0
- data/spec/fortnox/api/mappers/base_spec.rb +156 -0
- data/spec/fortnox/api/mappers/contexts/json_conversion.rb +56 -0
- data/spec/fortnox/api/mappers/customer_spec.rb +25 -0
- data/spec/fortnox/api/mappers/default_delivery_types_spec.rb +12 -0
- data/spec/fortnox/api/mappers/edi_information_spec.rb +21 -0
- data/spec/fortnox/api/mappers/email_information_spec.rb +17 -0
- data/spec/fortnox/api/mappers/examples/mapper.rb +26 -0
- data/spec/fortnox/api/mappers/invoice_row_spec.rb +19 -0
- data/spec/fortnox/api/mappers/invoice_spec.rb +24 -0
- data/spec/fortnox/api/mappers/order_row_spec.rb +14 -0
- data/spec/fortnox/api/mappers/order_spec.rb +20 -0
- data/spec/fortnox/api/models/base_spec.rb +44 -22
- data/spec/fortnox/api/models/customer_spec.rb +9 -0
- data/spec/fortnox/api/models/examples/document_base.rb +13 -0
- data/spec/fortnox/api/models/examples/model.rb +13 -0
- data/spec/fortnox/api/models/invoice_spec.rb +7 -31
- data/spec/fortnox/api/models/order_spec.rb +13 -0
- data/spec/fortnox/api/repositories/customer_spec.rb +20 -76
- data/spec/fortnox/api/repositories/examples/all.rb +17 -0
- data/spec/fortnox/api/repositories/examples/find.rb +25 -0
- data/spec/fortnox/api/repositories/examples/only.rb +42 -0
- data/spec/fortnox/api/repositories/examples/save.rb +69 -0
- data/spec/fortnox/api/repositories/examples/save_with_nested_model.rb +32 -0
- data/spec/fortnox/api/repositories/examples/save_with_specially_named_attribute.rb +27 -0
- data/spec/fortnox/api/repositories/examples/search.rb +31 -0
- data/spec/fortnox/api/repositories/invoice_spec.rb +36 -5
- data/spec/fortnox/api/repositories/order_spec.rb +35 -0
- data/spec/fortnox/api/types/account_number_spec.rb +28 -0
- data/spec/fortnox/api/types/default_delivery_types_spec.rb +10 -0
- data/spec/fortnox/api/types/edi_information_spec.rb +13 -0
- data/spec/fortnox/api/types/email_information_spec.rb +13 -0
- data/spec/fortnox/api/types/email_spec.rb +29 -0
- data/spec/fortnox/api/types/enums_spec.rb +13 -0
- data/spec/fortnox/api/types/examples/document_row.rb +15 -0
- data/spec/fortnox/api/types/examples/enum.rb +48 -0
- data/spec/fortnox/api/types/examples/types.rb +9 -0
- data/spec/fortnox/api/types/house_work_types_spec.rb +60 -0
- data/spec/fortnox/api/types/invoice_row_spec.rb +9 -0
- data/spec/fortnox/api/types/model_spec.rb +56 -0
- data/spec/fortnox/api/types/nullable_spec.rb +57 -0
- data/spec/fortnox/api/types/order_row_spec.rb +13 -0
- data/spec/fortnox/api/types/required_spec.rb +42 -0
- data/spec/fortnox/api/types/sized_spec.rb +74 -0
- data/spec/fortnox/api_spec.rb +16 -15
- data/spec/spec_helper.rb +19 -9
- data/spec/support/helpers/dummy_class_helper.rb +19 -0
- data/spec/support/helpers/environment_helper.rb +7 -0
- data/spec/support/helpers/repository_helper.rb +8 -0
- data/spec/support/helpers/when_performing_helper.rb +5 -0
- data/spec/support/matchers.rb +1 -1
- data/spec/support/matchers/type.rb +17 -0
- data/spec/support/matchers/type/attribute_matcher.rb +39 -0
- data/spec/support/matchers/type/enum_matcher.rb +21 -0
- data/spec/support/matchers/type/have_account_number_matcher.rb +21 -0
- data/spec/support/matchers/type/have_country_code_matcher.rb +13 -0
- data/spec/support/matchers/type/have_currency_matcher.rb +7 -0
- data/spec/support/matchers/type/have_customer_type_matcher.rb +13 -0
- data/spec/support/matchers/type/have_default_delivery_type_matcher.rb +7 -0
- data/spec/support/matchers/type/have_discount_type_matcher.rb +7 -0
- data/spec/support/matchers/type/have_email_matcher.rb +22 -0
- data/spec/support/matchers/type/have_house_work_type_matcher.rb +7 -0
- data/spec/support/matchers/type/have_nullable_date_matcher.rb +58 -0
- data/spec/support/matchers/type/have_nullable_matcher.rb +52 -0
- data/spec/support/matchers/type/have_nullable_string_matcher.rb +49 -0
- data/spec/support/matchers/type/have_sized_float_matcher.rb +8 -0
- data/spec/support/matchers/type/have_sized_integer_matcher.rb +8 -0
- data/spec/support/matchers/type/have_sized_string_matcher.rb +35 -0
- data/spec/support/matchers/type/have_vat_type_matcher.rb +7 -0
- data/spec/support/matchers/type/numeric_matcher.rb +50 -0
- data/spec/support/matchers/type/require_attribute_matcher.rb +69 -0
- data/spec/support/matchers/type/type_matcher.rb +38 -0
- data/spec/vcr_cassettes/customers/all.yml +119 -9
- data/spec/vcr_cassettes/customers/find_id_1.yml +8 -9
- data/spec/vcr_cassettes/customers/find_new.yml +46 -0
- data/spec/vcr_cassettes/customers/save_new.yml +9 -11
- data/spec/vcr_cassettes/customers/save_old.yml +9 -12
- data/spec/vcr_cassettes/customers/save_with_specially_named_attribute.yml +45 -0
- data/spec/vcr_cassettes/customers/search_by_name.yml +66 -0
- data/spec/vcr_cassettes/customers/search_miss.yml +45 -0
- data/spec/vcr_cassettes/invoices/all.yml +104 -0
- data/spec/vcr_cassettes/invoices/filter_hit.yml +46 -0
- data/spec/vcr_cassettes/invoices/filter_invalid.yml +42 -0
- data/spec/vcr_cassettes/invoices/find_id_1.yml +47 -0
- data/spec/vcr_cassettes/invoices/find_new.yml +49 -0
- data/spec/vcr_cassettes/invoices/save_new.yml +48 -0
- data/spec/vcr_cassettes/invoices/save_old.yml +49 -0
- data/spec/vcr_cassettes/invoices/save_with_nested_model.yml +47 -0
- data/spec/vcr_cassettes/invoices/save_with_specially_named_attribute.yml +47 -0
- data/spec/vcr_cassettes/invoices/search_by_name.yml +48 -0
- data/spec/vcr_cassettes/invoices/search_miss.yml +45 -0
- data/spec/vcr_cassettes/orders/all.yml +144 -0
- data/spec/vcr_cassettes/orders/filter_hit.yml +48 -0
- data/spec/vcr_cassettes/orders/filter_invalid.yml +42 -0
- data/spec/vcr_cassettes/orders/find_id_1.yml +48 -0
- data/spec/vcr_cassettes/orders/find_new.yml +49 -0
- data/spec/vcr_cassettes/orders/house_work_type_babysitting.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_cleaning.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_construction.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_cooking.yml +43 -0
- data/spec/vcr_cassettes/orders/house_work_type_electricity.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_gardening.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_glassmetalwork.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_grounddrainagework.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_hvac.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_masonry.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_othercare.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_othercosts.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_paintingwallpapering.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_snowplowing.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_textileclothing.yml +47 -0
- data/spec/vcr_cassettes/orders/house_work_type_tutoring.yml +43 -0
- data/spec/vcr_cassettes/orders/save_new.yml +48 -0
- data/spec/vcr_cassettes/orders/save_old.yml +49 -0
- data/spec/vcr_cassettes/orders/save_with_nested_model.yml +47 -0
- data/spec/vcr_cassettes/orders/search_by_name.yml +47 -0
- data/spec/vcr_cassettes/orders/search_miss.yml +45 -0
- metadata +301 -71
- data/lib/fortnox/api/models/attributes/country_code.rb +0 -17
- data/lib/fortnox/api/models/attributes/currency.rb +0 -17
- data/lib/fortnox/api/models/edi_information.rb +0 -28
- data/lib/fortnox/api/models/email_information.rb +0 -25
- data/lib/fortnox/api/models/row.rb +0 -82
- data/lib/fortnox/api/repositories/base/json_convertion.rb +0 -68
- data/lib/fortnox/api/repositories/base/options.rb +0 -33
- data/lib/fortnox/api/validators.rb +0 -1
- data/lib/fortnox/api/validators/attributes/country_code.rb +0 -42
- data/lib/fortnox/api/validators/attributes/currency.rb +0 -38
- data/lib/fortnox/api/validators/base.rb +0 -70
- data/lib/fortnox/api/validators/constant.rb +0 -21
- data/lib/fortnox/api/validators/customer.rb +0 -29
- data/lib/fortnox/api/validators/edi_information.rb +0 -11
- data/lib/fortnox/api/validators/email_information.rb +0 -19
- data/lib/fortnox/api/validators/invoice.rb +0 -33
- data/lib/fortnox/api/validators/row.rb +0 -22
- data/spec/fortnox/api/models/attributes/country_code_spec.rb +0 -23
- data/spec/fortnox/api/models/attributes/currency_spec.rb +0 -23
- data/spec/fortnox/api/models/attributes/dummy_model_context.rb +0 -9
- data/spec/fortnox/api/models/row_spec.rb +0 -13
- data/spec/fortnox/api/repositories/context.rb +0 -10
- data/spec/fortnox/api/repositories/examples.rb +0 -16
- data/spec/fortnox/api/validators/attributes/country_code_spec.rb +0 -9
- data/spec/fortnox/api/validators/attributes/currency_spec.rb +0 -9
- data/spec/fortnox/api/validators/attributes/examples_for_validate.rb +0 -29
- data/spec/fortnox/api/validators/base_spec.rb +0 -61
- data/spec/fortnox/api/validators/constant_spec.rb +0 -12
- data/spec/fortnox/api/validators/context.rb +0 -102
- data/spec/fortnox/api/validators/customer_spec.rb +0 -31
- data/spec/fortnox/api/validators/edi_information_spec.rb +0 -18
- data/spec/fortnox/api/validators/email_information_spec.rb +0 -26
- data/spec/fortnox/api/validators/invoice_spec.rb +0 -36
- data/spec/fortnox/api/validators/row_spec.rb +0 -27
- data/spec/fortnox/api/validators/validator_examples.rb +0 -20
- data/spec/support/matchers/models.rb +0 -27
- data/spec/support/matchers/validators.rb +0 -36
data/fortnox-api.gemspec
CHANGED
@@ -6,12 +6,12 @@ require 'fortnox/api/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "fortnox-api"
|
8
8
|
spec.version = Fortnox::API::VERSION
|
9
|
-
spec.authors = ["Jonas Schubert Erlandsson"]
|
9
|
+
spec.authors = ["Jonas Schubert Erlandsson", "Hannes Elvemyr"]
|
10
10
|
spec.email = ["jonas.schubert.erlandsson@my-codeworks.com"]
|
11
11
|
spec.summary = "Gem to use Fortnox REST API in Ruby."
|
12
12
|
spec.description = "This gem uses the HTTParty library to abstract away the REST calls. It gives you access to a number of objects that behave a lot like ActiveRecord instances, giving you access to methods like `all`, `find`, `find_by_...` and so on. And each individual instance can be easaly persistable to Fortnox again using the `save` method."
|
13
13
|
spec.homepage = "http://github.com/my-codeworks/fortnox-api"
|
14
|
-
spec.license = "
|
14
|
+
spec.license = "LGPL-3.0"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}){ |f| File.basename(f) }
|
@@ -20,17 +20,20 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_dependency "httparty", "~> 0.13"
|
22
22
|
spec.add_dependency "dotenv", "~> 2.0"
|
23
|
-
spec.add_dependency "
|
24
|
-
spec.add_dependency "
|
23
|
+
spec.add_dependency "dry-struct", "~> 0.1"
|
24
|
+
spec.add_dependency "dry-types", "~> 0.8"
|
25
25
|
|
26
26
|
spec.add_development_dependency "bundler", "~> 1.9"
|
27
27
|
spec.add_development_dependency "rake", "~> 10.4"
|
28
28
|
spec.add_development_dependency "rspec", "~> 3.2"
|
29
|
+
spec.add_development_dependency "rspec-collection_matchers", "~> 0"
|
29
30
|
spec.add_development_dependency "guard", "~> 2.12"
|
30
31
|
spec.add_development_dependency "guard-rspec", "~> 4.5"
|
31
32
|
spec.add_development_dependency "webmock", "~> 1.21"
|
32
33
|
spec.add_development_dependency "vcr", "~> 3.0"
|
33
|
-
spec.add_development_dependency "pry"
|
34
|
-
spec.add_development_dependency "codeclimate-test-reporter"
|
34
|
+
spec.add_development_dependency "pry", "~> 0"
|
35
|
+
spec.add_development_dependency "codeclimate-test-reporter", "~> 0"
|
36
|
+
spec.add_development_dependency "rubocop", "~> 0.41"
|
37
|
+
spec.add_development_dependency "rubocop-rspec", "~> 1.7"
|
35
38
|
|
36
39
|
end
|
data/lib/fortnox/api.rb
CHANGED
@@ -1,28 +1,44 @@
|
|
1
1
|
require "set"
|
2
2
|
require "dotenv"
|
3
|
+
require "dry-struct"
|
3
4
|
require "fortnox/api/base"
|
4
5
|
require "fortnox/api/version"
|
6
|
+
require 'logger'
|
5
7
|
|
6
8
|
Dotenv.load unless ENV['RUBY_ENV'] == 'test'
|
7
9
|
|
8
10
|
module Fortnox
|
9
11
|
module API
|
10
12
|
|
11
|
-
class
|
13
|
+
class Exception < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
class AttributeError < Fortnox::API::Exception
|
17
|
+
end
|
18
|
+
|
19
|
+
class RemoteServerError < Fortnox::API::Exception
|
20
|
+
end
|
21
|
+
|
22
|
+
class MissingAttributeError < Fortnox::API::Exception
|
12
23
|
end
|
13
24
|
|
14
25
|
class << self
|
15
26
|
@debugging = false
|
27
|
+
@logger = Logger.new(STDOUT)
|
16
28
|
attr_accessor :debugging
|
29
|
+
attr_accessor :logger
|
30
|
+
|
31
|
+
@logger.level = Logger::WARN
|
17
32
|
end
|
18
33
|
|
19
34
|
def self.get_access_token
|
20
35
|
Base.get_access_token
|
21
36
|
end
|
22
37
|
|
38
|
+
Registry = Dry::Container.new
|
23
39
|
end
|
24
40
|
end
|
25
41
|
|
26
42
|
require "fortnox/api/models"
|
27
43
|
require "fortnox/api/repositories"
|
28
|
-
require "fortnox/api/
|
44
|
+
require "fortnox/api/mappers"
|
data/lib/fortnox/api/base.rb
CHANGED
@@ -17,9 +17,9 @@ module Fortnox
|
|
17
17
|
DEFAULT_HEADERS = {
|
18
18
|
'Content-Type' => 'application/json',
|
19
19
|
'Accept' => 'application/json',
|
20
|
-
}
|
20
|
+
}.freeze
|
21
21
|
|
22
|
-
HTTP_METHODS = [ :get, :put, :post, :delete ]
|
22
|
+
HTTP_METHODS = [ :get, :put, :post, :delete ].freeze
|
23
23
|
|
24
24
|
attr_accessor :headers
|
25
25
|
|
@@ -28,12 +28,14 @@ module Fortnox
|
|
28
28
|
|
29
29
|
self.headers = DEFAULT_HEADERS.merge({
|
30
30
|
'Client-Secret' => get_client_secret,
|
31
|
-
'Access-Token' => get_access_token,
|
32
31
|
})
|
32
|
+
|
33
|
+
check_access_tokens!
|
33
34
|
end
|
34
35
|
|
35
36
|
HTTP_METHODS.each do |method|
|
36
37
|
define_method method do |*args|
|
38
|
+
self.headers['Access-Token'] = get_access_token
|
37
39
|
execute do |remote|
|
38
40
|
remote.send( method, *args )
|
39
41
|
end
|
@@ -1,33 +1,78 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
1
3
|
module Fortnox
|
2
4
|
module API
|
3
5
|
module EnvironmentValidation
|
4
6
|
|
7
|
+
class MissingEnvironmentVariable < ArgumentError
|
8
|
+
end
|
9
|
+
|
10
|
+
class CircularQueue
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
def initialize *items
|
14
|
+
@queue = [ *items ]
|
15
|
+
@@next_index = random_start_index
|
16
|
+
end
|
17
|
+
|
18
|
+
# support some general Array methods that fit Queues well
|
19
|
+
def_delegators :@queue, :new, :[], :size
|
20
|
+
|
21
|
+
def next
|
22
|
+
value = @queue[ @@next_index ]
|
23
|
+
if @@next_index == size - 1
|
24
|
+
@@next_index = 0
|
25
|
+
else
|
26
|
+
@@next_index += 1
|
27
|
+
end
|
28
|
+
return value
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def random_start_index
|
34
|
+
Random.rand(@queue.size)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
5
38
|
private
|
6
39
|
|
7
40
|
def get_base_url
|
8
41
|
base_url = ENV['FORTNOX_API_BASE_URL']
|
9
|
-
fail
|
42
|
+
fail MissingEnvironmentVariable, 'You have to provide a base url.' unless base_url
|
10
43
|
base_url
|
11
44
|
end
|
12
45
|
|
13
46
|
def get_client_secret
|
14
47
|
client_secret = ENV['FORTNOX_API_CLIENT_SECRET']
|
15
|
-
fail
|
48
|
+
fail MissingEnvironmentVariable, 'You have to provide your client secret.' unless client_secret
|
16
49
|
client_secret
|
17
50
|
end
|
18
51
|
|
19
52
|
def get_access_token
|
20
|
-
|
21
|
-
|
22
|
-
access_token
|
53
|
+
@access_tokens ||= load_access_tokens
|
54
|
+
@access_tokens.next
|
23
55
|
end
|
24
56
|
|
25
57
|
def get_authorization_code
|
26
58
|
authorization_code = ENV['FORTNOX_API_AUTHORIZATION_CODE']
|
27
|
-
fail
|
59
|
+
fail MissingEnvironmentVariable, 'You have to provide your authorization code.' unless authorization_code
|
28
60
|
authorization_code
|
29
61
|
end
|
30
62
|
|
63
|
+
def load_access_tokens
|
64
|
+
check_access_tokens!
|
65
|
+
access_token_string = ENV['FORTNOX_API_ACCESS_TOKEN']
|
66
|
+
access_tokens = access_token_string.split(",").map(&:strip)
|
67
|
+
CircularQueue.new( *access_tokens )
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_access_tokens!
|
71
|
+
unless ENV['FORTNOX_API_ACCESS_TOKEN']
|
72
|
+
fail MissingEnvironmentVariable, 'You have to provide your access token.'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
31
76
|
end
|
32
77
|
end
|
33
78
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'fortnox/api/types'
|
2
|
+
|
3
|
+
module Fortnox
|
4
|
+
module API
|
5
|
+
module Mapper
|
6
|
+
Identity = ->(value){ value }
|
7
|
+
|
8
|
+
Date = ->(value){ value.to_s }
|
9
|
+
|
10
|
+
Array = ->(array) do
|
11
|
+
array.each_with_object( [] ) do |item, converted_array|
|
12
|
+
name = Fortnox::API::Mapper::Base.canonical_name_sym( item )
|
13
|
+
converted_array << Fortnox::API::Registry[ name ].call( item )
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Registry.register( :fixnum, Fortnox::API::Mapper::Identity )
|
18
|
+
Registry.register( :int, Fortnox::API::Mapper::Identity )
|
19
|
+
Registry.register( :float, Fortnox::API::Mapper::Identity )
|
20
|
+
Registry.register( :string, Fortnox::API::Mapper::Identity )
|
21
|
+
Registry.register( :boolean, Fortnox::API::Mapper::Identity )
|
22
|
+
Registry.register( :falseclass, Fortnox::API::Mapper::Identity )
|
23
|
+
Registry.register( :trueclass, Fortnox::API::Mapper::Identity )
|
24
|
+
Registry.register( :nilclass, Fortnox::API::Mapper::Identity )
|
25
|
+
Registry.register( :array, Fortnox::API::Mapper::Array )
|
26
|
+
Registry.register( :date, Fortnox::API::Mapper::Date )
|
27
|
+
|
28
|
+
Registry.register( :account_number, Fortnox::API::Mapper::Identity )
|
29
|
+
Registry.register( :country_code, Fortnox::API::Mapper::Identity )
|
30
|
+
Registry.register( :currency, Fortnox::API::Mapper::Identity )
|
31
|
+
Registry.register( :customer_type, Fortnox::API::Mapper::Identity )
|
32
|
+
Registry.register( :discount_type, Fortnox::API::Mapper::Identity )
|
33
|
+
Registry.register( :email, Fortnox::API::Mapper::Identity )
|
34
|
+
Registry.register( :house_work_type, Fortnox::API::Mapper::Identity )
|
35
|
+
Registry.register( :vat_type, Fortnox::API::Mapper::Identity )
|
36
|
+
Registry.register( :labels, Fortnox::API::Mapper::Array )
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
require 'fortnox/api/mappers/customer'
|
42
|
+
require 'fortnox/api/mappers/default_delivery_types'
|
43
|
+
require 'fortnox/api/mappers/default_templates'
|
44
|
+
require 'fortnox/api/mappers/edi_information'
|
45
|
+
require 'fortnox/api/mappers/email_information'
|
46
|
+
require 'fortnox/api/mappers/invoice_row'
|
47
|
+
require 'fortnox/api/mappers/invoice'
|
48
|
+
require 'fortnox/api/mappers/order_row'
|
49
|
+
require 'fortnox/api/mappers/order'
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "fortnox/api/mappers/base/from_json"
|
2
|
+
require "fortnox/api/mappers/base/to_json"
|
3
|
+
|
4
|
+
module Fortnox
|
5
|
+
module API
|
6
|
+
module Mapper
|
7
|
+
class Base
|
8
|
+
include FromJSON
|
9
|
+
include ToJSON
|
10
|
+
|
11
|
+
Hash = ->(hash) do
|
12
|
+
hash.each do |key, value|
|
13
|
+
name = Fortnox::API::Mapper::Base.canonical_name_sym( value )
|
14
|
+
hash[key] = Fortnox::API::Registry[ name ].call( value )
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Registry.register( :hash, Fortnox::API::Mapper::Base::Hash )
|
19
|
+
|
20
|
+
def self.canonical_name_sym( *values )
|
21
|
+
klass = if values.empty?
|
22
|
+
self
|
23
|
+
elsif values.first.is_a? Class
|
24
|
+
values.first
|
25
|
+
else
|
26
|
+
values.first.class
|
27
|
+
end
|
28
|
+
|
29
|
+
klass.name.split('::').last.downcase.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
def diff( entity_hash, parent_hash )
|
33
|
+
hash_diff( entity_hash[self.class::JSON_ENTITY_WRAPPER],
|
34
|
+
parent_hash[self.class::JSON_ENTITY_WRAPPER] )
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def hash_diff( hash1, hash2 )
|
40
|
+
hash1.dup.
|
41
|
+
delete_if{ |k, v| hash2[k] == v }.
|
42
|
+
merge!(hash2.dup.delete_if{ |k, _| hash1.has_key?(k) })
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Fortnox
|
2
|
+
module API
|
3
|
+
module Mapper
|
4
|
+
module FromJSON
|
5
|
+
|
6
|
+
class MissingModelOrMapperException < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
def wrapped_json_collection_to_entities_hash( json_collection_hash )
|
10
|
+
entities_hash = []
|
11
|
+
json_collection_hash[ self.class::JSON_COLLECTION_WRAPPER ].each do |json_hash|
|
12
|
+
entities_hash << json_hash_to_entity_hash( json_hash, self.class::KEY_MAP )
|
13
|
+
end
|
14
|
+
|
15
|
+
entities_hash
|
16
|
+
end
|
17
|
+
|
18
|
+
def wrapped_json_hash_to_entity_hash( json_entity_hash )
|
19
|
+
json_hash_to_entity_hash( json_entity_hash[self.class::JSON_ENTITY_WRAPPER],
|
20
|
+
self.class::KEY_MAP )
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def json_hash_to_entity_hash( hash, key_map )
|
26
|
+
hash.each_with_object( {} ) do |(key, value), json_hash|
|
27
|
+
converted_key = convert_key_from_json( key, key_map )
|
28
|
+
json_hash[converted_key] =
|
29
|
+
if value.respond_to?(:each)
|
30
|
+
convert_collection( key, value )
|
31
|
+
else
|
32
|
+
value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def convert_collection( key, collection )
|
38
|
+
mapper_name = key.downcase
|
39
|
+
if Registry.key?(mapper_name)
|
40
|
+
convert_nested_data( mapper_name, key, collection )
|
41
|
+
else
|
42
|
+
# NOTE: This probably means this is a nested model that we have
|
43
|
+
# not implemented yet, or that is missing a mapper.
|
44
|
+
# Raise exception during test run if this happens so that we can
|
45
|
+
# add it before a new release.
|
46
|
+
|
47
|
+
raise MissingModelOrMapperException, "for #{ key } (#{ mapper_name }, #{ Fortnox::API::Mapper::DefaultTemplates.canonical_name_sym }) with #{ collection }" if ENV['RUBY_ENV']
|
48
|
+
Fortnox::API.logger.warn( "Missing Model or Mapper implementation for #{ key } with attributes: #{ collection }" )
|
49
|
+
return convert_hash_keys_from_json_format( collection, {} )
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def convert_nested_data( _mapper_name, key, nested_data )
|
54
|
+
nested_mapper = Registry[ key.downcase ]
|
55
|
+
if nested_data.is_a?(::Array) # Array of nested models
|
56
|
+
return nested_data.each_with_object( [] ) do |value, nested_models|
|
57
|
+
nested_models << json_hash_to_entity_hash( value, nested_mapper::KEY_MAP )
|
58
|
+
end
|
59
|
+
else # Assume Hash of nested model
|
60
|
+
return json_hash_to_entity_hash( nested_data, nested_mapper::KEY_MAP )
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def convert_key_from_json( key, key_map )
|
65
|
+
key_map.key( key ) || default_key_from_json_transform( key )
|
66
|
+
end
|
67
|
+
|
68
|
+
def default_key_from_json_transform( key )
|
69
|
+
key = key.to_s
|
70
|
+
unless key =~ /\A[A-Z]+\z/
|
71
|
+
key = key.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z])([A-Z])/, '\1_\2')
|
72
|
+
end
|
73
|
+
key.downcase.to_sym
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Fortnox
|
2
|
+
module API
|
3
|
+
module Mapper
|
4
|
+
module ToJSON
|
5
|
+
def self.included(base)
|
6
|
+
base.instance_eval do
|
7
|
+
|
8
|
+
# PUBLIC
|
9
|
+
|
10
|
+
def call( entity, keys_to_filter = {} )
|
11
|
+
entity_hash = entity.to_hash
|
12
|
+
clean_entity_hash = sanitise( entity_hash, keys_to_filter )
|
13
|
+
clean_entity_hash = convert_hash_keys_to_json_format( clean_entity_hash )
|
14
|
+
Registry[:hash].call( clean_entity_hash )
|
15
|
+
end
|
16
|
+
|
17
|
+
# PRIVATE
|
18
|
+
|
19
|
+
def convert_hash_keys_to_json_format( hash )
|
20
|
+
hash.each_with_object( {} ) do |(key, value), json_hash|
|
21
|
+
json_hash[ convert_key_to_json( key ) ] = value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def convert_key_to_json( key )
|
26
|
+
self::KEY_MAP.fetch( key ){ default_key_to_json_transform( key ) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_key_to_json_transform( key )
|
30
|
+
key.to_s.split('_').map(&:capitalize).join('')
|
31
|
+
end
|
32
|
+
|
33
|
+
def sanitise( hash, keys_to_filter )
|
34
|
+
hash.select do |key, value|
|
35
|
+
next false if keys_to_filter.include?( key )
|
36
|
+
value != nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private_class_method :convert_hash_keys_to_json_format,
|
41
|
+
:convert_key_to_json,
|
42
|
+
:default_key_to_json_transform,
|
43
|
+
:sanitise
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def entity_to_hash( entity, keys_to_filter )
|
48
|
+
entity_json_hash = Registry[ mapper_name_for( entity ) ]
|
49
|
+
.call( entity, keys_to_filter )
|
50
|
+
wrapp_entity_json_hash( entity_json_hash )
|
51
|
+
end
|
52
|
+
|
53
|
+
def wrapp_entity_json_hash( entity_json_hash )
|
54
|
+
{ self.class::JSON_ENTITY_WRAPPER => entity_json_hash }
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def mapper_name_for( value )
|
60
|
+
value.class.name.split('::').last.downcase.to_sym
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "fortnox/api/mappers/base"
|
2
|
+
|
3
|
+
module Fortnox
|
4
|
+
module API
|
5
|
+
module Mapper
|
6
|
+
class Customer < Fortnox::API::Mapper::Base
|
7
|
+
|
8
|
+
KEY_MAP = {
|
9
|
+
vat_type: 'VATType',
|
10
|
+
vat_number: 'VATNumber',
|
11
|
+
email_invoice_bcc: 'EmailInvoiceBCC',
|
12
|
+
email_invoice_cc: 'EmailInvoiceCC',
|
13
|
+
email_offer_bcc: 'EmailOfferBCC',
|
14
|
+
email_offer_cc: 'EmailOfferCC',
|
15
|
+
email_order_bcc: 'EmailOrderBCC',
|
16
|
+
email_order_cc: 'EmailOrderCC',
|
17
|
+
show_price_vat_included: 'ShowPriceVATIncluded',
|
18
|
+
}.freeze
|
19
|
+
JSON_ENTITY_WRAPPER = 'Customer'.freeze
|
20
|
+
JSON_COLLECTION_WRAPPER = 'Customers'.freeze
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
Registry.register( Customer.canonical_name_sym, Customer )
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|