diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index a85a188c76..10c09b7bdb 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -1,9 +1,11 @@ require 'csv' require 'open_food_web/order_and_distributor_report' +require 'open_food_web/group_buy_report' Spree::Admin::ReportsController.class_eval do Spree::Admin::ReportsController::AVAILABLE_REPORTS.merge!({:orders_and_distributors => {:name => "Orders And Distributors", :description => "Orders with distributor details"}}) + Spree::Admin::ReportsController::AVAILABLE_REPORTS.merge!({:group_buys => {:name => "Group Buys", :description => "Orders by supplier and variant"}}) def orders_and_distributors params[:q] = {} unless params[:q] @@ -23,7 +25,7 @@ Spree::Admin::ReportsController.class_eval do orders = @search.result @report = OpenFoodWeb::OrderAndDistributorReport.new orders - if(!params[:csv]) + unless params[:csv] render :html => @report else csv_string = CSV.generate do |csv| @@ -34,4 +36,35 @@ Spree::Admin::ReportsController.class_eval do end end + def group_buys + params[:q] = {} unless params[:q] + + if params[:q][:created_at_gt].blank? + params[:q][:created_at_gt] = Time.zone.now.beginning_of_month + else + params[:q][:created_at_gt] = Time.zone.parse(params[:q][:created_at_gt]).beginning_of_day rescue Time.zone.now.beginning_of_month + end + + if params[:q] && !params[:q][:created_at_lt].blank? + params[:q][:created_at_lt] = Time.zone.parse(params[:q][:created_at_lt]).end_of_day rescue "" + end + params[:q][:meta_sort] ||= "created_at.desc" + + @search = Spree::Order.complete.search(params[:q]) + orders = @search.result + + @distributors = Spree::Distributor.all + + @report = OpenFoodWeb::GroupBuyReport.new orders + unless params[:csv] + render :html => @report + else + csv_string = CSV.generate do |csv| + csv << @report.header + @report.table.each { |row| csv << row } + end + send_data csv_string, :filename => "group_buy.csv" + end + end + end \ No newline at end of file diff --git a/app/views/spree/admin/reports/group_buys.html.haml b/app/views/spree/admin/reports/group_buys.html.haml new file mode 100644 index 0000000000..f593483d57 --- /dev/null +++ b/app/views/spree/admin/reports/group_buys.html.haml @@ -0,0 +1,37 @@ += form_for @search, :url => spree.group_buys_admin_reports_path do |f| + = label_tag nil, t(:date_range) + %br + .date-range-filter + %div{"class" => "left sub-field"} + = f.text_field :created_at_gt, :class => 'datepicker' + %br + = label_tag nil, t(:start), :class => 'sub' + %div{"class" => "right sub-field"} + = f.text_field :created_at_lt, :class => 'datepicker' + %br + = label_tag nil, t(:stop) + %br + = label_tag nil, "Distributor: " + = f.collection_select(:distributor_id_eq, @distributors, :id, :name) + %br + %br + = check_box_tag :csv + = label_tag :csv, "Download as csv" + %br + = button t(:search) +%br +%br +%table#listing_orders.index + %thead + %tr{'data-hook' => "orders_header"} + - @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) + diff --git a/config/routes.rb b/config/routes.rb index 2bdedd6865..0befa2892e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -19,4 +19,6 @@ Spree::Core::Engine.routes.prepend do end match '/admin/reports/orders_and_distributors' => 'admin/reports#orders_and_distributors', :as => "orders_and_distributors_admin_reports", :via => [:get, :post] + match '/admin/reports/group_buys' => 'admin/reports#group_buys', :as => "group_buys_admin_reports", :via => [:get, :post] + end diff --git a/lib/open_food_web/group_buy_report.rb b/lib/open_food_web/group_buy_report.rb index 4a48b1e92f..825d6d4402 100644 --- a/lib/open_food_web/group_buy_report.rb +++ b/lib/open_food_web/group_buy_report.rb @@ -1,4 +1,17 @@ module OpenFoodWeb + + GroupBuyVariantRow = Struct.new(:variant, :sum_quantities, :sum_max_quantities) do + def to_row + [variant.product.supplier.name,variant.product.name,"UNITSIZE",variant.options_text,variant.weight,sum_quantities,sum_max_quantities] + end + end + + GroupBuyProductRow = Struct.new(:product, :sum_quantities, :sum_max_quantities) do + def to_row + [product.supplier.name,product.name,"UNITSIZE","TOTAL","",sum_quantities,sum_max_quantities] + end + end + class GroupBuyReport def initialize orders @orders = orders @@ -7,5 +20,38 @@ module OpenFoodWeb def header ["Supplier", "Product", "Unit Size", "Variant", "Weight", "Total Ordered", "Total Max"] end + + def variants_and_quantities + variants_and_quantities = [] + line_items = @orders.map { |o| o.line_items }.flatten + supplier_groups = line_items.group_by{ |li| li.variant.product.supplier } + supplier_groups.each do |supplier,line_items_by_supplier| + product_groups = line_items_by_supplier.group_by{ |li| li.variant.product } + product_groups.each do |product,line_items_by_product| + + # Cycle thorugh variant of a product + variant_groups = line_items_by_product.group_by{ |li| li.variant } + variant_groups.each do |variant,line_items_by_variant| + sum_quantities = line_items_by_variant.sum { |li| li.quantity } + sum_max_quantities = line_items_by_variant.sum { |li| li.max_quantity || 0 } + variants_and_quantities << GroupBuyVariantRow.new(variant,sum_quantities,sum_max_quantities) + end + + # Sum quantities for each product (Total line) + sum_quantities = line_items_by_product.sum { |li| li.variant.weight * li.quantity } + sum_max_quantities = line_items_by_product.sum { |li| li.variant.weight * (li.max_quantity || 0) } + variants_and_quantities << GroupBuyProductRow.new(product, sum_quantities, sum_max_quantities) + end + end + variants_and_quantities + end + + def table + table = [] + variants_and_quantities.each do |vr| + table << vr.to_row + end + table + end end -end \ No newline at end of file +end diff --git a/spec/lib/open_food_web/group_buy_report_spec.rb b/spec/lib/open_food_web/group_buy_report_spec.rb new file mode 100644 index 0000000000..c3ed851d55 --- /dev/null +++ b/spec/lib/open_food_web/group_buy_report_spec.rb @@ -0,0 +1,97 @@ +require 'spec_helper' + +module OpenFoodWeb + describe GroupBuyReport do + + before(:each) do + @orders = [] + bill_address = create(:address) + distributor_address = create(:address, :address1 => "distributor address", :city => 'The Shire', :zipcode => "1234") + distributor = create(:distributor, :pickup_address => distributor_address) + + @supplier1 = create(:supplier) + @variant1 = create(:variant) + @variant1.product.supplier = @supplier1 + @variant1.product.save! + shipping_method = create(:shipping_method) + product_distribution = create(:product_distribution, :product => @variant1.product, :distributor => distributor, :shipping_method => create(:shipping_method)) + shipping_instructions = "pick up on thursday please!" + + order1 = create(:order, :distributor => distributor, :bill_address => bill_address, :special_instructions => shipping_instructions) + line_item11 = create(:line_item, :variant => @variant1, :order => order1) + order1.line_items << line_item11 + @orders << order1 + + order2 = create(:order, :distributor => distributor, :bill_address => bill_address, :special_instructions => shipping_instructions) + line_item21 = create(:line_item, :variant => @variant1, :order => order2) + order2.line_items << line_item21 + + @variant2 = create(:variant) + @variant2.product.supplier = @supplier1 + @variant2.product.save! + product_distribution = create(:product_distribution, :product => @variant2.product, :distributor => distributor, :shipping_method => create(:shipping_method)) + + line_item22 = create(:line_item, :variant => @variant2, :order => order2) + order2.line_items << line_item22 + @orders << order2 + + @supplier2 = create(:supplier) + @variant3 = create(:variant) + @variant3.product.supplier = @supplier2 + @variant3.product.save! + product_distribution = create(:product_distribution, :product => @variant3.product, :distributor => distributor, :shipping_method => create(:shipping_method)) + + order3 = create(:order, :distributor => distributor, :bill_address => bill_address, :special_instructions => shipping_instructions) + line_item31 = create(:line_item, :variant => @variant3, :order => order3) + order3.line_items << line_item31 + @orders << order3 + end + + it "should return a header row describing the report" do + subject = GroupBuyReport.new [@order1] + header = subject.header + header.should == ["Supplier", "Product", "Unit Size", "Variant", "Weight", "Total Ordered", "Total Max"] + end + + it "should provide the required variant and quantity information in a table" do + subject = GroupBuyReport.new @orders + + table = subject.table + + line_items = @orders.map{ |o| o.line_items }.flatten.select{ |li| li.product.supplier == @supplier1 && li.variant == @variant1 } + + sum_quantities = line_items.map { |li| li.quantity }.sum + sum_max_quantities = line_items.map { |li| li.max_quantity || 0 }.sum + + table[0].should == [@variant1.product.supplier.name,@variant1.product.name,"UNITSIZE",@variant1.options_text,@variant1.weight,sum_quantities,sum_max_quantities] + end + + it "should return a table wherein each rows contains the same number of columns as the heading" do + subject = GroupBuyReport.new @orders + + table = subject.table + columns = subject.header.length + + table.each do |r| + r.length.should == columns + end + end + + it "should split and group line items from multiple suppliers and of multiple variants" do + subject = GroupBuyReport.new @orders + + table_row_objects = subject.variants_and_quantities + + variant_rows = table_row_objects.select{ |r| r.class == OpenFoodWeb::GroupBuyVariantRow } + product_rows = table_row_objects.select{ |r| r.class == OpenFoodWeb::GroupBuyProductRow } + + supplier_groups = variant_rows.group_by { |r| r.variant.product.supplier } + variant_groups = variant_rows.group_by{ |r| r.variant } + product_groups = product_rows.group_by{ |r| r.product } + + supplier_groups.length.should == 2 + variant_groups.length.should == 3 + product_groups.length.should == 3 + end + end +end \ No newline at end of file diff --git a/spec/lib/open_food_web/group_buy_spec.rb b/spec/lib/open_food_web/group_buy_spec.rb deleted file mode 100644 index 6616ffb9fb..0000000000 --- a/spec/lib/open_food_web/group_buy_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'spec_helper' - -module OpenFoodWeb - describe GroupBuyReport do - - before(:each) do - @bill_address = create(:address) - @distributor_address = create(:address, :address1 => "distributor address", :city => 'The Shire', :zipcode => "1234") - @distributor = create(:distributor, :pickup_address => @distributor_address) - product = create(:product) - product_distribution = create(:product_distribution, :product => product, :distributor => @distributor, :shipping_method => create(:shipping_method)) - @shipping_instructions = "pick up on thursday please!" - @order = create(:order, :distributor => @distributor, :bill_address => @bill_address, :special_instructions => @shipping_instructions) - @payment_method = create(:payment_method) - payment = create(:payment, :payment_method => @payment_method, :order => @order ) - @order.payments << payment - @line_item = create(:line_item, :product => product, :order => @order) - @order.line_items << @line_item - end - - it "should return a header row describing the report" do - subject = GroupBuyReport.new [@order] - - header = subject.header - header.should == ["Supplier", "Product", "Unit Size", "Variant", "Weight", "Total Ordered", "Total Max"] - end - - end -end \ No newline at end of file