dune-balanced 1.0.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 (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