zuora_connect 2.1.1 → 3.0.0.pre.e

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: 3f36eda986a37f2574d06c4e34785ba6da29d6dc1b4308744e8e73defd48c25a
4
+ data.tar.gz: 9b29a5f07f44fd2ba9df5440498fd1de7a9683654ca0ec7c742def938df8c166
5
5
  SHA512:
6
- metadata.gz: eb6497a343dde2b4a3edfe470c8e5a44eb37ff99b75ed434138c280e8ac25bf36806d58fbb477772182596917f1c37c0e237bd55e88f646e149743477fba2f15
7
- data.tar.gz: f0b1f8b6f647f204ce8c4bfed7a8e77b49f3aada0faf6a0c31fc47675f5bfca67feb464692006bcb490977a577d1d5a3feab53886815f4c6472023e9ade6823b
6
+ metadata.gz: ce99e27b914104c581943f5abed30d298841e402d6a76c53884c2041a4d1bf9780f063357f865ead9e8b144ade8dc8ac7d5fbdd64bfe54bb9a833df32ad30fa3
7
+ data.tar.gz: 5b108c5a4048412c39f0f5fb99c76532c0671012fb47c92397239c999fe7c0ea48af10132e41acb80f9957a6415282faea9c840c84f9c104bb268cce9de8812d
@@ -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
 
@@ -163,6 +168,7 @@ module ZuoraConnect
163
168
  end
164
169
 
165
170
  self.build_task(task_data: mock_task_data, session: session)
171
+ self.set_backup_creds
166
172
  self.last_refresh = Time.now.to_i
167
173
  else
168
174
  time_expire = (session["#{self.id}::last_refresh"] || Time.now).to_i - INSTANCE_REFRESH_WINDOW.ago.to_i
@@ -240,7 +246,9 @@ module ZuoraConnect
240
246
  rescue I18n::InvalidLocale => ex
241
247
  ZuoraConnect.logger.error(ex) if !IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
242
248
  end
243
- Time.zone = self.timezone
249
+
250
+ self.set_timezone
251
+
244
252
  if self.task_data.present?
245
253
  tenants = self.task_data.fetch('tenant_ids', [])
246
254
  organizations = self.task_data.fetch('organizations', [])
@@ -255,7 +263,7 @@ module ZuoraConnect
255
263
  end
256
264
 
