zuora_api 1.7.66 → 1.7.80

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff05150108e2fbba1a069083c46b53d4b43d95d95d4cfb4bcd82d10881e80091
4
- data.tar.gz: b8543c688b33ee85357716df5e1f93b7cafef3702074914355aa30960b8726dd
3
+ metadata.gz: b0865872f720e280a3a4805d314d27a3e2649b861495f80cf8523f4eb43f2c1e
4
+ data.tar.gz: cc80008e33f6b47245acc1a0b8cdb0ec326f4a714c842e434b25bd5643e94123
5
5
  SHA512:
6
- metadata.gz: 9b2a8309a4a1c88a13be63df6eb96c08d27e25076b379c740b7eddd1898a60f46249388e7279d98e67fd72469e49f1a6abdc5c7f3a62aa32905909c100de46ad
7
- data.tar.gz: 0a706abfa46ed54f332f903a2af7c118dfda2aaa6f61a280b9c2f989fb19790484aefcabed72bbcdc9b5ab37a2befb46913d2771ab6a924095c34ec80a8a595c
6
+ metadata.gz: 051c3a5244695357f0ecf6a42ee1eda7981c0145ed3b50d9e0b751dbbdf6e4aba1d7e36e69eec28056e2fb3b56888c48113699d32ab0f6479272e339b3c1ade2
7
+ data.tar.gz: f20c6fd7e534de55b5b94120e812ba19e18fda5f41e63f8f9183fb66d8ea4a0a01f441918d84196b2aa027724228b63332f54aea94b9515142534d5fff15574c
data/.gitignore CHANGED
@@ -7,4 +7,5 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
- .idea
10
+ .idea
11
+ .DS_Store
@@ -1,21 +1,8 @@
1
- image: ruby:2.6
1
+ image: ruby:2.7
2
2
  stages:
3
- - setup
4
3
  - test
5
4
  - deploy
6
5
 
7
- setup:
8
- stage: setup
9
- allow_failure: true
10
- cache:
11
- key: gems
12
- paths:
13
- - vendor/bundle
14
- script:
15
- - apt-get update -qy
16
- - apt-get install -y nodejs
17
- - bundle install
18
-
19
6
  rubocop-testing:
20
7
  stage: test
21
8
  allow_failure: true
@@ -30,11 +17,24 @@ security-testing:
30
17
  - gem install brakeman
31
18
  - brakeman
32
19
 
33
- rspec-testing:
20
+ ruby:test:
34
21
  stage: test
22
+ cache:
23
+ key: ruby:$RUBY_VERSION-rails:$RAILS_VERSION
24
+ paths:
25
+ - vendor/ruby
26
+ parallel:
27
+ matrix:
28
+ - RUBY_VERSION: "2.7"
29
+ RAILS_VERSION: ["5.0", "5.1", "5.2", "6.0"]
30
+ before_script:
31
+ - bundle config set path 'vendor/ruby'
32
+ - bundle config --global gemfile "gemfiles/Gemfile-rails.$RAILS_VERSION.x"
33
+ - bundle install
35
34
  script:
36
- - bundle install
37
- - rspec
35
+ - bundle exec rails -v
36
+ - bundle exec rspec
37
+ coverage: '/\(\d+.\d+\%\) covered/'
38
38
 
39
39
  rubygems-deploy:
40
40
  stage: deploy
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
-
2
+ ruby "2.7.2"
3
3
  # Specify your gem's dependencies in zuora.gemspec
4
4
  gemspec
