zuora_api 1.9.09 → 1.10.3

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: a6da8c9fbf54221b62336d0221ada0f53e9d22690b7a6a52cd83f214314b5ba5
4
- data.tar.gz: be31b09eef19df8b8d1fcbd70b9a11980f125c4eb4d5f96c3259ed516ab88934
3
+ metadata.gz: cb8a07811203b9141471afb4cb85bc7b3c62b6e2ce6c9254985d3ad7683f2540
4
+ data.tar.gz: 58fefaba666d1999c169fcc02208b6df7fca95aa0bc9b219d7aa1fb8c02e1599
5
5
  SHA512:
6
- metadata.gz: d6382ae611e80b38e574357baa771b432c4e554662293e98e4a73ca446c9445264d902f0b604ee071fe9dac6cf6bee4fde8319f0f782975955fdd562cf921b6c
7
- data.tar.gz: 1008b0e7e533e01b6636cc82e3e79b21c825d095d789d83c73c96142d9de78556c0caa38775aedb97a3b27e43a93f16281680f10a7d988fb005951084a36f75e
6
+ metadata.gz: 1c3c2d7503e8afb612edf442105d6c78d8feb6b480d625dc119ce2cd49645bbd2ad60e9090c93489e56af2921cc97921178c31aa0384a966fb3ed74efb5d2d32
7
+ data.tar.gz: ec1bc529dba10ef46600ae676fe693d63a3852ee466acd10332cdfb611beb4bee52d3c909a2b4d39d4b303f42782391fd0e32c63ecd54d5006c3cd1cbea8ca5f
@@ -125,6 +125,12 @@ module ZuoraAPI
125
125
  end
126
126
  end
127
127
 
128
+ class ZuoraAPIRequestConcurrentLimit < ZuoraAPIRequestLimit
129
+ end
130
+
131
+ class ZuoraAPIRequestRateLimit < ZuoraAPIRequestLimit
132
+ end
133
+
128
134
  class ZuoraAPIUnkownError < Error
129
135
  attr_reader :code, :response
130
136
  attr_writer :default_message
@@ -30,6 +30,8 @@ module ZuoraAPI
30
30
  ZUORA_API_ERRORS = [
31
31
  ZuoraAPI::Exceptions::ZuoraAPIError,
32
32
  ZuoraAPI::Exceptions::ZuoraAPIRequestLimit,
33
+ ZuoraAPI::Exceptions::ZuoraAPIRequestConcurrentLimit,
34
+ ZuoraAPI::Exceptions::ZuoraAPIRequestRateLimit,
33
35
  ZuoraAPI::Exceptions::ZuoraAPILockCompetition,
34
36
  ZuoraAPI::Exceptions::ZuoraAPITemporaryError,
35
37
  ZuoraAPI::Exceptions::ZuoraDataIntegrity,
@@ -45,9 +47,9 @@ module ZuoraAPI
45
47
  ZuoraAPI::Exceptions::ZuoraUnexpectedError
46
48
  ].freeze
47
49
 
48
- attr_accessor :region, :url, :wsdl_number, :current_session, :bearer_token, :oauth_session_expires_at, :environment, :status, :errors, :current_error, :user_info, :tenant_id, :tenant_name, :entity_id, :timeout_sleep, :hostname, :zconnect_provider
50
+ attr_accessor :region, :url, :wsdl_number, :current_session, :bearer_token, :oauth_session_expires_at, :environment, :status, :errors, :current_error, :user_info, :tenant_id, :tenant_name, :entity_id, :entity_identifier, :entity_header_type, :timeout_sleep, :hostname, :zconnect_provider
49
51
 
50
- def initialize(url: nil, entity_id: nil, session: nil, status: nil, bearer_token: nil, oauth_session_expires_at: nil, **keyword_args)
52
+ def initialize(url: nil, entity_id: nil, entity_identifier: nil, session: nil, status: nil, bearer_token: nil, oauth_session_expires_at: nil, **keyword_args)
51
53
  raise "URL is nil or empty, but URL is required" if url.nil? || url.empty?
52
54
  # raise "URL is improper. URL must contain zuora.com, zuora.eu, or zuora.na" if /zuora.com|zuora.eu|zuora.na/ === url
53
55
  self.hostname = /(?<=https:\/\/|http:\/\/)(.*?)(?=\/|$)/.match(url)[0] if !/(?<=https:\/\/|http:\/\/)(.*?)(?=\/|$)/.match(url).nil?
@@ -61,6 +63,8 @@ module ZuoraAPI
61
63
  self.url = url
62
64
  end
63
65
  self.entity_id = get_entity_id(entity_id: entity_id)