257
265
  params = {
258
- name: self.task_data.dig('name'),
266
+ name: self.task_data.dig('name'),
259
267
  zuora_entity_ids: (self.task_data.dig(LOGIN_TENANT_DESTINATION,'entities') || []).map{|e| e['id']}.uniq,
260
268
  zuora_tenant_ids: tenants.map(&:to_s).uniq,
261
269
  organizations: organizations
@@ -264,7 +272,7 @@ module ZuoraConnect
264
272
  client = self.send(LOGIN_TENANT_DESTINATION).client
265
273
  if defined?(client.rest_domain)
266
274
  ZuoraConnect::RequestIdMiddleware.zuora_rest_domain = client.rest_domain
267
- params.merge!({zuora_domain: client.rest_domain, environment: client.environment })
275
+ params.merge!({zuora_domain: client.rest_domain, environment: client.environment })
268
276
  end
269
277
  end
270
278
  params = params.reject{|k,v| !self.attributes.keys.member?(k.to_s) || self[k] == v}
@@ -272,12 +280,77 @@ module ZuoraConnect
272
280
  end
273
281
  end
274
282
 
275
- def refresh(session: {})
283
+ def set_timezone(timezone: self.timezone, type: :default)
284
+ if timezone.blank?
285
+ timezone = self.timezone
286
+ end
287
+
288
+ if type == :default
289
+ Time.zone = timezone
290
+ elsif type == :user
291
+ begin
292
+ sql = <<-eos
293
+ SELECT zuora_users.zuora_identity_response FROM "#{self.id}".zuora_users ORDER BY zuora_users.updated_at DESC LIMIT 1;
294
+ eos
295
+ user = ActiveRecord::Base.connection.execute(sql).to_a.first
296
+
297
+ if user.present?
298
+ zuora_identity_response = JSON.parse(user.fetch('zuora_identity_response', '{}'))
299
+ self.user_timezone = zuora_identity_response.values.first&.dig('timeZone')
300
+ else
301
+ if (Redis.current.hget(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id).to_i + TIMEZONE_LOG_PERIOD.to_i) <= Time.now.to_i
302
+ Rails.logger.error('Cannot find any user to set the timezone', app_instance_id: self.id)
303
+ Redis.current.hset(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id, Time.now.to_i)
304
+ end
305
+ end
306
+ rescue => ex
307
+ Rails.logger.error('There is an error while getting timezone users', ex)
308
+ end
309
+
310
+ if self.user_timezone.present?
311
+ # connect instance which has a custom timezone
312
+ if !self.auto_deployed? && (
313
+ ActiveSupport::TimeZone[self.task_data.dig('user_settings', 'timezone') || '']&.utc_offset !=
314
+ ActiveSupport::TimeZone[self.user_timezone]&.utc_offset
315
+ )
316
+ if self.environment == 'Production' &&
317
+ (Redis.current.hget(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id).to_i + TIMEZONE_LOG_PERIOD.to_i) <= Time.now.to_i
318
+ ZuoraConnect.logger.error(
319
+ "Instance and user timezones are different. User has '#{self.user_timezone}' and " \
320
+ "instance has '#{self.task_data.dig('user_settings', 'timezone')}'",
321
+ app_instance_id: self.id
322
+ )
323
+ Redis.current.hset(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id, Time.now.to_i)
324
+ end
325
+ self.user_timezone = nil
326
+ Time.zone = timezone
327
+ else
328
+ begin
329
+ Time.zone = self.user_timezone
330
+ rescue ArgumentError
331
+ Rails.logger.error('Malformed user timezone', app_instance_id: self.id)
332
+ Time.zone = timezone
333
+ end
334
+ end
335
+ else
336
+ Time.zone = timezone
337
+ end
338
+ end
339
+ rescue => e
340
+ Rails.logger.error('Malformed timezone used', e, app_instance_id: self.id)
341
+ Time.zone = self.timezone
342
+ end
343
+
344
+ def auto_deployed?
345
+ self.id >= 25000000
346
+ end
347
+
348
+ def refresh(session: {})
276
349
  refresh_count ||= 0
277
350
  skip_connect ||= false
278
351
  begin
279
352
  #Check how app was deployed
280
- if self.id < 25000000 && !skip_connect
353
+ if !self.auto_deployed? && !skip_connect
281
354
  self.check_oauth_state
282
355
  response = HTTParty.get(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}.json",:body => {:access_token => self.access_token})
283
356
 
@@ -289,16 +362,8 @@ module ZuoraConnect
289
362
  end
290
363
 
291
364
  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
365
+ self.set_backup_creds
366
+ self.save(validate: false) if self.changed?
302
367
  else
303
368
  raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
304
369
  end
@@ -338,9 +403,21 @@ module ZuoraConnect
338
403
  raise
339
404
  end
340
405
 
406
+ def aws_secrets
407
+ (Rails.application.secrets.aws || {}).transform_keys { |key| key.to_s }
408
+ end
409
+
341
410
  #### START KMS ENCRYPTION Methods ####
411
+ def set_backup_creds
412
+ if self.kms_key.present? && self.kms_key.match(/^arn:aws:.*/) && self.task_data.present?
413
+ self.zuora_logins = self.strip_cache_data(object: self.task_data.dup, keys: ['applications', 'tokens', 'user_settings'])
414
+ end
415
+ end
416
+
342
417
  def zuora_logins=(val)
343
418
  write_attribute(:zuora_logins, kms_encrypt(val.to_json))
419
+ rescue Aws::KMS::Errors::ValidationException, Aws::KMS::Errors::NotFoundException, *AWS_AUTH_ERRORS => ex
420
+ Rails.logger.warn(AWS_AUTH_ERRORS_MSG, ex)
344
421
  end
345
422
 
346
423
  def zuora_logins
@@ -350,7 +427,7 @@ module ZuoraConnect
350
427
 
351
428
  def kms_decrypt(value)
352
429
  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? })
