WIP: Create report grouper, write reports for bulk co-ops and payments

This commit is contained in:
Rob H
2012-10-21 13:12:48 +11:00
parent 8c7ed6f4ef
commit ddb01e4ccb
5 changed files with 571 additions and 1 deletions

View File

@@ -1,11 +1,14 @@
require 'csv'
require 'open_food_web/order_and_distributor_report'
require 'open_food_web/group_buy_report'
require 'open_food_web/order_grouper'
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"}})
Spree::Admin::ReportsController::AVAILABLE_REPORTS.merge!({:bulk_coop => {:name => "Bulk Co-Op", :description => "Reports for Bulk Co-Op orders"}})
Spree::Admin::ReportsController::AVAILABLE_REPORTS.merge!({:payments => {:name => "Payment Reports", :description => "Reports for Payments"}})
def orders_and_distributors
params[:q] = {} unless params[:q]
@@ -52,7 +55,7 @@ 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
@@ -67,4 +70,135 @@ Spree::Admin::ReportsController.class_eval do
end
end
def bulk_coop
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.select { |o| o.completed? } # Only select complete orders
line_items = orders.map { |o| o.line_items }.flatten
# Ignore supplier conditions if "All" selected
#if params[:supplier_id] && params[:supplier_id] != "All"
# line_items = line_items.select { |li| li.variant.product.supplier_id == params[:supplier_id] }
#end
#[Distributor.new(:id => nil, :name => 'All')]+
@distributors = Spree::Distributor.all
@report_type = params[:report_type]
case params[:report_type]
when "bulk_coop_supplier_report"
rules = [ { group_by: Proc.new { |li| li.variant.product.supplier }, sort_by: Proc.new { |supplier| supplier.name } }, { group_by: Proc.new { |li| li.variant.product }, sort_by: Proc.new { |product| product.name }, summary_columns: [ Proc.new { |lis| lis.first.variant.product.supplier.name }, Proc.new { |lis| lis.first.variant.product.name }, Proc.new { |lis| "UNIT SIZE" }, Proc.new { |lis| "" }, Proc.new { |lis| "" }, Proc.new { |lis| lis.sum { |li| li.quantity * li.variant.weight } }, Proc.new { |lis| lis.sum { |li| (li.max_quantity || 0) * li.variant.weight } } ] }, { group_by: Proc.new { |li| li.variant }, sort_by: Proc.new { |variant| variant.options_text } } ]
columns = [ Proc.new { |lis| lis.first.variant.product.supplier.name }, Proc.new { |lis| lis.first.variant.product.name }, Proc.new { |lis| "UNIT SIZE" }, Proc.new { |lis| lis.first.variant.options_text }, Proc.new { |lis| lis.first.variant.weight }, Proc.new { |lis| lis.sum { |li| li.quantity } }, Proc.new { |lis| lis.sum { |li| li.max_quantity || 0 } } ]
header = ["Supplier","Product","Unit Size","Variant","Weight","Sum Total","Sum Max Total"]
when "bulk_coop_allocation"
rules = [ { group_by: Proc.new { |li| li.variant.product }, sort_by: Proc.new { |product| product.name } }, { group_by: Proc.new { |li| li.variant }, sort_by: Proc.new { |variant| variant.options_text } }, { group_by: Proc.new { |li| li.order.user }, sort_by: Proc.new { |user| user.to_s } } ]
columns = [ Proc.new { |lis| lis.first.order.bill_address.firstname + " " + lis.first.order.bill_address.lastname }, Proc.new { |lis| lis.first.variant.product.name }, Proc.new { |lis| "UNIT SIZE" }, Proc.new { |lis| lis.first.variant.options_text }, Proc.new { |lis| lis.first.variant.weight }, Proc.new { |lis| lis.sum { |li| li.quantity } }, Proc.new { |lis| lis.sum { |li| li.max_quantity || 0 } } ]
header = ["Customer","Product","Unit Size","Variant","Weight","Sum Total","Sum Max Total"]
when "bulk_coop_packing_sheets"
rules = [ { group_by: Proc.new { |li| li.variant.product }, sort_by: Proc.new { |product| product.name } }, { group_by: Proc.new { |li| li.variant }, sort_by: Proc.new { |variant| variant.options_text } }, { group_by: Proc.new { |li| li.order.user }, sort_by: Proc.new { |user| user.to_s } } ]
columns = [ Proc.new { |lis| lis.first.order.bill_address.firstname + " " + lis.first.order.bill_address.lastname }, Proc.new { |lis| lis.first.variant.product.name }, Proc.new { |lis| lis.first.variant.options_text }, Proc.new { |lis| lis.sum { |li| li.quantity } } ]
header = ["Customer","Product","Variant","Sum Total"]
when "bulk_coop_customer_payments"
rules = [ { group_by: Proc.new { |li| li.order.user }, sort_by: Proc.new { |user| user.to_s } }, { group_by: Proc.new { |li| li.order }, sort_by: Proc.new { |order| order.created_at } } ]
columns = [ Proc.new { |lis| lis.first.order.bill_address.firstname + " " + lis.first.order.bill_address.lastname }, Proc.new { |lis| lis.first.order.created_at.to_s }, Proc.new { |lis| lis.map { |li| li.order }.to_set.to_a.sum { |o| o.total } }, Proc.new { |lis| lis.map { |li| li.order }.to_set.to_a.sum { |o| o.outstanding_balance } }, Proc.new { |lis| lis.map { |li| li.order }.to_set.to_a.sum { |o| o.payment_total } } ]
header = ["Customer","Date of Order","Total Cost","Amount Owing","Amount Paid"]
else # List all line items
rules = [ { group_by: Proc.new { |li| li.variant.product.supplier }, sort_by: Proc.new { |supplier| supplier.name } }, { group_by: Proc.new { |li| li.variant.product }, sort_by: Proc.new { |product| product.name } }, { group_by: Proc.new { |li| li.variant }, sort_by: Proc.new { |variant| variant.options_text } } ]
columns = [ Proc.new { |lis| lis.first.variant.product.supplier.name }, Proc.new { |lis| lis.first.variant.product.name }, Proc.new { |lis| "UNIT SIZE" }, Proc.new { |lis| lis.first.variant.options_text }, Proc.new { |lis| lis.first.variant.weight }, Proc.new { |lis| lis.sum { |li| li.quantity } }, Proc.new { |lis| lis.sum { |li| li.max_quantity || 0 } } ]
header = ["Supplier","Product","Unit Size","Variant","Weight","Sum Total","Sum Max Total"]
end
order_grouper = OpenFoodWeb::OrderGrouper.new rules, columns
@header = header
@table = order_grouper.table(line_items)
unless params[:csv]
render :html => @table
else
csv_string = CSV.generate do |csv|
csv << @header
@table.each { |row| csv << row }
end
send_data csv_string, :filename => "bulk_coop.csv"
end
end
def payments
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.select { |o| o.complete? } # Only select complete orders
payments = orders.map { |o| o.payments.select { |payment| payment.completed? } }.flatten # Only select completed payments
# Ignore supplier conditions if "All" selected
#if params[:supplier_id] && params[:supplier_id] != "All"
# line_items = line_items.select { |li| li.variant.product.supplier_id == params[:supplier_id] }
#end
#[Distributor.new(:id => nil, :name => 'All')]+
@distributors = Spree::Distributor.all
@report_type = params[:report_type]
case params[:report_type]
when "payments_by_payment_type"
table_items = payments
rules = [ { group_by: Proc.new { |payment| payment.order.payment_state }, sort_by: Proc.new { |payment_state| payment_state } }, { group_by: Proc.new { |payment| payment.order.distributor }, sort_by: Proc.new { |distributor| distributor.name } }, { group_by: Proc.new { |payment| payment.payment_method }, sort_by: Proc.new { |method| method.name } } ]
columns = [ Proc.new { |payments| payments.first.order.payment_state }, Proc.new { |payments| payments.first.order.distributor.name }, Proc.new { |payments| payments.first.payment_method.name }, Proc.new { |payments| payments.sum { |payment| payment.amount } } ]
header = ["Payment State", "Distributor", "Payment Type", "Total ($)"]
when "itemised_payment_totals"
table_items = orders
rules = [ { group_by: Proc.new { |order| order.payment_state }, sort_by: Proc.new { |payment_state| payment_state } }, { group_by: Proc.new { |order| order.distributor }, sort_by: Proc.new { |distributor| distributor.name } } ]
columns = [ Proc.new { |orders| orders.first.payment_state }, Proc.new { |orders| orders.first.distributor.name }, Proc.new { |orders| orders.sum { |o| o.item_total } }, Proc.new { |orders| orders.sum { |o| o.ship_total } }, Proc.new { |orders| orders.sum { |o| o.outstanding_balance } }, Proc.new { |orders| orders.sum { |o| o.total } } ]
header = ["Payment State", "Distributor", "Product Total ($)", "Shipping Total ($)", "Outstanding Balance ($)", "Total ($)"]
when "payment_totals"
table_items = orders
rules = [ { group_by: Proc.new { |order| order.payment_state }, sort_by: Proc.new { |payment_state| payment_state } }, { group_by: Proc.new { |order| order.distributor }, sort_by: Proc.new { |distributor| distributor.name } } ]
columns = [ Proc.new { |orders| orders.first.payment_state }, Proc.new { |orders| orders.first.distributor.name }, Proc.new { |orders| orders.sum { |o| o.item_total } }, Proc.new { |orders| orders.sum { |o| o.ship_total } }, Proc.new { |orders| orders.sum { |o| o.total } }, Proc.new { |orders| orders.sum { |o| o.payments.select { |payment| payment.completed? && (payment.payment_method.name.to_s.include? "EFT") }.sum { |payment| payment.amount } } }, Proc.new { |orders| orders.sum { |o| o.payments.select { |payment| payment.completed? && (payment.payment_method.name.to_s.include? "PayPal") }.sum{ |payment| payment.amount } } }, Proc.new { |orders| orders.sum { |o| o.outstanding_balance } } ]
header = ["Payment State", "Distributor", "Product Total ($)", "Shipping Total ($)", "Total ($)", "EFT ($)", "PayPal ($)", "Outstanding Balance ($)"]
else
table_items = payments
rules = [ { group_by: Proc.new { |payment| payment.order.payment_state }, sort_by: Proc.new { |payment_state| payment_state } }, { group_by: Proc.new { |payment| payment.order.distributor }, sort_by: Proc.new { |distributor| distributor.name } }, { group_by: Proc.new { |payment| payment.payment_method }, sort_by: Proc.new { |method| method.name } } ]
columns = [ Proc.new { |payments| payments.first.order.payment_state }, Proc.new { |payments| payments.first.order.distributor.name }, Proc.new { |payments| payments.first.payment_method.name }, Proc.new { |payments| payments.sum { |payment| payment.amount } } ]
header = ["Payment State", "Distributor", "Payment Type", "Total ($)"]
end
order_grouper = OpenFoodWeb::OrderGrouper.new rules, columns
@header = header
@table = order_grouper.table(table_items)
unless params[:csv]
render :html => @table
else
csv_string = CSV.generate do |csv|
csv << @header
@table.each { |row| csv << row }
end
send_data csv_string, :filename => "payments.csv"
end
end
end