@@ -0,0 +1,12 @@
1
+ ---
2
+ apiVersion: backstage.io/v1alpha1
3
+ kind: Component
4
+ metadata:
5
+ annotations:
6
+ backstage.io/techdocs-ref: "gitlab:https://gitlab.zeta.tools/extension-products/shared-libraries/zuora-gem.git"
7
+ description: "Zuora API Rails Gem"
8
+ name: Zuora-Gem
9
+ spec:
10
+ lifecycle: production
11
+ owner: connect@zuora.com
12
+ type: library
@@ -0,0 +1,147 @@
1
+ # Zuora Gem
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/zuora_api.svg)](https://badge.fury.io/rb/zuora_api) [![coverage report](https://gitlab.0.ecc.auw2.zuora/extension-products/shared-libraries/zuora-gem/badges/master/coverage.svg)](https://gitlab.0.ecc.auw2.zuora/extension-products/shared-libraries/zuora-gem/commits/master)
4
+
5
+ ## Installation
6
+ Add this line to your application's Gemfile:
7
+
8
+ ```ruby
9
+ gem 'zuora_api'
10
+ ```
11
+ Then execute `bundle install` in your terminal
12
+
13
+ ## Usage
14
+
15
+ ### Zuora Login Object
16
+ In order to make API calls a Zuora Login object must be created
17
+
18
+ ```ruby
19
+ zuora_client = ZuoraAPI::Login.new(username: "username", password: "password", url: "url")
20
+ ```
21
+
22
+ | Name | Type | Description | Example |
23
+ | ------------------- | ----------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
24
+ | username | `Attribute` | Username to the Zuora environment | `zuora_client.username = "username"` |
25
+ | password | `Attribute` | password to the Zuora environment | `zuora_client.password = "Password"` |
26
+ | url | `Attribute` | Endpoint to the Zuora tenant | `zuora_client.url = "www.zuora.com"` |
27
+ | wsdl_number | `Attribute` | WSDL number of the zuora login | `wsdl = zuora_client.wsdl_number` |
28
+ | status | `Attribute` | Status of the login | `zuora_client.status` |
29
+ | current_session | `Attribute` | Current session for the login | `zuora_client.current_session` |
30
+ | environment | `Attribute` | environment of the login | `zuora_client.environment` |
31
+ | errors | `Attribute` | Any errors that the login has based on the login call | `zuora_client.errors` |
32
+ | current_error | `Attribute` | Current error from the new_session call | `zuora_client.current_error` |
33
+ | user_info | `Attribute` | Information related to the login | `zuora_client.user_info` |
34
+ | tenant_id | `Attribute` | Tenant ID the login is associated to | `zuora_client.tenant_id` |
35
+ | tenant_name | `Attribute` | Tenant Name of tenant the login is associated to | `zuora_client.tenant_name` |
36
+ | entity_id | `Attribute` | Current entity the login session is associated to | `zuora_client.entity_id` |
37
+ | rest_call | `Method` | Executes a REST call | `zuora_client.rest_call()` |
38
+ | soap_call | `Method` | Executes a SOAP call | `output_xml, input_xml = zuora_client.soap_call() do `|xml, args|` xml['ns1'].query do xml['ns1'].queryString "select id, name from account" end end` |
39
+ | query | `Method` | Executes a query call | `zuora_client.query("select id, name from account")` |
40
+ | getDataSourceExport | `Method` | Pulls a data source export with the given query and returns the file location | `zuora_client.getDataSourceExport("select id, name from account")` |
41
+ | describe_call | `Method` | Performs the describe call against the Zuora tenant for all objects or a specific object | `response = zuora_client.describe_call("Account")` |
42
+ | createJournalRun | `Method` | Creates a Journal Run | `zuora_client.createJournalRun(call)` |
43
+ | checkJRStatus | `Method` | Checks the status of a journal run | `zuora_client.checkJRStatus(journal_run_id)` |
44
+ | update_environment | `Method` | Sets the login's environment based on the url | `zuora_client.update_environment` |
45
+ | aqua_endpoint | `Method` | Returns the AQuA endpoint for the login based off the environment | `zuora_client.aqua_endpoint` |
46
+ | rest_endpoint | `Method` | Returns the REST endpoint for the login based off the environment | `zuora_client.rest_endpoint` |
47
+ | fileURL | `Method` | Returns the URL for files | `zuora_client.fileURL` |
48
+ | dateFormat | `Method` | Returns the data format syntax based on the wsdl_number | `zuora_client.dateFormat` |
49
+ | new_session | `Method` | Create a new session | `zuora_client.new_session` |
50
+ | get_session | `Method` | Returns the current session | `zuora_client.get_session`|
51
+
52
+ ## Rest Call
53
+ ```ruby
54
+ zuora_client.rest_call(method: :get, body: {}, url: zuora_client.rest_endpoint("catalog/products?pageSize=4"))
55
+ ```
56
+
57
+ ### Soap Call
58
+ Returns both output and input XML
59
+
60
+ ```ruby
61
+ zuora_client.soap_call(ns1: 'ns1', ns2: 'ns2', batch_size: nil, single_transaction: false)
62
+ ```
63
+
64
+ Example Call
65
+
66
+ ```ruby
67
+ output_xml, input_xml = zuora_client.soap_call() do |xml, args|
68
+ xml['ns1'].query do
69
+ xml['ns1'].queryString "select id, name from account"
70
+ end
71
+ end
72
+ ```
73
+ ### Query
74
+ ```ruby
75
+ zuora_client.query("select id from account")
76
+ ```
77
+ ### Data Export
78
+ Returns the file location of the data source export after downloading from Zuora
79
+
80
+ ```ruby
81
+ zuora_client.getDataSourceExport("select id from account")
82
+ ```
83
+
84
+ | Name | Description | Default | Example |
85
+ | --------- | ---------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------- |
86
+ | query | The query to execute | `N/A` | `zuora_client.getDataSourceExport("select id from account")` |
87
+ | zip | Indicates if the data source export should be a zip | `true` | `zuora_client.getDataSourceExport("select id from account", zip: false)` |
88
+ | extract | Indicates if the data source export should be extracted if it is a zip | `true` | `zuora_client.getDataSourceExport("select id from account", extract: false)` |
89
+ | encrypted | Indicates if the data source export should be encrypted | `false` | `zuora_client.getDataSourceExport("select id from account", encrypted: true)` |
90
+
91
+ ### Describe Call
92
+ This returns all available objects from the describe call as a hash. This response can be accessed by using response["Account"] to retrieve all related data about that object.
93
+
94
+ ```ruby
95
+ response = zuora_client.describe_call("Account")
96
+ ```
97
+ This returns all information and fields related to that object model as a hash.
98
+
99
+ ```ruby
100
+ response = zuora_client.describe_call()
101
+ ```
102
+
103
+ ### Journal Run
104
+ ```ruby
105
+ zuora_client.createJournalRun(call)
106
+ ```
107
+
108
+ ## Insights API
109
+
110
+ In order to make API calls a Zuora Login object must be created by running:
111
+
112
+ ```ruby
113
+ insightsapi = InsightsAPI::Login.new(api_token: "api token", url: "Nw1.api.insights.zuora.com/api/")
114
+ ```
115
+
116
+ Note that the login will default to the insights production url.
117
+
118
+ ```ruby
119
+ Date format: "YYYY-MM-DDT00:00:00Z"
120
+ ```
121
+
122
+ ### Uploading Data into Insights
123
+ ```ruby
124
+ insightsapi.upload_into_insights(dataSourceName, recordType, batchDate, filePath)
125
+ ```
126
+ dataSourceName: What system the data is coming from.
127
+ recordType: The type of records ie: "EVENTS, ATTRIBUTES, and METRICS"
128
+ batachDate: The date the data applies to.
129
+
130
+ ### Describing Insights Data
131
+ ```ruby
132
+ insightsapi.describe(type: "ACCOUNT/USER", object: "ATTRIBUTES/EVENTS/SEGMENTS/METRICS")
133
+ ```
134
+ Returns json payload describing attributes, events, metrics for each Account or User.
135
+
136
+ ### Downloading Data from Insights
137
+ ```ruby
138
+ insightsapi.data_export_insights(objecttype, segmentuuid, startDate: nil, endDate: nil, tries: 30)
139
+ ```
140
+ ```ruby
141
+ insightsapi.data_export_insights_file(objecttype, segmentuuid, startDate: nil, endDate: nil, tries: 30)
142
+ ```
143
+ Both do the same thing except one returns a url(data_export_insights) to download the file yourself and the other returns an actual Ruby temporary file(data_export_insights_file).
144
+
145
+ objectype: "ACCOUNT/USER"
146
+
147
+ segmentuuid: A single or array of string or int of a segment uuid(s) that you get from the describe call. The csv holds a column with a bool that represents if that User or Account belongs to that segment.
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: "../"
4
+
5
+ gem "rails", "~> 5.0.0"
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: "../"
4
+
5
+ gem "rails", "~> 5.1.0"
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: "../"
4
+
5
+ gem "rails", "~> 5.2.0"
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: "../"
4
+
5
+ gem "rails", "~> 6.0.0"
@@ -40,6 +40,19 @@ module ZuoraAPI
40
40
  def to_s
41
41
  @message || @default_message
42
42
  end
43
+
44
+ def parse_message(message)
45
+ case message
46
+ when /^Invalid Oauth Client Id$/, /^Unable to generate token.$/
47
+ @message = "Invalid login, please check client ID and Client Secret or URL endpoint"
48
+ when /^Forbidden$/
49
+ @message = "The user associated to OAuth credential set has been deactivated."
50
+ when /^Invalid login. User name and password do not match.$/
51
+ @message = "Invalid login, please check username and password or URL endpoint"
52
+ else
53
+ @message = message
54
+ end
55
+ end
43
56
  end
44
57
 
45
58
  class BadEntityError < Error
@@ -177,14 +190,15 @@ module ZuoraAPI
177
190
  end
178
191
 
179
192
  class ZuoraAPITemporaryError < Error
180
- attr_reader :code, :response
193
+ attr_reader :code, :response, :errors
181
194
  attr_writer :default_message
182
195
 
183
- def initialize(message = nil,response=nil, errors = [], successes = [], *args)
196
+ def initialize(message = nil, response = nil, errors = [], successes = [], *args)
184
197
  @code = response.class.to_s == "HTTParty::Response" ? response.code : nil
185
198
  @message = parse_message(message)
186
199
  @response = response
187
200
  @default_message = "There is a temporary error with zuora system."
201
+ @errors = errors
188
202
  end
189
203
 
190
204
  def to_s
@@ -7,7 +7,7 @@ module ZuoraAPI
7
7
  class Login
8
8
  ENVIRONMENTS = [TEST = 'Test', SANDBOX = 'Sandbox', PRODUCTION = 'Production', PREFORMANCE = 'Preformance', SERVICES = 'Services', UNKNOWN = 'Unknown', STAGING = 'Staging' ]
9
9
  REGIONS = [EU = 'EU', US = 'US', NA = 'NA' ]
10
- MIN_Endpoint = '96.0'
10
+ MIN_Endpoints = {'Test': '107.0', 'Sandbox': '107.0', 'Production': '107.0', 'Performance': '107.0', 'Services': '96.0', 'Unknown': '96.0', 'Staging': '107.0'}.freeze
11
11
  XML_SAVE_OPTIONS = Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
12
12
 
13
13
  CONNECTION_EXCEPTIONS = [
@@ -39,8 +39,8 @@ module ZuoraAPI
39
39
 
40
40
  ZUORA_SERVER_ERRORS = [
41
41
  ZuoraAPI::Exceptions::ZuoraAPIInternalServerError,
42
- ZuoraAPI::Exceptions::ZuoraAPIConnectionTimeout,
43
- ZuoraAPI::Exceptions::ZuoraAPIReadTimeout,
42
+ ZuoraAPI::Exceptions::ZuoraAPIConnectionTimeout,
43
+ ZuoraAPI::Exceptions::ZuoraAPIReadTimeout,
44
44
  ZuoraAPI::Exceptions::ZuoraUnexpectedError
45
45
  ].freeze
46
46
 
@@ -50,10 +50,12 @@ module ZuoraAPI
50
50
  raise "URL is nil or empty, but URL is required" if url.nil? || url.empty?
51
51
  # raise "URL is improper. URL must contain zuora.com, zuora.eu, or zuora.na" if /zuora.com|zuora.eu|zuora.na/ === url
52
52
  self.hostname = /(?<=https:\/\/|http:\/\/)(.*?)(?=\/|$)/.match(url)[0] if !/(?<=https:\/\/|http:\/\/)(.*?)(?=\/|$)/.match(url).nil?
53
+ self.update_environment
54
+ min_endpoint = MIN_Endpoints[self.environment.to_sym]
53
55
  if !/apps\/services\/a\/\d+\.\d$/.match(url.strip)
54
- self.url = "https://#{hostname}/apps/services/a/#{MIN_Endpoint}"
55
- elsif MIN_Endpoint.to_f > url.scan(/(\d+\.\d)$/).dig(0,0).to_f
56
- self.url = url.gsub(/(\d+\.\d)$/, MIN_Endpoint)
56
+ self.url = "https://#{hostname}/apps/services/a/#{min_endpoint}"
57
+ elsif min_endpoint.to_f > url.scan(/(\d+\.\d)$/).dig(0,0).to_f
58
+ self.url = url.gsub(/(\d+\.\d)$/, min_endpoint)
57
59
  else
58
60
  self.url = url
59
61
  end
@@ -65,36 +67,18 @@ module ZuoraAPI
65
67
  self.status = status.blank? ? "Active" : status
66
68
  self.user_info = Hash.new
67
69
  self.update_region
68
- self.update_environment
69
70
  self.update_zconnect_provider
70
71
  @timeout_sleep = 5
71
72
  end
72
73
 
73
74
  def get_identity(cookies)
74
75
  zsession = cookies["ZSession"]
75
- zconnect_accesstoken = get_zconnect_accesstoken(cookies)
76
76
  begin
77
77
  if !zsession.blank?
78
78
  response = HTTParty.get("https://#{self.hostname}/apps/v1/identity", :headers => {'Cookie' => "ZSession=#{zsession}", 'Content-Type' => 'application/json'})
79
79
  output_json = JSON.parse(response.body)
80
- elsif zconnect_accesstoken.present?
81
- begin
82
- code = zconnect_accesstoken.split("#!").last
83
- encrypted_token, tenant_id = Base64.decode64(code).split(":")
84
- body = {'token' => encrypted_token}.to_json
85
- rescue => ex
86
- raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Invalid ZConnect Cookie")
87
- end
88
- Rails.logger.info("Using ZConnect cookie in get_identity method")
89
-
90
- response = HTTParty.post("https://#{self.hostname}/apps/zconnectsession/identity", :body => body, :headers => { 'Content-Type' => 'application/json' })
91
- output_json = JSON.parse(response.body)
92
80
  else
93
- if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
94
- raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}")
95
- else
96
- raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
97
- end
81
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
98
82
  end
99
83
  rescue JSON::ParserError => ex
100
84
  output_json = {}
@@ -105,21 +89,12 @@ module ZuoraAPI
105
89
 
106
90
  def get_full_nav(cookies)
107
91
  zsession = cookies["ZSession"]
108
- zconnect_accesstoken = get_zconnect_accesstoken(cookies)
109
92
  begin
110
93
  if zsession.present?
111
94
  response = HTTParty.get("https://#{self.hostname}/apps/v1/navigation", :headers => {'Cookie' => "ZSession=#{zsession}", 'Content-Type' => 'application/json'})
112
95
  output_json = JSON.parse(response.body)
113
- elsif zconnect_accesstoken.present?
114
- Rails.logger.info("Using ZConnect cookie in get_full_nav method")
115
- response = HTTParty.get("https://#{self.hostname}/apps/zconnectsession/navigation", :headers => {'Cookie' => "#{self.zconnect_provider}=#{zconnect_accesstoken}",'Content-Type' => 'application/json'})
116
- output_json = JSON.parse(response.body)
117
96
  else
118
- if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
119
- raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}")
120
- else
121
- raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
122
- end
97
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
123
98
  end