66
+ self.entity_identifier = entity_identifier
67
+ self.entity_header_type = :entity_id
64
68
  self.errors = Hash.new
65
69
  self.current_session = session
66
70
  self.bearer_token = bearer_token
@@ -454,6 +458,8 @@ module ZuoraAPI
454
458
 
455
459
  headers.merge!({ 'Content-Type' => "text/xml; charset=utf-8", 'Accept' => 'text/xml'})
456
460
  headers['Zuora-Track-Id'] = zuora_track_id if zuora_track_id.present?
461
+ headers['X-Amzn-Trace-Id'] = zuora_track_id if zuora_track_id.present?
462
+
457
463
  headers["User-Agent"] = USER_AGENT
458
464
 
459
465
  request = HTTParty::Request.new(
@@ -614,10 +620,7 @@ module ZuoraAPI
614
620
  case response.code
615
621
  when 504
616
622
  raise ZuoraAPI::Exceptions::ZuoraAPIReadTimeout.new("Received 504 from 'https://#{rest_domain(endpoint: request_uri)}'", response)
617
- when 429
618
- 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)
619
- when 401
620
-
623
+ when 401, 429
621
624
  else
622
625
  if body.class == Hash
623
626
  case request_path
@@ -634,6 +637,21 @@ module ZuoraAPI
634
637
  when :SOAP
635
638
  error, success, message = get_soap_error_and_message(body)
636
639
 
640
+ if response.code == 429
641
+ if message.to_s.downcase.include?('concurrent')
642
+ raise ZuoraAPI::Exceptions::ZuoraAPIRequestConcurrentLimit.new(
643
+ "The total number of concurrent requests has exceeded the limit allowed by the system. " \
644
+ "Please resubmit your request later.",
645
+ response
646
+ )
647
+ else
648
+ raise ZuoraAPI::Exceptions::ZuoraAPIRequestRateLimit.new(
649
+ "Rate limiting. Please resubmit your request later.",
650
+ response
651
+ )
652
+ end
653
+ end
654
+
637
655
  if body.xpath('//fns:LoginFault', 'fns' =>'http://fault.api.zuora.com/').present?
638
656
  raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(message, response)
639
657
  end
@@ -726,7 +744,12 @@ module ZuoraAPI
726
744
  codes_array = codes_array.push(body.dig("error", 'code')).compact
727
745
  end
728
746
 
729
- if body['message'] == 'request exceeded limit'
747
+ body_message = body.fetch('message', '').downcase
748
+ if body_message.include?('rate limit exceeded')
749
+ raise ZuoraAPI::Exceptions::ZuoraAPIRequestRateLimit.new("The total number of requests has exceeded the rate limit allowed by the system. Please resubmit your request later.", response)
750
+ end
751
+
752
+ if body_message.include?('request exceeded limit')
730
753
  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)
731
754
  end
732
755
 
@@ -798,7 +821,7 @@ module ZuoraAPI
798
821
 
799
822
  #Request exceeded limit
800
823
  if codes_array.map{|code| code.to_s.slice(6,7).to_i}.include?(70)
801
- raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new("#{messages_array.join(', ')}", response)
824
+ raise ZuoraAPI::Exceptions::ZuoraAPIRequestConcurrentLimit.new("#{messages_array.join(', ')}", response)
802
825
  end
803
826
 
804
827
  #All Errors catch
@@ -806,6 +829,10 @@ module ZuoraAPI
806
829
  raise ZuoraAPI::Exceptions::ZuoraAPIError.new("#{messages_array.join(', ')}", response)
807
830
  end
808
831
 
832
+ if response.code == 429
833
+ 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)
834
+ end
835
+
809
836
  #Zuora REST Query Errors
810
837
  if body["faultcode"].present?
811
838
  raise_errors_helper(error: body["faultcode"], message: body["faultstring"], response: response)
@@ -941,7 +968,11 @@ module ZuoraAPI
941
968
  when /.*INVALID_SESSION/
942
969
  raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(message, response, errors, success)
943
970
  when /.*REQUEST_EXCEEDED_LIMIT/
944
- raise ZuoraAPI::Exceptions::ZuoraAPIRequestLimit.new(message, response, errors, success)
971
+ if message.to_s.downcase.include?('concurrent')
972
+ raise ZuoraAPI::Exceptions::ZuoraAPIRequestConcurrentLimit.new(message, response, errors, success)
973
+ else
974
+ raise ZuoraAPI::Exceptions::ZuoraAPIRequestRateLimit.new(message, response, errors, success)
975
+ end
945
976
  when /.*LOCK_COMPETITION/
