kaui 4.0.11 → 4.0.13

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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/kaui/kaui_override.js +21 -0
  3. data/app/assets/stylesheets/kaui/subscription.css +75 -0
  4. data/app/assets/stylesheets/kaui/tags.css +6 -3
  5. data/app/controllers/kaui/account_timelines_controller.rb +3 -3
  6. data/app/controllers/kaui/accounts_controller.rb +52 -52
  7. data/app/controllers/kaui/admin_allowed_users_controller.rb +29 -29
  8. data/app/controllers/kaui/admin_controller.rb +2 -2
  9. data/app/controllers/kaui/admin_tenants_controller.rb +89 -81
  10. data/app/controllers/kaui/audit_logs_controller.rb +1 -1
  11. data/app/controllers/kaui/bundles_controller.rb +53 -5
  12. data/app/controllers/kaui/chargebacks_controller.rb +1 -1
  13. data/app/controllers/kaui/charges_controller.rb +5 -2
  14. data/app/controllers/kaui/credits_controller.rb +1 -1
  15. data/app/controllers/kaui/custom_fields_controller.rb +11 -11
  16. data/app/controllers/kaui/engine_controller_util.rb +5 -5
  17. data/app/controllers/kaui/home_controller.rb +6 -2
  18. data/app/controllers/kaui/invoices_controller.rb +6 -4
  19. data/app/controllers/kaui/payment_methods_controller.rb +5 -5
  20. data/app/controllers/kaui/payments_controller.rb +19 -19
  21. data/app/controllers/kaui/queues_controller.rb +6 -6
  22. data/app/controllers/kaui/registrations_controller.rb +1 -1
  23. data/app/controllers/kaui/role_definitions_controller.rb +2 -2
  24. data/app/controllers/kaui/sessions_controller.rb +1 -1
  25. data/app/controllers/kaui/subscriptions_controller.rb +15 -14
  26. data/app/controllers/kaui/tag_definitions_controller.rb +1 -1
  27. data/app/controllers/kaui/tenants_controller.rb +2 -2
  28. data/app/controllers/kaui/transactions_controller.rb +6 -6
  29. data/app/helpers/kaui/account_helper.rb +9 -7
  30. data/app/helpers/kaui/exception_helper.rb +7 -5
  31. data/app/helpers/kaui/payment_helper.rb +2 -9
  32. data/app/helpers/kaui/plugin_helper.rb +3 -5
  33. data/app/helpers/kaui/subscription_helper.rb +46 -30
  34. data/app/helpers/kaui/uuid_helper.rb +1 -1
  35. data/app/models/kaui/account.rb +4 -3
  36. data/app/models/kaui/admin_tenant.rb +2 -2
  37. data/app/models/kaui/allowed_user.rb +3 -1
  38. data/app/models/kaui/allowed_user_tenant.rb +2 -2
  39. data/app/models/kaui/audit_log.rb +1 -1
  40. data/app/models/kaui/bundle.rb +11 -5
  41. data/app/models/kaui/invoice.rb +1 -1
  42. data/app/models/kaui/invoice_payment.rb +2 -2
  43. data/app/models/kaui/killbill_authenticatable.rb +2 -39
  44. data/app/models/kaui/killbill_registerable.rb +3 -11
  45. data/app/models/kaui/overdue.rb +5 -2
  46. data/app/models/kaui/payment.rb +1 -1
  47. data/app/models/kaui/payment_state.rb +3 -1
  48. data/app/models/kaui/rails_methods.rb +2 -2
  49. data/app/models/kaui/tag_definition.rb +2 -2
  50. data/app/models/kaui/tenant.rb +2 -1
  51. data/app/models/kaui/transaction.rb +1 -1
  52. data/app/services/dependencies/kenui.rb +1 -1
  53. data/app/views/kaui/accounts/_account_details.html.erb +1 -1
  54. data/app/views/kaui/admin_tenants/new_overdue_config.html.erb +25 -1
  55. data/app/views/kaui/bundles/_bundle_filterbar.html.erb +119 -0
  56. data/app/views/kaui/bundles/index.html.erb +28 -3
  57. data/app/views/kaui/components/search_input/_search_input.html.erb +39 -1
  58. data/app/views/kaui/invoices/index.html.erb +15 -11
  59. data/app/views/kaui/refunds/_form.html.erb +3 -11
  60. data/app/views/kaui/subscriptions/_form.html.erb +7 -1
  61. data/app/views/kaui/subscriptions/_subscriptions_table.html.erb +12 -1
  62. data/config/routes.rb +79 -79
  63. data/lib/devise/models/killbill_authenticatable.rb +38 -0
  64. data/lib/devise/models/killbill_registerable.rb +9 -0
  65. data/lib/generators/kaui/install/install_generator.rb +1 -4
  66. data/lib/kaui/version.rb +1 -1
  67. data/lib/kaui.rb +7 -7
  68. metadata +5 -2
@@ -10,68 +10,6 @@ module Kaui
10
10
  @tenants = Kaui::Tenant.all.select { |tenant| tenants_for_current_user.include?(tenant.kb_tenant_id) }
11
11
  end
12
12
 
