zuora_api 1.7.66j → 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: 46c1d463bc291f1e674a92bc6dc28a35cb9df005a5e773124d752f624ebc9890
4
- data.tar.gz: bda2d5483c779155ebffd6e7b7f0472f6a19410f0dc47c168449acd3b31378f8
3
+ metadata.gz: b0865872f720e280a3a4805d314d27a3e2649b861495f80cf8523f4eb43f2c1e
4
+ data.tar.gz: cc80008e33f6b47245acc1a0b8cdb0ec326f4a714c842e434b25bd5643e94123
5
5
  SHA512:
6
- metadata.gz: a979bfcd6e7e668d0a87f097973b86b174d977862d002e7a2a60413e98d4a7481345a5a318ba5906b69ee0fdd8d9a18a96494ec93b476a7a16a3137a38352ca9
7
- data.tar.gz: 794dd0825636ab56d6aa5008fc9a7d9bd0f5e136db6223d426032b4eee16fd3e942842206c5ad39d50e5fa28aab44f7dc2bfa1f779027e03e6ff2e3fedd81075
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
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,23 @@ 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
38
37
  coverage: '/\(\d+.\d+\%\) covered/'
39
38
 
40
39
  rubygems-deploy:
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
- ruby "2.7.1"
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"
@@ -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 = [
@@ -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="")
@@ -387,20 +335,20 @@ module ZuoraAPI
387
335
  end
388
336
 
389
337
  def new_session(auth_type: :basic, debug: false, zuora_track_id: nil)
390
- tries ||= 2
338
+ retries ||= 2
391
339
  yield
392
340
 
393
341
  rescue ZuoraAPI::Exceptions::ZuoraAPISessionError => ex
394
- self.status = 'Inactive/Invalid'
342
+ self.status = 'Invalid'
395
343
  self.current_error = ex.message
396
344
  raise
397
345
  rescue ZuoraAPI::Exceptions::ZuoraAPIError => ex
398
346
  raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(ex.message, ex.response)
399
347
 
400
348
  rescue ZuoraAPI::Exceptions::ZuoraAPIInternalServerError => ex
401
- raise ex if tries.zero?
349
+ raise ex if retries.zero?
402
350
 
403
- tries -= 1
351
+ retries -= 1
404
352
  sleep(self.timeout_sleep)
405
353
  retry
406
354
 
@@ -586,7 +534,7 @@ module ZuoraAPI
586
534
  when ZuoraAPI::Exceptions::ZuoraAPIUnkownError, ZuoraAPI::Exceptions::ZuoraDataIntegrity
587
535
  Rails.logger.error('Zuora Unknown/Integrity Error', ex, exception_args)
588
536
  when ZuoraAPI::Exceptions::ZuoraAPIRequestLimit
589
- Rails.logger.info('Zuora APILimit Reached', exception_args)
537
+ Rails.logger.info('Zuora APILimit Reached', ex, exception_args)
590
538
  when *(ZuoraAPI::Login::ZUORA_API_ERRORS-ZuoraAPI::Login::ZUORA_SERVER_ERRORS)
591
539
  #Rails.logger.debug('Zuora API Error', ex, self.exception_args(ex))
592
540
  when *ZuoraAPI::Login::ZUORA_SERVER_ERRORS
@@ -605,12 +553,7 @@ module ZuoraAPI
605
553
 
606
554
  def exception_args(ex)
607
555
  args = {}