946
977
  raise ZuoraAPI::Exceptions::ZuoraAPILockCompetition.new(message, response, errors, success)
947
978
  when /.*BATCH_FAIL_ERROR/
@@ -1022,12 +1053,44 @@ module ZuoraAPI
1022
1053
  return self.get_file(url: self.aqua_endpoint("file/#{fileId}"))
1023
1054
  end
1024
1055
 
1056
+ def entity_header
1057
+ if self.entity_header_type == :entity_name && self.entity_identifier.present?
1058
+ { "entityName" => self.entity_identifier }
1059
+ elsif self.entity_id.present?
1060
+ { "Zuora-Entity-Ids" => self.entity_id }
1061
+ else
1062
+ {}
1063
+ end
1064
+ end
1065
+
1066
+ def insert_entity_header(destination_headers, lookup_headers: nil)
1067
+ # The entity header may be added to a place other than where we look for it
1068
+ lookup_headers = destination_headers if lookup_headers.nil?
1069
+
1070
+ entity_header_options = %w(zuora-entity-ids entityid entityname)
1071
+ # If the customer doesn't supply an entity header, fill it in
1072
+ if (entity_header_options & lookup_headers.keys.map(&:downcase)).blank?
1073
+ entity_header = self.entity_header
1074
+ if entity_header.present?
1075
+ destination_headers.merge!(entity_header)
1076
+ entity_header_options_to_exclude =
1077
+ entity_header_options.
1078
+ reject { |header| header == entity_header.keys.first&.downcase }
1079
+ destination_headers.delete_if { |key, _| entity_header_options_to_exclude.include?(key.to_s.downcase) }
1080
+ end
1081
+ end
1082
+ end
1083
+
1025
1084
  def describe_call(object = nil, log_errors = true)
1026
1085
  tries ||= 2
1027
1086
 
1028
1087
  base = self.url.include?(".com") ? self.url.split(".com")[0].concat(".com") : self.url.split(".eu")[0].concat(".eu")
1029
- url = object ? "#{base}/apps/api/describe/#{object}" : "#{base}/apps/api/describe/"
1030
- 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"}
1088
+
1089
+ version = self.url.scan(/(\d+\.\d)$/).dig(0,0).to_f
1090
+ url = object ? "#{base}/apps/api/#{version}/describe/#{object}" : "#{base}/apps/api/#{version}/describe/"
1091
+
1092
+ headers = { "Content-Type" => "text/xml; charset=utf-8" }.merge(self.entity_header)
1093
+
1031
1094
  response = HTTParty.get(url, headers: {"Authorization" => self.get_session(prefix: true, auth_type: :basic), "User-Agent" => USER_AGENT}.merge(headers), :timeout => 130)
1032
1095
 
1033
1096
  raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(self.current_error.present? ? self.current_error : 'Describe call 401', response) if response.code == 401
@@ -1114,12 +1177,12 @@ module ZuoraAPI
1114
1177
  authentication_headers = {}
1115
1178
  if z_session
1116
1179
  authentication_headers = {"Authorization" => self.get_session(prefix: true, auth_type: session_type, zuora_track_id: zuora_track_id) }
1117
- if self.entity_id.present?
1118
- authentication_headers["Zuora-Entity-Ids"] = self.entity_id if headers.dig("Zuora-Entity-Ids").nil?
1119
- authentication_headers.delete_if { |key, value| ["entityId", "entityName"].include?(key.to_s) }
1120
- end
1180
+
1181
+ self.insert_entity_header(authentication_headers, lookup_headers: headers)
1121
1182
  end
1122
1183
  headers['Zuora-Track-Id'] = zuora_track_id if zuora_track_id.present?
1184
+ headers['X-Amzn-Trace-Id'] = zuora_track_id if zuora_track_id.present?
1185
+
1123
1186
  headers['User-Agent'] = USER_AGENT
1124
1187
 
1125
1188
  modified_headers = {'Content-Type' => "application/json; charset=utf-8"}.merge(authentication_headers).merge(headers)
@@ -1282,10 +1345,13 @@ module ZuoraAPI
1282
1345
  http.use_ssl = true if !uri.scheme.nil? && uri.scheme.downcase == 'https'
1283
1346
  if z_session
1284
1347
  headers = headers.merge({"Authorization" => self.get_session(prefix: true)})
1285
- headers = headers.merge({"Zuora-Entity-Ids" => self.entity_id}) if !self.entity_id.blank?
1348
+
1349
+ self.insert_entity_header(headers)
1286
1350
  end
1287
1351
 
1288
1352
  headers['Zuora-Track-Id'] = zuora_track_id if zuora_track_id.present?