13
- def new
14
- @tenant = Kaui::Tenant.new
15
- end
16
-
17
- def create
18
- param_tenant = params[:tenant]
19
-
20
- old_tenant = Kaui::Tenant.find_by_name(param_tenant[:name]) || Kaui::Tenant.find_by_api_key(param_tenant[:api_key])
21
- if old_tenant
22
- old_tenant.kaui_allowed_users << Kaui::AllowedUser.where(kb_username: current_user.kb_username).first_or_create
23
- redirect_to admin_tenant_path(old_tenant[:id]), notice: 'Tenant was successfully configured' and return
24
- end
25
-
26
- begin
27
- options = tenant_options_for_client
28
- new_tenant = nil
29
-
30
- begin
31
- options[:api_key] = param_tenant[:api_key]
32
- options[:api_secret] = param_tenant[:api_secret]
33
- new_tenant = Kaui::AdminTenant.find_by_api_key(param_tenant[:api_key], options)
34
- rescue KillBillClient::API::Unauthorized, KillBillClient::API::NotFound, KillBillClient::API::InternalServerError => e
35
- # Create the tenant in Kill Bill
36
- if e.instance_of?(KillBillClient::API::InternalServerError) && !e.message&.include?('TenantCacheLoader cannot find value')
37
- flash[:error] = "Internal server error while retrieving tenant: #{as_string(e)}"
38
- redirect_to admin_tenants_path and return
39
- end
40
- new_tenant = Kaui::AdminTenant.new
41
- new_tenant.external_key = param_tenant[:name]
42
- new_tenant.api_key = param_tenant[:api_key]
43
- new_tenant.api_secret = param_tenant[:api_secret]
44
- new_tenant = new_tenant.create(false, options[:username], nil, comment, options)
45
- end
46
-
47
- # Transform object to Kaui model
48
- tenant_model = Kaui::Tenant.new
49
- tenant_model.name = param_tenant[:name]
50
- tenant_model.api_key = param_tenant[:api_key]
51
- tenant_model.api_secret = param_tenant[:api_secret]
52
- tenant_model.kb_tenant_id = new_tenant.tenant_id
53
-
54
- # Save in KAUI tables
55
- tenant_model.save!
56
- # Make sure at least the current user can access the tenant
57
- tenant_model.kaui_allowed_users << Kaui::AllowedUser.where(kb_username: current_user.kb_username).first_or_create
58
- rescue KillBillClient::API::Conflict => _e
59
- # tenant api_key was found but has a wrong api_secret
60
- flash[:error] = "Submitted credentials for #{param_tenant[:api_key]} did not match the expected credentials."
61
- redirect_to admin_tenants_path and return
62
- rescue StandardError => e
63
- flash[:error] = "Failed to create the tenant: #{as_string(e)}"
64
- redirect_to admin_tenants_path and return
65
- end
66
-
67
- # Select the tenant, see TenantsController
68
- session[:kb_tenant_id] = tenant_model.kb_tenant_id
69
- session[:kb_tenant_name] = tenant_model.name
70
- session[:tenant_id] = tenant_model.id
71
-
72
- redirect_to admin_tenant_path(tenant_model[:id]), notice: 'Tenant was successfully configured'
73
- end
74
-
75
13
  def show
76
14
  @tenant = safely_find_tenant_by_id(params[:id])
77
15
  @allowed_users = @tenant.kaui_allowed_users & retrieve_allowed_users_for_current_user
@@ -140,6 +78,68 @@ module Kaui
140
78
  end
141
79
  end
142
80
 
