fortnox-api 0.2.0 → 0.3.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/.gitignore +3 -0
- data/.travis.yml +1 -1
- data/fortnox-api.gemspec +3 -1
- data/lib/fortnox/api/mappers.rb +1 -0
- data/lib/fortnox/api/mappers/project.rb +15 -0
- data/lib/fortnox/api/models.rb +1 -0
- data/lib/fortnox/api/models/base.rb +1 -1
- data/lib/fortnox/api/models/customer.rb +0 -0
- data/lib/fortnox/api/models/project.rb +40 -0
- data/lib/fortnox/api/repositories.rb +1 -0
- data/lib/fortnox/api/repositories/base.rb +1 -1
- data/lib/fortnox/api/repositories/base/loaders.rb +13 -10
- data/lib/fortnox/api/repositories/base/savers.rb +3 -3
- data/lib/fortnox/api/repositories/project.rb +15 -0
- data/lib/fortnox/api/types.rb +2 -0
- data/lib/fortnox/api/types/enums.rb +3 -0
- data/lib/fortnox/api/version.rb +1 -1
- data/spec/fortnox/api/mappers/project_spec.rb +10 -0
- data/spec/fortnox/api/models/customer_spec.rb +1 -3
- data/spec/fortnox/api/models/examples/document_base.rb +2 -2
- data/spec/fortnox/api/models/examples/model.rb +11 -5
- data/spec/fortnox/api/models/invoice_spec.rb +1 -4
- data/spec/fortnox/api/models/order_spec.rb +0 -3
- data/spec/fortnox/api/models/project_spec.rb +7 -0
- data/spec/fortnox/api/repositories/customer_spec.rb +8 -1
- data/spec/fortnox/api/repositories/examples/find.rb +65 -10
- data/spec/fortnox/api/repositories/examples/search.rb +11 -0
- data/spec/fortnox/api/repositories/invoice_spec.rb +11 -1
- data/spec/fortnox/api/repositories/order_spec.rb +11 -1
- data/spec/fortnox/api/repositories/project_spec.rb +29 -0
- data/spec/fortnox/api/types/enums_spec.rb +1 -0
- data/spec/vcr_cassettes/customers/find_by_hash_failure.yml +45 -0
- data/spec/vcr_cassettes/customers/find_failure.yml +45 -0
- data/spec/vcr_cassettes/customers/multi_param_find_by_hash.yml +46 -0
- data/spec/vcr_cassettes/customers/search_with_special_char.yml +45 -0
- data/spec/vcr_cassettes/customers/single_param_find_by_hash.yml +47 -0
- data/spec/vcr_cassettes/invoices/find_by_hash_failure.yml +45 -0
- data/spec/vcr_cassettes/invoices/find_failure.yml +45 -0
- data/spec/vcr_cassettes/invoices/multi_param_find_by_hash.yml +46 -0
- data/spec/vcr_cassettes/invoices/search_with_special_char.yml +45 -0
- data/spec/vcr_cassettes/invoices/single_param_find_by_hash.yml +47 -0
- data/spec/vcr_cassettes/orders/find_by_hash_failure.yml +45 -0
- data/spec/vcr_cassettes/orders/find_failure.yml +45 -0
- data/spec/vcr_cassettes/orders/multi_param_find_by_hash.yml +46 -0
- data/spec/vcr_cassettes/orders/search_with_special_char.yml +45 -0
- data/spec/vcr_cassettes/orders/single_param_find_by_hash.yml +47 -0
- data/spec/vcr_cassettes/projects/all.yml +52 -0
- data/spec/vcr_cassettes/projects/find_by_hash_failure.yml +45 -0
- data/spec/vcr_cassettes/projects/find_failure.yml +45 -0
- data/spec/vcr_cassettes/projects/find_id_1.yml +46 -0
- data/spec/vcr_cassettes/projects/find_new.yml +46 -0
- data/spec/vcr_cassettes/projects/multi_param_find_by_hash.yml +46 -0
- data/spec/vcr_cassettes/projects/save_new.yml +45 -0
- data/spec/vcr_cassettes/projects/save_old.yml +46 -0
- data/spec/vcr_cassettes/projects/single_param_find_by_hash.yml +46 -0
- metadata +66 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 124c4cde46325d41cffa7a3bf092375697cb6b1d
|
4
|
+
data.tar.gz: cb91dde384a1c59e4304f29dc9dbdd9ea0c64d4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f7bc215cb29128bb0c8385c3769f9aa3576006d69ac84d275b8df4a8799583148e73b77a788538ed4d0fee45e700b7144b803b0a3dca4a2cfe430da1206b0de
|
7
|
+
data.tar.gz: d962b0e1dbb2e05900846866f69a585100b59ac993002dfb1bcef7d89dc8887ecb0e6eaa993be1355971d6d7e09cc4ae67b6881b2609b0a3abe260839aae5436
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/fortnox-api.gemspec
CHANGED
@@ -18,7 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(spec)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.
|
21
|
+
spec.required_ruby_version = ['> 2.2', '< 2.4'] # TODO: Gem breaks with Ruby 2.4 or higher. See issue #93.
|
22
|
+
|
23
|
+
spec.add_dependency "httparty", "~> 0.14.0" # TODO: Temporary lockdown. See issue #103 for more info.
|
22
24
|
spec.add_dependency "dotenv", "~> 2.0"
|
23
25
|
spec.add_dependency "dry-struct", "~> 0.1"
|
24
26
|
spec.add_dependency "dry-types", "~> 0.8"
|
data/lib/fortnox/api/mappers.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "fortnox/api/mappers/base"
|
2
|
+
|
3
|
+
module Fortnox
|
4
|
+
module API
|
5
|
+
module Mapper
|
6
|
+
class Project < Fortnox::API::Mapper::Base
|
7
|
+
KEY_MAP = {}.freeze
|
8
|
+
JSON_ENTITY_WRAPPER = 'Project'.freeze
|
9
|
+
JSON_COLLECTION_WRAPPER = 'Projects'.freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
Registry.register( Project.canonical_name_sym, Project )
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/fortnox/api/models.rb
CHANGED
@@ -79,7 +79,7 @@ module Fortnox
|
|
79
79
|
private_class_method
|
80
80
|
|
81
81
|
# dry-types filter anything that isn't specified as an attribute on the
|
82
|
-
# class that is being
|
82
|
+
# class that is being instantiated. This wrapper preserves the meta
|
83
83
|
# properties we need to track object state during that initilisation and
|
84
84
|
# sets them on the object after dry-types is done with it.
|
85
85
|
def self.preserve_meta_properties( hash )
|
File without changes
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "fortnox/api/types"
|
2
|
+
require "fortnox/api/models/base"
|
3
|
+
|
4
|
+
module Fortnox
|
5
|
+
module API
|
6
|
+
module Model
|
7
|
+
class Project < Fortnox::API::Model::Base
|
8
|
+
UNIQUE_ID = :project_number
|
9
|
+
STUB = { description: '' }.freeze
|
10
|
+
|
11
|
+
# Url Direct URL to the record
|
12
|
+
attribute :url, Types::Nullable::String.with( read_only: true )
|
13
|
+
|
14
|
+
# Comments Comments on project. 512 characters
|
15
|
+
attribute :comments, Types::Sized::String[ 512 ]
|
16
|
+
|
17
|
+
# ContactPerson ContactPerson for project. 50 characters
|
18
|
+
attribute :contact_person, Types::Sized::String[ 50 ]
|
19
|
+
|
20
|
+
# Description Description of the project. 50 characters
|
21
|
+
attribute :description, Types::Sized::String[ 50 ]
|
22
|
+
|
23
|
+
# EndDate End date of the project.
|
24
|
+
attribute :end_date, Types::Nullable::Date
|
25
|
+
|
26
|
+
# ProjectLeader Projectleader. 50 characters
|
27
|
+
attribute :project_leader, Types::Sized::String[ 50 ]
|
28
|
+
|
29
|
+
# ProjectNumber Projectnumber. 20 characters
|
30
|
+
attribute :project_number, Types::Sized::String[ 20 ]
|
31
|
+
|
32
|
+
# Status Status of the project
|
33
|
+
attribute :status, Types::ProjectStatusType
|
34
|
+
|
35
|
+
# StartDate Start date of the project
|
36
|
+
attribute :start_date, Types::Nullable::Date
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -7,18 +7,20 @@ module Fortnox
|
|
7
7
|
|
8
8
|
def all()
|
9
9
|
response_hash = get( self.class::URI )
|
10
|
-
|
10
|
+
instantiate_collection_response( response_hash )
|
11
11
|
end
|
12
12
|
|
13
13
|
def only( filter )
|
14
14
|
response_hash = get( "#{ self.class::URI }?filter=#{ filter }" )
|
15
|
-
|
15
|
+
instantiate_collection_response( response_hash )
|
16
16
|
end
|
17
17
|
|
18
18
|
def search( hash )
|
19
19
|
attribute, value = hash.first
|
20
|
-
|
21
|
-
|
20
|
+
uri_encoded_value = URI.encode(value)
|
21
|
+
uri = "#{ self.class::URI }?#{ attribute }=#{ uri_encoded_value }".freeze
|
22
|
+
response_hash = get( uri )
|
23
|
+
instantiate_collection_response( response_hash )
|
22
24
|
end
|
23
25
|
|
24
26
|
def find( id_or_hash )
|
@@ -33,12 +35,13 @@ module Fortnox
|
|
33
35
|
|
34
36
|
def find_one_by( id )
|
35
37
|
response_hash = get( "#{ self.class::URI }#{ id }" )
|
36
|
-
|
38
|
+
instantiate( @mapper.wrapped_json_hash_to_entity_hash( response_hash ) )
|
37
39
|
end
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
|
41
|
+
def find_all_by( hash )
|
42
|
+
response_hash = get( "#{ self.class::URI }?#{ to_query( hash ) }" )
|
43
|
+
instantiate_collection_response( response_hash )
|
44
|
+
end
|
42
45
|
|
43
46
|
def to_query( hash )
|
44
47
|
hash.collect do |key, value|
|
@@ -52,10 +55,10 @@ module Fortnox
|
|
52
55
|
|
53
56
|
private
|
54
57
|
|
55
|
-
def
|
58
|
+
def instantiate_collection_response( response_hash )
|
56
59
|
entities_hash = @mapper.wrapped_json_collection_to_entities_hash( response_hash )
|
57
60
|
entities_hash.map do |entity_hash|
|
58
|
-
|
61
|
+
instantiate( entity_hash )
|
59
62
|
end
|
60
63
|
end
|
61
64
|
|
@@ -14,7 +14,7 @@ module Fortnox
|
|
14
14
|
def execute_save( entity )
|
15
15
|
body = get_changes_on( entity ).to_json
|
16
16
|
result = yield body
|
17
|
-
|
17
|
+
instantiate_saved( result )
|
18
18
|
end
|
19
19
|
|
20
20
|
def save_new( entity )
|
@@ -40,8 +40,8 @@ module Fortnox
|
|
40
40
|
"#{ self.class::URI }#{ entity.unique_id }"
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
|
43
|
+
def instantiate_saved( wrapped_json_hash )
|
44
|
+
instantiate(
|
45
45
|
@mapper.wrapped_json_hash_to_entity_hash(
|
46
46
|
wrapped_json_hash
|
47
47
|
)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "fortnox/api/repositories/base"
|
2
|
+
require "fortnox/api/models/project"
|
3
|
+
require "fortnox/api/mappers/project"
|
4
|
+
|
5
|
+
module Fortnox
|
6
|
+
module API
|
7
|
+
module Repository
|
8
|
+
class Project < Fortnox::API::Repository::Base
|
9
|
+
MODEL = Fortnox::API::Model::Project
|
10
|
+
MAPPER = Fortnox::API::Mapper::Project
|
11
|
+
URI = '/projects/'.freeze
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/fortnox/api/types.rb
CHANGED
@@ -32,6 +32,8 @@ module Fortnox
|
|
32
32
|
|
33
33
|
DefaultDeliveryType = Strict::String.constrained( included_in: DefaultDeliveryTypeValues.values ).optional.constructor( EnumConstructors.default )
|
34
34
|
|
35
|
+
ProjectStatusType = Strict::String.constrained( included_in: ProjectStatusTypes.values ).optional.constructor( EnumConstructors.default )
|
36
|
+
|
35
37
|
require 'fortnox/api/types/model'
|
36
38
|
require 'fortnox/api/types/default_delivery_types'
|
37
39
|
require 'fortnox/api/types/default_templates'
|
data/lib/fortnox/api/version.rb
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fortnox/api'
|
3
|
+
require 'fortnox/api/mappers/project'
|
4
|
+
require 'fortnox/api/mappers/examples/mapper'
|
5
|
+
|
6
|
+
describe Fortnox::API::Mapper::Project do
|
7
|
+
it_behaves_like 'mapper', {}, 'Project', 'Projects' do
|
8
|
+
let(:mapper){ described_class.new }
|
9
|
+
end
|
10
|
+
end
|
@@ -3,7 +3,5 @@ require 'fortnox/api/models/customer'
|
|
3
3
|
require 'fortnox/api/models/examples/model'
|
4
4
|
|
5
5
|
describe Fortnox::API::Model::Customer, type: :model do
|
6
|
-
|
7
|
-
|
8
|
-
it_behaves_like 'a model', valid_hash, :customer_number, '5'
|
6
|
+
it_behaves_like 'a model', '1'
|
9
7
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'fortnox/api/models/examples/model'
|
2
2
|
|
3
|
-
shared_examples_for 'DocumentBase Model' do |row_class, row_attribute,
|
4
|
-
it_behaves_like 'a model',
|
3
|
+
shared_examples_for 'DocumentBase Model' do |row_class, row_attribute, valid_row_hash: {}|
|
4
|
+
it_behaves_like 'a model', 1
|
5
5
|
|
6
6
|
context "when having a(n) #{ row_class }" do
|
7
7
|
it 'returns the correct object' do
|
@@ -1,13 +1,19 @@
|
|
1
|
-
shared_examples_for 'a model' do |
|
1
|
+
shared_examples_for 'a model' do |unique_id|
|
2
|
+
let( :required_attributes ){ described_class::STUB.dup }
|
3
|
+
let( :unique_id_attribute ){ described_class::UNIQUE_ID }
|
4
|
+
|
2
5
|
it 'can be initialized' do
|
3
|
-
expect{ described_class.new(
|
6
|
+
expect{ described_class.new( required_attributes ) }.not_to raise_error
|
4
7
|
end
|
5
8
|
|
6
9
|
describe '.unique_id' do
|
7
|
-
|
10
|
+
subject{ model.unique_id }
|
11
|
+
|
12
|
+
before{ expect(model.send(unique_id_attribute)).to eq unique_id }
|
8
13
|
|
9
|
-
|
14
|
+
let( :attributes ){ required_attributes.merge(unique_id_attribute => unique_id) }
|
15
|
+
let( :model ){ described_class.new( attributes ) }
|
10
16
|
|
11
|
-
it{
|
17
|
+
it{ is_expected.to eq unique_id }
|
12
18
|
end
|
13
19
|
end
|
@@ -3,10 +3,7 @@ require 'fortnox/api/models/invoice'
|
|
3
3
|
require 'fortnox/api/models/examples/document_base'
|
4
4
|
|
5
5
|
describe Fortnox::API::Model::Invoice, type: :model do
|
6
|
-
valid_hash = { customer_number: '12345' }
|
7
|
-
|
8
6
|
it_behaves_like 'DocumentBase Model',
|
9
7
|
Fortnox::API::Types::InvoiceRow,
|
10
|
-
:invoice_rows
|
11
|
-
valid_hash
|
8
|
+
:invoice_rows
|
12
9
|
end
|
@@ -3,11 +3,8 @@ require 'fortnox/api/models/order'
|
|
3
3
|
require 'fortnox/api/models/examples/document_base'
|
4
4
|
|
5
5
|
describe Fortnox::API::Model::Order, type: :model do
|
6
|
-
valid_hash = { customer_number: '12345' }
|
7
|
-
|
8
6
|
it_behaves_like 'DocumentBase Model',
|
9
7
|
Fortnox::API::Types::OrderRow,
|
10
8
|
:order_rows,
|
11
|
-
valid_hash,
|
12
9
|
valid_row_hash: { ordered_quantity: 1.1 }
|
13
10
|
end
|
@@ -23,7 +23,14 @@ describe Fortnox::API::Repository::Customer, order: :defined, integration: true
|
|
23
23
|
# (until 100, which is max by default).
|
24
24
|
include_examples '.all', 100
|
25
25
|
|
26
|
-
include_examples '.find', '1'
|
26
|
+
include_examples '.find', '1' do
|
27
|
+
let( :find_by_hash_failure ){ { city: 'Not Found' } }
|
28
|
+
let( :single_param_find_by_hash ){ { find_hash: { city: 'New York' }, matches: 2 } }
|
29
|
+
|
30
|
+
let( :multi_param_find_by_hash ) do
|
31
|
+
{ find_hash: { city: 'New York', zipcode: '10001' }, matches: 1 }
|
32
|
+
end
|
33
|
+
end
|
27
34
|
|
28
35
|
include_examples '.search', :name, 'Test', 23
|
29
36
|
end
|
@@ -1,24 +1,79 @@
|
|
1
1
|
# rubocop:disable RSpec/DescribeClass
|
2
2
|
shared_examples_for '.find' do |searched_entity_id|
|
3
|
-
describe '.find' do
|
4
|
-
let( :
|
3
|
+
describe '.find by id' do
|
4
|
+
let( :returned_object ) do
|
5
5
|
VCR.use_cassette( "#{ vcr_dir }/find_id_1" ){ repository.find( searched_entity_id ) }
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
context 'when found' do
|
9
|
+
describe 'returned object' do
|
10
|
+
subject{ returned_object }
|
11
|
+
it{ is_expected.to be_saved }
|
12
|
+
it{ is_expected.not_to be_new }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'class' do
|
16
|
+
subject{ returned_object.class }
|
17
|
+
it{ is_expected.to be described_class::MODEL }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'unique id' do
|
21
|
+
subject{ returned_object.unique_id }
|
22
|
+
it{ is_expected.to eq searched_entity_id }
|
23
|
+
end
|
10
24
|
end
|
11
25
|
|
12
|
-
|
13
|
-
|
26
|
+
context 'when not found' do
|
27
|
+
subject{ find_failure }
|
28
|
+
|
29
|
+
let( :not_found_id ){ '123456789' }
|
30
|
+
let( :find_failure ) do
|
31
|
+
when_performing do
|
32
|
+
VCR.use_cassette( "#{ vcr_dir }/find_failure" ){ repository.find( not_found_id ) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it{ is_expected.to raise_error( Fortnox::API::RemoteServerError, /Kan inte hitta /) }
|
14
37
|
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '.find by hash' do
|
41
|
+
context 'when found' do
|
42
|
+
let( :returned_array ) do
|
43
|
+
VCR.use_cassette( "#{ vcr_dir }/#{ cassette }" ){ repository.find( find_hash ) }
|
44
|
+
end
|
15
45
|
|
16
|
-
|
17
|
-
|
46
|
+
context 'with single parameter' do
|
47
|
+
let( :cassette ){ 'single_param_find_by_hash' }
|
48
|
+
let( :find_hash ){ single_param_find_by_hash[:find_hash] }
|
49
|
+
|
50
|
+
describe 'returned array size' do
|
51
|
+
subject{ returned_array.size }
|
52
|
+
it{ is_expected.to eq single_param_find_by_hash[:matches] }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with multiple parameters' do
|
57
|
+
let( :cassette ){ 'multi_param_find_by_hash' }
|
58
|
+
let( :find_hash ){ multi_param_find_by_hash[:find_hash] }
|
59
|
+
|
60
|
+
describe 'returned array size' do
|
61
|
+
subject{ returned_array.size }
|
62
|
+
it{ is_expected.to eq multi_param_find_by_hash[:matches] }
|
63
|
+
end
|
64
|
+
end
|
18
65
|
end
|
19
66
|
|
20
|
-
|
21
|
-
|
67
|
+
context 'when not found' do
|
68
|
+
subject{ find_failure }
|
69
|
+
|
70
|
+
let( :find_failure ) do
|
71
|
+
VCR.use_cassette( "#{ vcr_dir }/find_by_hash_failure" ) do
|
72
|
+
repository.find( find_by_hash_failure )
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it{ is_expected.to eq [] }
|
22
77
|
end
|
23
78
|
end
|
24
79
|
end
|