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 +4 -4
- data/lib/zuora_api/exceptions.rb +6 -0
- data/lib/zuora_api/login.rb +132 -16
- data/lib/zuora_api/logins/oauth.rb +3 -1
- data/lib/zuora_api/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb8a07811203b9141471afb4cb85bc7b3c62b6e2ce6c9254985d3ad7683f2540
|
4
|
+
data.tar.gz: 58fefaba666d1999c169fcc02208b6df7fca95aa0bc9b219d7aa1fb8c02e1599
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c3c2d7503e8afb612edf442105d6c78d8feb6b480d625dc119ce2cd49645bbd2ad60e9090c93489e56af2921cc97921178c31aa0384a966fb3ed74efb5d2d32
|
7
|
+
data.tar.gz: ec1bc529dba10ef46600ae676fe693d63a3852ee466acd10332cdfb611beb4bee52d3c909a2b4d39d4b303f42782391fd0e32c63ecd54d5006c3cd1cbea8ca5f
|
data/lib/zuora_api/exceptions.rb
CHANGED
@@ -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
|
data/lib/zuora_api/login.rb
CHANGED
@@ -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
|
-
|
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::
|
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
|
-
|
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
|
-
|
1030
|
-
|
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
|
-
|
1118
|
-
|
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
|
-
|
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.
|
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"),
|
data/lib/zuora_api/version.rb
CHANGED
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.
|
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:
|
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.
|
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
|