124
99
  rescue JSON::ParserError => ex
125
100
  output_json = {}
@@ -130,21 +105,12 @@ module ZuoraAPI
130
105
 
131
106
  def set_nav(state, cookies)
132
107
  zsession = cookies["ZSession"]
133
- zconnect_accesstoken = get_zconnect_accesstoken(cookies)
134
108
  begin
135
109
  if !zsession.blank?
136
110
  response = HTTParty.put("https://#{self.hostname}/apps/v1/preference/navigation", :body => state.to_json, :headers => {'Cookie' => "ZSession=#{zsession}", 'Content-Type' => 'application/json'})
137
111
  output_json = JSON.parse(response.body)
138
- elsif !zconnect_accesstoken.blank?
139
- Rails.logger.info("Using ZConnect cookie in set_nav method")
140
- response = HTTParty.post("https://#{self.hostname}/apps/zconnectsession/navigationstate", :body => state.to_json, :headers => {'Cookie' => "#{self.zconnect_provider}=#{zconnect_accesstoken}", 'Content-Type' => 'application/json'})
141
- output_json = JSON.parse(response.body)
142
112
  else
143
- if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
144
- raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}")
145
- else
146
- raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
147
- end
113
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
148
114
  end
149
115
  rescue JSON::ParserError => ex
150
116
  output_json = {}
@@ -155,21 +121,12 @@ module ZuoraAPI
155
121
 
156
122
  def refresh_nav(cookies)
157
123
  zsession = cookies["ZSession"]
158
- zconnect_accesstoken = get_zconnect_accesstoken(cookies)
159
124
  begin
160
125
  if !zsession.blank?
161
126
  response = HTTParty.post("https://#{self.hostname}/apps/v1/navigation/fetch", :headers => {'Cookie' => "ZSession=#{zsession}", 'Content-Type' => 'application/json'})
162
127
  output_json = JSON.parse(response.body)
163
- elsif !zconnect_accesstoken.blank?
164
- Rails.logger.info("Using ZConnect cookie in refresh_nav method")
165
- response = HTTParty.post("https://#{self.hostname}/apps/zconnectsession/refresh-navbarcache", :headers => {'Cookie' => "#{self.zconnect_provider}=#{zconnect_accesstoken}", 'Content-Type' => 'application/json'})
166
- output_json = JSON.parse(response.body)
167
128
  else
168
- if zconnect_accesstoken.blank? && cookies.keys.any? { |x| x.include? "ZConnect"}
169
- raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZConnect cookie present matching #{self.hostname}")
170
- else
171
- raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
172
- end
129
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("No ZSession cookie present")
173
130
  end
174
131
  rescue JSON::ParserError => ex
175
132
  output_json = {}
@@ -178,15 +135,6 @@ module ZuoraAPI
178
135
  return output_json
179
136
  end
180
137
 
181
- def get_zconnect_accesstoken(cookies)
182
- accesstoken = nil
183
- self.update_zconnect_provider
184
- if !cookies[self.zconnect_provider].nil? && !cookies[self.zconnect_provider].empty?
185
- accesstoken = cookies[self.zconnect_provider]
186
- end
187
- return accesstoken
188
- end
189
-
190
138
  def reporting_url(path)
191
139
  map = {"US" => {"Sandbox" => "https://zconnectsandbox.zuora.com/api/rest/v1/",
192
140
  "Production" => "https://zconnect.zuora.com/api/rest/v1/",
@@ -208,7 +156,7 @@ module ZuoraAPI
208
156
  # 1. Pass in cookies and optionally custom_authorities, name, and description
209
157
  # 2. Pass in user_id, entity_ids, client_id, client_secret, and optionally custom_authorities, name, and description
210
158
  # https://intranet.zuora.com/confluence/display/Sunburst/Create+an+OAuth+Client+through+API+Gateway#CreateanOAuthClientthroughAPIGateway-ZSession
211
- def get_oauth_client (custom_authorities = [], info_name: "No Name", info_desc: "This client was created without a description.", user_id: nil, entity_ids: nil, client_id: nil, client_secret: nil, new_client_id: nil, new_client_secret: nil, cookies: nil)
159
+ def get_oauth_client (custom_authorities = [], info_name: "No Name", info_desc: "This client was created without a description.", user_id: nil, entity_ids: nil, client_id: nil, client_secret: nil, new_client_id: nil, new_client_secret: nil, cookies: nil, chomp_v1_from_genesis_endpoint: false, use_api_generated_client_secret: false)
212
160
  authorization = ""
213
161
  new_client_id = SecureRandom.uuid if new_client_id.blank?
214
162
  new_client_secret = SecureRandom.hex(10) if new_client_secret.blank?
@@ -234,11 +182,11 @@ module ZuoraAPI
234
182
  end
235
183
 
236
184
  if !authorization.blank? && !user_id.blank? && !entity_ids.blank?
237
- endpoint = self.rest_endpoint("genesis/clients")
185
+ endpoint = chomp_v1_from_genesis_endpoint ? self.rest_endpoint.chomp("v1/").concat("genesis/clients") : self.rest_endpoint("genesis/clients")
238
186
  oauth_response = HTTParty.post(endpoint, :headers => {'authorization' => authorization, 'Content-Type' => 'application/json'}, :body => {'clientId' => new_client_id, 'clientSecret' => new_client_secret, 'userId' => user_id, 'entityIds' => entity_ids, 'customAuthorities' => custom_authorities, 'additionalInformation' => {'description' => info_desc, 'name' => info_name}}.to_json)
239
187
  output_json = JSON.parse(oauth_response.body)
240
188
  if oauth_response.code == 201
241
- output_json["clientSecret"] = new_client_secret
189
+ output_json["clientSecret"] = new_client_secret if !use_api_generated_client_secret
242
190
  return output_json
243
191
  elsif oauth_response.code == 401 && !oauth_response.message.blank?
244
192
  raise ZuoraAPI::Exceptions::ZuoraAPIError.new(output_json["message"], oauth_response)
@@ -305,7 +253,7 @@ module ZuoraAPI
305
253
  end
306
254
 
307
255
  def update_environment
308
- if !self.url.blank?
256
+ if !self.hostname.blank?
309
257
  case self.hostname
310
258
  when /(?<=\.|\/|-|^)(apisandbox|sandbox)(?=\.|\/|-|$)/
311
259
  self.environment = 'Sandbox'
@@ -328,13 +276,13 @@ module ZuoraAPI
328
276
  end
329
277
 
330
278
  def update_zconnect_provider
331
- region = update_region
332
- environment = update_environment
279
+ update_region if self.region.blank?
280
+ update_environment if self.environment.blank?
333
281
  mappings = {"US" => {"Sandbox" => "ZConnectSbx", "Services" => "ZConnectSvcUS", "Production" => "ZConnectProd", "Performance" => "ZConnectPT1", "Test" => "ZConnectTest", "Staging" => "ZConnectQA", "KubeSTG" => "ZConnectDev", "KubeDEV" => "ZConnectDev", "KubePROD" => "ZConnectDev"},
334
282
  "NA" => {"Sandbox" => "ZConnectSbxNA", "Services" => "ZConnectSvcNA", "Production" => "ZConnectProdNA", "Performance" => "ZConnectPT1NA"},
335
283
  "EU" => {"Sandbox" => "ZConnectSbxEU", "Services" => "ZConnectSvcEU", "Production" => "ZConnectProdEU", "Performance" => "ZConnectPT1EU", "Test" => "ZConnectTest"},
336
284
  "Unknown" => {"Unknown" => "Unknown"}}
337
- self.zconnect_provider = mappings[region][environment]
285
+ self.zconnect_provider = mappings[self.region][self.environment]
338
286
  end
339
287
 
340
288
  def aqua_endpoint(url="")
@@ -374,8 +322,8 @@ module ZuoraAPI
374
322
  return domain ? endpoint.concat(prefix).concat(url) : prefix.concat(url)
375
323
  end
376
324
 
377
- def rest_domain
378
- return URI(self.rest_endpoint).host
325
+ def rest_domain(endpoint: self.rest_endpoint)
326
+ return URI(endpoint).host
379
327
  end
380
328
 
381
329
  def fileURL(url="")
@@ -387,10 +335,41 @@ module ZuoraAPI
387
335
  end
388
336
 
389
337
  def new_session(auth_type: :basic, debug: false, zuora_track_id: nil)
338
+ retries ||= 2
339
+ yield
340
+
341
+ rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
342
+ self.status = 'Invalid'
343
+ self.current_error = ex.message
344
+ raise
345
+ rescue ZuoraAPI::Exceptions::ZuoraAPIError => ex
346
+ raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(ex.message, ex.response)
347
+
348
+ rescue ZuoraAPI::Exceptions::ZuoraAPIInternalServerError => ex
349
+ raise ex if retries.zero?
350
+
351
+ retries -= 1
352
+ sleep(self.timeout_sleep)
353
+ retry
354
+
355
+ rescue *(CONNECTION_EXCEPTIONS + CONNECTION_READ_EXCEPTIONS) => ex
356
+ self.log(location: "BasicLogin", exception: ex, message: "Timed out", level: :error)
357
+
358
+ self.current_error = "Request timed out. Try again"
359
+ self.status = 'Timeout'
360
+
361
+ raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error)
362
+
363
+ rescue EOFError
364
+ if self.url.match?(/.*services\d{1,}.zuora.com*/)
365
+ self.current_error = "Services tenant '#{self.url.scan(/.*\/\/(services\d{1,}).zuora.com*/).last.first}' is no longer available."
366
+ self.status = 'Not Available'
367
+ raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error)
368
+ end
369
+
390
370
  end
