solidus_six_saferpay 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +220 -0
  4. data/Rakefile +56 -0
  5. data/app/assets/config/solidus_six_saferpay_manifest.js +2 -0
  6. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/amex.png +0 -0
  7. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/cirrus.png +0 -0
  8. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/delta.png +0 -0
  9. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/diners_club.png +0 -0
  10. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/directdebit.png +0 -0
  11. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/discover.png +0 -0
  12. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/egold.png +0 -0
  13. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/maestro.png +0 -0
  14. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/mastercard.png +0 -0
  15. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/paypal.png +0 -0
  16. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/solo.png +0 -0
  17. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/switch.png +0 -0
  18. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/twint.png +0 -0
  19. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/visa.png +0 -0
  20. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/visaelectron.png +0 -0
  21. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/westernunion.png +0 -0
  22. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/wirecard.png +0 -0
  23. data/app/assets/images/solidus_six_saferpay/credit_cards/icons/worldpay.png +0 -0
  24. data/app/assets/javascripts/solidus_six_saferpay/application.js +14 -0
  25. data/app/assets/javascripts/solidus_six_saferpay/saferpay_payment.js +120 -0
  26. data/app/assets/stylesheets/solidus_six_saferpay/application.css +15 -0
  27. data/app/assets/stylesheets/solidus_six_saferpay/loading_animation.scss +30 -0
  28. data/app/assets/stylesheets/solidus_six_saferpay/payments.scss +10 -0
  29. data/app/controllers/solidus_six_saferpay/application_controller.rb +5 -0
  30. data/app/controllers/spree/solidus_six_saferpay/checkout_controller.rb +93 -0
  31. data/app/controllers/spree/solidus_six_saferpay/payment_page/checkout_controller.rb +27 -0
  32. data/app/controllers/spree/solidus_six_saferpay/transaction/checkout_controller.rb +27 -0
  33. data/app/helpers/solidus_six_saferpay/application_helper.rb +4 -0
  34. data/app/jobs/solidus_six_saferpay/application_job.rb +4 -0
  35. data/app/mailers/solidus_six_saferpay/application_mailer.rb +6 -0
  36. data/app/models/solidus_six_saferpay/application_record.rb +5 -0
  37. data/app/models/spree/payment_method/saferpay_payment_method.rb +46 -0
  38. data/app/models/spree/payment_method/saferpay_payment_page.rb +13 -0
  39. data/app/models/spree/payment_method/saferpay_transaction.rb +12 -0
  40. data/app/models/spree/six_saferpay_payment.rb +69 -0
  41. data/app/services/spree/route_access.rb +5 -0
  42. data/app/services/spree/solidus_six_saferpay/assert_payment_page.rb +8 -0
  43. data/app/services/spree/solidus_six_saferpay/authorize_payment.rb +60 -0
  44. data/app/services/spree/solidus_six_saferpay/authorize_transaction.rb +8 -0
  45. data/app/services/spree/solidus_six_saferpay/initialize_payment.rb +57 -0
  46. data/app/services/spree/solidus_six_saferpay/initialize_payment_page.rb +15 -0
  47. data/app/services/spree/solidus_six_saferpay/initialize_transaction.rb +16 -0
  48. data/app/services/spree/solidus_six_saferpay/inquire_payment.rb +43 -0
  49. data/app/services/spree/solidus_six_saferpay/inquire_payment_page_payment.rb +7 -0
  50. data/app/services/spree/solidus_six_saferpay/inquire_transaction.rb +7 -0
  51. data/app/services/spree/solidus_six_saferpay/inquire_transaction_payment.rb +7 -0
  52. data/app/services/spree/solidus_six_saferpay/payment_validator.rb +62 -0
  53. data/app/services/spree/solidus_six_saferpay/process_authorized_payment.rb +87 -0
  54. data/app/services/spree/solidus_six_saferpay/process_payment_page_payment.rb +7 -0
  55. data/app/services/spree/solidus_six_saferpay/process_transaction_payment.rb +7 -0
  56. data/app/services/spree/solidus_six_saferpay/use_payment_page_gateway.rb +11 -0
  57. data/app/services/spree/solidus_six_saferpay/use_transaction_gateway.rb +11 -0
  58. data/app/views/spree/admin/payments/source_views/_saferpay_payment.erb +36 -0
  59. data/app/views/spree/api/payments/source_views/_saferpay_payment.json.jbuilder +1 -0
  60. data/app/views/spree/checkout/payment/_saferpay_payment.html.erb +12 -0
  61. data/app/views/spree/six_saferpay_payments/_six_saferpay_payment.html.erb +16 -0
  62. data/app/views/spree/solidus_six_saferpay/checkout/iframe_breakout_redirect.html.erb +7 -0
  63. data/config/locales/de.yml +52 -0
  64. data/config/locales/en.yml +52 -0
  65. data/config/locales/fr.yml +51 -0
  66. data/config/routes.rb +17 -0
  67. data/db/migrate/20190523075638_create_six_saferpay_payments.rb +31 -0
  68. data/lib/generators/solidus_six_saferpay/install/install_generator.rb +20 -0
  69. data/lib/solidus_six_saferpay.rb +5 -0
  70. data/lib/solidus_six_saferpay/configuration.rb +12 -0
  71. data/lib/solidus_six_saferpay/engine.rb +25 -0
  72. data/lib/solidus_six_saferpay/error_handler.rb +21 -0
  73. data/lib/solidus_six_saferpay/gateway.rb +183 -0
  74. data/lib/solidus_six_saferpay/gateway_response.rb +38 -0
  75. data/lib/solidus_six_saferpay/invalid_saferpay_payment.rb +11 -0
  76. data/lib/solidus_six_saferpay/payment_page_gateway.rb +55 -0
  77. data/lib/solidus_six_saferpay/transaction_gateway.rb +47 -0
  78. data/lib/solidus_six_saferpay/version.rb +3 -0
  79. data/lib/tasks/solidus_six_saferpay_tasks.rake +4 -0
  80. metadata +319 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 279fd99eb596c0341efdbd5e83c8e8cf328fbff094869d25674c52618e41f754
