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
@@ -0,0 +1,8 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class AuthorizeTransaction < AuthorizePayment
4
+ include UseTransactionGateway
5
+ end
6
+ end
7
+ end
8
+
@@ -0,0 +1,57 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+
4
+ class InitializePayment
5
+
6
+ attr_reader :order, :payment_method, :redirect_url, :success
7
+
8
+ def self.call(order, payment_method)
9
+ new(order, payment_method).call
10
+ end
11
+
12
+ def initialize(order, payment_method)
13
+ @order = order
14
+ @payment_method = payment_method
15
+ @success = false
16
+ end
17
+
18
+ def call
19
+ gateway_response = gateway.initialize_payment(order, payment_method)
20
+
21
+ if gateway_response.success?
22
+
23
+ saferpay_payment = build_saferpay_payment(gateway_response.api_response)
24
+
25
+ @redirect_url = saferpay_payment.redirect_url
26
+ @success = saferpay_payment.save!
27
+ end
28
+
29
+ self
30
+ end
31
+
32
+ def success?
33
+ @success
34
+ end
35
+
36
+ def gateway
37
+ raise NotImplementedError, "Must be implemented in InitializePaymentPage or InitializeTransaction by including UsePaymentPageGateway or UseTransactionGateway"
38
+ end
39
+
40
+ private
41
+
42
+ def build_saferpay_payment(api_response)
43
+ Spree::SixSaferpayPayment.new(saferpay_payment_attributes(api_response))
44
+ end
45
+
46
+ def saferpay_payment_attributes(api_response)
47
+ {
48
+ order: order,
49
+ payment_method: payment_method,
50
+ token: api_response.token,
51
+ expiration: DateTime.parse(api_response.expiration),
52
+ response_hash: api_response.to_h
53
+ }
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,15 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class InitializePaymentPage < InitializePayment
4
+ include UsePaymentPageGateway
5
+
6
+ private
7
+
8
+ def saferpay_payment_attributes(api_response)
9
+ super.merge(
10
+ redirect_url: api_response.redirect_url
11
+ )
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+
4
+ class InitializeTransaction < InitializePayment
5
+ include UseTransactionGateway
6
+
7
+ private
8
+
9
+ def saferpay_payment_attributes(initialize_response)
10
+ super.merge(
11
+ redirect_url: initialize_response.redirect.redirect_url
12
+ )
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,43 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class InquirePayment
4
+ attr_reader :saferpay_payment, :order, :success, :user_message
5
+
6
+ def self.call(saferpay_payment)
7
+ new(saferpay_payment).call
8
+ end
9
+
10
+ def initialize(saferpay_payment)
11
+ @saferpay_payment = saferpay_payment
12
+ @order = saferpay_payment.order
13
+ end
14
+
15
+ # NOTE: This will be successful regardless of the API response.
16
+ # The reason is that the API returns HTTP error codes for failed
17
+ # payments, but the inquiry was still successful
18
+ def call
19
+ inquiry = gateway.inquire(saferpay_payment)
20
+
21
+ if inquiry.success?
22
+ saferpay_payment.update_attributes(response_hash: inquiry.api_response.to_h)
23
+ else
24
+ general_error = I18n.t(:general_error, scope: [:solidus_six_saferpay, :errors])
25
+ specific_error = I18n.t(inquiry.error_name, scope: [:six_saferpay, :error_names])
26
+ @user_message = "#{general_error}: #{specific_error}"
27
+ end
28
+
29
+ @success = true
30
+
31
+ self
32
+ end
33
+
34
+ def success?
35
+ @success
36
+ end
37
+
38
+ def gateway
39
+ raise NotImplementedError, "Must be implemented in AssertPaymentPage or AuthorizeTransaction with UsePaymentPageGateway or UseTransactionGateway"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class InquirePaymentPagePayment < InquirePayment
4
+ include UsePaymentPageGateway
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class InquireTransactionPayment < InquirePayment
4
+ include UseTransactionGateway
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class InquireTransactionPayment < InquirePayment
4
+ include UseTransactionGateway
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,62 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class PaymentValidator
4
+ attr_reader :order, :saferpay_payment
5
+
6
+ def self.call(saferpay_payment)
7
+ new(saferpay_payment).call
8
+ end
9
+
10
+ def initialize(saferpay_payment)
11
+ @order = saferpay_payment.order
12
+ @saferpay_payment = saferpay_payment
13
+ end
14
+
15
+ def call
16
+ saferpay_transaction = saferpay_payment.transaction
17
+
18
+ validate_payment_authorized(saferpay_transaction)
19
+ validate_order_reference(saferpay_transaction)
20
+ validate_order_amount(saferpay_transaction)
21
+ end
22
+
23
+ def validate_payment_authorized(saferpay_transaction)
24
+ if saferpay_transaction.status != "AUTHORIZED"
25
+ error("Status should be 'AUTHORIZED', is: '#{saferpay_transaction.status}'")
26
+ end
27
+
28
+ true
29
+ end
30
+
31
+ def validate_order_reference(saferpay_transaction)
32
+ if order.number != saferpay_transaction.order_id
33
+ error("Order ID should be '#{order.number}', is: '#{saferpay_transaction.order_id}'")
34
+ end
35
+
36
+ true
37
+ end
38
+
39
+ def validate_order_amount(saferpay_transaction)
40
+ order_amount = Spree::Money.new(order.total, currency: order.currency)
41
+
42
+ saferpay_transaction_currency = saferpay_transaction.amount.currency_code
43
+ if order_amount.currency.iso_code != saferpay_transaction_currency
44
+ error("Currency should be '#{order.currency}', is: '#{saferpay_transaction_currency}'")
45
+ end
46
+
47
+ saferpay_transaction_cents = saferpay_transaction.amount.value
48
+ if order_amount.cents.to_s != saferpay_transaction_cents
49
+ error("Order total (cents) should be '#{order_amount.cents}', is: '#{saferpay_transaction_cents}'")
50
+ end
51
+
52
+ true
53
+ end
54
+
55
+ private
56
+
57
+ def error(details)
58
+ raise ::SolidusSixSaferpay::InvalidSaferpayPayment.new(details: details)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,87 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class ProcessAuthorizedPayment
4
+
5
+ attr_reader :saferpay_payment, :order, :success, :user_message
6
+
7
+ def self.call(saferpay_payment)
8
+ new(saferpay_payment).call
9
+ end
10
+
11
+ def initialize(saferpay_payment)
12
+ @saferpay_payment = saferpay_payment
13
+ @order = saferpay_payment.order
14
+ end
15
+
16
+ def call
17
+ check_liability_shift_requirements!
18
+
19
+ validate_payment!
20
+
21
+ # SUCCESS!
22
+
23
+ cancel_old_solidus_payments
24
+ saferpay_payment.create_solidus_payment!
25
+ @success = true
26
+
27
+ self
28
+
29
+ rescue ::SolidusSixSaferpay::InvalidSaferpayPayment => e
30
+ cancel_saferpay_payment
31
+ # TODO: Check if messages from liability shift check and PaymentValidator are appropriate for user!
32
+ @user_message = e.full_message
33
+ @success = false
34
+
35
+ self
36
+ end
37
+
38
+ def success?
39
+ @success
40
+ end
41
+
42
+ def gateway
43
+ raise NotImplementedError, "Must be implemented in ProcessPaymentPagePayment or ProcessTransactionPayment"
44
+ end
45
+
46
+ private
47
+
48
+ def validate_payment!
49
+ PaymentValidator.call(saferpay_payment)
50
+ end
51
+
52
+ # Cancels only the saferpay payment without affecting solidus
53
+ def cancel_saferpay_payment
54
+ if transaction_id = saferpay_payment.transaction_id
55
+ gateway.void(transaction_id)
56
+ end
57
+ end
58
+
59
+ # Cancels the solidus payments which automatically cancels the saferpay
60
+ # payments
61
+ def cancel_old_solidus_payments
62
+ solidus_payments_to_cancel.each do |payment|
63
+ # void or create refund
64
+ payment.cancel!
65
+ end
66
+ end
67
+
68
+ def check_liability_shift_requirements!
69
+ if require_liability_shift? && !liability_shifted?
70
+ raise ::SolidusSixSaferpay::InvalidSaferpayPayment.new(details: I18n.t(:liability_shift_not_granted, scope: [:solidus_six_saferpay, :errors]))
71
+ end
72
+ end
73
+
74
+ def require_liability_shift?
75
+ saferpay_payment.payment_method.preferred_require_liability_shift
76
+ end
77
+
78
+ def liability_shifted?
79
+ saferpay_payment.liability.liability_shift
80
+ end
81
+
82
+ def solidus_payments_to_cancel
83
+ order.payments.valid.where.not(state: [:void])
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,7 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class ProcessPaymentPagePayment < ProcessAuthorizedPayment
4
+ include UsePaymentPageGateway
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class ProcessTransactionPayment < ProcessAuthorizedPayment
4
+ include UseTransactionGateway
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ module UsePaymentPageGateway
4
+ include RouteAccess
5
+
6
+ def gateway
7
+ ::SolidusSixSaferpay::PaymentPageGateway.new
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ module UseTransactionGateway
4
+ include RouteAccess
5
+
6
+ def gateway
7
+ ::SolidusSixSaferpay::TransactionGateway.new
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+ <% source = payment.source %>
2
+ <% address = source.address %>
3
+ <fieldset data-hook="credit_card">
4
+ <legend align="center"><%= Spree::CreditCard.model_name.human %></legend>
5
+
6
+ <div class="row">
7
+ <div class="col-4">
8
+ <dl>
9
+ <dt><%= t('spree.name_on_card') %>:</dt>
10
+ <dd><%= source.card.holder_name %></dd>
11
+
12
+ <dt><%= Spree::CreditCard.human_attribute_name(:cc_type) %>:</dt>
13
+ <dd><%= source.brand_name %></dd>
14
+
15
+ <dt><%= Spree::CreditCard.human_attribute_name(:number) %>:</dt>
16
+ <dd><%= source.display_text %></dd>
17
+
18
+ <dt><%= Spree::CreditCard.human_attribute_name(:expiration) %>:</dt>
19
+ <dd><%= source.month %>/<%= source.year %></dd>
20
+ </dl>
21
+
22
+ <div data-hook="address">
23
+ <%= "#{address.first_name} #{address.last_name}" %><br />
24
+ <% if address.phone %>
25
+ <%= address.phone %><br />
26
+ <% end %>
27
+ <%= address.address1 %><br />
28
+ <% if address.address2.present? %>
29
+ <%= address.address2 %><br />
30
+ <% end %>
31
+ <%= "#{address.zipcode} #{address.city}" %><br />
32
+ <%= address.country %>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ </fieldset>
@@ -0,0 +1 @@
1
+ json.call(payment_source, :id, :token, :created_at)
@@ -0,0 +1,12 @@
1
+ <% payment_container_id = "saferpay-payment-container-#{payment_method.id}" %>
2
+ <% if payment_method.preferred_as_iframe %>
3
+ <iframe class="loading-animation saferpay-iframe" width='100%' height='550px' id="<%= payment_container_id %>" src="" frameborder="0">
4
+ </iframe>
5
+ <script charset="utf-8">
6
+ SaferpayPayment.registerIframePaymentMethod({id: "<%= payment_method.id %>", initUrl: "<%= payment_method.init_path %>", containerId: "#<%= payment_container_id %>"})
7
+ </script>
8
+ <% else %>
9
+ <script charset="utf-8">
10
+ SaferpayPayment.registerExternalRedirectPaymentMethod({id: "<%= payment_method.id %>", initUrl: "<%= payment_method.init_path %>"})
11
+ </script>
12
+ <% end %>
@@ -0,0 +1,16 @@
1
+ <% saferpay_payment = payment.source %>
2
+ <% container_class = "saferpay-payment #{payment.state}" %>
3
+ <div class="<%= container_class %>">
4
+ <div class="credit-card">
5
+ <span><%= image_tag "solidus_six_saferpay/credit_cards/icons/#{saferpay_payment.icon_name}.png" %></span>
6
+ <span><%= saferpay_payment.display_text %></span>
7
+ </div>
8
+ <div>
9
+ <div class="amount">
10
+ <%= payment.display_amount %>
11
+ </div>
12
+ <div class="state">
13
+ <%= t("spree.payment_states.#{payment.state}") %>
14
+ </div>
15
+ </div>
16
+ </div>
@@ -0,0 +1,7 @@
1
+ <html>
2
+ <body>
3
+ <script type='text/javascript' charset='utf-8'>
4
+ window.parent.document.location.href = "<%= @redirect_path %>"
5
+ </script>
6
+ </body>
7
+ </html>