391
371
 
392
372
  def get_session(prefix: false, auth_type: :basic, zuora_track_id: nil)
393
- Rails.logger.debug("Get session for #{auth_type} - #{self.class.to_s}") if Rails.env.to_s == 'development'
394
373
  case auth_type
395
374
  when :basic
396
375
  if self.current_session.blank?
@@ -399,14 +378,13 @@ module ZuoraAPI
399
378
  if self.bearer_token.blank? || self.oauth_expired?
400
379
  self.new_session(auth_type: :bearer, zuora_track_id: zuora_track_id)
401
380
  end
402
- self.get_z_session(zuora_track_id: zuora_track_id) if self.status == 'Active'
381
+ self.get_z_session(zuora_track_id: zuora_track_id)
403
382
  when 'ZuoraAPI::Basic'
404
383
  self.new_session(auth_type: :basic, zuora_track_id: zuora_track_id)
405
384
  else
406
385
  self.new_session(auth_type: :basic, zuora_track_id: zuora_track_id)
407
386
  end
408
387
  end
409
- raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error) if self.status != 'Active'
410
388
  return prefix ? "ZSession #{self.current_session}" : self.current_session.to_s
411
389
  when :bearer
412
390
  case self.class.to_s
@@ -419,8 +397,6 @@ module ZuoraAPI
419
397
  else
420
398
  raise ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError.new("Unknown Login, does not support Authentication of Type: #{auth_type}")
421
399
  end
422
-
423
- raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error) if self.status != 'Active'
424
400
  return prefix ? "Bearer #{self.bearer_token}" : self.bearer_token.to_s
425
401
  end
426
402
  end
@@ -428,16 +404,18 @@ module ZuoraAPI
428
404
  def soap_call(
429
405
  ns1: 'ns1',
430
406
  ns2: 'ns2',
431
- batch_size: nil,
407
+ batch_size: nil,
408
+ headers: {},
432
409
  single_transaction: false,
433
410
  debug: false,
434
411
  zuora_track_id: nil,
435
412
  errors: [ZuoraAPI::Exceptions::ZuoraAPISessionError].concat(ZUORA_API_ERRORS),
436
413
  z_session: true,
437
414
  timeout_retry: false,
438
- timeout: 120,
415
+ timeout: 130,
439
416
  timeout_sleep_interval: self.timeout_sleep,
440
417
  output_exception_messages: true,
418
+ skip_session: false,
441
419
  **keyword_args)
442
420
  tries ||= 2
443
421
  xml = Nokogiri::XML::Builder.new do |xml|
@@ -447,8 +425,10 @@ module ZuoraAPI
447
425
  'xmlns:api' => "http://api.zuora.com/",
448
426
  "xmlns:#{ns1}" => "http://api.zuora.com/") do
449
427
  xml['SOAP-ENV'].Header do
450
- xml["#{ns1}"].SessionHeader do
451
- xml["#{ns1}"].session self.get_session(prefix: false, auth_type: :basic, zuora_track_id: zuora_track_id)
428
+ if !skip_session
429
+ xml["#{ns1}"].SessionHeader do
430
+ xml["#{ns1}"].session self.get_session(prefix: false, auth_type: :basic, zuora_track_id: zuora_track_id)
431
+ end
452
432
  end
453
433
  if single_transaction
454
434
  xml["#{ns1}"].CallOptions do
@@ -466,12 +446,11 @@ module ZuoraAPI
466
446
  end
467
447
  end
468
448
  end
469
-
470
449
  input_xml = Nokogiri::XML(xml.to_xml(:save_with => XML_SAVE_OPTIONS).strip)
471
450
  input_xml.xpath('//ns1:session', 'ns1' =>'http://api.zuora.com/').children.remove
472
451
  Rails.logger.debug("Request SOAP XML: #{input_xml.to_xml(:save_with => XML_SAVE_OPTIONS).strip}") if debug
473
452
 
474
- headers = { 'Content-Type' => "text/xml; charset=utf-8", 'Accept' => 'text/xml'}
453
+ headers.merge!({ 'Content-Type' => "text/xml; charset=utf-8", 'Accept' => 'text/xml'})
475
454
  headers['Zuora-Track-Id'] = zuora_track_id if zuora_track_id.present?
476
455
 
