solidus_six_saferpay 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +220 -0
- data/Rakefile +56 -0
- data/app/assets/config/solidus_six_saferpay_manifest.js +2 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/amex.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/cirrus.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/delta.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/diners_club.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/directdebit.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/discover.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/egold.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/maestro.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/mastercard.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/paypal.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/solo.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/switch.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/twint.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/visa.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/visaelectron.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/westernunion.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/wirecard.png +0 -0
- data/app/assets/images/solidus_six_saferpay/credit_cards/icons/worldpay.png +0 -0
- data/app/assets/javascripts/solidus_six_saferpay/application.js +14 -0
- data/app/assets/javascripts/solidus_six_saferpay/saferpay_payment.js +120 -0
- data/app/assets/stylesheets/solidus_six_saferpay/application.css +15 -0
- data/app/assets/stylesheets/solidus_six_saferpay/loading_animation.scss +30 -0
- data/app/assets/stylesheets/solidus_six_saferpay/payments.scss +10 -0
- data/app/controllers/solidus_six_saferpay/application_controller.rb +5 -0
- data/app/controllers/spree/solidus_six_saferpay/checkout_controller.rb +93 -0
- data/app/controllers/spree/solidus_six_saferpay/payment_page/checkout_controller.rb +27 -0
- data/app/controllers/spree/solidus_six_saferpay/transaction/checkout_controller.rb +27 -0
- data/app/helpers/solidus_six_saferpay/application_helper.rb +4 -0
- data/app/jobs/solidus_six_saferpay/application_job.rb +4 -0
- data/app/mailers/solidus_six_saferpay/application_mailer.rb +6 -0
- data/app/models/solidus_six_saferpay/application_record.rb +5 -0
- data/app/models/spree/payment_method/saferpay_payment_method.rb +46 -0
- data/app/models/spree/payment_method/saferpay_payment_page.rb +13 -0
- data/app/models/spree/payment_method/saferpay_transaction.rb +12 -0
- data/app/models/spree/six_saferpay_payment.rb +69 -0
- data/app/services/spree/route_access.rb +5 -0
- data/app/services/spree/solidus_six_saferpay/assert_payment_page.rb +8 -0
- data/app/services/spree/solidus_six_saferpay/authorize_payment.rb +60 -0
- data/app/services/spree/solidus_six_saferpay/authorize_transaction.rb +8 -0
- data/app/services/spree/solidus_six_saferpay/initialize_payment.rb +57 -0
- data/app/services/spree/solidus_six_saferpay/initialize_payment_page.rb +15 -0
- data/app/services/spree/solidus_six_saferpay/initialize_transaction.rb +16 -0
- data/app/services/spree/solidus_six_saferpay/inquire_payment.rb +43 -0
- data/app/services/spree/solidus_six_saferpay/inquire_payment_page_payment.rb +7 -0
- data/app/services/spree/solidus_six_saferpay/inquire_transaction.rb +7 -0
- data/app/services/spree/solidus_six_saferpay/inquire_transaction_payment.rb +7 -0
- data/app/services/spree/solidus_six_saferpay/payment_validator.rb +62 -0
- data/app/services/spree/solidus_six_saferpay/process_authorized_payment.rb +87 -0
- data/app/services/spree/solidus_six_saferpay/process_payment_page_payment.rb +7 -0
- data/app/services/spree/solidus_six_saferpay/process_transaction_payment.rb +7 -0
- data/app/services/spree/solidus_six_saferpay/use_payment_page_gateway.rb +11 -0
- data/app/services/spree/solidus_six_saferpay/use_transaction_gateway.rb +11 -0
- data/app/views/spree/admin/payments/source_views/_saferpay_payment.erb +36 -0
- data/app/views/spree/api/payments/source_views/_saferpay_payment.json.jbuilder +1 -0
- data/app/views/spree/checkout/payment/_saferpay_payment.html.erb +12 -0
- data/app/views/spree/six_saferpay_payments/_six_saferpay_payment.html.erb +16 -0
- data/app/views/spree/solidus_six_saferpay/checkout/iframe_breakout_redirect.html.erb +7 -0
- data/config/locales/de.yml +52 -0
- data/config/locales/en.yml +52 -0
- data/config/locales/fr.yml +51 -0
- data/config/routes.rb +17 -0
- data/db/migrate/20190523075638_create_six_saferpay_payments.rb +31 -0
- data/lib/generators/solidus_six_saferpay/install/install_generator.rb +20 -0
- data/lib/solidus_six_saferpay.rb +5 -0
- data/lib/solidus_six_saferpay/configuration.rb +12 -0
- data/lib/solidus_six_saferpay/engine.rb +25 -0
- data/lib/solidus_six_saferpay/error_handler.rb +21 -0
- data/lib/solidus_six_saferpay/gateway.rb +183 -0
- data/lib/solidus_six_saferpay/gateway_response.rb +38 -0
- data/lib/solidus_six_saferpay/invalid_saferpay_payment.rb +11 -0
- data/lib/solidus_six_saferpay/payment_page_gateway.rb +55 -0
- data/lib/solidus_six_saferpay/transaction_gateway.rb +47 -0
- data/lib/solidus_six_saferpay/version.rb +3 -0
- data/lib/tasks/solidus_six_saferpay_tasks.rake +4 -0
- metadata +319 -0
@@ -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,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,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>
|