430
+ kms_client = Aws::KMS::Client.new({region: aws_secrets['AWS_REGION'], credentials: self.aws_auth_client}.delete_if { |k, v| v.blank? })
354
431
  resp = kms_client.decrypt({ciphertext_blob: [value].pack("H*") })
355
432
  return resp.plaintext
356
433
  rescue *AWS_AUTH_ERRORS => ex
@@ -365,7 +442,7 @@ module ZuoraConnect
365
442
 
366
443
  def kms_encrypt(value)
367
444
  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? })
445
+ kms_client = Aws::KMS::Client.new({region: aws_secrets['AWS_REGION'], credentials: self.aws_auth_client}.delete_if {|k,v| v.blank? })
369
446
 
370
447
  resp = kms_client.encrypt({key_id: kms_key, plaintext: value})
371
448
  return resp.ciphertext_blob.unpack('H*').first
@@ -380,12 +457,12 @@ module ZuoraConnect
380
457
  end
381
458
 
382
459
  def kms_key
383
- return ENV['AWS_KMS_ARN'] || Rails.application.secrets.dig(:aws,'AWS_KMS_ARN')
460
+ return ENV['AWS_KMS_ARN'] || aws_secrets['AWS_KMS_ARN']
384
461
  end
385
462
 
386
463
  def aws_auth_client
387
464
  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'])
465
+ return Aws::Credentials.new(aws_secrets['AWS_ACCESS_KEY_ID'], aws_secrets['AWS_SECRET_ACCESS_KEY'])
389
466
  else
390
467
  return nil
391
468
  end
@@ -400,82 +477,6 @@ module ZuoraConnect
400
477
  end
401
478
  Thread.current[:appinstance] = self
402
479
  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
480
  #### END Task Methods ####
480
481
 
481
482
  #### START Task Methods ####
@@ -518,7 +519,7 @@ module ZuoraConnect
518
519
  end
519
520
  rescue ZuoraConnect::Exceptions::MissMatch => ex
520
521
  raise
521
- rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
522
+ rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
522
523
  raise
523
524
  rescue => ex
524
525
  ZuoraConnect.logger.error("Build Task Error", ex)
@@ -574,12 +575,12 @@ module ZuoraConnect
574
575
  self.refresh if !defined?(self.target_login)
575
576
 
576
577
  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
-
578
+
578
579
  if response.success?
579
580
  parsed_json = JSON.parse(response.body)
580
-
581
+
581
582
  #Set Org
582
- if self.id >= 25000000 && parsed_json['organization'].present?
583
+ if self.auto_deployed? && parsed_json['organization'].present?
583
584
  login_cache = self.zuora_logins
584
585
  login_cache.delete('organization')
585
586
  self.zuora_logins = login_cache.merge({'organizations' => [parsed_json['organization']]})
@@ -599,7 +600,7 @@ module ZuoraConnect
599
600
  end
600
601
  end
601
602
  self.save(:validate => false)
602
-
603
+
603
604
  return parsed_json
604
605
  end
605
606
  rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS + ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
@@ -653,7 +654,7 @@ module ZuoraConnect
653
654
  end
654
655
 
655
656
  def refresh_oauth