608
- if ex.class == ZuoraAPI::Exceptions::ZuoraAPIRequestLimit
609
- args.merge!({
610
- zuora_trace_id: ex.response.headers["zuora-request-id"],
611
- zuora_track_id: ex.response.request.options[:headers]["Zuora-Track-Id"]
612
- })
613
- elsif defined?(ex.response) && ex.response.present?
556
+ if defined?(ex.response) && ex.response.present?
614
557
  args.merge!({
615
558
  request: {
616
559
  path: ex.response.request.path.to_s,
@@ -697,12 +640,12 @@ module ZuoraAPI
697
640
  ).present?
698
641
  result = body.xpath('//ns2:Status', 'ns2' => 'http://object.api.zuora.com/').text
699
642
  if result == 'Failed'
700
- reason = body.xpath('//ns2:StatusReason', 'ns2' => 'http://object.api.zuora.com/').text
701
- if reason.present?
702
- message = body.xpath('//ns2:StatusReason', 'ns2' => 'http://object.api.zuora.com/').text
703
- 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?
704
648
  else
705
- error = 'FATAL_ERROR'
706
649
  message = 'Export failed due to unknown reason. Consult api logs.'
707
650
  end
708
651
  end
@@ -755,14 +698,27 @@ module ZuoraAPI
755
698
  if body['code'].present? && /61$/.match(body['code'].to_s).present? # if last 2 digits of code are 61
756
699
  raise ZuoraAPI::Exceptions::ZuoraAPITemporaryError.new(body['message'], nil, body['details'])
757
700
  end
701
+ when /^\/api\/v1\/payment_plans.*/
702
+ raise ZuoraAPI::Exceptions::ZuoraAPIError.new(body['error'], response) if body['error']
758
703
  end
759
704
 
760
705
  body = body.dig("results").present? ? body["results"] : body if body.class == Hash
761
706
  if body.class == Hash && (!body["success"] || !body["Success"] || response.code != 200)
762
- messages_array = body.fetch("reasons", []).map {|error| error['message']}.compact
763
- messages_array = messages_array.push(body.dig("error", 'message')).compact if body.dig('error').class == Hash
764
- codes_array = body.fetch("reasons", []).map {|error| error['code']}.compact
765
- 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
766
722
 
767
723
  if body['message'] == 'request exceeded limit'
768
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)
@@ -905,7 +861,7 @@ module ZuoraAPI
905
861
  output_json = JSON.parse(response.body)
906
862
  self.raise_errors(type: :JSON, body: output_json, response: response)
907
863
 
908
- 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
909
865
  output_xml = Nokogiri::XML(response.body)
910
866
  self.raise_errors(type: :SOAP, body: output_xml, response: response)
911
867
 
@@ -953,6 +909,11 @@ module ZuoraAPI
953
909
  message = body.xpath('//ns1:Message', 'ns1' =>'http://api.zuora.com/').text
954
910
  end
955
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
+
956
917
  #Update/Create/Delete Calls with multiple requests and responses
957
918
  if body.xpath('//ns1:result', 'ns1' =>'http://api.zuora.com/').size > 0 && body.xpath('//ns1:Errors', 'ns1' =>'http://api.zuora.com/').size > 0
958
919
  error = []
@@ -1003,10 +964,15 @@ module ZuoraAPI
1003
964
  when /.*soapenv:Server.*/
1004
965
  if /^Invalid value.*for type.*|^Id is invalid|^date string can not be less than 19 charactors$/.match(message).present?
1005
966
  raise ZuoraAPI::Exceptions::ZuoraAPIError.new(message, response, errors, success)
1006
- 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?
1007
968
  raise ZuoraAPI::Exceptions::ZuoraAPIUnkownError.new(message, response, errors, success)
1008
969
  end
1009
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)
1010
976
  else
1011
977
  raise ZuoraAPI::Exceptions::ZuoraAPIInternalServerError.new("Z:#{error}::#{message}", response, errors, success)
1012
978
  end
@@ -1398,13 +1364,21 @@ module ZuoraAPI
1398
1364
  return file_handle
1399
1365
  when Net::HTTPUnauthorized
1400
1366
  if z_session
1401
- if !(retry_count -= 1).zero?
1367
+ unless (retry_count -= 1).zero?
1402
1368
  self.new_session
1403
- raise response.class
1369
+ raise ZuoraAPI::Exceptions::ZuoraAPISessionError, 'Retrying'
1404
1370
  end
1405
1371
  raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error)
1406
1372
  end
