From 9737f21bb850bd7d221517a3eef466729d526d40 Mon Sep 17 00:00:00 2001 From: Rob H Date: Wed, 10 Oct 2012 13:46:51 +1100 Subject: [PATCH] WIP: Write body of group buy report --- .../admin/reports_controller_decorator.rb | 31 ++++++ .../spree/admin/reports/group_buys.html.haml | 37 +++++++ config/routes.rb | 2 + lib/open_food_web/group_buy_report.rb | 46 +++++++++ spec/lib/open_food_web/group_buy_spec.rb | 96 ++++++++++++++++--- 5 files changed, 198 insertions(+), 14 deletions(-) create mode 100644 app/views/spree/admin/reports/group_buys.html.haml diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index a85a188c76..8b50df3f04 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] @@ -34,4 +36,33 @@ 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 + + @report = OpenFoodWeb::GroupBuyReport.new orders + if(!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..b223276c60 --- /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 |s| + = label_tag nil, t(:date_range) + %br + .date-range-filter + %div{"class" => "left sub-field"} + = s.text_field :created_at_gt, :class => 'datepicker' + %br + = label_tag nil, t(:start), :class => 'sub' + %div{"class" => "right sub-field"} + = s.text_field :created_at_lt, :class => 'datepicker' + %br + = label_tag nil, t(:stop) + %br + = label_tag nil, "Distributor: " + = collection_select(:q, :distributor_id_eq, Spree::Distributor.all, :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..78cfbc5ad8 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 + + class GroupBuyVariantRow < Struct.new :variant, :sum_quantities, :sum_max_quantities + def to_row + [variant.product.supplier.name,variant.product.name,"UNITSIZE",variant.options_text,variant.weight,sum_quantities,sum_max_quantities] + end + end + + class GroupBuyProductRow < Struct.new :product, :sum_quantities, :sum_max_quantities + 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 diff --git a/spec/lib/open_food_web/group_buy_spec.rb b/spec/lib/open_food_web/group_buy_spec.rb index 6616ffb9fb..4a9ba335ef 100644 --- a/spec/lib/open_food_web/group_buy_spec.rb +++ b/spec/lib/open_food_web/group_buy_spec.rb @@ -4,26 +4,94 @@ 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 + @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 [@order] - + 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