zuora_connect 2.1.1 → 3.0.0k

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: 0342c5ac7396b4e8ba75aff8dbab5d579fa6d0ad04a421b7d1d809ab3abbd90a
4
- data.tar.gz: 70f7277a93fec8e481f63e56f85e466b5e0b4d1307e2413e4f8da9497e980be2
3
+ metadata.gz: bad84d0fc35d26f517f83b2cc38e5d1569dafc4253c6c12a474f69aa9d9fee5e
4
+ data.tar.gz: 0ad1de0856425104abb6288662ca1481b097dfb3af696c40d1e8d5a1d018a0af
5
5
  SHA512:
6
- metadata.gz: eb6497a343dde2b4a3edfe470c8e5a44eb37ff99b75ed434138c280e8ac25bf36806d58fbb477772182596917f1c37c0e237bd55e88f646e149743477fba2f15
7
- data.tar.gz: f0b1f8b6f647f204ce8c4bfed7a8e77b49f3aada0faf6a0c31fc47675f5bfca67feb464692006bcb490977a577d1d5a3feab53886815f4c6472023e9ade6823b
6
+ metadata.gz: c00dcd65d70b84242e2c298f1d663d98259083c53e4232cf00c477b32fb32d480a49a39bf982a5682807ee0ae828905cd6dfeb1f548bf6e1a501dd4aca58c63e
7
+ data.tar.gz: 91fe7a9815f2340879cc0a30ef405b48960d44b54f1a020f193c5f029448b19ddb513944ce424fde25764cc0b5bf9a25ae25f3b70d124d715f69e4304ebf36d3
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ RDoc::Task.new(:rdoc) do |rdoc|
15
15
  rdoc.rdoc_files.include('lib/**/*.rb')
16
16
  end
17
17
 
18
- APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
19
19
  load 'rails/tasks/engine.rake'
20
20
 
21
21
 
@@ -1,23 +1,20 @@
1
1
  module ZuoraConnect
2
2
  class StaticController < ApplicationController
3
- before_action :authenticate_connect_app_request, :except => [:metrics, :health, :initialize_app]
4
- before_action :clear_connect_app_session, :only => [:metrics, :health, :initialize_app]
5
- after_action :persist_connect_app_session, :except => [:metrics, :health, :initialize_app]
6
-
7
- skip_before_action :verify_authenticity_token, :only => [:initialize_app]
8
-
9
- def metrics
10
- type = params[:type].present? ? params[:type] : "versions"
11
- render json: ZuoraConnect::AppInstance.get_metrics(type).to_json, status: 200
12
- end
3
+ before_action :authenticate_connect_app_request, :except => [:health, :initialize_app, :provision, :instance_user]
4
+ before_action :clear_connect_app_session, :only => [:health, :initialize_app, :provision, :instance_user]
5
+ after_action :persist_connect_app_session, :except => [:health, :initialize_app, :provision, :instance_user]
6
+
7
+ skip_before_action :verify_authenticity_token, :only => [:initialize_app, :provision]
8
+ http_basic_authenticate_with name: ENV['PROVISION_USER'], password: ENV['PROVISION_SECRET'], :only => [:provision, :instance_user]
9
+
13
10
 
14
11
  def health
15
12
  if params[:error].present?
16
- begin
13
+ begin
17
14
  raise ZuoraConnect::Exceptions::Error.new('This is an error')
18
15
  rescue => ex
19
16
  case params[:error]
20
- when 'Log'
17
+ when 'Log'
21
18
  Rails.logger.error("Error in Health", ex)
22
19
  when 'Exception'
23
20
  raise
@@ -34,11 +31,13 @@ module ZuoraConnect
34
31
  def initialize_app
35
32
  begin
36
33
  authenticate_connect_app_request
37
- @appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
38
- render json: {
39
- message: "Success",
40
- status: 200
41
- }, status: 200
34
+ unless performed?
35
+ @appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
36
+ render json: {
37
+ message: 'Success',
38
+ status: 200
39
+ }, status: 200
40
+ end
42
41
  rescue => ex
43
42
  Rails.logger.error("Failed to Initialize application", ex)
44
43
  if performed?
@@ -52,6 +51,74 @@ module ZuoraConnect
52
51
  end
53
52
  end
