myfinance 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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