81
+ def new
82
+ @tenant = Kaui::Tenant.new
83
+ end
84
+
85
+ def create
86
+ param_tenant = params[:tenant]
87
+
88
+ old_tenant = Kaui::Tenant.find_by(name: param_tenant[:name]) || Kaui::Tenant.find_by(api_key: param_tenant[:api_key])
89
+ if old_tenant
90
+ old_tenant.kaui_allowed_users << Kaui::AllowedUser.where(kb_username: current_user.kb_username).first_or_create
91
+ redirect_to admin_tenant_path(old_tenant[:id]), notice: 'Tenant was successfully configured' and return
92
+ end
93
+
94
+ begin
95
+ options = tenant_options_for_client
96
+ new_tenant = nil
97
+
98
+ begin
99
+ options[:api_key] = param_tenant[:api_key]
100
+ options[:api_secret] = param_tenant[:api_secret]
101
+ new_tenant = Kaui::AdminTenant.find_by_api_key(param_tenant[:api_key], options)
102
+ rescue KillBillClient::API::Unauthorized, KillBillClient::API::NotFound, KillBillClient::API::InternalServerError => e
103
+ # Create the tenant in Kill Bill
104
+ if e.instance_of?(KillBillClient::API::InternalServerError) && !e.message&.include?('TenantCacheLoader cannot find value')
105
+ flash[:error] = "Internal server error while retrieving tenant: #{as_string(e)}"
106
+ redirect_to admin_tenants_path and return
107
+ end
108
+ new_tenant = Kaui::AdminTenant.new
109
+ new_tenant.external_key = param_tenant[:name]
110
+ new_tenant.api_key = param_tenant[:api_key]
111
+ new_tenant.api_secret = param_tenant[:api_secret]
112
+ new_tenant = new_tenant.create(false, options[:username], nil, comment, options)
113
+ end
114
+
115
+ # Transform object to Kaui model
116
+ tenant_model = Kaui::Tenant.new
117
+ tenant_model.name = param_tenant[:name]
118
+ tenant_model.api_key = param_tenant[:api_key]
119
+ tenant_model.api_secret = param_tenant[:api_secret]
120
+ tenant_model.kb_tenant_id = new_tenant.tenant_id
121
+
122
+ # Save in KAUI tables
123
+ tenant_model.save!
124
+ # Make sure at least the current user can access the tenant
125
+ tenant_model.kaui_allowed_users << Kaui::AllowedUser.where(kb_username: current_user.kb_username).first_or_create
126
+ rescue KillBillClient::API::Conflict => _e
127
+ # tenant api_key was found but has a wrong api_secret
128
+ flash[:error] = "Submitted credentials for #{param_tenant[:api_key]} did not match the expected credentials."
129
+ redirect_to admin_tenants_path and return
130
+ rescue StandardError => e
131
+ flash[:error] = "Failed to create the tenant: #{as_string(e)}"
132
+ redirect_to admin_tenants_path and return
133
+ end
134
+
135
+ # Select the tenant, see TenantsController
136
+ session[:kb_tenant_id] = tenant_model.kb_tenant_id
137
+ session[:kb_tenant_name] = tenant_model.name
138
+ session[:tenant_id] = tenant_model.id
139
+
140
+ redirect_to admin_tenant_path(tenant_model[:id]), notice: 'Tenant was successfully configured'
141
+ end
142
+
143
143
  def upload_catalog
144
144
  current_tenant = safely_find_tenant_by_id(params[:id])
145
145
 
@@ -158,7 +158,7 @@ module Kaui
158
158
  end
159
159
  if catalog_validation_errors.blank?
160
160
  Kaui::AdminTenant.upload_catalog(catalog_xml, options[:username], nil, comment, options)
161
- redirect_to admin_tenant_path(current_tenant.id), notice: I18n.translate('flashes.notices.catalog_uploaded_successfully')
161
+ redirect_to admin_tenant_path(current_tenant.id), notice: I18n.t('flashes.notices.catalog_uploaded_successfully')
162
162
  else
163
163
  errors = ''
164
164
  catalog_validation_errors.each do |validation_error|
@@ -234,7 +234,7 @@ module Kaui
234
234
  options = tenant_options_for_client
235
235
  fetch_state_for_new_catalog_screen(options)
236
236
 
237
- simple_plan = params.require(:simple_plan).delete_if { |_e, value| value.blank? }
237
+ simple_plan = params.require(:simple_plan).permit!.to_h.compact_blank
238
238
  # Fix issue in Rails where first entry in the multi-select array is an empty string
239
239
  simple_plan['available_base_products']&.reject!(&:blank?)
240
240
 
@@ -288,7 +288,15 @@ module Kaui
288
288
  options = tenant_options_for_client
289
289
  options[:api_key] = @tenant.api_key
290
290
  options[:api_secret] = @tenant.api_secret
291
- @overdue = Kaui::Overdue.get_overdue_json(options)
291
+ begin
292
+ @overdue = Kaui::Overdue.get_overdue_json(options)
293
+ @overdue_corrupted = false
294
+ rescue StandardError => e
295
+ Rails.logger.warn("Failed to load overdue configuration for tenant #{@tenant.id}: #{e.class}: #{e.message}")
296
+ @overdue = KillBillClient::Model::Overdue.new.tap { |o| o.overdue_states = [] }
297
+ @overdue_corrupted = true
298
+ flash.now[:warning] = 'The existing overdue configuration is corrupted and cannot be loaded. Use the XML upload below to replace it with a valid configuration.'
299
+ end
292
300
  end
293
301
 
294
302
  def modify_overdue_config
@@ -298,12 +306,12 @@ module Kaui
298
306
  options[:api_key] = current_tenant.api_key
299
307
  options[:api_secret] = current_tenant.api_secret
300
308
 
301
- view_form_model = params.require(:kill_bill_client_model_overdue).delete_if { |_e, value| value.blank? }
302
- view_form_model['states'] = view_form_model['states'].values unless view_form_model['states'].blank?
309
+ view_form_model = params.require(:kill_bill_client_model_overdue).permit!.to_h.compact_blank
310
+ view_form_model['states'] = view_form_model['states'].values if view_form_model['states'].present?
303
311
 
304
312
  overdue = Kaui::Overdue.from_overdue_form_model(view_form_model)
305
313
  Kaui::Overdue.upload_tenant_overdue_config_json(overdue.to_json, options[:username], nil, comment, options)
306
- redirect_to admin_tenant_path(current_tenant.id, active_tab: 'OverdueShow'), notice: I18n.translate('flashes.notices.overdue_added_successfully')
314
+ redirect_to admin_tenant_path(current_tenant.id, active_tab: 'OverdueShow'), notice: I18n.t('flashes.notices.overdue_added_successfully')
307
315
  end
