pensio_api 0.2.3 → 0.3.4

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