4
+ data.tar.gz: 2dc28f60246777a1768ac1d8eed9440692dc3995041d45abb15bb7f0aa7ac536
5
+ SHA512:
6
+ metadata.gz: 1c6e99a096e95162697ab9d2ce89588c770e681b621a7207527fc4997bb830dfff245f79bdbd72c609c933e7f16afce01a4a1559a6b7a58eee1f52f00dcf883e
7
+ data.tar.gz: 45e8bd49927c402a9f6a64decbb986b432d808da15ea452085c7ce270b63258a850c2c613ded02706198a4da46ab01ea661a81072eb1462ad07e1ece3374688c
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2019 Simon Kiener
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,220 @@
1
+ # SolidusSixSaferpay
2
+ The `solidus_six_saferpay` engine adds checkout options for the Saferpay Payment Page ([Integration Guide](https://saferpay.github.io/sndbx/Integration_PP.html), [JSON API documentation](http://saferpay.github.io/jsonapi/#ChapterPaymentPage)) and the Saferpay Transaction ([Integration Guide](https://saferpay.github.io/sndbx/Integration_trx.html), [JSON API documentation](https://saferpay.github.io/sndbx/Integration_trx.html)).
3
+
4
+ ## Status
5
+ Travis CI status: [![Build Status](https://travis-ci.org/fadendaten/solidus_six_saferpay.svg?branch=master)](https://travis-ci.org/fadendaten/solidus_six_saferpay)
6
+
7
+
8
+ ## Installation
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'solidus_six_saferpay'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ ```bash
18
+ $ bundle
19
+ ```
20
+
21
+ Or install it yourself as:
22
+
23
+ ```bash
24
+ $ gem install solidus_six_saferpay
25
+ ```
26
+
27
+ After installing the gem, copy the migrations to your host application and migrate:
28
+
29
+ ```bash
30
+ $ bundle exec rails g solidus_six_saferpay:install
31
+ ```
32
+
33
+ Add the following javascript to your `application.js` manifest file below the `//= require spree` line:
34
+
35
+ ```javascript
36
+ //= require solidus_six_saferpay/saferpay_payment
37
+ ```
38
+
39
+ Configure the credentials for the Saferpay API. These credentials must be set as ENV variables.
40
+ You can find the required information in the Saferpay interface under https://test.saferpay.com/BO/Settings/Terminal
41
+
42
+ ```bash
43
+ SIX_SAFERPAY_CUSTOMER_ID='XXXXXX'
44
+ SIX_SAFERPAY_TERMINAL_ID='XXXXXXXX'
45
+ SIX_SAFERPAY_USERNAME='your api basic auth username'
46
+ SIX_SAFERPAY_PASSWORD='your api basic auth password'
47
+ SIX_SAFERPAY_BASE_URL='https://test.saferpay.com/api/'
48
+ SIX_SAFERPAY_CSS_URL='' # currently not tested
49
+ ```
50
+
51
+ Configure the host for your application so that we can give Saferpay an absolute URL to redirect on success or failure
52
+
53
+ ```
54
+ # in development.rb
55
+ Spree::Core::Engine.routes.default_url_options { 'http://localhost:3000' }
56
+ ```
57
+
58
+ ```
59
+ # in production.rb
60
+ Spree::Core::Engine.routes.default_url_options { 'https://url-to-your-solidus-shop.tld' }
61
+ ```
62
+
63
+
64
+ ## Configuration and Usage
65
+ After adding the `solidus_six_saferpay` gem to your Solidus Rails app, you can create new payment methods `Saferpay Payment Page` and `Saferpay Transaction` in the admin backend under "Settings" > "Payment". When adding a new Saferpay payment method, you can configure the payment method with the information you have received from SIX when creating a new test account.
66
+
67
+ ### Configuration Options
68
+
69
+ Notable configuration options are:
70
+
71
+ * `as_iframe`: If checked, the payment form is displayed on the "Payment" checkout page. If unchecked, the user needs to select a payment method and then proceed with the checkout to be redirected to the Saferpay payment interface.
72
+ * `require_liability_shift`: If checked, payments are only accepted if Saferpay grants liability shift for the payment. If a payment has no liability shift, then the checkout process fails and the customer needs to use other means of payment.
73
+
74
+ All other configuration options are restrictions for available payment methods. If you don't check any payment methods, then the interface will make all payment methods available. If you restrict the available payment methods for the user, the interface will reflect your choice. If you select only a single payment method, the user is directly forwarded to the input form for the selected payment method without having to choose themselves.
75
+
76
+ ### Customizing the Confirm Page
77
+ If you want to display the masked number on the confirm page, you must override the default `_payment.html.erb` partial of spree so that the provided partial can be rendered (instead of just displaying the name of your payment method).
78
+
79
+ ```erb
80
+ <!-- This is the default "app/views/spree/payments/_payment.html.erb" (including our modification) -->
81
+ <% source = payment.source %>
82
+
83
+ <!-- Add this code to render our provided partial that shows the masked number -->
84
+ <% if source.is_a?(Spree::SixSaferpayPayment) %>
85
+ <%= render source, payment: payment %>
86
+
87
+ <!-- turn this "if" into an "elsif" to prevent rendering the payment method name -->
88
+ <% elsif source.is_a?(Spree::CreditCard) %>
89
+ <span class="cc-type">
90
+ <% unless (cc_type = source.cc_type).blank? %>
91
+ <%= image_tag "credit_cards/icons/#{cc_type}.png" %>
92
+ <% end %>
93
+ <% if source.last_digits %>
94
+ <%= t('spree.ending_in') %> <%= source.last_digits %>
95
+ <% end %>
96
+ </span>
97
+ <br />
98
+ <span class="full-name"><%= source.name %></span>
99
+ <% elsif source.is_a?(Spree::StoreCredit) %>
100
+ <%= content_tag(:span, payment.payment_method.name) %>:
101
+ <%= content_tag(:span, payment.display_amount) %>
102
+ <% else %>
103
+ <%= content_tag(:span, payment.payment_method.name) %>
104
+ <% end %>
105
+ ```
106
+
107
+ ## Technical Details: How it works
108
+
109
+ ### Overview
110
+
111
+ This section should provide a birds-eye view of the implementation to help you not get lost when you dive into the details below.
112
+
113
+ The basic flow for a Saferpay Payment goes like this:
114
+
115
+ 1. User chooses Saferpay payment method on "Payment" checkout step
116
+ 2. Controller receives AJAX request to initialize Saferpay payment
117
+ 3. The `InitializePayment` service requests a `token` from the Saferpay API and stores this token in a `SixSaferpayPayment`
118
+ 4. User enters payment information and submits Saferpay form
119
+ 5. Controller receives the `success` request from Saferpay
120
+ 6. Controller asserts/authorizes payment via `AuthorizePayment` service with help of the previously stored `token`
121
+ 7. If assert/authorize are successful, Controller validates and processes the payment via `ProcessPayment` service which results in a `Spree::Payment`
122
+ 8. Controller redirects to the "Confirm" checkout step
123
+ 9. User confirms the purchase
124
+ 10. During completing the order, `Spree::Payment` initiates the `capture!` of the payment
125
+
126
+
127
+ As you can see, most interactions with the Saferpay API are encapsulated in service objects, which then call the appropriate gateway methods to perform requests.
128
+
129
+ A note about __error handling__:
130
+ If the user aborts the checkout at any point or the payment fails for some other reason, the user is redirected to the "Payment" step of the checkout process and shown an error message.
131
+ Additionally, already authorized payments are voided so that no money stays allocated for longer than necessary.
132
+
133
+ ### Technical Implementation Details
134
+
135
+ In this section, we provide detailed information about the checkout flow and its implementation. Note that the flow is almost identical for both the PaymentPage and the Transaction interface.
136
+ Because of this, there is usually a base service class that contains the logic, and then there are subclass services for the PaymentPage and Transaction interface that configure the base service class.
137
+
138
+ The same pattern also exists for the gateway: The `SolidusSixSaferpay::Gateway` implements the common logic, and the `SolidusSixSaferpay::PaymentPageGateway` and `SolidusSixSaferpay::TransactionGateway` only implement gateway actions that are unique for this interface.
139
+
140
+ #### Checkout: Payment Initialize
141
+ During the "Payment" step of the checkout process, solidus renders a partial for all active and available payment methods. Our partial is called `_saferpay_payment`.
142
+ When the partial is loaded, an AJAX request goes to the `CheckoutController#initialize_payment` action.
143
+ From there, we make a request to the Saferpay server to initialize the Payment. This request happens via the SixSaferpay Gateway and is abstracted away in the `InitializePayment` service.
144
+
145
+ If this request is successful, a new `SixSaferpayPayment` object is created. This object contains the Saferpay `Token` for the current payment and links it with the current `Spree::Order` and the used `Spree::PaymentMethod`. It also stores the response of the `PaymentInitialize` request in hash form.
146
+
147
+ If the initialize request is not successful, then the user is shown an error message.
148
+
149
+ ##### Success
150
+ If Saferpay can successfully process the user-submitted information, then Saferpay redirects the user to a `SuccessUrl`, which is configured to be handled by `CheckoutController#success`.
151
+ In this `#success` action, we find the `SixSaferpayPayment` record with the correct token that was created in the `PaymentInitialize` request. If the `SixSaferpayPayment` is found, a `PaymentAuthorize` request is performed (abstracted away the `AuthorizePayment` service).
152
+
153
+ ##### Fail
154
+ If Saferpay can not successfully process the submitted information or the payment fails for some other reason, Saferpay redirects to a `FailUrl`, which is configured to be handled by `SaferpayPaymentPageController#fail`.
155
+ In this `#fail` action, we try to find the `SixSaferpayPayment` record based on the token that was created in the `PaymentPageInitialize` request. If the `SixSaferpayPayment` is found, a `PaymentPageInquire` request is performed to gather information about the failure, and the user is redirected to the "Payment" step of the checkout process and shown an error with information about the failure. If the record can not be found, then a generic error is displayed.
156
+
157
+ #### Checkout: Payment Authorize
158
+ If the user has entered the payment information successfully, we can perform an authorize request. Because this request is different depending on the payment interface, it is explained for each interface below.
159
+ When the authorize request is successful, we update the `SixSaferpayPayment` record with the received data. This data most importantly includes:
160
+
161
+ * `TransactionId`
162
+ * `TransactionStatus`
163
+ * `TransactionDate`
164
+ * `SixTransactionReference`
165
+ * `DisplayText`
166
+
167
+ And, if a credit card was used:
168
+
169
+ * `MaskedNumber`
170
+ * `ExpirationYear`
171
+ * `ExpirationMonth`
172
+
173
+ ##### PaymentPage Interface
174
+ If the PaymentPage interface is used, then the payment is authorized directly when the user submits the Saferpay form. In this case, we can not perform an authorize request and instead perform an assert request to gather information about the payment.
175
+ After performing the assert request, we update the `SixSaferpayPayment` record based on the data from the assert request.
176
+
177
+ ##### Transaction Interface
178
+ If the Transaction interface is used, then the payment must be authorized after it has been initialized. Therefore, we perform an authorize request to reserve the requested amount.
179
+ If the authorize request is successful, we update the `SixSaferpayPayment` based on the data from the authorize request.
180
+
181
+
182
+ #### Checkout: Payment Validation and Processing
183
+ If the authorize request is successful, the received information is validated and processed in the `ProcessPaymentPagePayment` service.
184
+ At the moment, the following validations are performed:
185
+
186
+ * Liability Shift: We check if the liability shift has been granted for the payment
187
+ * Payment Status: We check if the payment status of the Saferpay payment is `AUTHORIZED`
188
+ * Order Reference: We check if the order referenced by Saferpay matches the order that is being processed
189
+ * Matching Amount and Currency: We check if the Saferpay amount and currency match the total and currency of the processed order
190
+
191
+ If any of these checks fail, then the payment process is aborted and the user must restart the payment flow.
192
+
193
+ If the payment validation is successful, all previously existing payments for this order that are still valid are cancelled.
194
+ After cancelling old payments, a new `Spree::Payment` is created based on the data stored in the `SixSaferpayPayment` record.
195
+ This ensures that only one valid payment exists from this point onward.
196
+
197
+ If the payment processing fails, then the user is redirected to the "Payment" step of the checkout process and shown an error message.
198
+
199
+ #### Checkout: Confirm
200
+ When the user confirms the purchase in the checkout process, the saferpay payment is automatically captured. This action is triggered in the following way:
201
+
202
+ 1. When the user confirms the order, `Spree::CheckoutController#update` triggers `@order.complete` (through `#transition_forward`)
203
+ 2. `Spree::Order::Checkout` defines the state transition `before_transition_to :complete, do: :process_payments_before_complete`
204
+ 3. `Spree::Order` defines `#process_payments_before_complete` and calls `#process_payments!` if any valid payments exist
205
+ 4. `Spree::Order::Payments` defines `#process_payments!` which calls `process!` on each unprocessed payment
206
+ 5. `Spree::Payment::Processing` defines `#process!` and calls `#purchase!`
207
+ 6. `Spree::Payment::Processing` defines `#purchase` and calls `#purchase` on the `PaymentMethod` associated with the payment
208
+ 7. Since this payment method is a `Spree::PaymentMethod::SaferpayPaymentPage` that inherits from `Spree::PaymentMethod` (through `SaferpayPaymentMethod` and `CreditCard`), the `#purchase` method is delegated to the `#gateway`
209
+ 8. `Spree::PaymentMethod::SaferpayPaymentPage#gateway_class` defines the gateway to be the `SolidusSixSaferpay::PaymentPageGateway`
210
+ 9. Therefore, the `PaymentPageGateway#purchase` action is called
211
+
212
+ #### Checkout: Payment Cancel
213
+ When a user cancels a payment, the `CheckoutController` receives a `fail` request and handles this request in the `#fail` action. The result is that the user is shown an error message stating that the payment was aborted.
214
+
215
+ ## Contributing
216
+ This gem is available for everyone to use, however chances are that its implementation is still tailored towards our custom solidus-based shop.
217
+ If you see improvements to be made, feel free to fork the gem and submit pull requests. All incoming pull requests will be discussed, but it's possible that we will reject pull requests that break functionality for our use case.
218
+
219
+ ## License
220
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,56 @@
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 = 'SolidusSixSaferpay'
12
+ # rdoc.options << '--line-numbers'
13
+ # rdoc.rdoc_files.include('README.md')
14
+ # rdoc.rdoc_files.include('lib/**/*.rb')
15
+ # end
16
+
17
+ # APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
18
+ # load 'rails/tasks/engine.rake'
19
+
20
+ # load 'rails/tasks/statistics.rake'
21
+
22
+ # require 'bundler/gem_tasks'
23
+
24
+ # require 'rspec/core/rake_task'
25
+ # RSpec::Core::RakeTask.new(:spec)
26
+
27
+ # task default: :spec
28
+
29
+ require 'bundler'
30
+
31
+ Bundler::GemHelper.install_tasks
32
+
33
+ begin
34
+ require 'spree/testing_support/extension_rake'
35
+ require 'rspec/core/rake_task'
36
+
37
+ RSpec::Core::RakeTask.new(:spec)
38
+
39
+ # task default: %i(first_run spec)
40
+ task default: %i(first_run spec)
41
+ rescue LoadError
42
+ # no rspec available
43
+ end
44
+
45
+ task :first_run do
46
+ if Dir['spec/dummy'].empty?
47
+ Rake::Task[:test_app].invoke
48
+ Dir.chdir('../../')
49
+ end
50
+ end
51
+
52
+ desc 'Generates a dummy app for testing'
53
+ task :test_app do
54
+ ENV['LIB_NAME'] = 'solidus_six_saferpay'
55
+ Rake::Task['extension:test_app'].invoke
56
+ end
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/solidus_six_saferpay .js
2
+ //= link_directory ../stylesheets/solidus_six_saferpay .css
@@ -0,0 +1,14 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require rails-ujs
14
+ //= require_tree .
@@ -0,0 +1,120 @@
1
+ let SaferpayPayment = {
2
+ paymentFormId: "#checkout_form_payment",
3
+ paymentMethodRadioButtonSelector: 'input[type="radio"][name="order[payments_attributes][][payment_method_id]"]',
4
+
5
+ paymentMethods: {},
6
+
7
+ getRedirectUrl: function(paymentMethodId, initUrl, callbackParams, callback) {
8
+ $.ajax({
9
+ url: Spree.pathFor(initUrl),
10
+ data: {
11
+ payment_method_id: paymentMethodId,
12
+ },
13
+ method: 'GET',
14
+ dataType: 'json',
15
+ success: function(data) {
16
+ var redirectUrl = data.redirect_url;
17
+ callback(callbackParams, redirectUrl);
18
+ },
19
+
20
+ error: function(xhr) {
21
+ // debugger;
22
+ alert(xhr.responseText);
23
+ console.info(xhr.responseText);
24
+ return false;
25
+ },
26
+ })
27
+ },
28
+
29
+ loadIframe: function(callbackParams, redirectUrl) {
30
+ containerId = callbackParams.containerId;
31
+ $(".saferpay-iframe").not(containerId).addClass("loading-animation");
32
+ $(".saferpay-iframe").not(containerId).attr("src", "");
33
+ $(containerId).removeClass('loading-animation');
34
+ $(containerId).attr('src', redirectUrl);
35
+
36
+ $(window).bind("message", function (e) {
37
+ if (e.originalEvent.data.height <= 450) {
38
+ return;
39
+ }
40
+
41
+ $(containerId).css("height", e.originalEvent.data.height + "px");
42
+ });
43
+ },
44
+
45
+ redirectExternal: function(callbackParams, redirectUrl) {
46
+ $(window).attr('location', redirectUrl);
47
+ },
48
+
49
+ disableFormSubmit: function() {
50
+ var form = $(this.paymentFormId);
51
+ form.on("submit", function(e) { alert("Submitting this form has been disabled because you are trying to pay with the SIX payment interface.\nIf you see this message, please contact support."); e.stopPropagation(); return false });
52
+ form.find('input[type="submit"]').toggle(false);
53
+ },
54
+
55
+ enableFormSubmit: function() {
56
+ var form = $(this.paymentFormId);
57
+ form.off("submit");
58
+ form.find('input[type="submit"]').toggle(true);
59
+ },
60
+
61
+
62
+ prepareForIframePayment: function(paymentMethod) {
63
+ this.disableFormSubmit();
64
+ this.getRedirectUrl(paymentMethod.id, paymentMethod.initUrl, { containerId: paymentMethod.containerId }, this.loadIframe);
65
+ },
66
+
67
+ prepareForRedirectPayment: function(paymentMethod) {
68
+ $(document).off('submit', this.paymentFormId);
69
+ $(document).on('submit', this.paymentFormId, function(e) {
70
+ SaferpayPayment.getRedirectUrl(paymentMethod.id, paymentMethod.initUrl, {}, SaferpayPayment.redirectExternal);
71
+ });
72
+ },
73
+
74
+ handleSelectedPaymentMethod: function() {
75
+ var selectedPaymentMethodId = $(this.paymentMethodRadioButtonSelector+":checked").val()
76
+
77
+ if (!this.isSaferpayPayment(selectedPaymentMethodId)) { return false; }
78
+
79
+ paymentMethod = this.paymentMethods[selectedPaymentMethodId];
80
+
81
+ switch (paymentMethod.paymentInterface) {
82
+ case 'iframe':
83
+ this.prepareForIframePayment(paymentMethod);
84
+ break;
85
+ case 'redirect':
86
+ this.prepareForRedirectPayment(paymentMethod);
87
+ break;
88
+ default:
89
+ console.info("Payment Interface not supported, choose either 'iframe' or 'redirect'");
90
+ return false;
91
+ }
92
+ },
93
+
94
+ isSaferpayPayment: function(paymentMethodId) {
95
+ return !!(this.paymentMethods[paymentMethodId])
96
+ },
97
+
98
+ registerIframePaymentMethod: function(paymentMethod) {
99
+ paymentMethod.paymentInterface = "iframe";
100
+ this.paymentMethods[paymentMethod.id] = paymentMethod;
101
+ },
102
+
103
+ registerExternalRedirectPaymentMethod: function(paymentMethod) {
104
+ paymentMethod.paymentInterface = "redirect";
105
+ this.paymentMethods[paymentMethod.id] = paymentMethod;
106
+ },
107
+ };
108
+
109
+ $(document).ready(function() {
110
+ var form = $(SaferpayPayment.paymentFormId);
111
+ if (form.length == 0) {
112
+ return false;
113
+ }
114
+ SaferpayPayment.handleSelectedPaymentMethod();
115
+ });
116
+
117
+ $(document).on('change', SaferpayPayment.paymentMethodRadioButtonSelector, function() {
118
+ SaferpayPayment.enableFormSubmit();
119
+ SaferpayPayment.handleSelectedPaymentMethod();
120
+ });