pactas_itero 0.2.0
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.
- 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
|
+
}
|