spree_ideal 2.4.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 (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +12 -0
  5. data/LICENSE +22 -0
  6. data/README.md +69 -0
  7. data/Rakefile +17 -0
  8. data/app/assets/images/ideal_small.png +0 -0
  9. data/app/assets/javascripts/admin/spree_ideal.js +1 -0
  10. data/app/assets/javascripts/store/spree_ideal.js +1 -0
  11. data/app/assets/stylesheets/admin/spree_ideal.css +3 -0
  12. data/app/assets/stylesheets/store/spree_ideal.css +3 -0
  13. data/app/controllers/spree/checkout_controller_decorator.rb +21 -0
  14. data/app/controllers/spree/ideal_controller.rb +160 -0
  15. data/app/models/spree/hash_factory.rb +64 -0
  16. data/app/models/spree/locale_helper.rb +48 -0
  17. data/app/models/spree/order_decorator.rb +21 -0
  18. data/app/models/spree/payment_method/ideal.rb +15 -0
  19. data/app/models/spree/url_factory.rb +21 -0
  20. data/app/services/spree/ideal_service.rb +33 -0
  21. data/app/views/spree/admin/payments/source_forms/_ideal.html.erb +1 -0
  22. data/app/views/spree/admin/payments/source_views/_ideal.html.erb +2 -0
  23. data/app/views/spree/checkout/payment/_ideal.html.erb +6 -0
  24. data/config/locales/en.yml +24 -0
  25. data/config/routes.rb +6 -0
  26. data/db/migrate/20150505204200_add_ideal_data_to_payments.rb +9 -0
  27. data/lib/generators/spree_ideal/install/install_generator.rb +27 -0
  28. data/lib/spree_ideal.rb +2 -0
  29. data/lib/spree_ideal/engine.rb +26 -0
  30. data/lib/spree_ideal/factories.rb +10 -0
  31. data/script/rails +5 -0
  32. data/spec/models/spree/hash_factory_spec.rb +26 -0
  33. data/spec/models/spree/order_spec.rb +49 -0
  34. data/spec/models/spree/payment_method/ideal_spec.rb +77 -0
  35. data/spec/models/spree/url_factory_spec.rb +27 -0
  36. data/spec/services/spree/ideal_service_spec.rb +36 -0
  37. data/spec/spec_helper.rb +85 -0
  38. data/spree_ideal.gemspec +32 -0
  39. metadata +268 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6ad0379ec12d43a06ef9436990bac9fa7bec5ce5
4
+ data.tar.gz: d313142a13cef028f744c11d92d355dcf7c75cd6
5
+ SHA512:
6
+ metadata.gz: 51c71860729915e8ba8ecfbee8611c547f9e77775c6a533409d8541398f5ee3701c65b096a1b27cecbd7e399489db6740ea35442a7c25c890502c1b1a1b0ec67
7
+ data.tar.gz: cbd4104bf45100a07a4968258d58f36663369fdb228f580b523408ef9faea6bdb6f77b6abdebb5f0f96d1d1a00123dbabda30c439a7eef453982f5140d5064ab
@@ -0,0 +1,18 @@
1
+ \#*
2
+ *~
3
+ .#*
4
+ .DS_Store
5
+ *.iml
6
+ .idea
7
+ .project
8
+ .sass-cache
9
+ coverage
10
+ Gemfile.lock
11
+ tmp
12
+ log/
13
+ nbproject
14
+ pkg
15
+ *.swp
16
+ spec/dummy
17
+ .ruby-gemset
18
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --format documentation --colour
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+ ruby '2.2.1'
3
+
4
+ gem 'spree', :github => 'spree/spree', :branch => '2-4-stable'
5
+ gem 'spree_auth_devise', github: 'spree/spree_auth_devise', :branch => '2-4-stable'
6
+
7
+ group :development, :test do
8
+ gem "therubyracer"
9
+ gem "byebug"
10
+ end
11
+
12
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+
4
+ Copyright (c) 2014 Stefan Hartmann
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
@@ -0,0 +1,69 @@
1
+ # SpreeIdeal
2
+
3
+ Adds [iDEAL payment](https://www.ideal.nl/en/) Support to Spree through [ABN AMRO Internetkassa's iDEAL Integration](https://internetkassa.abnamro.nl).
4
+
5
+ ## Installation
6
+
7
+ Add spree_ideal to your Gemfile:
8
+
9
+ ```ruby
10
+ gem 'spree_ideal', :git => 'git://github.com/arein/spree_ideal.git'
11
+ ```
12
+
13
+ For a specific version use the appropriate branch, for example
14
+
15
+ ```ruby
16
+ gem 'spree_ideal', :git => 'git://github.com/arein/spree_ideal.git', :branch => '2-4-stable'
17
+ ```
18
+
19
+ Bundle your dependencies and run the installation generator:
20
+
21
+ ```bash
22
+ bundle
23
+ bundle exec rails g spree_ideal:install
24
+ ```
25
+
26
+ ## Setup
27
+
28
+ Navigate to Spree Backend/Configuration/Payment Methods and add a new payment method with Provider "Spree::PaymentMethod::Ideal".
29
+
30
+ Then log into either your testing or production [ABN AMRO Internetkassa Back Office here](https://internetkassa.abnamro.nl).
31
+
32
+ Edit the following fields according to this doc:
33
+
34
+ * ABN URL: https://internetkassa.abnamro.nl/ncol/test/orderstandard.asp for testing or https://internetkassa.abnamro.nl/ncol/prod/orderstandard.asp for production
35
+ * PSPID: You'll find the PSPID in the footer of the Back Office
36
+ * Accept URL: <shop base url>/ideal/accept
37
+ * Decline URL: <shop base url>/ideal/decline
38
+ * Exception URL: <shop base url>/ideal/exception
39
+ * Cancel URL: <shop base url>/ideal/cancel
40
+ * SHA IN Pass Phrase: Set this in the Back Office under Configuration -> Technical Information -> Data and Origin Verification -> SHA-IN Pass Phrase
41
+ * SHA Out Pass Phrase: Set this in the Back Office under Configuration -> Technical Information -> Transaction Feedback -> SHA-OUT Pass Phrase (may not equal the SHA-IN Pass Phrase)
42
+ * SHA Algorithm: Either "SHA-1", "SHA-256", or "SHA-512", according to the setting in the Back Office under Configuration -> Technical Information -> Global Security Parameters -> Hash Algorithm
43
+ * Shop Base URL: <shop base url>
44
+
45
+
46
+ __IMPORTANT__:In the backoffice you need to carry out a few actions:
47
+ * Set Configuration -> Technical Information -> Transaction Feedback -> "I would like to receive transaction feedback parameters on the redirection URLs" to YES
48
+ * Set Configuration -> Technical Information -> Transaction Feedback -> "Timing of the request" to "Always Deferred" and "Request Method" to "GET"
49
+ * Set Configuration -> Technical Information -> Transaction Feedback -> "Dynamic e-Commerce parameters" to "ACCEPTANCE", "AMOUNT", "BRAND", "CARDNO", "CURRENCY", "NCERROR", "ORDERID", "PAYID", "PM", "STATUS"
50
+
51
+ ## Running the Tests
52
+
53
+ 1. Install dependencies `bundle install`
54
+ 2. Create a Dummy app `bundle exec rake test_app`
55
+ 3. Change Directory `cd spec/dummy`
56
+ 4. Create a Test Database `rake db:create RAILS_ENV=test`
57
+ 5. Migrate `rake db:migrate RAILS_ENV=test`
58
+ 6. Seed `bin/rake db:seed RAILS_ENV=test`
59
+ 7. Load sample data `bin/rake spree_sample:load RAILS_ENV=test`
60
+ 8. Change Directory `cd ../..`
61
+ 9. Run RSpec `rspec spec`
62
+
63
+
64
+ ## Acknowledgements
65
+
66
+ This repository is inspired by [@hefan's](https://github.com/hefan) [Spree Sofort Plugin](https://github.com/hefan/spree_sofort)
67
+
68
+ ## License
69
+ released under the New BSD License
@@ -0,0 +1,17 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ require 'spree/testing_support/extension_rake'
6
+
7
+ RSpec::Core::RakeTask.new
8
+
9
+
10
+ task :default => [:spec]
11
+
12
+
13
+ desc 'Generates a dummy app for testing'
14
+ task :test_app do
15
+ ENV['LIB_NAME'] = 'spree_ideal'
16
+ Rake::Task['extension:test_app'].invoke
17
+ end
@@ -0,0 +1 @@
1
+ //= require admin/spree_core
@@ -0,0 +1 @@
1
+ //= require store/spree_core
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= require admin/spree_core
3
+ */
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= require store/spree_core
3
+ */
@@ -0,0 +1,21 @@
1
+ Spree::CheckoutController.class_eval do
2
+ before_filter :redirect_to_ideal, :only => [:update]
3
+
4
+ def redirect_to_ideal
5
+ return unless (params[:state] == "payment")
6
+ return unless params[:order][:payments_attributes]
7
+
8
+ payment_method = Spree::PaymentMethod.find(params[:order][:payments_attributes].first[:payment_method_id])
9
+
10
+ if payment_method.kind_of?(Spree::PaymentMethod::Ideal)
11
+ @order.update_from_params(params, permitted_checkout_attributes)
12
+
13
+ Spree::IdealService.instance.initial_request(@order)
14
+
15
+ # Create iDEAL Url
16
+ redirect_url = Spree::UrlFactory.create_ideal_checkout_url_from_payment(@order, payment_method, @order.last_payment.ideal_hash, I18n.locale)
17
+ redirect_to redirect_url, :status => 302
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,160 @@
1
+ require 'pp'
2
+ require 'uri'
3
+
4
+ class Spree::IdealController < ApplicationController
5
+
6
+ skip_before_filter :verify_authenticity_token, :only => :status
7
+
8
+ def success
9
+
10
+ if params[:orderID].blank?
11
+ flash[:error] = I18n.t("ideal.order_invalid_setup")
12
+ redirect_to '/checkout/payment', :status => 302
13
+ return
14
+ end
15
+
16
+ # Some Validation
17
+ if !params.has_key?("currency") || params[:currency].blank? ||
18
+ !params.has_key?("amount") || params[:amount].blank? ||
19
+ !params.has_key?("PM") || params[:PM].blank? ||
20
+ !params.has_key?("CARDNO") || params[:CARDNO].blank? ||
21
+ !params.has_key?("STATUS") || params[:STATUS].blank? ||
22
+ !params.has_key?("PAYID") || params[:PAYID].blank? ||
23
+ !params.has_key?("NCERROR") || params[:NCERROR].blank? ||
24
+ !params.has_key?("BRAND") || params[:BRAND].blank?
25
+ flash[:error] = I18n.t("ideal.order_invalid_setup")
26
+ redirect_to '/checkout/payment', :status => 302
27
+ return
28
+ end
29
+
30
+ order = Spree::Order.where(number: params[:orderID]).take
31
+
32
+ if params.blank? or order.blank?
33
+ flash[:error] = I18n.t("ideal.payment_not_found")
34
+ redirect_to '/checkout/payment', :status => 302
35
+ return
36
+ end
37
+
38
+ ideal_payment = order.last_payment
39
+
40
+ if params.blank? or ideal_payment.blank? or !order.last_payment_method.kind_of? Spree::PaymentMethod::Ideal
41
+ flash[:error] = I18n.t("ideal.payment_not_found")
42
+ redirect_to '/checkout/payment', :status => 302
43
+ return
44
+ end
45
+
46
+ hash_algorithm = ideal_payment.payment_method.preferred_sha_algorithm
47
+ secret = ideal_payment.payment_method.preferred_sha_out_pass_phrase.to_s
48
+
49
+ # Some Validation
50
+ unless params.has_key?("SHASIGN")
51
+ flash[:error] = I18n.t("ideal.order_invalid_setup")
52
+ redirect_to '/checkout/payment', :status => 302
53
+ return
54
+ end
55
+
56
+ # Security Validation
57
+ shasign = ""
58
+ if params.has_key?("SHASIGN")
59
+ shasign = params[:SHASIGN].downcase
60
+ end
61
+
62
+ sha_out_hash = Spree::HashFactory.create_sha_out_hash(params, secret, hash_algorithm)
63
+
64
+ pp sha_out_hash
65
+ unless sha_out_hash.eql? shasign
66
+ flash[:error] = I18n.t("ideal.security_error")
67
+ redirect_to '/checkout/payment', :status => 302
68
+ return
69
+ end
70
+
71
+ order = ideal_payment.order
72
+ if order.blank?
73
+ flash[:error] = I18n.t("ideal.order_not_found")
74
+ redirect_to '/checkout/payment', :status => 302
75
+ return
76
+ end
77
+
78
+ if not order.state.eql? "complete" and not order.state.eql? "payment" and not order.state.eql? "checkout"
79
+ flash[:error] = I18n.t("ideal.order_invalid_state")
80
+ redirect_to '/checkout/payment', :status => 302
81
+ return
82
+ end
83
+
84
+ if order.state.eql? "complete" # complete again via browser back or recalling ideal "go" url
85
+ success_redirect order
86
+ else
87
+ ActiveRecord::Base.transaction do
88
+ ideal_payment.update_attribute(:ideal_transaction, params[:PAYID])
89
+ if ideal_payment.ideal_log.blank?
90
+ ideal_payment.update_attribute(:ideal_log, "payment_successful,")
91
+ else
92
+ ideal_payment.update_attribute(:ideal_log, ideal_payment.ideal_log + "payment_successful,")
93
+ end
94
+ ideal_payment.complete!
95
+ order.finalize!
96
+ order.state = "complete"
97
+ order.save!
98
+ end
99
+ session[:order_id] = nil
100
+ flash[:success] = I18n.t("ideal.completed_successfully")
101
+ success_redirect order
102
+ end
103
+
104
+ end
105
+
106
+ def decline
107
+ self.handle_status(params, "canceled")
108
+ flash[:error] = I18n.t("ideal.decline")
109
+ redirect_to '/checkout/payment', :status => 302
110
+ end
111
+
112
+ def exception
113
+ self.handle_status(params, "exception")
114
+ flash[:error] = I18n.t("ideal.exception")
115
+ redirect_to '/checkout/payment', :status => 302
116
+ end
117
+
118
+ def cancel
119
+ self.handle_status(params, "canceled")
120
+ flash[:error] = I18n.t("ideal.canceled")
121
+ redirect_to '/checkout/payment', :status => 302
122
+ end
123
+
124
+ private
125
+
126
+ def handle_status(params, message)
127
+ if params.blank? or params[:orderID].blank?
128
+ return
129
+ end
130
+
131
+ order = Spree::Order.where(number: params[:orderID]).take
132
+
133
+ if order.blank?
134
+ return
135
+ end
136
+
137
+ unless order.last_payment_method.kind_of? Spree::PaymentMethod::Ideal
138
+ return
139
+ end
140
+
141
+ ideal_payment = order.last_payment
142
+
143
+ if ideal_payment.blank?
144
+ return
145
+ end
146
+
147
+ if ideal_payment.ideal_log.blank?
148
+ ideal_payment.update_attribute(:ideal_log, message + ",")
149
+ else
150
+ ideal_payment.update_attribute(:ideal_log, ideal_payment.ideal_log + message + ",")
151
+ end
152
+ ideal_payment.save!
153
+
154
+ end
155
+
156
+ def success_redirect order
157
+ redirect_to "/orders/#{order.number}", :status => 302
158
+ end
159
+
160
+ end
@@ -0,0 +1,64 @@
1
+ class Spree::HashFactory
2
+ def self.create_hash(order, ideal_payment_settings, locale)
3
+
4
+ secret = ideal_payment_settings.preferred_sha_in_pass_phrase.to_s
5
+
6
+ language = Spree::LocaleHelper.format_locale(locale)
7
+
8
+ if secret.blank?
9
+ secret = "" # Fallback if secret not set
10
+ end
11
+
12
+ total = (order.total * 100).to_i # Convert according to
13
+ to_hash = "ACCEPTURL=" + ideal_payment_settings.preferred_accept_url + secret + "" \
14
+ + "AMOUNT=" + total.to_s + secret + ""\
15
+ + "BACKURL=" + ideal_payment_settings.preferred_shop_base_url + "/orders/#{order.number}" + secret + "" \
16
+ + "CANCELURL=" + ideal_payment_settings.preferred_cancel_url + secret + "" \
17
+ + "CURRENCY=" + Spree::Config.currency.to_s + secret + "" \
18
+ + "DECLINEURL=" + ideal_payment_settings.preferred_decline_url + secret + "" \
19
+ + "EXCEPTIONURL=" + ideal_payment_settings.preferred_exception_url + secret + "" \
20
+ + "LANGUAGE=" + language + secret + "" \
21
+ + "ORDERID=" + order.number.to_s + secret + "" \
22
+ + "PSPID=" + ideal_payment_settings.preferred_pspid.to_s + secret + "" \
23
+
24
+ case ideal_payment_settings.preferred_sha_algorithm
25
+ when "SHA-1"
26
+ Digest::SHA1.hexdigest to_hash
27
+ when "SHA-256"
28
+ Digest::SHA256.hexdigest to_hash
29
+ when "SHA-512"
30
+ Digest::SHA512.hexdigest to_hash
31
+ else
32
+ Digest::SHA1.hexdigest to_hash
33
+ end
34
+ end
35
+
36
+ def self.create_sha_out_hash(params, secret, hash_algorithm)
37
+
38
+ if secret.blank?
39
+ return secret
40
+ end
41
+
42
+ to_hash = "ACCEPTANCE=" + params[:ACCEPTANCE] + secret + ""\
43
+ + "AMOUNT=" + params[:amount] + secret + "" \
44
+ + "BRAND=" + params[:BRAND] + secret + "" \
45
+ + "CARDNO=" + params[:CARDNO] + secret + "" \
46
+ + "CURRENCY=" + params[:currency] + secret + "" \
47
+ + "NCERROR=" + params[:NCERROR] + secret + "" \
48
+ + "ORDERID=" + params[:orderID] + secret + "" \
49
+ + "PAYID=" + params[:PAYID] + secret + "" \
50
+ + "PM=" + params[:PM] + secret + "" \
51
+ + "STATUS=" + params[:STATUS] + secret + "" \
52
+
53
+ case hash_algorithm
54
+ when "SHA-1"
55
+ Digest::SHA1.hexdigest to_hash
56
+ when "SHA-256"
57
+ Digest::SHA256.hexdigest to_hash
58
+ when "SHA-512"
59
+ Digest::SHA512.hexdigest to_hash
60
+ else
61
+ Digest::SHA1.hexdigest to_hash
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,48 @@
1
+ class Spree::LocaleHelper
2
+ def self.format_locale(locale)
3
+ case locale
4
+ when "ar"
5
+ return "ar_AR"
6
+ when "cs"
7
+ return "cs_CZ"
8
+ when "dk"
9
+ return "dk_DK"
10
+ when "de"
11
+ return "de_DE"
12
+ when "es"
13
+ return "es_ES"
14
+ when "fi"
15
+ return "fi_FI"
16
+ when "fr"
17
+ return "fr_FR"
18
+ when "hu"
19
+ return "hu_HU"
20
+ when "it"
21
+ return "it_IT"
22
+ when "ja"
23
+ return "ja_JP"
24
+ when "ko"
25
+ return "ko_KR"
26
+ when "nl"
27
+ return "nl_NL"
28
+ when "no"
29
+ return "no_NO"
30
+ when "pl"
31
+ return "pl_PL"
32
+ when "pt"
33
+ return "pt_PT"
34
+ when "ru"
35
+ return "ru_RU"
36
+ when "se"
37
+ return "se_SE"
38
+ when "sk"
39
+ return "sk_SK"
40
+ when "tr"
41
+ return "tr_TR"
42
+ when "zh"
43
+ return "zh_CN"
44
+ else
45
+ return "en_US"
46
+ end
47
+ end
48
+ end