dune-balanced-creditcard 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.travis.yml +13 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +48 -0
- data/Rakefile +34 -0
- data/app/assets/images/dune/balanced/creditcard/.gitkeep +0 -0
- data/app/assets/javascripts/dune/balanced/creditcard/flash.js.coffee +15 -0
- data/app/assets/javascripts/dune/balanced/creditcard/payments.js.coffee.erb +86 -0
- data/app/assets/javascripts/dune-balanced-creditcard.js +1 -0
- data/app/assets/stylesheets/dune/balanced/creditcard/application.css +16 -0
- data/app/controllers/dune/balanced/creditcard/application_controller.rb +4 -0
- data/app/controllers/dune/balanced/creditcard/payments_controller.rb +84 -0
- data/app/models/dune/balanced/creditcard/payment.rb +94 -0
- data/app/models/dune/balanced/creditcard/transaction_additional_fee_calculator.rb +12 -0
- data/app/models/dune/balanced/creditcard/transaction_fee_calculator_base.rb +31 -0
- data/app/models/dune/balanced/creditcard/transaction_inclusive_fee_calculator.rb +13 -0
- data/app/views/dune/balanced/creditcard/.gitkeep +0 -0
- data/app/views/dune/balanced/creditcard/payments/new.html.slim +98 -0
- data/bin/rails +8 -0
- data/config/initializers/registration.rb +5 -0
- data/config/locales/en.yml +32 -0
- data/config/locales/simple_form.en.yml +12 -0
- data/config/routes.rb +5 -0
- data/dune-balanced-creditcard.gemspec +27 -0
- data/lib/dune/balanced/creditcard/engine.rb +9 -0
- data/lib/dune/balanced/creditcard/interface.rb +27 -0
- data/lib/dune/balanced/creditcard/version.rb +7 -0
- data/lib/dune/balanced/creditcard.rb +11 -0
- data/lib/float_extensions.rb +11 -0
- data/spec/controllers/neighborly/balanced/creditcard/payments_controller_spec.rb +199 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/models/configuration.rb +9 -0
- data/spec/dummy/app/models/contribution.rb +32 -0
- data/spec/dummy/app/models/match.rb +31 -0
- data/spec/dummy/app/models/payment_engine.rb +5 -0
- data/spec/dummy/app/models/project.rb +9 -0
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +24 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +8 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/schema.rb +27 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/lib/neighborly/balanced/creditcard/interface_spec.rb +37 -0
- data/spec/models/neighborly/balanced/creditcard/payment_spec.rb +223 -0
- data/spec/models/neighborly/balanced/creditcard/transaction_additional_fee_calculator_spec.rb +38 -0
- data/spec/models/neighborly/balanced/creditcard/transaction_inclusive_fee_calculator_spec.rb +19 -0
- data/spec/spec_helper.rb +15 -0
- metadata +252 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 14effd0d0371b543d21fe4c045d35dd4109e1e40
|
4
|
+
data.tar.gz: 68ef4267ea6a24e978c7d318a348c859e95493fc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a5dc95a5b2653b6351b5744446157b1812ecf94a98977980017eb24e266ac94fae07a46a91a2e51cc427218d7be8143642feb6b1a5abaeea133aa6e215644db9
|
7
|
+
data.tar.gz: c38c301ed8689a0b1701c2a3773e7478cf627ca8cc4776bb932cc76d28abc5142064f18898d229a1f0bb176f3c8a2b8720d293b400d21b8ab8591565116d1582
|
data/.gitignore
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
*.gem
|
2
|
+
*.log
|
3
|
+
*.rbc
|
4
|
+
.bundle
|
5
|
+
.config
|
6
|
+
.yardoc
|
7
|
+
Gemfile.lock
|
8
|
+
InstalledFiles
|
9
|
+
_yardoc
|
10
|
+
coverage
|
11
|
+
doc/
|
12
|
+
lib/bundler/man
|
13
|
+
pkg
|
14
|
+
rdoc
|
15
|
+
spec/reports
|
16
|
+
spec/dummy/db/*.sqlite3
|
17
|
+
test/tmp
|
18
|
+
test/version_tmp
|
19
|
+
tmp
|
20
|
+
spec/dummy/log/*.log
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Legrand Pierre
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Dune::Balanced::Creditcard
|
2
|
+
|
3
|
+
|
4
|
+
## What
|
5
|
+
|
6
|
+
This is an integration between [Balanced](https://www.balancedpayments.com/) and [dune-investissement](https://github.com/FromUte/dune-donate), a crowdfunding platform.
|
7
|
+
|
8
|
+
## How
|
9
|
+
|
10
|
+
Include this gem as dependency of your project, adding the following line in your `Gemfile`.
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
# Gemfile
|
14
|
+
gem 'dune-balanced-creditcard'
|
15
|
+
```
|
16
|
+
|
17
|
+
Dune::Balanced::Creditcard 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:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# config/routes.rb
|
21
|
+
mount Dune::Balanced::Creditcard::Engine => '/balanced/creditcard/', as: :dune_balanced_creditcard
|
22
|
+
```
|
23
|
+
|
24
|
+
And load our JavaScript:
|
25
|
+
|
26
|
+
```coffeescript
|
27
|
+
//= require dune-balanced-creditcard
|
28
|
+
```
|
29
|
+
|
30
|
+
## Contributing
|
31
|
+
|
32
|
+
1. Fork it
|
33
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
34
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
35
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
36
|
+
5. Create new Pull Request
|
37
|
+
|
38
|
+
### Running specs
|
39
|
+
|
40
|
+
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.
|
41
|
+
|
42
|
+
```
|
43
|
+
bundle exec rspec
|
44
|
+
```
|
45
|
+
|
46
|
+
## License
|
47
|
+
|
48
|
+
Licensed under the [MIT license](LICENSE.txt).
|
data/Rakefile
ADDED
@@ -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
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Dune.Dune ?= {}
|
2
|
+
Dune.Dune.Balanced ?= {}
|
3
|
+
Dune.Dune.Balanced.Creditcard ?= {}
|
4
|
+
|
5
|
+
Dune.Dune.Balanced.Creditcard.Flash =
|
6
|
+
message: (text)->
|
7
|
+
this.remove()
|
8
|
+
alertBox = $('<div>', { 'class': 'alert-box error text-center', 'html':
|
9
|
+
$('<h5>', { 'html': text })
|
10
|
+
} )
|
11
|
+
errorBoxWrapper = $('<div>', { 'class': 'error-box large-12 columns hide', 'html': alertBox}).insertBefore('.dune-balanced-creditcard-form .submit')
|
12
|
+
errorBoxWrapper.fadeIn(300)
|
13
|
+
|
14
|
+
remove: ->
|
15
|
+
$('.error-box').remove()
|
@@ -0,0 +1,86 @@
|
|
1
|
+
Dune.Dune ?= {}
|
2
|
+
Dune.Dune.Balanced ?= {}
|
3
|
+
Dune.Dune.Balanced.Creditcard ?= {}
|
4
|
+
Dune.Dune.Balanced.Creditcard.Payments ?= {}
|
5
|
+
|
6
|
+
Dune.Dune.Balanced.Creditcard.Payments.New = Backbone.View.extend
|
7
|
+
el: '.dune-balanced-creditcard-form'
|
8
|
+
|
9
|
+
initialize: ->
|
10
|
+
_.bindAll(this, 'submit', 'submitToBalanced', 'toggleAddNewCard', 'toggleSelected')
|
11
|
+
this.Flash = Dune.Dune.Balanced.Creditcard.Flash
|
12
|
+
|
13
|
+
$.getScript 'https://js.balancedpayments.com/1.1/balanced.js'
|
14
|
+
|
15
|
+
this.$button = this.$('input[type=submit]')
|
16
|
+
this.$('form').bind('submit', this.submit)
|
17
|
+
this.$('input[type=radio]').bind('change', this.toggleAddNewCard)
|
18
|
+
this.$('input[type=radio]').bind('change', this.toggleSelected)
|
19
|
+
this.toggleSelected()
|
20
|
+
|
21
|
+
submit: (event) ->
|
22
|
+
selectedCard = this.$('[name="payment[use_card]"]:checked, [name="payment[use_card]"]:hidden')
|
23
|
+
return if $.inArray(selectedCard.val(), ['new', '']) == -1
|
24
|
+
|
25
|
+
event.preventDefault()
|
26
|
+
this.submitToBalanced(selectedCard)
|
27
|
+
# This return is necessary because of jquery_ujs was disabling the submit
|
28
|
+
# button even when we enable it.
|
29
|
+
return false
|
30
|
+
|
31
|
+
submitToBalanced: (selectedCard) ->
|
32
|
+
that = this
|
33
|
+
$.rails.disableFormElements(that.$el)
|
34
|
+
|
35
|
+
creditCardData =
|
36
|
+
number: this.$('#payment_card_number').val()
|
37
|
+
expiration_month: this.$('#payment_expiration_month').val()
|
38
|
+
expiration_year: this.$('#payment_expiration_year').val()
|
39
|
+
cvv: this.$('#payment_security_code').val()
|
40
|
+
name: this.$('#payment_user_name').val()
|
41
|
+
address:
|
42
|
+
postal_code: this.$('#payment_user_address_zip_code').val()
|
43
|
+
country_code: 'USA'
|
44
|
+
|
45
|
+
balanced_callback_for_201 = (response) ->
|
46
|
+
selectedCard.val(response.cards[0].href)
|
47
|
+
that.$('[data-balanced-credit-card-input]').val('')
|
48
|
+
that.$('form').submit()
|
49
|
+
that.Flash.remove()
|
50
|
+
|
51
|
+
<% i18n_scope = 'dune.balanced.creditcard.payments.new.errors' %>
|
52
|
+
|
53
|
+
balanced_callback_for_400 = (response) ->
|
54
|
+
that.Flash.message('<%= I18n.t("#{i18n_scope}.invalid_card") %>')
|
55
|
+
|
56
|
+
balanced_callback_for_402 = (response) ->
|
57
|
+
that.Flash.message('<%= I18n.t("#{i18n_scope}.card_tokenization_error") %>')
|
58
|
+
|
59
|
+
balanced_callback_for_404 = (response) ->
|
60
|
+
that.Flash.message('<%= I18n.t("#{i18n_scope}.marketplace_uri") %>')
|
61
|
+
|
62
|
+
balanced_callback_for_500 = (response) ->
|
63
|
+
that.Flash.message('<%= I18n.t("#{i18n_scope}.balanced") %>')
|
64
|
+
|
65
|
+
balanced.card.create creditCardData, (response) ->
|
66
|
+
switch response.status_code
|
67
|
+
when 201 then balanced_callback_for_201(response)
|
68
|
+
when 400 then balanced_callback_for_400(response)
|
69
|
+
when 402 then balanced_callback_for_402(response)
|
70
|
+
when 404 then balanced_callback_for_404(response)
|
71
|
+
when 500 then balanced_callback_for_500(response)
|
72
|
+
|
73
|
+
if response.status != 201
|
74
|
+
$.rails.enableFormElements(that.$el)
|
75
|
+
$submit = that.$('input[type=submit]')
|
76
|
+
$submit.val($submit.data('enable-with'))
|
77
|
+
|
78
|
+
toggleSelected: ->
|
79
|
+
this.$('.card-box').removeClass('selected')
|
80
|
+
this.$('input[type=radio]:checked').parents('.card-box').addClass('selected')
|
81
|
+
|
82
|
+
toggleAddNewCard: ->
|
83
|
+
if this.$('#payment_use_card_new').is(':checked')
|
84
|
+
this.$('.add-new-creditcard-form').removeClass('hide')
|
85
|
+
else
|
86
|
+
this.$('.add-new-creditcard-form').addClass('hide')
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require_tree .
|
@@ -0,0 +1,16 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any styles
|
10
|
+
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
|
11
|
+
* file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
16
|
+
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Dune::Balanced::Creditcard
|
2
|
+
class PaymentsController < ActionController::Base
|
3
|
+
before_filter :authenticate_user!
|
4
|
+
|
5
|
+
def new
|
6
|
+
@cards = customer.cards
|
7
|
+
end
|
8
|
+
|
9
|
+
def create
|
10
|
+
attach_card_to_customer
|
11
|
+
update_customer
|
12
|
+
|
13
|
+
payment = Payment.new('balanced-creditcard',
|
14
|
+
customer,
|
15
|
+
resource,
|
16
|
+
resource_params)
|
17
|
+
payment.checkout!
|
18
|
+
redirect_to(*checkout_response_params(resource, payment.successful?))
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def resource
|
23
|
+
@resource ||= if params[:payment][:match_id].present?
|
24
|
+
Match.find(params[:payment].fetch(:match_id))
|
25
|
+
else
|
26
|
+
Contribution.find(params[:payment].fetch(:contribution_id))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def resource_name
|
31
|
+
resource.class.model_name.singular.to_sym
|
32
|
+
end
|
33
|
+
|
34
|
+
def checkout_response_params(resource, success)
|
35
|
+
status = success ? :succeeded : :failed
|
36
|
+
route_params = [resource.project.permalink, resource.id]
|
37
|
+
|
38
|
+
{
|
39
|
+
contribution: {
|
40
|
+
succeeded: [
|
41
|
+
main_app.project_contribution_path(*route_params)
|
42
|
+
],
|
43
|
+
failed: [
|
44
|
+
main_app.edit_project_contribution_path(*route_params),
|
45
|
+
alert: t('.errors.default')
|
46
|
+
]
|
47
|
+
},
|
48
|
+
match: {
|
49
|
+
succeeded: [
|
50
|
+
main_app.project_match_path(*route_params)
|
51
|
+
],
|
52
|
+
failed: [
|
53
|
+
main_app.edit_project_match_path(*route_params),
|
54
|
+
alert: t('.errors.default')
|
55
|
+
]
|
56
|
+
}
|
57
|
+
}.fetch(resource_name).fetch(status)
|
58
|
+
end
|
59
|
+
|
60
|
+
def resource_params
|
61
|
+
params.require(:payment).
|
62
|
+
permit(:contribution_id,
|
63
|
+
:match_id,
|
64
|
+
:use_card,
|
65
|
+
:pay_fee,
|
66
|
+
user: {})
|
67
|
+
end
|
68
|
+
|
69
|
+
def attach_card_to_customer
|
70
|
+
card = Balanced::Card.fetch(resource_params.fetch(:use_card))
|
71
|
+
unless customer.cards.to_a.any? { |c| c.id.eql? card.id }
|
72
|
+
card.associate_to_customer(customer)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def customer
|
77
|
+
@customer ||= Dune::Balanced::Customer.new(current_user, params).fetch
|
78
|
+
end
|
79
|
+
|
80
|
+
def update_customer
|
81
|
+
Dune::Balanced::Customer.new(current_user, params).update!
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Dune::Balanced::Creditcard
|
2
|
+
class Payment
|
3
|
+
attr_reader :engine_name, :customer, :resource, :attrs
|
4
|
+
|
5
|
+
def initialize(engine_name, customer, resource, attrs = {})
|
6
|
+
@engine_name = engine_name
|
7
|
+
@customer = customer
|
8
|
+
@resource = resource
|
9
|
+
@attrs = attrs
|
10
|
+
end
|
11
|
+
|
12
|
+
def checkout!
|
13
|
+
perform_debit!
|
14
|
+
resource.confirm!
|
15
|
+
rescue Balanced::PaymentRequired
|
16
|
+
resource.cancel!
|
17
|
+
ensure
|
18
|
+
resource.update_attributes(
|
19
|
+
payment_id: @debit.try(:id),
|
20
|
+
payment_method: engine_name,
|
21
|
+
payment_service_fee: fee_calculator.fees,
|
22
|
+
payment_service_fee_paid_by_user: attrs[:pay_fee]
|
23
|
+
)
|
24
|
+
update_meta(@debit) if @debit
|
25
|
+
end
|
26
|
+
|
27
|
+
def amount_in_cents
|
28
|
+
(fee_calculator.gross_amount * 100).round
|
29
|
+
end
|
30
|
+
|
31
|
+
def fee_calculator
|
32
|
+
@fee_calculator and return @fee_calculator
|
33
|
+
|
34
|
+
calculator_class = if ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include? attrs[:pay_fee]
|
35
|
+
TransactionAdditionalFeeCalculator
|
36
|
+
else
|
37
|
+
TransactionInclusiveFeeCalculator
|
38
|
+
end
|
39
|
+
|
40
|
+
@fee_calculator = calculator_class.new(resource.value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def debit
|
44
|
+
@debit.try(:sanitize)
|
45
|
+
end
|
46
|
+
|
47
|
+
def successful?
|
48
|
+
%w(pending succeeded).include? @debit.try(:status)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def perform_debit!
|
54
|
+
debit_params = {
|
55
|
+
amount: amount_in_cents,
|
56
|
+
appears_on_statement_as: ::Configuration[:balanced_appears_on_statement_as],
|
57
|
+
description: debit_description,
|
58
|
+
meta: meta,
|
59
|
+
source: card
|
60
|
+
}
|
61
|
+
|
62
|
+
order = Dune::Balanced::OrderProxy.new(resource.project)
|
63
|
+
@debit = order.debit_from(debit_params)
|
64
|
+
end
|
65
|
+
|
66
|
+
def card
|
67
|
+
Balanced::Card.fetch(attrs.fetch(:use_card))
|
68
|
+
end
|
69
|
+
|
70
|
+
def update_meta(debit)
|
71
|
+
debit.meta = meta
|
72
|
+
debit.save
|
73
|
+
end
|
74
|
+
|
75
|
+
def resource_name
|
76
|
+
resource.class.model_name.singular
|
77
|
+
end
|
78
|
+
|
79
|
+
def debit_description
|
80
|
+
I18n.t('description',
|
81
|
+
project_name: resource.try(:project).try(:name),
|
82
|
+
scope: "dune.balanced.creditcard.payments.debit.#{resource_name}")
|
83
|
+
end
|
84
|
+
|
85
|
+
def project_owner_customer
|
86
|
+
@project_owner_customer ||= Dune::Balanced::Customer.new(
|
87
|
+
resource.project.user, {}).fetch
|
88
|
+
end
|
89
|
+
|
90
|
+
def meta
|
91
|
+
PayableResourceSerializer.new(resource).to_json
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'float_extensions'
|
2
|
+
|
3
|
+
module Dune::Balanced::Creditcard
|
4
|
+
class TransactionAdditionalFeeCalculator < TransactionFeeCalculatorBase
|
5
|
+
using FloatExtensions
|
6
|
+
|
7
|
+
def net_amount
|
8
|
+
transaction_value.to_f.floor_with_two_decimal_places
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'float_extensions'
|
2
|
+
|
3
|
+
module Dune::Balanced::Creditcard
|
4
|
+
class TransactionFeeCalculatorBase
|
5
|
+
using FloatExtensions
|
6
|
+
|
7
|
+
attr_writer :transaction_value
|
8
|
+
|
9
|
+
def initialize(transaction_value)
|
10
|
+
@transaction_value = transaction_value
|
11
|
+
end
|
12
|
+
|
13
|
+
def transaction_value
|
14
|
+
@transaction_value.to_f.floor_with_two_decimal_places
|
15
|
+
end
|
16
|
+
|
17
|
+
def gross_amount
|
18
|
+
net_amount + fees
|
19
|
+
end
|
20
|
+
|
21
|
+
def net_amount
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
# Base calculation of fees
|
26
|
+
# 2.9% + 30¢
|
27
|
+
def fees
|
28
|
+
(net_amount * 0.029 + 0.3).ceil_with_two_decimal_places
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'float_extensions'
|
2
|
+
|
3
|
+
module Dune::Balanced::Creditcard
|
4
|
+
class TransactionInclusiveFeeCalculator < TransactionFeeCalculatorBase
|
5
|
+
using FloatExtensions
|
6
|
+
|
7
|
+
# Base calculation of fees
|
8
|
+
# 2.9% + 30¢
|
9
|
+
def net_amount
|
10
|
+
((transaction_value - 0.3) / 1.029).floor_with_two_decimal_places
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
File without changes
|
@@ -0,0 +1,98 @@
|
|
1
|
+
= initjs_tag app_name: 'Dune', partial: true
|
2
|
+
|
3
|
+
.dune-balanced-creditcard-form[data-balanced-credit-card-form]
|
4
|
+
= simple_form_for :payment, url: payments_path, html: { novalidate: '' } do |f|
|
5
|
+
- if params[:match_id].present?
|
6
|
+
= f.input :match_id, as: :hidden, input_html: { value: params[:match_id] }
|
7
|
+
- else
|
8
|
+
= f.input :contribution_id, as: :hidden, input_html: { value: params[:contribution_id] }
|
9
|
+
|
10
|
+
= f.input :pay_fee, as: :hidden, input_html: { value: 1, 'data-pay-payment-fee' => '' }
|
11
|
+
section.highlighted[class="#{'use-existing-item' if @cards.any?}"]
|
12
|
+
- if @cards.any?
|
13
|
+
section.use-existing-item.row
|
14
|
+
.large-12.columns.title
|
15
|
+
h4 = t('.cards.title')
|
16
|
+
|
17
|
+
- @cards.reverse_each.with_index do |card,index|
|
18
|
+
.large-12.columns
|
19
|
+
.card-box
|
20
|
+
label.row
|
21
|
+
dl
|
22
|
+
.large-1.columns
|
23
|
+
= f.radio_button :use_card, card.href, { checked: index.zero?, label: false }
|
24
|
+
.large-6.columns
|
25
|
+
dt.hide
|
26
|
+
dd = t('.cards.card_ending_in', brand: card.brand, number: card.number)
|
27
|
+
.large-5.columns.expiration
|
28
|
+
dt = t('.cards.expiration')
|
29
|
+
dd = sprintf('%02i/%i', card.expiration_month, card.expiration_year)
|
30
|
+
|
31
|
+
- else
|
32
|
+
= f.input :use_card, as: :hidden
|
33
|
+
|
34
|
+
.row
|
35
|
+
.large-12.columns.title
|
36
|
+
h4 = t('.card.title')
|
37
|
+
|
38
|
+
|
39
|
+
section.row
|
40
|
+
.large-12.columns
|
41
|
+
.card-box[class="#{'new-card' unless @cards.any?}"]
|
42
|
+
.row
|
43
|
+
- if @cards.any?
|
44
|
+
label
|
45
|
+
.large-1.columns
|
46
|
+
= f.radio_button :use_card, 'new', { checked: false, label: false }
|
47
|
+
.large-8.columns
|
48
|
+
= t('.add_new_card')
|
49
|
+
.large-3.columns.expiration
|
50
|
+
|
51
|
+
.large-12.columns.add-new-creditcard-form[class="#{'hide with-others-cards' if @cards.any?}"]
|
52
|
+
.row
|
53
|
+
.large-5.columns
|
54
|
+
= f.input :card_number, input_html: { 'data-balanced-credit-card-input' => '' }
|
55
|
+
.large-2.columns
|
56
|
+
= f.input :security_code, maxlength: 4, input_html: { 'data-balanced-credit-card-input' => '' }
|
57
|
+
.large-5.columns
|
58
|
+
- date = Date.today + 1.month
|
59
|
+
= f.label :expiration
|
60
|
+
.row.collapse
|
61
|
+
.large-5.small-5.columns
|
62
|
+
= select_month date, { use_two_digit_numbers: true }, { name: 'payment[expiration_month]', id: 'payment_expiration_month', 'data-balanced-credit-card-input' => '' }
|
63
|
+
.large-1.small-1.columns.text-center.divider
|
64
|
+
| /
|
65
|
+
.large-6.small-6.columns
|
66
|
+
= select_year date, { start_year: date.year, end_year: date.year+15 }, { name: 'payment[expiration_year]', id: 'payment_expiration_year', 'data-balanced-credit-card-input' => '' }
|
67
|
+
|
68
|
+
section.user-informations.highlighted
|
69
|
+
= f.simple_fields_for :user do |fu|
|
70
|
+
.row
|
71
|
+
.large-12.columns.title
|
72
|
+
h4 = t('.billing.title')
|
73
|
+
|
74
|
+
.row
|
75
|
+
.large-6.columns
|
76
|
+
= fu.input :name, required: false, input_html: { value: @customer.name }
|
77
|
+
.large-6.columns
|
78
|
+
= fu.input :address_street, required: false, input_html: { value: @customer.address.try(:[], :line1) }
|
79
|
+
.row
|
80
|
+
.large-5.columns
|
81
|
+
= fu.input :address_city, required: false, input_html: { value: @customer.address.try(:[], :city) }
|
82
|
+
.large-4.columns
|
83
|
+
= fu.input :address_state, required: false, as: :select, collection: State.array, selected: @customer.address.try(:[], :state), include_blank: false
|
84
|
+
.large-3.columns
|
85
|
+
= fu.input :address_zip_code, input_html: { value: @customer.address.try(:[], :postal_code) }
|
86
|
+
|
87
|
+
section
|
88
|
+
.row
|
89
|
+
.large-12.columns.terms
|
90
|
+
= t('.terms', link: link_to(t('.terms-link'), main_app.terms_path(), data: { 'reveal-id' => 'terms-modal', 'reveal-ajax' => true })).html_safe
|
91
|
+
|
92
|
+
.row
|
93
|
+
.large-6.columns.submit
|
94
|
+
= f.button :submit, t('.confirm'), data: { disable_with: t('.proccessing'), enable_with: t('.confirm') }
|
95
|
+
.large-6.columns.text-right.balanced-seal
|
96
|
+
= link_to image_tag('https://balancedpowered.s3.amazonaws.com/secured-1-4.png'), 'https://www.balancedpayments.com/', target: :blank
|
97
|
+
|
98
|
+
#terms-modal.reveal-modal.small.fixed
|
data/bin/rails
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
|
3
|
+
|
4
|
+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
5
|
+
ENGINE_PATH = File.expand_path('../../lib/dune/balanced/creditcard/engine', __FILE__)
|
6
|
+
|
7
|
+
require 'rails/all'
|
8
|
+
require 'rails/engine/commands'
|