View File

@@ -0,0 +1,41 @@
= form_for @search, :url => spree.bulk_coop_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, :include_blank => 'All')
/= label_tag nil, "Supplier: "
/= collection_select(:supplier, :supplier_id, @suppliers, :id, :name, :prompt => 'All')
%br
= label_tag nil, "Report Type: "
= select_tag(:report_type, options_for_select([['Bulk Co-op - Totals by Supplier',:bulk_coop_supplier_report],['Bulk Co-op - Allocation',:bulk_coop_allocation],['Bulk Co-op - Packing Sheets',:bulk_coop_packing_sheets],['Bulk Co-op - Customer Payments',:bulk_coop_customer_payments]], @report_type))
%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"}
- @header.each do |heading|
%th=heading
%tbody
- @table.each do |row|
%tr
- row.each do |column|
%td= column
- if @table.empty?
%tr
%td{:colspan => "2"}= t(:none)

View File

@@ -0,0 +1,41 @@
= form_for @search, :url => spree.payments_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, :include_blank => 'All')
/= label_tag nil, "Supplier: "
/= collection_select(:supplier, :supplier_id, @suppliers, :id, :name, :prompt => 'All')
%br
= label_tag nil, "Report Type: "
= select_tag(:report_type, options_for_select([['Payments By Type',:payments_by_payment_type],['Itemised Payment Totals',:itemised_payment_totals],['Payment Totals',:payment_totals]], @report_type))
%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"}
- @header.each do |heading|
%th=heading
%tbody
- @table.each do |row|
%tr
- row.each do |column|
%td= column
- if @table.empty?
%tr
%td{:colspan => "2"}= t(:none)

