dune-balanced-creditcard 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.
- 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'
|