308
316
 
309
317
  def upload_overdue_config
@@ -319,13 +327,13 @@ module Kaui
319
327
  begin
320
328
  Nokogiri::XML(overdue_config_xml, &:strict)
321
329
  rescue Nokogiri::XML::SyntaxError => e
322
- flash[:error] = I18n.translate('errors.messages.invalid_xml', error: e)
330
+ flash[:error] = I18n.t('errors.messages.invalid_xml', error: e)
323
331
  redirect_to admin_tenant_path(current_tenant.id) and return
324
332
  end
325
333
 
326
334
  Kaui::AdminTenant.upload_overdue_config(overdue_config_xml, options[:username], nil, comment, options)
327
335
 
328
- redirect_to admin_tenant_path(current_tenant.id, active_tab: 'OverdueShow'), notice: I18n.translate('flashes.notices.overdue_uploaded_successfully')
336
+ redirect_to admin_tenant_path(current_tenant.id, active_tab: 'OverdueShow'), notice: I18n.t('flashes.notices.overdue_uploaded_successfully')
329
337
  end
330
338
 
331
339
  def upload_invoice_template
@@ -341,7 +349,7 @@ module Kaui
341
349
 
342
350
  Kaui::AdminTenant.upload_invoice_template(invoice_template, is_manual_pay, true, options[:username], nil, comment, options)
343
351
 
344
- redirect_to admin_tenant_path(current_tenant.id), notice: I18n.translate('flashes.notices.invoice_template_uploaded_successfully')
352
+ redirect_to admin_tenant_path(current_tenant.id), notice: I18n.t('flashes.notices.invoice_template_uploaded_successfully')
345
353
  end
346
354
 
347
355
  def upload_invoice_translation
@@ -357,7 +365,7 @@ module Kaui
357
365
 
358
366
  Kaui::AdminTenant.upload_invoice_translation(invoice_translation, locale, true, options[:username], nil, comment, options)
359
367
 
360
- redirect_to admin_tenant_path(current_tenant.id), notice: I18n.translate('flashes.notices.invoice_translation_uploaded_successfully')
368
+ redirect_to admin_tenant_path(current_tenant.id), notice: I18n.t('flashes.notices.invoice_translation_uploaded_successfully')
361
369
  end
362
370
 
363
371
  def upload_catalog_translation
@@ -373,7 +381,7 @@ module Kaui
373
381
 
374
382
  Kaui::AdminTenant.upload_catalog_translation(catalog_translation, locale, true, options[:username], nil, comment, options)
375
383
 
376
- redirect_to admin_tenant_path(current_tenant.id), notice: I18n.translate('flashes.notices.catalog_translation_uploaded_successfully')
384
+ redirect_to admin_tenant_path(current_tenant.id), notice: I18n.t('flashes.notices.catalog_translation_uploaded_successfully')
377
385
  end
378
386
 
379
387
  def upload_plugin_config
@@ -407,18 +415,18 @@ module Kaui
407
415
  au = Kaui::AllowedUser.find(params.require(:allowed_user).require(:id))
408
416
 
409
417
  unless current_user.root?
410
- render json: { alert: 'Only the root user can remove users from tenants' }.to_json, status: 401
418
+ render json: { alert: 'Only the root user can remove users from tenants' }.to_json, status: :unauthorized
411
419
  return
412
420
  end
413
421
 
414
422
  # remove the association
415
423
  au.kaui_tenants.delete current_tenant
416
- render json: '{}', status: 200
424
+ render json: '{}', status: :ok
417
425
  end
418
426
 
419
427
  def add_allowed_user
420
428
  current_tenant = safely_find_tenant_by_id(params[:tenant_id])
421
- allowed_user = Kaui::AllowedUser.find_by_kb_username(params.require(:allowed_user).require(:kb_username))
429
+ allowed_user = Kaui::AllowedUser.find_by(kb_username: params.require(:allowed_user).require(:kb_username))
422
430
 
423
431
  unless current_user.root?
424
432
  flash[:error] = 'Only the root user can add users from tenants'
@@ -498,10 +506,10 @@ module Kaui
498
506
 
499
507
  if params[:commit] == 'Submit'
500
508
  date = Date.parse(params[:new_date]).strftime('%Y-%m-%d')
501
- msg = I18n.translate('flashes.notices.clock_updated_successfully', new_date: date)
509
+ msg = I18n.t('flashes.notices.clock_updated_successfully', new_date: date)
502
510
  else
503
511
  date = nil
504
- msg = I18n.translate('flashes.notices.clock_reset_successfully')
512
+ msg = I18n.t('flashes.notices.clock_reset_successfully')
505
513
  end
506
514
 
507
515
  begin
@@ -515,7 +523,7 @@ module Kaui
515
523
  end
516
524
 
517
525
  def switch_tenant
518
- tenant = Kaui::Tenant.find_by_kb_tenant_id(params.require(:kb_tenant_id))
526
+ tenant = Kaui::Tenant.find_by(kb_tenant_id: params.require(:kb_tenant_id))
519
527
 
520
528
  # Select the tenant, see TenantsController
521
529
  session[:kb_tenant_id] = tenant.kb_tenant_id
