zuora_api 1.9.09 → 1.10.3

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: 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