pensio_api 0.2.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/Gemfile.lock +60 -49
  4. data/README.md +39 -1
  5. data/lib/pensio_api.rb +4 -0
  6. data/lib/pensio_api/callback.rb +13 -6
  7. data/lib/pensio_api/chargeback_event.rb +25 -0
  8. data/lib/pensio_api/credentials.rb +48 -2
  9. data/lib/pensio_api/funding_list.rb +3 -3
  10. data/lib/pensio_api/funding_list_request.rb +1 -1
  11. data/lib/pensio_api/mixins/request_defaults.rb +14 -16
  12. data/lib/pensio_api/request.rb +1 -1
  13. data/lib/pensio_api/responses/base.rb +9 -5
  14. data/lib/pensio_api/responses/chargeback_callback.rb +6 -0
  15. data/lib/pensio_api/responses/refund.rb +1 -1
  16. data/lib/pensio_api/responses/reservation.rb +11 -7
  17. data/lib/pensio_api/responses/reservation_capture.rb +6 -3
  18. data/lib/pensio_api/responses/reservation_release.rb +10 -1
  19. data/lib/pensio_api/transaction.rb +28 -4
  20. data/lib/pensio_api/version.rb +3 -0
  21. data/pensio_api.gemspec +5 -1
  22. data/spec/lib/pensio_api/callback_spec.rb +10 -2
  23. data/spec/lib/pensio_api/chargeback_event_spec.rb +37 -0
  24. data/spec/lib/pensio_api/ecommerce_spec.rb +13 -2
  25. data/spec/lib/pensio_api/errors/bad_request_spec.rb +1 -1
  26. data/spec/lib/pensio_api/errors/gateway_error_spec.rb +1 -1
  27. data/spec/lib/pensio_api/request_spec.rb +32 -15
  28. data/spec/lib/pensio_api/responses/base_spec.rb +2 -2
  29. data/spec/lib/pensio_api/responses/chargeback_callback_spec.rb +9 -0
  30. data/spec/lib/pensio_api/responses/funding_list_spec.rb +1 -1
  31. data/spec/lib/pensio_api/responses/refund_spec.rb +1 -1
  32. data/spec/lib/pensio_api/responses/reservation_capture_spec.rb +1 -1
  33. data/spec/lib/pensio_api/responses/reservation_spec.rb +2 -1
  34. data/spec/lib/pensio_api/responses/subscription_charge_spec.rb +1 -1
  35. data/spec/lib/pensio_api/responses/subscription_failure_callback_spec.rb +1 -1
  36. data/spec/lib/pensio_api/responses/success_callback_spec.rb +1 -1
  37. data/spec/lib/pensio_api/responses/terminal_spec.rb +1 -1
  38. data/spec/lib/pensio_api/responses/transaction_spec.rb +1 -1
  39. data/spec/lib/pensio_api/transaction_spec.rb +8 -4
  40. data/spec/spec_helper.rb +1 -1
  41. data/spec/support/fixtures/chargeback_callback.xml +92 -0
  42. data/spec/support/fixtures/reservation_of_fixed_amount.xml +136 -45
  43. metadata +37 -44
@@ -9,24 +9,28 @@ module PensioAPI
9
9
  @raw = request.body
10
10
  @headers = request.headers
11
11
  unless success?
12
- raise PensioAPI::Errors::BadRequest.new(request) unless header_ok
13
- raise PensioAPI::Errors::GatewayError.new(request) unless body_ok
12
+ raise PensioAPI::Errors::BadRequest.new(request) unless header_ok?
13
+ raise PensioAPI::Errors::GatewayError.new(request) unless body_ok? || chargeback?
14
14
  end
15
15
  end
16
16
 
17
17
  def success?
18
- header_ok && body_ok
18
+ header_ok? && (body_ok? || chargeback?)
19
19
  end
20
20
 
21
21
  private
22
22
 
23
- def header_ok
23
+ def header_ok?
24
24
  @headers['ErrorCode'].to_i == 0
25
25
  end
26
26
 
27
- def body_ok
27
+ def body_ok?
28
28
  !@raw.has_key?('Result') || ['Success', 'OK', nil].include?(@raw['Result'])
29
29
  end
30
+
31
+ def chargeback?
32
+ @raw['Result'] == 'ChargebackEvent'
33
+ end
30
34
  end