@@ -560,7 +568,7 @@ module Kaui
560
568
  end
561
569
 
562
570
  def safely_find_tenant_by_id(tenant_id)
563
- tenant = Kaui::Tenant.find_by_id(tenant_id)
571
+ tenant = Kaui::Tenant.find_by(id: tenant_id)
564
572
  raise ActiveRecord::RecordNotFound, "Could not find tenant #{tenant_id}" unless retrieve_tenants_for_current_user.include?(tenant.kb_tenant_id)
565
573
 
566
574
  tenant
@@ -606,7 +614,7 @@ module Kaui
606
614
  end
607
615
 
608
616
  catalog_xml = {}
609
- catalog_xml = response[0][:xml] unless response.blank?
617
+ catalog_xml = response[0][:xml] if response.present?
610
618
 
611
619
  catalog_xml
612
620
  end
@@ -76,7 +76,7 @@ module Kaui
76
76
  end
77
77
  end
78
78
 
79
- send_data csv_file, type: 'text/csv', filename: "audit-logs-#{Date.today}.csv"
79
+ send_data csv_file, type: 'text/csv', filename: "audit-logs-#{Time.zone.today}.csv"
80
80
  end
81
81
 
82
82
  def history
@@ -5,10 +5,11 @@ module Kaui
5
5
  # rubocop:disable Lint/HashCompareByIdentity
6
6
  def index
7
7
  cached_options_for_klient = options_for_klient
8
+ @search_query = params[:q].presence
9
+ @search_by = params[:search_by] || 'bundle_id'
8
10
  @per_page = (params[:per_page] || 10).to_i
9
11
  @page = (params[:page] || 1).to_i
10
12
 
11
- fetch_bundles = promise { Kaui::Account.paginated_bundles(@account.account_id, (@page - 1) * @per_page, @per_page, 'NONE', cached_options_for_klient) }
12
13
  fetch_bundle_tags = promise do
13
14
  all_bundle_tags = @account.all_tags(:BUNDLE, false, 'NONE', cached_options_for_klient)
14
15
  all_bundle_tags.each_with_object({}) do |entry, hsh|
@@ -36,8 +37,15 @@ module Kaui
36
37
  fetch_available_tags = promise { Kaui::TagDefinition.all_for_bundle(cached_options_for_klient) }
37
38
  fetch_available_subscription_tags = promise { Kaui::TagDefinition.all_for_subscription(cached_options_for_klient) }
38
39
 
39
- @bundles = wait(fetch_bundles)
40
- @total_pages = (@bundles.pagination_max_nb_records.to_f / @per_page).ceil
40
+ if @search_query.present?
41
+ @bundles = search_bundles(@search_query, @search_by, cached_options_for_klient)
42
+ @total_pages = 1
43
+ @page = 1
44
+ else
45
+ fetched = Kaui::Account.paginated_bundles(@account.account_id, (@page - 1) * @per_page, @per_page, 'NONE', cached_options_for_klient)
46
+ @bundles = fetched
47
+ @total_pages = (fetched.pagination_max_nb_records.to_f / @per_page).ceil
48
+ end
41
49
 
42
50
  @tags_per_bundle = wait(fetch_bundle_tags)
43
51
  @tags_per_subscription = wait(fetch_subscription_tags)
@@ -46,8 +54,15 @@ module Kaui
46
54
  @available_tags = wait(fetch_available_tags)
47
55
  @available_subscription_tags = wait(fetch_available_subscription_tags)
48
56
 
49
- # Don't load the full catalog to avoid memory issues
50
- @catalog = nil
57
+ # Collect the distinct start dates from subscriptions on this page, then fetch
58
+ # only the catalog versions needed — one per unique date — to avoid loading all
59
+ # historical versions into memory.
60
+ start_dates = @bundles.flat_map(&:subscriptions).filter_map(&:start_date).uniq
61
+ @catalogs = start_dates.filter_map do |date|
62
+ Kaui::Catalog.get_account_catalog_json(@account.account_id, date, cached_options_for_klient)&.last
63
+ rescue StandardError
64
+ nil
65
+ end.uniq(&:effective_date)
51
66
 
52
67
  @subscription = {}
53
68
  @bundles.each do |bundle|
@@ -112,5 +127,38 @@ module Kaui
112
127
  end
113
128
  redirect_to kaui_engine.account_bundles_path(@account.account_id), notice: msg
114
129
  end
130
+
131
+ private
132
+
133
+ def search_bundles(query, search_by, options)
134
+ case search_by
135
+ when 'bundle_id'
136
+ bundle = Kaui::Bundle.find_by_id(query, options)
137
+ bundle ? [bundle] : []
138
+ when 'bundle_external_key'
139
+ bundle = Kaui::Bundle.find_by_external_key(query, false, options)
140
+ bundle ? [bundle] : []
141
+ when 'subscription_id'
142
+ subscription = KillBillClient::Model::Subscription.find_by_id(query, 'NONE', options)
143
+ if subscription
144
+ bundle = Kaui::Bundle.find_by_id(subscription.bundle_id, options)
145
+ bundle ? [bundle] : []
146
+ else
147
+ []
148
+ end
149
+ when 'subscription_external_key'
150
+ subscription = KillBillClient::Model::Subscription.find_by_external_key(query, 'NONE', options)
151
+ if subscription
152
+ bundle = Kaui::Bundle.find_by_id(subscription.bundle_id, options)
153
+ bundle ? [bundle] : []
154
+ else
155
+ []
156
+ end
157
+ else
158
+ []
159
+ end
160
+ rescue KillBillClient::API::NotFound
161
+ []
162
+ end
115
163
  end
