frilans_finans_api 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +6 -0
  6. data/{README.MD → README.md} +0 -0
  7. data/Rakefile +8 -0
  8. data/fixtures/companies_fixture.json +55 -0
  9. data/fixtures/company_fixture.json +18 -0
  10. data/fixtures/company_post_body_fixture.json +13 -0
  11. data/fixtures/company_post_fixture.json +13 -0
  12. data/fixtures/currencies_fixture.json +148 -0
  13. data/fixtures/invoice_fixture.json +11 -0
  14. data/fixtures/invoice_post_body_fixture.json +26 -0
  15. data/fixtures/invoice_post_fixture.json +11 -0
  16. data/fixtures/invoices_fixture.json +111 -0
  17. data/fixtures/profession_fixture.json +14 -0
  18. data/fixtures/professions_fixture.json +150 -0
  19. data/fixtures/salaries_fixture.json +45 -0
  20. data/fixtures/tax_fixture.json +13 -0
  21. data/fixtures/taxes_fixture.json +59 -0
  22. data/fixtures/user_fixture.json +30 -0
  23. data/fixtures/user_post_body_fixture.json +9 -0
  24. data/fixtures/user_post_fixture.json +30 -0
  25. data/fixtures/users_fixture.json +56 -0
  26. data/frilans_finans_api.gemspec +32 -0
  27. data/lib/frilans_finans_api/client/client.rb +88 -0
  28. data/lib/frilans_finans_api/client/fixture_client.rb +83 -0
  29. data/lib/frilans_finans_api/client/nil_client.rb +31 -0
  30. data/lib/frilans_finans_api/client/request.rb +145 -0
  31. data/lib/frilans_finans_api/client/terms.rb +28 -0
  32. data/lib/frilans_finans_api/client/walker.rb +29 -0
  33. data/lib/frilans_finans_api/models/company.rb +10 -0
  34. data/lib/frilans_finans_api/models/currency.rb +12 -0
  35. data/lib/frilans_finans_api/models/employment_certificate.rb +10 -0
  36. data/lib/frilans_finans_api/models/invoice.rb +20 -0
  37. data/lib/frilans_finans_api/models/profession.rb +17 -0
  38. data/lib/frilans_finans_api/models/salary.rb +10 -0
  39. data/lib/frilans_finans_api/models/tax.rb +12 -0
  40. data/lib/frilans_finans_api/models/user.rb +27 -0
  41. data/lib/frilans_finans_api/version.rb +1 -1
  42. data/lib/frilans_finans_api.rb +61 -0
  43. metadata +41 -2