31
35
  end
32
36
  end
@@ -0,0 +1,6 @@
1
+ module PensioAPI
2
+ module Responses
3
+ class ChargebackCallback < Transaction
4
+ end
5
+ end
6
+ end
@@ -9,7 +9,7 @@ module PensioAPI
9
9
  @transaction = PensioAPI::Transaction.new(
10
10
  transactions['Transaction']
11
11
  )
12
- @refund_amount = BigDecimal.new(@raw['RefundedAmount'])
12
+ @refund_amount = BigDecimal(@raw['RefundedAmount'])
13
13
  @refund_currency = @raw['RefundCurrency'].to_i
14
14
  end
15
15
  end
@@ -1,15 +1,19 @@
1
1
  module PensioAPI
2
2
  module Responses
3
- class Reservation < Base
4
- attr_reader :transaction
3
+ class Reservation < Transaction
5
4
 
6
- def initialize(request)
7
- super(request)
5
+ def each
6
+ [reservation, charge].each { |t| yield t }
7
+ end
8
+
9
+ def reservation
10
+ @transactions.first
11
+ end
8
12
 
9
- @transaction = PensioAPI::Transaction.new(
10
- transactions['Transaction']
11
- )
13
+ def charge
14
+ @transactions.last
12
15
  end
16
+
13
17
  end
14
18
  end
15
19
  end
@@ -1,12 +1,15 @@
1
1
  module PensioAPI
2
2
  module Responses
3
- class ReservationCapture < Responses::Reservation
4
- attr_reader :capture_amount, :capture_currency
3
+ class ReservationCapture < Base
4
+ attr_reader :transaction, :capture_amount, :capture_currency
5
5
 
6
6
  def initialize(request)
7
7
  super(request)
8
8
 
9
- @capture_amount = BigDecimal.new(@raw['CaptureAmount'])
9
+ @transaction = PensioAPI::Transaction.new(
10
+ transactions['Transaction']
11
+ )
12
+ @capture_amount = BigDecimal(@raw['CaptureAmount'])
10
13
  @capture_currency = @raw['CaptureCurrency'].to_i
11
14
  end
12
15
  end
@@ -1,6 +1,15 @@
1
1
  module PensioAPI
2
2
  module Responses
3
- class ReservationRelease < Responses::Reservation
3
+ class ReservationRelease < Base
4
+ attr_reader :transaction
5
+
6
+ def initialize(request)
7
+ super(request)
8
+
9
+ @transaction = PensioAPI::Transaction.new(
10
+ transactions['Transaction']
11
+ )
12
+ end
4
13
  end
5
14
  end
6
15
  end
@@ -15,6 +15,8 @@ module PensioAPI
15
15
  attr_reader :order_id
16
16
  attr_reader :merchant_currency
17
17
  attr_reader :card_holder_currency
18
+ attr_reader :payment_source
19
+ attr_reader :chargeback_events
18
20
 
19
21
  # constants for transaction statuses
20
22
  STATUS_RECURRING_CONFIRMED = 'recurring_confirmed'
@@ -30,10 +32,10 @@ module PensioAPI
30
32
 
31
33
  @status = @raw['TransactionStatus']
32
34
 
33
- @captured_amount = BigDecimal.new(@raw['CapturedAmount'])
34
- @reserved_amount = BigDecimal.new(@raw['ReservedAmount'])
35
- @refunded_amount = BigDecimal.new(@raw['RefundedAmount'])
36
- @recurring_default_amount = BigDecimal.new(@raw['RecurringDefaultAmount'])
35
+ @captured_amount = BigDecimal(@raw['CapturedAmount'])
36
+ @reserved_amount = BigDecimal(@raw['ReservedAmount'])
37
+ @refunded_amount = BigDecimal(@raw['RefundedAmount'])
38
+ @recurring_default_amount = BigDecimal(@raw['RecurringDefaultAmount'])
37
39
 
38
40
  @card_status = @raw['CardStatus']
39
41
  @card_token = @raw['CreditCardToken']
@@ -43,6 +45,10 @@ module PensioAPI
43
45
 
44
46
  @merchant_currency = @raw['MerchantCurrency'].to_i
45
47
  @card_holder_currency = @raw['CardHolderCurrency'].to_i
48
+
49
+ @payment_source = @raw['PaymentSource']
50
+
51
+ map_chargeback_events
46
52
  end