1407
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
+ )
1379
+ else
1380
+ raise ZuoraAPI::Exceptions::FileDownloadError.new("File Download Failed #{response.class}")
1381
+ end
1408
1382
  else
1409
1383
  raise ZuoraAPI::Exceptions::FileDownloadError.new("File Download Failed #{response.class}")
1410
1384
  end
@@ -1421,68 +1395,35 @@ module ZuoraAPI
1421
1395
 
1422
1396
  def getDataSourceExport(query, extract: true, encrypted: false, zip: true, z_track_id: "")
1423
1397
  tries ||= 3
1424
- request = Nokogiri::XML::Builder.new do |xml|
1425
- 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
1426
- xml['SOAP-ENV'].Header do
1427
- xml['ns1'].SessionHeader do
1428
- xml['ns1'].session self.get_session(prefix: false, auth_type: :basic, zuora_track_id: z_track_id)
1429
- end
1430
- end
1431
- xml['SOAP-ENV'].Body do
1432
- xml['ns1'].create do
1433
- xml['ns1'].zObjects('xsi:type' => "ns2:Export") do
1434
- xml['ns2'].Format 'csv'
1435
- xml['ns2'].Zip zip
1436
- xml['ns2'].Name 'googman'
1437
- xml['ns2'].Query query
1438
- xml['ns2'].Encrypted encrypted
1439
- end
1440
- end
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
1441
1407
  end
1442
1408
  end
1443
1409
  end
1444
-
1445
- 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 => 130)
1446
-
1447
- output_xml = Nokogiri::XML(response_query.body)
1448
- raise_errors(type: :SOAP, body: output_xml, response: response_query) if output_xml.xpath('//ns1:Success', 'ns1' =>'http://api.zuora.com/').text != "true"
1449
-
1450
- # raise "Export Creation Unsuccessful : #{response_query.code}: #{response_query.parsed_response}" if output_xml.xpath('//ns1:Success', 'ns1' =>'http://api.zuora.com/').text != "true"
1451
1410
 
1452
1411
  id = output_xml.xpath('//ns1:Id', 'ns1' =>'http://api.zuora.com/').text
1453
1412
 
1454
- confirmRequest = Nokogiri::XML::Builder.new do |xml|
1455
- 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
1456
- xml['SOAP-ENV'].Header do
1457
- xml['ns1'].SessionHeader do
1458
- xml['ns1'].session self.get_session(prefix: false, auth_type: :basic, zuora_track_id: z_track_id)
1459
- end
1460
- end
1461
- xml['SOAP-ENV'].Body do
1462
- xml['ns1'].query do
1463
- xml['ns1'].queryString "SELECT Id, CreatedById, CreatedDate, Encrypted, FileId, Format, Name, Query, Size, Status, StatusReason, UpdatedById, UpdatedDate, Zip From Export where Id = '#{id}'"
1464
- end
1465
- end
1466
- end
1467
- end
1468
1413
  result = 'Waiting'
1469
-
1470
1414
  while result != "Completed"
1471
1415
  sleep 3
1472
- 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 => 130)
1473
-
1474
- output_xml = Nokogiri::XML(response_query.body)
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}'"
1419
+ end
1420
+ end
1475
1421
  result = output_xml.xpath('//ns2:Status', 'ns2' =>'http://object.api.zuora.com/').text
1476
- status_code = response_query.code if response_query
1477
-
1478
- raise_errors(type: :SOAP, body: output_xml, response: response_query) if result.blank? || result == "Failed"
1479
- # raise "Export Creation Unsuccessful : #{response_query.code}: #{response_query.parsed_response}" if result.blank? || result == "Failed"
1480
1422
  end
1481
1423
 
1482
1424
  file_id = output_xml.xpath('//ns2:FileId', 'ns2' =>'http://object.api.zuora.com/').text
1483
1425
  export_file = get_file(:url => self.fileURL(file_id))
1484
1426
  export_file_path = export_file.path