View File

@@ -0,0 +1,56 @@
module OpenFoodWeb
class OrderGrouper
def initialize rules, column_constructors
@rules = rules
@column_constructors = column_constructors
end
def build_tree items, remaining_rules
rules = remaining_rules.clone
unless rules.empty?
rule = rules.delete_at(0) # Remove current rule for subsequent groupings
group_and_sort(rule, rules, items)
else
items
end
end
def group_and_sort rule, remaining_rules, items
branch = {}
groups = items.group_by { |item| rule[:group_by].call(item) }
sorted_groups = groups.sort_by { |key, value| rule[:sort_by].call(key) }
sorted_groups.each do |property,items_by_property|
branch[property] = build_tree(items_by_property, remaining_rules)
branch[property][:summary_row] = { items: items_by_property, columns: rule[:summary_columns] } unless rule[:summary_columns] == nil || branch[property].class == Array
end
branch
end
def build_table groups
rows = []
unless groups.class == Array
groups.each do |key, group|
unless key == :summary_row
build_table(group).each { |g| rows << g }
else
row = Array.new
group[:columns].each { |cols| row << cols.call(group[:items]) }
rows << row
end
end
else
row = Array.new
@column_constructors.each { |column_constructor| row << column_constructor.call(groups) }
rows << row
end
rows
end
def table items
tree = build_tree(items,@rules)
table = build_table(tree)
table
end
end
end