477
456
  request = HTTParty::Request.new(
@@ -488,7 +467,11 @@ module ZuoraAPI
488
467
  Rails.logger.debug("Response SOAP XML: #{output_xml.to_xml(:save_with => XML_SAVE_OPTIONS).strip}") if debug
489
468
 
490
469
  raise_errors(type: :SOAP, body: output_xml, response: response)
470
+
471
+ return output_xml, input_xml, response
472
+
491
473
  rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
474
+ raise if skip_session
492
475
  if !tries.zero? && z_session
493
476
  tries -= 1
494
477
  Rails.logger.debug("SOAP Call - Session Invalid")
@@ -500,39 +483,33 @@ module ZuoraAPI
500
483
  end
501
484
 
502
485
  retry
503
- else
504
- if errors.include?(ex.class)
505
- raise ex
506
- else
507
- return output_xml, input_xml, response
508
- end
509
486
  end
487
+
488
+ raise ex if errors.include?(ex.class)
489
+
490
+ return output_xml, input_xml, response
491
+
510
492
  rescue *ZUORA_API_ERRORS => ex
511
- if errors.include?(ex.class)
512
- raise ex
513
- else
514
- response = ex.response unless response
515
- return output_xml, input_xml, response
516
- end
493
+ raise ex if errors.include?(ex.class)
494
+
495
+ response = ex.response unless response
496
+ return output_xml, input_xml, response
497
+
517
498
  rescue *CONNECTION_EXCEPTIONS => ex
518
- if tries.zero?
519
- if output_exception_messages
520
- if Rails.logger.class.to_s == "Ougai::Logger"
521
- Rails.logger.error("SOAP Call - Timed out will retry after #{timeout_sleep_interval} seconds", ex)
522
- else
523
- Rails.logger.error("SOAP Call - #{ex.class} Timed out will retry after #{timeout_sleep_interval} seconds")
524
- end
525
- end
526
- raise ex
499
+ if !tries.zero?
500
+ tries -= 1
501
+ self.log(location: "SOAP Call", exception: ex, message: "Timed out will retry after #{timeout_sleep_interval} seconds", level: :debug)
502
+ sleep(timeout_sleep_interval)
503
+ retry
527
504
  end
528
505
 
529
- tries -= 1
530
- sleep(timeout_sleep_interval)
531
- retry
506
+ self.log(location: "SOAP Call", exception: ex, message: "Timed out", level: :error) if output_exception_messages
507
+ raise ex
508
+
532
509
  rescue *CONNECTION_READ_EXCEPTIONS => ex
533
510
  if !tries.zero?
534
511
  tries -= 1
535
-
512
+ self.log(location: "SOAP Call", exception: ex, message: "Timed out will retry after #{timeout_sleep_interval} seconds", level: :debug)
536
513
  if ex.is_a?(Errno::ECONNRESET) && ex.message.include?('SSL_connect')
537
514
  retry
538
515
  elsif timeout_retry
@@ -541,19 +518,74 @@ module ZuoraAPI
541
518
  end
542
519
  end
543
520
 
544
- if output_exception_messages
545
- if Rails.logger.class.to_s == "Ougai::Logger"
546
- Rails.logger.error("SOAP Call - Timed out will retry after #{timeout_sleep_interval} seconds", ex)
547
- else
548
- Rails.logger.error("SOAP Call - #{ex.class} Timed out will retry after #{timeout_sleep_interval} seconds")
549
- end
550
- end
551
- raise ZuoraAPI::Exceptions::ZuoraAPIReadTimeout.new("Received read timeout from #{url}", nil, request) if ex.instance_of?(Net::ReadTimeout)
521
+ self.log(location: "SOAP Call", exception: ex, message: "Timed out", level: :error) if output_exception_messages
522
+ ex = ZuoraAPI::Exceptions::ZuoraAPIReadTimeout.new("Received read timeout from 'https://#{rest_domain(endpoint: url)}'", nil, request) if ex.instance_of?(Net::ReadTimeout)
552
523
  raise ex
524
+
553
525
  rescue => ex
554
526
  raise ex
555
- else
556
- return output_xml, input_xml, response
527
+ ensure
528
+ self.error_logger(ex) if defined?(ex) && Rails.logger.class.to_s == "Ougai::Logger"
529
+ end
530
+
531
+ def error_logger(ex)
532
+ exception_args = Rails.logger.with_fields.merge(self.exception_args(ex))
533
+ case ex
534
+ when ZuoraAPI::Exceptions::ZuoraAPIUnkownError, ZuoraAPI::Exceptions::ZuoraDataIntegrity
535
+ Rails.logger.error('Zuora Unknown/Integrity Error', ex, exception_args)
536
+ when ZuoraAPI::Exceptions::ZuoraAPIRequestLimit
537
+ Rails.logger.info('Zuora APILimit Reached', ex, exception_args)
538
+ when *(ZuoraAPI::Login::ZUORA_API_ERRORS-ZuoraAPI::Login::ZUORA_SERVER_ERRORS)
539
+ #Rails.logger.debug('Zuora API Error', ex, self.exception_args(ex))
540
+ when *ZuoraAPI::Login::ZUORA_SERVER_ERRORS
541
+ Rails.logger.error('Zuora Server Error', ex, exception_args)
542
+ end
543
+ end
544
+
545
+ def log(location: "Rest Call", exception: nil, message: "Timed out will retry after #{self.timeout_sleep} seconds", level: :info )
546
+ level = :debug if ![:debug, :info, :warn, :error, :fatal].include?(level)
547
+ if Rails.logger.class.to_s == "Ougai::Logger"
548
+ Rails.logger.send(level.to_sym, "#{location} - #{message}", exception)
549
+ else
550
+ Rails.logger.send(level.to_sym, "#{location} - #{exception.class} #{message}")
551
+ end
552
+ end
553
+
554
+ def exception_args(ex)
555
+ args = {}
556
+ if defined?(ex.response) && ex.response.present?
557
+ args.merge!({
558
+ request: {
559
+ path: ex.response.request.path.to_s,
560
+ method: ex.response.request.http_method.to_s.split("Net::HTTP::").last.upcase,
561
+ params: ex.response.request.raw_body.to_s,
562
+ headers: ex.response.request.options[:headers].map{|k,v| [k.to_s, k.to_s.downcase.strip == "authorization" ? "VALUE FILTERED" : v]}.to_h.to_s,
563
+ },
564
+ response: {
565
+ status: ex.response.code,
566
+ params: ex.response.body.to_s,
567
+ headers: ex.response.headers.to_s,
568
+ },
569
+ zuora_trace_id: ex.response.headers["zuora-request-id"],
570
+ zuora_track_id: ex.response.request.options[:headers]["Zuora-Track-Id"],
571
+ })
572
+ elsif defined?(ex.request) && ex.request.present?
573
+ args.merge!({
574
+ request: {
575
+ path: ex.request.path.to_s,
576
+ method: ex.request.http_method.to_s.split("Net::HTTP::").last.upcase,
577
+ params: ex.request.options[:body],
578
+ headers: ex.request.options[:headers].map{|k,v| [k.to_s, k.to_s.downcase.strip == "authorization" ? "VALUE FILTERED" : v]}.to_h.to_s
579
+ }
580
+ })
581
+ args.merge!({
582
+ zuora_track_id: ex.request.options[:headers]["Zuora-Track-Id"]
583
+ }) if ex.request.options[:headers]["Zuora-Track-Id"].present?
584
+ end
585
+ rescue => ex
586
+ Rails.logger.error("Failed to create exception arguments", ex, args)
587
+ ensure
588
+ return args
557
589
  end
558
590
 
559
591
  def raise_errors(type: :SOAP, body: nil, response: nil)
@@ -570,13 +602,13 @@ module ZuoraAPI
570
602
  end
571
603
 
572
604
  if [502,503].include?(response.code)
573
- raise ZuoraAPI::Exceptions::ZuoraAPIConnectionTimeout.new("Received #{response.code} from #{request_uri}", response)
605
+ raise ZuoraAPI::Exceptions::ZuoraAPIConnectionTimeout.new("Received #{response.code} from 'https://#{rest_domain(endpoint: request_uri)}'", response)
574
606
  end
575
607
 
576
608
  # Check failure response code
577
609
  case response.code
578
610
  when 504
579
- raise ZuoraAPI::Exceptions::ZuoraAPIReadTimeout.new("Received 504 from #{request_uri}", response)
611
+ raise ZuoraAPI::Exceptions::ZuoraAPIReadTimeout.new("Received 504 from 'https://#{rest_domain(endpoint: request_uri)}'", response)
580
612
  when 429
581
613
  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)
582
614
  when 401
@@ -597,6 +629,10 @@ module ZuoraAPI
597
629
  when :SOAP
598
630
  error, success, message = get_soap_error_and_message(body)
599
631
 
632
+ if body.xpath('//fns:LoginFault', 'fns' =>'http://fault.api.zuora.com/').present?
633
+ raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(message, response)
634
+ end
635
+
600
636
  if body.xpath('//ns1:queryResponse', 'ns1' => 'http://api.zuora.com/').present? &&
601
637
  body.xpath(
602
638
  '//ns1:records[@xsi:type="ns2:Export"]',
@@ -604,12 +640,12 @@ module ZuoraAPI
604
640
  ).present?
605
641
  result = body.xpath('//ns2:Status', 'ns2' => 'http://object.api.zuora.com/').text
606
642
  if result == 'Failed'
607
- reason = body.xpath('//ns2:StatusReason', 'ns2' => 'http://object.api.zuora.com/').text
608
- if reason.present?
609
- message = body.xpath('//ns2:StatusReason', 'ns2' => 'http://object.api.zuora.com/').text
610
- error = message.match(/^[\w\d]{16}\: (Unexpected error.|No HTTP Response|Socket Timeout|There is an internal error, please try again later)/).present? ? 'UNEXPECTED_ERROR' : 'FATAL_ERROR'
643
+ message = body.xpath('//ns2:StatusReason', 'ns2' => 'http://object.api.zuora.com/').text
644
+ error = 'FATAL_ERROR'
645
+ if message.present?
646
+ identifier, new_message = message.scan(/^([\w\d]{16})\: (.*)/).first
647
+ error, message = ['UNEXPECTED_ERROR', new_message] if new_message.present?
611
648
  else
612
- error = 'FATAL_ERROR'
613
649
  message = 'Export failed due to unknown reason. Consult api logs.'
614
650
  end
615
651
  end
@@ -658,14 +694,31 @@ module ZuoraAPI
658
694
  when /^GET::400::\/api\/rest\/v1\/reports\/(reportlabels\/)?([a-zA-Z0-9\-_]+)\/report-details$/ # Get report, capture of the id is present if needed in future error responses.
659
695
  raise ZuoraAPI::Exceptions::ZuoraAPIError.new(reporting_message, response) if reporting_message.present?
660
696
  end
697
+ when /\/objects\/batch\//
698
+ if body['code'].present? && /61$/.match(body['code'].to_s).present? # if last 2 digits of code are 61
699
+ raise ZuoraAPI::Exceptions::ZuoraAPITemporaryError.new(body['message'], nil, body['details'])
700
+ end
701
+ when /^\/api\/v1\/payment_plans.*/
702
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new(body['error'], response) if body['error']
661
703
  end
662
704
 
663
705
  body = body.dig("results").present? ? body["results"] : body if body.class == Hash
664
706
  if body.class == Hash && (!body["success"] || !body["Success"] || response.code != 200)
665
- messages_array = body.fetch("reasons", []).map {|error| error['message']}.compact
666
- messages_array = messages_array.push(body.dig("error", 'message')).compact if body.dig('error').class == Hash
667
- codes_array = body.fetch("reasons", []).map {|error| error['code']}.compact
668
- codes_array = codes_array.push(body.dig("error", 'code')).compact if body.dig('error').class == Hash
707
+ reason_keys = %w(reasons errors)
708
+ message_keys = %w(message title)
709
+ messages_array, codes_array = [[],[]]
710
+ reason_keys.each do |rsn_key|
711
+ message_keys.each do |msg_key|
712
+ messages_array = body.fetch(rsn_key, []).map {|error| error[msg_key]}.compact
713
+ break if messages_array.present?
714
+ end
715
+ codes_array = body.fetch(rsn_key, []).map {|error| error['code']}.compact
716
+ break if messages_array.present? && codes_array.present?
717
+ end
718
+ if body.dig('error').class == Hash
719
+ messages_array = messages_array.push(body.dig("error", 'message')).compact
720
+ codes_array = codes_array.push(body.dig("error", 'code')).compact
721
+ end
669
722
 
670
723
  if body['message'] == 'request exceeded limit'
671
724
  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)
@@ -697,7 +750,11 @@ module ZuoraAPI
697
750
  end
698
751
 
699
752
  if body['error'] == 'Unauthorized' && body['status'] == 401