116
164
  end
@@ -29,7 +29,7 @@ module Kaui
29
29
  account.bundles(cached_options_for_klient).each do |bundle|
30
30
  bundle.subscriptions.each do |subscription|
31
31
  # Already cancelled?
32
- next unless subscription.billing_end_date.blank?
32
+ next if subscription.billing_end_date.present?
33
33
 
34
34
  # Cancel the entitlement immediately but use the default billing policy
35
35
  entitlement = Kaui::Subscription.new(subscription_id: subscription.subscription_id)
@@ -19,13 +19,16 @@ module Kaui
19
19
  end
20
20
 
21
21
  def create
22
- charge = Kaui::InvoiceItem.new(params.require(:invoice_item).delete_if { |_key, value| value.blank? })
22
+ charge = Kaui::InvoiceItem.new(params.require(:invoice_item).permit!.to_h.compact_blank)
23
23
  charge.account_id ||= params.require(:account_id)
24
24
 
25
+ # Preserve the original invoice_id since the API may not return it
26
+ original_invoice_id = charge.invoice_id
27
+
25
28
  auto_commit = params[:auto_commit] == '1'
26
29
 
27
30
  charge = charge.create(auto_commit, current_user.kb_username, params[:reason], params[:comment], options_for_klient)
28
- redirect_to kaui_engine.account_invoice_path(charge.account_id, charge.invoice_id), notice: 'Charge was successfully created'
31
+ redirect_to kaui_engine.account_invoice_path(charge.account_id, charge.invoice_id || original_invoice_id), notice: 'Charge was successfully created'
29
32
  end
30
33
  end
31
34
  end
@@ -19,7 +19,7 @@ module Kaui
19
19
  end
20
20
 
21
21
  def create
22
- credit = Kaui::Credit.new(params[:credit].delete_if { |_key, value| value.blank? })
22
+ credit = Kaui::Credit.new(params[:credit].permit!.to_h.compact_blank)
23
23
  credit.account_id ||= params.require(:account_id)
24
24
 
25
25
  # No need to show the newly created invoice for account level credits
@@ -101,7 +101,7 @@ module Kaui
101
101
  end
102
102
 
103
103
  if test_uuid.blank?
104
- flash[:error] = I18n.translate('object_invalid_dont_exist')
104
+ flash[:error] = I18n.t('object_invalid_dont_exist')
105
105
  redirect_to custom_fields_path
106
106
  return
107
107
  end
@@ -120,12 +120,12 @@ module Kaui
120
120
  when :INVOICE_ITEM
121
121
  Kaui::InvoiceItem.new(invoice_item_id: @custom_field.object_id)
122
122
  else
123
- flash.now[:error] = I18n.translate('invalid_object_type', error: @custom_field.object_type)
123
+ flash.now[:error] = I18n.t('invalid_object_type', error: @custom_field.object_type)
124
124
  render :new and return
125
125
  end
126
126
  model.add_custom_field(@custom_field, current_user.kb_username, params[:reason], params[:comment], options_for_klient)
127
127
 
128
- redirect_to custom_fields_path, notice: I18n.translate('custom_field_created_success')
128
+ redirect_to custom_fields_path, notice: I18n.t('custom_field_created_success')
129
129
  end
130
130
 
131
131
  private
@@ -143,7 +143,7 @@ module Kaui
143
143
  rescue StandardError
144
144
  # Ignore
145
145
  ensure
146
- msg = { status: '200', message: I18n.translate('custom_field_uuid_exist_in_invoice_item_db') } unless test_uuid.blank?
146
+ msg = { status: '200', message: I18n.t('custom_field_uuid_exist_in_invoice_item_db') } if test_uuid.present?
147
147
  end
148
148
  when 'ACCOUNT'
149
149
  begin
@@ -151,7 +151,7 @@ module Kaui
151
151
  rescue StandardError
152
152
  # Ignore
153
153
  ensure
154
- msg = { status: '200', message: I18n.translate('custom_field_uuid_exist_in_account_db') } if !test_uuid.blank? && (test_uuid.account_id == param_uuid)
154
+ msg = { status: '200', message: I18n.t('custom_field_uuid_exist_in_account_db') } if test_uuid.present? && (test_uuid.account_id == param_uuid)
155
155
  end
156
156
  when 'BUNDLE'
157
157
  begin
@@ -159,7 +159,7 @@ module Kaui
159
159
  rescue StandardError
160
160
  # Ignore
161
161
  ensure