54
53
 
54
+ def provision
55
+ create_new_instance
56
+ unless performed?
57
+ render json: {
58
+ status: 200,
59
+ message: 'Success',
60
+ app_instance_id: @appinstance.id
61
+ }, status: 200
62
+ end
63
+ rescue StandardError => e
64
+ message = 'Failed to provision new instance'
65
+ if performed?
66
+ Rails.logger.error("#{message}: #{performed?}", e)
67
+ else
68
+ Rails.logger.error(message, e)
69
+ render json: {
70
+ status: 500,
71
+ message: message
72
+ }, status: 500
73
+ end
74
+ end
75
+
76
+ def instance_user
77
+ ZuoraConnect::AppInstance.read_master_db do
78
+ ZuoraConnect.logger.with_fields = {} if ZuoraConnect.logger.is_a?(Ougai::Logger)
79
+ Rails.logger.with_fields = {} if Rails.logger.is_a?(Ougai::Logger)
80
+
81
+ if defined?(ElasticAPM) && ElasticAPM.running? && ElasticAPM.respond_to?(:set_label)
82
+ ElasticAPM.set_label(:trace_id, request.uuid)
83
+ end
84
+
85
+ unless params[:id].present?
86
+ render json: {
87
+ status: 400,
88
+ message: 'No app instance id provided'
89
+ }, status: :bad_request
90
+ return
91
+ end
92
+
93
+ @appinstance = ZuoraConnect::AppInstance.find(params[:id]).new_session
94
+ end
95
+
96
+ zuora_client = @appinstance.send(ZuoraConnect::AppInstance::LOGIN_TENANT_DESTINATION).client
97
+ client_describe, = zuora_client.rest_call(
98
+ url: zuora_client.rest_endpoint('genesis/user/info').gsub('v1/', ''),
99
+ session_type: zuora_client.class == ZuoraAPI::Oauth ? :bearer : :basic
100
+ )
101
+
102
+ render json: {
103
+ status: 200,
104
+ message: 'Success',
105
+ user_id: client_describe['coreUserId'],
106
+ username: client_describe['username'],
107
+ email: client_describe['workEmail']
108
+ }, status: 200
109
+ rescue ActiveRecord::RecordNotFound
110
+ render json: {
111
+ status: 400,
112
+ message: 'No app instance found'
113
+ }, status: :bad_request
114
+ rescue StandardError => e
115
+ Rails.logger.error('Error occurred getting user details', e)
116
+ render json: {
117
+ status: 500,
118
+ message: 'Failed to get user details'
119
+ }, status: 500
120
+ end
121
+
55
122
  private
56
123
 
57
124
  def clear_connect_app_session
@@ -11,8 +11,7 @@ module ZuoraConnect
11
11
  before_destroy :prune_data
12
12
 
13
13
  self.table_name = "zuora_connect_app_instances"
14
- attr_accessor :options, :mode, :logins, :task_data, :last_refresh, :username, :password, :s3_client, :api_version, :drop_message, :new_session_message, :connect_user, :logitems
15
- @@telegraf_host = nil
14
+ attr_accessor :options, :mode, :logins, :task_data, :last_refresh, :username, :password, :s3_client, :api_version, :drop_message, :new_session_message, :connect_user, :logitems, :user_timezone
16
15
  REFRESH_TIMEOUT = 2.minute #Used to determine how long to wait on current refresh call before executing another
17
16
  INSTANCE_REFRESH_WINDOW = 1.hours #Used to set how how long till app starts attempting to refresh cached task connect data
18
17
  INSTANCE_REDIS_CACHE_PERIOD = 24.hours #Used to determine how long to cached task data will live for
@@ -21,6 +20,12 @@ module ZuoraConnect
21
20
  HOLDING_PATTERN_SLEEP = 5.seconds
22
21
  CONNECT_APPLICATION_ID = 0
23
22
  CONNECT_COMMUNICATION_SLEEP = Rails.env.test? ? 0.seconds : 5.seconds
