pensio_api 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 +13 -5
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +83 -0
- data/Guardfile +23 -0
- data/LICENSE +24 -0
- data/README.md +77 -0
- data/lib/pensio_api/billing_address.rb +15 -0
- data/lib/pensio_api/callback.rb +30 -0
- data/lib/pensio_api/credentials.rb +7 -0
- data/lib/pensio_api/ecommerce.rb +13 -0
- data/lib/pensio_api/errors/bad_request.rb +15 -0
- data/lib/pensio_api/errors/gateway_error.rb +21 -0
- data/lib/pensio_api/errors/no_credentials.rb +9 -0
- data/lib/pensio_api/funding_list.rb +30 -0
- data/lib/pensio_api/funding_list_request.rb +15 -0
- data/lib/pensio_api/mixins/has_transactions.rb +36 -0
- data/lib/pensio_api/mixins/id.rb +9 -0
- data/lib/pensio_api/mixins/method_missing.rb +9 -0
- data/lib/pensio_api/mixins/request_defaults.rb +50 -0
- data/lib/pensio_api/mixins/timestamps.rb +13 -0
- data/lib/pensio_api/request.rb +18 -0
- data/lib/pensio_api/reservation.rb +28 -0
- data/lib/pensio_api/responses/base.rb +32 -0
- data/lib/pensio_api/responses/funding_list.rb +43 -0
- data/lib/pensio_api/responses/gateway_url.rb +13 -0
- data/lib/pensio_api/responses/refund.rb +17 -0
- data/lib/pensio_api/responses/reservation.rb +15 -0
- data/lib/pensio_api/responses/reservation_capture.rb +14 -0
- data/lib/pensio_api/responses/reservation_release.rb +6 -0
- data/lib/pensio_api/responses/subscription_charge.rb +21 -0
- data/lib/pensio_api/responses/subscription_failure_callback.rb +21 -0
- data/lib/pensio_api/responses/success_callback.rb +21 -0
- data/lib/pensio_api/responses/terminal.rb +41 -0
- data/lib/pensio_api/responses/transaction.rb +13 -0
- data/lib/pensio_api/subscription.rb +30 -0
- data/lib/pensio_api/terminal.rb +17 -0
- data/lib/pensio_api/transaction.rb +84 -0
- data/lib/pensio_api.rb +36 -0
- data/pensio_api.gemspec +20 -0
- data/spec/lib/pensio_api/billing_address_spec.rb +40 -0
- data/spec/lib/pensio_api/callback_spec.rb +21 -0
- data/spec/lib/pensio_api/ecommerce_spec.rb +22 -0
- data/spec/lib/pensio_api/errors/bad_request_spec.rb +31 -0
- data/spec/lib/pensio_api/errors/gateway_error_spec.rb +38 -0
- data/spec/lib/pensio_api/funding_list_request_spec.rb +17 -0
- data/spec/lib/pensio_api/funding_list_spec.rb +38 -0
- data/spec/lib/pensio_api/request_spec.rb +122 -0
- data/spec/lib/pensio_api/reservation_spec.rb +32 -0
- data/spec/lib/pensio_api/responses/base_spec.rb +68 -0
- data/spec/lib/pensio_api/responses/funding_list_spec.rb +23 -0
- data/spec/lib/pensio_api/responses/gateway_url_spec.rb +17 -0
- data/spec/lib/pensio_api/responses/refund_spec.rb +18 -0
- data/spec/lib/pensio_api/responses/reservation_capture_spec.rb +18 -0
- data/spec/lib/pensio_api/responses/reservation_release_spec.rb +12 -0
- data/spec/lib/pensio_api/responses/reservation_spec.rb +15 -0
- data/spec/lib/pensio_api/responses/subscription_charge_spec.rb +56 -0
- data/spec/lib/pensio_api/responses/subscription_failure_callback_spec.rb +48 -0
- data/spec/lib/pensio_api/responses/success_callback_spec.rb +45 -0
- data/spec/lib/pensio_api/responses/terminal_spec.rb +55 -0
- data/spec/lib/pensio_api/responses/transaction_spec.rb +56 -0
- data/spec/lib/pensio_api/subscription_spec.rb +37 -0
- data/spec/lib/pensio_api/terminal_spec.rb +18 -0
- data/spec/lib/pensio_api/transaction_spec.rb +101 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/fixtures/bad_request_error.xml +10 -0
- data/spec/support/fixtures/capture_reservation.xml +84 -0
- data/spec/support/fixtures/charge_subscription.xml +89 -0
- data/spec/support/fixtures/create_multi_payment_request.xml +13 -0
- data/spec/support/fixtures/create_payment_request.xml +13 -0
- data/spec/support/fixtures/failure_callback.xml +76 -0
- data/spec/support/fixtures/funding_download.csv +6 -0
- data/spec/support/fixtures/funding_list.xml +43 -0
- data/spec/support/fixtures/get_terminals.xml +38 -0
- data/spec/support/fixtures/get_terminals_none.xml +12 -0
- data/spec/support/fixtures/get_terminals_single.xml +28 -0
- data/spec/support/fixtures/multiple_payments.xml +146 -0
- data/spec/support/fixtures/payments.xml +80 -0
- data/spec/support/fixtures/payments_none.xml +13 -0
- data/spec/support/fixtures/pensio_error.xml +48 -0
- data/spec/support/fixtures/refund_captured_reservation.xml +88 -0
- data/spec/support/fixtures/release_reservation.xml +72 -0
- data/spec/support/fixtures/reservation_of_fixed_amount.xml +46 -0
- data/spec/support/fixtures/reserve_subscription_charge.xml +86 -0
- data/spec/support/fixtures/setup_subscription.xml +46 -0
- data/spec/support/fixtures/subscription_failure_callback.xml +132 -0
- data/spec/support/fixtures/success_callback.xml +119 -0
- data/spec/support/helpers.rb +38 -0
- metadata +150 -15
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MmJkMDI1NTg4NzNiYjk4NjQ1ZTFjMGY5YTAxOGMxM2Y1MTgwMWZkZg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NTEzODc3OWY4Yjc2YjA1NDk0ODQ1MGU2MzE3NTQ1OWI0MThmZTA0NQ==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
N2U3YjYwMjZjYWVlN2UyNTczYmNiZTZhMzE1N2JjYzgwMzAwMmYwZmNlOThh
|
10
|
+
NjM3YzdhOTMwZmVkYTBlMDFiODExNzEzYzNmMzgxMDNmZWU0OTc4MGU4NWI3
|
11
|
+
OTkwOWFkNjVkN2RjMzNhNDkyNjE2ZWM5ODdiYTgxNGEzMjJkYjk=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ODRiYzQzY2JmODhkYmFhMjE4ZTdhZjQzMWJhMzU2ZmRhMGRhNTMwMjgzMTc0
|
14
|
+
NTBlNWE0ZDVlNmE0NDIzNjdlNDE4ODQzMDAwZDBiNTMyNjkxOWNhMjAyMmM0
|
15
|
+
NjBlNzUwMjY0ZDdiMTk0NjhhZDc1NDQxMmRmZjAzZTJmMGE2YjE=
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
pensio_api (0.2.2)
|
5
|
+
activesupport (>= 3.2)
|
6
|
+
httparty (>= 0.12.0)
|
7
|
+
multi_xml (>= 0.5.2)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://www.rubygems.org/
|
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)
|
27
|
+
guard (2.2.5)
|
28
|
+
formatador (>= 0.2.4)
|
29
|
+
listen (~> 2.1)
|
30
|
+
lumberjack (~> 1.0)
|
31
|
+
pry (>= 0.9.12)
|
32
|
+
thor (>= 0.18.1)
|
33
|
+
guard-rspec (4.2.4)
|
34
|
+
guard (~> 2.1)
|
35
|
+
rspec (>= 2.14, < 4.0)
|
36
|
+
httparty (0.13.0)
|
37
|
+
json (~> 1.8)
|
38
|
+
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)
|
43
|
+
rb-fsevent (>= 0.9.3)
|
44
|
+
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)
|
71
|
+
webmock (1.16.1)
|
72
|
+
addressable (>= 2.2.7)
|
73
|
+
crack (>= 0.3.2)
|
74
|
+
|
75
|
+
PLATFORMS
|
76
|
+
ruby
|
77
|
+
|
78
|
+
DEPENDENCIES
|
79
|
+
guard (~> 2.2.5)
|
80
|
+
guard-rspec (~> 4.2.4)
|
81
|
+
pensio_api!
|
82
|
+
rspec (>= 2.14)
|
83
|
+
webmock (~> 1.16.1)
|
data/Guardfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard :rspec do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
watch('config/routes.rb') { "spec/routing" }
|
15
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
|
17
|
+
# Capybara features specs
|
18
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
19
|
+
|
20
|
+
# Turnip features and steps
|
21
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
22
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
23
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Copyright (c) 2014, ASMALLWORLD, AG
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
* Redistributions of source code must retain the above copyright
|
7
|
+
notice, this list of conditions and the following disclaimer.
|
8
|
+
* Redistributions in binary form must reproduce the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer in the
|
10
|
+
documentation and/or other materials provided with the distribution.
|
11
|
+
* Neither the name of ASMALLWORLD, AG nor the
|
12
|
+
names of its contributors may be used to endorse or promote products
|
13
|
+
derived from this software without specific prior written permission.
|
14
|
+
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
16
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
17
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL ASMALLWORLD, AG BE LIABLE FOR ANY
|
19
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
20
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
21
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
22
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
23
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
24
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# PensioAPI
|
2
|
+
This gem covers most of the Merchant and eCommerce API functionality provided by Pensio (http://www.pensio.com).
|
3
|
+
|
4
|
+
## Getting Started
|
5
|
+
|
6
|
+
First, register your Pensio credentials. For example, if you're using rails, create `config/initializers/pensio.rb` with the following contents:
|
7
|
+
|
8
|
+
```
|
9
|
+
PensioAPI::Credentials.base_uri = 'Your pensio gateway URI'
|
10
|
+
PensioAPI::Credentials.username = 'Your pensio username'
|
11
|
+
PensioAPI::Credentials.password = 'Your pensio password'
|
12
|
+
```
|
13
|
+
|
14
|
+
## Transactions
|
15
|
+
|
16
|
+
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:
|
17
|
+
|
18
|
+
```
|
19
|
+
PensioAPI::Transaction.find(transaction_id: '123')
|
20
|
+
```
|
21
|
+
|
22
|
+
This returns an enumerable `PensioAPI::Responses::Transaction` object as many `PensioAPI::Transaction` objects as match your criteria.
|
23
|
+
|
24
|
+
With a transaction object, you can perform several actions.
|
25
|
+
|
26
|
+
* Determine status via `.status`, `.captured?` and `.reserved`
|
27
|
+
* Refund via `.refund`
|
28
|
+
* Expose terminal details via `.terminal`
|
29
|
+
* Expose billing address via `.billing_address`
|
30
|
+
* Map to a subscription object via `.to_subscription`
|
31
|
+
* Map to a reservation object via `.to_reservation`
|
32
|
+
|
33
|
+
## Funding Lists
|
34
|
+
|
35
|
+
The funding list functionality of the Pensio Merchant API is exposed via `PensioAPI::FundingList.all` which returns an iterable collection of `PensioAPI::FundingList` objects. Calling `.download` on any of these objects downloads and parses the CSV file from the Pensio Gateway.
|
36
|
+
|
37
|
+
## Terminals
|
38
|
+
|
39
|
+
To query terminals, use the method `PensioAPI::Terminal.all`. This will return an enumerable object containing as many `PensioAPI::Terminals` as are associated with your gateway.
|
40
|
+
|
41
|
+
## Reservations
|
42
|
+
|
43
|
+
To create a fixed amount reservation (via the API call '/merchant/API/reservationOfFixedAmount') use the class method `PensioAPI::Reservation.of_fixed_amount`.
|
44
|
+
|
45
|
+
To capture an existing reservation, use `.capture`. Likewise to release it, use `.release`.
|
46
|
+
|
47
|
+
## Subscriptions
|
48
|
+
|
49
|
+
To create a subscription, use the class method `PensioAPI::Subscription.setup`. This takes the arguments documented in Pensio's documentation for the '/merchant/API/setupSubscription' API call.
|
50
|
+
|
51
|
+
With an existing subscription, use `.reserve_charge` to place a charge reservation upon the subscription or `.charge` to attempt a reservation and charge of the associated transaction.
|
52
|
+
|
53
|
+
## eCommerce
|
54
|
+
|
55
|
+
PensioAPI::Ecommerce is a module which exposes the eCommerce API endpoints. Two module methods `.create_payment_request` and `.create_multi_payment_request` can be used to generate payment URLs for a multitude of payment types. Consult the Pensio eCommerce API documentation for parameter details.
|
56
|
+
|
57
|
+
## Callbacks
|
58
|
+
|
59
|
+
`PensioAPI::Callback` provides two methods `.parse_success` and `.parse_failure`. These are designed to parse the callbacks Pensio send to your transaction success and transaction failure endpoints. Each returns a callback response which exposes the transaction details for processing by your app.
|
60
|
+
|
61
|
+
## Error Handling
|
62
|
+
|
63
|
+
The library provides two generic error classes for requests.
|
64
|
+
|
65
|
+
* `PensioAPI::Errors::BadRequest` is raised when the response from Pensio indicates that a request has invalid parameters
|
66
|
+
* `PensioAPI::Errors::GatewayError` is raised when the parameters have been provided correctly, but the gateway was unable to process the request
|
67
|
+
|
68
|
+
Additionally, a third error class `PensioAPI::NoCredentials` is raised if credentials have not been provided. See "Getting Started" for more details.
|
69
|
+
|
70
|
+
## TODO
|
71
|
+
|
72
|
+
* Better documentation - more examples, RDoc docs
|
73
|
+
* Further API implementation
|
74
|
+
|
75
|
+
## Contributing
|
76
|
+
|
77
|
+
Contributions are very welcome. Please submit pull requests with adequately-tested code.
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
class BillingAddress
|
3
|
+
attr_reader :first_name, :last_name, :street_address, :city, :region, :postal_code, :country
|
4
|
+
|
5
|
+
def initialize(address_params)
|
6
|
+
@first_name = address_params['Firstname']
|
7
|
+
@last_name = address_params['Lastname']
|
8
|
+
@street_address = address_params['Address']
|
9
|
+
@city = address_params['City']
|
10
|
+
@region = address_params['Region']
|
11
|
+
@postal_code = address_params['PostalCode']
|
12
|
+
@country = address_params['Country']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
module Callback
|
3
|
+
FakeRequest = Struct.new(:headers, :body)
|
4
|
+
|
5
|
+
def self.parse_success(xml)
|
6
|
+
parse(xml, true)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.parse_failure(xml)
|
10
|
+
parse(xml, false)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def self.parse(xml, success)
|
16
|
+
params = MultiXml.parse(xml)
|
17
|
+
|
18
|
+
request = FakeRequest.new(
|
19
|
+
params['APIResponse']['Header'],
|
20
|
+
params['APIResponse']['Body']
|
21
|
+
)
|
22
|
+
|
23
|
+
if success
|
24
|
+
PensioAPI::Responses::SuccessCallback.new(request)
|
25
|
+
else
|
26
|
+
PensioAPI::Responses::SubscriptionFailureCallback.new(request)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
module Ecommerce
|
3
|
+
def self.create_payment_request(options={})
|
4
|
+
request = Request.new('/merchant/API/createPaymentRequest', options)
|
5
|
+
Responses::GatewayURL.new(request)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.create_multi_payment_request(options={})
|
9
|
+
request = Request.new('/merchant/API/createMultiPaymentRequest', options)
|
10
|
+
Responses::GatewayURL.new(request)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
module Errors
|
3
|
+
class BadRequest < StandardError
|
4
|
+
attr_reader :request_time, :request_path, :error_code
|
5
|
+
|
6
|
+
def initialize(request)
|
7
|
+
super(request.headers['ErrorMessage'])
|
8
|
+
|
9
|
+
@request_time = Time.parse(request.headers['Date'])
|
10
|
+
@request_path = request.headers['Path']
|
11
|
+
@error_code = request.headers['ErrorCode'].to_i
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
module Errors
|
3
|
+
class GatewayError < StandardError
|
4
|
+
include Mixins::HasTransactions
|
5
|
+
attr_reader :request_time, :request_path, :cardholder_message
|
6
|
+
|
7
|
+
def initialize(request)
|
8
|
+
super(request.body['MerchantErrorMessage'])
|
9
|
+
|
10
|
+
@raw = request.body
|
11
|
+
|
12
|
+
@request_time = Time.parse(request.headers['Date'])
|
13
|
+
@request_path = request.headers['Path']
|
14
|
+
|
15
|
+
@cardholder_message = request.body['CardHolderErrorMessage']
|
16
|
+
|
17
|
+
map_transactions
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
class FundingList
|
3
|
+
attr_reader :filename
|
4
|
+
attr_reader :amount
|
5
|
+
attr_reader :acquirer
|
6
|
+
attr_reader :funding_date
|
7
|
+
attr_reader :created_at
|
8
|
+
attr_reader :download_link
|
9
|
+
|
10
|
+
def self.all(options={})
|
11
|
+
request = Request.new('/merchant/API/fundingList', options)
|
12
|
+
Responses::FundingList.new(request)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(funding_list_body)
|
16
|
+
@raw = funding_list_body
|
17
|
+
|
18
|
+
@filename = @raw['Filename']
|
19
|
+
@amount = @raw['Amount']
|
20
|
+
@acquirer = @raw['Acquirer']
|
21
|
+
@funding_date = Date.parse(@raw['FundingDate'])
|
22
|
+
@created_at = Date.parse(@raw['CreatedDate'])
|
23
|
+
@download_link = @raw['DownloadLink']
|
24
|
+
end
|
25
|
+
|
26
|
+
def download
|
27
|
+
@result ||= FundingListRequest.new(@download_link).result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module PensioAPI
|
4
|
+
class FundingListRequest
|
5
|
+
include Mixins::RequestDefaults
|
6
|
+
|
7
|
+
attr_reader :result
|
8
|
+
|
9
|
+
def initialize(path, options={})
|
10
|
+
super(path, options)
|
11
|
+
|
12
|
+
@result = CSV.parse(@response.parsed_response, col_sep: ';', headers: true).reject(&:empty?)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
module Mixins
|
3
|
+
module HasTransactions
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:include, Enumerable)
|
6
|
+
base.send(:attr_reader, :transactions)
|
7
|
+
end
|
8
|
+
|
9
|
+
def each
|
10
|
+
@transactions.each { |t| yield t }
|
11
|
+
end
|
12
|
+
|
13
|
+
def last
|
14
|
+
@transactions.last
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def map_transactions
|
20
|
+
@transactions = if raw_transactions.is_a?(Array)
|
21
|
+
raw_transactions.map { |t| PensioAPI::Transaction.new(t) }
|
22
|
+
else
|
23
|
+
[PensioAPI::Transaction.new(raw_transactions)]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def raw_transactions
|
28
|
+
@raw_transactions ||= if @raw['Transactions']
|
29
|
+
@raw['Transactions']['Transaction']
|
30
|
+
else
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
module Mixins
|
3
|
+
module RequestDefaults
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:include, HTTParty)
|
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
|
14
|
+
end
|
15
|
+
|
16
|
+
HEADERS = {
|
17
|
+
'Content-Type' => 'application/x-www-form-urlencoded'
|
18
|
+
}
|
19
|
+
|
20
|
+
def initialize(path, options={})
|
21
|
+
self.class.set_base_uri
|
22
|
+
|
23
|
+
raise Errors::NoCredentials unless credentials_supplied?
|
24
|
+
|
25
|
+
@response = self.class.post(path, request_options(options))
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def request_options(options)
|
31
|
+
{
|
32
|
+
basic_auth: auth,
|
33
|
+
headers: (options.delete(:headers) || {}).merge(HEADERS),
|
34
|
+
body: options
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def auth
|
39
|
+
{
|
40
|
+
username: PensioAPI::Credentials.username,
|
41
|
+
password: PensioAPI::Credentials.password
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def credentials_supplied?
|
46
|
+
Credentials.base_uri && Credentials.username && Credentials.password
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
class Request
|
3
|
+
include Mixins::RequestDefaults
|
4
|
+
|
5
|
+
attr_reader :headers, :body
|
6
|
+
|
7
|
+
def initialize(path, options={})
|
8
|
+
super(path, options)
|
9
|
+
|
10
|
+
@headers = @response.parsed_response['APIResponse']['Header']
|
11
|
+
@body = @response.parsed_response['APIResponse']['Body']
|
12
|
+
end
|
13
|
+
|
14
|
+
def response_contains?(key)
|
15
|
+
@body && @body.has_key?(key)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
class Reservation
|
3
|
+
def self.of_fixed_amount(options={})
|
4
|
+
request = Request.new('/merchant/API/reservationOfFixedAmount', options)
|
5
|
+
Responses::Reservation.new(request)
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(transaction)
|
9
|
+
@transaction = transaction
|
10
|
+
end
|
11
|
+
|
12
|
+
def capture(options={})
|
13
|
+
request = Request.new('/merchant/API/captureReservation', options.merge(reservation_options))
|
14
|
+
Responses::ReservationCapture.new(request)
|
15
|
+
end
|
16
|
+
|
17
|
+
def release(options={})
|
18
|
+
request = Request.new('/merchant/API/releaseReservation', options.merge(reservation_options))
|
19
|
+
Responses::ReservationRelease.new(request)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def reservation_options
|
25
|
+
{ transaction_id: @transaction.id }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
module Responses
|
3
|
+
class Base
|
4
|
+
include PensioAPI::Mixins::MethodMissing
|
5
|
+
|
6
|
+
attr_reader :raw
|
7
|
+
|
8
|
+
def initialize(request)
|
9
|
+
@raw = request.body
|
10
|
+
@headers = request.headers
|
11
|
+
unless success?
|
12
|
+
raise PensioAPI::Errors::BadRequest.new(request) unless header_ok
|
13
|
+
raise PensioAPI::Errors::GatewayError.new(request) unless body_ok
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def success?
|
18
|
+
header_ok && body_ok
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def header_ok
|
24
|
+
@headers['ErrorCode'].to_i == 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def body_ok
|
28
|
+
!@raw.has_key?('Result') || ['Success', 'OK', nil].include?(@raw['Result'])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module PensioAPI
|
2
|
+
module Responses
|
3
|
+
class FundingList < Base
|
4
|
+
attr_reader :funding_lists, :page_count
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize(request)
|
9
|
+
super(request)
|
10
|
+
|
11
|
+
map_funding_lists
|
12
|
+
|
13
|
+
@page_count = if @raw['Fundings']
|
14
|
+
(@raw['Fundings']['numberOfPages'] || 0).to_i
|
15
|
+
else
|
16
|
+
0
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def each
|
21
|
+
@funding_lists.each { |fl| yield fl }
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def map_funding_lists
|
27
|
+
@funding_lists = if raw_funding_lists.is_a?(Array)
|
28
|
+
raw_funding_lists.map { |fl| PensioAPI::FundingList.new(fl) }
|
29
|
+
else
|
30
|
+
[PensioAPI::FundingList.new(raw_funding_lists)]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def raw_funding_lists
|
35
|
+
@raw_funding_lists ||= if @raw['Fundings'] && raw['Fundings']['Funding']
|
36
|
+
@raw['Fundings']['Funding']
|
37
|
+
else
|
38
|
+
[]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|