solidus-adyen 0.1.2
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.
- checksums.yaml +7 -0
- data/.gitignore +26 -0
- data/.rubocop.yml +9 -0
- data/.rubocop_todo.yml +325 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +238 -0
- data/Rakefile +16 -0
- data/app/assets/javascripts/spree/backend/solidus-adyen.js +1 -0
- data/app/assets/javascripts/spree/checkout/payment/adyen.js +10 -0
- data/app/assets/javascripts/spree/frontend/solidus-adyen.js +1 -0
- data/app/assets/stylesheets/spree/backend/solidus-adyen/buttons.scss +15 -0
- data/app/assets/stylesheets/spree/backend/solidus-adyen/communication.scss +121 -0
- data/app/assets/stylesheets/spree/backend/solidus-adyen/variables.scss +4 -0
- data/app/assets/stylesheets/spree/backend/solidus-adyen.css +5 -0
- data/app/assets/stylesheets/spree/frontend/solidus-adyen.css +3 -0
- data/app/controllers/concerns/spree/adyen/admin/refunds_controller.rb +59 -0
- data/app/controllers/spree/adyen/hpps_controller.rb +22 -0
- data/app/controllers/spree/adyen_notifications_controller.rb +34 -0
- data/app/controllers/spree/adyen_redirect_controller.rb +90 -0
- data/app/models/adyen_notification.rb +159 -0
- data/app/models/concerns/spree/adyen/order.rb +11 -0
- data/app/models/concerns/spree/adyen/payment.rb +95 -0
- data/app/models/spree/adyen/hpp_source.rb +101 -0
- data/app/models/spree/adyen/notification_processor.rb +102 -0
- data/app/models/spree/adyen/presenters/communication.rb +31 -0
- data/app/models/spree/adyen/presenters/communications/adyen_notification.rb +26 -0
- data/app/models/spree/adyen/presenters/communications/base.rb +50 -0
- data/app/models/spree/adyen/presenters/communications/hpp_source.rb +31 -0
- data/app/models/spree/adyen/presenters/communications/log_entry.rb +28 -0
- data/app/models/spree/adyen/presenters/communications.rb +9 -0
- data/app/models/spree/gateway/adyen_hpp.rb +95 -0
- data/app/overrides/spree/admin/shared/_order_summary.rb +6 -0
- data/app/views/spree/admin/payments/source_forms/_adyen.html.erb +1 -0
- data/app/views/spree/admin/payments/source_views/_adyen.html.erb +14 -0
- data/app/views/spree/adyen/_manual_refund.html.erb +9 -0
- data/app/views/spree/adyen/communication/_communication.html.erb +42 -0
- data/app/views/spree/adyen/hpps/directory.html.erb +10 -0
- data/app/views/spree/checkout/payment/_adyen.html.erb +33 -0
- data/bin/checkout.rb +111 -0
- data/bin/regen.sh +1 -0
- data/config/initializers/solidus_adyen.rb +1 -0
- data/config/locales/en.yml +23 -0
- data/config/routes.rb +13 -0
- data/db/migrate/20131017040945_create_adyen_notifications.rb +29 -0
- data/db/migrate/20150911201942_add_index_adyen_notifications_psp_reference.rb +5 -0
- data/db/migrate/20150914162539_create_spree_adyen_hpp_sources.rb +21 -0
- data/db/migrate/20151007090519_add_days_to_ship_to_config.rb +5 -0
- data/db/migrate/20151020230830_remove_indices_on_adyen_notifications.rb +6 -0
- data/db/migrate/20151106093023_allow_merchant_reference_to_be_null_for_adyen_notification.rb +5 -0
- data/lib/solidus-adyen.rb +1 -0
- data/lib/spree/adyen/engine.rb +32 -0
- data/lib/spree/adyen/form.rb +135 -0
- data/lib/spree/adyen/hpp_check.rb +11 -0
- data/lib/spree/adyen/url.rb +30 -0
- data/lib/spree/adyen/version.rb +5 -0
- data/lib/spree/adyen.rb +6 -0
- data/solidus-adyen.gemspec +51 -0
- data/spec/controllers/concerns/spree/adyen/admin/refunds_controller_spec.rb +76 -0
- data/spec/controllers/spree/adyen/hpps_controller_spec.rb +43 -0
- data/spec/controllers/spree/adyen_notifications_controller_spec.rb +118 -0
- data/spec/controllers/spree/adyen_redirect_controller_spec.rb +154 -0
- data/spec/factories/active_merchant_billing_response.rb +23 -0
- data/spec/factories/adyen_notification.rb +91 -0
- data/spec/factories/spree_adyen_hpp_source.rb +15 -0
- data/spec/factories/spree_gateway_adyen_hpp.rb +23 -0
- data/spec/factories/spree_payment.rb +13 -0
- data/spec/lib/spree/adyen/form_spec.rb +214 -0
- data/spec/models/adyen_notification_spec.rb +86 -0
- data/spec/models/concerns/spree/adyen/order_spec.rb +22 -0
- data/spec/models/concerns/spree/adyen/payment_spec.rb +93 -0
- data/spec/models/spree/adyen/hpp_source_spec.rb +101 -0
- data/spec/models/spree/adyen/notification_processor_spec.rb +205 -0
- data/spec/models/spree/adyen/presenters/communication_spec.rb +62 -0
- data/spec/models/spree/gateway/adyen_hpp_spec.rb +76 -0
- data/spec/spec_helper.rb +65 -0
- data/spec/support/shared_contexts/mock_adyen_api.rb +47 -0
- metadata +463 -0
data/bin/checkout.rb
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require "bundler/setup"
|
|
3
|
+
require "capybara"
|
|
4
|
+
require "capybara"
|
|
5
|
+
require "capybara/dsl"
|
|
6
|
+
require "capybara/poltergeist"
|
|
7
|
+
require "pry"
|
|
8
|
+
|
|
9
|
+
Capybara.default_driver = :poltergeist
|
|
10
|
+
|
|
11
|
+
class Driver
|
|
12
|
+
include Capybara::DSL
|
|
13
|
+
|
|
14
|
+
def amex_purchase
|
|
15
|
+
checkout :norway
|
|
16
|
+
|
|
17
|
+
click_link "American Express"
|
|
18
|
+
|
|
19
|
+
fill_in "card.cardNumber", with: "370000000000002"
|
|
20
|
+
fill_in "card.cardHolderName", with: "John Doe"
|
|
21
|
+
select "08", from: "card.expiryMonth"
|
|
22
|
+
select "2018", from: "card.expiryYear"
|
|
23
|
+
fill_in "card.cvcCode", with: "7373"
|
|
24
|
+
|
|
25
|
+
click_button "continue"
|
|
26
|
+
click_button "pay"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def sofort_purchase
|
|
30
|
+
checkout :germany
|
|
31
|
+
|
|
32
|
+
click_link "Sofort Banking"
|
|
33
|
+
fill_in "Account number", with: "88888888"
|
|
34
|
+
fill_in "PIN", with: "12345"
|
|
35
|
+
click_button "Next"
|
|
36
|
+
find(
|
|
37
|
+
"label",
|
|
38
|
+
text: "23456789 - Girokonto (Max Mustermann)",
|
|
39
|
+
match: :prefer_exact).
|
|
40
|
+
click
|
|
41
|
+
click_button "Next"
|
|
42
|
+
fill_in "TAN", with: "12345"
|
|
43
|
+
click_button "Next"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def ideal_purchase issuer
|
|
47
|
+
checkout :norway
|
|
48
|
+
|
|
49
|
+
click_link "iDEAL"
|
|
50
|
+
select issuer
|
|
51
|
+
click_button "continue"
|
|
52
|
+
click_button "Continue"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def login
|
|
56
|
+
visit "http://localhost:3000/login"
|
|
57
|
+
fill_in "Email", with: "spree@example.com", match: :first
|
|
58
|
+
fill_in "Password", with: "spree123"
|
|
59
|
+
|
|
60
|
+
click_button "Login"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def checkout address_type
|
|
64
|
+
visit "http://localhost:3000/"
|
|
65
|
+
click_link "Ruby on Rails Tote", match: :first
|
|
66
|
+
click_button "Add To Cart"
|
|
67
|
+
click_button "Checkout"
|
|
68
|
+
fill_address address_type
|
|
69
|
+
click_button "Save and Continue"
|
|
70
|
+
click_button "Save and Continue"
|
|
71
|
+
choose "Adyen"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def fill_address type
|
|
75
|
+
fill_in "First Name", with: "John"
|
|
76
|
+
fill_in "Last Name", with: "Doe"
|
|
77
|
+
fill_in "Phone", with: "250-111-1111"
|
|
78
|
+
case type
|
|
79
|
+
when :norway
|
|
80
|
+
fill_norway_address
|
|
81
|
+
when :germany
|
|
82
|
+
fill_german_address
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def fill_german_address
|
|
87
|
+
fill_in "Street Address", with: "Gleimstraße 62"
|
|
88
|
+
fill_in "City", with: "Berlin"
|
|
89
|
+
select "Germany"
|
|
90
|
+
select "Berlin"
|
|
91
|
+
fill_in "Zip", with: "13355"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def fill_norway_address
|
|
95
|
+
fill_in "Street Address", with: "Noordwal 540"
|
|
96
|
+
fill_in "City", with: "Den Haag"
|
|
97
|
+
select "Netherlands"
|
|
98
|
+
select "Zuid-Holland"
|
|
99
|
+
fill_in "Zip", with: "2513dz"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
driver = Driver.new
|
|
104
|
+
|
|
105
|
+
driver.login
|
|
106
|
+
driver.sofort_purchase
|
|
107
|
+
driver.amex_purchase
|
|
108
|
+
driver.ideal_purchase "Test Issuer"
|
|
109
|
+
# driver.ideal_purchase "Test Issuer Refused"
|
|
110
|
+
# driver.ideal_purchase "Test Issuer Pending"
|
|
111
|
+
# driver.ideal_purchase "Test Issuer Cancelled"
|
data/bin/regen.sh
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rm -rf spec/dummy && bundle install && rake test_app && cd spec/dummy && rake db:migrate && rails s
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Rails.application.config.assets.precompile += %w( spree/checkout/payment/adyen.js )
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
en:
|
|
3
|
+
spree:
|
|
4
|
+
adyen:
|
|
5
|
+
communication:
|
|
6
|
+
communication:
|
|
7
|
+
payment_method: "Payment method"
|
|
8
|
+
event_code: "Event code"
|
|
9
|
+
result: "Result"
|
|
10
|
+
message: "Message"
|
|
11
|
+
Reason: "Reason"
|
|
12
|
+
amount: "Amount"
|
|
13
|
+
solidus-adyen:
|
|
14
|
+
payment:
|
|
15
|
+
failure: "Action failed, check reason for more information."
|
|
16
|
+
success: "Action succeeded."
|
|
17
|
+
unprocessed: "Action was not processed: payment may require manual resolution."
|
|
18
|
+
manual_refund:
|
|
19
|
+
order_button: "manual refund required"
|
|
20
|
+
log_message: A cancellation was attempted on this payment but the payment
|
|
21
|
+
method only supports manual refunds.
|
|
22
|
+
Please attempt to refund this payment through the Adyen customer area
|
|
23
|
+
or contact an Adyen representative to assist.
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Spree::Core::Engine.routes.draw do
|
|
2
|
+
namespace :adyen do
|
|
3
|
+
resource :hpp, only: [] do
|
|
4
|
+
member do
|
|
5
|
+
get :directory
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
get "checkout/payment/adyen", to: "adyen_redirect#confirm", as: :adyen_confirmation
|
|
11
|
+
post "adyen/notify", to: "adyen_notifications#notify"
|
|
12
|
+
post "adyen/authorise3d", to: "adyen_redirect#authorise3d", as: :adyen_authorise3d
|
|
13
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# @private
|
|
2
|
+
class CreateAdyenNotifications < ActiveRecord::Migration
|
|
3
|
+
|
|
4
|
+
def self.up
|
|
5
|
+
create_table :adyen_notifications do |t|
|
|
6
|
+
t.boolean :live, :null => false, :default => false
|
|
7
|
+
t.string :event_code, :null => false, :limit => 40
|
|
8
|
+
t.string :psp_reference, :null => false, :limit => 50
|
|
9
|
+
t.string :original_reference, :null => true
|
|
10
|
+
t.string :merchant_reference, :null => false
|
|
11
|
+
t.string :merchant_account_code, :null => false
|
|
12
|
+
t.datetime :event_date, :null => false
|
|
13
|
+
t.boolean :success, :null => false, :default => false
|
|
14
|
+
t.string :payment_method, :null => true
|
|
15
|
+
t.string :operations, :null => true
|
|
16
|
+
t.text :reason, :null => true
|
|
17
|
+
t.string :currency, :null => true, :limit => 3
|
|
18
|
+
t.integer :value, :null => true
|
|
19
|
+
t.boolean :processed, :null => false, :default => false
|
|
20
|
+
t.timestamps
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
add_index :adyen_notifications, [:psp_reference, :event_code, :success], :unique => true, :name => "adyen_notification_uniqueness"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.down
|
|
27
|
+
drop_table :adyen_notifications
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Fields come from
|
|
2
|
+
# https://docs.adyen.com/display/TD/HPP+payment+response
|
|
3
|
+
class CreateSpreeAdyenHppSources < ActiveRecord::Migration
|
|
4
|
+
def change
|
|
5
|
+
create_table :spree_adyen_hpp_sources do |t|
|
|
6
|
+
t.string :auth_result
|
|
7
|
+
t.string :psp_reference
|
|
8
|
+
t.string :merchant_reference
|
|
9
|
+
t.string :skin_code
|
|
10
|
+
t.string :merchant_sig
|
|
11
|
+
t.string :payment_method
|
|
12
|
+
t.string :shopper_locale
|
|
13
|
+
t.string :merchant_return_data
|
|
14
|
+
|
|
15
|
+
t.timestamps
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
add_index :spree_adyen_hpp_sources, :psp_reference, unique: true
|
|
19
|
+
add_index :spree_adyen_hpp_sources, :merchant_reference
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "spree/adyen"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Adyen
|
|
3
|
+
class Engine < ::Rails::Engine
|
|
4
|
+
engine_name "solidus-adyen"
|
|
5
|
+
|
|
6
|
+
isolate_namespace Spree::Adyen
|
|
7
|
+
|
|
8
|
+
config.autoload_paths += Dir["#{config.root}/lib/**/"]
|
|
9
|
+
|
|
10
|
+
config.autoload_paths += %W(
|
|
11
|
+
#{config.root}/app/controllers/concerns
|
|
12
|
+
#{config.root}/app/models/concerns
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
config.generators do |g|
|
|
16
|
+
g.test_framework :rspec
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
initializer "spree.solidus-adyen.payment_methods", after: "spree.register.payment_methods" do |app|
|
|
20
|
+
app.config.spree.payment_methods << Gateway::AdyenHPP
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.activate
|
|
24
|
+
Spree::Payment.include Spree::Adyen::Payment
|
|
25
|
+
Spree::Order.include Spree::Adyen::Order
|
|
26
|
+
Spree::Admin::RefundsController.include Spree::Adyen::Admin::RefundsController
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
config.to_prepare(&method(:activate).to_proc)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
module Spree
|
|
4
|
+
module Adyen
|
|
5
|
+
module Form
|
|
6
|
+
Form = ::Adyen::Form
|
|
7
|
+
UrlHelper = Object.new.extend ActionView::Helpers::UrlHelper
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def payment_methods_from_directory order, payment_method
|
|
11
|
+
payment_methods(order, payment_method)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def select_url order, payment_method
|
|
15
|
+
endpoint_url "select", order, payment_method
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def directory_url order, payment_method
|
|
19
|
+
endpoint_url "directory", order, payment_method
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def details_url order, payment_method, brand_code
|
|
23
|
+
endpoint_url(
|
|
24
|
+
"details", order, payment_method, { brandCode: brand_code })
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def details_url_with_issuer order, payment_method, brand_code, issuer_id
|
|
28
|
+
endpoint_url(
|
|
29
|
+
"details",
|
|
30
|
+
order,
|
|
31
|
+
payment_method,
|
|
32
|
+
{
|
|
33
|
+
brandCode: brand_code,
|
|
34
|
+
issuerId: issuer_id
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def endpoint_url endpoint, order, payment_method, opts = {}
|
|
40
|
+
base = URI::parse(url payment_method, endpoint)
|
|
41
|
+
|
|
42
|
+
URI::HTTPS.build(
|
|
43
|
+
host: base.host,
|
|
44
|
+
path: base.path,
|
|
45
|
+
query: params(order, payment_method).merge(opts).to_query)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
def payment_methods order, payment_method
|
|
50
|
+
url = directory_url(order, payment_method)
|
|
51
|
+
|
|
52
|
+
form_payment_methods_and_urls(
|
|
53
|
+
JSON.parse(::Net::HTTP.get(url)),
|
|
54
|
+
order,
|
|
55
|
+
payment_method
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def url payment_method, endpoint
|
|
60
|
+
server = payment_method.preferences.fetch(:server)
|
|
61
|
+
Form.url(server, endpoint)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def form_payment_methods_and_urls response, order, payment_method
|
|
65
|
+
response.fetch("paymentMethods").map do |brand|
|
|
66
|
+
issuers = brand.fetch("issuers", []).map do |issuer|
|
|
67
|
+
form_issuer(issuer, order, payment_method, brand)
|
|
68
|
+
end
|
|
69
|
+
form_payment_method(brand, order, payment_method, issuers)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def form_issuer issuer, order, payment_method, brand
|
|
74
|
+
{
|
|
75
|
+
name: issuer["name"],
|
|
76
|
+
payment_url: details_url_with_issuer(
|
|
77
|
+
order,
|
|
78
|
+
payment_method,
|
|
79
|
+
brand["brandCode"],
|
|
80
|
+
issuer["issuerId"]
|
|
81
|
+
).to_s
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def form_payment_method brand, order, payment_method, issuers
|
|
86
|
+
{
|
|
87
|
+
brand_code: brand["brandCode"],
|
|
88
|
+
name: brand["name"],
|
|
89
|
+
payment_url: details_url(
|
|
90
|
+
order,
|
|
91
|
+
payment_method,
|
|
92
|
+
brand["brandCode"]
|
|
93
|
+
).to_s,
|
|
94
|
+
issuers: issuers
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def params order, payment_method
|
|
99
|
+
merchant_return_data = [
|
|
100
|
+
order.guest_token,
|
|
101
|
+
payment_method.id
|
|
102
|
+
].
|
|
103
|
+
join("|")
|
|
104
|
+
|
|
105
|
+
Form.flat_payment_parameters default_params.
|
|
106
|
+
merge(order_params order).
|
|
107
|
+
merge(payment_method_params payment_method).
|
|
108
|
+
merge(merchant_return_data: merchant_return_data)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# TODO set this in the adyen config
|
|
112
|
+
def default_params
|
|
113
|
+
{ session_validity: 10.minutes.from_now,
|
|
114
|
+
recurring: false }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def order_params order
|
|
118
|
+
{ currency_code: order.currency,
|
|
119
|
+
merchant_reference: order.number.to_s,
|
|
120
|
+
country_code: order.billing_address.country.iso,
|
|
121
|
+
payment_amount: (order.total * 100).to_int
|
|
122
|
+
}
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def payment_method_params payment_method
|
|
126
|
+
{ merchant_account: payment_method.merchant_account,
|
|
127
|
+
skin_code: payment_method.skin_code,
|
|
128
|
+
shared_secret: payment_method.shared_secret,
|
|
129
|
+
ship_before_date: payment_method.ship_before_date
|
|
130
|
+
}
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Adyen
|
|
3
|
+
# Used when we have to override functionally inside spree, usually payments,
|
|
4
|
+
# that is a conditional flow only on hpp payments.
|
|
5
|
+
module HppCheck
|
|
6
|
+
def hpp_payment? payment = self
|
|
7
|
+
payment.source.class == Spree::Adyen::HppSource
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Adyen
|
|
3
|
+
module URL
|
|
4
|
+
def self.payment_adyen_customer_area_url(psp_reference:, merchant_account:)
|
|
5
|
+
::URI::HTTPS.build(
|
|
6
|
+
host: "ca-test.adyen.com",
|
|
7
|
+
path: "/ca/ca/accounts/showTx.shtml",
|
|
8
|
+
query:
|
|
9
|
+
{ txType: "Payment",
|
|
10
|
+
accountKey: "MerchantAccount.#{merchant_account}",
|
|
11
|
+
pspReference: psp_reference
|
|
12
|
+
}.to_query
|
|
13
|
+
).to_s
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.modify_search_url(query:)
|
|
17
|
+
::URI::HTTPS.build(
|
|
18
|
+
host: "ca-test.adyen.com",
|
|
19
|
+
path: "/ca/ca/payments/modifySearch.shtml",
|
|
20
|
+
query:
|
|
21
|
+
{ uxEvent: "PAYMENT_SEARCH",
|
|
22
|
+
query: query,
|
|
23
|
+
search: "Search"
|
|
24
|
+
}.to_query
|
|
25
|
+
).to_s
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
data/lib/spree/adyen.rb
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require "spree/adyen/version"
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "solidus-adyen"
|
|
8
|
+
spec.version = Spree::Adyen::VERSION
|
|
9
|
+
spec.authors = ["Dylan Kendal"]
|
|
10
|
+
spec.email = ["dylan@stembolt.com"]
|
|
11
|
+
spec.description = "Adyen HPP payments for Solidus Stores"
|
|
12
|
+
spec.summary = "Adyen HPP payments for Solidus Stores"
|
|
13
|
+
spec.homepage = "https://github.com/StemboltHQ/solidus-adyen"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files`.split($/)
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_runtime_dependency "adyen", "~> 1.4"
|
|
22
|
+
spec.add_runtime_dependency "solidus_core", "~> 1.0"
|
|
23
|
+
spec.add_runtime_dependency "bourbon"
|
|
24
|
+
|
|
25
|
+
spec.add_development_dependency "solidus", "~> 1.0"
|
|
26
|
+
spec.add_development_dependency "solidus_auth_devise", "~> 1.2"
|
|
27
|
+
spec.add_development_dependency "solidus_sample", "~> 1.0"
|
|
28
|
+
|
|
29
|
+
spec.add_development_dependency "sass-rails", "~> 4.0.2"
|
|
30
|
+
spec.add_development_dependency "coffee-rails"
|
|
31
|
+
|
|
32
|
+
spec.add_development_dependency "sqlite3"
|
|
33
|
+
|
|
34
|
+
spec.add_development_dependency "rspec-rails", "~> 3.3"
|
|
35
|
+
spec.add_development_dependency "rspec-activemodel-mocks"
|
|
36
|
+
spec.add_development_dependency "factory_girl"
|
|
37
|
+
spec.add_development_dependency "shoulda-matchers"
|
|
38
|
+
|
|
39
|
+
spec.add_development_dependency "simplecov"
|
|
40
|
+
spec.add_development_dependency "simplecov-rcov"
|
|
41
|
+
|
|
42
|
+
spec.add_development_dependency "awesome_print"
|
|
43
|
+
spec.add_development_dependency "pry-rails"
|
|
44
|
+
spec.add_development_dependency "better_errors"
|
|
45
|
+
spec.add_development_dependency "binding_of_caller"
|
|
46
|
+
spec.add_development_dependency "pry-stack_explorer"
|
|
47
|
+
|
|
48
|
+
spec.add_development_dependency "capybara"
|
|
49
|
+
spec.add_development_dependency "poltergeist"
|
|
50
|
+
spec.add_development_dependency "launchy"
|
|
51
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe Spree::Admin::RefundsController do
|
|
4
|
+
stub_authorization!
|
|
5
|
+
include_context "mock adyen api", success: true
|
|
6
|
+
routes { Spree::Core::Engine.routes }
|
|
7
|
+
|
|
8
|
+
describe "POST create" do
|
|
9
|
+
subject { post :create, params }
|
|
10
|
+
|
|
11
|
+
let(:params) do
|
|
12
|
+
{
|
|
13
|
+
"refund" => {
|
|
14
|
+
"amount" => amount,
|
|
15
|
+
"refund_reason_id" => reason.id
|
|
16
|
+
},
|
|
17
|
+
"order_id" => order.number,
|
|
18
|
+
"payment_id" => payment.id
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
let(:reason) { create :refund_reason }
|
|
23
|
+
let(:order) { create :order, currency: "EUR" }
|
|
24
|
+
let(:amount) { 100.0 }
|
|
25
|
+
let(:payment_opts) { {state: "completed", amount: 100.0} }
|
|
26
|
+
|
|
27
|
+
before do
|
|
28
|
+
payment.capture_events.create!(amount: 100.0)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context "when the payment comes from Adyen Hosted Payment Pages" do
|
|
32
|
+
let(:payment) { create :hpp_payment, order: order, **payment_opts }
|
|
33
|
+
|
|
34
|
+
it "does not create the record" do
|
|
35
|
+
expect { subject }.to_not change { payment.reload.refunds.count }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "sets the success flash" do
|
|
39
|
+
subject
|
|
40
|
+
expect(flash[:success]).to eq "Refund request was received"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "requests the refund" do
|
|
44
|
+
expect_any_instance_of(Spree::Payment).
|
|
45
|
+
to receive(:credit!).
|
|
46
|
+
with(10000, currency: "EUR")
|
|
47
|
+
subject
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it { is_expected.to have_http_status :redirect }
|
|
51
|
+
|
|
52
|
+
context "and the refund is invalid" do
|
|
53
|
+
let(:amount) { 0 }
|
|
54
|
+
|
|
55
|
+
it "displays an error" do
|
|
56
|
+
is_expected.to have_http_status :ok
|
|
57
|
+
expect(flash[:error]).to be_present
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "doesn't attempt to credit the payment" do
|
|
61
|
+
expect_any_instance_of(Spree::Payment).
|
|
62
|
+
to_not receive(:credit!)
|
|
63
|
+
subject
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
context "when any other kind of payment" do
|
|
69
|
+
let(:payment) { create :payment, **payment_opts }
|
|
70
|
+
|
|
71
|
+
it "creates the refund" do
|
|
72
|
+
expect { subject }.to change { payment.reload.refunds.count }.by(1)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe Spree::Adyen::HppsController, type: :controller do
|
|
4
|
+
describe "GET directory" do
|
|
5
|
+
let(:order) { create :order }
|
|
6
|
+
let(:payment_method) { create :hpp_gateway }
|
|
7
|
+
let(:parsed_directory_response) { [{
|
|
8
|
+
name: "American Express",
|
|
9
|
+
brandCode: "amex",
|
|
10
|
+
payment_url: "www.test-payment-url.com/amex"}] }
|
|
11
|
+
|
|
12
|
+
before do
|
|
13
|
+
allow(Spree::Adyen::Form).to receive(:payment_methods_from_directory).
|
|
14
|
+
with(order, payment_method).
|
|
15
|
+
and_return(parsed_directory_response)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context "html response" do
|
|
19
|
+
subject {
|
|
20
|
+
get :directory,
|
|
21
|
+
order_id: order.id,
|
|
22
|
+
payment_method_id: payment_method.id }
|
|
23
|
+
|
|
24
|
+
it { is_expected.to have_http_status :ok }
|
|
25
|
+
it { is_expected.to render_template "directory" }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "json response" do
|
|
29
|
+
subject {
|
|
30
|
+
get :directory,
|
|
31
|
+
order_id: order.id,
|
|
32
|
+
payment_method_id: payment_method.id,
|
|
33
|
+
format: :json }
|
|
34
|
+
|
|
35
|
+
it { is_expected.to have_http_status :ok }
|
|
36
|
+
|
|
37
|
+
it "renders a json response" do
|
|
38
|
+
subject
|
|
39
|
+
expect(response.body).to eq parsed_directory_response.to_json
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|