solidus-adyen 0.2.1 → 0.2.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 +4 -4
- data/.gitignore +4 -5
- data/.travis.yml +10 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -1
- data/README.md +2 -2
- data/app/controllers/spree/adyen/hpps_controller.rb +2 -0
- data/app/controllers/spree/adyen_notifications_controller.rb +4 -5
- data/app/controllers/spree/adyen_redirect_controller.rb +17 -7
- data/app/models/adyen_notification.rb +8 -2
- data/app/models/spree/adyen/notification_processor.rb +34 -26
- data/db/migrate/20151123000000_recreate_adyen_notification_index.rb +5 -0
- data/lib/spree/adyen/form.rb +6 -1
- data/lib/spree/adyen/version.rb +1 -1
- data/solidus-adyen.gemspec +3 -6
- data/spec/cassettes/adyen_capture.yml +63 -0
- data/spec/controllers/spree/adyen_notifications_controller_spec.rb +11 -2
- data/spec/controllers/spree/adyen_redirect_controller_spec.rb +1 -1
- data/spec/factories/spree_gateway_adyen_hpp.rb +2 -1
- data/spec/lib/spree/adyen/form_spec.rb +16 -1
- data/spec/lib/tasks/requests/notification_processing_spec.rb +129 -0
- data/spec/models/spree/adyen/notification_processor_spec.rb +47 -33
- data/spec/spec_helper.rb +17 -2
- data/spec/support/controller_helpers.rb +12 -0
- metadata +28 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b981dfc62f2ab3ffa76996fe091a6ff639b86d32
|
4
|
+
data.tar.gz: 0372a49ad6ff5763af8c0748315838c7b8976321
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a2ec3751f1119a2d271fc03f8ace0a8364d6605ea9f68afe71caca65faca6e2d669b0fd2fb52bddb8d98c726b38a2b5ab6bb0d7f400fb1cc7b90032688f33dc
|
7
|
+
data.tar.gz: 5145598ee3116a7ac02bbdbb7c2eef673f655ec34e52869d0352f4ac0fda0ff0e28f066c0f539138d45397c75db07546912ea49ebc3aeeeee09e67120e8f6d73
|
data/.gitignore
CHANGED
@@ -4,10 +4,10 @@
|
|
4
4
|
capybara-*.html
|
5
5
|
.rspec
|
6
6
|
.rvmrc
|
7
|
-
/.bundle
|
8
|
-
/vendor/bundle
|
9
|
-
/log
|
10
|
-
/tmp
|
7
|
+
/.bundle/
|
8
|
+
/vendor/bundle/
|
9
|
+
/log/
|
10
|
+
/tmp/
|
11
11
|
/db/*.sqlite3
|
12
12
|
/public/system/*
|
13
13
|
/coverage/
|
@@ -22,5 +22,4 @@ Gemfile.lock
|
|
22
22
|
spec/dummy
|
23
23
|
config/credentials.yml
|
24
24
|
|
25
|
-
spec/cassettes
|
26
25
|
spec/examples.txt
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Solidus-Adyen
|
1
|
+
# Solidus-Adyen [](https://travis-ci.org/StemboltHQ/solidus-adyen)
|
2
2
|
Adds support for Adyen Hosted Payment Page payments to Solidus stores using the
|
3
3
|
[Adyen](https://github.com/wvanbergen/adyen/) gem.
|
4
4
|
|
@@ -14,7 +14,7 @@ notification is received from Adyen.
|
|
14
14
|
# Installation
|
15
15
|
Add this line to your application's Gemfile:
|
16
16
|
```ruby
|
17
|
-
gem 'solidus-adyen',
|
17
|
+
gem 'solidus-adyen', '~> 0.1'
|
18
18
|
```
|
19
19
|
|
20
20
|
Then run:
|
@@ -6,15 +6,14 @@ module Spree
|
|
6
6
|
|
7
7
|
def notify
|
8
8
|
notification = AdyenNotification.build(params)
|
9
|
-
|
10
|
-
if notification.duplicate?
|
11
|
-
accept and return
|
12
|
-
end
|
13
|
-
|
14
9
|
notification.save!
|
15
10
|
|
11
|
+
# prevent alteration to associated payment while we're handling the action
|
16
12
|
Spree::Adyen::NotificationProcessor.new(notification).process!
|
17
13
|
accept
|
14
|
+
rescue ActiveRecord::RecordNotUnique
|
15
|
+
# Notification is a duplicate, ignore it and return a success.
|
16
|
+
accept
|
18
17
|
end
|
19
18
|
|
20
19
|
protected
|
@@ -7,10 +7,17 @@ module Spree
|
|
7
7
|
|
8
8
|
# This is the entry point after an Adyen HPP payment is completed
|
9
9
|
def confirm
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
# Reload order as it might have changed since previously loading it
|
11
|
+
# from an auth notification coming in at the same time.
|
12
|
+
# This and the notification processing need to have a lock on the order
|
13
|
+
# as they both decide what to do based on whether or not the order is
|
14
|
+
# complete.
|
15
|
+
@order.with_lock do
|
16
|
+
if @order.complete?
|
17
|
+
confirm_order_already_completed
|
18
|
+
else
|
19
|
+
confirm_order_incomplete
|
20
|
+
end
|
14
21
|
end
|
15
22
|
end
|
16
23
|
|
@@ -52,6 +59,7 @@ module Spree
|
|
52
59
|
# so we need to make sure we complete the payment and order.
|
53
60
|
def confirm_order_already_completed
|
54
61
|
payment = @order.payments.find_by!(response_code: psp_reference)
|
62
|
+
|
55
63
|
payment.source.update(source_params)
|
56
64
|
|
57
65
|
redirect_to_order
|
@@ -78,9 +86,7 @@ module Spree
|
|
78
86
|
|
79
87
|
@payment_method = Spree::PaymentMethod.find(payment_method_id)
|
80
88
|
|
81
|
-
@order =
|
82
|
-
Spree::Order.
|
83
|
-
find_by!(guest_token: cookies.signed[:guest_token])
|
89
|
+
@order = Spree::Order.find_by!(number: order_number)
|
84
90
|
end
|
85
91
|
|
86
92
|
def source_params
|
@@ -95,6 +101,10 @@ module Spree
|
|
95
101
|
:merchantReturnData)
|
96
102
|
end
|
97
103
|
|
104
|
+
def order_number
|
105
|
+
params[:merchantReference]
|
106
|
+
end
|
107
|
+
|
98
108
|
def psp_reference
|
99
109
|
params[:pspReference]
|
100
110
|
end
|
@@ -16,7 +16,14 @@
|
|
16
16
|
# @invoice.set_paid!
|
17
17
|
# end
|
18
18
|
class AdyenNotification < ActiveRecord::Base
|
19
|
-
AUTO_CAPTURE_ONLY_METHODS = [
|
19
|
+
AUTO_CAPTURE_ONLY_METHODS = [
|
20
|
+
"ideal",
|
21
|
+
"c_cash",
|
22
|
+
"directEbanking",
|
23
|
+
"trustly",
|
24
|
+
"giropay",
|
25
|
+
"bcmc"
|
26
|
+
].freeze
|
20
27
|
|
21
28
|
AUTHORISATION = "AUTHORISATION".freeze
|
22
29
|
CANCELLATION = "CANCELLATION".freeze
|
@@ -53,7 +60,6 @@ class AdyenNotification < ActiveRecord::Base
|
|
53
60
|
|
54
61
|
validates_presence_of :event_code
|
55
62
|
validates_presence_of :psp_reference
|
56
|
-
validates_uniqueness_of :success, scope: [:psp_reference, :event_code]
|
57
63
|
|
58
64
|
# Logs an incoming notification into the database.
|
59
65
|
#
|
@@ -7,48 +7,47 @@ module Spree
|
|
7
7
|
# separate classes that are only aware of how to process specific kinds of
|
8
8
|
# notifications (auth, capture, refund, etc.).
|
9
9
|
class NotificationProcessor
|
10
|
-
attr_accessor :notification, :payment
|
10
|
+
attr_accessor :notification, :payment, :order
|
11
11
|
|
12
12
|
def initialize(notification, payment = nil)
|
13
13
|
self.notification = notification
|
14
|
+
self.order = notification.order
|
14
15
|
self.payment = payment ? payment : notification.payment
|
15
|
-
|
16
|
-
if self.payment.nil?
|
17
|
-
self.payment = create_missing_payment
|
18
|
-
end
|
19
16
|
end
|
20
17
|
|
21
18
|
# for the given payment, process all notifications that are currently
|
22
19
|
# unprocessed in the order that they were dispatched.
|
23
20
|
def self.process_outstanding!(payment)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
21
|
+
payment.
|
22
|
+
source.
|
23
|
+
notifications(true). # bypass caching
|
24
|
+
unprocessed.
|
25
|
+
as_dispatched.
|
26
|
+
map do |notification|
|
27
|
+
new(notification, payment).process!
|
28
|
+
end
|
34
29
|
end
|
35
30
|
|
36
31
|
# only process the notification if there is a matching payment there's a
|
37
32
|
# number of reasons why there may not be a matching payment such as test
|
38
33
|
# notifications, reports etc, we just log them and then accept
|
39
34
|
def process!
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
35
|
+
return notification if order.nil?
|
36
|
+
|
37
|
+
order.with_lock do
|
38
|
+
if should_create_payment?
|
39
|
+
self.payment = create_missing_payment
|
40
|
+
end
|
41
|
+
|
42
|
+
if !notification.success?
|
43
|
+
handle_failure
|
44
44
|
|
45
|
-
|
46
|
-
|
45
|
+
elsif notification.modification_event?
|
46
|
+
handle_modification_event
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
elsif notification.normal_event?
|
49
|
+
handle_normal_event
|
50
50
|
|
51
|
-
end
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
@@ -59,8 +58,9 @@ module Spree
|
|
59
58
|
|
60
59
|
def handle_failure
|
61
60
|
notification.processed!
|
62
|
-
# ignore failures if the payment was already completed
|
63
|
-
|
61
|
+
# ignore failures if the payment was already completed, or if it doesn't
|
62
|
+
# exist
|
63
|
+
return if payment.nil? || payment.completed?
|
64
64
|
# might have to do something else on modification events,
|
65
65
|
# namely refunds
|
66
66
|
payment.failure!
|
@@ -135,6 +135,14 @@ module Spree
|
|
135
135
|
order.complete
|
136
136
|
payment
|
137
137
|
end
|
138
|
+
|
139
|
+
def should_create_payment?
|
140
|
+
notification.authorisation? &&
|
141
|
+
notification.success? &&
|
142
|
+
notification.order.present? &&
|
143
|
+
payment.nil?
|
144
|
+
end
|
145
|
+
|
138
146
|
end
|
139
147
|
end
|
140
148
|
end
|
data/lib/spree/adyen/form.rb
CHANGED
@@ -11,6 +11,10 @@ module Spree
|
|
11
11
|
payment_methods(order, payment_method)
|
12
12
|
end
|
13
13
|
|
14
|
+
def pay_url order, payment_method
|
15
|
+
endpoint_url "pay", order, payment_method
|
16
|
+
end
|
17
|
+
|
14
18
|
def select_url order, payment_method
|
15
19
|
endpoint_url "select", order, payment_method
|
16
20
|
end
|
@@ -118,7 +122,8 @@ module Spree
|
|
118
122
|
{ currency_code: order.currency,
|
119
123
|
merchant_reference: order.number.to_s,
|
120
124
|
country_code: order.billing_address.country.iso,
|
121
|
-
payment_amount: (order.total * 100).to_int
|
125
|
+
payment_amount: (order.total * 100).to_int,
|
126
|
+
shopper_locale: I18n.locale.to_s.gsub("-", "_")
|
122
127
|
}
|
123
128
|
end
|
124
129
|
|
data/lib/spree/adyen/version.rb
CHANGED
data/solidus-adyen.gemspec
CHANGED
@@ -19,17 +19,13 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_runtime_dependency "adyen", "~> 1.4"
|
22
|
-
spec.add_runtime_dependency "solidus_core", "~> 1.0"
|
22
|
+
spec.add_runtime_dependency "solidus_core", "~> 1.0.0"
|
23
23
|
spec.add_runtime_dependency "bourbon"
|
24
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
25
|
spec.add_development_dependency "sass-rails", "~> 4.0.2"
|
30
26
|
spec.add_development_dependency "coffee-rails"
|
31
27
|
|
32
|
-
spec.add_development_dependency "
|
28
|
+
spec.add_development_dependency "pg"
|
33
29
|
|
34
30
|
spec.add_development_dependency "rspec-rails", "~> 3.3"
|
35
31
|
spec.add_development_dependency "rspec-activemodel-mocks"
|
@@ -48,4 +44,5 @@ Gem::Specification.new do |spec|
|
|
48
44
|
spec.add_development_dependency "capybara"
|
49
45
|
spec.add_development_dependency "poltergeist"
|
50
46
|
spec.add_development_dependency "launchy"
|
47
|
+
spec.add_development_dependency "database_cleaner"
|
51
48
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://username:password@pal-test.adyen.com/pal/servlet/soap/Payment
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: |-
|
9
|
+
<?xml version="1.0"?>
|
10
|
+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
11
|
+
<soap:Body>
|
12
|
+
<payment:capture xmlns:payment="http://payment.services.adyen.com" xmlns:recurring="http://recurring.services.adyen.com" xmlns:common="http://common.services.adyen.com">
|
13
|
+
<payment:modificationRequest>
|
14
|
+
<payment:merchantAccount>xxxxxxxxxxxxxxxxxxxxxxxxxx</payment:merchantAccount>
|
15
|
+
<payment:originalReference>7914483013255061</payment:originalReference>
|
16
|
+
<payment:modificationAmount>
|
17
|
+
<common:currency>EUR</common:currency>
|
18
|
+
<common:value>11000</common:value>
|
19
|
+
</payment:modificationAmount>
|
20
|
+
|
21
|
+
</payment:modificationRequest>
|
22
|
+
</payment:capture>
|
23
|
+
|
24
|
+
</soap:Body>
|
25
|
+
</soap:Envelope>
|
26
|
+
headers:
|
27
|
+
Accept:
|
28
|
+
- text/xml
|
29
|
+
Content-Type:
|
30
|
+
- text/xml; charset=utf-8
|
31
|
+
Soapaction:
|
32
|
+
- authorise
|
33
|
+
Accept-Encoding:
|
34
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
35
|
+
User-Agent:
|
36
|
+
- Ruby
|
37
|
+
response:
|
38
|
+
status:
|
39
|
+
code: 200
|
40
|
+
message: OK
|
41
|
+
headers:
|
42
|
+
Date:
|
43
|
+
- Mon, 23 Nov 2015 18:53:15 GMT
|
44
|
+
Server:
|
45
|
+
- Apache
|
46
|
+
Set-Cookie:
|
47
|
+
- JSESSIONID=60F4E60645ADD5B702F8DA2708CB7779.test4e; Path=/pal/; Secure; HttpOnly
|
48
|
+
Last-Modified:
|
49
|
+
- Mon, 23 Nov 2015 18:53:15 GMT
|
50
|
+
Transfer-Encoding:
|
51
|
+
- chunked
|
52
|
+
Content-Type:
|
53
|
+
- text/xml;charset=UTF-8
|
54
|
+
body:
|
55
|
+
encoding: UTF-8
|
56
|
+
string: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
|
57
|
+
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body><ns1:captureResponse
|
58
|
+
xmlns:ns1="http://payment.services.adyen.com"><ns1:captureResult><additionalData
|
59
|
+
xmlns="http://payment.services.adyen.com" xsi:nil="true" /><pspReference xmlns="http://payment.services.adyen.com">8614483047954094</pspReference><response
|
60
|
+
xmlns="http://payment.services.adyen.com">[capture-received]</response></ns1:captureResult></ns1:captureResponse></soap:Body></soap:Envelope>
|
61
|
+
http_version:
|
62
|
+
recorded_at: Mon, 23 Nov 2015 18:53:15 GMT
|
63
|
+
recorded_with: VCR 2.9.3
|
@@ -24,8 +24,17 @@ describe Spree::AdyenNotificationsController do
|
|
24
24
|
let!(:order) { create :completed_order_with_totals }
|
25
25
|
|
26
26
|
let!(:payment) do
|
27
|
-
create
|
28
|
-
|
27
|
+
create(
|
28
|
+
:hpp_payment,
|
29
|
+
response_code: reference,
|
30
|
+
payment_method: payment_method,
|
31
|
+
order: order,
|
32
|
+
source: create(
|
33
|
+
:hpp_source,
|
34
|
+
psp_reference: reference,
|
35
|
+
order: order
|
36
|
+
)
|
37
|
+
)
|
29
38
|
end
|
30
39
|
|
31
40
|
let!(:payment_method) { create :hpp_gateway }
|
@@ -3,6 +3,7 @@ FactoryGirl.define do
|
|
3
3
|
class: "Spree::Gateway::AdyenHPP" do
|
4
4
|
name "Adyen"
|
5
5
|
environment "test"
|
6
|
+
display_on "both"
|
6
7
|
preferences(
|
7
8
|
skin_code: "XXXXX",
|
8
9
|
shared_secret: "1234",
|
@@ -16,7 +17,7 @@ FactoryGirl.define do
|
|
16
17
|
preferred_api_password { ENV.fetch("ADYEN_API_PASSWORD") }
|
17
18
|
preferred_api_username { ENV.fetch("ADYEN_API_USERNAME") }
|
18
19
|
preferred_merchant_account { ENV.fetch("ADYEN_MERCHANT_ACCOUNT") }
|
19
|
-
preferred_shared_secret { ENV.fetch("
|
20
|
+
preferred_shared_secret { ENV.fetch("ADYEN_SHARED_SECRET") }
|
20
21
|
preferred_skin_code { ENV.fetch("ADYEN_SKIN_CODE") }
|
21
22
|
end
|
22
23
|
end
|
@@ -13,6 +13,7 @@ RSpec.describe Spree::Adyen::Form do
|
|
13
13
|
shared_secret: "1234567890",
|
14
14
|
days_to_ship: 3}
|
15
15
|
}
|
16
|
+
let(:locale) { I18n.locale.to_s.gsub("-", "_") }
|
16
17
|
|
17
18
|
describe "directory_url" do
|
18
19
|
let(:expected) do
|
@@ -27,7 +28,8 @@ RSpec.describe Spree::Adyen::Form do
|
|
27
28
|
shared_secret: payment_method.shared_secret,
|
28
29
|
country_code: order.billing_address.country.iso,
|
29
30
|
merchant_return_data: merchant_return_data,
|
30
|
-
payment_amount: 3998
|
31
|
+
payment_amount: 3998,
|
32
|
+
shopper_locale: locale
|
31
33
|
}
|
32
34
|
|
33
35
|
::Adyen::Form.redirect_url(redirect_params)
|
@@ -183,6 +185,19 @@ RSpec.describe Spree::Adyen::Form do
|
|
183
185
|
end
|
184
186
|
end
|
185
187
|
|
188
|
+
describe "pay_url" do
|
189
|
+
subject {
|
190
|
+
described_class.pay_url(order, payment_method)
|
191
|
+
}
|
192
|
+
|
193
|
+
it "calls endpoint url with the expected params" do
|
194
|
+
expect(described_class).
|
195
|
+
to receive(:endpoint_url).
|
196
|
+
with("pay", order, payment_method)
|
197
|
+
subject
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
186
201
|
describe "details_url_with_issuer" do
|
187
202
|
let(:issuer_id) { "1654" }
|
188
203
|
let(:brand_code) { "paypal" }
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe "Notification processing", type: :request do
|
4
|
+
before do
|
5
|
+
allow_any_instance_of(Spree::AdyenRedirectController).
|
6
|
+
to receive(:check_signature)
|
7
|
+
|
8
|
+
ENV["ADYEN_NOTIFY_USER"] = "spree_user"
|
9
|
+
ENV["ADYEN_NOTIFY_PASSWD"] = "1234"
|
10
|
+
|
11
|
+
order.contents.advance
|
12
|
+
expect(order.state).to eq "payment"
|
13
|
+
end
|
14
|
+
|
15
|
+
let!(:order) { create(:order_with_line_items, number: "R207199925") }
|
16
|
+
|
17
|
+
let!(:payment_method) do
|
18
|
+
create(
|
19
|
+
:hpp_gateway,
|
20
|
+
preferred_api_username: "username",
|
21
|
+
preferred_api_password: "password"
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:auth_params) do
|
26
|
+
{
|
27
|
+
"originalReference" => "",
|
28
|
+
"reason" => "21633:0002:8/2018",
|
29
|
+
"additionalData.hmacSignature" => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
30
|
+
"additionalData.authCode" => "21633",
|
31
|
+
"additionalData.expiryDate" => "8/2018",
|
32
|
+
"additionalData.cardHolderName" => "John Doe",
|
33
|
+
"additionalData.cardSummary" => "0002",
|
34
|
+
"merchantAccountCode" => "xxxxxxxxxxxxxxxxxxxxxxxxxx",
|
35
|
+
"eventCode" => "AUTHORISATION",
|
36
|
+
"operations" => "CANCEL,CAPTURE,REFUND",
|
37
|
+
"additionalData.cardBin" => "370000",
|
38
|
+
"success" => "true",
|
39
|
+
"paymentMethod" => "amex",
|
40
|
+
"currency" => "EUR",
|
41
|
+
"pspReference" => "7914483013255061",
|
42
|
+
"merchantReference" => "R207199925",
|
43
|
+
"value" => "2200",
|
44
|
+
"live" => "false",
|
45
|
+
"eventDate" => "2015-11-23T17:55:25.30Z"
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
let(:capture_params) do
|
50
|
+
{
|
51
|
+
"originalReference" => "7914483013255061",
|
52
|
+
"reason" => "",
|
53
|
+
"additionalData.hmacSignature" => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
54
|
+
"merchantAccountCode" => "xxxxxxxxxxxxxxxxxxxxxxxxxx",
|
55
|
+
"eventCode" => "CAPTURE",
|
56
|
+
"operations" => "",
|
57
|
+
"success" => "true",
|
58
|
+
"paymentMethod" => "amex",
|
59
|
+
"currency" => "EUR",
|
60
|
+
"pspReference" => "8614483013279252",
|
61
|
+
"merchantReference" => "R207199925",
|
62
|
+
"value" => "2200",
|
63
|
+
"live" => "false",
|
64
|
+
"eventDate" => "2015-11-23T17:55:27.00Z"
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
let(:checkout_params) do
|
69
|
+
{
|
70
|
+
"merchantReference" => "R207199925",
|
71
|
+
"skinCode" => "xxxxxxxx",
|
72
|
+
"shopperLocale" => "en",
|
73
|
+
"paymentMethod" => "amex",
|
74
|
+
"authResult" => "AUTHORISED",
|
75
|
+
"pspReference" => "7914483013255061",
|
76
|
+
"merchantReturnData" => "adKbcFeXxOVE76UJRDF88g|#{payment_method.id}",
|
77
|
+
"merchantSig" => "SBdhua18U+8xkPmK/a/8VprF230="
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
let(:headers) do
|
82
|
+
{
|
83
|
+
"HTTP_AUTHORIZATION" =>
|
84
|
+
ActionController::HttpAuthentication::Basic.
|
85
|
+
encode_credentials("spree_user", "1234")
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "full redirect, auth, capture flow", truncation: true do
|
90
|
+
it "creates a payment, completes order, captures payment" do
|
91
|
+
authorize_request = lambda do
|
92
|
+
post "/adyen/notify", auth_params, headers
|
93
|
+
expect(response).to have_http_status :ok
|
94
|
+
expect(response.body).to eq "[accepted]"
|
95
|
+
end
|
96
|
+
|
97
|
+
redirect_request = lambda do
|
98
|
+
get "/checkout/payment/adyen", checkout_params, headers
|
99
|
+
expect(response).to have_http_status :redirect
|
100
|
+
end
|
101
|
+
|
102
|
+
capture_request = lambda do
|
103
|
+
expect do
|
104
|
+
post "/adyen/notify", capture_params, headers
|
105
|
+
end.
|
106
|
+
to change { order.payments.last.reload.state }.
|
107
|
+
from("processing").
|
108
|
+
to("completed")
|
109
|
+
end
|
110
|
+
|
111
|
+
VCR.use_cassette "adyen capture" do
|
112
|
+
expect do
|
113
|
+
# these come in at the same time
|
114
|
+
[
|
115
|
+
Thread.new(&authorize_request),
|
116
|
+
Thread.new(&redirect_request)
|
117
|
+
].map(&:join)
|
118
|
+
# typically get a duplicate auth notification
|
119
|
+
authorize_request.call
|
120
|
+
end.
|
121
|
+
to change { order.payments.count }.by(1).
|
122
|
+
and change { order.reload.state}.to("complete").
|
123
|
+
and change { AdyenNotification.count }.by(1)
|
124
|
+
|
125
|
+
capture_request.call
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -3,6 +3,14 @@ require "spec_helper"
|
|
3
3
|
RSpec.describe Spree::Adyen::NotificationProcessor do
|
4
4
|
include_context "mock adyen api", success: true
|
5
5
|
|
6
|
+
let!(:order) do
|
7
|
+
# spree factories suck, it's not easy to get something to payment state
|
8
|
+
create(:order_with_line_items).tap do |order|
|
9
|
+
order.contents.advance
|
10
|
+
expect(order.state).to eq "payment"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
6
14
|
describe "#process" do
|
7
15
|
subject { described_class.new(notification).process! }
|
8
16
|
|
@@ -16,14 +24,6 @@ RSpec.describe Spree::Adyen::NotificationProcessor do
|
|
16
24
|
)
|
17
25
|
end
|
18
26
|
|
19
|
-
let!(:order) do
|
20
|
-
# spree factories suck, it's not easy to get something to payment state
|
21
|
-
create(:order_with_line_items).tap do |order|
|
22
|
-
order.contents.advance
|
23
|
-
expect(order.state).to eq "payment"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
27
|
let!(:hpp_gateway) do
|
28
28
|
create(:hpp_gateway)
|
29
29
|
end
|
@@ -116,31 +116,6 @@ RSpec.describe Spree::Adyen::NotificationProcessor do
|
|
116
116
|
pending "completes payment"
|
117
117
|
end
|
118
118
|
|
119
|
-
# this is for the situation where we can the notification before the
|
120
|
-
# redirect
|
121
|
-
context "and the payment doesn't exist yet" do
|
122
|
-
let!(:payment) { nil }
|
123
|
-
|
124
|
-
it "processes the notification" do
|
125
|
-
expect { subject }.
|
126
|
-
to change { notification.processed }.
|
127
|
-
to true
|
128
|
-
end
|
129
|
-
|
130
|
-
it "completes the order" do
|
131
|
-
subject
|
132
|
-
expect(order.reload).to have_attributes(
|
133
|
-
state: "complete"
|
134
|
-
)
|
135
|
-
end
|
136
|
-
|
137
|
-
it "creates a payment" do
|
138
|
-
expect { subject }.
|
139
|
-
to change { order.payments.count }.
|
140
|
-
to 1
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
119
|
context "and payment method was ideal" do
|
145
120
|
let(:event_type) { :ideal_auth }
|
146
121
|
include_examples "completes payment"
|
@@ -155,6 +130,43 @@ RSpec.describe Spree::Adyen::NotificationProcessor do
|
|
155
130
|
include_examples "does nothing"
|
156
131
|
end
|
157
132
|
end
|
133
|
+
|
134
|
+
# this is for the situation where we can the notification before the
|
135
|
+
# redirect
|
136
|
+
context "and the payment doesn't exist yet" do
|
137
|
+
let(:payment) { nil }
|
138
|
+
|
139
|
+
context "an it is not a successful auth notification" do
|
140
|
+
let(:notification) do
|
141
|
+
create(:notification, :auth, success: false, order: order)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "does not create a payment" do
|
145
|
+
expect { subject }.to_not change { order.payments.count }
|
146
|
+
end
|
147
|
+
|
148
|
+
it "does not complete the order" do
|
149
|
+
expect { subject }.to_not change { order.state }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context "and it is a successful auth notification" do
|
154
|
+
let(:notification) do
|
155
|
+
create(:notification, :auth, order: order)
|
156
|
+
end
|
157
|
+
|
158
|
+
it "creates a payment" do
|
159
|
+
expect { subject }.
|
160
|
+
to change { order.payments.count }.
|
161
|
+
to 1
|
162
|
+
end
|
163
|
+
|
164
|
+
it "completes the order" do
|
165
|
+
expect { subject }.
|
166
|
+
to change { order.state }.to "complete"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
158
170
|
end
|
159
171
|
|
160
172
|
context "when event is CAPTURE" do
|
@@ -178,6 +190,8 @@ RSpec.describe Spree::Adyen::NotificationProcessor do
|
|
178
190
|
end
|
179
191
|
|
180
192
|
context "when event is REFUND" do
|
193
|
+
before { create :refund_reason }
|
194
|
+
|
181
195
|
shared_examples "refund" do
|
182
196
|
let(:event_type) { :refund }
|
183
197
|
it "creates a refund" do
|
data/spec/spec_helper.rb
CHANGED
@@ -22,6 +22,7 @@ require "vcr"
|
|
22
22
|
require "ffaker"
|
23
23
|
require "shoulda/matchers"
|
24
24
|
require "pry"
|
25
|
+
require "database_cleaner"
|
25
26
|
|
26
27
|
require "spree/testing_support/factories"
|
27
28
|
require "spree/testing_support/controller_requests"
|
@@ -41,18 +42,32 @@ RSpec.configure do |config|
|
|
41
42
|
config.color = true
|
42
43
|
config.infer_spec_type_from_file_location!
|
43
44
|
config.mock_with :rspec
|
44
|
-
config.use_transactional_fixtures =
|
45
|
+
config.use_transactional_fixtures = false
|
45
46
|
config.example_status_persistence_file_path = "./spec/examples.txt"
|
46
47
|
|
48
|
+
config.include ControllerHelpers, type: :controller
|
49
|
+
config.include Devise::TestHelpers, type: :controller
|
47
50
|
config.include Spree::TestingSupport::ControllerRequests, type: :controller
|
48
51
|
config.include FactoryGirl::Syntax::Methods
|
52
|
+
config.include Spree::TestingSupport::ControllerRequests, type: :controller
|
49
53
|
config.include Spree::TestingSupport::UrlHelpers
|
50
54
|
|
51
|
-
config.
|
55
|
+
config.before(:suite) do
|
56
|
+
DatabaseCleaner.clean_with(:truncation)
|
57
|
+
end
|
58
|
+
|
59
|
+
config.around(:each) do |example|
|
60
|
+
DatabaseCleaner.strategy =
|
61
|
+
example.metadata[:truncation] ? :truncation : :transaction
|
62
|
+
DatabaseCleaner.start
|
63
|
+
example.run
|
64
|
+
DatabaseCleaner.clean
|
65
|
+
end
|
52
66
|
end
|
53
67
|
|
54
68
|
VCR.configure do |c|
|
55
69
|
# c.allow_http_connections_when_no_cassette = true
|
70
|
+
c.ignore_localhost = true
|
56
71
|
c.cassette_library_dir = "spec/cassettes"
|
57
72
|
c.hook_into :webmock
|
58
73
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module ControllerHelpers
|
2
|
+
def sign_in(user = double("user"))
|
3
|
+
if user.nil?
|
4
|
+
allow(request.env["warden"]).to receive(:authenticate!).
|
5
|
+
and_throw(:warden, scope: :user)
|
6
|
+
allow(controller).to receive(:current_user).and_return(nil)
|
7
|
+
else
|
8
|
+
allow(request.env["warden"]).to receive(:authenticate!).and_return(user)
|
9
|
+
allow(controller).to receive(:current_user).and_return(user)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solidus-adyen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dylan Kendal
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: adyen
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 1.0.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 1.0.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bourbon
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,48 +52,6 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: solidus
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '1.0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '1.0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: solidus_auth_devise
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '1.2'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '1.2'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: solidus_sample
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '1.0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '1.0'
|
97
55
|
- !ruby/object:Gem::Dependency
|
98
56
|
name: sass-rails
|
99
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,7 +81,7 @@ dependencies:
|
|
123
81
|
- !ruby/object:Gem::Version
|
124
82
|
version: '0'
|
125
83
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
84
|
+
name: pg
|
127
85
|
requirement: !ruby/object:Gem::Requirement
|
128
86
|
requirements:
|
129
87
|
- - ">="
|
@@ -332,6 +290,20 @@ dependencies:
|
|
332
290
|
- - ">="
|
333
291
|
- !ruby/object:Gem::Version
|
334
292
|
version: '0'
|
293
|
+
- !ruby/object:Gem::Dependency
|
294
|
+
name: database_cleaner
|
295
|
+
requirement: !ruby/object:Gem::Requirement
|
296
|
+
requirements:
|
297
|
+
- - ">="
|
298
|
+
- !ruby/object:Gem::Version
|
299
|
+
version: '0'
|
300
|
+
type: :development
|
301
|
+
prerelease: false
|
302
|
+
version_requirements: !ruby/object:Gem::Requirement
|
303
|
+
requirements:
|
304
|
+
- - ">="
|
305
|
+
- !ruby/object:Gem::Version
|
306
|
+
version: '0'
|
335
307
|
description: Adyen HPP payments for Solidus Stores
|
336
308
|
email:
|
337
309
|
- dylan@stembolt.com
|
@@ -344,6 +316,8 @@ files:
|
|
344
316
|
- ".gitignore"
|
345
317
|
- ".rubocop.yml"
|
346
318
|
- ".rubocop_todo.yml"
|
319
|
+
- ".travis.yml"
|
320
|
+
- CHANGELOG.md
|
347
321
|
- Gemfile
|
348
322
|
- LICENSE.txt
|
349
323
|
- README.md
|
@@ -390,6 +364,7 @@ files:
|
|
390
364
|
- db/migrate/20151007090519_add_days_to_ship_to_config.rb
|
391
365
|
- db/migrate/20151020230830_remove_indices_on_adyen_notifications.rb
|
392
366
|
- db/migrate/20151106093023_allow_merchant_reference_to_be_null_for_adyen_notification.rb
|
367
|
+
- db/migrate/20151123000000_recreate_adyen_notification_index.rb
|
393
368
|
- lib/solidus-adyen.rb
|
394
369
|
- lib/spree/adyen.rb
|
395
370
|
- lib/spree/adyen/engine.rb
|
@@ -398,6 +373,7 @@ files:
|
|
398
373
|
- lib/spree/adyen/url.rb
|
399
374
|
- lib/spree/adyen/version.rb
|
400
375
|
- solidus-adyen.gemspec
|
376
|
+
- spec/cassettes/adyen_capture.yml
|
401
377
|
- spec/controllers/concerns/spree/adyen/admin/refunds_controller_spec.rb
|
402
378
|
- spec/controllers/spree/adyen/hpps_controller_spec.rb
|
403
379
|
- spec/controllers/spree/adyen_notifications_controller_spec.rb
|
@@ -408,6 +384,7 @@ files:
|
|
408
384
|
- spec/factories/spree_gateway_adyen_hpp.rb
|
409
385
|
- spec/factories/spree_payment.rb
|
410
386
|
- spec/lib/spree/adyen/form_spec.rb
|
387
|
+
- spec/lib/tasks/requests/notification_processing_spec.rb
|
411
388
|
- spec/models/adyen_notification_spec.rb
|
412
389
|
- spec/models/concerns/spree/adyen/order_spec.rb
|
413
390
|
- spec/models/concerns/spree/adyen/payment_spec.rb
|
@@ -416,6 +393,7 @@ files:
|
|
416
393
|
- spec/models/spree/adyen/presenters/communication_spec.rb
|
417
394
|
- spec/models/spree/gateway/adyen_hpp_spec.rb
|
418
395
|
- spec/spec_helper.rb
|
396
|
+
- spec/support/controller_helpers.rb
|
419
397
|
- spec/support/shared_contexts/mock_adyen_api.rb
|
420
398
|
homepage: https://github.com/StemboltHQ/solidus-adyen
|
421
399
|
licenses:
|
@@ -442,6 +420,7 @@ signing_key:
|
|
442
420
|
specification_version: 4
|
443
421
|
summary: Adyen HPP payments for Solidus Stores
|
444
422
|
test_files:
|
423
|
+
- spec/cassettes/adyen_capture.yml
|
445
424
|
- spec/controllers/concerns/spree/adyen/admin/refunds_controller_spec.rb
|
446
425
|
- spec/controllers/spree/adyen/hpps_controller_spec.rb
|
447
426
|
- spec/controllers/spree/adyen_notifications_controller_spec.rb
|
@@ -452,6 +431,7 @@ test_files:
|
|
452
431
|
- spec/factories/spree_gateway_adyen_hpp.rb
|
453
432
|
- spec/factories/spree_payment.rb
|
454
433
|
- spec/lib/spree/adyen/form_spec.rb
|
434
|
+
- spec/lib/tasks/requests/notification_processing_spec.rb
|
455
435
|
- spec/models/adyen_notification_spec.rb
|
456
436
|
- spec/models/concerns/spree/adyen/order_spec.rb
|
457
437
|
- spec/models/concerns/spree/adyen/payment_spec.rb
|
@@ -460,4 +440,5 @@ test_files:
|
|
460
440
|
- spec/models/spree/adyen/presenters/communication_spec.rb
|
461
441
|
- spec/models/spree/gateway/adyen_hpp_spec.rb
|
462
442
|
- spec/spec_helper.rb
|
443
|
+
- spec/support/controller_helpers.rb
|
463
444
|
- spec/support/shared_contexts/mock_adyen_api.rb
|