dune-balanced 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +13 -0
  6. data/CHANGELOG.md +5 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +125 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +63 -0
  11. data/Rakefile +34 -0
  12. data/app/controllers/dune/balanced/notifications_controller.rb +11 -0
  13. data/app/decorators/dune/balanced/customer_decorator.rb +14 -0
  14. data/app/models/dune/balanced/.gitkip +0 -0
  15. data/app/models/dune/balanced/contributor.rb +11 -0
  16. data/app/models/dune/balanced/customer.rb +56 -0
  17. data/app/models/dune/balanced/event.rb +101 -0
  18. data/app/models/dune/balanced/order.rb +9 -0
  19. data/app/models/dune/balanced/order_proxy.rb +55 -0
  20. data/app/models/dune/balanced/payout.rb +77 -0
  21. data/app/models/dune/balanced/refund.rb +53 -0
  22. data/app/models/dune/balanced/user.rb +6 -0
  23. data/app/observers/dune/balanced/events_observer/debit_canceled.rb +13 -0
  24. data/bin/rails +8 -0
  25. data/config/initializers/balanced.rb +2 -0
  26. data/config/initializers/events_observer.rb +2 -0
  27. data/config/locales/en.yml +9 -0
  28. data/config/routes.rb +4 -0
  29. data/db/migrate/20140211203335_create_balanced_contributors.rb +10 -0
  30. data/db/migrate/20140324175041_add_bank_account_uri_to_balanced_contributors.rb +5 -0
  31. data/db/migrate/20140817195359_create_dune_balanced_orders.rb +10 -0
  32. data/dune-balanced.gemspec +32 -0
  33. data/lib/dune/balanced.rb +9 -0
  34. data/lib/dune/balanced/engine.rb +13 -0
  35. data/lib/dune/balanced/version.rb +5 -0
  36. data/spec/controllers/dune/balanced/notifications_controller_spec.rb +61 -0
  37. data/spec/decorators/dune/balanced/customer_decorator_spec.rb +19 -0
  38. data/spec/fixtures/notifications/bank_account_verification.deposited.yml +48 -0
  39. data/spec/fixtures/notifications/bank_account_verification.verified.yml +48 -0
  40. data/spec/fixtures/notifications/debit.canceled.yml +74 -0
  41. data/spec/fixtures/notifications/debit.created.yml +72 -0
  42. data/spec/fixtures/notifications/debit.succeeded.yml +72 -0
  43. data/spec/models/dune/balanced/customer_spec.rb +73 -0
  44. data/spec/models/dune/balanced/event_spec.rb +219 -0
  45. data/spec/models/dune/balanced/order_proxy_spec.rb +87 -0
  46. data/spec/models/dune/balanced/order_spec.rb +8 -0
  47. data/spec/models/dune/balanced/payout_spec.rb +104 -0
  48. data/spec/models/dune/balanced/refund_spec.rb +157 -0
  49. data/spec/observers/dune/balanced/events_observer/debit_canceled_spec.rb +32 -0
  50. data/spec/spec_helper.rb +18 -0
  51. data/spec/support/fixtures_test_helper.rb +11 -0
  52. metadata +223 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c0e991d42abe166c2df185f37c059bec1943db64