23
+ CATALOG_LOOKUP_PAGE_SIZE = 10_000
24
+ CATALOG_LOOKUP_CACHE_TIME_KEY = 'CatalogCachedAt'
25
+ CATALOG_LOOKUP_TTL = 60.seconds
26
+ CATALOG_LOOKUP_CACHE_RESULT_KEY = 'CatalogCache'
27
+ TIMEZONE_LOG_RATE_LIMIT_KEY = 'TimezoneLoggedAt'
28
+ TIMEZONE_LOG_PERIOD = 4.hours
24
29
  IGNORED_LOCALS = ['fr', 'ja', 'es', 'zh', 'de']
25
30
  INTERNAL_HOSTS = []
26
31
  LOGIN_TENANT_DESTINATION = 'target_login'
@@ -29,7 +34,7 @@ module ZuoraConnect
29
34
  Aws::Errors::MissingCredentialsError,
30
35
  Aws::S3::Errors::AccessDenied,
31
36
  Aws::SES::Errors::AccessDenied,
32
- Aws::KMS::Errors::AccessDeniedException
37
+ Aws::KMS::Errors::AccessDeniedException
33
38
  ].freeze
34
39
  AWS_AUTH_ERRORS_MSG = "AWS Auth Errors".freeze
35
40
 
@@ -147,7 +152,8 @@ module ZuoraConnect
147
152
  if ZuoraConnect.configuration.mode != "Production"
148
153
  mock_task_data = {
149
154
  "id" => ZuoraConnect.configuration.dev_mode_appinstance,
150
- "mode" => ZuoraConnect.configuration.dev_mode_mode
155
+ "mode" => ZuoraConnect.configuration.dev_mode_mode,
156
+ "name" => "Developer Instance"
151
157
  }
152
158
 
153
159
  case ZuoraConnect.configuration.dev_mode_options.class
@@ -163,6 +169,7 @@ module ZuoraConnect
163
169
  end
164
170
 
165
171
  self.build_task(task_data: mock_task_data, session: session)
172
+ self.set_backup_creds if !self['zuora_logins'].present?
166
173
  self.last_refresh = Time.now.to_i
167
174
  else
168
175
  time_expire = (session["#{self.id}::last_refresh"] || Time.now).to_i - INSTANCE_REFRESH_WINDOW.ago.to_i
@@ -240,7 +247,9 @@ module ZuoraConnect
240
247
  rescue I18n::InvalidLocale => ex
241
248
  ZuoraConnect.logger.error(ex) if !IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
242
249
  end
243
- Time.zone = self.timezone
250
+
251
+ self.set_timezone
252
+
244
253
  if self.task_data.present?
245
254
  tenants = self.task_data.fetch('tenant_ids', [])
246
255
  organizations = self.task_data.fetch('organizations', [])
@@ -255,7 +264,7 @@ module ZuoraConnect
255
264
  end
256
265
 
