myfinance 0.1.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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +23 -0
  4. data/.hound.yml +1063 -0
  5. data/.rspec +2 -0
  6. data/.travis.yml +7 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +94 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +209 -0
  11. data/Rakefile +6 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +7 -0
  14. data/lib/myfinance.rb +35 -0
  15. data/lib/myfinance/client.rb +31 -0
  16. data/lib/myfinance/configuration.rb +12 -0
  17. data/lib/myfinance/entities/base.rb +9 -0
  18. data/lib/myfinance/entities/collection.rb +57 -0
  19. data/lib/myfinance/entities/entity.rb +16 -0
  20. data/lib/myfinance/entities/entity_collection.rb +14 -0
  21. data/lib/myfinance/entities/financial_account.rb +30 -0
  22. data/lib/myfinance/entities/payable_account.rb +6 -0
  23. data/lib/myfinance/entities/receivable_account.rb +6 -0
  24. data/lib/myfinance/exception.rb +11 -0
  25. data/lib/myfinance/http.rb +33 -0
  26. data/lib/myfinance/request.rb +53 -0
  27. data/lib/myfinance/resources/base.rb +28 -0
  28. data/lib/myfinance/resources/entity.rb +39 -0
  29. data/lib/myfinance/resources/financial_account.rb +70 -0
  30. data/lib/myfinance/resources/payable_account.rb +33 -0
  31. data/lib/myfinance/resources/receivable_account.rb +33 -0
  32. data/lib/myfinance/response.rb +41 -0
  33. data/lib/myfinance/version.rb +3 -0
  34. data/myfinance.gemspec +45 -0
  35. data/spec/lib/myfinance/client_spec.rb +49 -0
  36. data/spec/lib/myfinance/configuration_spec.rb +26 -0
  37. data/spec/lib/myfinance/entities/base_spec.rb +28 -0
  38. data/spec/lib/myfinance/entities/collection_spec.rb +70 -0
  39. data/spec/lib/myfinance/entities/entity_collection_spec.rb +20 -0
  40. data/spec/lib/myfinance/entities/entity_spec.rb +11 -0
  41. data/spec/lib/myfinance/entities/payable_account_spec.rb +13 -0
  42. data/spec/lib/myfinance/entities/receivable_account_spec.rb +13 -0
  43. data/spec/lib/myfinance/http_spec.rb +37 -0
  44. data/spec/lib/myfinance/request_spec.rb +29 -0
  45. data/spec/lib/myfinance/resources/entity_spec.rb +63 -0
  46. data/spec/lib/myfinance/resources/payable_account_spec.rb +146 -0
  47. data/spec/lib/myfinance/resources/receivable_account_spec.rb +146 -0
  48. data/spec/lib/myfinance/response_spec.rb +58 -0
  49. data/spec/myfinance_spec.rb +25 -0
  50. data/spec/spec_helper.rb +39 -0
  51. data/spec/support/client.rb +3 -0
  52. data/spec/support/matchers/have_attr_accessor.rb +18 -0
  53. data/spec/support/shared_examples/entity_attributes.rb +9 -0
  54. data/spec/support/shared_examples/http_request_methods.rb +29 -0
  55. data/spec/support/vcr.rb +7 -0
  56. metadata +306 -0