View File

@@ -0,0 +1,298 @@
#require 'spec_helper'
#module OpenFoodWeb
# describe OrderGrouper do
#
# before(:each) do
# @orders = []
# 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!"
#
# bill_address1 = create(:address)
# order1 = create(:order, :distributor => distributor, :bill_address => bill_address1, :special_instructions => shipping_instructions)
# line_item11 = create(:line_item, :variant => @variant1, :order => order1)
# order1.line_items << line_item11
# @orders << order1
#
# bill_address2 = create(:address)
# order2 = create(:order, :distributor => distributor, :bill_address => bill_address2, :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))
# bill_address3 = create(:address)
# order3 = create(:order, :distributor => distributor, :bill_address => bill_address3, :special_instructions => shipping_instructions)
# line_item31 = create(:line_item, :variant => @variant3, :order => order3)
# order3.line_items << line_item31
# @orders << order3
# end
# context "when grouping by supplier, then product, then variant" do
# group_rules = [ { group_by: Proc.new { |li| li.variant.product.supplier }, sort_by: Proc.new { |supplier| supplier.name } }, { group_by: Proc.new { |li| li.variant.product }, sort_by: Proc.new { |product| product.name } }, { group_by: Proc.new { |li| li.variant }, sort_by: Proc.new { |variant| variant.options_text } } ]
# column_properties = [ Proc.new { |lis| lis.first.variant.product.supplier.name }, Proc.new { |lis| lis.first.variant.product.name }, Proc.new { |lis| "UNIT SIZE" }, Proc.new { |lis| lis.first.variant.options_text }, Proc.new { |lis| lis.first.variant.weight }, Proc.new { |lis| lis.sum { |li| li.quantity } }, Proc.new { |lis| lis.sum { |li| li.max_quantity || 0 } } ]
# it "should return a Hash with one key for each supplier represented by the orders" do
# subject = OrderGrouper.new group_rules, column_properties
# line_items = @orders.map { |o| o.line_items }.flatten
# groups = subject.grouper_sorter(line_items, group_rules)
# groups.class.should == Hash
# groups.length.should == 2
# end
# it "should group items over multiple levels according to group by rules" do
# subject = OrderGrouper.new group_rules, column_properties
# line_items = @orders.map { |o| o.line_items }.flatten
# groups = subject.grouper_sorter(line_items, group_rules)
# groups[@supplier1].length.should == 2
# groups[@supplier2].length.should == 1
# end
# it "should return a table as an array" do
# subject = OrderGrouper.new group_rules, column_properties
#
# line_items = @orders.map { |o| o.line_items }.flatten
# subject.table(line_items).class.should == Array
# end
# end
# context "when grouping by customers" do
# group_rules = [ { group_by: Proc.new { |li| li.variant.product }, sort_by: Proc.new { |product| product.name } }, { group_by: Proc.new { |li| li.variant }, sort_by: Proc.new { |variant| variant.options_text } }, { group_by: Proc.new { |li| li.order.bill_address }, sort_by: Proc.new { |bill_address| bill_address.firstname + " " + bill_address.lastname } } ]
# column_properties = [ Proc.new { |lis| lis.first.order.bill_address.firstname + " " + lis.first.order.bill_address.lastname }, Proc.new { |lis| lis.first.variant.product.name }, Proc.new { |lis| "UNIT SIZE" }, Proc.new { |lis| lis.first.variant.options_text }, Proc.new { |lis| lis.first.variant.weight }, Proc.new { |lis| lis.sum { |li| li.quantity } }, Proc.new { |lis| lis.sum { |li| li.max_quantity || 0 } } ]
# it "should return a table as an array" do
# subject = OrderGrouper.new group_rules, column_properties
# line_items = @orders.map { |o| o.line_items }.flatten
# subject.table(line_items).class.should == Array
# end
# end
# end
#end
require 'spec_helper'
module OpenFoodWeb
describe OrderGrouper do
before(:each) do
@items = [1, 2, 3, 4]
end
context "constructing the table" do
it "should build a tree then build a table" do
rules = [ { group_by: Proc.new { |sentence| sentence.paragraph.chapter }, sort_by: Proc.new { |chapter| chapter.name }, summary_columns: [Proc.new { |is| is.first.paragraph.chapter.name }, Proc.new { |is| "TOTAL" }, Proc.new { |is| "" }, Proc.new { |is| is.sum {|i| i.property1 } } ] },
{ group_by: Proc.new { |sentence| sentence.paragraph }, sort_by: Proc.new { |paragraph| paragraph.name } } ]
columns = [Proc.new { |is| is.first.paragraph.chapter.name }, Proc.new { |is| is.first.paragraph.name }, Proc.new { |is| is.first.name }, Proc.new { |is| is.sum {|i| i.property1 } }]
subject = OrderGrouper.new rules, columns
tree = double(:tree)
subject.should_receive(:build_tree).with(@items, rules).and_return(tree)
subject.should_receive(:build_table).with(tree)
subject.table(@items)
end
end
context "grouping items without rules" do
it "returns the original array when no rules are provided" do
rules = []
column1 = double(:col1)
column2 = double(:col2)
columns = [column1, column2]
subject = OrderGrouper.new rules, columns
rules.should_receive(:clone).and_return(rules)
subject.build_tree(@items, rules).should == @items
end
end
context "grouping items with rules" do
it "builds branches by removing a rule from \"rules\" and running group_and_sort" do
rule1 = double(:rule1)
rule2 = double(:rule2)
rules = [rule1, rule2]
column1 = double(:col1)
column2 = double(:col2)
columns = [column1, column2]
subject = OrderGrouper.new rules, columns
#rules = [ { group_by: Proc.new { |sentence| sentence.paragraph.chapter }, sort_by: Proc.new { |chapter| chapter.name }, summary_columns: [Proc.new { |is| is.first.paragraph.chapter.name }, Proc.new { |is| "TOTAL" }, Proc.new { |is| "" }, Proc.new { |is| is.sum {|i| i.property1 } } ] },
#{ group_by: Proc.new { |sentence| sentence.paragraph }, sort_by: Proc.new { |paragraph| paragraph.name } } ]
#columns = [Proc.new { |is| is.first.paragraph.chapter.name }, Proc.new { |is| is.first.paragraph.name }, Proc.new { |is| is.first.name }, Proc.new { |is| is.sum {|i| i.property1 } }]
rules.should_receive(:clone).and_return(rules)
rules.should_receive(:delete_at).with(0)
grouped_tree = double(:grouped_tree)
subject.should_receive(:group_and_sort).and_return(grouped_tree)
subject.build_tree(@items, rules).should == grouped_tree
end
it "separates the first rule from rules before sending to group_and_sort" do
rule1 = double(:rule1)
rule2 = double(:rule2)
rules = [rule1, rule2]
column1 = double(:col1)
column2 = double(:col2)
columns = [column1, column2]
subject = OrderGrouper.new rules, columns
grouped_tree = double(:grouped_tree)
subject.should_receive(:group_and_sort).with(rule1, rules[1..-1], @items).and_return(grouped_tree)
subject.build_tree(@items, rules).should == grouped_tree
end
it "should group, then sort, send each group to build_tree, and return a branch" do
rule1 = double(:rule1)
rule2 = double(:rule2)
rules = [rule1, rule2]
remaining_rules = [rule2]
column1 = double(:col1)
column2 = double(:col2)
columns = [column1, column2]
summary_columns_object = double(:summary_columns)
rule1.stub(:[]).with(:summary_columns) { summary_columns_object }
subject = OrderGrouper.new rules, columns
number_of_categories = 3
groups = double(:groups)
@items.should_receive(:group_by).and_return(groups)
sorted_groups = {}
1.upto(number_of_categories) { |i| sorted_groups[i] = double(:group, name: "Group "+ i.to_s ) }
groups.should_receive(:sort_by).and_return(sorted_groups)
group = { group1: 1, group2: 2, group3: 3 }
subject.should_receive(:build_tree).exactly(number_of_categories).times.and_return(group)
group_tree = {}
1.upto(number_of_categories) { |i| group_tree[i] = group }
1.upto(number_of_categories) { |i| group_tree[i][:summary_row] = summary_columns_object }
subject.group_and_sort(rule1, remaining_rules, @items).should == group_tree
end
end
context "building the table Array" do
it "should return columns when given an Array" do
rule1 = double(:rule1)
rule2 = double(:rule2)
rules = [rule1, rule2]
column1 = double(:col1)
column2 = double(:col2)
columns = [column1, column2]
column1.stub(:call) { "Column1" }
column2.stub(:call) { "Column2" }
item1 = double(:item1)
item2 = double(:item2)
item3 = double(:item3)
items1 = [item1, item2]
items2 = [item2, item3]
groups = { items1: items1, items2: items1 }
subject = OrderGrouper.new rules, columns
column1.should_receive(:call)
column2.should_receive(:call)
subject.build_table(items1).should == [["Column1", "Column2"]]
end
it "should return a row for each key-value pair when given a Hash" do
rule1 = double(:rule1)
rule2 = double(:rule2)
rules = [rule1, rule2]
column1 = double(:col1)
column2 = double(:col2)
columns = [column1, column2]
column1.stub(:call) { "Column1" }
column2.stub(:call) { "Column2" }
item1 = double(:item1)
item2 = double(:item2)
item3 = double(:item3)
items1 = [item1, item2]
items2 = [item2, item3]
items3 = [item3, item1]
groups = { items1: items1, items2: items2, items3: items3 }
subject = OrderGrouper.new rules, columns
#subject.should_receive(:build_table).exactly(2).times
expected_return = []
groups.length.times { expected_return << ["Column1", "Column2"] }
subject.build_table(groups).should == expected_return
end
it "should return an extra row when a :summary_row key appears in a given Hash" do
rule1 = double(:rule1)
rule2 = double(:rule2)
rules = [rule1, rule2]
column1 = double(:col1)
column2 = double(:col2)
columns = [column1, column2]
column1.stub(:call) { "Column1" }
column2.stub(:call) { "Column2" }
sumcol1 = double(:sumcol1)
sumcol2 = double(:sumcol2)
sumcols = [sumcol1, sumcol2]
sumcol1.stub(:call) { "SumColumn1" }
sumcol2.stub(:call) { "SumColumn2" }
item1 = double(:item1)
item2 = double(:item2)
item3 = double(:item3)
items1 = [item1, item2]
items2 = [item2, item3]
items3 = [item3, item1]
groups = { items1: items1, items2: items2, items3: items3, summary_row: { items: { items2: items2, items3: items3 }, columns: sumcols } }
subject = OrderGrouper.new rules, columns
expected_return = []
groups.each do |key, group|
if key == :summary_row
expected_return << ["SumColumn1", "SumColumn2"]
else
expected_return << ["Column1", "Column2"]
end
end
subject.build_table(groups).should == expected_return
end
end
end
end