162
- msg = { status: '200', message: I18n.translate('custom_field_uuid_exist_in_bundle_db') } if !test_uuid.blank? && (test_uuid.bundle_id == param_uuid)
162
+ msg = { status: '200', message: I18n.t('custom_field_uuid_exist_in_bundle_db') } if test_uuid.present? && (test_uuid.bundle_id == param_uuid)
163
163
  end
164
164
  when 'SUBSCRIPTION'
165
165
  begin
@@ -167,7 +167,7 @@ module Kaui
167
167
  rescue StandardError
168
168
  # Ignore
169
169
  ensure
170
- msg = { status: '200', message: I18n.translate('custom_field_uuid_exist_in_subscription_db') } if !test_uuid.blank? && (test_uuid.subscription_id == param_uuid)
170
+ msg = { status: '200', message: I18n.t('custom_field_uuid_exist_in_subscription_db') } if test_uuid.present? && (test_uuid.subscription_id == param_uuid)
171
171
  end
172
172
  when 'INVOICE'
173
173
  begin
@@ -176,7 +176,7 @@ module Kaui
176
176
  rescue StandardError
177
177
  # Ignore
178
178
  ensure
179
- msg = { status: '200', message: I18n.translate('custom_field_uuid_exist_in_invoice_db') } if !test_uuid.blank? && (test_uuid.invoice_id == param_uuid)
179
+ msg = { status: '200', message: I18n.t('custom_field_uuid_exist_in_invoice_db') } if test_uuid.present? && (test_uuid.invoice_id == param_uuid)
180
180
  end
181
181
  when 'PAYMENT'
182
182
  begin
@@ -184,18 +184,18 @@ module Kaui
184
184
  rescue StandardError
185
185
  # Ignore
186
186
  ensure
187
- msg = { status: '200', message: I18n.translate('custom_field_uuid_exist_in_invoice_payment_db') } if !test_uuid.blank? && (test_uuid.payment_id == param_uuid)
187
+ msg = { status: '200', message: I18n.t('custom_field_uuid_exist_in_invoice_payment_db') } if test_uuid.present? && (test_uuid.payment_id == param_uuid)
188
188
  end
189
189
  begin
190
190
  test_uuid = Kaui::Payment.find_by_external_key(param_uuid, false, true, options_for_klient)
191
191
  rescue StandardError
192
192
  # Ignore
193
193
  ensure
194
- msg = { status: '200', message: I18n.translate('custom_field_uuid_exist_in_payment_db') } if !test_uuid.blank? && (test_uuid.payment_id == param_uuid)
194
+ msg = { status: '200', message: I18n.t('custom_field_uuid_exist_in_payment_db') } if test_uuid.present? && (test_uuid.payment_id == param_uuid)
195
195
  end
196
196
  end
197
197
 
198
- msg ||= { status: '431', message: I18n.translate('custom_field_uuid_do_not_exist_in_db') }
198
+ msg ||= { status: '431', message: I18n.t('custom_field_uuid_do_not_exist_in_db') }
199
199
  render json: msg
200
200
  end
201
201
  end
@@ -111,9 +111,9 @@ module Kaui
111
111
  def promise_as_string(promise)
112
112
  return 'nil' if promise.nil?
113
113
 
114
- executor = promise.instance_variable_get('@executor')
114
+ executor = promise.instance_variable_get(:@executor)
115
115
  executor_as_string = "queue_length=#{executor.queue_length}, pool_size=#{executor.length}"
116
- "#{promise.instance_variable_get('@promise_body')}[state=#{promise.state}, parent=#{promise_as_string(promise.instance_variable_get('@parent'))}, executor=[#{executor_as_string}]]"
116
+ "#{promise.instance_variable_get(:@promise_body)}[state=#{promise.state}, parent=#{promise_as_string(promise.instance_variable_get(:@parent))}, executor=[#{executor_as_string}]]"
117
117
  end
118
118
 
119
119
  # Used to format flash error messages
@@ -127,7 +127,7 @@ module Kaui
127
127
  as_string(exception.cause)
128
128
  else
129
129
  log_rescue_error(exception)
130
- exception.message
130
+ exception.message.to_s[0..200]
131
131
  end
132
132
  end
133
133
 
@@ -147,10 +147,10 @@ module Kaui
147
147
  if error_message.respond_to?(:[]) && error_message['message'].present?
148
148
  # Likely BillingExceptionJson
149
149
  error_message = error_message['message']
150
- error_message += " (code=#{error_message['code']})" unless error_message['code'].blank?
150
+ error_message += " (code=#{error_message['code']})" if error_message['code'].present?
151
151
  end
152
152
  # Limit the error size to avoid ActionDispatch::Cookies::CookieOverflow
153
- error_message[0..1000]
153
+ error_message.to_s[0..200]
154
154
  end
155
155
 
156
156
  def nested_hash_value(obj, key)
@@ -20,6 +20,10 @@ module Kaui
20
20
 
21
21
  def search
22
22
  object_type, search_query = splitting_new_search(params[:q])
23
+ if search_query.nil?
24
+ search_error('Please specify a search type (e.g., "Account: search_term")')
25
+ return
26
+ end
23
27
  object_type = object_type.tr(' ', '_').downcase
24
28
  cached_options_for_klient = options_for_klient