4
+ data.tar.gz: 14c445795667912a7798a09e5669ae026b5ac1d0
5
+ SHA512:
6
+ metadata.gz: b1cdff697436bddfd26da4881697a8a358057b24486ffb27c9efac7b11c4f007b717723ba738e78849344802b2f5e03eee4bcaf09474048ba19104062a901bc3
7
+ data.tar.gz: b71c1b0fb7499dfb5453c35dfaef813f2dee15ebc6231591c6a43ba97d88630520876add8d16d9dc955aa4caf42580681fb7e5570a640bac0896616be9c5038e
@@ -0,0 +1,5 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ spec/dummy/log/*.log
5
+ spec/dummy/db/*.sqlite3
@@ -0,0 +1,3 @@
1
+ [submodule "spec/dummy"]
2
+ path = spec/dummy
3
+ url = https://github.com/FromUte/dune.git
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format d
@@ -0,0 +1,13 @@
1
+ rvm:
2
+ - 2.1.2
3
+
4
+ before_install: gem update --remote bundler
5
+
6
+ before_script:
7
+ - "bundle exec rake db:migrate"
8
+
9
+ script:
10
+ - "bundle exec rspec"
11
+
12
+ notifications:
13
+ webhooks: https://ci.neighbor.ly/projects/a0073d78-eb37-4fc1-8dfd-e2420d39e948/status
@@ -0,0 +1,5 @@
1
+ # CHANGELOG
2
+
3
+ ## 1.0.0
4
+
5
+ * First version From neighborly-balanced
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dune-balanced.gemspec
4
+ gemspec
@@ -0,0 +1,125 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dune-balanced (2.0.2)
5
+ balanced (~> 1.1)
6
+ draper (~> 1.3)
7
+ faraday (= 0.8.9)
8
+ faraday_middleware (= 0.9.0)
9
+ rails (~> 4.0)
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ actionmailer (4.0.3)
15
+ actionpack (= 4.0.3)
16
+ mail (~> 2.5.4)
17
+ actionpack (4.0.3)
18
+ activesupport (= 4.0.3)
19
+ builder (~> 3.1.0)
20
+ erubis (~> 2.7.0)
21
+ rack (~> 1.5.2)
22
+ rack-test (~> 0.6.2)
23
+ activemodel (4.0.3)
24
+ activesupport (= 4.0.3)
25
+ builder (~> 3.1.0)
26
+ activerecord (4.0.3)
27
+ activemodel (= 4.0.3)
28
+ activerecord-deprecated_finders (~> 1.0.2)
29
+ activesupport (= 4.0.3)
30
+ arel (~> 4.0.0)
31
+ activerecord-deprecated_finders (1.0.3)
32
+ activesupport (4.0.3)
33
+ i18n (~> 0.6, >= 0.6.4)
34
+ minitest (~> 4.2)
35
+ multi_json (~> 1.3)
36
+ thread_safe (~> 0.1)
37
+ tzinfo (~> 0.3.37)
38
+ addressable (2.3.6)
39
+ arel (4.0.2)
40
+ atomic (1.1.14)
41
+ balanced (1.1.1)
42
+ addressable (~> 2.3.5)
43
+ faraday (>= 0.8.6, <= 0.9.0)
44
+ faraday_middleware (~> 0.9.0)
45
+ builder (3.1.4)
46
+ diff-lcs (1.2.5)
47
+ draper (1.4.0)
48
+ actionpack (>= 3.0)
49
+ activemodel (>= 3.0)
50
+ activesupport (>= 3.0)
51
+ request_store (~> 1.0)
52
+ erubis (2.7.0)
53
+ faraday (0.8.9)
54
+ multipart-post (~> 1.2.0)
55
+ faraday_middleware (0.9.0)
56
+ faraday (>= 0.7.4, < 0.9)
57
+ hike (1.2.3)
58
+ i18n (0.6.9)
59
+ mail (2.5.4)
60
+ mime-types (~> 1.16)
61
+ treetop (~> 1.4.8)
62
+ mime-types (1.25.1)
63
+ minitest (4.7.5)
64
+ multi_json (1.8.4)
65
+ multipart-post (1.2.0)
66
+ polyglot (0.3.5)
67
+ rack (1.5.2)
68
+ rack-test (0.6.2)
69
+ rack (>= 1.0)
70
+ rails (4.0.3)
71
+ actionmailer (= 4.0.3)
72
+ actionpack (= 4.0.3)
73
+ activerecord (= 4.0.3)
74
+ activesupport (= 4.0.3)
75
+ bundler (>= 1.3.0, < 2.0)
76
+ railties (= 4.0.3)
77
+ sprockets-rails (~> 2.0.0)
78
+ railties (4.0.3)
79
+ actionpack (= 4.0.3)
80
+ activesupport (= 4.0.3)
81
+ rake (>= 0.8.7)
82
+ thor (>= 0.18.1, < 2.0)
83
+ rake (10.1.1)
84
+ request_store (1.1.0)
85
+ rspec-core (2.14.7)
86
+ rspec-expectations (2.14.5)
87
+ diff-lcs (>= 1.1.3, < 2.0)
88
+ rspec-mocks (2.14.5)
89
+ rspec-rails (2.14.1)
90
+ actionpack (>= 3.0)
91
+ activemodel (>= 3.0)
92
+ activesupport (>= 3.0)
93
+ railties (>= 3.0)
94
+ rspec-core (~> 2.14.0)
95
+ rspec-expectations (~> 2.14.0)
96
+ rspec-mocks (~> 2.14.0)
97
+ shoulda-matchers (2.6.2)
98
+ activesupport (>= 3.0.0)
99
+ sprockets (2.12.2)
100
+ hike (~> 1.2)
101
+ multi_json (~> 1.0)
102
+ rack (~> 1.0)
103
+ tilt (~> 1.1, != 1.3.0)
104
+ sprockets-rails (2.0.1)
105
+ actionpack (>= 3.0)
106
+ activesupport (>= 3.0)
107
+ sprockets (~> 2.8)
108
+ sqlite3 (1.3.8)
109
+ thor (0.18.1)
110
+ thread_safe (0.1.3)
111
+ atomic
112
+ tilt (1.4.1)
113
+ treetop (1.4.15)
114
+ polyglot
115
+ polyglot (>= 0.3.1)
116
+ tzinfo (0.3.38)
117
+
118
+ PLATFORMS
119
+ ruby
120
+
121
+ DEPENDENCIES
122
+ dune-balanced!
123
+ rspec-rails (~> 2.14)
124
+ shoulda-matchers
125
+ sqlite3 (~> 1.3)
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Neighbor.ly
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,63 @@
1
+ # Dune::Balanced
2
+
3
+ [![Build Status](https://travis-ci.org/dune/dune-balanced.png?branch=master)](https://travis-ci.org/dune/dune-balanced) [![Code Climate](https://codeclimate.com/github/dune/dune-balanced.png)](https://codeclimate.com/github/dune/dune-balanced)
4
+
5
+ ## What
6
+
7
+ This is an integration between [Balanced](https://www.balancedpayments.com/) and [Dune investement](https://github.com/FromUte/dune-investissement), a crowdfunding platform.
8
+
9
+ ## How
10
+
11
+ Include this gem as dependency of your project, adding the following line in your `Gemfile`.
12
+
13
+ ```ruby
14
+ # Gemfile
15
+ gem 'dune-balanced'
16
+ ```
17
+
18
+ And install the migrations:
19
+
20
+ ```console
21
+ $ bundle exec rake railties:install:migrations db:migrate
22
+ ```
23
+
24
+ Dune::Balanced is a Rails Engine, integrating with your (dune-investissement) Rails application with very little of effort. To turn the engine on, mount it in an appropriate route:
25
+
26
+ ```ruby
27
+ # config/routes.rb
28
+ mount Dune::Balanced::Engine => '/balanced/', as: :dune_balanced
29
+ ```
30
+
31
+ As you might know, Dune has a `Configuration` class, responsible to... project's configuration. You need to set API key secret and Marketplace ID, and you find yours acessing settings of [Balanced Dashboard](https://dashboard.balancedpayments.com/). Also you need to inform how the debit will appears on the statement.
32
+
33
+ ```console
34
+ $ rails runner "Configuration.create!(name: 'balanced_api_key_secret', value: 'YOUR_API_KEY_SECRET_HERE')"
35
+ $ rails runner "Configuration.create!(name: 'balanced_marketplace_id', value: 'YOUR_MARKETPLACE_ID_HERE')"
36
+ $ rails runner "Configuration.create!(name: 'balanced_appears_on_statement_as', value: 'Neighbor.ly')"
37
+ ```
38
+
39
+ ### Balanced Webhook
40
+
41
+ Balanced has a webhook that allow us to receive notifications of events that happen there. We execute a few things when certain events occurs, so you need to add on [Balanced Settings](https://dashboard.balancedpayments.com) the webhook with the following URL:
42
+
43
+ `http://my-dune.com/balanced/notifications`
44
+
45
+ ## Contributing
46
+
47
+ 1. Fork it
48
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
49
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
50
+ 4. Push to the branch (`git push origin my-new-feature`)
51
+ 5. Create new Pull Request
52
+
53
+ ### Running specs
54
+
55
+ We prize for our test suite and coverage, so it would be great if you could run the specs to ensure that your patch is not breaking the existing codebase.
56
+
57
+ ```
58
+ bundle exec rspec
59
+ ```
60
+
61
+ ## License
62
+
63
+ Licensed under the [MIT license](LICENSE.txt).
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Dune::Balanced::Creditcard'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task default: :test
@@ -0,0 +1,11 @@
1
+ module Dune::Balanced
2
+ class NotificationsController < ApplicationController
3
+ def create
4
+ event = Event.new(params)
5
+ event.save
6
+
7
+ status = event.valid? ? :ok : :bad_request
8
+ render nothing: true, status: status
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ require 'draper'
2
+
3
+ module Dune::Balanced
4
+ class CustomerDecorator < Draper::Decorator
5
+ delegate_all
6
+
7
+ delegate :bank_accounts, to: :fetch
8
+
9
+ def bank_account_name
10
+ @bank_account ||= bank_accounts.first
11
+ "#{@bank_account.bank_name} #{@bank_account.account_number}"
12
+ end
13
+ end
14
+ end
File without changes
@@ -0,0 +1,11 @@
1
+ module Dune::Balanced
2
+ class Contributor < ActiveRecord::Base
3
+ self.table_name = :balanced_contributors
4
+
5
+ # The class_name is needed because Ruby tries
6
+ # to get this User constant inside
7
+ # Dune::Balanced module.
8
+ belongs_to :user, class_name: '::User'
9
+ has_many :projects, through: :user
10
+ end
11
+ end
@@ -0,0 +1,56 @@
1
+ module Dune::Balanced
2
+ class Customer
3
+ def initialize(user, request_params)
4
+ @user = user
5
+ @request_params = request_params
6
+ end
7
+
8
+ def fetch
9
+ current_customer_href = @user.balanced_contributor.try(:href)
10
+ @customer ||= if current_customer_href
11
+ ::Balanced::Customer.find(current_customer_href)
12
+ else
13
+ create!
14
+ end
15
+ end
16
+
17
+ def update!
18
+ return unless user_params
19
+ fetch.name = user_params.delete(:name)
20
+ fetch.address = { line1: user_params[:address_street],
21
+ city: user_params[:address_city],
22
+ state: user_params[:address_state],
23
+ postal_code: user_params[:address_zip_code]
24
+ }
25
+ fetch.save
26
+ @user.update!(user_params)
27
+ end
28
+
29
+ private
30
+ def create!
31
+ customer = ::Balanced::Customer.new(meta: { user_id: @user.id },
32
+ name: @user.display_name,
33
+ email: @user.email,
34
+ address: {
35
+ line1: @user.address_street,
36
+ city: @user.address_city,
37
+ state: @user.address_state,
38
+ postal_code: @user.address_zip_code
39
+ })
40
+ customer.save
41
+ @user.create_balanced_contributor(href: customer.href)
42
+
43
+ customer
44
+ end
45
+
46
+ def user_params
47
+ @request_params.permit(payment: [user: %i(
48
+ name
49
+ address_street
50
+ address_city
51
+ address_state
52
+ address_zip_code
53
+ )])[:payment][:user]
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,101 @@
1
+ require 'observer'
2
+
3
+ module Dune::Balanced
4
+ class Event
5
+ extend Observable
6
+
7
+ TYPES = %w(debit.canceled
8
+ debit.created
9
+ debit.succeeded
10
+ bank_account_verification.verified
11
+ bank_account_verification.deposited)
12
+
13
+ def initialize(request_params)
14
+ @request_params = request_params
15
+ end
16
+
17
+ def save
18
+ return unless valid?
19
+
20
+ if resource.present?
21
+ key = "#{ActiveModel::Naming.param_key(resource)}_id".to_sym
22
+ PaymentEngine.create_payment_notification(
23
+ key => resource.id,
24
+ extra_data: @request_params.to_json
25
+ )
26
+ end
27
+
28
+ self.class.changed
29
+ self.class.notify_observers(self)
30
+ end
31
+
32
+ def valid?
33
+ valid_type? or return false
34
+
35
+ {
36
+ 'debit.created' => -> { values_matches? },
37
+ 'debit.succeeded' => -> { values_matches? },
38
+ 'debit.canceled' => -> { values_matches? },
39
+ # Skip validation for these types
40
+ 'bank_account_verification.deposited' => -> { true },
41
+ 'bank_account_verification.verified' => -> { true }
42
+ }.fetch(type).call
43
+ end
44
+
45
+ def resource
46
+ payment_id = entity_params.fetch(:id)
47
+ return false unless payment_id
48
+
49
+ resource = Contribution.find_by(payment_id: payment_id)
50
+ unless resource.present?
51
+ resource = Match.find_by(payment_id: payment_id)
52
+ end
53
+ resource
54
+ end
55
+
56
+ def type
57
+ @request_params.fetch(:events).last.fetch(:type)
58
+ end
59
+
60
+ def entity_href
61
+ entity_params.fetch(:href)
62
+ end
63
+
64
+ def contributor
65
+ Dune::Balanced::Contributor.find_by(bank_account_href: bank_account_href)
66
+ end
67
+
68
+ def user
69
+ contributor.try(:user) || resource.try(:user)
70
+ end
71
+
72
+ protected
73
+
74
+ def valid_type?
75
+ TYPES.include? type
76
+ end
77
+
78
+ def values_matches?
79
+ resource.try(:price_in_cents).eql?(payment_amount)
80
+ end
81
+
82
+ def payment_amount
83
+ entity_params.fetch(:amount).to_i
84
+ end
85
+
86
+ def verification?
87
+ !!type['bank_account_verification']
88
+ end
89
+
90
+ def bank_account_href
91
+ if verification?
92
+ "/bank_accounts/#{entity_params.fetch(:links).fetch(:bank_account)}"
93
+ end
94
+ end
95
+
96
+ def entity_params
97
+ entity_type = type.split('.').first.pluralize
98
+ @request_params.fetch(:events).last.fetch(:entity).fetch(entity_type).last
99
+ end
100
+ end
101
+ end