47
53
 
48
54
  def self.find(options={})
@@ -80,5 +86,23 @@ module PensioAPI
80
86
  BillingAddress.new(@raw['CustomerInfo']['BillingAddress'])
81
87
  end
82
88
  end
89
+
90
+ private
91
+
92
+ def map_chargeback_events
93
+ @chargeback_events = if raw_chargeback_events.is_a?(Array)
94
+ raw_chargeback_events.map { |c| PensioAPI::ChargebackEvent.new(c) }
95
+ else
96
+ [PensioAPI::ChargebackEvent.new(raw_chargeback_events)]
97
+ end
98
+ end
99
+
100
+ def raw_chargeback_events
101
+ @raw_chargeback_events ||= if @raw['ChargebackEvents']
102
+ @raw['ChargebackEvents']['ChargebackEvent']
103
+ else
104
+ []
105
+ end
106
+ end
83
107
  end
84
108
  end
@@ -0,0 +1,3 @@
1
+ module PensioAPI
2
+ VERSION = '0.3.4'.freeze
3
+ end
@@ -1,6 +1,10 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'pensio_api/version'
4
+
1
5
  Gem::Specification.new do |s|
2
6
  s.name = 'pensio_api'
3
- s.version = '0.2.3'
7
+ s.version = PensioAPI::VERSION
4
8
  s.license = 'BSD-3-Clause'
5
9
  s.summary = "Provides integration for the Pensio Merchant API"
6
10
  s.authors = ['Michael Sell', 'Rory Sinclair']
@@ -6,7 +6,7 @@ describe PensioAPI::Callback do
6
6
  let(:response) { PensioAPI::Callback.parse_success(file_fixture("success_callback.xml")) }
7
7
  it "should return a SuccessCallback response" do
8
8
  expect(response).to be_an_instance_of(PensioAPI::Responses::SuccessCallback)
9
- expect(response.success?).to be_true
9
+ expect(response.success?).to be true
10
10
  end
11
11
  end
12
12
 
@@ -14,7 +14,15 @@ describe PensioAPI::Callback do
14
14
  let(:response) { PensioAPI::Callback.parse_failure(file_fixture("subscription_failure_callback.xml")) }
15
15
  it "should return a SubscriptionFailureCallback response" do
16
16
  expect(response).to be_an_instance_of(PensioAPI::Responses::SubscriptionFailureCallback)
17
- expect(response.success?).to be_true
17
+ expect(response.success?).to be true
18
+ end
19
+ end
20
+
21
+ describe ".parse_chargeback" do
22
+ let(:response) { PensioAPI::Callback.parse_chargeback(file_fixture("chargeback_callback.xml")) }
23
+ it "should return a ChargebackCallback response" do
24
+ expect(response).to be_an_instance_of(PensioAPI::Responses::ChargebackCallback)
25
+ expect(response.success?).to be true
18
26
  end
19
27
  end
20
28
  end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe PensioAPI::ChargebackEvent do
4
+ let(:response) { PensioAPI::Callback.parse_chargeback(file_fixture("chargeback_callback.xml")) }
5
+ let(:transaction) { response.transactions.last }
6
+ let(:chargeback_event) { transaction.chargeback_events.last }
7
+
8
+ describe 'reader attributes' do
9
+ describe 'type' do
10
+ specify { expect(chargeback_event.type).to be_an_instance_of(String) }
11
+ end
12
+
13
+ describe 'reason_code' do
14
+ specify { expect(chargeback_event.reason_code).to be_an_instance_of(Integer) }
15
+ end
16
+
17
+ describe 'reason' do
18
+ specify { expect(chargeback_event.reason).to be_an_instance_of(String) }
19
+ end
20
+
21
+ describe 'amount' do
22
+ specify { expect(chargeback_event.amount).to be_an_instance_of(BigDecimal) }
23
+ end
24
+
25
+ describe 'currency' do
26
+ specify { expect(chargeback_event.currency).to be_an_instance_of(String) }
27
+ end
28
+
29
+ describe 'acquirer_transaction_id' do
30
+ specify { expect(chargeback_event.acquirer_transaction_id).to be_an_instance_of(String) }
31
+ end
32
+ end
33
+
34
+ describe 'created_at' do
35
+ specify { expect(chargeback_event.created_at).to be_an_instance_of(Time) }
36
+ end
37
+ end
@@ -7,14 +7,25 @@ describe PensioAPI::Ecommerce do
7
7
  end