25
29
  send("#{object_type}_search", search_query, nil, 0, cached_options_for_klient)
@@ -254,7 +258,7 @@ module Kaui
254
258
  end
255
259
 
256
260
  def unsupported_search_field(object_type, object_field)
257
- field_name = object_field.gsub('_', ' ')
261
+ field_name = object_field.tr('_', ' ')
258
262
  search_error("\"#{object_type}\": Search by \"#{field_name}\" is not supported.")
259
263
  end
260
264
 
@@ -283,7 +287,7 @@ module Kaui
283
287
  '0'
284
288
  end
285
289
 
286
- search_error("\"#{search_by}\" is not a valid search by value") if !search_by.blank? && !search_by.in?(Kaui::ObjectHelper::ADVANCED_SEARCH_OBJECT_FIELDS)
290
+ search_error("\"#{search_by}\" is not a valid search by value") if search_by.present? && !search_by.in?(Kaui::ObjectHelper::ADVANCED_SEARCH_OBJECT_FIELDS)
287
291
 
288
292
  [object_type, search_for, search_by, fast]
289
293
  end
@@ -6,7 +6,7 @@ module Kaui
6
6
  def index
7
7
  @search_query = params[:account_id]
8
8
  @advance_search_query = params[:q] || request.query_string
9
- @ordering = params[:ordering] || (@search_query.blank? ? 'desc' : 'asc')
9
+ @ordering = params[:ordering] || 'desc'
10
10
  @offset = params[:offset] || 0
11
11
  @limit = params[:limit] || 50
12
12
  @search_fields = Kaui::Invoice::ADVANCED_SEARCH_COLUMNS.map { |attr| [attr, attr.split('_').join(' ').capitalize] }
@@ -21,7 +21,7 @@ module Kaui
21
21
  all_fields_checked = params[:allFieldsChecked] == 'true'
22
22
  query_string = handle_balance_search(params[:search])
23
23
  columns = if all_fields_checked
24
- KillBillClient::Model::InvoiceAttributes.instance_variable_get('@json_attributes') - Kaui::Invoice::TABLE_IGNORE_COLUMNS
24
+ KillBillClient::Model::InvoiceAttributes.instance_variable_get(:@json_attributes) - Kaui::Invoice::TABLE_IGNORE_COLUMNS
25
25
  else
26
26
  params.require(:columnsString).split(',').map { |attr| attr.split.join('_').downcase }
27
27
  end
@@ -52,7 +52,7 @@ module Kaui
52
52
  csv << columns.map { |attr| invoice&.send(attr.downcase) }
53
53
  end
54
54
  end
55
- send_data csv_string, filename: "invoices-#{Date.today}.csv", type: 'text/csv'
55
+ send_data csv_string, filename: "invoices-#{Time.zone.today}.csv", type: 'text/csv'
56
56
  end
57
57
 
58
58
  def pagination
@@ -134,7 +134,7 @@ module Kaui
134
134
  end
135
135
  end
136
136
 
137
- fetch_invoice_tags = promise { @invoice.tags(false, 'NONE', cached_options_for_klient).sort { |tag_a, tag_b| tag_a <=> tag_b } }
137
+ fetch_invoice_tags = promise { @invoice.tags(false, 'NONE', cached_options_for_klient).sort }
138
138
  fetch_available_invoice_tags = promise { Kaui::TagDefinition.all_for_invoice(cached_options_for_klient) }
139
139
 
140
140
  @payments = wait(fetch_payments)
@@ -173,7 +173,9 @@ module Kaui
173
173
  end
174
174
 
175
175
  def show_html
176
+ # rubocop:disable Rails/OutputSafety -- Invoice HTML from Kill Bill backend is trusted
176
177
  render html: Kaui::Invoice.as_html(params.require(:id), options_for_klient).html_safe
178
+ # rubocop:enable Rails/OutputSafety
177
179
  end
178
180
 
179
181
  def commit_invoice
@@ -2,13 +2,17 @@
2
2
 
3
3
  module Kaui
4
4
  class PaymentMethodsController < Kaui::EngineController
5
+ def show
6
+ restful_show
7
+ end
8
+
5
9
  def new
6
10
  @payment_method = Kaui::PaymentMethod.new(account_id: params[:account_id],
7
11
  plugin_name: params[:plugin_name] || Kaui.creditcard_plugin_name.call)
8
12
  end
9
13
 
10
14
  def create
11
- @payment_method = Kaui::PaymentMethod.new(params[:payment_method].delete_if { |_key, value| value.blank? })
15
+ @payment_method = Kaui::PaymentMethod.new(params[:payment_method].permit!.to_h.compact_blank)
12
16
  # Transform "1" into boolean
13
17
  @payment_method.is_default = @payment_method.is_default == '1'
14
18
  # Sensible default
@@ -84,10 +88,6 @@ module Kaui
84
88
  end
85
89
  end
86
90
 
87
- def show
88
- restful_show
89
- end
90
-
91
91
  def restful_show
92
92
  payment_method = Kaui::PaymentMethod.find_by_id(params.require(:id), false, false, [], 'NONE', options_for_klient)
93
93
  redirect_to kaui_engine.account_path(payment_method.account_id)