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,15 @@
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 any plugin's vendor/assets/stylesheets directory 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 other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,30 @@
1
+ .saferpay-iframe {
2
+ width: 100%;
3
+ }
4
+
5
+ .loading-animation {
6
+ text-align: center;
7
+ background-color: #222222;
8
+
9
+ -webkit-animation: sk-scaleout 0.5s infinite ease-in-out;
10
+ animation: sk-scaleout 0.5s infinite ease-in-out;
11
+ }
12
+
13
+ @-webkit-keyframes sk-scaleout {
14
+ 0% { -webkit-transform: scale(0) }
15
+ 100% {
16
+ -webkit-transform: scale(0.2);
17
+ opacity: 0;
18
+ }
19
+ }
20
+
21
+ @keyframes sk-scaleout {
22
+ 0% {
23
+ -webkit-transform: scale(0);
24
+ transform: scale(0);
25
+ } 100% {
26
+ -webkit-transform: scale(0.2);
27
+ transform: scale(0.2);
28
+ opacity: 0;
29
+ }
30
+ }
@@ -0,0 +1,10 @@
1
+ .saferpay-payment {
2
+ &.void {
3
+
4
+ .amount {
5
+ text-decoration: line-through;
6
+ }
7
+ }
8
+ }
9
+
10
+
@@ -0,0 +1,5 @@
1
+ module SolidusSixSaferpay
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,93 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class CheckoutController < StoreController
4
+
5
+ before_action :load_order
6
+
7
+ def init
8
+ payment_method = Spree::PaymentMethod.find(params[:payment_method_id])
9
+ initialized_payment = initialize_payment(@order, payment_method)
10
+
11
+ if initialized_payment.success?
12
+ redirect_url = initialized_payment.redirect_url
13
+ render json: { redirect_url: redirect_url }
14
+ else
15
+ render json: { errors: t('.checkout_not_initialized') }, status: 422
16
+ end
17
+ end
18
+
19
+ def success
20
+ saferpay_payment = Spree::SixSaferpayPayment.where(order_id: @order.id).order(:created_at).last
21
+
22
+ if saferpay_payment.nil?
23
+ raise Spree::Core::GatewayError, t('.payment_source_not_created')
24
+ end
25
+
26
+ # NOTE: PaymentPage payments are authorized directly. Instead, we
27
+ # perform an ASSERT here to gather the necessary details.
28
+ # This might be confusing at first, but doing it this way makes sense
29
+ # (and the code a LOT more readable) IMO. Feel free to disagree and PR
30
+ # a better solution.
31
+ # NOTE: Transaction payments are authorized here so that the money is
32
+ # already allocated when the user is on the confirm page. If the user
33
+ # then chooses another payment, the authorized payment is voided
34
+ # (cancelled).
35
+ payment_authorization = authorize_payment(saferpay_payment)
36
+
37
+ if payment_authorization.success?
38
+
39
+ processed_authorization = process_authorization(saferpay_payment)
40
+ if processed_authorization.success?
41
+ @order.next! if @order.payment?
42
+ else
43
+ flash[:error] = processed_authorization.user_message
44
+ end
45
+
46
+ else
47
+ payment_inquiry = inquire_payment(saferpay_payment)
48
+ flash[:error] = payment_inquiry.user_message
49
+ end
50
+
51
+ @redirect_path = order_checkout_path(@order.state)
52
+ render :iframe_breakout_redirect, layout: false
53
+ end
54
+
55
+ def fail
56
+ saferpay_payment = Spree::SixSaferpayPayment.where(order_id: @order.id).order(:created_at).last
57
+
58
+ payment_inquiry = inquire_payment(saferpay_payment)
59
+
60
+ @redirect_path = order_checkout_path(:payment)
61
+ flash[:error] = payment_inquiry.user_message
62
+ render :iframe_breakout_redirect, layout: false
63
+ end
64
+
65
+ private
66
+
67
+ def initialize_payment(order, payment_method)
68
+ raise NotImplementedError, "Must be implemented in PaymentPageCheckoutController or TransactionCheckoutController"
69
+ end
70
+
71
+ def authorize_payment(saferpay_payment)
72
+ raise NotImplementedError, "Must be implemented in PaymentPageCheckoutController or TransactionCheckoutController"
73
+ end
74
+
75
+ def process_authorization(saferpay_payment)
76
+ raise NotImplementedError, "Must be implemented in PaymentPageCheckoutController or TransactionCheckoutController"
77
+ end
78
+
79
+ def inquire_payment(saferpay_payment)
80
+ raise NotImplementedError, "Must be implemented in PaymentPageCheckoutController or TransactionCheckoutController"
81
+ end
82
+
83
+ def load_order
84
+ @order = current_order
85
+ redirect_to(spree.cart_path) && return unless @order
86
+ end
87
+
88
+ def order_checkout_path(state)
89
+ Spree::Core::Engine.routes.url_helpers.checkout_state_path(state)
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,27 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ module PaymentPage
4
+ # explicit parent must be stated, otherwise Spree::CheckoutController has precendence
5
+ class CheckoutController < SolidusSixSaferpay::CheckoutController
6
+
7
+ private
8
+
9
+ def initialize_payment(order, payment_method)
10
+ InitializePaymentPage.call(order, payment_method)
11
+ end
12
+
13
+ def authorize_payment(saferpay_payment)
14
+ AssertPaymentPage.call(saferpay_payment)
15
+ end
16
+
17
+ def process_authorization(saferpay_payment)
18
+ ProcessPaymentPagePayment.call(saferpay_payment)
19
+ end
20
+
21
+ def inquire_payment(saferpay_payment)
22
+ InquirePaymentPagePayment.call(saferpay_payment)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ # explicit parent must be stated, otherwise Spree::CheckoutController has precendence
4
+ module Transaction
5
+ class CheckoutController < SolidusSixSaferpay::CheckoutController
6
+
7
+ private
8
+
9
+ def initialize_payment(order, payment_method)
10
+ InitializeTransaction.call(order, payment_method)
11
+ end
12
+
13
+ def authorize_payment(saferpay_payment)
14
+ AuthorizeTransaction.call(saferpay_payment)
15
+ end
16
+
17
+ def process_authorization(saferpay_payment)
18
+ ProcessTransactionPayment.call(saferpay_payment)
19
+ end
20
+
21
+ def inquire_payment(saferpay_payment)
22
+ InquireTransactionPayment.call(saferpay_payment)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,4 @@
1
+ module SolidusSixSaferpay
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module SolidusSixSaferpay
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module SolidusSixSaferpay
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: 'from@example.com'
4
+ layout 'mailer'
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module SolidusSixSaferpay
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,46 @@
1
+ module Spree
2
+ class PaymentMethod::SaferpayPaymentMethod < PaymentMethod::CreditCard
3
+ include RouteAccess
4
+
5
+ AVAILABLE_PAYMENT_METHODS = %w(ALIPAY AMEX BANCONTACT BONUS DINERS DIRECTDEBIT EPRZELEWY EPS GIROPAY IDEAL INVOICE JCB MAESTRO MASTERCARD MYONE PAYPAL PAYDIREKT POSTCARD POSTFINANCE SAFERPAYTEST SOFORT TWINT UNIONPAY VISA VPAY)
6
+
7
+ delegate :try_void, to: :gateway
8
+
9
+ preference :as_iframe, :boolean, default: true
10
+
11
+ preference :require_liability_shift, :boolean, default: true
12
+
13
+ # Configure all available Payment Methods for the Saferpay API as
14
+ # preferences
15
+ AVAILABLE_PAYMENT_METHODS.each do |six_payment_method|
16
+ preference "payment_method_#{six_payment_method.downcase}", :boolean, default: false
17
+ end
18
+
19
+ def enabled_payment_methods
20
+ AVAILABLE_PAYMENT_METHODS.select do |six_payment_method|
21
+ public_send("preferred_payment_method_#{six_payment_method.downcase}")
22
+ end
23
+ end
24
+
25
+ def payment_source_class
26
+ Spree::SixSaferpayPayment
27
+ end
28
+
29
+ def profiles_supported?
30
+ false
31
+ end
32
+
33
+ # We want to automatically capture the payment when the order is completed
34
+ def auto_capture
35
+ true
36
+ end
37
+
38
+ def partial_name
39
+ 'saferpay_payment'
40
+ end
41
+
42
+ def init_path
43
+ raise NotImplementedError, "Must be implemented in SaferpayPaymentPage or SaferpayTransaction"
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ module Spree
2
+ class PaymentMethod::SaferpayPaymentPage < PaymentMethod::SaferpayPaymentMethod
3
+
4
+
5
+ def gateway_class
6
+ ::SolidusSixSaferpay::PaymentPageGateway
7
+ end
8
+
9
+ def init_path
10
+ url_helpers.solidus_six_saferpay_payment_page_init_path
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module Spree
2
+ class PaymentMethod::SaferpayTransaction < PaymentMethod::SaferpayPaymentMethod
3
+
4
+ def gateway_class
5
+ ::SolidusSixSaferpay::TransactionGateway
6
+ end
7
+
8
+ def init_path
9
+ url_helpers.solidus_six_saferpay_transaction_init_path
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,69 @@
1
+ module Spree
2
+
3
+ # attributes
4
+ # * :token
5
+ # * :expiration
6
+ # * :redirect_url
7
+ # * :transaction_id
8
+ # * :transaction_status
9
+ # * :transaction_date
10
+ # * :six_transaction_reference
11
+ # * :display_text
12
+ # * :masked_number
13
+ # * :expiration_year
14
+ # * :expiration_month
15
+ # * :response_hash
16
+ class SixSaferpayPayment < PaymentSource
17
+ belongs_to :order
18
+ belongs_to :payment_method
19
+ # store this anyway for accountability reasons
20
+ serialize :response_hash, Hash
21
+
22
+ validates :token, :expiration, presence: true
23
+ validates :token, :transaction_id, :six_transaction_reference, uniqueness: true, allow_blank: true
24
+
25
+ def create_solidus_payment!
26
+ payments.create!(order: order, response_code: transaction_id, payment_method: payment_method, amount: order.total, source: self)
27
+ end
28
+
29
+ def address
30
+ @address ||= order.bill_address
31
+ end
32
+
33
+ def payment_means
34
+ @payment_means ||= ::SixSaferpay::ResponsePaymentMeans.new(response_hash[:payment_means])
35
+ end
36
+
37
+ def transaction
38
+ @transaction ||= ::SixSaferpay::Transaction.new(response_hash[:transaction])
39
+ end
40
+
41
+ def liability
42
+ @liability ||= ::SixSaferpay::Liability.new(response_hash[:liability])
43
+ end
44
+
45
+ def card
46
+ payment_means.card
47
+ end
48
+
49
+ def name
50
+ card.holder_name
51
+ end
52
+
53
+ def brand_name
54
+ payment_means.brand.name
55
+ end
56
+
57
+ def month
58
+ card.exp_month
59
+ end
60
+
61
+ def year
62
+ card.exp_year
63
+ end
64
+
65
+ def icon_name
66
+ payment_means.brand.payment_method.downcase
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,5 @@
1
+ module Spree
2
+ module RouteAccess
3
+ delegate :url_helpers, to: 'Spree::Core::Engine.routes'
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class AssertPaymentPage < AuthorizePayment
4
+ include UsePaymentPageGateway
5
+ end
6
+ end
7
+ end
8
+
@@ -0,0 +1,60 @@
1
+ module Spree
2
+ module SolidusSixSaferpay
3
+ class AuthorizePayment
4
+ attr_reader :saferpay_payment, :order, :success
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
+ def call
16
+ authorization = gateway.authorize(order.total, saferpay_payment)
17
+
18
+ if authorization.success?
19
+ saferpay_payment.update_attributes!(saferpay_payment_attributes(authorization.api_response))
20
+ @success = true
21
+ end
22
+ self
23
+ end
24
+
25
+ def success?
26
+ @success
27
+ end
28
+
29
+
30
+ def gateway
31
+ raise NotImplementedError, "Must be implemented in AssertPaymentPage or AuthorizeTransaction with UsePaymentPageGateway or UseTransactionGateway"
32
+ end
33
+
34
+ private
35
+
36
+ def saferpay_payment_attributes(saferpay_response)
37
+ payment_means = saferpay_response.payment_means
38
+ brand = payment_means.brand
39
+ card = payment_means.card
40
+
41
+ attributes = {
42
+ transaction_id: saferpay_response.transaction.id,
43
+ transaction_status: saferpay_response.transaction.status,
44
+ transaction_date: DateTime.parse(saferpay_response.transaction.date),
45
+ six_transaction_reference: saferpay_response.transaction.six_transaction_reference,
46
+ display_text: saferpay_response.payment_means.display_text,
47
+ response_hash: saferpay_response.to_h
48
+ }
49
+
50
+ if card
51
+ attributes[:masked_number] = card.masked_number
52
+ attributes[:expiration_year] = card.exp_year
53
+ attributes[:expiration_month] = card.exp_month
54
+ end
55
+
56
+ attributes
57
+ end
58
+ end
59
+ end
60
+ end