257
266
  params = {
258
- name: self.task_data.dig('name'),
267
+ name: self.task_data.dig('name'),
259
268
  zuora_entity_ids: (self.task_data.dig(LOGIN_TENANT_DESTINATION,'entities') || []).map{|e| e['id']}.uniq,
260
269
  zuora_tenant_ids: tenants.map(&:to_s).uniq,
261
270
  organizations: organizations
@@ -264,7 +273,7 @@ module ZuoraConnect
264
273
  client = self.send(LOGIN_TENANT_DESTINATION).client
265
274
  if defined?(client.rest_domain)
266
275
  ZuoraConnect::RequestIdMiddleware.zuora_rest_domain = client.rest_domain
267
- params.merge!({zuora_domain: client.rest_domain, environment: client.environment })
276
+ params.merge!({zuora_domain: client.rest_domain, environment: client.environment })
268
277
  end
269
278
  end
270
279
  params = params.reject{|k,v| !self.attributes.keys.member?(k.to_s) || self[k] == v}
@@ -272,12 +281,77 @@ module ZuoraConnect
272
281
  end
273
282
  end
274
283
 
275
- def refresh(session: {})
284
+ def set_timezone(timezone: self.timezone, type: :default)
285
+ if timezone.blank?
286
+ timezone = self.timezone
287
+ end
288
+
289
+ if type == :default
290
+ Time.zone = timezone
291
+ elsif type == :user
292
+ begin
293
+ sql = <<-eos
294
+ SELECT zuora_users.zuora_identity_response FROM "#{self.id}".zuora_users ORDER BY zuora_users.updated_at DESC LIMIT 1;
295
+ eos
296
+ user = ActiveRecord::Base.connection.execute(sql).to_a.first
297
+
298
+ if user.present?
299
+ zuora_identity_response = JSON.parse(user.fetch('zuora_identity_response', '{}'))
300
+ self.user_timezone = zuora_identity_response.values.first&.dig('timeZone')
301
+ else
302
+ if (Redis.current.hget(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id).to_i + TIMEZONE_LOG_PERIOD.to_i) <= Time.now.to_i
303
+ Rails.logger.error('Cannot find any user to set the timezone', app_instance_id: self.id)
304
+ Redis.current.hset(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id, Time.now.to_i)
305
+ end
306
+ end
307
+ rescue => ex
308
+ Rails.logger.error('There is an error while getting timezone users', ex)
309
+ end
310
+
311
+ if self.user_timezone.present?
312
+ # connect instance which has a custom timezone
313
+ if !self.auto_deployed? && (
314
+ ActiveSupport::TimeZone[self.task_data.dig('user_settings', 'timezone') || '']&.utc_offset !=
315
+ ActiveSupport::TimeZone[self.user_timezone]&.utc_offset
316
+ )
317
+ if self.environment == 'Production' &&
318
+ (Redis.current.hget(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id).to_i + TIMEZONE_LOG_PERIOD.to_i) <= Time.now.to_i
319
+ ZuoraConnect.logger.error(
320
+ "Instance and user timezones are different. User has '#{self.user_timezone}' and " \
321
+ "instance has '#{self.task_data.dig('user_settings', 'timezone')}'",
322
+ app_instance_id: self.id
323
+ )
324
+ Redis.current.hset(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id, Time.now.to_i)
325
+ end
326
+ self.user_timezone = nil
327
+ Time.zone = timezone
328
+ else
329
+ begin
330
+ Time.zone = self.user_timezone
331
+ rescue ArgumentError
332
+ Rails.logger.error('Malformed user timezone', app_instance_id: self.id)
333
+ Time.zone = timezone
334
+ end
335
+ end
336
+ else
337
+ Time.zone = timezone
338
+ end
339
+ end
340
+ rescue => e
341
+ Rails.logger.error('Malformed timezone used', e, app_instance_id: self.id)
342
+ Time.zone = self.timezone
343
+ end
344
+
345
+ def auto_deployed?
346
+ self.id >= 25000000
347
+ end
348
+
349
+ def refresh(session: {})
276
350
  refresh_count ||= 0
277
351
  skip_connect ||= false
278
352
  begin
279
353
  #Check how app was deployed
280
- if self.id < 25000000 && !skip_connect
354
+ if !self.auto_deployed? && !skip_connect
281
355
  self.check_oauth_state
282
356
  response = HTTParty.get(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}.json",:body => {:access_token => self.access_token})
283
357
 
@@ -289,16 +363,8 @@ module ZuoraConnect
289
363
  end
290
364
 
291
365
  self.build_task(task_data: parsed_json, session: session)
292
- if self.kms_key.present? && self.kms_key.match(/^arn:aws:.*/)
293
- begin
294
- self.zuora_logins = self.strip_cache_data(object: parsed_json.dup, keys: ['applications', 'tokens', 'user_settings'])
295
- self.save(:validate => false)
296
- rescue Aws::KMS::Errors::ValidationException, *AWS_AUTH_ERRORS => ex
297
- Rails.logger.warn(AWS_AUTH_ERRORS_MSG, ex)
298
- rescue => ex
299
- Rails.logger.error(AWS_AUTH_ERRORS_MSG, ex)
300
- end
301
- end
366
+ self.set_backup_creds
367
+ self.save(validate: false) if self.changed?
302
368
  else
303
369
  raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
304
370
  end
@@ -338,9 +404,21 @@ module ZuoraConnect
338
404
  raise
339
405
  end
340
406
 
407
+ def aws_secrets
408
+ (Rails.application.secrets.aws || {}).transform_keys { |key| key.to_s }
409
+ end
410
+
341
411
  #### START KMS ENCRYPTION Methods ####
412
+ def set_backup_creds
413
+ if self.kms_key.present? && self.kms_key.match(/^arn:aws:.*/) && self.task_data.present?
414
+ self.zuora_logins = self.strip_cache_data(object: self.task_data.dup, keys: ['applications', 'tokens', 'user_settings'])
415
+ end
416
+ end
417
+
342
418
  def zuora_logins=(val)
343
419
  write_attribute(:zuora_logins, kms_encrypt(val.to_json))
420
+ rescue Aws::KMS::Errors::ValidationException, Aws::KMS::Errors::NotFoundException, *AWS_AUTH_ERRORS => ex
421
+ Rails.logger.warn(AWS_AUTH_ERRORS_MSG, ex)
344
422
  end
345
423
 
346
424
  def zuora_logins
@@ -350,7 +428,7 @@ module ZuoraConnect
350
428
 
351
429
  def kms_decrypt(value)
352
430
  kms_tries ||= 0
353
- kms_client = Aws::KMS::Client.new({region: Rails.application.secrets.aws['AWS_REGION'], credentials: self.aws_auth_client}.delete_if { |k, v| v.blank? })
431
+ kms_client = Aws::KMS::Client.new({region: aws_secrets['AWS_REGION'], credentials: self.aws_auth_client}.delete_if { |k, v| v.blank? })
354
432
  resp = kms_client.decrypt({ciphertext_blob: [value].pack("H*") })
355
433
  return resp.plaintext
356
434
  rescue *AWS_AUTH_ERRORS => ex
@@ -365,7 +443,7 @@ module ZuoraConnect
365
443
 
366
444
  def kms_encrypt(value)
367
445
  kms_tries ||= 0
368
- kms_client = Aws::KMS::Client.new({region: Rails.application.secrets.aws['AWS_REGION'], credentials: self.aws_auth_client}.delete_if {|k,v| v.blank? })
446
+ kms_client = Aws::KMS::Client.new({region: aws_secrets['AWS_REGION'], credentials: self.aws_auth_client}.delete_if {|k,v| v.blank? })
369
447
 
370
448
  resp = kms_client.encrypt({key_id: kms_key, plaintext: value})
371
449
  return resp.ciphertext_blob.unpack('H*').first
@@ -380,12 +458,12 @@ module ZuoraConnect
380
458
  end
381
459
 
382
460
  def kms_key
383
- return ENV['AWS_KMS_ARN'] || Rails.application.secrets.dig(:aws,'AWS_KMS_ARN')
461
+ return ENV['AWS_KMS_ARN'] || aws_secrets['AWS_KMS_ARN']
384
462
  end
385
463
 
386
464
  def aws_auth_client
387
465
  if Rails.env.to_s == 'development'
388
- return Aws::Credentials.new(Rails.application.secrets.aws['AWS_ACCESS_KEY_ID'], Rails.application.secrets.aws['AWS_SECRET_ACCESS_KEY'])
466
+ return Aws::Credentials.new(aws_secrets['AWS_ACCESS_KEY_ID'], aws_secrets['AWS_SECRET_ACCESS_KEY'])
389
467
  else
390
468
  return nil
391
469
  end
@@ -400,82 +478,6 @@ module ZuoraConnect
400
478
  end
401
479
  Thread.current[:appinstance] = self
402
480
  end
403
-
404
- def self.write_to_telegraf(*args)
405
- if ZuoraConnect.configuration.enable_metrics
406
- @@telegraf_host = ZuoraConnect::Telegraf.new() if @@telegraf_host == nil
407
- unicorn_stats = self.unicorn_listener_stats() if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
408
- @@telegraf_host.write(direction: 'Raindrops', tags: {}, values: unicorn_stats) unless unicorn_stats.blank?
409
- return @@telegraf_host.write(*args)
410
- end
411
- end
412
-
413
- def self.unicorn_listener_stats ()
414
- stats_hash = {}
415
- stats_hash["total_active"] = 0
416
- stats_hash["total_queued"] = 0
417
-
418
- begin
419
- tmp = Unicorn.listener_names
420
- unix = tmp.grep(%r{\A/})
421
- tcp = tmp.grep(/\A.+:\d+\z/)
422
- tcp = nil if tcp.empty?
423
- unix = nil if unix.empty?
424
-
425
-
426
- Raindrops::Linux.tcp_listener_stats(tcp).each do |addr,stats|
427
- stats_hash["active_#{addr}"] = stats.active
428
- stats_hash["queued_#{addr}"] = stats.queued
429
- stats_hash["total_active"] = stats.active + stats_hash["total_active"]
430
- stats_hash["total_queued"] = stats.queued + stats_hash["total_queued"]
431
- end if tcp
432
-
433
- Raindrops::Linux.unix_listener_stats(unix).each do |addr,stats|
434
- stats_hash["active_#{addr}"] = stats.active
435
- stats_hash["queued_#{addr}"] = stats.queued
436
- stats_hash["total_active"] = stats.active + stats_hash["total_active"]
437
- stats_hash["total_queued"] = stats.queued + stats_hash["total_queued"]
438
- end if unix
439
- rescue IOError => ex
440
- rescue => ex
441
- ZuoraConnect.logger.error(ex)
442
- end
443
- return stats_hash
444
- end
445
-
446
- def self.get_metrics(type)
447
- @data = {}
448
-
449
- if type == "versions"
450
- @data = {
451
- app_name: ZuoraConnect::Telegraf.app_name,
452
- url: "dummy",
453
- Version_Gem: ZuoraConnect::VERSION,
454
- Version_Zuora: ZuoraAPI::VERSION ,
455
- Version_Ruby: RUBY_VERSION,
456
- Version_Rails: Rails.version,
457
- hold: 1
458
- }
459
- elsif type == "stats"
460
- begin
461
- Resque.redis.ping
462
- @resque = Resque.info
463
- @data = {
464
- app_name: ZuoraConnect::Telegraf.app_name,
465
- url: "dummy",
466
- Resque:{
467
- Jobs_Finished: @resque[:processed] ,
468
- Jobs_Failed: @resque[:failed],
469
- Jobs_Pending: @resque[:pending],
470
- Workers_Active: @resque[:working],
471
- Workers_Total: @resque[:workers]
472
- }
473
- }
474
- rescue
475
- end
476
- end
477
- return @data
478
- end
479
481
  #### END Task Methods ####
480
482
 
481
483
  #### START Task Methods ####
@@ -518,7 +520,7 @@ module ZuoraConnect
518
520
  end
519
521
  rescue ZuoraConnect::Exceptions::MissMatch => ex
520
522
  raise
521
- rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
523
+ rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
522
524
  raise
523
525
  rescue => ex
524
526
  ZuoraConnect.logger.error("Build Task Error", ex)
@@ -574,12 +576,12 @@ module ZuoraConnect
574
576
  self.refresh if !defined?(self.target_login)
575
577
 
576
578
  response = HTTParty.get("#{ZuoraConnect.configuration.url}/api/#{self.api_version}/tenants/search?hostname=#{self.target_login.client.hostname}&node_id=#{self.zuora_entity_ids.first}")
577
-
579
+
578
580
  if response.success?
579
581
  parsed_json = JSON.parse(response.body)
580
-
582
+
581
583
  #Set Org
582
- if self.id >= 25000000 && parsed_json['organization'].present?
584
+ if self.auto_deployed? && parsed_json['organization'].present?
583
585
  login_cache = self.zuora_logins
584
586
  login_cache.delete('organization')
585
587
  self.zuora_logins = login_cache.merge({'organizations' => [parsed_json['organization']]})
@@ -599,7 +601,7 @@ module ZuoraConnect
599
601
  end
600
602
  end
601
603
  self.save(:validate => false)
602
-
604
+
603
605
  return parsed_json
604
606
  end
605
607
  rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS + ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
@@ -653,7 +655,7 @@ module ZuoraConnect
653
655
  end
654
656
 
655
657
  def refresh_oauth
656
- refresh_oauth_count ||= 0
658
+ refresh_oauth_count ||= 0
657
659
  response = HTTParty.post("#{ZuoraConnect.configuration.url}/oauth/token", body: {
658
660
  :grant_type => "refresh_token",
659
661
  :redirect_uri => ZuoraConnect.configuration.oauth_client_redirect_uri,
@@ -955,13 +957,81 @@ module ZuoraConnect
955
957
  # object_id: The id or id's of the object/objects to be returned.
956
958
  # child_objects: Whether to include child objects of the object in question.
957
959
  # cache: Store individual "1" object lookup in redis for caching.
958
- def catalog_lookup(entity_id: nil, object: :product, object_id: nil, child_objects: false, cache: false)
960
+ def catalog_lookup(entity_id: nil, object: :product, object_id: nil, child_objects: false, cache: false, source: 'DB')
959
961
  entity_reference = entity_id.blank? ? 'Default' : entity_id
960
962
 
961
963
  if object_id.present? && ![Array, String].include?(object_id.class)
962
964
  raise "Object Id can only be a string or an array of strings"
963
965
  end
964
966
 
967
+ if source == 'API'
968
+ catalog_container = {}
969
+
970
+ if (Redis.current.hget(CATALOG_LOOKUP_CACHE_TIME_KEY, self.id).to_i + CATALOG_LOOKUP_TTL.to_i) > Time.now.to_i
971
+ begin
972
+ catalog_container = JSON.parse(Redis.current.hget(CATALOG_LOOKUP_CACHE_RESULT_KEY, self.id))
973
+ rescue JSON::ParserError => ex
974
+ Rails.logger.warn('Failed to parse catalog cache', ex)
975
+ end
976
+ else
977
+ zuora_login = self.login_lookup(type: 'Zuora').first
978
+ login = zuora_login.client(entity_reference)
979
+
980
+ response = {
981
+ 'nextPage' => login.rest_endpoint("catalog/products?pageSize=#{CATALOG_LOOKUP_PAGE_SIZE}")
982
+ }
983
+
984
+ while response['nextPage'].present?
985
+ url = login.rest_endpoint(response['nextPage'].split('/v1/').last)
986
+ output_json, response = login.rest_call(debug: false, url: url, timeout_retry: true)
987
+
988
+ case object
989
+ when :product
990
+ output_json.fetch('products', []).each do |product|
991
+ rate_plans = {}
992
+ product['productRatePlans'].each do |rate_plan|
993
+ charges = {}
994
+ rate_plan['productRatePlanCharges'].each do |charge|
995
+ charges[charge['id']] = charge.merge(
996
+ {
997
+ 'productId' => product['id'],
998
+ 'productName' => product['name'],
999
+ 'productRatePlanId' => rate_plan['id'],
1000
+ 'productRatePlanName' => rate_plan['name'],
1001
+ }
1002
+ )
1003
+ end
1004
+
1005
+ rate_plan['productRatePlanCharges'] = charges
1006
+ rate_plans[rate_plan['id']] = rate_plan.merge(
1007
+ {
1008
+ 'productId' => product['id'],
1009
+ 'productName' => product['name']
1010
+ }
1011
+ )
1012
+ end
1013
+
1014
+ product['productRatePlans'] = rate_plans
1015
+ catalog_container[product['id']] = product
1016
+ end
1017
+ else
1018
+ raise "Available objects include [:product]"
1019
+ end
1020
+ end
1021
+
1022
+ Redis.current.hset(CATALOG_LOOKUP_CACHE_RESULT_KEY, self.id, catalog_container.to_json)
1023
+ Redis.current.hset(CATALOG_LOOKUP_CACHE_TIME_KEY, self.id, Time.now.to_i)
1024
+ end
1025
+
1026
+ if object_id.nil?
1027
+ catalog_container.transform_values! { |v| v.except('productRatePlans') }
1028
+ elsif object_id.is_a?(String)
1029
+ catalog_container = catalog_container[object_id]
1030
+ end
1031
+
1032
+ return catalog_container || {}
1033
+ end
1034
+
965
1035
  if defined?(Redis.current) && object_id.present? && object_id.class == String && object_id.present?
966
1036
  stub_catalog = cache ? decrypt_data(data: Redis.current.get("Catalog:#{self.id}:#{object_id}:Children:#{child_objects}")) : nil
967
1037
  object_hierarchy = decrypt_data(data: Redis.current.get("Catalog:#{self.id}:#{object_id}:Hierarchy"))
@@ -1221,7 +1291,7 @@ module ZuoraConnect
1221
1291
 
1222
1292
  def self.without_sticking
1223
1293
  if self.connection.respond_to?(:without_sticking)
1224
- self.connection.without_sticking do
1294
+ self.connection.without_sticking do
1225
1295
  yield
1226
1296
  end
1227
1297
  else