@@ -0,0 +1,12 @@
1
+ require 'base64'
2
+
3
+ module Myfinance
4
+ class Configuration
5
+ attr_accessor :url, :user_agent
6
+
7
+ def initialize
8
+ @url = 'https://app.myfinance.com.br'
9
+ @user_agent = "Myfinance Ruby Client v#{Myfinance::VERSION}"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ require "virtus"
2
+
3
+ module Myfinance
4
+ module Entities
5
+ class Base
6
+ include Virtus.model
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,57 @@
1
+ module Myfinance
2
+ module Entities
3
+ #
4
+ # A wrapper to Myfinance collection returns from API. This wrapper represents a collection and it's responsible for processing pagination information as well.
5
+ #
6
+ class Collection < Base
7
+ PAGE_REGEX = /page=(\d+)/
8
+
9
+ attr_reader :response, :collection, :headers
10
+
11
+ def initialize(response)
12
+ @response = response
13
+ @collection = []
14
+ @headers = response.headers['Link'].split(',') rescue []
15
+ end
16
+
17
+ def self.build(response)
18
+ self.new(response).build
19
+ end
20
+
21
+ def build
22
+ build_collection
23
+ self
24
+ end
25
+
26
+ def next_page
27
+ page_for(:next)
28
+ end
29
+
30
+ def last_page
31
+ page_for(:last)
32
+ end
33
+
34
+ def previous_page
35
+ page_for(:prev)
36
+ end
37
+
38
+ def first_page
39
+ page_for(:first)
40
+ end
41
+
42
+ private
43
+
44
+ def page_for(page_rel)
45
+ header_link_for(page_rel).match(PAGE_REGEX)[1].to_i rescue nil
46
+ end
47
+
48
+ def header_link_for(rel)
49
+ headers.select{|n| n =~ /rel=#{rel}/}.first
50
+ end
51
+
52
+ def build_collection
53
+ raise NotImplementedError
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,16 @@
1
+ module Myfinance
2
+ module Entities
3
+ class Entity < Base
4
+ attribute :id, Integer
5
+ attribute :name, String
6
+ attribute :account_id, Integer
7
+ attribute :charging_uuid, String
8
+ attribute :created_at, DateTime
9
+ attribute :default_in_menu, Boolean
10
+ attribute :deleted_at, DateTime
11
+ attribute :federation_subscription_number, String
12
+ attribute :imported_from_sync_at, DateTime
13
+ attribute :updated_at, DateTime
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ module Myfinance
2
+ module Entities
3
+ #
4
+ # A wrapper to Myfinance entities collection
5
+ #
6
+ class EntityCollection < Collection
7
+ def build_collection
8
+ response.parsed_body.each do |attributes|
9
+ collection.push(Myfinance::Entities::Entity.new(attributes['entity']))
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ module Myfinance
2
+ module Entities
3
+ class FinancialAccount < Base
4
+ [:id, :entity_id, :status, :category_id, :person_id, :recurrence_id, :number_of_parcels,
5
+ :current_parcel, :classification_center_id, :expected_deposit_account_id].each do |k|
6
+ attribute k, Integer
7
+ end
8
+
9
+ [:status_name, :description, :document, :observation, :recurrence_period,
10
+ :competency_month].each { |k| attribute k, String }
11
+
12
+ [:amount, :interest_amount, :discount_amount, :total_amount, :ticket_amount].each do |k|
13
+ attribute k, Float
14
+ end
15
+
16
+ [:remind, :income_tax_relevant, :recurrent, :parcelled, :ticket_amount].each do |k|
17
+ attribute k, Boolean
18
+ end
19
+
20
+ [:due_date, :occurred_at, :document_emission_date, :reminded_at].each do |k|
21
+ attribute k, Date
22
+ end
23
+ [:created_at, :updated_at].each { |k| attribute k, DateTime }
24
+
25
+ attribute :financial_account_taxes_attributes, Array[Hash]
26
+ attribute :reconciliations, Hash[String => Array]
27
+ attribute :links, Array[Hash[String => String]]
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ module Myfinance
2
+ module Entities
3
+ class PayableAccount < FinancialAccount
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Myfinance
2
+ module Entities
3
+ class ReceivableAccount < FinancialAccount
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ module Myfinance
2
+ class Exception < StandardError
3
+ attr_accessor :code, :body
4
+
5
+ def initialize(args = {})
6
+ super(args[:message])
7
+ @code = args[:code]
8
+ @body = args[:body]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,33 @@
1
+ require "myfinance/request"
2
+ require "myfinance/response"
3
+
4
+ module Myfinance
5
+ class Http
6
+ attr_reader :token
7
+
8
+ def initialize(token)
9
+ @token = token
10
+ end
11
+
12
+ %w[get post delete put].each do |m|
13
+ define_method(m) do |path, options = {}, &block|
14
+ send_request(m.to_sym, path, options, &block)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def send_request(method, path, options, &block)
21
+ request = Request.new(options.merge!({
22
+ method: method,
23
+ token: token,
24
+ url: "#{Myfinance.configuration.url}#{path}",
25
+ user_agent: Myfinance.configuration.user_agent
26
+ }))
27
+
28
+ response = Response.new(request.run)
29
+
30
+ response.resolve!(&block)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,53 @@
1
+ module Myfinance
2
+ class Request
3
+
4
+ def initialize(args)
5
+ @args = args
6
+ end
7
+
8
+ def run
9
+ request.run
10
+ request.response
11
+ end
12
+
13
+ private
14
+
15
+ attr_reader :args
16
+
17
+ def request
18
+ @request ||= Typhoeus::Request.new(args[:url], options)
19
+ end
20
+
21
+ def options
22
+ {
23
+ method: args[:method],
24
+ params: args[:params],
25
+ body: body,
26
+ headers: headers,
27
+ accept_encoding: "gzip"
28
+ }.reject {|k,v| v.nil?}
29
+ end
30
+
31
+ def headers
32
+ headers = args.fetch(:headers) { {} }
33
+
34
+ {
35
+ "Accept" => "application/json",
36
+ "Content-Type" => "application/json",
37
+ "User-Agent" => args[:user_agent],
38
+ "Authorization" => "Basic #{authorization_hash}"
39
+ }.merge(headers)
40
+ end
41
+
42
+ def body
43
+ body = args[:body]
44
+ body = MultiJson.dump(body) if body.is_a?(Hash)
45
+ body
46
+ end
47
+
48
+ def authorization_hash
49
+ ::Base64.strict_encode64("#{args[:token]}:X")
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,28 @@
1
+ module Myfinance
2
+ module Resources
3
+ class Base
4
+
5
+ attr_accessor :http
6
+
7
+ def initialize(http)
8
+ @http = http
9
+ end
10
+
11
+ private
12
+
13
+ def respond_with_collection(response)
14
+ collection_klass = Myfinance::Entities.const_get("#{entity_klass_name}Collection")
15
+ collection_klass.build(response)
16
+ end
17
+
18
+ def respond_with_object(response, key)
19
+ entity_klass = Myfinance::Entities.const_get(entity_klass_name)
20
+ entity_klass.new(response.parsed_body(key))
21
+ end
22
+
23
+ def entity_klass_name
24
+ self.class.to_s.gsub('Resources', 'Entities')
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ module Myfinance
2
+ module Resources
3
+ #
4
+ # A wrapper to Myfinance entities API
5
+ #
6
+ # [API]
7
+ # Documentation: https://app.myfinance.com.br/docs/api/entities
8
+ #
9
+ class Entity < Base
10
+ #
11
+ # List all entities of the user
12
+ #
13
+ # [API]
14
+ # Method: <tt>GET /entities</tt>
15
+ #
16
+ # Documentation: https://app.myfinance.com.br/docs/api/entities#get_index
17
+ #
18
+ def find_all
19
+ http.get('/entities', body: {}) do |response|
20
+ respond_with_collection(response)
21
+ end
22
+ end
23
+
24
+ #
25
+ # Find a specific entity
26
+ #
27
+ # [API]
28
+ # Method: <tt>GET /entities/:id</tt>
29
+ #
30
+ # Documentation: https://app.myfinance.com.br/docs/api/entities#get_show
31
+ #
32
+ def find(entity_id)
33
+ http.get("/entities/#{entity_id}", body: {}) do |response|
34
+ respond_with_object(response, 'entity')
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,70 @@
1
+ module Myfinance
2
+ module Resources
3
+ class FinancialAccount < Base
4
+
5
+ def initialize(http)
6
+ @http = http
7
+ set_method_for(pay_or_receive_method)
8
+ set_method_for(undo_payment_or_receivement)
9
+ end
10
+ #
11
+ # Creates a payable/receivable account
12
+ #
13
+ # [API]
14
+ # Method: <tt>POST /entities/:entity_id/payable_accounts</tt>
15
+ # Method: <tt>POST /entities/:entity_id/receivable_accounts</tt>
16
+ #
17
+ # Documentation: https://app.myfinance.com.br/docs/api/payable_accounts#post_create
18
+ # Documentation: https://app.myfinance.com.br/docs/api/receivable_accounts#post_create
19
+ #
20
+ def create(entity_id, params = {})
21
+ request_and_build_response(:post, endpoint_for(nil, entity_id, :create), params)
22
+ end
23
+
24
+ #
25
+ # Destroys a payable/receivable account
26
+ #
27
+ # [API]
28
+ # Method: <tt>DELETE /entities/:entity_id/payable_accounts/:id</tt>
29
+ # Method: <tt>DELETE /entities/:entity_id/receivable_accounts/:id</tt>
30
+ #
31
+ # Documentation: https://app.myfinance.com.br/docs/api/payable_accounts#delete_destroy
32
+ # Documentation: https://app.myfinance.com.br/docs/api/receivable_accounts#delete_destroy
33
+ #
34
+ def destroy(id, entity_id)
35
+ http.delete(endpoint_for(id, entity_id, :destroy)) do |response|
36
+ true
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def request_and_build_response(method, endpoint, params={})
43
+ http.send(method, endpoint, body: { resource_key => params }) do |response|
44
+ respond_with_object(response, resource_key)
45
+ end
46
+ end
47
+
48
+ def endpoint_for(id, entity_id, key)
49
+ parameterize_endoint(id, entity_id, key)
50
+ end
51
+
52
+ def default_endpoints
53
+ {
54
+ create: "/entities/:entity_id/#{resource_key}s",
55
+ destroy: "/entities/:entity_id/#{resource_key}s/:id"
56
+ }
57
+ end
58
+
59
+ def parameterize_endoint(id, entity_id, key)
60
+ endpoints[key.to_sym].gsub(':entity_id', entity_id.to_s).gsub(':id', id.to_s)
61
+ end
62
+
63
+ def set_method_for(action)
64
+ self.class.send(:define_method, action) do |id, entity_id, params={}|
65
+ request_and_build_response(:put, endpoint_for(id, entity_id, action), params)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,33 @@
1
+ module Myfinance
2
+ module Resources
3
+ #
4
+ # A wrapper to Myfinance payable accounts API
5
+ #
6
+ # [API]
7
+ # Documentation: https://app.myfinance.com.br/docs/api/payable_accounts
8
+ #
9
+ class PayableAccount < FinancialAccount
10
+
11
+ private
12
+
13
+ def endpoints
14
+ default_endpoints.merge({
15
+ pay: '/entities/:entity_id/payable_accounts/:id/pay',
16
+ undo_payment: '/entities/:entity_id/payable_accounts/:id/undo_payment'
17
+ })
18
+ end
19
+
20
+ def pay_or_receive_method
21
+ 'pay'
22
+ end
23
+
24
+ def undo_payment_or_receivement
25
+ 'undo_payment'
26
+ end
27
+
28
+ def resource_key
29
+ 'payable_account'
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ module Myfinance
2
+ module Resources
3
+ #
4
+ # A wrapper to Myfinance receivable accounts API
5
+ #
6
+ # [API]
7
+ # Documentation: https://app.myfinance.com.br/docs/api/receivable_accounts
8
+ #
9
+ class ReceivableAccount < FinancialAccount
10
+
11
+ private
12
+
13
+ def endpoints
14
+ default_endpoints.merge({
15
+ receive: '/entities/:entity_id/receivable_accounts/:id/receive',
16
+ undo_receivement: '/entities/:entity_id/receivable_accounts/:id/undo_receivement',
17
+ })
18
+ end
19
+
20
+ def pay_or_receive_method
21
+ 'receive'
22
+ end
23
+
24
+ def undo_payment_or_receivement
25
+ 'undo_receivement'
26
+ end
27
+
28
+ def resource_key
29
+ 'receivable_account'
30
+ end
31
+ end
32
+ end
33
+ end