From 79a83ee206f5d1c2a6359a3f3ac1a2fb853f0cc8 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 14 Nov 2014 12:52:19 +1100 Subject: [PATCH] Adding users and enterprises report, controller action and template --- .../admin/reports_controller_decorator.rb | 10 ++- .../reports/users_and_enterprises.html.haml | 39 +++++++++++ .../users_and_enterprises_report.rb | 69 +++++++++++++++++++ .../users_and_enterprises_report.rb | 56 +++++++++++++++ 4 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 app/views/spree/admin/reports/users_and_enterprises.html.haml create mode 100644 lib/open_food_network/users_and_enterprises_report.rb create mode 100644 spec/lib/open_food_network/users_and_enterprises_report.rb diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index 038e12020a..622edbe9a9 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -4,6 +4,7 @@ require 'open_food_network/products_and_inventory_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' Spree::Admin::ReportsController.class_eval do @@ -572,13 +573,16 @@ Spree::Admin::ReportsController.class_eval do def products_and_inventory @report_types = REPORT_TYPES[:products_and_inventory] - @report = OpenFoodNetwork::ProductsAndInventoryReport.new spree_current_user, params - #@table = @report.table - #@header = @report.header render_report(@report.header, @report.table, params[:csv], "products_and_inventory.csv") end + def users_and_enterprises + # @report_types = REPORT_TYPES[:users_and_enterprises] + @report = OpenFoodNetwork::UsersAndEnterprisesReport.new params + render_report(@report.header, @report.table, params[:csv], "users_and_enterprises.csv") + end + def render_report (header, table, create_csv, csv_file_name) unless create_csv render :html => table diff --git a/app/views/spree/admin/reports/users_and_enterprises.html.haml b/app/views/spree/admin/reports/users_and_enterprises.html.haml new file mode 100644 index 0000000000..d6b4332d3a --- /dev/null +++ b/app/views/spree/admin/reports/users_and_enterprises.html.haml @@ -0,0 +1,39 @@ +-# = form_tag spree.users_and_enterprises_reports_url do |f| +-# %br +-# = label_tag nil, "Enterprise: " +-# = select_tag(:distributor_id, +-# options_from_collection_for_select(@distributors, :id, :name, params[:distributor_id]), +-# :include_blank => true) +-# +-# %br +-# = label_tag nil, "User: " +-# = select_tag(:supplier_id, +-# options_from_collection_for_select(@suppliers, :id, :name, params[:supplier_id]), +-# :include_blank => true) +-# +-# -# Might need this later if we add different kinds of reports +-# -# %br +-# -# = label_tag nil, "Report Type: " +-# -# = select_tag(:report_type, options_for_select(@report_types, params[:report_type])) +-# +-# %br +-# %br +-# = check_box_tag :csv +-# = label_tag :csv, "Download as csv" +-# %br +-# = button t(:search) +-# %br +-# %br +%table + %thead + %trs + - @report.header.each do |heading| + %th=heading + %tbody + - @report.table.each do |row| + %tr + - row.each do |column| + %td= column + - if @report.table.empty? + %tr + %td{:colspan => "2"}= t(:none) \ No newline at end of file diff --git a/lib/open_food_network/users_and_enterprises_report.rb b/lib/open_food_network/users_and_enterprises_report.rb new file mode 100644 index 0000000000..e3686cbacf --- /dev/null +++ b/lib/open_food_network/users_and_enterprises_report.rb @@ -0,0 +1,69 @@ +module OpenFoodNetwork + class UsersAndEnterprisesReport + attr_reader :params + def initialize(params = {}) + @params = params + end + + def header + [ + "User", + "Relationship", + "Enterprise", + "Producer?", + "Sells", + "Confirmation Date" + ] + end + + def table + users_and_enterprises.map do |uae| [ + uae["user_email"], + uae["relationship_type"], + uae["name"], + to_bool(uae["is_primary_producer"]), + uae["sells"], + to_local_datetime(uae["confirmed_at"]) + ] + end + end + + def owners_and_enterprises + ActiveRecord::Base.connection.execute("SELECT enterprises.name, enterprises.sells, enterprises.is_primary_producer, enterprises.confirmed_at, + 'owns' AS relationship_type, owners.email as user_email FROM enterprises + LEFT JOIN spree_users AS owners ON owners.id=enterprises.owner_id ORDER BY enterprises.name DESC" ) + .to_a + end + + def managers_and_enterprises + ActiveRecord::Base.connection.execute("SELECT enterprises.name, enterprises.sells, enterprises.is_primary_producer, enterprises.confirmed_at, + 'manages' AS relationship_type, managers.email as user_email FROM enterprises + LEFT JOIN enterprise_roles ON enterprises.id=enterprise_roles.enterprise_id + LEFT JOIN spree_users AS managers ON enterprise_roles.user_id=managers.id + WHERE enterprise_id IS NOT NULL + AND user_id IS NOT NULL + ORDER BY enterprises.name DESC, user_email DESC") + .to_a + end + + def users_and_enterprises + sort( owners_and_enterprises.concat managers_and_enterprises ) + end + + def sort(results) + results.sort do |a,b| + [ a["name"], b["relationship_type"], a["user_email"] ] <=> + [ b["name"], a["relationship_type"], b["user_email"] ] + end + end + + def to_bool(value) + ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value) + end + + def to_local_datetime(string) + return "Not Confirmed" if string.nil? + string.to_datetime.in_time_zone.strftime "%Y-%m-%d %H:%M" + end + end +end \ No newline at end of file diff --git a/spec/lib/open_food_network/users_and_enterprises_report.rb b/spec/lib/open_food_network/users_and_enterprises_report.rb new file mode 100644 index 0000000000..11de231871 --- /dev/null +++ b/spec/lib/open_food_network/users_and_enterprises_report.rb @@ -0,0 +1,56 @@ +require 'spec_helper' + + +module OpenFoodNetwork + describe OrderAndDistributorReport do + + describe "users_and_enterprises" do + let!(:owners_and_enterprises) { double(:owners_and_enterprises) } + let!(:managers_and_enterprises) { double(:managers_and_enterprises) } + let!(:subject) { OpenFoodNetwork::UsersAndEnterprisesReport.new {} } + + before do + subject.stub(:owners_and_enterprises) { owners_and_enterprises } + subject.stub(:managers_and_enterprises) { managers_and_enterprises } + end + + it "should concatenate owner and manager queries" do + expect(subject).to receive(:owners_and_enterprises).once + expect(subject).to receive(:managers_and_enterprises).once + expect(owners_and_enterprises).to receive(:concat).with(managers_and_enterprises).and_return [] + expect(subject).to receive(:sort).with [] + subject.users_and_enterprises + end + end + + describe "sorting results" do + let!(:subject) { OpenFoodNetwork::UsersAndEnterprisesReport.new {} } + + it "sorts by name first" do + uae_mock = [ + { "name" => "aaa", "relationship_type" => "bbb", "user_email" => "bbb" }, + { "name" => "bbb", "relationship_type" => "aaa", "user_email" => "aaa" } + ] + expect(subject.sort uae_mock).to eq [ uae_mock[0], uae_mock[1] ] + end + + it "sorts by relationship type (reveresed) second" do + uae_mock = [ + { "name" => "aaa", "relationship_type" => "bbb", "user_email" => "bbb" }, + { "name" => "aaa", "relationship_type" => "aaa", "user_email" => "aaa" }, + { "name" => "aaa", "relationship_type" => "bbb", "user_email" => "aaa" } + ] + expect(subject.sort uae_mock).to eq [ uae_mock[2], uae_mock[0], uae_mock[1] ] + end + + it "sorts by user_email third" do + uae_mock = [ + { "name" => "aaa", "relationship_type" => "bbb", "user_email" => "aaa" }, + { "name" => "aaa", "relationship_type" => "aaa", "user_email" => "aaa" }, + { "name" => "aaa", "relationship_type" => "aaa", "user_email" => "bbb" } + ] + expect(subject.sort uae_mock).to eq [ uae_mock[0], uae_mock[1], uae_mock[2] ] + end + end + end +end \ No newline at end of file