700
- raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{messages_array.join(', ')}", response)
753
+ if body['message'].present?
754
+ raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(body['message'], response)
755
+ else
756
+ raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new("#{messages_array.join(', ')}", response)
757
+ end
701
758
  end
702
759
  #Authentication failed
703
760
  if (codes_array.map{|code| code.to_s.slice(6,7).to_i}.include?(11) || response.code == 401) && !codes_array.include?(422)
@@ -804,7 +861,7 @@ module ZuoraAPI
804
861
  output_json = JSON.parse(response.body)
805
862
  self.raise_errors(type: :JSON, body: output_json, response: response)
806
863
 
807
- elsif (response_content_types.include?('application/xml') || response_content_types.include?('text/xml')) and type != :xml
864
+ elsif (response_content_types.include?('application/xml') || response_content_types.include?('text/xml') || response_content_types.include?('application/soap+xml')) and type != :xml
808
865
  output_xml = Nokogiri::XML(response.body)
809
866
  self.raise_errors(type: :SOAP, body: output_xml, response: response)
810
867
 
@@ -824,6 +881,8 @@ module ZuoraAPI
824
881
  raise ZuoraAPI::Exceptions::ZuoraAPIConnectionTimeout.new(error_message, response)
825
882
  when /Client sent a bad request./, /Bad Request/, /403 Forbidden/
826
883
  raise ZuoraAPI::Exceptions::ZuoraAPIInternalServerError.new(error_message, response)
884
+ when /414 Request-URI Too Large/
885
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Request URL is too long", response)
827
886
  else
828
887
  raise ZuoraAPI::Exceptions::ZuoraAPIInternalServerError.new(error_message, response)
829
888
  end
@@ -850,6 +909,11 @@ module ZuoraAPI
850
909
  message = body.xpath('//ns1:Message', 'ns1' =>'http://api.zuora.com/').text
851
910
  end
852
911
 
912
+ if error.blank? || message.blank?
913
+ error = body.xpath('//soapenv:Value', 'soapenv'=>'http://www.w3.org/2003/05/soap-envelope').text
914
+ message = body.xpath('//soapenv:Text', 'soapenv'=>'http://www.w3.org/2003/05/soap-envelope').text
915
+ end
916
+
853
917
  #Update/Create/Delete Calls with multiple requests and responses
854
918
  if body.xpath('//ns1:result', 'ns1' =>'http://api.zuora.com/').size > 0 && body.xpath('//ns1:Errors', 'ns1' =>'http://api.zuora.com/').size > 0
855
919
  error = []
@@ -893,17 +957,22 @@ module ZuoraAPI
893
957
  raise ZuoraAPI::Exceptions::ZuoraAPIUnkownError.new(message, response, errors, success)
894
958
  end
895
959
  raise ZuoraAPI::Exceptions::ZuoraAPIError.new(message, response, errors, success)
896
- when /invalid/, /^DUPLICATE_VALUE/, /^REQUEST_REJECTED/, /INVALID_ID/, /MAX_RECORDS_EXCEEDED/, /INVALID_FIELD/, /MALFORMED_QUERY/, /NO_PERMISSION/, /PDF_QUERY_ERROR/, /MISSING_REQUIRED_VALUE/, /INVALID_TYPE/, /TRANSACTION_FAILED/, /API_DISABLED/, /CANNOT_DELETE/, /ACCOUNTING_PERIOD_CLOSED/
960
+ when /^INVALID_VERSION/, /invalid/, /^DUPLICATE_VALUE/, /^REQUEST_REJECTED/, /INVALID_ID/, /MAX_RECORDS_EXCEEDED/, /INVALID_FIELD/, /MALFORMED_QUERY/, /NO_PERMISSION/, /PDF_QUERY_ERROR/, /MISSING_REQUIRED_VALUE/, /INVALID_TYPE/, /TRANSACTION_FAILED/, /API_DISABLED/, /CANNOT_DELETE/, /ACCOUNTING_PERIOD_CLOSED/
897
961
  raise ZuoraAPI::Exceptions::ZuoraAPIError.new(message, response, errors, success)
898
962
  when /.*UNEXPECTED_ERROR/
899
963
  raise ZuoraAPI::Exceptions::ZuoraUnexpectedError.new(message, response, errors, success)
900
964
  when /.*soapenv:Server.*/
901
965
  if /^Invalid value.*for type.*|^Id is invalid|^date string can not be less than 19 charactors$/.match(message).present?
902
966
  raise ZuoraAPI::Exceptions::ZuoraAPIError.new(message, response, errors, success)
903
- elsif /^Invalid white space character \(.*\) in text to output$|^Invalid null character in text to output$/.match(message).present?
967
+ elsif /^unknown$|^Invalid white space character \(.*\) in text to output$|^Invalid null character in text to output$/.match(message).present?
904
968
  raise ZuoraAPI::Exceptions::ZuoraAPIUnkownError.new(message, response, errors, success)
905
969
  end
906
970
  raise ZuoraAPI::Exceptions::ZuoraAPIInternalServerError.new(message, response, errors, success)
971
+ when /soapenv:Receiver/
972
+ if /^com.ctc.wstx.exc.WstxUnexpectedCharException: Unexpected character.*$/.match(message).present?
973
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new(message, response, errors, success)
974
+ end
975
+ raise ZuoraAPI::Exceptions::ZuoraAPIInternalServerError.new(message, response, errors, success)
907
976
  else
908
977
  raise ZuoraAPI::Exceptions::ZuoraAPIInternalServerError.new("Z:#{error}::#{message}", response, errors, success)
909
978
  end
@@ -953,7 +1022,7 @@ module ZuoraAPI
953
1022
  base = self.url.include?(".com") ? self.url.split(".com")[0].concat(".com") : self.url.split(".eu")[0].concat(".eu")
954
1023
  url = object ? "#{base}/apps/api/describe/#{object}" : "#{base}/apps/api/describe/"
955
1024
  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"}
956
- response = HTTParty.get(url, headers: {"Authorization" => self.get_session(prefix: true, auth_type: :basic)}.merge(headers), :timeout => 120)
1025
+ response = HTTParty.get(url, headers: {"Authorization" => self.get_session(prefix: true, auth_type: :basic)}.merge(headers), :timeout => 130)
957
1026
 
958
1027
  raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error.present? ? self.current_error : 'Describe call 401', response) if response.code == 401
959
1028
 
@@ -986,35 +1055,31 @@ module ZuoraAPI
986
1055
  end
987
1056
  des_hash[:related_objects] = output_xml.xpath(".//related-objects").xpath(".//object").map{ |x| [x.xpath(".//name").text.to_sym, [ [:url, x.attributes["href"].value], [:label, x.xpath(".//name").text ] ].to_h] }.to_h
988
1057
  end
1058
+
1059
+ return des_hash
989
1060
  rescue *(CONNECTION_EXCEPTIONS + CONNECTION_READ_EXCEPTIONS) => ex
990
- if tries.zero?
991
- if log_errors
992
- if Rails.logger.class.to_s == "Ougai::Logger"
993
- Rails.logger.error("Describe - Timed out will retry after #{self.timeout_sleep} seconds", ex)
994
- else
995
- Rails.logger.error("Describe - #{ex.class} Timed out will retry after #{self.timeout_sleep} seconds")
996
- end
997
- end
998
- raise ex
1061
+ if !tries.zero?
1062
+ tries -= 1
1063
+ self.log(location: "Describe", exception: ex, message: "Timed out will retry after #{self.timeout_sleep} seconds", level: :debug)
1064
+ sleep(self.timeout_sleep)
1065
+ retry
999
1066
  end
1000
1067
 
1001
- tries -= 1
1002
- sleep(self.timeout_sleep)
1003
- retry
1068
+ self.log(location: "Describe", exception: ex, message: "Timed out", level: :error) if log_errors
1069
+ raise ex
1070
+
1004
1071
  rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
1005
1072
  if !tries.zero? && self.status == 'Active'
1006
1073
  tries -= 1
1007
1074
  Rails.logger.debug("Describe session expired. Starting new session.")
1008
1075
  self.new_session
1009
1076
  retry
1010
- else
1011
- Rails.logger.error("Describe session expired. Starting new session.") if log_errors
1012
- raise ex
1013
1077
  end
1078
+
1079
+ Rails.logger.error("Describe session expired. Starting new session.") if log_errors
1080
+ raise ex
1014
1081
  rescue => ex
1015
1082
  raise ex
1016
- else
1017
- return des_hash
1018
1083
  end
1019
1084
 
1020
1085
  def rest_call(
@@ -1027,11 +1092,12 @@ module ZuoraAPI
1027
1092
  z_session: true,
1028
1093
  session_type: :basic,
1029
1094
  timeout_retry: false,
1030
- timeout: 120,
1095
+ timeout: 130,
1031
1096
  timeout_sleep_interval: self.timeout_sleep,
1032
1097
  multipart: false,
1033
1098
  stream_body: false,
1034
1099
  output_exception_messages: true,
1100
+ zuora_track_id: nil,
1035
1101
  **keyword_args,
1036
1102
  &block
1037
1103
  )
@@ -1041,12 +1107,13 @@ module ZuoraAPI
1041
1107
 
1042
1108
  authentication_headers = {}
1043
1109
  if z_session
