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,41 @@
1
+ require "myfinance/exception"
2
+
3
+ module Myfinance
4
+ RequestTimeout = Class.new(Exception)
5
+ RequestError = Class.new(Exception)
6
+
7
+ class Response < SimpleDelegator
8
+
9
+ def resolve!(&block)
10
+ if success?
11
+ block_given? ? yield(self) : self
12
+ elsif timed_out?
13
+ timeout!
14
+ else
15
+ error!
16
+ end
17
+ end
18
+
19
+ def parsed_body(key=nil)
20
+ return MultiJson.load(self.body)[key] unless key.nil?
21
+ MultiJson.load(self.body)
22
+ rescue MultiJson::ParseError
23
+ {}
24
+ end
25
+
26
+ private
27
+
28
+ def timeout!
29
+ raise RequestTimeout
30
+ end
31
+
32
+ def error!
33
+ raise RequestError.new(
34
+ code: code,
35
+ message: status_message,
36
+ body: body
37
+ )
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module Myfinance
2
+ VERSION = "0.1.0"
3
+ end
data/myfinance.gemspec ADDED
@@ -0,0 +1,45 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'myfinance/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "myfinance"
8
+ spec.version = Myfinance::VERSION
9
+ spec.authors = ["Eduardo Hertz", "Rodrigo Tassinari"]
10
+ spec.email = ["eduardohertz@gmail.com", "rodrigo@pittlandia.net"]
11
+
12
+ spec.summary = %q{A Ruby client for the Myfinance REST API}
13
+ spec.description = %q{A Ruby client for the Myfinance REST API: https://app.myfinance.com.br/docs/api}
14
+ spec.homepage = "https://github.com/myfreecomm/myfinance-client-ruby"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files`.split($/).reject { |f| f =~ %r{(vcr_cassettes)/} }
26
+ spec.bindir = "bin"
27
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
28
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_dependency "typhoeus", "~> 0.7.1"
32
+ spec.add_dependency "multi_json", "~> 1.9.0"
33
+ spec.add_dependency "virtus", '~> 1.0.5'
34
+
35
+ spec.add_development_dependency "bundler", "~> 1.10"
36
+ spec.add_development_dependency "rake", "~> 10.0"
37
+ spec.add_development_dependency "rspec"
38
+ spec.add_development_dependency "vcr", "~> 2.4"
39
+ spec.add_development_dependency "webmock", "~> 1.9.3"
40
+ spec.add_development_dependency "pry", "~> 0.9"
41
+ spec.add_development_dependency "pry-nav", "~> 0.2"
42
+ spec.add_development_dependency "awesome_print", "~> 1.1"
43
+ spec.add_development_dependency "simplecov", "~> 0.9"
44
+ spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4"
45
+ end
@@ -0,0 +1,49 @@
1
+ require "spec_helper"
2
+
3
+ describe Myfinance::Client do
4
+ subject { client }
5
+
6
+ describe "#initialize" do
7
+ it "instantiates a new Myfinance::Http object" do
8
+ expect(Myfinance::Http).to receive(:new).with("abc")
9
+ Myfinance::Client.new("abc")
10
+ end
11
+ end
12
+
13
+ describe "#authenticated?" do
14
+ context "with a valid token" do
15
+ it "returns true" do
16
+ VCR.use_cassette("client/authenticated/true") { expect(subject.authenticated?).to be_truthy }
17
+ end
18
+ end
19
+
20
+ context "with an invalid token" do
21
+ subject { described_class.new("FAKE-TOKEN") }
22
+
23
+ it "returns false" do
24
+ VCR.use_cassette("client/authenticated/false") { expect(subject.authenticated?).to be_falsey }
25
+ end
26
+ end
27
+ end
28
+
29
+ describe "#entities" do
30
+ it "instantiates a new Myfinance::Resources::Entity" do
31
+ expect(Myfinance::Resources::Entity).to receive(:new).with(subject.http)
32
+ subject.entities
33
+ end
34
+ end
35
+
36
+ describe "#payable_accounts" do
37
+ it "instantiates a new Myfinance::Resources::PayableAccount" do
38
+ expect(Myfinance::Resources::PayableAccount).to receive(:new).with(subject.http)
39
+ subject.payable_accounts
40
+ end
41
+ end
42
+
43
+ describe "#receivable_accounts" do
44
+ it "instantiates a new Myfinance::Resources::ReceivableAccount" do
45
+ expect(Myfinance::Resources::ReceivableAccount).to receive(:new).with(subject.http)
46
+ subject.receivable_accounts
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe Myfinance::Configuration do
5
+ subject { Myfinance::Configuration.new }
6
+
7
+ it "uses the production Myfinance URL by default" do
8
+ expect(subject.url).to eq("https://app.myfinance.com.br")
9
+ end
10
+
11
+ it "uses a default user agent" do
12
+ expect(subject.user_agent).to eq("Myfinance Ruby Client v#{Myfinance::VERSION}")
13
+ end
14
+
15
+ it 'allows setting the configuration parameters' do
16
+ subject.url = "https://sandbox.myfinance.com.br"
17
+ subject.user_agent = "My specific user agent"
18
+
19
+ expect(subject.url).to eq("https://sandbox.myfinance.com.br")
20
+ expect(subject.user_agent).to eq("My specific user agent")
21
+ end
22
+
23
+ it 'does not respond to #token' do
24
+ expect(subject).to_not respond_to(:token)
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ describe Myfinance::Entities::Base do
4
+
5
+ class DummyEntity < Myfinance::Entities::Base
6
+ attribute :property_1, String
7
+ attribute :property_2, String
8
+ end
9
+
10
+ let(:hash) { { property_1: 1, property_2: 2 } }
11
+ subject { DummyEntity.new(hash) }
12
+
13
+ it "builds an object from a hash" do
14
+ expect(subject).to respond_to(:property_1)
15
+ expect(subject).to respond_to(:property_2)
16
+ expect(subject.property_1).to eq("1")
17
+ expect(subject.property_2).to eq("2")
18
+ end
19
+
20
+ describe "#attributes" do
21
+ it "returns a hash from object attributes" do
22
+ expect(subject.to_hash).to eq({
23
+ property_1: "1",
24
+ property_2: "2"
25
+ })
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe Myfinance::Entities::Collection do
4
+ let(:response) { double(headers: {"Link" => "<https://sandbox.myfinance.com.br/entities?page=3>; rel=next, <http://https://sandbox.myfinance.com.br/entities?page=1>; rel=prev, <http://https://sandbox.myfinance.com.br/entities?page=3>; rel=last, <http://https://sandbox.myfinance.com.br/entities?page=1>; rel=first" },
5
+ body: "[{\"entity\":{\"account_id\":3613,\"charging_uuid\":null,\"created_at\":\"2015-07-29T11:04:45-03:00\",\"default_in_menu\":true,\"deleted_at\":null,\"federation_subscription_number\":\"\",\"force_destroy\":false,\"id\":3798,\"imported_from_sync_at\":null,\"name\":\"Minhas Finan\\u00e7as\",\"updated_at\":\"2015-07-29T14:30:36-03:00\"}}]") }
6
+
7
+ subject { described_class.new(response) }
8
+
9
+ describe '#build' do
10
+ it 'raises NotImplementedError' do
11
+ expect { subject.build }.to raise_error(NotImplementedError)
12
+ end
13
+ end
14
+
15
+ describe '#next_page' do
16
+ it 'returns next page (3)' do
17
+ expect(subject.next_page).to eq(3)
18
+ end
19
+
20
+ context 'when there is no next page' do
21
+ let(:response) { double(headers: {"Link" => ""}, body: "") }
22
+
23
+ it 'returns nil' do
24
+ expect(subject.next_page).to be_nil
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '#last_page' do
30
+ it 'returns last page (3)' do
31
+ expect(subject.last_page).to eq(3)
32
+ end
33
+
34
+ context 'when there is no last page' do
35
+ let(:response) { double(headers: {"Link" => ""}, body: "") }
36
+
37
+ it 'returns nil' do
38
+ expect(subject.last_page).to be_nil
39
+ end
40
+ end
41
+ end
42
+
43
+ describe '#previous_page' do
44
+ it 'returns previous page (3)' do
45
+ expect(subject.previous_page).to eq(1)
46
+ end
47
+
48
+ context 'when there is no previous page' do
49
+ let(:response) { double(headers: {"Link" => ""}, body: "") }
50
+
51
+ it 'returns nil' do
52
+ expect(subject.previous_page).to be_nil
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#first_page' do
58
+ it 'returns first page (3)' do
59
+ expect(subject.first_page).to eq(1)
60
+ end
61
+
62
+ context 'when there is no first page' do
63
+ let(:response) { double(headers: {"Link" => ""}, body: "") }
64
+
65
+ it 'returns nil' do
66
+ expect(subject.first_page).to be_nil
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Myfinance::Entities::EntityCollection do
4
+ let(:response) { double(headers: { "Link" => "<https://sandbox.myfinance.com.br/entities?page=3>; rel=next, <http://https://sandbox.myfinance.com.br/entities?page=1>; rel=prev, <http://https://sandbox.myfinance.com.br/entities?page=3>; rel=last, <http://https://sandbox.myfinance.com.br/entities?page=1>; rel=first" },
5
+ parsed_body: [{"entity" => {"account_id" => 3613,"charging_uuid" => nil,"created_at" => "2015-07-29T11:04:45-03:00","default_in_menu" => true,"deleted_at" => nil,"federation_subscription_number" => "","force_destroy" => false,"id" => 3798,"imported_from_sync_at" => nil,"name" => "Minhas Finan\\u00e7as","updated_at" => "2015-07-29T14:30:36-03:00"} }]) }
6
+
7
+ subject { Myfinance::Entities::EntityCollection.new(response) }
8
+
9
+ describe '#build' do
10
+ it 'returns order collection' do
11
+ expect(subject.build.class).to eq(Myfinance::Entities::EntityCollection)
12
+ end
13
+
14
+ it "returns orders" do
15
+ subject.build
16
+ expect(subject.collection.count).to eq(1)
17
+ expect(subject.collection.first.class).to eq(Myfinance::Entities::Entity)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Myfinance::Entities::Entity do
4
+ subject { described_class.new({}) }
5
+
6
+ it_behaves_like "entity_attributes", [
7
+ :id, :name, :account_id,:charging_uuid, :created_at,
8
+ :default_in_menu, :deleted_at, :federation_subscription_number,
9
+ :imported_from_sync_at, :updated_at
10
+ ]
11
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Myfinance::Entities::PayableAccount do
4
+ subject { described_class.new({}) }
5
+
6
+ it_behaves_like "entity_attributes", [
7
+ :id, :entity_id, :status, :status_name, :due_date, :occurred_at, :ticket_amount, :interest_amount, :amount,
8
+ :discount_amount, :total_amount, :description, :document, :document_emission_date, :observation, :remind,
9
+ :reminded_at, :income_tax_relevant, :category_id, :classification_center_id, :expected_deposit_account_id,
10
+ :recurrence_id, :person_id, :recurrent, :parcelled, :recurrence_period, :number_of_parcels, :current_parcel,
11
+ :competency_month, :financial_account_taxes_attributes, :reconciliations, :links, :created_at, :updated_at
12
+ ]
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Myfinance::Entities::ReceivableAccount do
4
+ subject { described_class.new({}) }
5
+
6
+ it_behaves_like "entity_attributes", [
7
+ :id, :entity_id, :status, :status_name, :due_date, :occurred_at, :ticket_amount, :interest_amount, :amount,
8
+ :discount_amount, :total_amount, :description, :document, :document_emission_date, :observation, :remind,
9
+ :reminded_at, :income_tax_relevant, :category_id, :classification_center_id, :expected_deposit_account_id,
10
+ :recurrence_id, :person_id, :recurrent, :parcelled, :recurrence_period, :number_of_parcels, :current_parcel,
11
+ :competency_month, :financial_account_taxes_attributes, :reconciliations, :links, :created_at, :updated_at
12
+ ]
13
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Myfinance::Http do
4
+ subject { Myfinance::Http.new('b552dd5a8598ca089b91c5e355a83b86e4696aefac9eaa05') }
5
+
6
+ describe '#get' do
7
+ let(:http_method) { :get }
8
+ let(:url) { '/accounts' }
9
+ let(:params) { {} }
10
+
11
+ it_behaves_like 'available http request methods'
12
+ end
13
+
14
+ describe '#post' do
15
+ let(:http_method) { :post }
16
+ let(:url) { '/entities' }
17
+ let(:params) { { entity: { name: 'Second entity' } } }
18
+
19
+ it_behaves_like 'available http request methods'
20
+ end
21
+
22
+ describe '#put' do
23
+ let(:http_method) { :put }
24
+ let(:url) { '/entities/3798' }
25
+ let(:params) { { entity: { name: 'Second updated entity' } } }
26
+
27
+ it_behaves_like 'available http request methods'
28
+ end
29
+
30
+ describe '#delete' do
31
+ let(:http_method) { :delete }
32
+ let(:url) { '/entities/3799' }
33
+ let(:params) { {} }
34
+
35
+ it_behaves_like 'available http request methods'
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ describe Myfinance::Request do
4
+ describe "#run" do
5
+ subject { described_class.new({ method: 'post', params: {}, url: Myfinance.configuration.url, user_agent: 'My Test User-Agent', token: 'my-auth-hash' }) }
6
+
7
+ it "does a request using Typhoeus::Request" do
8
+ expect(Typhoeus::Request).to receive(:new).with("https://sandbox.myfinance.com.br", { method: "post", params: {}, headers: { "Accept" => "application/json", "Content-Type" => "application/json", "User-Agent" => "My Test User-Agent", "Authorization" => "Basic bXktYXV0aC1oYXNoOlg=" }, accept_encoding: "gzip" }).and_return(double(run: true, response: true))
9
+ subject.run
10
+ end
11
+
12
+ it "invokes Typhoeus::Request#run" do
13
+ expect_any_instance_of(Typhoeus::Request).to receive(:run)
14
+ subject.run
15
+ end
16
+
17
+ it "invokes Typhoeus::Request#response" do
18
+ allow_any_instance_of(Typhoeus::Request).to receive(:run)
19
+ expect_any_instance_of(Typhoeus::Request).to receive(:response)
20
+ subject.run
21
+ end
22
+
23
+ it 'generates the base 64 of the user token' do
24
+ allow_any_instance_of(Typhoeus::Request).to receive(:run)
25
+ expect(Base64).to receive(:strict_encode64).with("my-auth-hash:X").and_call_original
26
+ subject.run
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,63 @@
1
+ require "spec_helper"
2
+
3
+ describe Myfinance::Resources::Entity do
4
+ describe "#find_all", vcr: true do
5
+ context "when success" do
6
+ subject { client.entities.find_all }
7
+
8
+ it "returns a find_all of orders" do
9
+ expect(subject.class).to eq(Myfinance::Entities::EntityCollection)
10
+ expect(subject.collection.first.class).to eq(Myfinance::Entities::Entity)
11
+ expect(subject.collection.first.id).to eq(3798)
12
+ expect(subject.collection.first.name).to eq("Minhas Finanças")
13
+ expect(subject.collection.first.account_id).to eq(3613)
14
+ expect(subject.collection.first.charging_uuid).to be_nil
15
+ expect(subject.collection.first.created_at).to eq(DateTime.parse("2015-07-29T11:04:45-03:00"))
16
+ expect(subject.collection.first.default_in_menu).to be_truthy
17
+ expect(subject.collection.first.deleted_at).to be_nil
18
+ expect(subject.collection.first.federation_subscription_number).to eq("")
19
+ expect(subject.collection.first.imported_from_sync_at).to be_nil
20
+ expect(subject.collection.first.updated_at).to eq(DateTime.parse("2015-07-29T14:30:36-03:00"))
21
+ expect(subject.collection.count).to eq(1)
22
+ end
23
+ end
24
+
25
+ context "when not found" do
26
+ let(:client) { Myfinance.client('') }
27
+ subject { client.entities.find_all }
28
+
29
+ it "raises NotFound" do
30
+ expect{ subject }.to raise_error(Myfinance::RequestError)
31
+ end
32
+ end
33
+ end
34
+
35
+ describe "#find", vcr: true do
36
+ context "when success" do
37
+ subject { client.entities.find(3798) }
38
+
39
+ it "returns a find_all of orders" do
40
+ expect(subject.class).to eq(Myfinance::Entities::Entity)
41
+ expect(subject.id).to eq(3798)
42
+ expect(subject.name).to eq("Minhas Finanças")
43
+ expect(subject.account_id).to eq(3613)
44
+ expect(subject.charging_uuid).to be_nil
45
+ expect(subject.created_at).to eq(DateTime.parse("2015-07-29T11:04:45-03:00"))
46
+ expect(subject.default_in_menu).to be_truthy
47
+ expect(subject.deleted_at).to be_nil
48
+ expect(subject.federation_subscription_number).to eq("")
49
+ expect(subject.imported_from_sync_at).to be_nil
50
+ expect(subject.updated_at).to eq(DateTime.parse("2015-07-29T14:30:36-03:00"))
51
+ end
52
+ end
53
+
54
+ context "when not found" do
55
+ let(:client) { Myfinance.client('') }
56
+ subject { client.entities.find(3798) }
57
+
58
+ it "raises NotFound" do
59
+ expect{ subject }.to raise_error(Myfinance::RequestError)
60
+ end
61
+ end
62
+ end
63
+ end