zuora_api 1.7.66j → 1.7.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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