diff --git a/app/controllers/kaui/account_timelines_controller.rb b/app/controllers/kaui/account_timelines_controller.rb index f16412e9..5c3d1c40 100644 --- a/app/controllers/kaui/account_timelines_controller.rb +++ b/app/controllers/kaui/account_timelines_controller.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'csv' + module Kaui class AccountTimelinesController < Kaui::EngineController def show @@ -30,8 +32,127 @@ def show @selected_bundle = params.key?(:external_key) ? @bundle_names[params[:external_key]] : nil end + def download + timeline = Kaui::AccountTimeline.find_by_account_id(params.require(:account_id), 'FULL', options_for_klient) + start_date = params[:startDate] + end_date = params[:endDate] + start_date = begin + Date.parse(start_date) + rescue StandardError + nil + end + end_date = begin + Date.parse(end_date) + rescue StandardError + nil + end + start_date = params[:startDate].present? ? Date.parse(params[:startDate]) : nil + end_date = params[:endDate].present? ? Date.parse(params[:endDate]) : nil + + event_type = params[:eventType] + @account = timeline.account + @bundles = timeline.bundles + @invoices = timeline.invoices + @payments = timeline.payments + extract_invoices_by_id(@invoices) + + # Lookup all bundle names + @bundle_names = {} + @bundle_names_by_invoice_id = {} + @bundle_keys_by_invoice_id = {} + @bundles.each do |bundle| + load_bundle_name_for_timeline(bundle.external_key) + end + @invoices.each do |invoice| + @bundle_names_by_invoice_id[invoice.invoice_id] = Set.new + @bundle_keys_by_invoice_id[invoice.invoice_id] = Set.new + (invoice.bundle_keys || '').split(',').each do |bundle_key| + load_bundle_name_for_timeline(bundle_key) + @bundle_names_by_invoice_id[invoice.invoice_id] << @bundle_names[bundle_key] + @bundle_keys_by_invoice_id[invoice.invoice_id] << bundle_key + end + end + + @selected_bundle = params.key?(:external_key) ? @bundle_names[params[:external_key]] : nil + + csv_string = CSV.generate(headers: true) do |csv| + csv << ['Effective Date', 'Bundles', 'Even Type', 'Details', 'Reason Code/ Comments'] + if %w[INVOICE ALL].include?(event_type) + @invoices.each do |invoice_stub| + invoice = invoice_stub.invoice_id.present? && @invoices_by_id.key?(invoice_stub.invoice_id) ? @invoices_by_id[invoice_stub.invoice_id] : invoice_stub + target_date = invoice.target_date.present? ? invoice.target_date : '[unknown]' + bundle_keys = invoice_stub.bundle_keys.present? ? invoice_stub.bundle_keys.split(',').map { |bundle_key| @bundle_names[bundle_key] }.join(', ') : '' + invoice_details = [] + invoice_details << "Amount: #{invoice.amount_to_money} (#{@account.currency})" + invoice_details << "Balance: #{invoice.balance_to_money} (#{@account.currency})" + invoice_details << "Credit adjustment: #{invoice.credit_adjustment_to_money} (#{@account.currency})" if invoice.credit_adj.present? && invoice.credit_adj.positive? + invoice_details << "Refund adjustment: #{invoice.refund_adjustment_to_money} (#{@account.currency})" if invoice.refund_adj.present? && invoice.refund_adj.negative? + invoice_details << "Invoice #: #{invoice.invoice_number}" + audit_logs = invoice_stub.audit_logs.present? ? invoice_stub.audit_logs.map { |entry| Kaui::AuditLog.description(entry) }.join(', ') : '' + csv << [target_date, bundle_keys, 'INVOICE', invoice_details.join('; '), audit_logs] if filter_date(target_date, start_date, end_date) + end + end + if %w[PAYMENT ALL].include?(event_type) + @payments.each do |payment| + invoice = if payment.target_invoice_id.present? + @invoices_by_id[payment.target_invoice_id] + else + nil + end + + payment.transactions.each do |transaction| + effective_date = transaction.effective_date.present? ? transaction.effective_date : '[unknown]' + bundle_keys = @bundle_keys_by_invoice_id[payment.target_invoice_id].present? ? @bundle_keys_by_invoice_id[payment.target_invoice_id].map { |bundle_key| @bundle_names[bundle_key] }.join(', ') : '' + transaction_type = transaction.transaction_type + details = [] + details << "Amount: #{Kaui::Transaction.amount_to_money(transaction)} (#{transaction.currency})" unless transaction.transaction_type == 'VOID' + details << "Status: #{transaction.status}" + details << "Payment #: #{payment.payment_number}" + details << "Invoice #: #{invoice.invoice_number}" unless invoice.nil? + + audit_logs = transaction.audit_logs.present? ? transaction.audit_logs.map { |entry| Kaui::AuditLog.description(entry) }.chunk { |x| x }.map(&:first).join(', ') : '' + + csv << [effective_date, bundle_keys, transaction_type, details.join('; '), audit_logs] if filter_date(effective_date, start_date, end_date) + end + end + end + + if %w[ENTITLEMENT ALL].include?(event_type) + @bundles.each do |bundle| + bundle.subscriptions.each do |sub| + sub.events.each do |event| + # Skip SERVICE_STATE_CHANGE events + next if event.event_type == 'SERVICE_STATE_CHANGE' + + effective_date = event.effective_date.present? ? event.effective_date : '[unknown]' + bundle_keys = @bundle_names[bundle.external_key] + event_type = event.event_type + phase = event.phase + audit_logs = event.audit_logs.present? ? event.audit_logs.map { |entry| Kaui::AuditLog.description(entry) }.join(', ') : '' + + csv << [effective_date, bundle_keys, event_type, phase, audit_logs] if filter_date(effective_date, start_date, end_date) + end + end + end + end + end + + send_data csv_string, filename: "account-timelines-#{Date.today}.csv", type: 'text/csv' + end + private + def filter_date(target_date, start_date, end_date) + return true if start_date.nil? || end_date.nil? + + target_date = begin + Date.parse(target_date) + rescue StandardError + nil + end + target_date >= start_date && target_date <= end_date + end + def load_bundle_name_for_timeline(bundle_key) @bundle_names[bundle_key] ||= Kaui.bundle_key_display_string.call(bundle_key) end diff --git a/app/controllers/kaui/accounts_controller.rb b/app/controllers/kaui/accounts_controller.rb index efd0b470..7d196305 100644 --- a/app/controllers/kaui/accounts_controller.rb +++ b/app/controllers/kaui/accounts_controller.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require 'csv' module Kaui class AccountsController < Kaui::EngineController def index @@ -16,6 +17,8 @@ def index return end + @dropdown_default = default_columns(Kaui.account_search_columns.call[2], Kaui::Account::SENSIVITE_DATA_FIELDS) + @ordering = params[:ordering] || (@search_query.blank? ? 'desc' : 'asc') @offset = params[:offset] || 0 @limit = params[:limit] || 50 @@ -42,7 +45,38 @@ def pagination Kaui.account_search_columns.call(account, view_context)[1] end - paginate searcher, data_extractor, formatter + paginate searcher, data_extractor, formatter, default_columns(Kaui.account_search_columns.call[2], Kaui::Account::SENSIVITE_DATA_FIELDS) + end + + def download + columns = params.require(:columnsString).split(',').map { |attr| attr.split.join('_').downcase } + start_date = params[:startDate] + end_date = params[:endDate] + start_date = begin + Date.parse(start_date) + rescue StandardError + nil + end + end_date = begin + Date.parse(end_date) + rescue StandardError + nil + end + accounts = Kaui::Account.list_or_search(nil, 0, MAXIMUM_NUMBER_OF_RECORDS_DOWNLOAD, options_for_klient) + + csv_string = CSV.generate(headers: true) do |csv| + csv << columns + accounts.each do |account| + change_date = Date.parse(account.reference_time) + data = columns.map do |attr| + account&.send(attr.downcase) + end + next if start_date && end_date && change_date && (change_date < start_date || change_date > end_date) + + csv << data + end + end + send_data csv_string, filename: "accounts-#{Date.today}.csv", type: 'text/csv' end def new diff --git a/app/controllers/kaui/audit_logs_controller.rb b/app/controllers/kaui/audit_logs_controller.rb index 0554974b..e1dfbcf7 100644 --- a/app/controllers/kaui/audit_logs_controller.rb +++ b/app/controllers/kaui/audit_logs_controller.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'csv' + module Kaui class AuditLogsController < Kaui::EngineController OBJECT_WITH_HISTORY = %w[ACCOUNT ACCOUNT_EMAIL BLOCKING_STATES BUNDLE CUSTOM_FIELD INVOICE INVOICE_ITEM PAYMENT_ATTEMPT PAYMENT PAYMENT_METHOD SUBSCRIPTION SUBSCRIPTION_EVENT TRANSACTION TAG TAG_DEFINITION].freeze @@ -42,6 +44,41 @@ def index @audit_logs_json = @audit_logs_json.to_json end + def download + account_id = params.require(:account_id) + start_date = params[:startDate] + end_date = params[:endDate] + start_date = begin + Date.parse(start_date) + rescue StandardError + nil + end + end_date = begin + Date.parse(end_date) + rescue StandardError + nil + end + + account = Kaui::Account.find_by_id_or_key(account_id, false, false, options_for_klient) + audit_logs = account.audit(options_for_klient) + + csv_file = CSV.generate do |csv| + csv << Kaui.account_audit_logs_columns.call[0] + audit_logs.each do |log| + change_date = begin + Date.parse(log.change_date) + rescue StandardError + nil + end + next if start_date && end_date && change_date && !(change_date > start_date && change_date < end_date) + + csv << [log.change_date, log.object_id, log.object_type, log.change_type, log.changed_by, log.reason_code, log.comments, log.user_token] + end + end + + send_data csv_file, type: 'text/csv', filename: "audit_logs_#{account_id}.csv" + end + def history json_response do account_id = params.require(:account_id) diff --git a/app/controllers/kaui/engine_controller_util.rb b/app/controllers/kaui/engine_controller_util.rb index 4a55f5be..8c645b24 100644 --- a/app/controllers/kaui/engine_controller_util.rb +++ b/app/controllers/kaui/engine_controller_util.rb @@ -4,6 +4,7 @@ module Kaui module EngineControllerUtil # See DefaultPaginationSqlDaoHelper.java SIMPLE_PAGINATION_THRESHOLD = 20_000 + MAXIMUM_NUMBER_OF_RECORDS_DOWNLOAD = 1000 protected @@ -13,7 +14,7 @@ def get_layout end # rubocop:enable Lint/UselessAssignment, Naming/AccessorMethodName - def paginate(searcher, data_extractor, formatter) + def paginate(searcher, data_extractor, formatter, table_default_columns = []) search_key = (params[:search] || {})[:value].presence offset = (params[:start] || 0).to_i limit = (params[:length] || 10).to_i @@ -30,7 +31,8 @@ def paginate(searcher, data_extractor, formatter) # We need to fill-in a number to make DataTables happy recordsTotal: pages.nil? ? 0 : (pages.pagination_max_nb_records || SIMPLE_PAGINATION_THRESHOLD), recordsFiltered: pages.nil? ? 0 : (pages.pagination_total_nb_records || SIMPLE_PAGINATION_THRESHOLD), - data: [] + data: [], + columns: table_default_columns } json[:error] = error unless error.nil? @@ -151,5 +153,9 @@ def json_response end render json: response, status: response_status end + + def default_columns(fields, sensivite_fields) + fields.map { |field| { data: fields.index(field), visible: !(sensivite_fields.include? field) } } + end end end diff --git a/app/controllers/kaui/invoices_controller.rb b/app/controllers/kaui/invoices_controller.rb index 40b7554b..ac931640 100644 --- a/app/controllers/kaui/invoices_controller.rb +++ b/app/controllers/kaui/invoices_controller.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require 'csv' module Kaui class InvoicesController < Kaui::EngineController def index @@ -12,6 +13,31 @@ def index @max_nb_records = @search_query.blank? ? Kaui::Invoice.list_or_search(nil, 0, 0, options_for_klient).pagination_max_nb_records : 0 end + def download + account_id = params[:account_id] + start_date = params[:startDate] + end_date = params[:endDate] + columns = params.require(:columnsString).split(',').map { |attr| attr.split.join('_').downcase } + kb_params = {} + kb_params[:startDate] = Date.parse(start_date).strftime('%Y-%m-%d') if start_date + kb_params[:endDate] = Date.parse(end_date).strftime('%Y-%m-%d') if end_date + if account_id.present? + account = Kaui::Account.find_by_id_or_key(account_id, false, false, options_for_klient) + invoices = account.invoices(options_for_klient.merge(params: kb_params)) + else + invoices = Kaui::Invoice.list_or_search(nil, 0, MAXIMUM_NUMBER_OF_RECORDS_DOWNLOAD, options_for_klient.merge(params: kb_params)) + end + + csv_string = CSV.generate(headers: true) do |csv| + csv << columns + + invoices.each do |invoice| + csv << columns.map { |attr| invoice&.send(attr.downcase) } + end + end + send_data csv_string, filename: "invoices-#{Date.today}.csv", type: 'text/csv' + end + def pagination cached_options_for_klient = options_for_klient @@ -24,7 +50,7 @@ def pagination if account.nil? Kaui::Invoice.list_or_search(search_key, offset, limit, cached_options_for_klient) else - Kaui::Account.paginated_invoices(search_key, offset, limit, 'NONE', cached_options_for_klient.merge({ params: { includeVoidedInvoices: true } })).map! { |invoice| Kaui::Invoice.build_from_raw_invoice(invoice) } + Kaui::Account.paginated_invoices(search_key, offset, limit, 'NONE', cached_options_for_klient).map! { |invoice| Kaui::Invoice.build_from_raw_invoice(invoice) } end end @@ -53,9 +79,7 @@ def pagination ][column] end formatter = lambda do |invoice| - row = [view_context.link_to(invoice.invoice_number, view_context.url_for(controller: :invoices, action: :show, account_id: invoice.account_id, id: invoice.invoice_id))] - row += Kaui.account_invoices_columns.call(invoice, view_context)[1] - row + Kaui.account_invoices_columns.call(invoice, view_context)[1] end end diff --git a/app/controllers/kaui/payments_controller.rb b/app/controllers/kaui/payments_controller.rb index c8735613..3c61c796 100644 --- a/app/controllers/kaui/payments_controller.rb +++ b/app/controllers/kaui/payments_controller.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'csv' + module Kaui class PaymentsController < Kaui::EngineController def index @@ -12,7 +14,59 @@ def index @max_nb_records = @search_query.blank? ? Kaui::Payment.list_or_search(nil, 0, 0, options_for_klient).pagination_max_nb_records : 0 end + def download + account_id = params[:account_id] + start_date = params[:startDate] + end_date = params[:endDate] + columns = params.require(:columnsString).split(',').map { |attr| attr.split.join('_').downcase } + kb_params = {} + kb_params[:startDate] = Date.parse(start_date).strftime('%Y-%m-%d') if start_date + kb_params[:endDate] = Date.parse(end_date).strftime('%Y-%m-%d') if end_date + if account_id.present? + account = Kaui::Account.find_by_id_or_key(account_id, false, false, options_for_klient) + payments = account.payments(options_for_klient).map! { |payment| Kaui::Payment.build_from_raw_payment(payment) } + else + payments = Kaui::Payment.list_or_search(nil, 0, MAXIMUM_NUMBER_OF_RECORDS_DOWNLOAD, options_for_klient.merge(params: kb_params)) + end + payments.each do |payment| + created_date = nil + payment.transactions.each do |transaction| + transaction_date = Date.parse(transaction.effective_date) + created_date = transaction_date if created_date.nil? || (transaction_date < created_date) + end + payment.payment_date = created_date + end + + csv_string = CSV.generate(headers: true) do |csv| + csv << columns + + payments.each do |payment| + data = columns.map do |attr| + case attr + when 'payment_number' + payment.payment_number + when 'payment_date' + view_context.format_date(payment.payment_date, account&.time_zone) + when 'total_authed_amount_to_money' + view_context.humanized_money_with_symbol(payment.total_authed_amount_to_money) + when 'paid_amount_to_money' + view_context.humanized_money_with_symbol(payment.paid_amount_to_money) + when 'returned_amount_to_money' + view_context.humanized_money_with_symbol(payment.returned_amount_to_money) + when 'status' + payment.transactions.empty? ? nil : payment.transactions[-1].status + else + payment&.send(attr.downcase) + end + end + csv << data + end + end + send_data csv_string, filename: "payments-#{Date.today}.csv", type: 'text/csv' + end + def pagination + account = nil searcher = lambda do |search_key, offset, limit| if Kaui::Payment::TRANSACTION_STATUSES.include?(search_key) # Search is done by payment state on the server side, see http://docs.killbill.io/latest/userguide_payment.html#_payment_states @@ -30,6 +84,7 @@ def pagination rescue StandardError nil end + payments = if account.nil? Kaui::Payment.list_or_search(search_key, offset, limit, options_for_klient) else @@ -62,15 +117,7 @@ def pagination end formatter = lambda do |payment| - [ - view_context.link_to(payment.payment_number, view_context.url_for(controller: :payments, action: :show, account_id: payment.account_id, id: payment.payment_id)), - view_context.format_date(payment.payment_date, @account.time_zone), - view_context.humanized_money_with_symbol(payment.total_authed_amount_to_money), - view_context.humanized_money_with_symbol(payment.paid_amount_to_money), - view_context.humanized_money_with_symbol(payment.returned_amount_to_money), - payment.transactions.empty? ? nil : view_context.colored_transaction_status(payment.transactions[-1].status), - payment.payment_external_key - ] + Kaui.account_payments_columns.call(account, payment, view_context)[1] end paginate searcher, data_extractor, formatter diff --git a/app/models/kaui/account.rb b/app/models/kaui/account.rb index a3478bb4..b0341c02 100644 --- a/app/models/kaui/account.rb +++ b/app/models/kaui/account.rb @@ -4,6 +4,8 @@ module Kaui class Account < KillBillClient::Model::Account attr_accessor :phone, :bill_cycle_day_local + SENSIVITE_DATA_FIELDS = %w[name email].freeze + def check_account_details_phone return true if phone =~ /\A(?:\+?\d{1,3}\s*-?)?\(?(?:\d{3})?\)?[- ]?\d{3}[- ]?\d{4}\z/i diff --git a/app/views/kaui/account_timelines/_multi_functions_bar.html.erb b/app/views/kaui/account_timelines/_multi_functions_bar.html.erb new file mode 100644 index 00000000..ec47e9e8 --- /dev/null +++ b/app/views/kaui/account_timelines/_multi_functions_bar.html.erb @@ -0,0 +1,178 @@ +
+ +
+ + + + + +<%= javascript_tag do %> +$(document).ready(function() { + $('.dropdown-menu').on('click', 'input[type="checkbox"], label', function(event) { + event.stopPropagation(); + }); + + $('#modalDownloadButton').click(function() { + $('#downloadCsvModal').modal('show'); + }); + + $('#startDate, #endDate').datepicker({ + dateFormat: 'yy-mm-dd' + }); + + $('#downloadCsvModal').on('show.bs.modal', function (e) { + $('#customDate').prop('checked', true); + $('#startDate, #endDate').prop('disabled', false); + $('#startDate').val(null); + $('#endDate').val(null); + }); + + $('#allData').change(function() { + var isChecked = $(this).is(':checked'); + $('#startDate, #endDate').prop('disabled', true); + }); + + function setDateRange(option) { + var currentDate = new Date(); + var startDate, endDate; + + if (option === "week") { + startDate = new Date(currentDate.setDate(currentDate.getDate() - currentDate.getDay() + 1)); + currentDate = new Date(); + endDate = new Date(currentDate.setDate(currentDate.getDate() - currentDate.getDay() + 7)); + } else if (option === "month") { + startDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1); + endDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0); + } else if (option === "year") { + startDate = new Date(currentDate.getFullYear(), 0, 1); + endDate = new Date(currentDate.getFullYear(), 11, 31); + } + + var startDateFormatted = startDate.toISOString().split('T')[0]; + var endDateFormatted = endDate.toISOString().split('T')[0]; + + $('#startDate').val(startDateFormatted); + $('#endDate').val(endDateFormatted); + $('#startDate, #endDate').prop('disabled', true); + } + + $('#thisWeek').change(function() { + if ($(this).is(':checked')) { + setDateRange("week"); + } + }); + + $('#thisMonth').change(function() { + if ($(this).is(':checked')) { + setDateRange("month"); + } + }); + + $('#thisYear').change(function() { + if ($(this).is(':checked')) { + setDateRange("year"); + } + }); + + $('#customDate').change(function() { + var isChecked = $(this).is(':checked'); + $('#startDate, #endDate').prop('disabled', false); + $('#startDate').val(null); + $('#endDate').val(null); + }); + + var downloadButton = document.getElementById('downloadButton'); + if (downloadButton) { + downloadButton.addEventListener('click', function() { + event.preventDefault(); + var startDate = $('#startDate').val(); + var endDate = $('#endDate').val(); + var downloadAll = $('#allData').is(':checked'); + var eventToFilter = $('#event_types').val().toUpperCase() + + if (downloadAll) { + window.open("<%= download_account_timeline_path %>?account_id=<%=@account.account_id%>&eventType="+eventToFilter, '_blank'); + } else { + window.open("<%= download_account_timeline_path %>?account_id=<%=@account.account_id%>&startDate="+startDate+"&endDate="+endDate+"&eventType="+eventToFilter, '_blank'); + } + }); + } +}); +<% end %> diff --git a/app/views/kaui/account_timelines/show.html.erb b/app/views/kaui/account_timelines/show.html.erb index 75c00f61..d9ffcd07 100644 --- a/app/views/kaui/account_timelines/show.html.erb +++ b/app/views/kaui/account_timelines/show.html.erb @@ -21,6 +21,8 @@ + <%= render :partial => 'multi_functions_bar' %> +
diff --git a/app/views/kaui/accounts/_edit_columns.erb b/app/views/kaui/accounts/_edit_columns.erb deleted file mode 100644 index cef9c9e5..00000000 --- a/app/views/kaui/accounts/_edit_columns.erb +++ /dev/null @@ -1,144 +0,0 @@ - - - - -<%= javascript_tag do %> -$(document).ready(function() { - updateDropdownOrder(); - - function loadState() { - var state = JSON.parse(localStorage.getItem('DataTables_accounts-table_' + window.location.pathname)); - return state || { columns: [], columnOrder: [] }; - } - - function updateDropdownOrder() { - var state = loadState(); - var columnOrder = state.ColReorder; - var $list = $('#column-visibility'); - var thElements = document.querySelectorAll('#accounts-table th'); - var $columnTitles = Array.from(thElements).map(function(th) { - return th.textContent.trim(); - }); - if (columnOrder !== undefined) { - $list.empty(); - columnOrder.forEach(function(colIdx, index) { - var $item = $('
  • ', { class: "list-group-item-manual", "data-id": index }); - var column = state.columns[colIdx]; - var col_name = $columnTitles[colIdx]; - var $label = $('
  • ', { class: "list-group-item-manual", "data-id": data_id }); + var column = state.columns[colIdx]; + var col_name = $columnTitles[colIdx]; + var $label = $('
  • - <% Kaui.account_search_columns.call()[0].each do |title| %> + <% Kaui.account_search_columns.call[0].each do |title| %> <% end %> @@ -28,32 +28,50 @@ <%= javascript_tag do %> $(document).ready(function() { + $.ajax({ + url: "<%= accounts_pagination_path(:ordering => @ordering, :format => :json) %>", + type: "GET", + success: function(response) { + const visibleColumns = response.columns; - var table = $('#accounts-table').DataTable({ - "colReorder": { - "enable": false - }, - "stateSave": true, - "scrollX": true, - "dom": "<'row'r>t<'row'<'col-md-6'i><'col-md-6'p>>", - "pagingType": <% if @max_nb_records.nil? -%>"simple"<% else -%>"full_numbers"<% end -%>, - "language": { - - "info": <% if @max_nb_records.nil? -%>"Showing _START_ to _END_ of <%= number_with_delimiter(Kaui::EngineControllerUtil::SIMPLE_PAGINATION_THRESHOLD) -%>+ entries"<% else -%>"Showing _START_ to _END_ of _TOTAL_ entries"<% end -%> - }, - "pageLength": <%= @limit %>, - "displayStart": <%= @offset %>, - <% if @search_query.blank? %> - "ordering": false, - <% elsif !@ordering.blank? %> - "order": [[ 1, "<%= @ordering %>" ]], - <% end %> - "processing": true, - "serverSide": true, - "search": {"search": "<%= @search_query %>"}, - "ajax": "<%= accounts_pagination_path(:ordering => @ordering, :format => :json) %>", - drawCallback: function() { - setObjectIdPopover(); + var table = $('#accounts-table').DataTable({ + "colReorder": { + "enable": false + }, + "stateSave": true, + "scrollX": true, + "dom": "<'row'r>t<'row'<'col-md-6'i><'col-md-6'p>>", + "pagingType": <% if @max_nb_records.nil? -%>"simple"<% else -%>"full_numbers"<% end -%>, + "language": { + + "info": <% if @max_nb_records.nil? -%>"Showing _START_ to _END_ of <%= number_with_delimiter(Kaui::EngineControllerUtil::SIMPLE_PAGINATION_THRESHOLD) -%>+ entries"<% else -%>"Showing _START_ to _END_ of _TOTAL_ entries"<% end -%> + }, + "pageLength": <%= @limit %>, + "displayStart": <%= @offset %>, + <% if @search_query.blank? %> + "ordering": false, + <% elsif !@ordering.blank? %> + "order": [[ 1, "<%= @ordering %>" ]], + <% end %> + "processing": true, + "serverSide": true, + "search": {"search": "<%= @search_query %>"}, + "ajax": { + url: "<%= accounts_pagination_path(:ordering => @ordering, :format => :json) %>", + dataSrc: function(json) { + var colOrder = $('#accounts-table').DataTable().colReorder.order(); + var reorderedData = json.data.map(function(row) { + var newRow = []; + for (var i = 0; i < colOrder.length; i++) { + newRow.push(row[colOrder[i]]); + } + return newRow; + }); + return reorderedData; + } + }, + "columns": visibleColumns + }); } }); diff --git a/app/views/kaui/audit_logs/_multi_functions_bar.html.erb b/app/views/kaui/audit_logs/_multi_functions_bar.html.erb new file mode 100644 index 00000000..ea6e53ab --- /dev/null +++ b/app/views/kaui/audit_logs/_multi_functions_bar.html.erb @@ -0,0 +1,212 @@ + + + + + + +<%= javascript_tag do %> +$(document).ready(function() { + $('.dropdown-menu').on('click', 'input[type="checkbox"], label', function(event) { + event.stopPropagation(); + }); + + $('#modalDownloadButton').click(function() { + $('#downloadCsvModal').modal('show'); + }); + + $('#startDate, #endDate').datepicker({ + dateFormat: 'yy-mm-dd' + }); + + $('#downloadCsvModal').on('show.bs.modal', function (e) { + $('#customDate').prop('checked', true); + $('#startDate, #endDate').prop('disabled', false); + $('#startDate').val(null); + $('#endDate').val(null); + }); + + $('#allData').change(function() { + var isChecked = $(this).is(':checked'); + $('#startDate, #endDate').prop('disabled', true); + }); + + function setDateRange(option) { + var currentDate = new Date(); + var startDate, endDate; + + if (option === "week") { + startDate = new Date(currentDate.setDate(currentDate.getDate() - currentDate.getDay() + 1)); + currentDate = new Date(); + endDate = new Date(currentDate.setDate(currentDate.getDate() - currentDate.getDay() + 7)); + } else if (option === "month") { + startDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1); + endDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0); + } else if (option === "year") { + startDate = new Date(currentDate.getFullYear(), 0, 1); + endDate = new Date(currentDate.getFullYear(), 11, 31); + } + + var startDateFormatted = startDate.toISOString().split('T')[0]; + var endDateFormatted = endDate.toISOString().split('T')[0]; + + $('#startDate').val(startDateFormatted); + $('#endDate').val(endDateFormatted); + $('#startDate, #endDate').prop('disabled', true); + } + + $('#thisWeek').change(function() { + if ($(this).is(':checked')) { + setDateRange("week"); + } + }); + + $('#thisMonth').change(function() { + if ($(this).is(':checked')) { + setDateRange("month"); + } + }); + + $('#thisYear').change(function() { + if ($(this).is(':checked')) { + setDateRange("year"); + } + }); + + $('#customDate').change(function() { + var isChecked = $(this).is(':checked'); + $('#startDate, #endDate').prop('disabled', false); + $('#startDate').val(null); + $('#endDate').val(null); + }); + + var downloadButton = document.getElementById('downloadButton'); + if (downloadButton) { + downloadButton.addEventListener('click', function() { + event.preventDefault(); + var startDate = $('#startDate').val(); + var endDate = $('#endDate').val(); + var downloadAll = $('#allData').is(':checked'); + + if (downloadAll) { + window.open("<%= download_audit_logs_path %>?account_id=<%=@account.account_id%>", '_blank'); + } else { + window.open("<%= download_audit_logs_path %>?account_id=<%=@account.account_id%>&startDate="+startDate+"&endDate="+endDate, '_blank'); + } + }); + } +}); +<% end %> diff --git a/app/views/kaui/audit_logs/index.html.erb b/app/views/kaui/audit_logs/index.html.erb index 223d618f..4da22bdb 100644 --- a/app/views/kaui/audit_logs/index.html.erb +++ b/app/views/kaui/audit_logs/index.html.erb @@ -3,6 +3,7 @@

    Audit logs

    + <%= render :partial => 'multi_functions_bar' %>
    <%= title %>
    diff --git a/app/views/kaui/invoices/_multi_functions_bar.html.erb b/app/views/kaui/invoices/_multi_functions_bar.html.erb new file mode 100644 index 00000000..6a5144d2 --- /dev/null +++ b/app/views/kaui/invoices/_multi_functions_bar.html.erb @@ -0,0 +1,318 @@ + + + + + + +<%= javascript_tag do %> +$(document).ready(function() { + $('.dropdown-menu').on('click', 'input[type="checkbox"], label', function(event) { + event.stopPropagation(); + }); + + $('#modalDownloadButton').click(function() { + $('#downloadCsvModal').modal('show'); + }); + $('#startDate, #endDate').datepicker({ + dateFormat: 'yy-mm-dd' + }); + + $('#downloadCsvModal').on('show.bs.modal', function (e) { + $('#customDate').prop('checked', true); + $('#startDate, #endDate').prop('disabled', false); + $('#startDate').val(null); + $('#endDate').val(null); + }); + + $('#allInvoices').change(function() { + var isChecked = $(this).is(':checked'); + $('#startDate, #endDate').prop('disabled', true); + }); + + function setDateRange(option) { + var currentDate = new Date(); + var startDate, endDate; + + if (option === "week") { + startDate = new Date(currentDate.setDate(currentDate.getDate() - currentDate.getDay() + 1)); + currentDate = new Date(); + endDate = new Date(currentDate.setDate(currentDate.getDate() - currentDate.getDay() + 7)); + } else if (option === "month") { + startDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1); + endDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0); + } else if (option === "year") { + startDate = new Date(currentDate.getFullYear(), 0, 1); + endDate = new Date(currentDate.getFullYear(), 11, 31); + } + + var startDateFormatted = startDate.toISOString().split('T')[0]; + var endDateFormatted = endDate.toISOString().split('T')[0]; + + $('#startDate').val(startDateFormatted); + $('#endDate').val(endDateFormatted); + $('#startDate, #endDate').prop('disabled', true); + } + + $('#thisWeek').change(function() { + if ($(this).is(':checked')) { + setDateRange("week"); + } + }); + + $('#thisMonth').change(function() { + if ($(this).is(':checked')) { + setDateRange("month"); + } + }); + + $('#thisYear').change(function() { + if ($(this).is(':checked')) { + setDateRange("year"); + } + }); + + $('#customDate').change(function() { + var isChecked = $(this).is(':checked'); + $('#startDate, #endDate').prop('disabled', false); + $('#startDate').val(null); + $('#endDate').val(null); + }); + + var downloadButton = document.getElementById('downloadButton'); + if (downloadButton) { + downloadButton.addEventListener('click', function() { + event.preventDefault(); // Prevent the default form submission if the button is a submit type + + // Retrieve the values and checked state + var startDate = $('#startDate').val(); + var endDate = $('#endDate').val(); + var downloadAll = $('#allInvoices').is(':checked'); + var thElements = document.querySelectorAll('#invoices-table th'); + var columnTitles = Array.from(thElements).map(function(th) { + return th.textContent.trim(); + }); + + var columnsString = columnTitles.join(',') + + if (downloadAll) { + window.open("<%= download_invoices_path %>?account_id=<%=@account.account_id%>&columnsString="+columnsString, '_blank'); + } else { + window.open("<%= download_invoices_path %>?account_id=<%=@account.account_id%>&columnsString="+columnsString+"&startDate="+startDate+"&endDate="+endDate, '_blank'); + } + }); + } + + updateDropdownOrder(); + + function loadState() { + var state = JSON.parse(localStorage.getItem('DataTables_invoices-table')); + return state || { columns: [], columnOrder: [] }; + } + + function updateDropdownOrder() { + var state = loadState(); + var columnOrder = state.ColReorder; + var $list = $('#column-visibility'); + var thElements = document.querySelectorAll('#invoices-table th'); + var $columnTitles = Array.from(thElements).map(function(th) { + return th.textContent.trim(); + }); + if (columnOrder !== undefined) { + $list.empty(); + columnOrder.forEach(function(colIdx, index) { + var $item = $('
  • ', { class: "list-group-item-manual", "data-id": index }); + var column = state.columns[colIdx]; + var col_name = $columnTitles[colIdx]; + var $label = $('
  • + <%= render :partial => 'multi_functions_bar' %> + +
    - <% (@account.account_id.blank? ? Kaui.invoice_search_columns : Kaui.account_invoices_columns).call()[0].each do |title| %> <% end %> @@ -27,6 +28,17 @@ <%= javascript_tag do %> $(document).ready(function() { var table = $('#invoices-table').DataTable({ + "colReorder": { + "enable": false + }, + "stateSave": true, + "stateSaveCallback": function(settings, data) { + localStorage.setItem('DataTables_invoices-table', JSON.stringify(data)); + }, + "stateLoadCallback": function(settings) { + return JSON.parse(localStorage.getItem('DataTables_invoices-table')); + }, + "scrollX": true, "dom": "<'row'r>t<'row'<'col-md-6'i><'col-md-6'p>>", "pagingType": <% if @max_nb_records.nil? -%>"simple"<% else -%>"full_numbers"<% end -%>, "language": { @@ -34,7 +46,6 @@ $(document).ready(function() { }, "pageLength": <%= @limit %>, "displayStart": <%= @offset %>, - "ajax": "<%= invoices_pagination_path(:ordering => @ordering, :format => :json) %>", <% if @search_query.blank? %> "ordering": false, <% elsif !@ordering.blank? %> @@ -43,6 +54,20 @@ $(document).ready(function() { "processing": true, "serverSide": true, "search": {"search": "<%= @search_query %>"}, + "ajax": { + url: "<%= invoices_pagination_path(:ordering => @ordering, :format => :json) %>", + dataSrc: function(json) { + var colOrder = $('#invoices-table').DataTable().colReorder.order(); + var reorderedData = json.data.map(function(row) { + var newRow = []; + for (var i = 0; i < colOrder.length; i++) { + newRow.push(row[colOrder[i]]); + } + return newRow; + }); + return reorderedData; + } + } }); diff --git a/app/views/kaui/payments/_multi_functions_bar.html.erb b/app/views/kaui/payments/_multi_functions_bar.html.erb new file mode 100644 index 00000000..5077a8a8 --- /dev/null +++ b/app/views/kaui/payments/_multi_functions_bar.html.erb @@ -0,0 +1,319 @@ + + + + + + +<%= javascript_tag do %> +$(document).ready(function() { + $('.dropdown-menu').on('click', 'input[type="checkbox"], label', function(event) { + event.stopPropagation(); + }); + + $('#modalDownloadButton').click(function() { + $('#downloadCsvModal').modal('show'); + }); + + $('#startDate, #endDate').datepicker({ + dateFormat: 'yy-mm-dd' + }); + + $('#downloadCsvModal').on('show.bs.modal', function (e) { + $('#customDate').prop('checked', true); + $('#startDate, #endDate').prop('disabled', false); + $('#startDate').val(null); + $('#endDate').val(null); + }); + + $('#allData').change(function() { + var isChecked = $(this).is(':checked'); + $('#startDate, #endDate').prop('disabled', true); + }); + + function setDateRange(option) { + var currentDate = new Date(); + var startDate, endDate; + + if (option === "week") { + startDate = new Date(currentDate.setDate(currentDate.getDate() - currentDate.getDay() + 1)); + currentDate = new Date(); + endDate = new Date(currentDate.setDate(currentDate.getDate() - currentDate.getDay() + 7)); + } else if (option === "month") { + startDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1); + endDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0); + } else if (option === "year") { + startDate = new Date(currentDate.getFullYear(), 0, 1); + endDate = new Date(currentDate.getFullYear(), 11, 31); + } + + var startDateFormatted = startDate.toISOString().split('T')[0]; + var endDateFormatted = endDate.toISOString().split('T')[0]; + + $('#startDate').val(startDateFormatted); + $('#endDate').val(endDateFormatted); + $('#startDate, #endDate').prop('disabled', true); + } + + $('#thisWeek').change(function() { + if ($(this).is(':checked')) { + setDateRange("week"); + } + }); + + $('#thisMonth').change(function() { + if ($(this).is(':checked')) { + setDateRange("month"); + } + }); + + $('#thisYear').change(function() { + if ($(this).is(':checked')) { + setDateRange("year"); + } + }); + + $('#customDate').change(function() { + var isChecked = $(this).is(':checked'); + $('#startDate, #endDate').prop('disabled', false); + $('#startDate').val(null); + $('#endDate').val(null); + }); + + var downloadButton = document.getElementById('downloadButton'); + if (downloadButton) { + downloadButton.addEventListener('click', function() { + event.preventDefault(); // Prevent the default form submission if the button is a submit type + + // Retrieve the values and checked state + var startDate = $('#startDate').val(); + var endDate = $('#endDate').val(); + var downloadAll = $('#allData').is(':checked'); + var thElements = document.querySelectorAll('#payments-table th'); + var columnTitles = Array.from(thElements).map(function(th) { + return th.textContent.trim(); + }); + + var columnsString = columnTitles.join(',') + + if (downloadAll) { + window.open("<%= download_payments_path %>?account_id=<%=@account.account_id%>&columnsString="+columnsString, '_blank'); + } else { + window.open("<%= download_payments_path %>?account_id=<%=@account.account_id%>&columnsString="+columnsString+"&startDate="+startDate+"&endDate="+endDate, '_blank'); + } + }); + } + + updateDropdownOrder(); + + function loadState() { + var state = JSON.parse(localStorage.getItem('DataTables_payments-table')); + return state || { columns: [], columnOrder: [] }; + } + + function updateDropdownOrder() { + var state = loadState(); + var columnOrder = state.ColReorder; + var $list = $('#column-visibility'); + var thElements = document.querySelectorAll('#payments-table th'); + var $columnTitles = Array.from(thElements).map(function(th) { + return th.textContent.trim(); + }); + if (columnOrder !== undefined) { + $list.empty(); + columnOrder.forEach(function(colIdx, index) { + var $item = $('
  • ', { class: "list-group-item-manual", "data-id": index }); + var column = state.columns[colIdx]; + var col_name = $columnTitles[colIdx]; + var $label = $('
  • Number<%= title %>
    - - - - - - - - - + + <% Kaui.account_payments_columns.call()[0].each do |title| %> + + <% end %> + @@ -30,26 +27,63 @@ <%= javascript_tag do %> $(document).ready(function() { var table = $('#payments-table').DataTable({ + "colReorder": { + "enable": false + }, + "stateSave": true, + "stateSaveCallback": function(settings, data) { + localStorage.setItem('DataTables_payments-table', JSON.stringify(data)); + }, + "stateLoadCallback": function(settings) { + return JSON.parse(localStorage.getItem('DataTables_payments-table')); + }, + "scrollX": true, <% if @account.account_id.blank? %> - "dom": "<'row'r>t<'row'<'col-md-6'i><'col-md-6'p>>", - "pagingType": <% if @max_nb_records.nil? -%>"simple"<% else -%>"full_numbers"<% end -%>, - "language": { - - "info": <% if @max_nb_records.nil? -%>"Showing _START_ to _END_ of <%= number_with_delimiter(Kaui::EngineControllerUtil::SIMPLE_PAGINATION_THRESHOLD) -%>+ entries"<% else -%>"Showing _START_ to _END_ of _TOTAL_ entries"<% end -%> - }, - "pageLength": <%= @limit %>, - "displayStart": <%= @offset %>, - "ajax": "<%= payments_pagination_path(:ordering => @ordering, :format => :json) %>", + "dom": "<'row'r>t<'row'<'col-md-6'i><'col-md-6'p>>", + "pagingType": <% if @max_nb_records.nil? -%>"simple"<% else -%>"full_numbers"<% end -%>, + "language": { + + "info": <% if @max_nb_records.nil? -%>"Showing _START_ to _END_ of <%= number_with_delimiter(Kaui::EngineControllerUtil::SIMPLE_PAGINATION_THRESHOLD) -%>+ entries"<% else -%>"Showing _START_ to _END_ of _TOTAL_ entries"<% end -%> + }, + "pageLength": <%= @limit %>, + "displayStart": <%= @offset %>, + "ajax": { + url: "<%= payments_pagination_path(:ordering => @ordering, :format => :json) %>", + dataSrc: function(json) { + var colOrder = $('#payments-table').DataTable().colReorder.order(); + var reorderedData = json.data.map(function(row) { + var newRow = []; + for (var i = 0; i < colOrder.length; i++) { + newRow.push(row[colOrder[i]]); + } + return newRow; + }); + return reorderedData; + } + }, <% else %> - // No paging for per-account listings - "dom": "t", - "paging": false, - "ajax": "<%= payments_pagination_path :format => :json %>", + // No paging for per-account listings + "dom": "t", + "paging": false, + "ajax": { + url: "<%= payments_pagination_path(:format => :json) %>", + dataSrc: function(json) { + var colOrder = $('#payments-table').DataTable().colReorder.order(); + var reorderedData = json.data.map(function(row) { + var newRow = []; + for (var i = 0; i < colOrder.length; i++) { + newRow.push(row[colOrder[i]]); + } + return newRow; + }); + return reorderedData; + } + }, <% end %> <% if @search_query.blank? %> - "ordering": false, + "ordering": false, <% elsif !@ordering.blank? %> - "order": [[ 0, "<%= @ordering %>" ]], + "order": [[ 0, "<%= @ordering %>" ]], <% end %> "processing": true, "serverSide": true, diff --git a/config/routes.rb b/config/routes.rb index 5866face..732934e7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -27,6 +27,7 @@ def nested_param scope '/accounts' do match '/pagination' => 'accounts#pagination', :via => :get, :as => 'accounts_pagination' match '/validate_external_key' => 'accounts#validate_external_key', :via => :get, :as => 'accounts_validate_external_key' + match '/download' => 'accounts#download', :via => :get, :as => 'download_accounts' get '/export/:account_id', to: 'accounts#export_account', as: 'export_account' scope '/email_notifications' do @@ -55,6 +56,7 @@ def nested_param end scope '/timeline' do match '/' => 'account_timelines#show', :via => :get, :as => 'account_timeline' + match '/download' => 'account_timelines#download', :via => :get, :as => 'download_account_timeline' end scope '/custom_fields' do match '/' => 'account_custom_fields#index', :via => :get, :as => 'account_custom_fields' @@ -65,6 +67,7 @@ def nested_param end scope '/audit_logs' do match '/history' => 'audit_logs#history', :via => :get, :as => 'audit_logs_history' + match '/download' => 'audit_logs#download', :via => :get, :as => 'download_audit_logs' end end end @@ -99,6 +102,7 @@ def nested_param scope '/invoices' do match '/pagination' => 'invoices#pagination', :via => :get, :as => 'invoices_pagination' + match '/download' => 'invoices#download', :via => :get, :as => 'download_invoices' match '/:id/show_html' => 'invoices#show_html', :via => :get, :as => 'show_html_invoice' match '/:number' => 'invoices#restful_show_by_number', :via => :get, :constraints => { number: /\d+/ } match '/:id' => 'invoices#restful_show', :via => :get, :as => 'invoice' @@ -114,6 +118,7 @@ def nested_param scope '/payments' do match '/pagination' => 'payments#pagination', :via => :get, :as => 'payments_pagination' + match '/download' => 'payments#download', :via => :get, :as => 'download_payments' match '/:id' => 'payments#restful_show', :via => :get, :as => 'payment' match '/:id/cancel_scheduled_payment' => 'payments#cancel_scheduled_payment', :via => :delete, :as => 'payment_cancel_scheduled_payment' end diff --git a/lib/kaui.rb b/lib/kaui.rb index a5fd7961..6aad1630 100644 --- a/lib/kaui.rb +++ b/lib/kaui.rb @@ -20,6 +20,8 @@ module Kaui mattr_accessor :account_search_columns mattr_accessor :invoice_search_columns mattr_accessor :account_invoices_columns + mattr_accessor :account_payments_columns + mattr_accessor :account_audit_logs_columns mattr_accessor :refund_invoice_description mattr_accessor :customer_invoice_link @@ -60,10 +62,11 @@ module Kaui self.creditcard_plugin_name = -> { '__EXTERNAL_PAYMENT__' } self.account_search_columns = lambda do |account = nil, view_context = nil| - fields = KillBillClient::Model::AccountAttributes.instance_variable_get('@json_attributes') + original_fields = KillBillClient::Model::AccountAttributes.instance_variable_get('@json_attributes') + # Add additional fields if needed + fields = original_fields.dup + headers = fields.map { |attr| attr.split('_').join(' ').capitalize } - # Add additional headers if needed - headers << 'Child' values = fields.map do |attr| case attr when 'account_id' @@ -76,39 +79,95 @@ module Kaui account&.send(attr.downcase) end end - # Add additional values if needed - values << (account.nil? || account.parent_account_id.nil? ? '' : view_context.content_tag(:span, 'Child', class: %w[label label-info account-child-label])) - [headers, values] + [headers, values, fields] end self.invoice_search_columns = lambda do |invoice = nil, view_context = nil, _cached_options_for_klient = nil| - default_label = 'label-info' - default_label = 'label-default' if invoice&.status == 'DRAFT' - default_label = 'label-success' if invoice&.status == 'COMMITTED' - default_label = 'label-danger' if invoice&.status == 'VOID' - [ - %w[Date Status], - [ - invoice&.invoice_date, + fields = %w[invoice_number invoice_date status] + headers = fields.map { |attr| attr.split('_').join(' ').capitalize } + values = fields.map do |attr| + case attr + when 'status' + default_label = 'label-info' + default_label = 'label-default' if invoice&.status == 'DRAFT' + default_label = 'label-success' if invoice&.status == 'COMMITTED' + default_label = 'label-danger' if invoice&.status == 'VOID' invoice.nil? || view_context.nil? ? nil : view_context.content_tag(:span, invoice.status, class: ['label', default_label]) - ] - ] + else + invoice&.send(attr.downcase) + end + end + [headers, values] end self.account_invoices_columns = lambda do |invoice = nil, view_context = nil| - default_label = 'label-info' - default_label = 'label-default' if invoice&.status == 'DRAFT' - default_label = 'label-success' if invoice&.status == 'COMMITTED' - default_label = 'label-danger' if invoice&.status == 'VOID' - [ - %w[Date Amount Balance Status], - [ - invoice&.invoice_date, - invoice.nil? || view_context.nil? ? nil : view_context.humanized_money_with_symbol(invoice.amount_to_money), - invoice.nil? || view_context.nil? ? nil : view_context.humanized_money_with_symbol(invoice.balance_to_money), + fields = KillBillClient::Model::InvoiceAttributes.instance_variable_get('@json_attributes') + # Change the order if needed + fields.delete('invoice_id') + fields.unshift('invoice_id') + + headers = fields.map { |attr| attr.split('_').join(' ').capitalize } + # Add additional headers if needed + + values = fields.map do |attr| + case attr + when 'amount_to_money' + invoice.nil? || view_context.nil? ? nil : view_context.humanized_money_with_symbol(invoice.amount_to_money) + when 'balance_to_money' + invoice.nil? || view_context.nil? ? nil : view_context.humanized_money_with_symbol(invoice.balance_to_money) + when 'invoice_id' + invoice.nil? || view_context.nil? ? nil : view_context.link_to(invoice.invoice_number, view_context.url_for(controller: :invoices, action: :show, account_id: invoice.account_id, id: invoice.invoice_id)) + when 'status' + default_label = 'label-info' + default_label = 'label-default' if invoice&.status == 'DRAFT' + default_label = 'label-success' if invoice&.status == 'COMMITTED' + default_label = 'label-danger' if invoice&.status == 'VOID' invoice.nil? || view_context.nil? ? nil : view_context.content_tag(:span, invoice.status, class: ['label', default_label]) - ] - ] + else + invoice&.send(attr.downcase) + end + end + # Add additional values if needed + [headers, values] + end + + self.account_payments_columns = lambda do |account = nil, payment = nil, view_context = nil| + fields = KillBillClient::Model::PaymentAttributes.instance_variable_get('@json_attributes') + # Change the order if needed + fields = %w[payment_date total_authed_amount_to_money paid_amount_to_money returned_amount_to_money] + fields + fields -= %w[payment_number transactions audit_logs] + fields.unshift('status') + fields.unshift('payment_number') + + headers = fields.map { |attr| attr.split('_').join(' ').capitalize } + return [headers, []] if payment.nil? + + values = fields.map do |attr| + case attr + when 'payment_number' + view_context.link_to(payment.payment_number, view_context.url_for(controller: :payments, action: :show, account_id: payment.account_id, id: payment.payment_id)) + when 'payment_date' + view_context.format_date(payment.payment_date, account&.time_zone) + when 'total_authed_amount_to_money' + view_context.humanized_money_with_symbol(payment.total_authed_amount_to_money) + when 'paid_amount_to_money' + view_context.humanized_money_with_symbol(payment.paid_amount_to_money) + when 'returned_amount_to_money' + view_context.humanized_money_with_symbol(payment.returned_amount_to_money) + when 'status' + payment.transactions.empty? ? nil : view_context.colored_transaction_status(payment.transactions[-1].status) + else + payment&.send(attr.downcase) + end + end + + # Add additional values if needed + [headers, values] + end + + self.account_audit_logs_columns = lambda do + headers = %w[CreatedDate ObjectID ObjectType ChangeType Username Reason Comment UserToken] + [headers, []] end self.refund_invoice_description = lambda { |index, ii, bundle_result|
    <%= I18n.translate('number') %><%= I18n.translate('date') %><%= I18n.translate('auth_amount') %><%= I18n.translate('capture_amount') %><%= I18n.translate('refund_amount') %><%= I18n.translate('last_transaction_status') %><%= I18n.translate('external_key') %>
    <%= title %>