1485
- Rails.logger.debug("=====> Export path #{export_file.path}")
1486
1427
 
1487
1428
  if extract && zip
1488
1429
  require "zip"
@@ -1506,24 +1447,18 @@ module ZuoraAPI
1506
1447
  rescue ZuoraAPI::Exceptions::ZuoraUnexpectedError => ex
1507
1448
  if !(tries -= 1).zero?
1508
1449
  Rails.logger.info("Trace ID: #{z_track_id} UnexpectedError, will retry after 10 seconds")
1509
- sleep 10
1450
+ sleep(self.timeout_sleep)
1510
1451
  retry
1511
1452
  end
1512
1453
  raise ex
1513
-
1514
- rescue *ZUORA_API_ERRORS => ex
1515
- raise ex
1516
-
1454
+
1517
1455
  rescue *(CONNECTION_EXCEPTIONS + CONNECTION_READ_EXCEPTIONS) => ex
1518
1456
  if !(tries -= 1).zero?
1519
1457
  Rails.logger.info("Trace ID: #{z_track_id} Timed out will retry after 5 seconds")
1520
- sleep 5
1458
+ sleep(self.timeout_sleep)
1521
1459
  retry
1522
1460
  end
1523
1461
  raise ex
1524
-
1525
- rescue ZuoraAPI::Exceptions::BadEntityError => ex
1526
- raise ex
1527
1462
  end
1528
1463
 
1529
1464
  def query(query, parse = false)
@@ -1,3 +1,3 @@
1
1
  module ZuoraAPI
2
- VERSION = "1.7.66j"
2
+ VERSION = "1.7.80"
3
3
  end
@@ -27,5 +27,5 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency("nokogiri")
28
28
  spec.add_dependency("httparty")
29
29
  spec.add_dependency("rubyzip")
30
- spec.add_dependency("railties", ">= 4.1.0", "< 6")
30
+ spec.add_dependency 'railties', '>= 4.1.0', '< 6.1'
31
31
  end
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.7.66j
4
+ version: 1.7.80
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: 2020-06-19 00:00:00.000000000 Z
11
+ date: 2021-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -145,7 +145,7 @@ dependencies:
145
145
  version: 4.1.0
146
146
  - - "<"
147
147
  - !ruby/object:Gem::Version
148
- version: '6'
148
+ version: '6.1'
149
149
  type: :runtime
150
150
  prerelease: false
151
151
  version_requirements: !ruby/object:Gem::Requirement
@@ -155,7 +155,7 @@ dependencies:
155
155
  version: 4.1.0
156
156
  - - "<"
157
157
  - !ruby/object:Gem::Version
158
- version: '6'
158
+ version: '6.1'
159
159
  description: Gem that provides easy integration to Zuora
160
160
  email:
161
161
  - connect@zuora.com
@@ -174,6 +174,12 @@ files:
174
174
  - Rakefile
175
175
  - bin/console
176
176
  - bin/setup
177
+ - catalog-info.yaml
178
+ - docs/index.md
179
+ - gemfiles/Gemfile-rails.5.0.x
180
+ - gemfiles/Gemfile-rails.5.1.x
181
+ - gemfiles/Gemfile-rails.5.2.x
182
+ - gemfiles/Gemfile-rails.6.0.x
177
183
  - lib/insights_api/login.rb
178
184
  - lib/zuora_api.rb
179
185
  - lib/zuora_api/exceptions.rb
@@ -196,11 +202,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
196
202
  version: '0'
197
203
  required_rubygems_version: !ruby/object:Gem::Requirement
198
204
  requirements:
199
- - - ">"
205
+ - - ">="
200
206
  - !ruby/object:Gem::Version
201
- version: 1.3.1
207
+ version: '0'
202
208
  requirements: []
203
- rubygems_version: 3.1.2
209
+ rubygems_version: 3.1.4
204
210
  signing_key:
205
211
  specification_version: 4
206
212
  summary: Gem that provides easy integration to Zuora