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 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