656
- refresh_oauth_count ||= 0
657
+ refresh_oauth_count ||= 0
657
658
  response = HTTParty.post("#{ZuoraConnect.configuration.url}/oauth/token", body: {
658
659
  :grant_type => "refresh_token",
659
660
  :redirect_uri => ZuoraConnect.configuration.oauth_client_redirect_uri,
@@ -955,13 +956,81 @@ module ZuoraConnect
955
956
  # object_id: The id or id's of the object/objects to be returned.
956
957
  # child_objects: Whether to include child objects of the object in question.
957
958
  # 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)
959
+ def catalog_lookup(entity_id: nil, object: :product, object_id: nil, child_objects: false, cache: false, source: 'DB')
959
960
  entity_reference = entity_id.blank? ? 'Default' : entity_id
960
961
 
961
962
  if object_id.present? && ![Array, String].include?(object_id.class)
962
963
  raise "Object Id can only be a string or an array of strings"
963
964
  end
964
965
 
966
+ if source == 'API'
967
+ catalog_container = {}
968
+
969
+ if (Redis.current.hget(CATALOG_LOOKUP_CACHE_TIME_KEY, self.id).to_i + CATALOG_LOOKUP_TTL.to_i) > Time.now.to_i
970
+ begin
971
+ catalog_container = JSON.parse(Redis.current.hget(CATALOG_LOOKUP_CACHE_RESULT_KEY, self.id))
972
+ rescue JSON::ParserError => ex
973
+ Rails.logger.warn('Failed to parse catalog cache', ex)
974
+ end
975
+ else
976
+ zuora_login = self.login_lookup(type: 'Zuora').first
977
+ login = zuora_login.client(entity_reference)
978
+
979
+ response = {
980
+ 'nextPage' => login.rest_endpoint("catalog/products?pageSize=#{CATALOG_LOOKUP_PAGE_SIZE}")
981
+ }
982
+
983
+ while response['nextPage'].present?
984
+ url = login.rest_endpoint(response['nextPage'].split('/v1/').last)
985
+ output_json, response = login.rest_call(debug: false, url: url, timeout_retry: true)
986
+
987
+ case object
988
+ when :product
989
+ output_json.fetch('products', []).each do |product|
990
+ rate_plans = {}
991
+ product['productRatePlans'].each do |rate_plan|
992
+ charges = {}
993
+ rate_plan['productRatePlanCharges'].each do |charge|
994
+ charges[charge['id']] = charge.merge(
995
+ {
996
+ 'productId' => product['id'],
997
+ 'productName' => product['name'],
998
+ 'productRatePlanId' => rate_plan['id'],
999
+ 'productRatePlanName' => rate_plan['name'],
1000
+ }
1001
+ )
1002
+ end
1003
+
1004
+ rate_plan['productRatePlanCharges'] = charges
1005
+ rate_plans[rate_plan['id']] = rate_plan.merge(
1006
+ {
1007
+ 'productId' => product['id'],
1008
+ 'productName' => product['name']
1009
+ }
1010
+ )
1011
+ end
1012
+
1013
+ product['productRatePlans'] = rate_plans
1014
+ catalog_container[product['id']] = product
1015
+ end
1016
+ else
1017
+ raise "Available objects include [:product]"
1018
+ end
1019
+ end
1020
+
1021
+ Redis.current.hset(CATALOG_LOOKUP_CACHE_RESULT_KEY, self.id, catalog_container.to_json)
1022
+ Redis.current.hset(CATALOG_LOOKUP_CACHE_TIME_KEY, self.id, Time.now.to_i)
1023
+ end
1024
+
1025
+ if object_id.nil?
1026
+ catalog_container.transform_values! { |v| v.except('productRatePlans') }
1027
+ elsif object_id.is_a?(String)
1028
+ catalog_container = catalog_container[object_id]
1029
+ end
1030
+
1031
+ return catalog_container
1032
+ end
1033
+
965
1034
  if defined?(Redis.current) && object_id.present? && object_id.class == String && object_id.present?
966
1035
  stub_catalog = cache ? decrypt_data(data: Redis.current.get("Catalog:#{self.id}:#{object_id}:Children:#{child_objects}")) : nil
967
1036
  object_hierarchy = decrypt_data(data: Redis.current.get("Catalog:#{self.id}:#{object_id}:Hierarchy"))
@@ -1221,7 +1290,7 @@ module ZuoraConnect
1221
1290
 
1222
1291
  def self.without_sticking
1223
1292
  if self.connection.respond_to?(:without_sticking)
1224
- self.connection.without_sticking do
1293
+ self.connection.without_sticking do
1225
1294
  yield
1226
1295
  end
1227
1296
  else