1044
- authentication_headers = {"Authorization" => self.get_session(prefix: true, auth_type: session_type) }
1110
+ authentication_headers = {"Authorization" => self.get_session(prefix: true, auth_type: session_type, zuora_track_id: zuora_track_id) }
1045
1111
  if self.entity_id.present?
1046
1112
  authentication_headers["Zuora-Entity-Ids"] = self.entity_id if headers.dig("Zuora-Entity-Ids").nil?
1047
1113
  authentication_headers.delete_if { |key, value| ["entityId", "entityName"].include?(key.to_s) }
1048
1114
  end
1049
1115
  end
1116
+ headers['Zuora-Track-Id'] = zuora_track_id if zuora_track_id.present?
1050
1117
 
1051
1118
  modified_headers = {'Content-Type' => "application/json; charset=utf-8"}.merge(authentication_headers).merge(headers)
1052
1119
 
@@ -1072,18 +1139,20 @@ module ZuoraAPI
1072
1139
  Rails.logger.debug("Response JSON: #{output_json}") if debug && output_json.present?
1073
1140
 
1074
1141
  raise_errors(type: :JSON, body: output_json, response: response)
1075
- rescue
1142
+ rescue => ex
1076
1143
  reset_files(body) if multipart
1077
1144
  raise
1078
1145
  end
1146
+
1147
+ return [output_json, response]
1079
1148
  rescue ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError => ex
1080
1149
  if self.class.to_s == 'ZuoraAPI::Oauth' && ex.message.include?("Authentication type is not supported by this Login")
1081
1150
  session_type = :bearer
1082
1151
  retry
1083
- else
1084
- Rails.logger.debug("Rest Call - Session Bad Auth type")
1085
- raise ex
1086
1152
  end
1153
+ Rails.logger.debug("Rest Call - Session Bad Auth type")
1154
+ raise ex
1155
+
1087
1156
  rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
1088
1157
  if !tries.zero? && z_session
1089
1158
  tries -= 1
@@ -1096,40 +1165,35 @@ module ZuoraAPI
1096
1165
  end
1097
1166
 
1098
1167
  retry
1099
- else
1100
- if errors.include?(ex.class)
1101
- raise ex
1102
- else
1103
- return [output_json, response]
1104
- end
1105
1168
  end
1169
+
1170
+ raise ex if errors.include?(ex.class)
1171
+ return [output_json, response]
1172
+
1106
1173
  rescue *ZUORA_API_ERRORS => ex
1107
- if errors.include?(ex.class)
1108
- raise ex
1109
- else
1110
- response = ex.response unless response
1111
- return [output_json, response]
1112
- end
1174
+ raise ex if errors.include?(ex.class)
1175
+
1176
+ response = ex.response unless response
1177
+ return [output_json, response]
1178
+
1113
1179
  rescue ZuoraAPI::Exceptions::BadEntityError => ex
1114
1180
  raise ex
1115
1181
  rescue *CONNECTION_EXCEPTIONS => ex
1116
- if tries.zero?
1117
- if output_exception_messages
1118
- if Rails.logger.class.to_s == "Ougai::Logger"
1119
- Rails.logger.error("Rest Call - Timed out will retry after #{timeout_sleep_interval} seconds", ex)
1120
- else
1121
- Rails.logger.error("Rest Call - #{ex.class} Timed out will retry after #{timeout_sleep_interval} seconds")
1122
- end
1123
- end
1124
- raise ex
1182
+ if !tries.zero?
1183
+ tries -= 1
1184
+ self.log(location: "Rest Call", exception: ex, message: "Timed out will retry after #{timeout_sleep_interval} seconds", level: :debug)
1185
+ sleep(timeout_sleep_interval)
1186
+ retry
1125
1187
  end
1126
1188
 
1127
- tries -= 1
1128
- sleep(timeout_sleep_interval)
1129
- retry
1189
+ self.log(location: "Rest Call", exception: ex, message: "Timed out", level: :error) if output_exception_messages
1190
+ raise ex
1191
+
1130
1192
  rescue *CONNECTION_READ_EXCEPTIONS => ex
1193
+
1131
1194
  if !tries.zero?
1132
1195
  tries -= 1
1196
+ self.log(location: "Rest Call", exception: ex, message: "Timed out will retry after #{timeout_sleep_interval} seconds", level: :debug)
1133
1197
  if ex.is_a?(Errno::ECONNRESET) && ex.message.include?('SSL_connect')
1134
1198
  retry
1135
1199
  elsif timeout_retry
@@ -1137,20 +1201,15 @@ module ZuoraAPI
1137
1201
  retry
1138
1202
  end
1139
1203
  end
1140
-
1141
- if output_exception_messages
1142
- if Rails.logger.class.to_s == "Ougai::Logger"
1143
- Rails.logger.error("Rest Call - Timed out will retry after #{timeout_sleep_interval} seconds", ex)
1144
- else
1145
- Rails.logger.error("Rest Call - #{ex.class} Timed out will retry after #{timeout_sleep_interval} seconds")
1146
- end
1147
- end
1148
- raise ZuoraAPI::Exceptions::ZuoraAPIReadTimeout.new("Received read timeout from #{url}", nil, request) if ex.instance_of?(Net::ReadTimeout)
1204
+
1205
+ self.log(location: "Rest Call", exception: ex, message: "Timed out", level: :error) if output_exception_messages
1206
+ ex = ZuoraAPI::Exceptions::ZuoraAPIReadTimeout.new("Received read timeout from 'https://#{rest_domain(endpoint: url)}'", nil, request) if ex.instance_of?(Net::ReadTimeout)
1149
1207
  raise ex
1208
+
1150
1209
  rescue => ex
1151
1210
  raise ex
1152
- else
1153
- return [output_json, response]
1211
+ ensure
1212
+ self.error_logger(ex) if defined?(ex) && Rails.logger.class.to_s == "Ougai::Logger"
1154
1213
  end
1155
1214
 
1156
1215
  def update_create_tenant
@@ -1172,8 +1231,9 @@ module ZuoraAPI
1172
1231
  while !response["nextPage"].blank?
1173
1232
  url = self.rest_endpoint(response["nextPage"].split('/v1/').last)
1174
1233
  Rails.logger.debug("Fetch Catalog URL #{url}")
1175
- output_json, response = self.rest_call(:debug => false, :url => url, :errors => [ZuoraAPI::Exceptions::ZuoraAPISessionError], :timeout_retry => true )
1176
- if !output_json['success'] =~ (/(true|t|yes|y|1)$/i) || output_json['success'].class != TrueClass
1234
+ output_json, response = self.rest_call(debug: false, url: url, timeout_retry: true)
1235
+
1236
+ if !/(true|t|yes|y|1)$/.match(output_json['success'].to_s) || output_json['success'].class != TrueClass
1177
1237
  raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Error Getting Catalog: #{output_json}", response)
1178
1238
  end
1179
1239
  output_json["products"].each do |product|
@@ -1199,7 +1259,7 @@ module ZuoraAPI
1199
1259
  return products, catalog_map
1200
1260
  end
1201
1261
 
1202
- def get_file(url: nil, headers: {}, z_session: true, tempfile: true, output_file_name: nil, zuora_track_id: nil, add_timestamp: true, file_path: defined?(Rails.root.join('tmp')) ? Rails.root.join('tmp') : Pathname.new(Dir.pwd), timeout_retries: 3, timeout: 120, session_type: :basic, **execute_params)
1262
+ def get_file(url: nil, headers: {}, z_session: true, tempfile: true, output_file_name: nil, zuora_track_id: nil, add_timestamp: true, file_path: defined?(Rails.root.join('tmp')) ? Rails.root.join('tmp') : Pathname.new(Dir.pwd), timeout_retries: 3, timeout: 130, session_type: :basic, **execute_params)
1203
1263
  raise "file_path must be of class Pathname" if file_path.class != Pathname
1204
1264
 
1205
1265
  retry_count ||= timeout_retries
@@ -1304,14 +1364,20 @@ module ZuoraAPI
1304
1364
  return file_handle
1305
1365
  when Net::HTTPUnauthorized
1306
1366
  if z_session
1307
- if !(retry_count -= 1).zero?
1367
+ unless (retry_count -= 1).zero?
1308
1368
  self.new_session
1309
- raise response.class
1310
- else
1311
- raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error)
1369
+ raise ZuoraAPI::Exceptions::ZuoraAPISessionError, 'Retrying'
1312
1370
  end
1371
+ raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error)
1372
+ end
1373
+ raise
1374
+ when Net::HTTPNotFound
1375
+ if url.include?(self.fileURL)
1376
+ raise ZuoraAPI::Exceptions::FileDownloadError.new(
1377
+ "The current tenant does not have a file with id '#{url.split('/').last}'"
1378
+ )
1313
1379
  else
1314
- raise
1380
+ raise ZuoraAPI::Exceptions::FileDownloadError.new("File Download Failed #{response.class}")
1315
1381
  end
1316
1382
  else
1317
1383
  raise ZuoraAPI::Exceptions::FileDownloadError.new("File Download Failed #{response.class}")
@@ -1322,133 +1388,81 @@ module ZuoraAPI
1322
1388
  sleep(5)
1323
1389
  if (retry_count -= 1) >= 0
1324
1390
  retry
1325
- else
1326
- Rails.logger.error("File Download Failed")
1327
- raise
1328
1391
  end
