solidus_six_saferpay 0.1.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 (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>