1353
+ headers['X-Amzn-Trace-Id'] = zuora_track_id if zuora_track_id.present?
1354
+
1289
1355
  headers["User-Agent"] = USER_AGENT
1290
1356
 
1291
1357
  response_save = nil
@@ -1401,6 +1467,56 @@ module ZuoraAPI
1401
1467
  raise
1402
1468
  end
1403
1469
 
1470
+ def create_data_source_export(query: "", encrypted: false, zip: true, z_track_id: "")
1471
+ begin
1472
+ output_xml, input_xml = self.soap_call(debug: false, timeout_retry: true, zuora_track_id: z_track_id) do |xml|
1473
+ xml['ns1'].create do
1474
+ xml['ns1'].zObjects('xsi:type' => "ns2:Export") do
1475
+ xml['ns2'].Format 'csv'
1476
+ xml['ns2'].Zip zip
1477
+ xml['ns2'].Name 'googman'
1478
+ xml['ns2'].Query query
1479
+ xml['ns2'].Encrypted encrypted
1480
+ end
1481
+ end
1482
+ end
1483
+
1484
+ return output_xml.xpath('//ns1:Id', 'ns1' =>'http://api.zuora.com/').text
1485
+ rescue Exception => ex
1486
+ raise ex.class.new("#{z_track_id} #{ex.message}")
1487
+ end
1488
+ end
1489
+
1490
+ def check_export_status(export_id: "")
1491
+ begin
1492
+ response, full_response = self.rest_call(method: :get,url: self.rest_endpoint("object/export/#{export_id}"))
1493
+
1494
+ return full_response.parsed_response
1495
+ rescue Exception => ex
1496
+ raise ex
1497
+ end
1498
+ end
1499
+
1500
+ def get_export_file(file_id: "", extract: true, zip: true)
1501
+ begin
1502
+ export_file_path = self.get_file(:url => self.rest_endpoint("files/#{file_id}")).path
1503
+
1504
+ if extract && zip
1505
+ require "zip"
1506
+ new_path = export_file_path.partition('.zip').first
1507
+ zipped = Zip::File.open(export_file_path)
1508
+ file_handle = zipped.entries.first
1509
+ file_handle.extract(new_path)
1510
+ File.delete(export_file_path)
1511
+ return new_path
1512
+ else
1513
+ return export_file_path
1514
+ end
1515
+ rescue Exception => ex
1516
+ raise ex
1517
+ end
1518
+ end
1519
+
1404
1520
  def getDataSourceExport(query, extract: true, encrypted: false, zip: true, z_track_id: "")
1405
1521
  tries ||= 3
1406
1522
 
@@ -32,8 +32,9 @@ module ZuoraAPI
32
32
  end
33
33
 
34
34
  def get_z_session(debug: false, zuora_track_id: nil)
35
- headers = self.entity_id.present? ? {"Zuora-Entity-Ids" => self.entity_id } : {}
35
+ headers = self.entity_header
36
36
  headers['Zuora-Track-Id'] = zuora_track_id if zuora_track_id.present?
37
+ headers['X-Amzn-Trace-Id'] = zuora_track_id if zuora_track_id.present?
37
38
  output_json, response = self.rest_call(:url => self.rest_endpoint("connections"), :session_type => :bearer, :headers => headers)
38
39
  begin
39
40
  self.current_session = response.headers.to_h['set-cookie'][0].split(';')[0].split('=',2)[1].gsub('%3D', '=')
@@ -54,6 +55,7 @@ module ZuoraAPI
54
55
 
55
56
  headers = { "content-type" => "application/x-www-form-urlencoded" }
56
57
  headers['Zuora-Track-Id'] = zuora_track_id if zuora_track_id.present?
58
+ headers['X-Amzn-Trace-Id'] = zuora_track_id if zuora_track_id.present?
57
59
 
58
60
  output_json, response = self.rest_call(:method => :post,
59
61
  url: self.rest_endpoint.chomp('v1/').concat("oauth/token"),
@@ -1,3 +1,3 @@
1
1
  module ZuoraAPI
2
- VERSION = "1.9.09"
2
+ VERSION = "1.10.3"
3
3
  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.9.09
4
+ version: 1.10.3
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: 2021-08-04 00:00:00.000000000 Z
11
+ date: 2022-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -219,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
219
  - !ruby/object:Gem::Version
220
220
  version: '0'
221
221
  requirements: []
222
- rubygems_version: 3.2.22
222
+ rubygems_version: 3.2.32
223
223
  signing_key:
224
224
  specification_version: 4
225
225
  summary: Gem that provides easy integration to Zuora