8
8
 
9
9
  describe '.create_payment_request' do
10
- let(:response) { PensioAPI::Ecommerce.create_payment_request(reservation_arguments) }
10
+ let(:response) {PensioAPI::Ecommerce.create_payment_request(reservation_arguments.merge({timeout: 10}))}
11
11
  it 'returns an instance of PensioAPI::Responses::GatewayURL' do
12
+ expect(PensioAPI::Request).to receive(:post).with("/merchant/API/createPaymentRequest",
13
+ {:basic_auth => {:username => "test_user", :password => "password"},
14
+ :headers => {
15
+ "Content-Type" => "application/x-www-form-urlencoded; charset=utf-8",
16
+ 'x-altapay-client-version' => "RUBYSDK/#{PensioAPI::VERSION}"
17
+ },
18
+ :body => {:terminal => "Pensio Test Terminal",
19
+ :shop_orderid => "Test Payment",
20
+ :amount => 123.45,
21
+ :currency => "eur"},
22
+ :timeout => 10}).and_call_original
12
23
  expect(response).to be_an_instance_of(PensioAPI::Responses::GatewayURL)
13
24
  end
14
25
  end
15
26
 
16
27
  describe '.create_multi_payment_request' do
17
- let(:response) { PensioAPI::Ecommerce.create_multi_payment_request(reservation_arguments) }
28
+ let(:response) {PensioAPI::Ecommerce.create_multi_payment_request(reservation_arguments)}
18
29
  it 'returns an instance of PensioAPI::Responses::GatewayURL' do
19
30
  expect(response).to be_an_instance_of(PensioAPI::Responses::GatewayURL)
20
31
  end
@@ -25,7 +25,7 @@ describe PensioAPI::Errors::BadRequest do
25
25
  end
26
26
 
27
27
  describe '.error_code' do
28
- specify { expect(error.error_code).to be_an_instance_of(Fixnum) }
28
+ specify { expect(error.error_code).to be_an_instance_of(Integer) }
29
29
  end
30
30
  end
31
31
  end
@@ -31,7 +31,7 @@ describe PensioAPI::Errors::GatewayError do
31
31
 
32
32
  describe 'object mapping' do
33
33
  it 'maps transactions to transaction objects' do
34
- expect(error.transactions.all? { |r| r.class == PensioAPI::Transaction }).to be_true
34
+ expect(error.transactions.all? { |r| r.class == PensioAPI::Transaction }).to be true
35
35
  end
36
36
  end
37
37
  end
@@ -3,12 +3,12 @@ require 'spec_helper'
3
3
  describe PensioAPI::Request do
4
4
  describe '.new' do
5
5
  before :each do
6
- PensioAPI::Request.stub(:post).and_return(construct_response(nil))
6
+ allow(PensioAPI::Request).to receive(:post).and_return(construct_response(nil))
7
7
  end
8
8
 
9
9
  it 'POSTs to the given API path and passes in request options' do
10
10
  request_options = PensioAPI::Request.new('/test').send(:request_options, {})
11
- PensioAPI::Request.should_receive(:post).with('/test', request_options)
11
+ expect(PensioAPI::Request).to receive(:post).with('/test', request_options)
12
12
  PensioAPI::Request.new('/test')
13
13
  end
14
14
  end
@@ -16,10 +16,10 @@ describe PensioAPI::Request do
16
16
  describe '.response_contains' do
17
17
  context 'with a populated response body' do
18
18
  before :each do
19
- PensioAPI::Request.stub(:post).and_return(
19
+ allow(PensioAPI::Request).to receive(:post).and_return(
20
20
  construct_response({
21
- 'Test' => 'true'
22
- })
21
+ 'Test' => 'true'
22
+ })
23
23
  )
24
24
  end
25
25
 
@@ -27,33 +27,33 @@ describe PensioAPI::Request do
27
27
 
28
28
  context 'given a valid key' do
29
29
  it 'returns true' do
30
- expect(request.response_contains?('Test')).to be_true
30
+ expect(request.response_contains?('Test')).to be true
31
31
  end
32
32
  end
33
33
 
34
34
  context 'given an invalid key' do
35
35
  it 'returns false' do
