zuora_api 1.3.2 → 1.3.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 +4 -4
- data/README.md +41 -1
- data/lib/insights_api/login.rb +213 -0
- data/lib/zuora_api.rb +1 -0
- data/lib/zuora_api/login.rb +8 -2
- data/lib/zuora_api/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d92c60b9da5b74041b862fdd2af9194efaf4d9fd
|
4
|
+
data.tar.gz: 56465882c0f981d112eaa407ddff336a2ac9b2f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aba52fda66bbb00072045a19d1ec30d534c7544e50395afef39c48a0ea1fb146a3939a14bf2bf97dc258542b7a84df008965a35e68e82470f18fd1aeb68ec995
|
7
|
+
data.tar.gz: 99bb1f0be83771d07212c1d7dfd25a3dcd517c01f9b1a06fc5d962415e1ae2be834bd2bdba1d8c8a06e07069e141046243ede52d735c1cbce6670770daaef4f2
|
data/README.md
CHANGED
@@ -101,7 +101,47 @@ response = zuora_client.describe_call()
|
|
101
101
|
```
|
102
102
|
|
103
103
|
### Journal Run
|
104
|
-
|
105
104
|
```ruby
|
106
105
|
zuora_client.createJournalRun(call)
|
107
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,213 @@
|
|
1
|
+
require "httparty"
|
2
|
+
require "zip"
|
3
|
+
module InsightsAPI
|
4
|
+
class Login
|
5
|
+
attr_accessor :api_token, :url
|
6
|
+
|
7
|
+
def initialize(api_token: nil, url: "Nw1.api.insights.zuora.com/api/", **keyword_args)
|
8
|
+
@api_token = api_token
|
9
|
+
@url = url
|
10
|
+
end
|
11
|
+
|
12
|
+
def insight_getstatus(uuid)
|
13
|
+
response = HTTParty.get(
|
14
|
+
"https://#{@url}/export/status/#{uuid}",
|
15
|
+
:basic_auth => { :username => @api_token })
|
16
|
+
if response.code == 200
|
17
|
+
parsed = JSON.parse(response.body)
|
18
|
+
return parsed
|
19
|
+
#error handing here
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def data_export_insights_file(objecttype, segmentuuid, startDate: nil, endDate: nil, tries: 30)
|
24
|
+
status = data_export_insights(objecttype, segmentuuid, startDate, endDate, tries: 30)
|
25
|
+
if status['status']== "COMPLETE"
|
26
|
+
signedUrl = status['signedUrl']
|
27
|
+
return get_file(file_name: "insights-#{startDate}-#{endDate}.csv", url: signedUrl, headers: {}, count: 3, file_type: "zip")
|
28
|
+
else
|
29
|
+
return status
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def data_export_insights(objecttype, segmentuuid, startDate: nil, endDate: nil, tries: 30)
|
34
|
+
status = insights_fetch_all(objecttype, segmentuuid, startDate, endDate)
|
35
|
+
if status['uuid'] == nil
|
36
|
+
return "Failed: #{status["response"]}"
|
37
|
+
else
|
38
|
+
fileid = status['uuid']
|
39
|
+
end
|
40
|
+
for retries in 1..tries
|
41
|
+
status = insight_getstatus(fileid)
|
42
|
+
if status['status']== "COMPLETE"
|
43
|
+
signedUrl = status['signedUrl']
|
44
|
+
return status
|
45
|
+
elsif status['status'] == "FAILED"
|
46
|
+
return status
|
47
|
+
else
|
48
|
+
sleep(60)
|
49
|
+
retries+=1
|
50
|
+
end
|
51
|
+
if retries > tries - 1
|
52
|
+
return "Timeout"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
return signedUrl
|
56
|
+
end
|
57
|
+
|
58
|
+
def insights_fetch_all(objecttype, segmentuuid, startDate, endDate)
|
59
|
+
if segmentuuid.is_a? Array
|
60
|
+
segmentsForAPI = segmentuuid.join('","')
|
61
|
+
elsif segmentuuid.is_a? String
|
62
|
+
segmentsForAPI = segmentuuid
|
63
|
+
elsif segmentuuid.is_a? Integer
|
64
|
+
segmentsForAPI = segmentuuid.to_s
|
65
|
+
else
|
66
|
+
raise "Error fetching Insights data: Segmentuuid must be either an array of uuids or an single uuid in string or interger format."
|
67
|
+
end
|
68
|
+
|
69
|
+
response = HTTParty.post(
|
70
|
+
"https://#{@url}/export/type/#{objecttype}",
|
71
|
+
:basic_auth => { :username => @api_token },
|
72
|
+
:headers => {'Content-Type'=> "Application/json"},
|
73
|
+
:body =>
|
74
|
+
'
|
75
|
+
{
|
76
|
+
"endDate": "' + (dateFormat(date: endDate)).to_s + '",
|
77
|
+
"startDate":"' + (dateFormat(date: startDate)).to_s + '",
|
78
|
+
"segments": [
|
79
|
+
"'+segmentsForAPI+'"
|
80
|
+
]
|
81
|
+
}
|
82
|
+
')
|
83
|
+
if response.code == 200
|
84
|
+
parsed = JSON.parse(response.body)
|
85
|
+
return parsed
|
86
|
+
else
|
87
|
+
return {"uuid"=> nil, "status"=>"Error", "signedUrl"=>"signedUrl", "response" => response.body}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def dateFormat(date: nil)
|
92
|
+
date ||= DateTime.now
|
93
|
+
return (date.to_date).to_s
|
94
|
+
end
|
95
|
+
|
96
|
+
def upload_into_insights(dataSourceName, recordType, batchDate, filePath)
|
97
|
+
begin
|
98
|
+
response = HTTParty.post(
|
99
|
+
"https://#{@url}/files/upload",
|
100
|
+
:basic_auth => { :username => @api_token }, :body => {
|
101
|
+
:dataSource => dataSourceName, :recordType => recordType,
|
102
|
+
:batchDate => dateFormat(date: batchDate) + "T00:00:00Z"})
|
103
|
+
parsed = JSON.parse(response.body)
|
104
|
+
signedUrl = parsed['signedUrl']
|
105
|
+
if !File.extname(filePath) == ".gz"
|
106
|
+
zipPath = gzip_file(filePath)
|
107
|
+
else
|
108
|
+
zipPath = filePath
|
109
|
+
end
|
110
|
+
|
111
|
+
gzippedFile = File.open(zipPath)
|
112
|
+
post = HTTParty.put(signedUrl,
|
113
|
+
:body => gzippedFile.read)
|
114
|
+
if post.code == 200
|
115
|
+
return {"status"=>"COMPLETE", "signedUrl"=>"signedUrl", "response" => post.code}
|
116
|
+
else
|
117
|
+
return {"status"=>"Error", "signedUrl"=>"signedUrl", "response" => post.code}
|
118
|
+
end
|
119
|
+
rescue Exception => e
|
120
|
+
Rails.logger.debug "[ZuoraGem]: While uploading to insights Error: #{e}"
|
121
|
+
raise e
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def describe(type: "ACCOUNT", object: "attributes")
|
126
|
+
url = "https://#{@url}/export/#{object}/#{type}"
|
127
|
+
uri = URI.parse(url)
|
128
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
129
|
+
http.use_ssl = true
|
130
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
131
|
+
begin
|
132
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
133
|
+
|
134
|
+
request.basic_auth(@api_token, "")
|
135
|
+
|
136
|
+
if request.code == '200'
|
137
|
+
return http.request(request)
|
138
|
+
else
|
139
|
+
return "Failed"
|
140
|
+
end
|
141
|
+
rescue Exception => e
|
142
|
+
Rails.logger.debug "[ZuoraGem]: While describing Zoura Insights objects: #{e}"
|
143
|
+
return "Failed"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def get_file(file_name: nil, url: nil, basic: {:username => nil, :password => nil}, headers: {}, count: 3, file_type: "zip")
|
148
|
+
tries ||= 2
|
149
|
+
temp_file = nil
|
150
|
+
uri = URI(url)
|
151
|
+
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
|
152
|
+
request = Net::HTTP::Get.new(uri)
|
153
|
+
headers.each do |k,v|
|
154
|
+
request["#{k}"] = v
|
155
|
+
end
|
156
|
+
request.basic_auth(basic[:username], basic[:password]) if (!basic[:username].blank? && !basic[:password].blank?)
|
157
|
+
http.request request do |response|
|
158
|
+
case response
|
159
|
+
when Net::HTTPNotFound
|
160
|
+
Rails.logger.fatal("[ZuoraGem]: 404 - Not Found")
|
161
|
+
raise response
|
162
|
+
|
163
|
+
when Net::HTTPUnauthorized
|
164
|
+
raise ZuoraAPI::Exceptions::ZuoraAPISessionError.new(zuora_client.current_error) if count <= 0
|
165
|
+
Rails.logger.fatal("[ZuoraGem]: Retry")
|
166
|
+
zuora_client.new_session
|
167
|
+
return get_file(:url => url, :count => count - 1, :headers => headers)
|
168
|
+
|
169
|
+
when Net::HTTPClientError
|
170
|
+
Rails.logger.debug("[ZuoraGem]: #{response}")
|
171
|
+
raise response
|
172
|
+
|
173
|
+
when Net::HTTPOK
|
174
|
+
Tempfile.open([file_name.rpartition('.').first, ".#{file_name.rpartition('.').last}"], "#{Rails.root}/tmp") do |tmp_file|
|
175
|
+
temp_file ||= tmp_file
|
176
|
+
tmp_file.binmode if (response.to_hash["content-type"].include?("application/zip") || response.to_hash["content-type"] == "application/zip")
|
177
|
+
response.read_body do |chunk|
|
178
|
+
tmp_file.write chunk.force_encoding("UTF-8")
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
rescue => ex
|
186
|
+
if !(tries -= 1).zero?
|
187
|
+
sleep 3
|
188
|
+
retry
|
189
|
+
else
|
190
|
+
raise ex
|
191
|
+
end
|
192
|
+
else
|
193
|
+
return temp_file
|
194
|
+
end
|
195
|
+
|
196
|
+
def gzip_file(filePath)
|
197
|
+
Zlib::GzipWriter.open(filePath + ".gz") do |gzip|
|
198
|
+
open(filePath, "rb") do |f|
|
199
|
+
f.each_chunk() {|chunk| gzip.write chunk }
|
200
|
+
end
|
201
|
+
gzip.close
|
202
|
+
end
|
203
|
+
return filePath+ ".gz"
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
class File
|
210
|
+
def each_chunk(chunk_size=2**16)
|
211
|
+
yield read(chunk_size) until eof?
|
212
|
+
end
|
213
|
+
end
|
data/lib/zuora_api.rb
CHANGED
data/lib/zuora_api/login.rb
CHANGED
@@ -366,7 +366,7 @@ module ZuoraAPI
|
|
366
366
|
end
|
367
367
|
|
368
368
|
def get_catalog
|
369
|
-
products, response = [{}, {'nextPage' => self.rest_endpoint('catalog/products?pageSize=40') }]
|
369
|
+
products, catalog_map, response = [{}, {}, {'nextPage' => self.rest_endpoint('catalog/products?pageSize=40') }]
|
370
370
|
while !response["nextPage"].blank?
|
371
371
|
url = self.rest_endpoint(response["nextPage"].split('/v1/').last)
|
372
372
|
Rails.logger.debug("Fetch Catalog URL #{url}")
|
@@ -375,12 +375,18 @@ module ZuoraAPI
|
|
375
375
|
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Error Getting Catalog: #{output_json}")
|
376
376
|
end
|
377
377
|
output_json["products"].each do |product|
|
378
|
+
catalog_map[product["id"]] = {"productId" => product["id"]}
|
378
379
|
rateplans = {}
|
380
|
+
|
379
381
|
product["productRatePlans"].each do |rateplan|
|
382
|
+
catalog_map[rateplan["id"]] = {"productId" => product["id"], "productRatePlanId" => rateplan["id"]}
|
380
383
|
charges = {}
|
384
|
+
|
381
385
|
rateplan["productRatePlanCharges"].each do |charge|
|
386
|
+
catalog_map[charge["id"]] = {"productId" => product["id"], "productRatePlanId" => rateplan["id"], "productRatePlanChargeId" => charge["id"], }
|
382
387
|
charges[charge["id"]] = charge.merge({"productId" => product["id"], "productName" => product["name"], "productRatePlanId" => rateplan["id"], "productRatePlanName" => rateplan["name"] })
|
383
388
|
end
|
389
|
+
|
384
390
|
rateplan["productRatePlanCharges"] = charges
|
385
391
|
rateplans[rateplan["id"]] = rateplan.merge({"productId" => product["id"], "productName" => product["name"]})
|
386
392
|
end
|
@@ -388,7 +394,7 @@ module ZuoraAPI
|
|
388
394
|
products[product['id']] = product
|
389
395
|
end
|
390
396
|
end
|
391
|
-
return products
|
397
|
+
return products, catalog_map
|
392
398
|
end
|
393
399
|
|
394
400
|
def get_file(file_name: nil, url: nil, headers: {}, count: 3, file_type: "zip")
|
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.3.
|
4
|
+
version: 1.3.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: 2017-05-
|
11
|
+
date: 2017-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -131,6 +131,7 @@ files:
|
|
131
131
|
- Rakefile
|
132
132
|
- bin/console
|
133
133
|
- bin/setup
|
134
|
+
- lib/insights_api/login.rb
|
134
135
|
- lib/zuora_api.rb
|
135
136
|
- lib/zuora_api/exceptions.rb
|
136
137
|
- lib/zuora_api/login.rb
|