From 9737f21bb850bd7d221517a3eef466729d526d40 Mon Sep 17 00:00:00 2001 From: Rob H Date: Wed, 10 Oct 2012 13:46:51 +1100 Subject: [PATCH 1/3] 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 From 0ad60453636a46648f737cde59add7e3cf517f9b Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 10 Oct 2012 14:02:44 +1100 Subject: [PATCH 2/3] Fix struct superclass mismatch error --- lib/open_food_web/group_buy_report.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/open_food_web/group_buy_report.rb b/lib/open_food_web/group_buy_report.rb index 78cfbc5ad8..ebf3a77349 100644 --- a/lib/open_food_web/group_buy_report.rb +++ b/lib/open_food_web/group_buy_report.rb @@ -1,12 +1,12 @@ module OpenFoodWeb - class GroupBuyVariantRow < Struct.new :variant, :sum_quantities, :sum_max_quantities + 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 - - class GroupBuyProductRow < Struct.new :product, :sum_quantities, :sum_max_quantities +# class Blah < Struct.new :foo + 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 @@ -54,4 +54,4 @@ module OpenFoodWeb table end end -end \ No newline at end of file +end From 5803da9c5553ab4595d8c45e7285520f93955467 Mon Sep 17 00:00:00 2001 From: Rob H Date: Wed, 10 Oct 2012 15:13:15 +1100 Subject: [PATCH 3/3] Syntax fixes for group buy report classes and tests --- .../admin/reports_controller_decorator.rb | 6 +++-- .../spree/admin/reports/group_buys.html.haml | 8 +++---- lib/open_food_web/group_buy_report.rb | 24 +++++++++---------- ...p_buy_spec.rb => group_buy_report_spec.rb} | 16 ++++++------- 4 files changed, 28 insertions(+), 26 deletions(-) rename spec/lib/open_food_web/{group_buy_spec.rb => group_buy_report_spec.rb} (84%) diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index 8b50df3f04..10c09b7bdb 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -25,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| @@ -52,9 +52,11 @@ Spree::Admin::ReportsController.class_eval do @search = Spree::Order.complete.search(params[:q]) orders = @search.result + + @distributors = Spree::Distributor.all @report = OpenFoodWeb::GroupBuyReport.new orders - if(!params[:csv]) + unless params[:csv] render :html => @report else csv_string = CSV.generate do |csv| diff --git a/app/views/spree/admin/reports/group_buys.html.haml b/app/views/spree/admin/reports/group_buys.html.haml index b223276c60..f593483d57 100644 --- a/app/views/spree/admin/reports/group_buys.html.haml +++ b/app/views/spree/admin/reports/group_buys.html.haml @@ -1,18 +1,18 @@ -= form_for @search, :url => spree.group_buys_admin_reports_path do |s| += 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"} - = s.text_field :created_at_gt, :class => 'datepicker' + = f.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' + = f.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) + = f.collection_select(:distributor_id_eq, @distributors, :id, :name) %br %br = check_box_tag :csv diff --git a/lib/open_food_web/group_buy_report.rb b/lib/open_food_web/group_buy_report.rb index ebf3a77349..825d6d4402 100644 --- a/lib/open_food_web/group_buy_report.rb +++ b/lib/open_food_web/group_buy_report.rb @@ -5,7 +5,7 @@ module OpenFoodWeb [variant.product.supplier.name,variant.product.name,"UNITSIZE",variant.options_text,variant.weight,sum_quantities,sum_max_quantities] end end -# class Blah < Struct.new :foo + 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] @@ -23,24 +23,24 @@ module OpenFoodWeb 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} + 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 = 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} + # 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} + 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) + # 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 diff --git a/spec/lib/open_food_web/group_buy_spec.rb b/spec/lib/open_food_web/group_buy_report_spec.rb similarity index 84% rename from spec/lib/open_food_web/group_buy_spec.rb rename to spec/lib/open_food_web/group_buy_report_spec.rb index 4a9ba335ef..c3ed851d55 100644 --- a/spec/lib/open_food_web/group_buy_spec.rb +++ b/spec/lib/open_food_web/group_buy_report_spec.rb @@ -58,10 +58,10 @@ module OpenFoodWeb table = subject.table - line_items = @orders.map{|o| o.line_items}.flatten.select{|li| li.product.supplier == @supplier1 && li.variant == @variant1} + 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 + 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 @@ -82,12 +82,12 @@ module OpenFoodWeb 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} + 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 = 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