pactas_itero 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +39 -0
- data/.hound.yml +14 -0
- data/.rubocop.yml +2 -0
- data/.ruby-style.yml +268 -0
- data/.travis.yml +13 -0
- data/CHANGELOG.md +46 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/Rakefile +16 -0
- data/lib/pactas_itero/api/contracts.rb +30 -0
- data/lib/pactas_itero/api/customers.rb +20 -0
- data/lib/pactas_itero/api/invoices.rb +25 -0
- data/lib/pactas_itero/api/oauth.rb +12 -0
- data/lib/pactas_itero/api/orders.rb +19 -0
- data/lib/pactas_itero/api/rated_items.rb +16 -0
- data/lib/pactas_itero/api.rb +18 -0
- data/lib/pactas_itero/client.rb +108 -0
- data/lib/pactas_itero/configurable.rb +59 -0
- data/lib/pactas_itero/default.rb +77 -0
- data/lib/pactas_itero/error.rb +217 -0
- data/lib/pactas_itero/ext/hash/camelize_keys.rb +32 -0
- data/lib/pactas_itero/response/raise_error.rb +21 -0
- data/lib/pactas_itero/version.rb +3 -0
- data/lib/pactas_itero.rb +31 -0
- data/pactas_itero.gemspec +32 -0
- data/spec/fixtures/bearer_token.json +5 -0
- data/spec/fixtures/commit_order_response.json +50 -0
- data/spec/fixtures/contract.json +46 -0
- data/spec/fixtures/contract_cancellation_preview_response.json +73 -0
- data/spec/fixtures/contracts.json +48 -0
- data/spec/fixtures/create_order_response.json +17 -0
- data/spec/fixtures/create_rated_item.json +8 -0
- data/spec/fixtures/customer.json +23 -0
- data/spec/fixtures/customers.json +40 -0
- data/spec/fixtures/invoice.json +22 -0
- data/spec/fixtures/invoices.json +46 -0
- data/spec/fixtures/order.json +15 -0
- data/spec/pactas_itero/api/contracts_spec.rb +118 -0
- data/spec/pactas_itero/api/customers_spec.rb +188 -0
- data/spec/pactas_itero/api/invoices_spec.rb +87 -0
- data/spec/pactas_itero/api/oauth_spec.rb +40 -0
- data/spec/pactas_itero/api/orders_spec.rb +102 -0
- data/spec/pactas_itero/api/rated_items_spec.rb +74 -0
- data/spec/pactas_itero/client_spec.rb +316 -0
- data/spec/pactas_itero_spec.rb +32 -0
- data/spec/spec_helper.rb +100 -0
- metadata +218 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'rash'
|
3
|
+
require 'pactas_itero/configurable'
|
4
|
+
require 'pactas_itero/api'
|
5
|
+
|
6
|
+
module PactasItero
|
7
|
+
class Client
|
8
|
+
include PactasItero::Configurable
|
9
|
+
include PactasItero::Api
|
10
|
+
|
11
|
+
attr_accessor :bearer_token
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
PactasItero::Configurable.keys.each do |key|
|
15
|
+
instance_variable_set(:"@#{key}", options[key] || PactasItero.instance_variable_get(:"@#{key}"))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def get(url, options = {})
|
20
|
+
request :get, url, options
|
21
|
+
end
|
22
|
+
|
23
|
+
def post(url, options = {})
|
24
|
+
request :post, url, options
|
25
|
+
end
|
26
|
+
|
27
|
+
def put(url, options = {})
|
28
|
+
request :put, url, options
|
29
|
+
end
|
30
|
+
|
31
|
+
def patch(url, options = {})
|
32
|
+
request :patch, url, options
|
33
|
+
end
|
34
|
+
|
35
|
+
def delete(url, options = {})
|
36
|
+
request :delete, url, options
|
37
|
+
end
|
38
|
+
|
39
|
+
def head(url, options = {})
|
40
|
+
request :head, url, options
|
41
|
+
end
|
42
|
+
|
43
|
+
def bearer_token?
|
44
|
+
!!bearer_token
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def connection
|
50
|
+
@connection ||= Faraday.new(api_endpoint, connection_options)
|
51
|
+
end
|
52
|
+
|
53
|
+
def request(method, path, params = {})
|
54
|
+
headers = params.delete(:headers) || {}
|
55
|
+
if accept = params.delete(:accept)
|
56
|
+
headers[:accept] = accept
|
57
|
+
end
|
58
|
+
|
59
|
+
bearer_token_request = params.delete(:bearer_token_request)
|
60
|
+
|
61
|
+
if bearer_token_request
|
62
|
+
headers[:accept] = '*/*'
|
63
|
+
headers[:authorization] = bearer_token_credentials_auth_header
|
64
|
+
headers[:content_type] = 'application/x-www-form-urlencoded; charset=UTF-8'
|
65
|
+
else
|
66
|
+
headers[:authorization] = auth_header
|
67
|
+
end
|
68
|
+
|
69
|
+
response = connection.send(method.to_sym, path, params) {
|
70
|
+
|request| request.headers.update(headers)
|
71
|
+
}.env
|
72
|
+
response.body
|
73
|
+
end
|
74
|
+
|
75
|
+
def connection_options
|
76
|
+
@connection_options ||= {
|
77
|
+
:builder => middleware,
|
78
|
+
:headers => {
|
79
|
+
:accept => default_media_type,
|
80
|
+
:user_agent => user_agent,
|
81
|
+
},
|
82
|
+
:request => {
|
83
|
+
:open_timeout => 10,
|
84
|
+
:timeout => 30,
|
85
|
+
},
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def bearer_token_credentials_auth_header
|
90
|
+
basic_auth_token = Base64.strict_encode64("#{@client_id}:#{@client_secret}")
|
91
|
+
"Basic #{basic_auth_token}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def bearer_auth_header
|
95
|
+
token = if bearer_token.respond_to?(:access_token)
|
96
|
+
bearer_token.access_token
|
97
|
+
else
|
98
|
+
bearer_token
|
99
|
+
end
|
100
|
+
"Bearer #{token}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def auth_header
|
104
|
+
@bearer_token = token unless bearer_token?
|
105
|
+
bearer_auth_header
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module PactasItero
|
2
|
+
|
3
|
+
module Configurable
|
4
|
+
attr_accessor :bearer_token, :client_id, :client_secret, :user_agent,
|
5
|
+
:default_media_type, :middleware, :production
|
6
|
+
attr_writer :api_endpoint
|
7
|
+
class << self
|
8
|
+
|
9
|
+
# List of configurable keys for PactasItero::Client
|
10
|
+
def keys
|
11
|
+
@keys ||= [
|
12
|
+
:bearer_token,
|
13
|
+
:api_endpoint,
|
14
|
+
:client_id,
|
15
|
+
:client_secret,
|
16
|
+
:user_agent,
|
17
|
+
:default_media_type,
|
18
|
+
:middleware,
|
19
|
+
:production
|
20
|
+
]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Set configuration options using a block
|
25
|
+
def configure
|
26
|
+
yield self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Reset configuration options to default values
|
30
|
+
def reset!
|
31
|
+
PactasItero::Configurable.keys.each do |key|
|
32
|
+
send(:"#{key}=", PactasItero::Default.options[key])
|
33
|
+
end
|
34
|
+
self
|
35
|
+
end
|
36
|
+
alias setup reset!
|
37
|
+
|
38
|
+
def api_endpoint
|
39
|
+
endpoint = @api_endpoint ||
|
40
|
+
production && production_api_endpoint ||
|
41
|
+
sandbox_api_endpoint
|
42
|
+
File.join(endpoint, "")
|
43
|
+
end
|
44
|
+
|
45
|
+
def sandbox_api_endpoint
|
46
|
+
PactasItero::Default.sandbox_api_endpoint
|
47
|
+
end
|
48
|
+
|
49
|
+
def production_api_endpoint
|
50
|
+
PactasItero::Default.production_api_endpoint
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def options
|
56
|
+
Hash[PactasItero::Configurable.keys.map{|key| [key, send(:"#{key}")]}]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'pactas_itero/response/raise_error'
|
2
|
+
require 'pactas_itero/version'
|
3
|
+
require 'faraday_middleware'
|
4
|
+
|
5
|
+
module PactasItero
|
6
|
+
|
7
|
+
# Default configuration options for {Client}
|
8
|
+
module Default
|
9
|
+
|
10
|
+
SANDBOX_API_ENDPOINT = "https://sandbox.billwerk.com".freeze
|
11
|
+
|
12
|
+
PRODUCTION_API_ENDPOINT = "https://itero.pactas.com".freeze
|
13
|
+
|
14
|
+
PRODUCTION = false
|
15
|
+
|
16
|
+
USER_AGENT = "Pactas.Itero Ruby Gem #{PactasItero::VERSION}".freeze
|
17
|
+
|
18
|
+
MEDIA_TYPE = "application/json"
|
19
|
+
|
20
|
+
MIDDLEWARE = Faraday::RackBuilder.new do |builder|
|
21
|
+
builder.request :json
|
22
|
+
builder.use PactasItero::Response::RaiseError
|
23
|
+
builder.response :rashify
|
24
|
+
builder.request :url_encoded
|
25
|
+
builder.response :json, :content_type => /\bjson$/
|
26
|
+
|
27
|
+
builder.adapter Faraday.default_adapter
|
28
|
+
end
|
29
|
+
|
30
|
+
class << self
|
31
|
+
|
32
|
+
def options
|
33
|
+
Hash[PactasItero::Configurable.keys.map{|key| [key, send(key)]}]
|
34
|
+
end
|
35
|
+
|
36
|
+
def api_endpoint
|
37
|
+
ENV['PACTAS_ITERO_ENDPOINT']
|
38
|
+
end
|
39
|
+
|
40
|
+
def sandbox_api_endpoint
|
41
|
+
SANDBOX_API_ENDPOINT
|
42
|
+
end
|
43
|
+
|
44
|
+
def production_api_endpoint
|
45
|
+
PRODUCTION_API_ENDPOINT
|
46
|
+
end
|
47
|
+
|
48
|
+
def production
|
49
|
+
PRODUCTION
|
50
|
+
end
|
51
|
+
|
52
|
+
def client_id
|
53
|
+
ENV['PACTAS_ITERO_CLIENT_ID']
|
54
|
+
end
|
55
|
+
|
56
|
+
def client_secret
|
57
|
+
ENV['PACTAS_ITERO_CLIENT_SECRET']
|
58
|
+
end
|
59
|
+
|
60
|
+
def bearer_token
|
61
|
+
ENV['PACTAS_ITERO_BEARER_TOKEN']
|
62
|
+
end
|
63
|
+
|
64
|
+
def default_media_type
|
65
|
+
ENV['PACTAS_ITERO_CLIENT_DEFAULT_MEDIA_TYPE'] || MEDIA_TYPE
|
66
|
+
end
|
67
|
+
|
68
|
+
def middleware
|
69
|
+
MIDDLEWARE
|
70
|
+
end
|
71
|
+
|
72
|
+
def user_agent
|
73
|
+
ENV['PACTAS_ITERO_USER_AGENT'] || USER_AGENT
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
module PactasItero
|
2
|
+
# Custom error class for rescuing from all Pactas errors
|
3
|
+
class Error < StandardError
|
4
|
+
|
5
|
+
# Returns the appropriate PactasItero::Error sublcass based
|
6
|
+
# on status and response message
|
7
|
+
#
|
8
|
+
# @param [Hash] response HTTP response
|
9
|
+
# @return [PactasItero::Error]
|
10
|
+
def self.from_response(response)
|
11
|
+
status = response[:status].to_i
|
12
|
+
body = response[:body].to_s
|
13
|
+
headers = response[:response_headers]
|
14
|
+
|
15
|
+
if klass = case status
|
16
|
+
when 400 then PactasItero::BadRequest
|
17
|
+
when 401 then error_for_401(headers)
|
18
|
+
when 403 then error_for_403(body)
|
19
|
+
when 404 then PactasItero::NotFound
|
20
|
+
when 406 then PactasItero::NotAcceptable
|
21
|
+
when 409 then PactasItero::Conflict
|
22
|
+
when 415 then PactasItero::UnsupportedMediaType
|
23
|
+
when 422 then PactasItero::UnprocessableEntity
|
24
|
+
when 400..499 then PactasItero::ClientError
|
25
|
+
when 500 then PactasItero::InternalServerError
|
26
|
+
when 501 then PactasItero::NotImplemented
|
27
|
+
when 502 then PactasItero::BadGateway
|
28
|
+
when 503 then PactasItero::ServiceUnavailable
|
29
|
+
when 500..599 then PactasItero::ServerError
|
30
|
+
end
|
31
|
+
klass.new(response)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(response=nil)
|
36
|
+
@response = response
|
37
|
+
super(build_error_message)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns most appropriate error for 401 HTTP status code
|
41
|
+
# @private
|
42
|
+
def self.error_for_401(headers)
|
43
|
+
if PactasItero::OneTimePasswordRequired.required_header(headers)
|
44
|
+
PactasItero::OneTimePasswordRequired
|
45
|
+
else
|
46
|
+
PactasItero::Unauthorized
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns most appropriate error for 403 HTTP status code
|
51
|
+
# @private
|
52
|
+
def self.error_for_403(body)
|
53
|
+
if body =~ /rate limit exceeded/i
|
54
|
+
PactasItero::TooManyRequests
|
55
|
+
elsif body =~ /login attempts exceeded/i
|
56
|
+
PactasItero::TooManyLoginAttempts
|
57
|
+
else
|
58
|
+
PactasItero::Forbidden
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Array of validation errors
|
63
|
+
# @return [Array<Hash>] Error info
|
64
|
+
def errors
|
65
|
+
if data && data.is_a?(Hash)
|
66
|
+
data[:errors] || []
|
67
|
+
else
|
68
|
+
[]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def data
|
75
|
+
@data ||=
|
76
|
+
if (body = @response[:body]) && !body.empty?
|
77
|
+
if body.is_a?(String) &&
|
78
|
+
@response[:response_headers] &&
|
79
|
+
@response[:response_headers][:content_type] =~ /json/
|
80
|
+
|
81
|
+
Sawyer::Agent.serializer.decode(body)
|
82
|
+
else
|
83
|
+
body
|
84
|
+
end
|
85
|
+
else
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def response_message
|
91
|
+
case data
|
92
|
+
when Hash
|
93
|
+
data[:Message]
|
94
|
+
when String
|
95
|
+
data
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def response_error
|
100
|
+
"Error: #{data[:error]}" if data.is_a?(Hash) && data[:error]
|
101
|
+
end
|
102
|
+
|
103
|
+
def response_error_summary
|
104
|
+
return nil unless data.is_a?(Hash) && !Array(data[:errors]).empty?
|
105
|
+
|
106
|
+
summary = "\nError summary:\n"
|
107
|
+
summary << data[:errors].map do |hash|
|
108
|
+
hash.map { |k,v| " #{k}: #{v}" }
|
109
|
+
end.join("\n")
|
110
|
+
|
111
|
+
summary
|
112
|
+
end
|
113
|
+
|
114
|
+
def build_error_message
|
115
|
+
return nil if @response.nil?
|
116
|
+
|
117
|
+
message = "#{@response[:method].to_s.upcase} "
|
118
|
+
message << redact_url(@response[:url].to_s) + ": "
|
119
|
+
message << "#{@response[:status]} - "
|
120
|
+
message << "#{response_message}" unless response_message.nil?
|
121
|
+
message << "#{response_error}" unless response_error.nil?
|
122
|
+
message << "#{response_error_summary}" unless response_error_summary.nil?
|
123
|
+
message
|
124
|
+
end
|
125
|
+
|
126
|
+
def redact_url(url_string)
|
127
|
+
%w[client_secret access_token].each do |token|
|
128
|
+
url_string.gsub!(/#{token}=\S+/, "#{token}=(redacted)") if url_string.include? token
|
129
|
+
end
|
130
|
+
url_string
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Raised on errors in the 400-499 range
|
135
|
+
class ClientError < Error; end
|
136
|
+
|
137
|
+
# Raised when Pactas returns a 400 HTTP status code
|
138
|
+
class BadRequest < ClientError; end
|
139
|
+
|
140
|
+
# Raised when Pactas returns a 401 HTTP status code
|
141
|
+
class Unauthorized < ClientError; end
|
142
|
+
|
143
|
+
# Raised when Pactas returns a 401 HTTP status code
|
144
|
+
# and headers include "X-Pactas-OTP"
|
145
|
+
class OneTimePasswordRequired < ClientError
|
146
|
+
#@private
|
147
|
+
OTP_DELIVERY_PATTERN = /required; (\w+)/i
|
148
|
+
|
149
|
+
#@private
|
150
|
+
def self.required_header(headers)
|
151
|
+
OTP_DELIVERY_PATTERN.match headers['X-Pactas-OTP'].to_s
|
152
|
+
end
|
153
|
+
|
154
|
+
# Delivery method for the user's OTP
|
155
|
+
#
|
156
|
+
# @return [String]
|
157
|
+
def password_delivery
|
158
|
+
@password_delivery ||= delivery_method_from_header
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
def delivery_method_from_header
|
164
|
+
if match = self.class.required_header(@response[:response_headers])
|
165
|
+
match[1]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Raised when Pactas returns a 403 HTTP status code
|
171
|
+
class Forbidden < ClientError; end
|
172
|
+
|
173
|
+
# Raised when Pactas returns a 403 HTTP status code
|
174
|
+
# and body matches 'rate limit exceeded'
|
175
|
+
class TooManyRequests < Forbidden; end
|
176
|
+
|
177
|
+
# Raised when Pactas returns a 403 HTTP status code
|
178
|
+
# and body matches 'login attempts exceeded'
|
179
|
+
class TooManyLoginAttempts < Forbidden; end
|
180
|
+
|
181
|
+
# Raised when Pactas returns a 404 HTTP status code
|
182
|
+
class NotFound < ClientError; end
|
183
|
+
|
184
|
+
# Raised when Pactas returns a 406 HTTP status code
|
185
|
+
class NotAcceptable < ClientError; end
|
186
|
+
|
187
|
+
# Raised when Pactas returns a 409 HTTP status code
|
188
|
+
class Conflict < ClientError; end
|
189
|
+
|
190
|
+
# Raised when Pactas returns a 414 HTTP status code
|
191
|
+
class UnsupportedMediaType < ClientError; end
|
192
|
+
|
193
|
+
# Raised when Pactas returns a 422 HTTP status code
|
194
|
+
class UnprocessableEntity < ClientError; end
|
195
|
+
|
196
|
+
# Raised on errors in the 500-599 range
|
197
|
+
class ServerError < Error; end
|
198
|
+
|
199
|
+
# Raised when Pactas returns a 500 HTTP status code
|
200
|
+
class InternalServerError < ServerError; end
|
201
|
+
|
202
|
+
# Raised when Pactas returns a 501 HTTP status code
|
203
|
+
class NotImplemented < ServerError; end
|
204
|
+
|
205
|
+
# Raised when Pactas returns a 502 HTTP status code
|
206
|
+
class BadGateway < ServerError; end
|
207
|
+
|
208
|
+
# Raised when Pactas returns a 503 HTTP status code
|
209
|
+
class ServiceUnavailable < ServerError; end
|
210
|
+
|
211
|
+
# Raised when client fails to provide valid Content-Type
|
212
|
+
class MissingContentType < ArgumentError; end
|
213
|
+
|
214
|
+
# Raised when a method requires an application client_id
|
215
|
+
# and secret but none is provided
|
216
|
+
class ApplicationCredentialsRequired < StandardError; end
|
217
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
def camelize_keys(value = self)
|
4
|
+
case value
|
5
|
+
when Array
|
6
|
+
value.map { |v| camelize_keys(v) }
|
7
|
+
when Hash
|
8
|
+
Hash[value.map { |k, v| [camelize_key(k), camelize_keys(v)] }]
|
9
|
+
else
|
10
|
+
value
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def camelize_key(key)
|
17
|
+
if key.is_a? Symbol
|
18
|
+
camelize(key.to_s).to_sym
|
19
|
+
elsif key.is_a? String
|
20
|
+
camelize(key)
|
21
|
+
else
|
22
|
+
key
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# copied from ActiveSupport
|
27
|
+
def camelize(term)
|
28
|
+
string = term.to_s
|
29
|
+
string = string.sub(/^[a-z\d]*/) { $&.capitalize }
|
30
|
+
string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub('/', '::')
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'pactas_itero/error'
|
3
|
+
|
4
|
+
module PactasItero
|
5
|
+
# Faraday response middleware
|
6
|
+
module Response
|
7
|
+
|
8
|
+
# This class raises an PactasItero-flavored exception based
|
9
|
+
# HTTP status codes returned by the API
|
10
|
+
class RaiseError < Faraday::Response::Middleware
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def on_complete(response)
|
15
|
+
if error = PactasItero::Error.from_response(response)
|
16
|
+
raise error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/pactas_itero.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'pactas_itero/client'
|
2
|
+
require 'pactas_itero/default'
|
3
|
+
|
4
|
+
module PactasItero
|
5
|
+
|
6
|
+
class << self
|
7
|
+
include PactasItero::Configurable
|
8
|
+
|
9
|
+
# API client based on configured options {Configurable}
|
10
|
+
#
|
11
|
+
# @return [PactasItero::Client] API wrapper
|
12
|
+
def client
|
13
|
+
@client = PactasItero::Client.new(options)
|
14
|
+
@client
|
15
|
+
end
|
16
|
+
|
17
|
+
# @private
|
18
|
+
def respond_to_missing?(method_name, include_private=false); client.respond_to?(method_name, include_private); end if RUBY_VERSION >= "1.9"
|
19
|
+
# @private
|
20
|
+
def respond_to?(method_name, include_private=false); client.respond_to?(method_name, include_private) || super; end if RUBY_VERSION < "1.9"
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def method_missing(method_name, *args, &block)
|
25
|
+
return super unless client.respond_to?(method_name)
|
26
|
+
client.send(method_name, *args, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
PactasItero.setup
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pactas_itero/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'pactas_itero'
|
8
|
+
spec.version = PactasItero::VERSION
|
9
|
+
spec.authors = ['Simon Fröhler']
|
10
|
+
spec.email = "simon@shipcloud.io"
|
11
|
+
spec.summary = %q{pactas_itero provides a client mapping for accessing
|
12
|
+
the Pactas Itero API.}
|
13
|
+
spec.description = %q{pactas_itero provides a client mapping for accessing
|
14
|
+
the Pactas Itero API, making it easy to post your data to, adn read your
|
15
|
+
data from your Pactas account.}
|
16
|
+
spec.homepage = 'https://github.com/webionate/pactas_itero'
|
17
|
+
spec.license = 'MIT'
|
18
|
+
|
19
|
+
spec.files = `git ls-files`.split("\n")
|
20
|
+
spec.test_files = `git ls-files -- spec/*`.split("\n")
|
21
|
+
spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
spec.require_paths = ['lib']
|
23
|
+
|
24
|
+
spec.add_dependency('faraday_middleware', '~> 0.9.1')
|
25
|
+
spec.add_dependency('rash', '~> 0.4.0')
|
26
|
+
|
27
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
spec.add_development_dependency "rspec", '~> 3.0'
|
30
|
+
spec.add_development_dependency("simplecov", "~> 0")
|
31
|
+
spec.add_development_dependency("webmock", "~> 1.18", ">= 1.18.0")
|
32
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
{
|
2
|
+
"Id": "5370e5ab9e40071fd01e01e0",
|
3
|
+
"LastBillingDate": "2014-05-22T13:33:30.9510000Z",
|
4
|
+
"NextBillingDate": "2014-06-22T13:33:30.9510000Z",
|
5
|
+
"PlanId": "525bf8eb9e40073a58590fd4",
|
6
|
+
"CustomerId": "5370e5ab9e40071fd01e01df",
|
7
|
+
"LifecycleStatus": "Active",
|
8
|
+
"CustomerName": "asd asd",
|
9
|
+
"Phases": [{
|
10
|
+
"Type": "Normal",
|
11
|
+
"StartDate": "2014-05-12T15:15:55.8410000Z",
|
12
|
+
"PlanVariantId": "5256be5c9e4007398ce610f0",
|
13
|
+
"PlanId": "5256be2a9e4007398ce610ef"
|
14
|
+
}, {
|
15
|
+
"Type": "Inactive",
|
16
|
+
"StartDate": "2014-05-13T22:00:00.0000000Z"
|
17
|
+
}, {
|
18
|
+
"Type": "Normal",
|
19
|
+
"StartDate": "2014-05-22T13:22:41.4510000Z",
|
20
|
+
"PlanVariantId": "5256be5c9e4007398ce610f0",
|
21
|
+
"PlanId": "5256be2a9e4007398ce610ef"
|
22
|
+
}, {
|
23
|
+
"Type": "Normal",
|
24
|
+
"StartDate": "2014-05-22T13:33:30.9510000Z",
|
25
|
+
"PlanVariantId": "525bf9089e40073a58590fd5",
|
26
|
+
"PlanId": "525bf8eb9e40073a58590fd4"
|
27
|
+
}],
|
28
|
+
"Balance": 0,
|
29
|
+
"Currency": "EUR",
|
30
|
+
"PlanGroupId": "5256be1b9e4007398ce610ee",
|
31
|
+
"PaymentBearer": {
|
32
|
+
"Code": "41212312",
|
33
|
+
"Holder": "asdasd asdad",
|
34
|
+
"Country": "de",
|
35
|
+
"Account": "*****3123",
|
36
|
+
"Type": "BankAccount"
|
37
|
+
},
|
38
|
+
"PaymentProvider": "Paymill",
|
39
|
+
"EscalationSuspended": false,
|
40
|
+
"RecurringPaymentsPaused": false,
|
41
|
+
"CurrentPhase": {
|
42
|
+
"Type": "Normal",
|
43
|
+
"StartDate": "2014-05-22T13:33:30.9510000Z",
|
44
|
+
"PlanVariantId": "525bf9089e40073a58590fd5",
|
45
|
+
"PlanId": "525bf8eb9e40073a58590fd4"
|
46
|
+
},
|
47
|
+
"StartDate": "2014-05-12T15:15:55.8410000Z",
|
48
|
+
"BilledUntil": "2014-06-22T13:33:30.9510000Z",
|
49
|
+
"PlanVariantId": "525bf9089e40073a58590fd5"
|
50
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
{
|
2
|
+
"Balance": 0,
|
3
|
+
"BilledUntil": "2014-05-23T13:12:47.0760000Z",
|
4
|
+
"Currency": "EUR",
|
5
|
+
"CurrentPhase": {
|
6
|
+
"PlanId": "53567a9e1d8dd00df056564d",
|
7
|
+
"PlanVariantId": "53567b431d8dd00df056564f",
|
8
|
+
"StartDate": "2014-04-23T13:12:47.0760000Z",
|
9
|
+
"Type": "Normal"
|
10
|
+
},
|
11
|
+
"CustomerId": "5357bc4f1d8dd00fa0db6c31",
|
12
|
+
"CustomerName": "Max Mustermann",
|
13
|
+
"EndDate": "2014-05-23T13:12:47.0760000Z",
|
14
|
+
"EscalationSuspended": false,
|
15
|
+
"Id": "5357bc4f1d8dd00fa0db6c32",
|
16
|
+
"LastBillingDate": "2014-04-23T13:12:47.0760000Z",
|
17
|
+
"LifecycleStatus": "Active",
|
18
|
+
"NextBillingDate": "2014-05-23T13:12:47.0760000Z",
|
19
|
+
"PaymentBearer": {
|
20
|
+
"CardType": "visa",
|
21
|
+
"Country": "DE",
|
22
|
+
"ExpiryMonth": 12,
|
23
|
+
"ExpiryYear": 2017,
|
24
|
+
"Holder": "Marcellus Wallace",
|
25
|
+
"Last4": "1111",
|
26
|
+
"Type": "CreditCard"
|
27
|
+
},
|
28
|
+
"PaymentProvider": "Paymill",
|
29
|
+
"Phases": [
|
30
|
+
{
|
31
|
+
"PlanId": "53567a9e1d8dd00df056564d",
|
32
|
+
"PlanVariantId": "53567b431d8dd00df056564f",
|
33
|
+
"StartDate": "2014-04-23T13:12:47.0760000Z",
|
34
|
+
"Type": "Normal"
|
35
|
+
},
|
36
|
+
{
|
37
|
+
"StartDate": "2014-05-23T13:12:47.0760000Z",
|
38
|
+
"Type": "Inactive"
|
39
|
+
}
|
40
|
+
],
|
41
|
+
"PlanGroupId": "53567a731d8dd00df056564a",
|
42
|
+
"PlanId": "53567a9e1d8dd00df056564d",
|
43
|
+
"PlanVariantId": "53567b431d8dd00df056564f",
|
44
|
+
"RecurringPaymentsPaused": false,
|
45
|
+
"StartDate": "2014-04-23T13:12:47.0760000Z"
|
46
|
+
}
|