1392
+ Rails.logger.error("File Download Failed")
1393
+ raise
1329
1394
  end
1330
1395
 
1331
1396
  def getDataSourceExport(query, extract: true, encrypted: false, zip: true, z_track_id: "")
1332
- begin
1333
- tries ||= 3
1334
- request = Nokogiri::XML::Builder.new do |xml|
1335
- 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
1336
- xml['SOAP-ENV'].Header do
1337
- xml['ns1'].SessionHeader do
1338
- xml['ns1'].session self.get_session(prefix: false, auth_type: :basic, zuora_track_id: z_track_id)
1339
- end
1340
- end
1341
- xml['SOAP-ENV'].Body do
1342
- xml['ns1'].create do
1343
- xml['ns1'].zObjects('xsi:type' => "ns2:Export") do
1344
- xml['ns2'].Format 'csv'
1345
- xml['ns2'].Zip zip
1346
- xml['ns2'].Name 'googman'
1347
- xml['ns2'].Query query
1348
- xml['ns2'].Encrypted encrypted
1349
- end
1350
- end
1351
- end
1397
+ tries ||= 3
1398
+
1399
+ output_xml, input_xml = self.soap_call(debug: false, timeout_retry: true, zuora_track_id: z_track_id) do |xml|
1400
+ xml['ns1'].create do
1401
+ xml['ns1'].zObjects('xsi:type' => "ns2:Export") do
1402
+ xml['ns2'].Format 'csv'
1403
+ xml['ns2'].Zip zip
1404
+ xml['ns2'].Name 'googman'
1405
+ xml['ns2'].Query query
1406
+ xml['ns2'].Encrypted encrypted
1352
1407
  end
1353
1408
  end
1354
-
1355
- response_query = HTTParty.post(self.url, body: request.to_xml(:save_with => XML_SAVE_OPTIONS).strip, headers: {'Content-Type' => "application/json; charset=utf-8", "Z-Track-Id" => z_track_id}, :timeout => 120)
1356
-
1357
- output_xml = Nokogiri::XML(response_query.body)
1358
- raise_errors(type: :SOAP, body: output_xml, response: response_query) if output_xml.xpath('//ns1:Success', 'ns1' =>'http://api.zuora.com/').text != "true"
1359
-
1360
- # raise "Export Creation Unsuccessful : #{response_query.code}: #{response_query.parsed_response}" if output_xml.xpath('//ns1:Success', 'ns1' =>'http://api.zuora.com/').text != "true"
1361
-
1362
- id = output_xml.xpath('//ns1:Id', 'ns1' =>'http://api.zuora.com/').text
1363
-
1364
- confirmRequest = Nokogiri::XML::Builder.new do |xml|
1365
- 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
1366
- xml['SOAP-ENV'].Header do
1367
- xml['ns1'].SessionHeader do
1368
- xml['ns1'].session self.get_session(prefix: false, auth_type: :basic, zuora_track_id: z_track_id)
1369
- end
1370
- end
1371
- xml['SOAP-ENV'].Body do
1372
- xml['ns1'].query do
1373
- xml['ns1'].queryString "SELECT Id, CreatedById, CreatedDate, Encrypted, FileId, Format, Name, Query, Size, Status, StatusReason, UpdatedById, UpdatedDate, Zip From Export where Id = '#{id}'"
1374
- end
1375
- end
1409
+ end
1410
+
1411
+ id = output_xml.xpath('//ns1:Id', 'ns1' =>'http://api.zuora.com/').text
1412
+
1413
+ result = 'Waiting'
1414
+ while result != "Completed"
1415
+ sleep 3
1416
+ output_xml, input_xml = self.soap_call(debug: false, timeout_retry: true, zuora_track_id: z_track_id) do |xml|
1417
+ xml['ns1'].query do
1418
+ xml['ns1'].queryString "SELECT Id, CreatedById, CreatedDate, Encrypted, FileId, Format, Name, Query, Size, Status, StatusReason, UpdatedById, UpdatedDate, Zip From Export where Id = '#{id}'"
1376
1419
  end
1377
1420
  end
1378
- result = 'Waiting'
1379
-
1380
- while result != "Completed"
1381
- sleep 3
1382
- response_query = HTTParty.post(self.url, body: confirmRequest.to_xml(:save_with => XML_SAVE_OPTIONS).strip, headers: {'Content-Type' => "application/json; charset=utf-8", "Z-Track-Id" => z_track_id}, :timeout => 120)
1383
-
1384
- output_xml = Nokogiri::XML(response_query.body)
1385
- result = output_xml.xpath('//ns2:Status', 'ns2' =>'http://object.api.zuora.com/').text
1386
- status_code = response_query.code if response_query
1387
-
1388
- raise_errors(type: :SOAP, body: output_xml, response: response_query) if result.blank? || result == "Failed"
1389
- # raise "Export Creation Unsuccessful : #{response_query.code}: #{response_query.parsed_response}" if result.blank? || result == "Failed"
1390
- end
1391
-
1392
- file_id = output_xml.xpath('//ns2:FileId', 'ns2' =>'http://object.api.zuora.com/').text
1393
- export_file = get_file(:url => self.fileURL(file_id))
1394
- export_file_path = export_file.path
1395
- Rails.logger.debug("=====> Export path #{export_file.path}")
1396
-
1397
- if extract && zip
1398
- require "zip"
1399
- new_path = export_file_path.partition('.zip').first
1400
- zipped = Zip::File.open(export_file_path)
1401
- file_handle = zipped.entries.first
1402
- file_handle.extract(new_path)
1403
- File.delete(export_file_path)
1404
- return new_path
1405
- else
1406
- return export_file_path
1407
- end
1408
- rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
1409
- if !(tries -= 1).zero?
1410
- Rails.logger.info("Export call failed - Trace ID: #{z_track_id}")
1411
- self.new_session
1412
- retry
1413
- else
1414
- raise ex
1415
- end
1416
-
1417
- rescue ZuoraAPI::Exceptions::ZuoraUnexpectedError => ex
1418
- if !(tries -= 1).zero?
1419
- Rails.logger.info("Trace ID: #{z_track_id} UnexpectedError, will retry after 10 seconds")
1420
- sleep 10
1421
- retry
1422
- else
1423
- raise ex
1424
- end
1425
-
1426
- rescue *ZUORA_API_ERRORS => ex
1427
- raise ex
1428
-
1429
- rescue *(CONNECTION_EXCEPTIONS + CONNECTION_READ_EXCEPTIONS) => ex
1430
- if !(tries -= 1).zero?
1431
- Rails.logger.info("Trace ID: #{z_track_id} Timed out will retry after 5 seconds")
1432
- sleep 5
1433
- retry
1434
- else
1435
- raise ex
1436
- end
1421
+ result = output_xml.xpath('//ns2:Status', 'ns2' =>'http://object.api.zuora.com/').text
1422
+ end
1437
1423
 
1438
- rescue Errno::ECONNRESET => ex
1439
- if !(tries -= 1).zero? && ex.message.include?('SSL_connect')
1440
- retry
1441
- else
1442
- raise ex
1443
- end
1424
+ file_id = output_xml.xpath('//ns2:FileId', 'ns2' =>'http://object.api.zuora.com/').text
1425
+ export_file = get_file(:url => self.fileURL(file_id))
1426
+ export_file_path = export_file.path
1427
+
1428
+ if extract && zip
1429
+ require "zip"
1430
+ new_path = export_file_path.partition('.zip').first
1431
+ zipped = Zip::File.open(export_file_path)
1432
+ file_handle = zipped.entries.first
1433
+ file_handle.extract(new_path)
1434
+ File.delete(export_file_path)
1435
+ return new_path
1436
+ else
1437
+ return export_file_path
1438
+ end
1439
+ rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
1440
+ if !(tries -= 1).zero?
1441
+ Rails.logger.info("Export call failed - Trace ID: #{z_track_id}")
1442
+ self.new_session
1443
+ retry
1444
+ end
1445
+ raise ex
1444
1446
 
1445
- rescue ZuoraAPI::Exceptions::BadEntityError => ex
1446
- raise ex
1447
+ rescue ZuoraAPI::Exceptions::ZuoraUnexpectedError => ex
1448
+ if !(tries -= 1).zero?
1449
+ Rails.logger.info("Trace ID: #{z_track_id} UnexpectedError, will retry after 10 seconds")
1450
+ sleep(self.timeout_sleep)
1451
+ retry
1447
1452
  end
1453
+ raise ex
1454
+
1455
+ rescue *(CONNECTION_EXCEPTIONS + CONNECTION_READ_EXCEPTIONS) => ex
1456
+ if !(tries -= 1).zero?
1457
+ Rails.logger.info("Trace ID: #{z_track_id} Timed out will retry after 5 seconds")
1458
+ sleep(self.timeout_sleep)
1459
+ retry
1460
+ end
1461
+ raise ex
1448
1462
  end
1449
1463
 
1450
1464
  def query(query, parse = false)
1451
- output_xml, input_xml = self.soap_call({:debug => false, :timeout_retry => true}) do |xml|
1465
+ output_xml, input_xml = self.soap_call(debug: false, timeout_retry: true) do |xml|
1452
1466
  xml['ns1'].query do
1453
1467
  xml['ns1'].queryString query
1454
1468
  end