@@ -0,0 +1,13 @@
1
+ {
2
+ "data": {
3
+ "type": "taxes",
4
+ "id": "1",
5
+ "attributes": {
6
+ "standard": 0,
7
+ "percent": 0
8
+ },
9
+ "links": {
10
+ "self": "https://frilansfinans.se/api/tax/1"
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,59 @@
1
+ {
2
+ "data": [
3
+ {
4
+ "type": "taxes",
5
+ "id": "0",
6
+ "attributes": {
7
+ "standard": 0,
8
+ "percent": 0
9
+ },
10
+ "links": {
11
+ "self": "https://frilansfinans.se/api/tax/0"
12
+ }
13
+ },
14
+ {
15
+ "type": "taxes",
16
+ "id": "1",
17
+ "attributes": {
18
+ "standard": 0,
19
+ "percent": 6
20
+ },
21
+ "links": {
22
+ "self": "https://frilansfinans.se/api/tax/1"
23
+ }
24
+ },
25
+ {
26
+ "type": "taxes",
27
+ "id": "2",
28
+ "attributes": {
29
+ "standard": 0,
30
+ "percent": 12
31
+ },
32
+ "links": {
33
+ "self": "https://frilansfinans.se/api/tax/2"
34
+ }
35
+ },
36
+ {
37
+ "type": "taxes",
38
+ "id": "3",
39
+ "attributes": {
40
+ "standard": 1,
41
+ "percent": 25
42
+ },
43
+ "links": {
44
+ "self": "https://frilansfinans.se/api/tax/3"
45
+ }
46
+ }
47
+ ],
48
+ "meta": {
49
+ "pagination": {
50
+ "page": {
51
+ "size": 25,
52
+ "number": 1,
53
+ "items": 25
54
+ },
55
+ "items": 4,
56
+ "pages": 1
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "data": {
3
+ "type": "users",
4
+ "id": "1",
5
+ "attributes": {
6
+ "first_name": "Jacob",
7
+ "last_name": "Burenstam",
8
+ "social_security_number": null,
9
+ "account_clearing_number": null,
10
+ "account_number": null,
11
+ "user_status_id": null,
12
+ "profession_title": null,
13
+ "user_id_owner": null,
14
+ "created_at": {
15
+ "date": "2016-04-25 19:16:00.000000",
16
+ "timezone_type": 3,
17
+ "timezone": "UTC"
18
+ },
19
+ "verify_password": null,
20
+ "default_taxkey_id": null,
21
+ "show_reg_invoice_page": null,
22
+ "company_name": null,
23
+ "api_consumer_id": null,
24
+ "last_login": null
25
+ },
26
+ "links": {
27
+ "self": "https://frilansfinans.se/api/user/2"
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "access_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
3
+ "data": {
4
+ "attributes": {
5
+ "first_name": "Jacob",
6
+ "last_name": "Burenstam"
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "data": {
3
+ "type": "users",
4
+ "id": "1",
5
+ "attributes": {
6
+ "first_name": "Jacob",
7
+ "last_name": "Burenstam",
8
+ "social_security_number": null,
9
+ "account_clearing_number": null,
10
+ "account_number": null,
11
+ "user_status_id": null,
12
+ "profession_title": null,
13
+ "user_id_owner": null,
14
+ "created_at": {
15
+ "date": "2016-04-25 19:16:00.000000",
16
+ "timezone_type": 3,
17
+ "timezone": "UTC"
18
+ },
19
+ "verify_password": null,
20
+ "default_taxkey_id": null,
21
+ "show_reg_invoice_page": null,
22
+ "company_name": null,
23
+ "api_consumer_id": null,
24
+ "last_login": null
25
+ },
26
+ "links": {
27
+ "self": "https://frilansfinans.se/api/user/1"
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "data": [
3
+ {
4
+ "type": "users",
5
+ "id": "1",
6
+ "attributes": {
7
+ "email": "account@example.com",
8
+ "co": "",
9
+ "street": "Dag Hammarskjölds väg 13",
10
+ "zip": "752 37",
11
+ "city": "UPPSALA",
12
+ "country": "SWEDEN",
13
+ "telephone": "",
14
+ "cellphone": "0771151000",
15
+ "autogen": 0,
16
+ "role": "normal",
17
+ "foreclosure": 0,
18
+ "bankgiro": null,
19
+ "postgiro": null,
20
+ "first_name": "Firstname",
21
+ "last_name": "Lastname",
22
+ "social_security_number": 7405280269,
23
+ "account_clearing_number": "4569-80",
24
+ "account_number": "401.062.424-2",
25
+ "user_status_id": 1,
26
+ "profession_title": "Grafisk formgivare",
27
+ "user_id_owner": 0,
28
+ "created_at": {
29
+ "date": "2016-04-05 12:21:38.000000",
30
+ "timezone_type": 3,
31
+ "timezone": "UTC"
32
+ },
33
+ "verify_password": "",
34
+ "default_taxkey_id": 1,
35
+ "show_reg_invoice_page": 1,
36
+ "company_name": "",
37
+ "api_consumer_id": null,
38
+ "last_login": "2016-04-05 12:21:38"
39
+ },
40
+ "links": {
41
+ "self": "https://frilansfinans.se/api/user/1"
42
+ }
43
+ }
44
+ ],
45
+ "meta": {
46
+ "pagination": {
47
+ "page": {
48
+ "size": 25,
49
+ "number": 1,
50
+ "items": 25
51
+ },
52
+ "items": 1,
53
+ "pages": 1
54
+ }
55
+ }
56
+ }
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ lib = File.expand_path('../lib', __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+ require 'frilans_finans_api/version'
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = 'frilans_finans_api'
10
+ spec.version = FrilansFinansApi::VERSION
11
+ spec.authors = ['Jacob Burenstam']
12
+ spec.email = ['burenstam@gmail.com']
13
+
14
+ spec.summary = 'Interact with Frilans Finans API'
15
+ spec.description = 'Interact with Frilans Finans API (still under development)'
16
+ spec.homepage = 'https://github.com/buren/frilans_finans_api'
17
+ spec.license = 'MIT'
18
+
19
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
20
+ f.match(%r{^(test|spec|features)/})
21
+ end
22
+ spec.bindir = 'exe'
23
+ spec.executables = []
24
+ spec.require_paths = ['lib']
25
+
26
+ spec.add_dependency 'httparty', '~> 0.13' # Easy HTTP requests
27
+
28
+ spec.add_development_dependency 'webmock', '~> 2.0'
29
+ spec.add_development_dependency 'bundler', '~> 1.11'
30
+ spec.add_development_dependency 'rake', '~> 10.0'
31
+ spec.add_development_dependency 'rspec', '~> 3.0'
32
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'frilans_finans_api/client/request'
4
+
5
+ module FrilansFinansApi
6
+ class Client
7
+ attr_reader :request
8
+
9
+ def initialize(base_uri: nil, client_id: nil, client_secret: nil)
10
+ @request = Request.new(
11
+ base_uri: base_uri,
12
+ client_id: client_id,
13
+ client_secret: client_secret
14
+ )
15
+ end
16
+
17
+ def currencies(page: 1)
18
+ request.get(uri: '/currencies', query: build_query(page: page))
19
+ end
20
+
21
+ def professions(page: 1)
22
+ request.get(uri: '/professions', query: build_query(page: page))
23
+ end
24
+
25
+ def salaries(invoice_id:, page: 1)
26
+ request.get(uri: "/invoices/#{invoice_id}/salaries", query: build_query(page: page))
27
+ end
28
+
29
+ def users(page: 1, email: nil)
30
+ filter = email ? { email: email } : {}
31
+ request.get(uri: '/users', query: build_query(page: page, filter: filter))
32
+ end
33
+
34
+ def taxes(page: 1, only_standard: false)
35
+ filter = only_standard ? { standard: 1 } : {}
36
+ request.get(uri: '/taxes', query: build_query(page: page, filter: filter))
37
+ end
38
+
39
+ def invoice(id:)
40
+ request.get(uri: "/invoices/#{id}")
41
+ end
42
+
43
+ def user(id:)
44
+ request.get(uri: "/users/#{id}")
45
+ end
46
+
47
+ def profession(id:)
48
+ request.get(uri: "/professions/#{id}")
49
+ end
50
+
51
+ def create_user(attributes: {})
52
+ request.post(uri: '/users', body: build_attributes(attributes))
53
+ end
54
+
55
+ def create_company(attributes: {})
56
+ request.post(uri: '/companies', body: build_attributes(attributes))
57
+ end
58
+
59
+ def create_employment_certificate(attributes: {})
60
+ request.post(uri: '/employment-certificate', body: build_attributes(attributes))
61
+ end
62
+
63
+ def create_invoice(attributes: {})
64
+ request.post(uri: '/invoices', body: build_attributes(attributes))
65
+ end
66
+
67
+ def update_invoice(id:, attributes: {})
68
+ request.patch(uri: "/invoices/#{id}", body: build_attributes(attributes))
69
+ end
70
+
71
+ def update_user(id:, attributes: {})
72
+ request.patch(uri: "/users/#{id}", body: build_attributes(attributes))
73
+ end
74
+
75
+ private
76
+
77
+ def build_attributes(attributes)
78
+ { data: { attributes: attributes } }
79
+ end
80
+
81
+ def build_query(page:, filter: {})
82
+ {
83
+ page: { number: page },
84
+ filter: filter
85
+ }
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+
5
+ module FrilansFinansApi
6
+ class FixtureClient
7
+ # NOTE: If this is extracted out of just_match_api, this will need to change
8
+ BASE_PATH = __dir__ + '/../../../fixtures'
9
+
10
+ HTTP_STATUS = 200
11
+ FIXTURE_URI = URI('http://example.com')
12
+
13
+ Request = Struct.new(:uri)
14
+ Response = Struct.new(:code, :body, :request)
15
+
16
+ def currencies(**_args)
17
+ mock_response(read(:currencies))
18
+ end
19
+
20
+ def professions(**_args)
21
+ mock_response(read(:professions))
22
+ end
23
+
24
+ def users(**_args)
25
+ mock_response(read(:users))
26
+ end
27
+
28
+ def salaries(**_args)
29
+ mock_response(read(:salaries))
30
+ end
31
+
32
+ def taxes(**_args)
33
+ mock_response(read(:taxes))
34
+ end
35
+
36
+ def user(**_args)
37
+ mock_response(read(:user))
38
+ end
39
+
40
+ def profession(**_args)
41
+ mock_response(read(:profession))
42
+ end
43
+
44
+ def invoice(**_args)
45
+ mock_response(read(:invoice))
46
+ end
47
+
48
+ def create_user(**_args)
49
+ mock_response(read(:user))
50
+ end
51
+
52
+ def create_company(**_args)
53
+ mock_response(read(:company))
54
+ end
55
+
56
+ def create_employment_certificate(**_args)
57
+ mock_response('{}')
58
+ end
59
+
60
+ def create_invoice(**_args)
61
+ mock_response(read(:invoice))
62
+ end
63
+
64
+ def update_invoice(**_args)
65
+ mock_response(read(:invoice))
66
+ end
67
+
68
+ def update_user(**_args)
69
+ mock_response(read(:user))
70
+ end
71
+
72
+ def read(type)
73
+ File.read("#{BASE_PATH}/#{type}_fixture.json")
74
+ end
75
+
76
+ private
77
+
78
+ def mock_response(body)
79
+ request = Request.new(FIXTURE_URI)
80
+ Response.new(HTTP_STATUS, body, request)
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrilansFinansApi
4
+ class NilClient
5
+ HTTP_STATUS = 200
6
+ NIL_URI = URI('http://example.com')
7
+
8
+ Request = Struct.new(:uri)
9
+ Response = Struct.new(:code, :body, :request)
10
+
11
+ def currencies(**_args)
12
+ body = '{}'
13
+ request = Request.new(NIL_URI)
14
+ Response.new(HTTP_STATUS, body, request)
15
+ end
16
+
17
+ alias_method :professions, :currencies
18
+ alias_method :salaries, :currencies
19
+ alias_method :taxes, :currencies
20
+ alias_method :users, :currencies
21
+ alias_method :invoice, :currencies
22
+ alias_method :user, :currencies
23
+ alias_method :profession, :currencies
24
+ alias_method :create_user, :currencies
25
+ alias_method :create_company, :currencies
26
+ alias_method :create_employment_certificate, :currencies
27
+ alias_method :create_invoice, :currencies
28
+ alias_method :update_invoice, :currencies
29
+ alias_method :update_user, :currencies
30
+ end
31
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'httparty'
4
+
5
+ module FrilansFinansApi
6
+ class Request
7
+ USER_AGENT = {
8
+ 'User-Agent' => 'FrilansFinansAPI - Ruby client'
9
+ }.freeze
10
+
11
+ HEADERS = {
12
+ 'Content-Type' => 'application/json',
13
+ 'Accept' => 'application/vnd.api.v2+json'
14
+ }.merge!(USER_AGENT).freeze
15
+
16
+ GRANT_TYPE = 'client_credentials'
17
+
18
+ attr_reader :credentials, :base_uri, :access_token
19
+
20
+ def initialize(base_uri: nil, client_id: nil, client_secret: nil)
21
+ @base_uri = base_uri || FrilansFinansApi.config.base_uri
22
+ @credentials = {
23
+ grant_type: GRANT_TYPE,
24
+ client_id: client_id || FrilansFinansApi.config.client_id,
25
+ client_secret: client_secret || FrilansFinansApi.config.client_secret
26
+ }
27
+ @access_token = nil
28
+ end
29
+
30
+ def get(uri:, query: {})
31
+ authorized_request do
32
+ _get(uri: uri, query: query)
33
+ end
34
+ end
35
+
36
+ def post(uri:, query: {}, body: {})
37
+ authorized_request do
38
+ _post(uri: uri, query: query, body: body.to_json)
39
+ end
40
+ end
41
+
42
+ def patch(uri:, query: {}, body: {})
43
+ authorized_request do
44
+ _patch(uri: uri, query: query, body: body.to_json)
45
+ end
46
+ end
47
+
48
+ def _get(uri:, query: {})
49
+ opts = build_get_opts(query: query)
50
+ response = HTTParty.get("#{base_uri}#{uri}", opts)
51
+ log_response(:get, uri: uri, params: opts, response: response)
52
+ response
53
+ end
54
+
55
+ def _post(uri:, query: {}, body: {})
56
+ opts = build_post_opts(query: query, body: body)
57
+ response = HTTParty.post("#{base_uri}#{uri}", opts)
58
+ log_response(:post, uri: uri, params: opts, response: response)
59
+ response
60
+ end
61
+
62
+ def _patch(uri:, query: {}, body: {})
63
+ opts = build_post_opts(query: query, body: body)
64
+ response = HTTParty.patch("#{base_uri}#{uri}", opts)
65
+ log_response(:patch, uri: uri, params: opts, response: response)
66
+ response
67
+ end
68
+
69
+ private
70
+
71
+ def build_get_opts(query: {})
72
+ { query: query }.merge(headers: headers)
73
+ end
74
+
75
+ def build_post_opts(query: {}, body: {})
76
+ {
77
+ query: query,
78
+ body: body
79
+ }.merge(headers: headers)
80
+ end
81
+
82
+ def headers
83
+ HEADERS.merge(auth_headers).dup
84
+ end
85
+
86
+ def authorized_request
87
+ fetch_access_token if access_token.nil?
88
+
89
+ response = yield
90
+ return response unless reauthorize?(response)
91
+
92
+ fetch_access_token
93
+ yield
94
+ end
95
+
96
+ def reauthorize?(response)
97
+ response.code == '401'
98
+ end
99
+
100
+ def auth_headers
101
+ { 'Authorization' => "Bearer #{access_token}" }
102
+ end
103
+
104
+ def fetch_access_token
105
+ uri = "#{base_uri}/auth/accesstoken"
106
+ response = HTTParty.post(uri, body: credentials, headers: USER_AGENT)
107
+ log_response(:post, uri: uri, params: {}, response: response)
108
+
109
+ @access_token = extract_access_token(response)
110
+ response
111
+ end
112
+
113
+ def extract_access_token(response)
114
+ parsed = response.parsed_response
115
+
116
+ # In tests HTTParty and Webmock aren't friends, causing HTTParty to return a string
117
+ # from #parsed_response instead of a Hash
118
+ parsed = JSON.parse(parsed) if parsed.is_a?(String)
119
+
120
+ parsed['access_token']
121
+ end
122
+
123
+ def log_response(method, uri:, params:, response:)
124
+ log_id = "[#{self.class.name}]"
125
+ verb = method.to_s.upcase
126
+ body = response.body
127
+ json_params = params.to_json
128
+ status = response.code
129
+ log_body = [
130
+ log_id,
131
+ verb,
132
+ "URI: #{uri}",
133
+ "PARAMS: #{json_params}",
134
+ "STATUS: #{status}",
135
+ "BODY: #{body}"
136
+ ].join(' ')
137
+ FrilansFinansApi.config.event_logger.request_event(params: json_params,
138
+ status: status,
139
+ verb: verb,
140
+ uri: uri,
141
+ body: body)
142
+ FrilansFinansApi.config.logger.info log_body
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'httparty'
4
+
5
+ module FrilansFinansApi
6
+ class Terms
7
+ USER_URL = 'https://www.frilansfinans.se/just-arrived-employment-agreement/'.freeze
8
+ COMPANY_USER_URL = 'https://www.frilansfinans.se/just-arrived-consultancy-agreement/'.freeze
9
+
10
+ HEADERS = Request::HEADERS
11
+
12
+ def self.get(type:)
13
+ url = case type
14
+ when :company then COMPANY_USER_URL
15
+ when :user then USER_URL
16
+ else
17
+ fail(ArgumentError, "Unknown type: '#{type}'")
18
+ end
19
+
20
+ HTTParty.get(url, headers: headers).parsed_response
21
+ end
22
+
23
+ def self.headers
24
+ # Must be dup frozen hash, since HTTParty modifies it
25
+ HEADERS.dup
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrilansFinansApi
4
+ module Walker
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ def walk(client: FrilansFinansApi.config.client_klass.new)
11
+ current_page = 1
12
+ total_pages = 2
13
+
14
+ resources = []
15
+
16
+ while total_pages >= current_page
17
+ resource_index = index(page: current_page, client: client)
18
+ total_pages = resource_index.total_pages
19
+
20
+ yield(resource_index) if block_given?
21
+ resources += resource_index.resources
22
+
23
+ current_page += 1
24
+ end
25
+ resources
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrilansFinansApi
4
+ class Company
5
+ def self.create(attributes:, client: FrilansFinansApi.config.client_klass.new)
6
+ response = client.create_company(attributes: attributes)
7
+ Document.new(response)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrilansFinansApi
4
+ class Currency
5
+ include Walker
6
+
7
+ def self.index(page: 1, client: FrilansFinansApi.config.client_klass.new)
8
+ response = client.currencies(page: page)
9
+ Document.new(response)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrilansFinansApi
4
+ class EmploymentCertificate
5
+ def self.create(attributes:, client: FrilansFinansApi.config.client_klass.new)
6
+ client.create_employment_certificate(attributes: attributes)
7
+ nil
8
+ end
9
+ end
10
+ end