solidus-adyen 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8d5a390a36ec18d1af12c1f0d506bbb43d2bb26a
4
- data.tar.gz: 7d2ddb172391f7a153bf8208bea04a63f8f3618c
3
+ metadata.gz: b981dfc62f2ab3ffa76996fe091a6ff639b86d32
4
+ data.tar.gz: 0372a49ad6ff5763af8c0748315838c7b8976321
5
5
  SHA512:
6
- metadata.gz: 4a40f1640428be6f878c1ed88cd3c1b560e8d0675ecf04e985f8eaa28524d14e6ac017e5c2ed72f9ad0999e07aa6742349d4c9761c8a42cc23c41127876948d5
7
- data.tar.gz: 4824b60671ed21f56d2a0e4d489aafb6154d4c896ddf4e4155fe6903e927190df990c7345b854c2188c3b9210158aacb921ed6f6afaf5b1ef0c8fb2446eaee63
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
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ env:
5
+ - DB=postgres
6
+ install:
7
+ - bundle install
8
+ script:
9
+ - bundle exec rake test_app
10
+ - bundle exec rspec
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # Changelog
2
+
3
+ ### Unreleased changes
data/Gemfile CHANGED
@@ -1,9 +1,12 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gemspec
3
+ gem "solidus", "~> 1.0.0"
4
+ gem "solidus_auth_devise", "~> 1.2.0"
4
5
 
5
6
  group :test do
6
7
  gem "timecop"
7
8
  gem "webmock"
8
9
  gem "vcr"
9
10
  end
11
+
12
+ gemspec
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Solidus-Adyen
1
+ # Solidus-Adyen [![Build Status](https://travis-ci.org/StemboltHQ/solidus-adyen.svg)](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', github: 'StemboltHQ/solidus-adyen', tag: 'v0.1.1'
17
+ gem 'solidus-adyen', '~> 0.1'
18
18
  ```
19
19
 
20
20
  Then run:
@@ -7,6 +7,8 @@ module Spree
7
7
  class: "Spree::PaymentMethod",
8
8
  id_param: :payment_method_id)
9
9
 
10
+ layout false
11
+
10
12
  def directory
11
13
  @brands = Adyen::Form.payment_methods_from_directory(
12
14
  @order,
@@ -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
- if @order.complete?
11
- confirm_order_already_completed
12
- else
13
- confirm_order_incomplete
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 = ["ideal", "c_cash", "directEbanking"].freeze
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
- Spree::Payment.transaction do
25
- payment.
26
- source.
27
- notifications(true). # bypass caching
28
- unprocessed.
29
- as_dispatched.
30
- map do |notification|
31
- new(notification, payment).process!
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
- Spree::Payment.transaction do
41
- if payment
42
- if !notification.success?
43
- handle_failure
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
- elsif notification.modification_event?
46
- handle_modification_event
45
+ elsif notification.modification_event?
46
+ handle_modification_event
47
47
 
48
- elsif notification.normal_event?
49
- handle_normal_event
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
- return if payment.completed?
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
@@ -0,0 +1,5 @@
1
+ class RecreateAdyenNotificationIndex < ActiveRecord::Migration
2
+ def change
3
+ add_index :adyen_notifications, [:psp_reference, :event_code, :success], unique: true, name: "adyen_notification_uniqueness"
4
+ end
5
+ end
@@ -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
 
@@ -1,5 +1,5 @@
1
1
  module Spree
2
2
  module Adyen
3
- VERSION = "0.2.1"
3
+ VERSION = "0.2.2"
4
4
  end
5
5
  end
@@ -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 "sqlite3"
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 :hpp_payment, response_code: reference,
28
- payment_method: payment_method, order: order
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 }
@@ -12,7 +12,7 @@ RSpec.describe Spree::AdyenRedirectController, type: :controller do
12
12
  )
13
13
  end
14
14
 
15
- let!(:store) { Spree::Store.default }
15
+ let!(:store) { create :store }
16
16
  let!(:gateway) { create :hpp_gateway }
17
17
 
18
18
  before do
@@ -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("ADYEN_SKIN_CODE") }
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 = true
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.filter_run_excluding :external => true
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.1
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-13 00:00:00.000000000 Z
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: '1.0'
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: '1.0'
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: sqlite3
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