36
- expect(request.response_contains?('OtherTest')).to be_false
36
+ expect(request.response_contains?('OtherTest')).to be false
37
37
  end
38
38
  end
39
39
  end
40
40
 
41
41
  context 'with an empty response body' do
42
42
  before :each do
43
- PensioAPI::Request.stub(:post).and_return(construct_response(nil))
43
+ allow(PensioAPI::Request).to receive(:post).and_return(construct_response(nil))
44
44
  end
45
45
 
46
46
  let(:request) { PensioAPI::Request.new('/test') }
47
47
 
48
48
  it 'returns false' do
49
- expect(request.response_contains?('Test')).to be_false
49
+ expect(request.response_contains?('Test')).to be false
50
50
  end
51
51
  end
52
52
  end
53
53
 
54
54
  describe '.request_options' do
55
55
  before :each do
56
- PensioAPI::Request.stub(:post).and_return(construct_response(nil))
56
+ allow(PensioAPI::Request).to receive(:post).and_return(construct_response(nil))
57
57
  end
58
58
 
59
59
  let(:p) { PensioAPI::Request.new('/test') }
@@ -82,6 +82,27 @@ describe PensioAPI::Request do
82
82
  expect(p.send(:request_options, {transaction_id: 5432})[:body][:transaction_id]).to eq(5432)
83
83
  end
84
84
  end
85
+
86
+ context 'with alternative credentials' do
87
+ it 'sends the correct credentials' do
88
+ creds = PensioAPI::Credentials.for(:ticketing)
89
+ creds.base_uri = 'https://www.test.com'
90
+ creds.username = 'ticketing_username'
91
+ creds.password = 'ticketing_password'
92
+
93
+ # pass credentials instance
94
+ req1 = PensioAPI::Request.new('/test', credentials: creds)
95
+
96
+ # or pass credentials set name
97
+ req2 = PensioAPI::Request.new('/test', credentials: :ticketing)
98
+
99
+ expect(req1.send(:request_options, {})[:basic_auth]).to_not be_nil
100
+ expect(req1.send(:request_options, {})[:basic_auth]).to eq({ username: creds.username, password: creds.password})
101
+
102
+ expect(req2.send(:request_options, {})[:basic_auth]).to_not be_nil
103
+ expect(req2.send(:request_options, {})[:basic_auth]).to eq({ username: creds.username, password: creds.password})
104
+ end
105
+ end
85
106
  end
86
107
 
87
108
  describe 'error handling' do
@@ -107,11 +128,7 @@ describe PensioAPI::Request do
107
128
 
108
129
  context 'with incomplete credentials' do
109
130
  before :each do
110
- PensioAPI::Credentials = OpenStruct.new({
111
- base_uri: nil,
112
- username: nil,
113
- password: nil
114
- })
131
+ PensioAPI::Credentials.base_uri = nil
115
132
  end
116
133
 
117
134
  it 'raises a PensioAPI::Errors::NoCredentials error' do
@@ -40,7 +40,7 @@ describe PensioAPI::Responses::Base do
40
40
  context 'with a successful response' do
41
41
  context 'with success specified in the response body' do
42
42
  it 'returns true' do
43
- expect(response_object.success?).to be_true
43
+ expect(response_object.success?).to be true
44
44
  end
45
45
  end
46
46
 
@@ -60,7 +60,7 @@ describe PensioAPI::Responses::Base do
60
60
  let(:response_object) { PensioAPI::Responses::Base.new(test_data) }
61
61
 
62
62
  it 'returns true' do
63
- expect(response_object.success?).to be_true
63
+ expect(response_object.success?).to be true
64
64
  end
65
65
  end
66
66
  end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe PensioAPI::Responses::ChargebackCallback do
4
+ let(:response) { PensioAPI::Callback.parse_chargeback(file_fixture("chargeback_callback.xml")) }
5
+
6
+ it "succeeds" do
7
+ expect(response.success?).to be true
8
+ end
9
+ end
@@ -16,7 +16,7 @@ describe PensioAPI::Responses::FundingList do
16
16
 
17
17
  describe '.page_count' do
18
18
  it 'returns a number of pages' do
19
- expect(funding_list.page_count).to be_an_instance_of(Fixnum)
19
+ expect(funding_list.page_count).to be_an_instance_of(Integer)
20
20
  end
21
21
  end
22
22
  end