zuora_api 1.6.255 → 1.7.00
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 +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
|