zuora_api 1.6.255 → 1.7.00
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitlab-ci.yml +16 -3
- data/CHANGELOG.md +57 -0
- data/lib/zuora_api/exceptions.rb +30 -14
- data/lib/zuora_api/login.rb +145 -111
- data/lib/zuora_api/logins/basic.rb +19 -17
- data/lib/zuora_api/logins/oauth.rb +18 -12
- data/lib/zuora_api/version.rb +1 -1
- data/zuora_api.gemspec +1 -1
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ecec87283f238f546be12e3fadb16e9fabbee7aec1129d47401876359271f868
|
4
|
+
data.tar.gz: 98d980959dcf672fad54bdc87fa89061f6aee4627eebb4ef89da8573c204419b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f18782b6e2bc5d2433c4f0b632fe931205392db8b334edf524accec0e17821394a064f82cb45983d0a0ae7cbbc106b8ae8911b90c35651445e139bf94d261d7
|
7
|
+
data.tar.gz: 56555f10ce5434a30a54d4cad556170987a033f1cbfef34dc0b246fd935878ae4e7bd989e4c7ba7f3f95a73d291c25983d39260b41a8c91a1dcb9a019e879eab
|
data/.gitlab-ci.yml
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
image: ruby:2.3.1
|
1
|
+
image: ruby:2.6
|
3
2
|
stages:
|
4
3
|
- setup
|
5
4
|
- test
|
@@ -41,10 +40,24 @@ rubygems-deploy:
|
|
41
40
|
stage: deploy
|
42
41
|
allow_failure: false
|
43
42
|
script:
|
43
|
+
- echo "deb http://ftp.us.debian.org/debian testing main contrib non-free" >> /etc/apt/sources.list
|
44
|
+
- apt-get update
|
45
|
+
- apt-get install -y git
|
46
|
+
- apt-get clean all
|
47
|
+
- gem install dpl
|
48
|
+
- if [[ "staging" == $CI_BUILD_REF_SLUG ]];then export VERSION=`git describe --match "[0-9]*\.[0-9]*\.[0-9]*[a-z]" --abbrev=0 --tags HEAD`; fi
|
49
|
+
- if [[ "master" == $CI_BUILD_REF_SLUG ]];then export VERSION=`git describe --exclude "[0-9]*\.[0-9]*\.[0-9]*[a-z]" --abbrev=0 --tags HEAD`; fi
|
50
|
+
- echo $VERSION
|
51
|
+
- sed -i "s/0.0.1/$VERSION/" /Connect/zuora-gem/lib/zuora_api/version.rb
|
52
|
+
- git add /Connect/zuora-gem/lib/zuora_api/version.rb
|
53
|
+
- git config --global user.email "connect@zuora.com"
|
54
|
+
- git config --global user.name "Connect Automation"
|
55
|
+
- git commit -m "Automated Version Update $VERSION"
|
44
56
|
- bundle install
|
45
57
|
- gem install rake
|
46
58
|
- version=$(rake install | grep -o 'pkg/zuora_api-.*gem')
|
47
59
|
- curl -u $USERNAME:$PASSWORD https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
|
48
60
|
- gem push $version
|
49
61
|
only:
|
50
|
-
|
62
|
+
- master
|
63
|
+
- staging
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,63 @@
|
|
1
1
|
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## [1.7.00] - 2018-8-05
|
5
|
+
### Changed
|
6
|
+
- Raise proper exception when oauth client is from deactivated user.
|
7
|
+
- Support for rails < 6
|
8
|
+
|
9
|
+
## [1.6.53] - 2018-7-29
|
10
|
+
### Changed
|
11
|
+
- Don't attempt zsession login if bearer token is bad
|
12
|
+
|
13
|
+
## [1.6.51 - 1.6.51] - 2018-7-22
|
14
|
+
### Changed
|
15
|
+
- Retry on address not available.
|
16
|
+
|
17
|
+
## [1.6.47 - 1.6.48] - 2018-6-26
|
18
|
+
### Changed
|
19
|
+
- Changed error raise statements when incorrect credentials are supplied to Basic/Oauth Logins
|
20
|
+
|
21
|
+
## [1.6.45] - 2018-5-30
|
22
|
+
### Changed
|
23
|
+
- Fix retry so headers are reinstaniated on session failure.
|
24
|
+
|
25
|
+
## [1.6.41] - 2018-5-30
|
26
|
+
### Changed
|
27
|
+
- Retry added on SSL connection failure
|
28
|
+
|
29
|
+
## [1.6.39-1.6.40] - 2018-5-30
|
30
|
+
### Changed
|
31
|
+
- Added validation to fix bad urls entered into object initialization
|
32
|
+
|
33
|
+
## [1.6.38] - 2018-5-26
|
34
|
+
### Changed
|
35
|
+
- HttpParty validation before code extraction
|
36
|
+
|
37
|
+
## [1.6.37] - 2018-5-23
|
38
|
+
### Added
|
39
|
+
- Added method to determine rest endpoint domain
|
40
|
+
|
41
|
+
## [1.6.36] - 2018-5-22
|
42
|
+
### Changed
|
43
|
+
- Fixed zuora staging 2 endpoint
|
44
|
+
|
45
|
+
## [1.6.33] - 2018-5-15
|
46
|
+
### Changed
|
47
|
+
- Added Errno::EHOSTUNREACH to list of retriable error codes
|
48
|
+
|
49
|
+
## [1.6.32] - 2018-5-14
|
50
|
+
### Changed
|
51
|
+
- Don't log fatal errors, allow application to decide for file download
|
52
|
+
- Don't change api url if the user set a high api url
|
53
|
+
|
54
|
+
###Removed
|
55
|
+
- Force encoding
|
56
|
+
|
57
|
+
## [1.6.28] - 2018-3-12
|
58
|
+
### Added
|
59
|
+
- Way to avoid force encoding for filedownload
|
60
|
+
|
4
61
|
## [1.6.28] - 2018-3-12
|
5
62
|
### Added
|
6
63
|
- Way to avoid force encoding for filedownload
|
data/lib/zuora_api/exceptions.rb
CHANGED
@@ -6,8 +6,8 @@ module ZuoraAPI
|
|
6
6
|
attr_reader :code, :response
|
7
7
|
attr_writer :default_message
|
8
8
|
|
9
|
-
def initialize(message = nil,response=nil
|
10
|
-
@code = code
|
9
|
+
def initialize(message = nil,response=nil)
|
10
|
+
@code = response.present? && response.class.to_s == "HTTParty::Response" ? response.code : nil
|
11
11
|
@message = message
|
12
12
|
@response = response
|
13
13
|
@default_message = "Error with Zuora Session."
|
@@ -22,8 +22,8 @@ module ZuoraAPI
|
|
22
22
|
attr_reader :code, :response, :errors, :successes
|
23
23
|
attr_writer :default_message
|
24
24
|
|
25
|
-
def initialize(message = nil,response=nil,
|
26
|
-
@code = code
|
25
|
+
def initialize(message = nil,response=nil, errors = [], successes = [], *args)
|
26
|
+
@code = response.present? && response.class.to_s == "HTTParty::Response" ? response.code : nil
|
27
27
|
@message = message
|
28
28
|
@response = response
|
29
29
|
@default_message = "Error with Zuora Entity"
|
@@ -40,8 +40,8 @@ module ZuoraAPI
|
|
40
40
|
attr_reader :code, :response, :errors, :successes
|
41
41
|
attr_writer :default_message
|
42
42
|
|
43
|
-
def initialize(message = nil,response=nil,
|
44
|
-
@code = code
|
43
|
+
def initialize(message = nil,response=nil, errors = [], successes = [], *args)
|
44
|
+
@code = response.present? && response.class.to_s == "HTTParty::Response" ? response.code : nil
|
45
45
|
@message = message
|
46
46
|
@response = response
|
47
47
|
@default_message = "Error communicating with Zuora."
|
@@ -58,8 +58,8 @@ module ZuoraAPI
|
|
58
58
|
attr_reader :code, :response
|
59
59
|
attr_writer :default_message
|
60
60
|
|
61
|
-
def initialize(message = nil,response=nil,
|
62
|
-
@code = code
|
61
|
+
def initialize(message = nil,response=nil, *args)
|
62
|
+
@code = response.present? && response.class.to_s == "HTTParty::Response" ? response.code : nil
|
63
63
|
@message = message
|
64
64
|
@response = response
|
65
65
|
@default_message = "Your request limit has been exceeded for zuora."
|
@@ -74,8 +74,24 @@ module ZuoraAPI
|
|
74
74
|
attr_reader :code, :response
|
75
75
|
attr_writer :default_message
|
76
76
|
|
77
|
-
def initialize(message = nil,response=nil,
|
78
|
-
@code = code
|
77
|
+
def initialize(message = nil,response=nil, *args)
|
78
|
+
@code = response.present? && response.class.to_s == "HTTParty::Response" ? response.code : nil
|
79
|
+
@message = message
|
80
|
+
@response = response
|
81
|
+
@default_message = "Operation failed due to lock competition. Please retry"
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
@message || @default_message
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class ZuoraDataIntegrity < Error
|
90
|
+
attr_reader :code, :response
|
91
|
+
attr_writer :default_message
|
92
|
+
|
93
|
+
def initialize(message = nil,response=nil, *args)
|
94
|
+
@code = response.present? && response.class.to_s == "HTTParty::Response" ? response.code : nil
|
79
95
|
@message = message
|
80
96
|
@response = response
|
81
97
|
@default_message = "Operation failed due to lock competition. Please retry"
|
@@ -90,8 +106,8 @@ module ZuoraAPI
|
|
90
106
|
attr_reader :code, :response
|
91
107
|
attr_writer :default_message
|
92
108
|
|
93
|
-
def initialize(message = nil,response=nil,
|
94
|
-
@code = code
|
109
|
+
def initialize(message = nil,response=nil, *args)
|
110
|
+
@code = response.present? && response.class.to_s == "HTTParty::Response" ? response.code : nil
|
95
111
|
@message = message
|
96
112
|
@response = response
|
97
113
|
@default_message = "There is a temporary error with zuora system."
|
@@ -106,8 +122,8 @@ module ZuoraAPI
|
|
106
122
|
attr_reader :code, :response
|
107
123
|
attr_writer :default_message
|
108
124
|
|
109
|
-
def initialize(message = nil,response=nil,
|
110
|
-
@code = code
|
125
|
+
def initialize(message = nil,response=nil, *args)
|
126
|
+
@code = response.present? && response.class.to_s == "HTTParty::Response" ? response.code : nil
|
111
127
|
@message = message
|
112
128
|
@response = response
|
113
129
|
@default_message = "Authentication type is not supported by this Login"
|
data/lib/zuora_api/login.rb
CHANGED
@@ -1,28 +1,38 @@
|
|
1
1
|
require "httparty"
|
2
2
|
require "nokogiri"
|
3
3
|
require "uri"
|
4
|
+
require 'zuora_api/exceptions'
|
4
5
|
|
5
6
|
module ZuoraAPI
|
6
7
|
class Login
|
7
8
|
ENVIRONMENTS = [SANDBOX = 'Sandbox', PRODUCTION = 'Production', PREFORMANCE = 'Preformance', SERVICES = 'Services', UNKNOWN = 'Unknown', STAGING = 'Staging' ]
|
8
9
|
REGIONS = [EU = 'EU', US = 'US', NA = 'NA' ]
|
9
|
-
MIN_Endpoint = '
|
10
|
+
MIN_Endpoint = '96.0'
|
10
11
|
XML_SAVE_OPTIONS = Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
|
11
|
-
CONNECTION_EXCEPTIONS = [Net::OpenTimeout, OpenSSL::SSL::SSLError, Errno::ECONNREFUSED, SocketError]
|
12
|
+
CONNECTION_EXCEPTIONS = [Net::OpenTimeout, OpenSSL::SSL::SSLError, Errno::ECONNREFUSED, SocketError, Errno::EHOSTUNREACH, Errno::EADDRNOTAVAIL]
|
12
13
|
CONNECTION_READ_EXCEPTIONS = [Net::ReadTimeout, Errno::ECONNRESET, Errno::EPIPE]
|
14
|
+
ZUORA_API_ERRORS = [ZuoraAPI::Exceptions::ZuoraAPIError, ZuoraAPI::Exceptions::ZuoraAPIRequestLimit, ZuoraAPI::Exceptions::ZuoraAPILockCompetition, ZuoraAPI::Exceptions::ZuoraAPITemporaryError, ZuoraAPI::Exceptions::ZuoraDataIntegrity]
|
15
|
+
|
16
|
+
attr_accessor :region, :url, :wsdl_number, :current_session, :bearer_token, :oauth_session_expires_at, :environment, :status, :errors, :current_error, :user_info, :tenant_id, :tenant_name, :entity_id, :timeout_sleep, :hostname, :zconnect_provider
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
def initialize(url: nil, entity_id: nil, session: nil, status: nil, **keyword_args)
|
17
|
-
raise "URL is nil or empty, but URL is required" if url.nil? | url.empty?
|
18
|
+
def initialize(url: nil, entity_id: nil, session: nil, status: nil, bearer_token: nil, oauth_session_expires_at: nil, **keyword_args)
|
19
|
+
raise "URL is nil or empty, but URL is required" if url.nil? || url.empty?
|
18
20
|
# raise "URL is improper. URL must contain zuora.com, zuora.eu, or zuora.na" if /zuora.com|zuora.eu|zuora.na/ === url
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
self.hostname = /(?<=https:\/\/|http:\/\/)(.*?)(?=\/|$)/.match(url)[0] if !/(?<=https:\/\/|http:\/\/)(.*?)(?=\/|$)/.match(url).nil?
|
22
|
+
if !/apps\/services\/a\/\d{2}\.\d$/.match(url.strip)
|
23
|
+
self.url = "https://#{hostname}/apps/services/a/#{MIN_Endpoint}"
|
24
|
+
elsif MIN_Endpoint.to_f > url.scan(/(\d{2}\.\d)$/).dig(0,0).to_f
|
25
|
+
self.url = url.gsub(/(\d{2}\.\d)$/, MIN_Endpoint)
|
26
|
+
else
|
27
|
+
self.url = url
|
28
|
+
end
|
29
|
+
self.entity_id = get_entity_id(entity_id: entity_id)
|
30
|
+
self.errors = Hash.new
|
31
|
+
self.current_session = session
|
32
|
+
self.bearer_token = bearer_token
|
33
|
+
self.oauth_session_expires_at = oauth_session_expires_at
|
34
|
+
self.status = status.blank? ? "Active" : status
|
35
|
+
self.user_info = Hash.new
|
26
36
|
self.update_region
|
27
37
|
self.update_environment
|
28
38
|
self.update_zconnect_provider
|
@@ -36,21 +46,21 @@ module ZuoraAPI
|
|
36
46
|
if !zsession.blank?
|
37
47
|
response = HTTParty.get("https://#{self.hostname}/apps/v1/identity", :headers => {'Cookie' => "ZSession=#{zsession}", 'Content-Type' => 'application/json'})
|
38
48
|
output_json = JSON.parse(response.body)
|
39
|
-
elsif
|
40
|
-
code = zconnect_accesstoken.split("#!").last
|
41
|
-
encrypted_token, tenant_id = Base64.decode64(code).split(":")
|
49
|
+
elsif zconnect_accesstoken.present?
|
42
50
|
begin
|
51
|
+
code = zconnect_accesstoken.split("#!").last
|
52
|
+
encrypted_token, tenant_id = Base64.decode64(code).split(":")
|
43
53
|
body = {'token' => encrypted_token}.to_json
|
44
54
|
rescue => ex
|
45
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Invalid ZConnect Cookie"
|
55
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Invalid ZConnect Cookie")
|
46
56
|
end
|
47
57
|
response = HTTParty.post("https://#{self.hostname}/apps/zconnectsession/identity", :body => body, :headers => { 'Content-Type' => 'application/json' })
|
48
58
|
output_json = JSON.parse(response.body)
|
49
59
|
else
|
50
60
|
if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
|
51
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}"
|
61
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}")
|
52
62
|
else
|
53
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present"
|
63
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
|
54
64
|
end
|
55
65
|
end
|
56
66
|
rescue JSON::ParserError => ex
|
@@ -64,17 +74,17 @@ module ZuoraAPI
|
|
64
74
|
zsession = cookies["ZSession"]
|
65
75
|
zconnect_accesstoken = get_zconnect_accesstoken(cookies)
|
66
76
|
begin
|
67
|
-
if
|
77
|
+
if zsession.present?
|
68
78
|
response = HTTParty.get("https://#{self.hostname}/apps/v1/navigation", :headers => {'Cookie' => "ZSession=#{zsession}", 'Content-Type' => 'application/json'})
|
69
79
|
output_json = JSON.parse(response.body)
|
70
|
-
elsif
|
80
|
+
elsif zconnect_accesstoken.present?
|
71
81
|
response = HTTParty.get("https://#{self.hostname}/apps/zconnectsession/navigation", :headers => {'Cookie' => "#{self.zconnect_provider}=#{zconnect_accesstoken}",'Content-Type' => 'application/json'})
|
72
82
|
output_json = JSON.parse(response.body)
|
73
83
|
else
|
74
84
|
if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
|
75
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}"
|
85
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}")
|
76
86
|
else
|
77
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present"
|
87
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
|
78
88
|
end
|
79
89
|
end
|
80
90
|
rescue JSON::ParserError => ex
|
@@ -96,9 +106,9 @@ module ZuoraAPI
|
|
96
106
|
output_json = JSON.parse(response.body)
|
97
107
|
else
|
98
108
|
if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
|
99
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}"
|
109
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}")
|
100
110
|
else
|
101
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present"
|
111
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
|
102
112
|
end
|
103
113
|
end
|
104
114
|
rescue JSON::ParserError => ex
|
@@ -120,9 +130,9 @@ module ZuoraAPI
|
|
120
130
|
output_json = JSON.parse(response.body)
|
121
131
|
else
|
122
132
|
if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
|
123
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}"
|
133
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}")
|
124
134
|
else
|
125
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present"
|
135
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
|
126
136
|
end
|
127
137
|
end
|
128
138
|
rescue JSON::ParserError => ex
|
@@ -170,12 +180,12 @@ module ZuoraAPI
|
|
170
180
|
if entity_ids.blank? && cookies["ZuoraCurrentEntity"].present?
|
171
181
|
entity_ids = Array(cookies["ZuoraCurrentEntity"].unpack("a8a4a4a4a12").join('-'))
|
172
182
|
else
|
173
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Zuora Entity ID not provided"
|
183
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Zuora Entity ID not provided")
|
174
184
|
end
|
175
185
|
if user_id.blank? && cookies["Zuora-User-Id"].present?
|
176
186
|
user_id = cookies["Zuora-User-Id"]
|
177
187
|
else
|
178
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Zuora User ID not provided"
|
188
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Zuora User ID not provided")
|
179
189
|
end
|
180
190
|
elsif !client_id.nil? && !client_secret.nil?
|
181
191
|
bearer_response = HTTParty.post("https://#{self.hostname}/oauth/token", :headers => {'Content-Type' => 'application/x-www-form-urlencoded', 'Accept' => 'application/json'}, :body => {'client_id' => client_id, 'client_secret' => URI::encode(client_secret), 'grant_type' => 'client_credentials'})
|
@@ -192,12 +202,12 @@ module ZuoraAPI
|
|
192
202
|
output_json["clientSecret"] = new_client_secret
|
193
203
|
return output_json
|
194
204
|
elsif oauth_response.code == 401 && !oauth_response.message.blank?
|
195
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(output_json["message"],
|
205
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(output_json["message"], oauth_response)
|
196
206
|
else
|
197
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(output_json["error"],
|
207
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(output_json["error"], oauth_response)
|
198
208
|
end
|
199
209
|
else
|
200
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Insufficient credentials provided"
|
210
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Insufficient credentials provided")
|
201
211
|
end
|
202
212
|
end
|
203
213
|
|
@@ -257,7 +267,7 @@ module ZuoraAPI
|
|
257
267
|
if !self.url.blank?
|
258
268
|
if /(?<=\.|\/|-|^)(apisandbox|sandbox)(?=\.|\/|-|$)/ === self.hostname
|
259
269
|
self.environment = 'Sandbox'
|
260
|
-
elsif /(?<=\.|\/|^)(service
|
270
|
+
elsif /(?<=\.|\/|^)(service[\d]*|services[\d]*|ep-edge)(?=\.|\/|$)/ === self.hostname
|
261
271
|
self.environment = 'Services'
|
262
272
|
elsif /(?<=\.|\/|-|^)(pt[\d]*)(?=\.|\/|-|$)/ === self.hostname
|
263
273
|
self.environment = 'Performance'
|
@@ -332,17 +342,22 @@ module ZuoraAPI
|
|
332
342
|
when 'Services'
|
333
343
|
https = /https:\/\/|http:\/\//.match(self.url)[0]
|
334
344
|
host = self.hostname
|
335
|
-
endpoint = "#{https}#{host}/
|
345
|
+
endpoint = "#{https}rest#{host}/v1/#{url}"
|
336
346
|
when 'Staging'
|
337
|
-
endpoint = "https://rest-staging2.zuora.com/".concat(url)
|
347
|
+
endpoint = "https://rest-staging2.zuora.com/v1/".concat(url)
|
338
348
|
when 'Unknown'
|
339
349
|
raise "Environment unknown, returning passed in parameter unaltered"
|
340
350
|
end
|
341
351
|
return endpoint
|
342
352
|
end
|
343
353
|
|
354
|
+
def rest_domain
|
355
|
+
require 'addressable/uri'
|
356
|
+
return ::Addressable::URI.parse(self.rest_endpoint).host
|
357
|
+
end
|
358
|
+
|
344
359
|
def fileURL(url="")
|
345
|
-
return self.
|
360
|
+
return self.rest_endpoint("file/").concat(url)
|
346
361
|
end
|
347
362
|
|
348
363
|
def dateFormat
|
@@ -353,17 +368,16 @@ module ZuoraAPI
|
|
353
368
|
end
|
354
369
|
|
355
370
|
def get_session(prefix: false, auth_type: :basic)
|
356
|
-
Rails.logger.debug("Get session for #{auth_type} - #{self.class.to_s}")
|
371
|
+
Rails.logger.debug("Get session for #{auth_type} - #{self.class.to_s}") if Rails.env.to_s == 'development'
|
357
372
|
case auth_type
|
358
373
|
when :basic
|
359
374
|
if self.current_session.blank?
|
360
|
-
Rails.logger.debug("Create new session")
|
361
375
|
case self.class.to_s
|
362
376
|
when 'ZuoraAPI::Oauth'
|
363
377
|
if self.bearer_token.blank? || self.oauth_expired?
|
364
378
|
self.new_session(auth_type: :bearer)
|
365
379
|
end
|
366
|
-
self.get_z_session
|
380
|
+
self.get_z_session if self.status == 'Active'
|
367
381
|
when 'ZuoraAPI::Basic'
|
368
382
|
self.new_session(auth_type: :basic)
|
369
383
|
else
|
@@ -386,7 +400,7 @@ module ZuoraAPI
|
|
386
400
|
end
|
387
401
|
end
|
388
402
|
|
389
|
-
def soap_call(ns1: 'ns1', ns2: 'ns2', batch_size: nil, single_transaction: false, debug: false, errors: [ZuoraAPI::Exceptions::ZuoraAPISessionError
|
403
|
+
def soap_call(ns1: 'ns1', ns2: 'ns2', batch_size: nil, single_transaction: false, debug: false, errors: [ZuoraAPI::Exceptions::ZuoraAPISessionError].concat(ZUORA_API_ERRORS), z_session: true, timeout_retry: false, timeout: 120,**keyword_args)
|
390
404
|
tries ||= 2
|
391
405
|
xml = Nokogiri::XML::Builder.new do |xml|
|
392
406
|
xml['SOAP-ENV'].Envelope('xmlns:SOAP-ENV' => "http://schemas.xmlsoap.org/soap/envelope/",
|
@@ -436,7 +450,7 @@ module ZuoraAPI
|
|
436
450
|
return output_xml, input_xml, response
|
437
451
|
end
|
438
452
|
end
|
439
|
-
rescue
|
453
|
+
rescue *ZUORA_API_ERRORS => ex
|
440
454
|
if errors.include?(ex.class)
|
441
455
|
raise ex
|
442
456
|
else
|
@@ -458,6 +472,12 @@ module ZuoraAPI
|
|
458
472
|
else
|
459
473
|
raise ex
|
460
474
|
end
|
475
|
+
rescue Errno::ECONNRESET => ex
|
476
|
+
if !(tries -= 1).zero? && ex.message.include?('SSL_connect')
|
477
|
+
retry
|
478
|
+
else
|
479
|
+
raise ex
|
480
|
+
end
|
461
481
|
rescue => ex
|
462
482
|
raise ex
|
463
483
|
else
|
@@ -499,94 +519,107 @@ module ZuoraAPI
|
|
499
519
|
if error.class == String
|
500
520
|
case error
|
501
521
|
when "INVALID_SESSION"
|
502
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{error}::#{message}",
|
522
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{error}::#{message}", response)
|
503
523
|
when "REQUEST_EXCEEDED_LIMIT"
|
504
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("#{error}::#{message}",
|
524
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("#{error}::#{message}", response)
|
505
525
|
when "LOCK_COMPETITION"
|
506
|
-
raise ZuoraAPI::Exceptions::ZuoraAPILockCompetition.new("#{error}::#{message}",
|
526
|
+
raise ZuoraAPI::Exceptions::ZuoraAPILockCompetition.new("#{error}::#{message}", response)
|
507
527
|
when "BATCH_FAIL_ERROR"
|
508
528
|
if message.include?("optimistic locking failed")
|
509
|
-
raise ZuoraAPI::Exceptions::ZuoraAPILockCompetition.new("#{error}::#{message}",
|
529
|
+
raise ZuoraAPI::Exceptions::ZuoraAPILockCompetition.new("#{error}::#{message}", response)
|
510
530
|
else
|
511
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{error}::#{message}",
|
531
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{error}::#{message}", response)
|
512
532
|
end
|
513
533
|
when "TEMPORARY_ERROR"
|
514
|
-
raise ZuoraAPI::Exceptions::ZuoraAPITemporaryError.new("#{error}::#{message}",
|
534
|
+
raise ZuoraAPI::Exceptions::ZuoraAPITemporaryError.new("#{error}::#{message}", response)
|
535
|
+
when "INVALID_VALUE"
|
536
|
+
if message.include?("data integrity violation")
|
537
|
+
raise ZuoraAPI::Exceptions::ZuoraDataIntegrity.new("Data Integrity Violation", response)
|
538
|
+
else
|
539
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{error}::#{message}", response)
|
540
|
+
end
|
515
541
|
else
|
516
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{error}::#{message}",
|
542
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{error}::#{message}", response) if error.present?
|
517
543
|
end
|
518
544
|
elsif error.class == Array
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
545
|
+
if error[0].include?("LOCK_COMPETITION") && error.count == 1
|
546
|
+
raise ZuoraAPI::Exceptions::ZuoraAPILockCompetition.new(error.group_by {|v| v}.map {|k,v| "(#{v.size}x) - #{k == "::" ? 'UNKNOWN::No error provided' : k}"}.join(', '), response)
|
547
|
+
else
|
548
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(error.group_by {|v| v}.map {|k,v| "(#{v.size}x) - #{k == "::" ? 'UNKNOWN::No error provided' : k}"}.join(', '), response, error, success)
|
549
|
+
end
|
524
550
|
end
|
525
551
|
end
|
526
|
-
|
552
|
+
|
527
553
|
if response.code == 429
|
528
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("The total number of concurrent requests has exceeded the limit allowed by the system. Please resubmit your request later.",
|
554
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("The total number of concurrent requests has exceeded the limit allowed by the system. Please resubmit your request later.", response)
|
529
555
|
end
|
530
556
|
|
531
557
|
when :JSON
|
532
558
|
body = body.dig("results").present? ? body["results"] : body if body.class == Hash
|
533
559
|
if body.class == Hash && (!body["success"] || !body["Success"] || response.code != 200)
|
534
|
-
messages_array = (
|
535
|
-
|
560
|
+
messages_array = body.fetch("reasons", []).map {|error| error['message']}.compact
|
561
|
+
messages_array = messages_array.push(body.dig("error", 'message')).compact if body.dig('error').class == Hash
|
562
|
+
codes_array = body.fetch("reasons", []).map {|error| error['code']}.compact
|
563
|
+
codes_array = codes_array.push(body.dig("error", 'code')).compact if body.dig('error').class == Hash
|
536
564
|
|
537
565
|
if body['message'] == "No bearer token" && response.code == 400
|
538
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new()
|
566
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new("Authentication type is not supported by this Login", response)
|
539
567
|
end
|
540
568
|
|
541
569
|
if body['errorMessage']
|
542
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(body['errorMessage'],
|
570
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new(body['errorMessage'], response)
|
543
571
|
end
|
544
572
|
|
545
573
|
if body.dig("reasons").nil? ? false : body.dig("reasons")[0].dig("code") == 90000020
|
546
|
-
raise ZuoraAPI::Exceptions::BadEntityError.new("#{messages_array.join(', ')}",
|
574
|
+
raise ZuoraAPI::Exceptions::BadEntityError.new("#{messages_array.join(', ')}", response)
|
575
|
+
end
|
576
|
+
|
577
|
+
#Oauth Tokens - User deactivated
|
578
|
+
if body['message'] == 'Forbidden' && body['status'] == 403 && response.code == 403
|
579
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("Forbidden", response)
|
547
580
|
end
|
548
581
|
|
549
|
-
if body['error'] == 'Unauthorized' && body['status']
|
550
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{messages_array.join(', ')}",
|
582
|
+
if body['error'] == 'Unauthorized' && body['status'] == 401
|
583
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{messages_array.join(', ')}", response)
|
551
584
|
end
|
552
585
|
#Authentication failed
|
553
|
-
if codes_array.map{|code| code.to_s.slice(6,7).to_i}.include?(11) || response.code == 401
|
554
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{messages_array.join(', ')}",
|
586
|
+
if (codes_array.map{|code| code.to_s.slice(6,7).to_i}.include?(11) || response.code == 401) && !codes_array.include?(422)
|
587
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{messages_array.join(', ')}", response)
|
555
588
|
end
|
556
589
|
|
557
590
|
#Zuora REST Create Amendment error #Authentication failed
|
558
591
|
if body["faultcode"].present? && body["faultcode"] == "fns:INVALID_SESSION"
|
559
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{body['faultstring']}",
|
592
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{body['faultstring']}", response)
|
560
593
|
end
|
561
594
|
|
562
595
|
#Request exceeded limit
|
563
596
|
if codes_array.map{|code| code.to_s.slice(6,7).to_i}.include?(70)
|
564
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("#{messages_array.join(', ')}",
|
597
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("#{messages_array.join(', ')}", response)
|
565
598
|
end
|
566
599
|
|
567
600
|
#Locking contention
|
568
601
|
if codes_array.map{|code| code.to_s.slice(6,7).to_i}.include?(50)
|
569
|
-
raise ZuoraAPI::Exceptions::ZuoraAPILockCompetition.new("#{messages_array.join(', ')}",
|
570
|
-
end
|
602
|
+
raise ZuoraAPI::Exceptions::ZuoraAPILockCompetition.new("#{messages_array.join(', ')}", response)
|
603
|
+
end
|
571
604
|
|
572
605
|
#All Errors catch
|
573
606
|
if codes_array.size > 0
|
574
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{messages_array.join(', ')}",
|
607
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{messages_array.join(', ')}", response)
|
575
608
|
end
|
576
609
|
|
577
610
|
#Zuora REST Query Errors
|
578
611
|
if body["faultcode"].present?
|
579
612
|
case body["faultcode"]
|
580
613
|
when "fns:MALFORMED_QUERY"
|
581
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{body["faultcode"]}::#{body["faultstring"]}",
|
614
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{body["faultcode"]}::#{body["faultstring"]}", response)
|
582
615
|
when "fns:REQUEST_EXCEEDED_LIMIT"
|
583
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("#{body["faultcode"]}::#{body["faultstring"]}",
|
616
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("#{body["faultcode"]}::#{body["faultstring"]}", response)
|
584
617
|
when "fns:LOCK_COMPETITION"
|
585
|
-
raise ZuoraAPI::Exceptions::ZuoraAPILockCompetition.new("#{body["faultcode"]}::#{body["faultstring"]}",
|
618
|
+
raise ZuoraAPI::Exceptions::ZuoraAPILockCompetition.new("#{body["faultcode"]}::#{body["faultstring"]}", response)
|
586
619
|
when "INVALID_SESSION"
|
587
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{body["faultcode"]}::#{body["faultstring"]}",
|
620
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{body["faultcode"]}::#{body["faultstring"]}", response)
|
588
621
|
else
|
589
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{body["faultcode"]}::#{body["faultstring"]}",
|
622
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{body["faultcode"]}::#{body["faultstring"]}", response)
|
590
623
|
end
|
591
624
|
end
|
592
625
|
|
@@ -595,7 +628,7 @@ module ZuoraAPI
|
|
595
628
|
(body["Errors"] || []).select { |obj| errors.push(obj["Message"]) }.compact
|
596
629
|
(body["errors"] || []).select { |obj| errors.push(obj["Message"]) }.compact
|
597
630
|
if errors.size > 0
|
598
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{errors.join(", ")}",
|
631
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{errors.join(", ")}", response, errors)
|
599
632
|
end
|
600
633
|
end
|
601
634
|
end
|
@@ -607,22 +640,27 @@ module ZuoraAPI
|
|
607
640
|
|
608
641
|
if all_success.blank? && all_errors.present?
|
609
642
|
error_codes = all_errors.flatten.group_by {|error| error['Code']}.keys.uniq
|
610
|
-
|
611
|
-
|
643
|
+
error_messages = all_errors.flatten.group_by {|error| error['Message']}.keys.uniq
|
644
|
+
if error_codes.size == 1 || error_messages.size == 1
|
645
|
+
if error_codes.first == "LOCK_COMPETITION"
|
646
|
+
raise ZuoraAPI::Exceptions::ZuoraAPILockCompetition.new("Retry Lock Competition", response)
|
647
|
+
elsif error_messages.first.include?("data integrity violation")
|
648
|
+
raise ZuoraAPI::Exceptions::ZuoraDataIntegrity.new("Data Integrity Violation", response)
|
649
|
+
end
|
612
650
|
end
|
613
651
|
end
|
614
652
|
|
615
653
|
if all_errors.size > 0
|
616
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{all_errors.flatten.group_by {|error| error['Message']}.keys.uniq.join(' ')}",
|
654
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{all_errors.flatten.group_by {|error| error['Message']}.keys.uniq.join(' ')}", response, all_errors, all_success)
|
617
655
|
end
|
618
656
|
end
|
619
657
|
|
620
658
|
#All other errors
|
621
|
-
if response.code
|
659
|
+
if ![200,201].include?(response.code)
|
622
660
|
if response.code == 429
|
623
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("The total number of concurrent requests has exceeded the limit allowed by the system. Please resubmit your request later.",
|
661
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("The total number of concurrent requests has exceeded the limit allowed by the system. Please resubmit your request later.", response)
|
624
662
|
else
|
625
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{response.message}",
|
663
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{response.message}", response)
|
626
664
|
end
|
627
665
|
end
|
628
666
|
end
|
@@ -645,7 +683,7 @@ module ZuoraAPI
|
|
645
683
|
}
|
646
684
|
response = self.rest_call(method: :post, body: params.to_json, url: self.aqua_endpoint("batch-query/"))
|
647
685
|
if(response[0]["id"].nil?)
|
648
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Error in AQuA Process.
|
686
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Error in AQuA Process.", response)
|
649
687
|
end
|
650
688
|
return getFileById(id: response[0]["id"])
|
651
689
|
end
|
@@ -658,7 +696,7 @@ module ZuoraAPI
|
|
658
696
|
response, fullResponse = self.rest_call(method: :get, body: {}, url: self.aqua_endpoint("batch-query/jobs/#{id}"))
|
659
697
|
result = response["batches"][0]["status"]
|
660
698
|
if result == "error"
|
661
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Aqua Error
|
699
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Aqua Error", response)
|
662
700
|
break
|
663
701
|
end
|
664
702
|
end
|
@@ -666,7 +704,7 @@ module ZuoraAPI
|
|
666
704
|
return self.get_file(url: self.aqua_endpoint("file/#{fileId}"))
|
667
705
|
end
|
668
706
|
|
669
|
-
def describe_call(object = nil)
|
707
|
+
def describe_call(object = nil, log_errors = true)
|
670
708
|
tries ||= 2
|
671
709
|
|
672
710
|
base = self.url.include?(".com") ? self.url.split(".com")[0].concat(".com") : self.url.split(".eu")[0].concat(".eu")
|
@@ -674,7 +712,7 @@ module ZuoraAPI
|
|
674
712
|
headers = self.entity_id.present? ? {"Zuora-Entity-Ids" => self.entity_id, 'Content-Type' => "text/xml; charset=utf-8"} : {'Content-Type' => "text/xml; charset=utf-8"}
|
675
713
|
response = HTTParty.get(url, headers: {"Authorization" => self.get_session(prefix: true, auth_type: :basic)}.merge(headers), :timeout => 120)
|
676
714
|
|
677
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error.present? ? self.current_error : 'Describe call 401' ) if response.code == 401
|
715
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error.present? ? self.current_error : 'Describe call 401', response) if response.code == 401
|
678
716
|
|
679
717
|
output_xml = Nokogiri::XML(response.body)
|
680
718
|
des_hash = Hash.new
|
@@ -714,11 +752,12 @@ module ZuoraAPI
|
|
714
752
|
raise ex
|
715
753
|
end
|
716
754
|
rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
|
717
|
-
if !(tries -= 1).zero?
|
718
|
-
Rails.logger.
|
755
|
+
if !(tries -= 1).zero? && self.status == 'Active'
|
756
|
+
Rails.logger.debug("Describe session expired. Starting new session.")
|
719
757
|
self.new_session
|
720
758
|
retry
|
721
759
|
else
|
760
|
+
Rails.logger.error("Describe session expired. Starting new session.") if log_errors
|
722
761
|
raise ex
|
723
762
|
end
|
724
763
|
rescue => ex
|
@@ -727,7 +766,7 @@ module ZuoraAPI
|
|
727
766
|
return des_hash
|
728
767
|
end
|
729
768
|
|
730
|
-
def rest_call(method: :get, body: nil, headers: {}, url: rest_endpoint("catalog/products?pageSize=4"), debug: false, errors: [ZuoraAPI::Exceptions::ZuoraAPISessionError
|
769
|
+
def rest_call(method: :get, body: nil, headers: {}, url: rest_endpoint("catalog/products?pageSize=4"), debug: false, errors: [ZuoraAPI::Exceptions::ZuoraAPISessionError].concat(ZUORA_API_ERRORS), z_session: true, session_type: :basic, timeout_retry: false, timeout: 120, **keyword_args)
|
731
770
|
tries ||= 2
|
732
771
|
|
733
772
|
if self.entity_id.present?
|
@@ -738,9 +777,9 @@ module ZuoraAPI
|
|
738
777
|
raise "Method not supported, supported methods include: :get, :post, :put, :delete, :patch, :head, :options" if ![:get, :post, :put, :delete, :patch, :head, :options].include?(method)
|
739
778
|
|
740
779
|
authentication_headers = z_session ? {"Authorization" => self.get_session(prefix: true, auth_type: session_type) } : {}
|
741
|
-
|
780
|
+
modified_headers = {'Content-Type' => "application/json; charset=utf-8"}.merge(authentication_headers).merge(headers)
|
742
781
|
|
743
|
-
response = HTTParty::Request.new("Net::HTTP::#{method.to_s.capitalize}".constantize, url, body: body, headers:
|
782
|
+
response = HTTParty::Request.new("Net::HTTP::#{method.to_s.capitalize}".constantize, url, body: body, headers: modified_headers, timeout: timeout).perform
|
744
783
|
Rails.logger.debug("Response Code: #{response.code}") if debug
|
745
784
|
begin
|
746
785
|
output_json = JSON.parse(response.body)
|
@@ -751,8 +790,8 @@ module ZuoraAPI
|
|
751
790
|
|
752
791
|
raise_errors(type: :JSON, body: output_json, response: response)
|
753
792
|
rescue ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError => ex
|
754
|
-
if self.class.to_s == 'ZuoraAPI::Oauth'
|
755
|
-
self.rest_call(method: method.to_sym, url: url, debug: debug, errors: errors, z_session: z_session, session_type: :bearer, timeout_retry: timeout_retry, timeout: timeout)
|
793
|
+
if self.class.to_s == 'ZuoraAPI::Oauth' && ex.message.include?("Authentication type is not supported by this Login")
|
794
|
+
self.rest_call(method: method.to_sym, url: url, body: body, debug: debug, errors: errors, z_session: z_session, session_type: :bearer, timeout_retry: timeout_retry, timeout: timeout)
|
756
795
|
else
|
757
796
|
Rails.logger.debug("Rest Call - Session Bad Auth type")
|
758
797
|
raise ex
|
@@ -769,7 +808,7 @@ module ZuoraAPI
|
|
769
808
|
return [output_json, response]
|
770
809
|
end
|
771
810
|
end
|
772
|
-
rescue
|
811
|
+
rescue *ZUORA_API_ERRORS => ex
|
773
812
|
if errors.include?(ex.class)
|
774
813
|
raise ex
|
775
814
|
else
|
@@ -793,6 +832,12 @@ module ZuoraAPI
|
|
793
832
|
else
|
794
833
|
raise ex
|
795
834
|
end
|
835
|
+
rescue Errno::ECONNRESET => ex
|
836
|
+
if !(tries -= 1).zero? && ex.message.include?('SSL_connect')
|
837
|
+
retry
|
838
|
+
else
|
839
|
+
raise ex
|
840
|
+
end
|
796
841
|
rescue => ex
|
797
842
|
raise ex
|
798
843
|
else
|
@@ -820,7 +865,7 @@ module ZuoraAPI
|
|
820
865
|
Rails.logger.debug("Fetch Catalog URL #{url}")
|
821
866
|
output_json, response = self.rest_call(:debug => false, :url => url, :errors => [ZuoraAPI::Exceptions::ZuoraAPISessionError], :timeout_retry => true )
|
822
867
|
if !output_json['success'] =~ (/(true|t|yes|y|1)$/i) || output_json['success'].class != TrueClass
|
823
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Error Getting Catalog: #{output_json}")
|
868
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Error Getting Catalog: #{output_json}", response)
|
824
869
|
end
|
825
870
|
output_json["products"].each do |product|
|
826
871
|
catalog_map[product["id"]] = {"productId" => product["id"]}
|
@@ -845,7 +890,7 @@ module ZuoraAPI
|
|
845
890
|
return products, catalog_map
|
846
891
|
end
|
847
892
|
|
848
|
-
def get_file(url: nil, headers: {}, count: 3, z_session: true, tempfile: true, output_file_name: nil, add_timestamp: true, file_path: defined?(Rails.root.join('tmp')) ? Rails.root.join('tmp') : Pathname.new(Dir.pwd), timeout_retries: 2, timeout: 120, session_type: :basic,
|
893
|
+
def get_file(url: nil, headers: {}, count: 3, z_session: true, tempfile: true, output_file_name: nil, add_timestamp: true, file_path: defined?(Rails.root.join('tmp')) ? Rails.root.join('tmp') : Pathname.new(Dir.pwd), timeout_retries: 2, timeout: 120, session_type: :basic, **execute_params)
|
849
894
|
raise "file_path must be of class Pathname" if file_path.class != Pathname
|
850
895
|
|
851
896
|
#Make sure directory exists
|
@@ -857,7 +902,7 @@ module ZuoraAPI
|
|
857
902
|
uri = URI.parse(url)
|
858
903
|
http = Net::HTTP.new(uri.host, uri.port)
|
859
904
|
http.read_timeout = timeout #Seconds
|
860
|
-
http.use_ssl = true if uri.scheme.downcase == 'https'
|
905
|
+
http.use_ssl = true if !uri.scheme.nil? && uri.scheme.downcase == 'https'
|
861
906
|
if z_session
|
862
907
|
headers = headers.merge({"Authorization" => self.get_session(prefix: true)})
|
863
908
|
headers = headers.merge({"Zuora-Entity-Ids" => self.entity_id}) if !self.entity_id.blank?
|
@@ -871,7 +916,6 @@ module ZuoraAPI
|
|
871
916
|
|
872
917
|
case response
|
873
918
|
when Net::HTTPNotFound
|
874
|
-
Rails.logger.fatal("404 - Not Found")
|
875
919
|
raise
|
876
920
|
|
877
921
|
when Net::HTTPUnauthorized
|
@@ -882,9 +926,8 @@ module ZuoraAPI
|
|
882
926
|
raise
|
883
927
|
end
|
884
928
|
end
|
885
|
-
Rails.logger.fatal("Unauthorized: Retry")
|
886
929
|
self.new_session if z_session
|
887
|
-
return get_file(:url => url, :headers => headers, :count => count - 1, :z_session => z_session, :tempfile => tempfile, :file_path => file_path, :timeout_retries => timeout_retries, :timeout => timeout
|
930
|
+
return get_file(:url => url, :headers => headers, :count => count - 1, :z_session => z_session, :tempfile => tempfile, :file_path => file_path, :timeout_retries => timeout_retries, :timeout => timeout)
|
888
931
|
|
889
932
|
when Net::HTTPClientError
|
890
933
|
raise
|
@@ -949,11 +992,7 @@ module ZuoraAPI
|
|
949
992
|
file_handle.binmode
|
950
993
|
|
951
994
|
response.read_body do |chunk|
|
952
|
-
|
953
|
-
file_handle << chunk.force_encoding(encoding)
|
954
|
-
else
|
955
|
-
file_handle << chunk
|
956
|
-
end
|
995
|
+
file_handle << chunk
|
957
996
|
|
958
997
|
if defined?(export_size) && export_size != 0 && export_size.class == Integer
|
959
998
|
size += chunk.size
|
@@ -980,16 +1019,13 @@ module ZuoraAPI
|
|
980
1019
|
raise
|
981
1020
|
end
|
982
1021
|
end
|
983
|
-
rescue
|
984
|
-
Rails.logger.fatal(
|
985
|
-
Rails.logger.fatal("Download Failed: #{e.backtrace.join("\n")}")
|
1022
|
+
rescue => ex
|
1023
|
+
Rails.logger.fatal(ex)
|
986
1024
|
raise
|
987
1025
|
end
|
988
1026
|
end
|
989
1027
|
|
990
1028
|
def getDataSourceExport(query, extract: true, encrypted: false, zip: true)
|
991
|
-
Rails.logger.debug("Build export")
|
992
|
-
Rails.logger.debug("#{query}")
|
993
1029
|
request = Nokogiri::XML::Builder.new do |xml|
|
994
1030
|
xml['SOAP-ENV'].Envelope('xmlns:SOAP-ENV' => "http://schemas.xmlsoap.org/soap/envelope/", 'xmlns:ns2' => "http://object.api.zuora.com/", 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance", 'xmlns:ns1' => "http://api.zuora.com/") do
|
995
1031
|
xml['SOAP-ENV'].Header do
|
@@ -1044,7 +1080,6 @@ module ZuoraAPI
|
|
1044
1080
|
end
|
1045
1081
|
|
1046
1082
|
file_id = output_xml.xpath('//ns2:FileId', 'ns2' =>'http://object.api.zuora.com/').text
|
1047
|
-
Rails.logger.debug('=====> Export finished')
|
1048
1083
|
export_file = get_file(:url => self.fileURL(file_id))
|
1049
1084
|
export_file_path = export_file.path
|
1050
1085
|
Rails.logger.debug("=====> Export path #{export_file.path}")
|
@@ -1063,7 +1098,6 @@ module ZuoraAPI
|
|
1063
1098
|
end
|
1064
1099
|
|
1065
1100
|
def query(query, parse = false)
|
1066
|
-
Rails.logger.debug("Querying Zuora for #{query}")
|
1067
1101
|
output_xml, input_xml = self.soap_call({:debug => false, :timeout_retry => true}) do |xml|
|
1068
1102
|
xml['ns1'].query do
|
1069
1103
|
xml['ns1'].queryString query
|
@@ -1,15 +1,17 @@
|
|
1
1
|
module ZuoraAPI
|
2
2
|
class Basic < Login
|
3
|
-
attr_accessor :username, :password
|
4
|
-
def initialize(username: nil, password: nil, **keyword_args)
|
5
|
-
|
6
|
-
|
3
|
+
attr_accessor :username, :password, :session
|
4
|
+
def initialize(username: nil, password: nil, session: nil, **keyword_args)
|
5
|
+
self.username = username
|
6
|
+
self.password = password
|
7
|
+
self.current_session = session
|
8
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new("Request Basic Login but either 'Username' or 'Password' were not passed.") if self.current_session.blank? && (self.password.blank? && self.username.blank?)
|
7
9
|
super
|
8
10
|
end
|
9
11
|
|
10
|
-
def new_session(
|
12
|
+
def new_session(auth_type: :basic, debug: false)
|
11
13
|
raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new("Basic Login, does not support Authentication of Type: #{auth_type}") if auth_type != :basic
|
12
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new("Basic Login
|
14
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new("Request Basic Login but either 'Username' or 'Password' were not passed.") if (self.password.blank? && self.username.blank?)
|
13
15
|
|
14
16
|
tries ||= 2
|
15
17
|
request = Nokogiri::XML::Builder.new do |xml|
|
@@ -27,16 +29,16 @@ module ZuoraAPI
|
|
27
29
|
|
28
30
|
input_xml = Nokogiri::XML(request.to_xml(:save_with => XML_SAVE_OPTIONS).strip)
|
29
31
|
input_xml.xpath('//ns1:session', 'ns1' =>'http://api.zuora.com/').children.remove
|
30
|
-
Rails.logger.debug('Connect') {"
|
32
|
+
Rails.logger.debug('Connect') {"SOAP XML: #{input_xml.to_xml(:save_with => XML_SAVE_OPTIONS).strip}"} if debug
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
-
Rails.logger.debug('Connect') {"Response Code: #{
|
34
|
+
response_query = HTTParty.post(self.url,:body => request.to_xml(:save_with => XML_SAVE_OPTIONS).strip, :headers => {'Content-Type' => "text/xml; charset=utf-8"}, :timeout => 10)
|
35
|
+
output_xml = Nokogiri::XML(response_query.body)
|
36
|
+
Rails.logger.debug('Connect') {"Response Code: #{response_query.code} SOAP XML: #{output_xml.to_xml(:save_with => XML_SAVE_OPTIONS).strip}"} if debug
|
35
37
|
|
36
|
-
if
|
38
|
+
if !response_query.success?
|
37
39
|
self.current_session = nil
|
38
|
-
if
|
39
|
-
self.current_error =
|
40
|
+
if output_xml.namespaces.size > 0 && output_xml.xpath('//soapenv:Fault').size > 0
|
41
|
+
self.current_error = output_xml.xpath('//fns:FaultMessage', 'fns' =>'http://fault.api.zuora.com/').text
|
40
42
|
if self.current_error.include?('deactivated')
|
41
43
|
self.status = 'Deactivated'
|
42
44
|
self.current_error = 'Deactivated user login, please check with Zuora tenant administrator'
|
@@ -75,19 +77,19 @@ module ZuoraAPI
|
|
75
77
|
self.errors[:base] = self.current_error
|
76
78
|
else
|
77
79
|
self.status = 'Unknown'
|
78
|
-
self.current_error =
|
80
|
+
self.current_error = output_xml.xpath('//faultstring').text if self.current_error.blank?
|
79
81
|
self.errors[:base] = self.current_error
|
80
82
|
end
|
81
83
|
|
82
84
|
else
|
83
85
|
self.status = 'Unknown'
|
84
|
-
self.current_error =
|
86
|
+
self.current_error = output_xml.xpath('//faultstring').text if self.current_error.blank?
|
85
87
|
self.errors[:base] = self.current_error
|
86
88
|
end
|
87
89
|
else
|
88
90
|
#Username & password combo
|
89
|
-
retrieved_session =
|
90
|
-
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("No session found for api call.") if retrieved_session.blank?
|
91
|
+
retrieved_session = output_xml.xpath('//ns1:Session', 'ns1' =>'http://api.zuora.com/').text
|
92
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("No session found for api call.", response_query) if retrieved_session.blank?
|
91
93
|
self.status = 'Active'
|
92
94
|
self.current_session = retrieved_session
|
93
95
|
end
|
@@ -5,9 +5,9 @@ module ZuoraAPI
|
|
5
5
|
def initialize(oauth_client_id: nil, oauth_secret: nil, bearer_token: nil, oauth_session_expires_at: nil, **keyword_args)
|
6
6
|
self.oauth_client_id = oauth_client_id
|
7
7
|
self.oauth_secret = oauth_secret
|
8
|
-
self.bearer_token = bearer_token
|
9
|
-
self.oauth_session_expires_at = oauth_session_expires_at
|
10
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new("Request Oauth Login but either 'Oauth Client Id' or 'Oauth Secret' were not passed") if
|
8
|
+
self.bearer_token = bearer_token
|
9
|
+
self.oauth_session_expires_at = oauth_session_expires_at
|
10
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new("Request Oauth Login but either 'Oauth Client Id' or 'Oauth Secret' were not passed") if self.bearer_token.blank? && (self.oauth_client_id.blank? || self.oauth_secret.blank?)
|
11
11
|
super
|
12
12
|
end
|
13
13
|
|
@@ -16,10 +16,10 @@ module ZuoraAPI
|
|
16
16
|
get_bearer_token()
|
17
17
|
elsif auth_type == :basic
|
18
18
|
get_bearer_token() if self.oauth_expired?
|
19
|
-
get_z_session()
|
19
|
+
get_z_session() if self.status == 'Active'
|
20
20
|
else
|
21
21
|
get_bearer_token()
|
22
|
-
get_z_session()
|
22
|
+
get_z_session() if self.status == 'Active'
|
23
23
|
end
|
24
24
|
return self.status
|
25
25
|
end
|
@@ -66,6 +66,8 @@ module ZuoraAPI
|
|
66
66
|
|
67
67
|
def get_bearer_token
|
68
68
|
tries ||= 2
|
69
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new("Request Oauth Login but either 'Oauth Client Id' or 'Oauth Secret' were not passed") if self.oauth_client_id.blank? || self.oauth_secret.blank?
|
70
|
+
|
69
71
|
output_json, response = self.rest_call(:method => :post,
|
70
72
|
:url => self.rest_endpoint.chomp('v1/').concat("oauth/token"),
|
71
73
|
:z_session => false,
|
@@ -83,15 +85,19 @@ module ZuoraAPI
|
|
83
85
|
rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
|
84
86
|
self.bearer_token = nil
|
85
87
|
self.oauth_session_expires_at = nil
|
86
|
-
self.current_error =
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
raise ex
|
88
|
+
self.current_error = ex.message
|
89
|
+
case ex.message
|
90
|
+
when "Forbidden"
|
91
|
+
self.current_error = "The user associated to OAuth credential, '#{self.oauth_client_id}', set has been deactivated."
|
92
|
+
self.status = 'Deactivated'
|
92
93
|
else
|
93
|
-
|
94
|
+
self.current_error = "Invalid login, please check client ID and Client Secret or URL endpoint"
|
95
|
+
self.status = 'Invalid Login'
|
94
96
|
end
|
97
|
+
|
98
|
+
return self.status
|
99
|
+
rescue ZuoraAPI::Exceptions::ZuoraAPIError, ZuoraAPI::Exceptions::ZuoraAPIRequestLimit, ZuoraAPI::Exceptions::ZuoraAPILockCompetition => ex
|
100
|
+
raise ex
|
95
101
|
rescue *(CONNECTION_EXCEPTIONS).concat(CONNECTION_READ_EXCEPTIONS) => ex
|
96
102
|
if !(tries -= 1).zero?
|
97
103
|
Rails.logger.info {"#{ex.class} Timed out will retry after 5 seconds"}
|
data/lib/zuora_api/version.rb
CHANGED
data/zuora_api.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zuora_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.00
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zuora Strategic Solutions Group
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -131,7 +131,7 @@ dependencies:
|
|
131
131
|
version: 4.1.0
|
132
132
|
- - "<"
|
133
133
|
- !ruby/object:Gem::Version
|
134
|
-
version: '
|
134
|
+
version: '6'
|
135
135
|
type: :runtime
|
136
136
|
prerelease: false
|
137
137
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -141,7 +141,7 @@ dependencies:
|
|
141
141
|
version: 4.1.0
|
142
142
|
- - "<"
|
143
143
|
- !ruby/object:Gem::Version
|
144
|
-
version: '
|
144
|
+
version: '6'
|
145
145
|
description: Gem that provides easy integration to Zuora
|
146
146
|
email:
|
147
147
|
- connect@zuora.com
|
@@ -186,8 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
186
|
- !ruby/object:Gem::Version
|
187
187
|
version: '0'
|
188
188
|
requirements: []
|
189
|
-
|
190
|
-
rubygems_version: 2.6.8
|
189
|
+
rubygems_version: 3.0.3
|
191
190
|
signing_key:
|
192
191
|
specification_version: 4
|
193
192
|
summary: Gem that provides easy integration to Zuora
|