From d22212ccfa62883c708ddf8744d6fa750c0a28e7 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Mon, 11 Nov 2019 18:40:04 +0000 Subject: [PATCH] Merge spree/admin/reports_controller with its decorator --- .rubocop_manual_todo.yml | 5 +- .rubocop_todo.yml | 2 +- .../spree/admin/reports_controller.rb | 294 ++++++++++++++++- .../admin/reports_controller_decorator.rb | 302 ------------------ 4 files changed, 294 insertions(+), 309 deletions(-) delete mode 100644 app/controllers/spree/admin/reports_controller_decorator.rb diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml index 8bb0590127..fd05a0d4f7 100644 --- a/.rubocop_manual_todo.yml +++ b/.rubocop_manual_todo.yml @@ -366,7 +366,7 @@ Metrics/AbcSize: - app/controllers/spree/admin/payment_methods_controller.rb - app/controllers/spree/admin/payments_controller_decorator.rb - app/controllers/spree/admin/products_controller_decorator.rb - - app/controllers/spree/admin/reports_controller_decorator.rb + - app/controllers/spree/admin/reports_controller.rb - app/controllers/spree/admin/search_controller_decorator.rb - app/controllers/spree/admin/taxons_controller.rb - app/controllers/spree/admin/users_controller.rb @@ -565,7 +565,7 @@ Metrics/MethodLength: - app/controllers/spree/admin/payment_methods_controller.rb - app/controllers/spree/admin/payments_controller_decorator.rb - app/controllers/spree/admin/products_controller_decorator.rb - - app/controllers/spree/admin/reports_controller_decorator.rb + - app/controllers/spree/admin/reports_controller.rb - app/controllers/spree/admin/search_controller_decorator.rb - app/controllers/spree/admin/tax_categories_controller.rb - app/controllers/spree/admin/taxons_controller.rb @@ -645,6 +645,7 @@ Metrics/ClassLength: - app/controllers/api/products_controller.rb - app/controllers/checkout_controller.rb - app/controllers/spree/admin/payment_methods_controller.rb + - app/controllers/spree/admin/reports_controller.rb - app/controllers/spree/admin/users_controller.rb - app/controllers/spree/orders_controller.rb - app/models/enterprise.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 1e83f1c304..2b7857d6ae 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -187,7 +187,7 @@ Rails/HasManyOrHasOneDependent: # Offense count: 6 Rails/OutputSafety: Exclude: - - 'app/controllers/spree/admin/reports_controller_decorator.rb' + - 'app/controllers/spree/admin/reports_controller.rb' - 'app/helpers/angular_form_helper.rb' - 'app/helpers/spree/reports_helper.rb' - 'app/serializers/api/product_serializer.rb' diff --git a/app/controllers/spree/admin/reports_controller.rb b/app/controllers/spree/admin/reports_controller.rb index f5d14c269c..f2ee207ca7 100644 --- a/app/controllers/spree/admin/reports_controller.rb +++ b/app/controllers/spree/admin/reports_controller.rb @@ -1,14 +1,42 @@ +require 'csv' + +require 'open_food_network/reports/list' +require 'open_food_network/order_and_distributor_report' +require 'open_food_network/products_and_inventory_report' +require 'open_food_network/lettuce_share_report' +require 'open_food_network/group_buy_report' +require 'open_food_network/order_grouper' +require 'open_food_network/customers_report' +require 'open_food_network/users_and_enterprises_report' +require 'open_food_network/order_cycle_management_report' +require 'open_food_network/packing_report' +require 'open_food_network/sales_tax_report' +require 'open_food_network/xero_invoices_report' +require 'open_food_network/bulk_coop_report' +require 'open_food_network/payments_report' +require 'open_food_network/orders_and_fulfillments_report' + module Spree module Admin class ReportsController < Spree::Admin::BaseController + include Spree::ReportsHelper + + helper_method :render_content? + + before_filter :cache_search_state + # Fetches user's distributors, suppliers and order_cycles + before_filter :load_data, + only: [:customers, :products_and_inventory, :order_cycle_management, :packing] + respond_to :html - AVAILABLE_REPORTS = { - :sales_total => { :name => Spree.t(:sales_total), :description => Spree.t(:sales_total_description) } - } + def report_types + OpenFoodNetwork::Reports::List.all + end def index - @reports = AVAILABLE_REPORTS + @reports = authorized_reports + respond_with(@reports) end def sales_total @@ -44,12 +72,270 @@ module Spree end end + def customers + @report_types = report_types[:customers] + @report_type = params[:report_type] + @report = OpenFoodNetwork::CustomersReport.new spree_current_user, params, render_content? + render_report(@report.header, @report.table, params[:csv], "customers_#{timestamp}.csv") + end + + def order_cycle_management + params[:q] ||= {} + + @report_types = report_types[:order_cycle_management] + @report_type = params[:report_type] + + # -- Build Report with Order Grouper + @report = OpenFoodNetwork::OrderCycleManagementReport.new spree_current_user, + params, + render_content? + @table = @report.table_items + + render_report(@report.header, @table, params[:csv], "order_cycle_management_#{timestamp}.csv") + end + + def packing + params[:q] ||= {} + + @report_types = report_types[:packing] + @report_type = params[:report_type] + + # -- Build Report with Order Grouper + @report = OpenFoodNetwork::PackingReport.new spree_current_user, params, render_content? + @table = order_grouper_table + + render_report(@report.header, @table, params[:csv], "packing_#{timestamp}.csv") + end + + def orders_and_distributors + @report = OpenFoodNetwork::OrderAndDistributorReport.new spree_current_user, + params, + render_content? + @search = @report.search + csv_file_name = "orders_and_distributors_#{timestamp}.csv" + render_report(@report.header, @report.table, params[:csv], csv_file_name) + end + + def sales_tax + @distributors = my_distributors + @report_type = params[:report_type] + @report = OpenFoodNetwork::SalesTaxReport.new spree_current_user, params, render_content? + render_report(@report.header, @report.table, params[:csv], "sales_tax.csv") + end + + def bulk_coop + # -- Prepare form options + @distributors = my_distributors + @report_type = params[:report_type] + + # -- Build Report with Order Grouper + @report = OpenFoodNetwork::BulkCoopReport.new spree_current_user, params, render_content? + @table = order_grouper_table + csv_file_name = "bulk_coop_#{params[:report_type]}_#{timestamp}.csv" + + render_report(@report.header, @table, params[:csv], csv_file_name) + end + + def payments + # -- Prepare Form Options + @distributors = my_distributors + @report_type = params[:report_type] + + # -- Build Report with Order Grouper + @report = OpenFoodNetwork::PaymentsReport.new spree_current_user, params, render_content? + @table = order_grouper_table + csv_file_name = "payments_#{timestamp}.csv" + + render_report(@report.header, @table, params[:csv], csv_file_name) + end + + def orders_and_fulfillment + params[:q] ||= orders_and_fulfillment_default_filters + + # -- Prepare Form Options + permissions = OpenFoodNetwork::Permissions.new(spree_current_user) + # My distributors and any distributors distributing products I supply + @distributors = permissions.visible_enterprises_for_order_reports.is_distributor + # My suppliers and any suppliers supplying products I distribute + @suppliers = permissions.visible_enterprises_for_order_reports.is_primary_producer + + @order_cycles = my_order_cycles + + @report_types = report_types[:orders_and_fulfillment] + @report_type = params[:report_type] + + @include_blank = I18n.t(:all) + + # -- Build Report with Order Grouper + @report = OpenFoodNetwork::OrdersAndFulfillmentsReport.new spree_current_user, + params, + render_content? + @table = order_grouper_table + csv_file_name = "#{params[:report_type]}_#{timestamp}.csv" + + render_report(@report.header, @table, params[:csv], csv_file_name) + end + + def products_and_inventory + @report_types = report_types[:products_and_inventory] + @report = if params[:report_type] != 'lettuce_share' + OpenFoodNetwork::ProductsAndInventoryReport.new spree_current_user, + params, + render_content? + else + OpenFoodNetwork::LettuceShareReport.new spree_current_user, params, render_content? + end + render_report(@report.header, + @report.table, + params[:csv], + "products_and_inventory_#{timestamp}.csv") + end + + def users_and_enterprises + @report = OpenFoodNetwork::UsersAndEnterprisesReport.new params, render_content? + render_report(@report.header, @report.table, params[:csv], "users_and_enterprises_#{timestamp}.csv") + end + + def xero_invoices + params[:q] ||= {} + + @distributors = my_distributors + @order_cycles = my_order_cycles + + @report = OpenFoodNetwork::XeroInvoicesReport.new spree_current_user, params, render_content? + render_report(@report.header, @report.table, params[:csv], "xero_invoices_#{timestamp}.csv") + end + private def model_class Spree::Admin::ReportsController end + # Some actions are changing the `params` object. That is unfortunate Spree + # behavior and we are building on it. So we have to look at `params` early + # to check if we are searching or just displaying a report search form. + def cache_search_state + search_keys = [ + # search parameter for ransack + :q, + # common in all reports, only set for CSV rendering + :csv, + # `button` is included in all forms. It's not important for searching, + # but the Users & Enterprises report doesn't have any other parameter + # for an empty search. So we use this one to display data. + :button, + # Some reports use filtering by enterprise or order cycle + :distributor_id, + :supplier_id, + :order_cycle_id, + # Xero Invoices can be filtered by date + :invoice_date, + :due_date + ] + @searching = search_keys.any? { |key| params.key? key } + end + + # We don't want to render data unless search params are supplied. + # Compiling data can take a long time. + def render_content? + @searching + end + + def render_report(header, table, create_csv, csv_file_name) + send_data csv_report(header, table), filename: csv_file_name if create_csv + @header = header + @table = table + # Rendering HTML is the default. + end + + def csv_report(header, table) + CSV.generate do |csv| + csv << header + table.each { |row| csv << row } + end + end + + def load_data + @distributors = my_distributors + @suppliers = my_suppliers | suppliers_of_products_distributed_by(@distributors) + @order_cycles = my_order_cycles + end + + # Load managed distributor enterprises of current user + def my_distributors + Enterprise.is_distributor.managed_by(spree_current_user) + end + + # Load managed producer enterprises of current user + def my_suppliers + Enterprise.is_primary_producer.managed_by(spree_current_user) + end + + def suppliers_of_products_distributed_by(distributors) + distributors.map { |d| Spree::Product.in_distributor(d).includes(:supplier).all }. + flatten.map(&:supplier).uniq + end + + # Load order cycles the current user has access to + def my_order_cycles + OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC') + end + + def order_grouper_table + order_grouper = OpenFoodNetwork::OrderGrouper.new @report.rules, @report.columns + order_grouper.table(@report.table_items) + end + + def authorized_reports + all_reports = [ + :orders_and_distributors, + :bulk_coop, + :payments, + :orders_and_fulfillment, + :customers, + :products_and_inventory, + :sales_total, + :users_and_enterprises, + :enterprise_fee_summary, + :order_cycle_management, + :sales_tax, + :xero_invoices, + :packing + ] + reports = all_reports.select { |action| can? action, Spree::Admin::ReportsController } + reports.map { |report| [report, describe_report(report)] }.to_h + end + + def describe_report(report) + name = I18n.t(:name, scope: [:admin, :reports, report]) + description = begin + I18n.t!(:description, scope: [:admin, :reports, report]) + rescue I18n::MissingTranslationData + render_to_string( + partial: "#{report}_description", + layout: false, + locals: { report_types: report_types[report] } + ).html_safe + end + { name: name, url: url_for_report(report), description: description } + end + + def url_for_report(report) + public_send("#{report}_admin_reports_url".to_sym) + rescue NoMethodError + url_for([:new, :admin, :reports, report.to_s.singularize]) + end + + def timestamp + Time.zone.now.strftime("%Y%m%d") + end + + def orders_and_fulfillment_default_filters + now = Time.zone.now + { completed_at_gt: (now - 1.month).beginning_of_day, + completed_at_lt: (now + 1.day).beginning_of_day } + end end end end diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb deleted file mode 100644 index 8efd7b64b9..0000000000 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ /dev/null @@ -1,302 +0,0 @@ -require 'csv' - -require 'open_food_network/reports/list' -require 'open_food_network/order_and_distributor_report' -require 'open_food_network/products_and_inventory_report' -require 'open_food_network/lettuce_share_report' -require 'open_food_network/group_buy_report' -require 'open_food_network/order_grouper' -require 'open_food_network/customers_report' -require 'open_food_network/users_and_enterprises_report' -require 'open_food_network/order_cycle_management_report' -require 'open_food_network/packing_report' -require 'open_food_network/sales_tax_report' -require 'open_food_network/xero_invoices_report' -require 'open_food_network/bulk_coop_report' -require 'open_food_network/payments_report' -require 'open_food_network/orders_and_fulfillments_report' - -Spree::Admin::ReportsController.class_eval do - include Spree::ReportsHelper - - helper_method :render_content? - - before_filter :cache_search_state - # Fetches user's distributors, suppliers and order_cycles - before_filter :load_data, - only: [:customers, :products_and_inventory, :order_cycle_management, :packing] - - def report_types - OpenFoodNetwork::Reports::List.all - end - - # Override spree reports list. - def index - @reports = authorized_reports - respond_with(@reports) - end - - def customers - @report_types = report_types[:customers] - @report_type = params[:report_type] - @report = OpenFoodNetwork::CustomersReport.new spree_current_user, params, render_content? - render_report(@report.header, @report.table, params[:csv], "customers_#{timestamp}.csv") - end - - def order_cycle_management - params[:q] ||= {} - - @report_types = report_types[:order_cycle_management] - @report_type = params[:report_type] - - # -- Build Report with Order Grouper - @report = OpenFoodNetwork::OrderCycleManagementReport.new spree_current_user, - params, - render_content? - @table = @report.table_items - - render_report(@report.header, @table, params[:csv], "order_cycle_management_#{timestamp}.csv") - end - - def packing - params[:q] ||= {} - - @report_types = report_types[:packing] - @report_type = params[:report_type] - - # -- Build Report with Order Grouper - @report = OpenFoodNetwork::PackingReport.new spree_current_user, params, render_content? - @table = order_grouper_table - - render_report(@report.header, @table, params[:csv], "packing_#{timestamp}.csv") - end - - def orders_and_distributors - @report = OpenFoodNetwork::OrderAndDistributorReport.new spree_current_user, - params, - render_content? - @search = @report.search - csv_file_name = "orders_and_distributors_#{timestamp}.csv" - render_report(@report.header, @report.table, params[:csv], csv_file_name) - end - - def sales_tax - @distributors = my_distributors - @report_type = params[:report_type] - @report = OpenFoodNetwork::SalesTaxReport.new spree_current_user, params, render_content? - render_report(@report.header, @report.table, params[:csv], "sales_tax.csv") - end - - def bulk_coop - # -- Prepare form options - @distributors = my_distributors - @report_type = params[:report_type] - - # -- Build Report with Order Grouper - @report = OpenFoodNetwork::BulkCoopReport.new spree_current_user, params, render_content? - @table = order_grouper_table - csv_file_name = "bulk_coop_#{params[:report_type]}_#{timestamp}.csv" - - render_report(@report.header, @table, params[:csv], csv_file_name) - end - - def payments - # -- Prepare Form Options - @distributors = my_distributors - @report_type = params[:report_type] - - # -- Build Report with Order Grouper - @report = OpenFoodNetwork::PaymentsReport.new spree_current_user, params, render_content? - @table = order_grouper_table - csv_file_name = "payments_#{timestamp}.csv" - - render_report(@report.header, @table, params[:csv], csv_file_name) - end - - def orders_and_fulfillment - params[:q] ||= orders_and_fulfillment_default_filters - - # -- Prepare Form Options - permissions = OpenFoodNetwork::Permissions.new(spree_current_user) - # My distributors and any distributors distributing products I supply - @distributors = permissions.visible_enterprises_for_order_reports.is_distributor - # My suppliers and any suppliers supplying products I distribute - @suppliers = permissions.visible_enterprises_for_order_reports.is_primary_producer - - @order_cycles = my_order_cycles - - @report_types = report_types[:orders_and_fulfillment] - @report_type = params[:report_type] - - @include_blank = I18n.t(:all) - - # -- Build Report with Order Grouper - @report = OpenFoodNetwork::OrdersAndFulfillmentsReport.new spree_current_user, - params, - render_content? - @table = order_grouper_table - csv_file_name = "#{params[:report_type]}_#{timestamp}.csv" - - render_report(@report.header, @table, params[:csv], csv_file_name) - end - - def products_and_inventory - @report_types = report_types[:products_and_inventory] - @report = if params[:report_type] != 'lettuce_share' - OpenFoodNetwork::ProductsAndInventoryReport.new spree_current_user, - params, - render_content? - else - OpenFoodNetwork::LettuceShareReport.new spree_current_user, params, render_content? - end - render_report(@report.header, - @report.table, - params[:csv], - "products_and_inventory_#{timestamp}.csv") - end - - def users_and_enterprises - @report = OpenFoodNetwork::UsersAndEnterprisesReport.new params, render_content? - render_report(@report.header, - @report.table, - params[:csv], - "users_and_enterprises_#{timestamp}.csv") - end - - def xero_invoices - params[:q] ||= {} - - @distributors = my_distributors - @order_cycles = my_order_cycles - - @report = OpenFoodNetwork::XeroInvoicesReport.new spree_current_user, params, render_content? - render_report(@report.header, @report.table, params[:csv], "xero_invoices_#{timestamp}.csv") - end - - private - - # Some actions are changing the `params` object. That is unfortunate Spree - # behavior and we are building on it. So we have to look at `params` early - # to check if we are searching or just displaying a report search form. - def cache_search_state - search_keys = [ - # search parameter for ransack - :q, - # common in all reports, only set for CSV rendering - :csv, - # `button` is included in all forms. It's not important for searching, - # but the Users & Enterprises report doesn't have any other parameter - # for an empty search. So we use this one to display data. - :button, - # Some reports use filtering by enterprise or order cycle - :distributor_id, - :supplier_id, - :order_cycle_id, - # Xero Invoices can be filtered by date - :invoice_date, - :due_date - ] - @searching = search_keys.any? { |key| params.key? key } - end - - # We don't want to render data unless search params are supplied. - # Compiling data can take a long time. - def render_content? - @searching - end - - def render_report(header, table, create_csv, csv_file_name) - send_data csv_report(header, table), filename: csv_file_name if create_csv - @header = header - @table = table - # Rendering HTML is the default. - end - - def csv_report(header, table) - CSV.generate do |csv| - csv << header - table.each { |row| csv << row } - end - end - - def load_data - @distributors = my_distributors - @suppliers = my_suppliers | suppliers_of_products_distributed_by(@distributors) - @order_cycles = my_order_cycles - end - - # Load managed distributor enterprises of current user - def my_distributors - Enterprise.is_distributor.managed_by(spree_current_user) - end - - # Load managed producer enterprises of current user - def my_suppliers - Enterprise.is_primary_producer.managed_by(spree_current_user) - end - - def suppliers_of_products_distributed_by(distributors) - distributors.map { |d| Spree::Product.in_distributor(d).includes(:supplier).all }. - flatten.map(&:supplier).uniq - end - - # Load order cycles the current user has access to - def my_order_cycles - OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC') - end - - def order_grouper_table - order_grouper = OpenFoodNetwork::OrderGrouper.new @report.rules, @report.columns - order_grouper.table(@report.table_items) - end - - def authorized_reports - all_reports = [ - :orders_and_distributors, - :bulk_coop, - :payments, - :orders_and_fulfillment, - :customers, - :products_and_inventory, - :sales_total, - :users_and_enterprises, - :enterprise_fee_summary, - :order_cycle_management, - :sales_tax, - :xero_invoices, - :packing - ] - reports = all_reports.select { |action| can? action, Spree::Admin::ReportsController } - reports.map { |report| [report, describe_report(report)] }.to_h - end - - def describe_report(report) - name = I18n.t(:name, scope: [:admin, :reports, report]) - description = begin - I18n.t!(:description, scope: [:admin, :reports, report]) - rescue I18n::MissingTranslationData - render_to_string( - partial: "#{report}_description", - layout: false, - locals: { report_types: report_types[report] } - ).html_safe - end - { name: name, url: url_for_report(report), description: description } - end - - def url_for_report(report) - public_send("#{report}_admin_reports_url".to_sym) - rescue NoMethodError - url_for([:new, :admin, :reports, report.to_s.singularize]) - end - - def timestamp - Time.zone.now.strftime("%Y%m%d") - end - - def orders_and_fulfillment_default_filters - now = Time.zone.now - { completed_at_gt: (now - 1.month).beginning_of_day, - completed_at_lt: (now + 1.day).beginning_of_day } - end -end