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
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 781ea82badd4f553a0041c19c1e6e0dca9caf62b971550c55b4aa932b24e2d80
4
+ data.tar.gz: 7699c92bd15352c2a54183e35f03362062295ccd0c840d94b8aed1dba9eba77c
5
+ SHA512:
6
+ metadata.gz: 06c96a50bc88c4d0e766c87909e7c787710b571d6221c3feed4e7c06c4f4567890639b63730243012e9f42d442e6026d57b127b663dab0a63efbf6c44a607bf8
7
+ data.tar.gz: 332ee83a97dc3a3eb8b9bac31fecf930dd4ef3bc2051d7da8e4e4be4177251f3ba4b2cda6ae7030cd904a23ea7a106a764d4dff1bfdccc3481029119fd676230
@@ -0,0 +1,3 @@
1
+ .idea/*
2
+ .ruby-version
3
+
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pensio_api (0.2.3)
4
+ pensio_api (0.3.4)
5
5
  activesupport (>= 3.2)
6
6
  httparty (>= 0.12.0)
7
7
  multi_xml (>= 0.5.2)
@@ -9,65 +9,73 @@ PATH
9
9
  GEM
10
10
  remote: https://www.rubygems.org/
11
11
  specs:
12
- activesupport (4.0.4)
13
- i18n (~> 0.6, >= 0.6.9)
14
- minitest (~> 4.2)
15
- multi_json (~> 1.3)
16
- thread_safe (~> 0.1)
17
- tzinfo (~> 0.3.37)
18
- addressable (2.3.5)
19
- celluloid (0.15.2)
20
- timers (~> 1.1.0)
21
- coderay (1.1.0)
22
- crack (0.4.1)
23
- safe_yaml (~> 0.9.0)
24
- diff-lcs (1.2.5)
25
- ffi (1.9.3)
26
- formatador (0.2.4)
12
+ activesupport (5.2.4.4)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 0.7, < 2)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+ addressable (2.7.0)
18
+ public_suffix (>= 2.0.2, < 5.0)
19
+ celluloid (0.16.0)
20
+ timers (~> 4.0.0)
21
+ coderay (1.1.3)
22
+ concurrent-ruby (1.1.7)
23
+ crack (0.4.4)
24
+ diff-lcs (1.4.4)
25
+ ffi (1.13.1)
26
+ formatador (0.2.5)
27
27
  guard (2.2.5)
28
28
  formatador (>= 0.2.4)
29
29
  listen (~> 2.1)
30
30
  lumberjack (~> 1.0)
31
31
  pry (>= 0.9.12)
32
32
  thor (>= 0.18.1)
33
- guard-rspec (4.2.4)
33
+ guard-rspec (4.2.10)
34
34
  guard (~> 2.1)
35
35
  rspec (>= 2.14, < 4.0)
36
- httparty (0.13.0)
37
- json (~> 1.8)
36
+ hitimes (2.0.0)
37
+ httparty (0.18.1)
38
+ mime-types (~> 3.0)
38
39
  multi_xml (>= 0.5.2)
39
- i18n (0.6.9)
40
- json (1.8.1)
41
- listen (2.4.0)
42
- celluloid (>= 0.15.2)
40
+ i18n (1.8.5)
41
+ concurrent-ruby (~> 1.0)
42
+ listen (2.10.1)
43
+ celluloid (~> 0.16.0)
43
44
  rb-fsevent (>= 0.9.3)
44
45
  rb-inotify (>= 0.9)
45
- lumberjack (1.0.4)
46
- method_source (0.8.2)
47
- minitest (4.7.5)
48
- multi_json (1.9.2)
49
- multi_xml (0.5.5)
50
- pry (0.9.12.4)
51
- coderay (~> 1.0)
52
- method_source (~> 0.8)
53
- slop (~> 3.4)
54
- rb-fsevent (0.9.4)
55
- rb-inotify (0.9.3)
56
- ffi (>= 0.5.0)
57
- rspec (2.14.1)
58
- rspec-core (~> 2.14.0)
59
- rspec-expectations (~> 2.14.0)
60
- rspec-mocks (~> 2.14.0)
61
- rspec-core (2.14.7)
62
- rspec-expectations (2.14.4)
63
- diff-lcs (>= 1.1.3, < 2.0)
64
- rspec-mocks (2.14.4)
65
- safe_yaml (0.9.7)
66
- slop (3.4.7)
67
- thor (0.18.1)
68
- thread_safe (0.3.2)
69
- timers (1.1.0)
70
- tzinfo (0.3.39)
46
+ lumberjack (1.2.8)
47
+ method_source (1.0.0)
48
+ mime-types (3.3.1)
49
+ mime-types-data (~> 3.2015)
50
+ mime-types-data (3.2020.0512)
51
+ minitest (5.14.2)
52
+ multi_xml (0.6.0)
53
+ pry (0.13.1)
54
+ coderay (~> 1.1)
55
+ method_source (~> 1.0)
56
+ public_suffix (4.0.6)
57
+ rb-fsevent (0.10.4)
58
+ rb-inotify (0.10.1)
59
+ ffi (~> 1.0)
60
+ rspec (3.10.0)
61
+ rspec-core (~> 3.10.0)
62
+ rspec-expectations (~> 3.10.0)
63
+ rspec-mocks (~> 3.10.0)
64
+ rspec-core (3.10.0)
65
+ rspec-support (~> 3.10.0)
66
+ rspec-expectations (3.10.0)
67
+ diff-lcs (>= 1.2.0, < 2.0)
68
+ rspec-support (~> 3.10.0)
69
+ rspec-mocks (3.10.0)
70
+ diff-lcs (>= 1.2.0, < 2.0)
71
+ rspec-support (~> 3.10.0)
72
+ rspec-support (3.10.0)
73
+ thor (1.0.1)
74
+ thread_safe (0.3.6)
75
+ timers (4.0.4)
76
+ hitimes
77
+ tzinfo (1.2.7)
78
+ thread_safe (~> 0.1)
71
79
  webmock (1.16.1)
72
80
  addressable (>= 2.2.7)
73
81
  crack (>= 0.3.2)
@@ -81,3 +89,6 @@ DEPENDENCIES
81
89
  pensio_api!
82
90
  rspec (>= 2.14)
83
91
  webmock (~> 1.16.1)
92
+
93
+ BUNDLED WITH
94
+ 2.1.4
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # PensioAPI
2
- This gem covers most of the Merchant and eCommerce API functionality provided by Pensio (http://www.pensio.com).
2
+ This gem covers most of the Merchant and eCommerce API functionality provided by AltaPay, formerly Pensio (https://altapay.com).
3
+
4
+ Ruby 2.4.x or later is recommended.
3
5
 
4
6
  ## Getting Started
5
7
 
@@ -11,6 +13,10 @@ PensioAPI::Credentials.username = 'Your pensio username'
11
13
  PensioAPI::Credentials.password = 'Your pensio password'
12
14
  ```
13
15
 
16
+ This is sufficient in the simple case where you only have a single integration with Pensio, using a single set of credentials.
17
+
18
+ If you require support for multiple connections to Pensio's API, using different sets of credentials, you must define named 'credentials sets' - see below under [Multiple Credentials Sets](#multiple-credentials-sets).
19
+
14
20
  ## Transactions
15
21
 
16
22
  To query transactions in your Pensio gateway, use the method `PensioAPI::Transaction.find`. This takes a number of parameters as defined in the Pensio documentation. For example:
@@ -67,6 +73,38 @@ The library provides two generic error classes for requests.
67
73
 
68
74
  Additionally, a third error class `PensioAPI::NoCredentials` is raised if credentials have not been provided. See "Getting Started" for more details.
69
75
 
76
+ ## Multiple Credentials Sets
77
+
78
+ If you require multiple connections to Pensio's API using different credentials, you must set up named credentials sets. For example, if you need separate credentials for your membership payments and ticket sales, you can configure them as follows:
79
+
80
+ ```
81
+ PensioAPI::Credentials.for(:membership).base_uri = 'Your pensio gateway URI for memberships'
82
+ PensioAPI::Credentials.for(:membership).username = 'Your pensio username for memberships'
83
+ PensioAPI::Credentials.for(:membership).password = 'Your pensio password for memberships'
84
+ ```
85
+
86
+ ```
87
+ PensioAPI::Credentials.for(:tickets).base_uri = 'Your pensio gateway URI for tickets'
88
+ PensioAPI::Credentials.for(:tickets).username = 'Your pensio username for tickets'
89
+ PensioAPI::Credentials.for(:tickets).password = 'Your pensio password for tickets'
90
+ ```
91
+
92
+ In this case, you *must* also pass the credential set to each request, by including a 'credentials' key in the options hash. The value should be a String or Symbol with the credential set name (e.g. :tickets, 'tickets'), or the PensioAPI::Credentials instance itself (e.g. PensioAPI::Credentials.for(:tickets)). For example, these three examples are equivalent:
93
+
94
+ ```
95
+ PensioAPI::Transaction.find(credentials: :tickets, transaction_id: '123')
96
+ PensioAPI::Transaction.find(credentials: 'tickets', transaction_id: '123')
97
+ PensioAPI::Transaction.find(credentials: PensioAPI::Credentials.for(:tickets), transaction_id: '123')
98
+ ```
99
+
100
+ Typically if you have multiple credentials sets, the default credentials (i.e. PensioAPI::Credentials.base_uri etc) are ignored, and making any Pensio API requests without explicitly passing a 'credentials' argument will raise `PensioAPI::NoCredentials`. However, if you have an existing Pensio integration using the simple default credentials approach and now want to also use a named credentials set, you can tell the library to explicitly allow this, by setting:
101
+
102
+ ```
103
+ PensioAPI::Credentials.allow_defaults = true
104
+ ```
105
+
106
+ In this scenario, requests performed without an explicit credentials set will use the default set, and those with named credentials will use those. BE CAREFUL: If you accidentally omit the 'credentials' options key when making a request, it will use the default credentials set, which could lead to undesired behaviour. This is why, by default, if you have multiple credentials sets, the default set is disabled.
107
+
70
108
  ## TODO
71
109
 
72
110
  * Better documentation - more examples, RDoc docs
@@ -1,5 +1,7 @@
1
1
  require 'active_support/core_ext/string/inflections'
2
2
 
3
+ require 'pensio_api/version'
4
+
3
5
  require 'pensio_api/mixins/id'
4
6
  require 'pensio_api/mixins/has_transactions'
5
7
  require 'pensio_api/mixins/method_missing'
@@ -8,6 +10,7 @@ require 'pensio_api/mixins/timestamps'
8
10
 
9
11
  require 'pensio_api/billing_address'
10
12
  require 'pensio_api/callback'
13
+ require 'pensio_api/chargeback_event'
11
14
  require 'pensio_api/credentials'
12
15
  require 'pensio_api/ecommerce'
13
16
  require 'pensio_api/funding_list'
@@ -32,5 +35,6 @@ require 'pensio_api/responses/reservation'
32
35
  require 'pensio_api/responses/reservation_capture'
33
36
  require 'pensio_api/responses/reservation_release'
34
37
  require 'pensio_api/responses/subscription_charge'
38
+ require 'pensio_api/responses/chargeback_callback'
35
39
  require 'pensio_api/responses/success_callback'
36
40
  require 'pensio_api/responses/subscription_failure_callback'
@@ -3,16 +3,20 @@ module PensioAPI
3
3
  FakeRequest = Struct.new(:headers, :body)
4
4
 
5
5
  def self.parse_success(xml)
6
- parse(xml, true)
6
+ parse(xml, :success)
7
7
  end
8
8
 
9
9
  def self.parse_failure(xml)
10
- parse(xml, false)
10
+ parse(xml, :failure)
11
+ end
12
+
13
+ def self.parse_chargeback(xml)
14
+ parse(xml, :chargeback)
11
15
  end
12
16
 
13
17
  private
14
18
 
15
- def self.parse(xml, success)
19
+ def self.parse(xml, handler)
16
20
  params = MultiXml.parse(xml)
17
21
 
18
22
  request = FakeRequest.new(
@@ -20,11 +24,14 @@ module PensioAPI
20
24
  params['APIResponse']['Body']
21
25
  )
22
26
 
23
- if success
27
+ case handler
28
+ when :success
24
29
  PensioAPI::Responses::SuccessCallback.new(request)
25
- else
30
+ when :failure
26
31
  PensioAPI::Responses::SubscriptionFailureCallback.new(request)
32
+ when :chargeback
33
+ PensioAPI::Responses::ChargebackCallback.new(request)
27
34
  end
28
35
  end
29
36
  end
30
- end
37
+ end
@@ -0,0 +1,25 @@
1
+ module PensioAPI
2
+ class ChargebackEvent
3
+ attr_reader :type
4
+ attr_reader :reason_code
5
+ attr_reader :reason
6
+ attr_reader :amount
7
+ attr_reader :currency
8
+ attr_reader :acquirer_transaction_id
9
+
10
+ def initialize(chargeback_body)
11
+ @raw = chargeback_body
12
+
13
+ @type = @raw['Type']
14
+ @reason_code = @raw['ReasonCode'].to_i
15
+ @reason = @raw['Reason']
16
+ @amount = BigDecimal(@raw['Amount'])
17
+ @currency = @raw['Currency']
18
+ @acquirer_transaction_id = @raw['AcquirerTransactionId']
19
+ end
20
+
21
+ def created_at
22
+ @created_at ||= Time.parse(@raw['Date'])
23
+ end
24
+ end
25
+ end
@@ -1,7 +1,53 @@
1
1
  module PensioAPI
2
- module Credentials
2
+ class Credentials
3
3
  class << self
4
- attr_accessor :base_uri, :username, :password
4
+ attr_accessor :credentials_sets, :allow_defaults
5
+
6
+ # backwards compatability - set default credentials
7
+
8
+ def base_uri
9
+ default_credentials.base_uri
10
+ end
11
+
12
+ def base_uri=(value)
13
+ default_credentials.base_uri = value
14
+ end
15
+
16
+ def username
17
+ default_credentials.username
18
+ end
19
+
20
+ def username=(value)
21
+ default_credentials.username = value
22
+ end
23
+
24
+ def password
25
+ default_credentials.password
26
+ end
27
+
28
+ def password=(value)
29
+ default_credentials.password = value
30
+ end
31
+
32
+ def for(context)
33
+ self.credentials_sets ||= {}
34
+ self.credentials_sets[context.to_sym] ||= PensioAPI::Credentials.new
35
+ end
36
+
37
+ def default_credentials
38
+ self.for(:default)
39
+ end
40
+
41
+ def credentials_mode
42
+ self.for(:default)
43
+ self.credentials_sets.count == 1 ? :default : :multiple
44
+ end
5
45
  end
46
+
47
+ def supplied?
48
+ !!(base_uri && username && password)
49
+ end
50
+
51
+ attr_accessor :base_uri, :username, :password
6
52
  end
7
53
  end
@@ -20,11 +20,11 @@ module PensioAPI
20
20
  @acquirer = @raw['Acquirer']
21
21
  @funding_date = Date.parse(@raw['FundingDate'])
22
22
  @created_at = Date.parse(@raw['CreatedDate'])
23
- @download_link = @raw['DownloadLink']
23
+ @download_link = @raw['DownloadLink'].strip
24
24
  end
25
25
 
26
- def download
27
- @result ||= FundingListRequest.new(@download_link).result
26
+ def download(options={})
27
+ @result ||= FundingListRequest.new(@download_link, options).result
28
28
  end
29
29
  end
30
30
  end
@@ -9,7 +9,7 @@ module PensioAPI
9
9
  def initialize(path, options={})
10
10
  super(path, options)
11
11
 
12
- @result = CSV.parse(@response.parsed_response, col_sep: ';', headers: true).reject(&:empty?)
12
+ @result = CSV.parse(@response.body, col_sep: ';', headers: true).reject(&:empty?)
13
13
  end
14
14
  end
15
15
  end
@@ -4,23 +4,21 @@ module PensioAPI
4
4
  def self.included(base)
5
5
  base.send(:include, HTTParty)
6
6
  base.send(:attr_reader, :response)
7
- base.extend(ClassMethods)
8
- end
9
-
10
- module ClassMethods
11
- def set_base_uri
12
- self.base_uri PensioAPI::Credentials.base_uri unless self.base_uri
13
- end
7
+ base.send(:attr_accessor, :credentials)
14
8
  end
15
9
 
16
10
  HEADERS = {
17
- 'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'
11
+ 'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8',
12
+ 'x-altapay-client-version' => "RUBYSDK/#{PensioAPI::VERSION}"
18
13
  }
19
14
 
20
15
  def initialize(path, options={})
21
- self.class.set_base_uri
16
+ @credentials = options.delete(:credentials)
17
+ @credentials = PensioAPI::Credentials.for(@credentials.to_sym) unless @credentials.nil? || @credentials.is_a?(PensioAPI::Credentials)
18
+ @credentials ||= PensioAPI::Credentials.default_credentials if PensioAPI::Credentials.credentials_mode == :default || PensioAPI::Credentials.allow_defaults
19
+ raise Errors::NoCredentials unless @credentials && @credentials.supplied?
22
20
 
23
- raise Errors::NoCredentials unless credentials_supplied?
21
+ self.class.base_uri @credentials.base_uri unless self.class.base_uri
24
22
 
25
23
  @response = self.class.post(path, request_options(options))
26
24
  end
@@ -28,23 +26,23 @@ module PensioAPI
28
26
  private
29
27
 
30
28
  def request_options(options)
29
+ timeout = options.delete(:timeout)
31
30
  {
32
31
  basic_auth: auth,
33
32
  headers: (options.delete(:headers) || {}).merge(HEADERS),
34
33
  body: options
35
- }
34
+ }.tap do |request_options|
35
+ request_options[:timeout] = timeout if timeout
36
+ end
36
37
  end
37
38
 
38
39
  def auth
39
40
  {
40
- username: PensioAPI::Credentials.username,
41
- password: PensioAPI::Credentials.password
41
+ username: @credentials.username,
42
+ password: @credentials.password
42
43
  }
43
44
  end
44
45
 
45
- def credentials_supplied?
46
- Credentials.base_uri && Credentials.username && Credentials.password
47
- end
48
46
  end
49
47
  end
50
48
  end
@@ -12,7 +12,7 @@ module PensioAPI
12
12
  end
13
13
 
14
14
  def response_contains?(key)
15
- @body && @body.has_key?(key)
15
+ !!@body && @body.has_key?(key)
16
16
  end
17
17
  end
18
18
  end