mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-04 22:16:08 +00:00
Add first cut of LettuceShare report
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
require 'csv'
|
||||
require 'open_food_network/order_and_distributor_report'
|
||||
require 'open_food_network/products_and_inventory_report'
|
||||
require 'open_food_network/lettuce_share_report'
|
||||
require 'open_food_network/group_buy_report'
|
||||
require 'open_food_network/order_grouper'
|
||||
require 'open_food_network/customers_report'
|
||||
@@ -26,7 +27,8 @@ Spree::Admin::ReportsController.class_eval do
|
||||
],
|
||||
products_and_inventory: [
|
||||
['All products', :all_products],
|
||||
['Inventory (on hand)', :inventory]
|
||||
['Inventory (on hand)', :inventory],
|
||||
['LettuceShare', :lettuce_share]
|
||||
],
|
||||
customers: [
|
||||
["Mailing List", :mailing_list],
|
||||
@@ -212,7 +214,11 @@ 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
|
||||
if params[:report_type] != 'lettuce_share'
|
||||
@report = OpenFoodNetwork::ProductsAndInventoryReport.new spree_current_user, params
|
||||
else
|
||||
@report = OpenFoodNetwork::LettuceShareReport.new spree_current_user, params
|
||||
end
|
||||
render_report(@report.header, @report.table, params[:csv], "products_and_inventory_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
|
||||
68
lib/open_food_network/lettuce_share_report.rb
Normal file
68
lib/open_food_network/lettuce_share_report.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
require 'open_food_network/products_and_inventory_report_base'
|
||||
|
||||
module OpenFoodNetwork
|
||||
class LettuceShareReport < ProductsAndInventoryReportBase
|
||||
def header
|
||||
[
|
||||
"PRODUCT",
|
||||
"Description",
|
||||
"Qty",
|
||||
"Pack Size",
|
||||
"Unit",
|
||||
"Unit Price",
|
||||
"Total",
|
||||
"GST incl.",
|
||||
"Grower and growing method",
|
||||
'',
|
||||
''
|
||||
]
|
||||
end
|
||||
|
||||
def table
|
||||
variants.map do |variant|
|
||||
[
|
||||
variant.product.name,
|
||||
variant.full_name,
|
||||
'',
|
||||
OptionValueNamer.new(variant).value,
|
||||
OptionValueNamer.new(variant).unit,
|
||||
variant.price - gst(variant),
|
||||
variant.price,
|
||||
gst(variant),
|
||||
variant.product.supplier.name,
|
||||
certification(variant),
|
||||
variant.product.primary_taxon.name
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def gst(variant)
|
||||
tax_category = variant.product.tax_category
|
||||
if tax_category
|
||||
tax_rate = tax_category.tax_rates.first
|
||||
line_item = mock_line_item(variant, tax_category)
|
||||
tax_rate.calculator.compute line_item
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
|
||||
def mock_line_item(variant, tax_category)
|
||||
product = OpenStruct.new tax_category: tax_category
|
||||
line_item = Spree::LineItem.new quantity: 1
|
||||
line_item.define_singleton_method(:product) { variant.product }
|
||||
line_item.define_singleton_method(:price) { variant.price }
|
||||
line_item
|
||||
end
|
||||
|
||||
def certification(variant)
|
||||
variant.product.properties_including_inherited.map do |p|
|
||||
"#{p[:name]} (#{p[:value]})"
|
||||
end.join(', ')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -1,13 +1,7 @@
|
||||
require 'open_food_network/products_and_inventory_report_base'
|
||||
|
||||
module OpenFoodNetwork
|
||||
|
||||
class ProductsAndInventoryReport
|
||||
attr_reader :params
|
||||
|
||||
def initialize(user, params = {})
|
||||
@user = user
|
||||
@params = params
|
||||
end
|
||||
|
||||
class ProductsAndInventoryReport < ProductsAndInventoryReportBase
|
||||
def header
|
||||
[
|
||||
"Supplier",
|
||||
@@ -38,70 +32,5 @@ module OpenFoodNetwork
|
||||
end
|
||||
end
|
||||
|
||||
def permissions
|
||||
@permissions ||= OpenFoodNetwork::Permissions.new(@user)
|
||||
end
|
||||
|
||||
def visible_products
|
||||
@visible_products ||= permissions.visible_products
|
||||
end
|
||||
|
||||
def variants
|
||||
filter(child_variants)
|
||||
end
|
||||
|
||||
def child_variants
|
||||
Spree::Variant.
|
||||
where(is_master: false).
|
||||
joins(:product).
|
||||
merge(visible_products).
|
||||
order('spree_products.name')
|
||||
end
|
||||
|
||||
def filter(variants)
|
||||
# NOTE: Ordering matters.
|
||||
# filter_to_order_cycle and filter_to_distributor return arrays not relations
|
||||
filter_to_distributor filter_to_order_cycle filter_on_hand filter_to_supplier filter_not_deleted variants
|
||||
end
|
||||
|
||||
def filter_not_deleted(variants)
|
||||
variants.not_deleted
|
||||
end
|
||||
|
||||
def filter_on_hand(variants)
|
||||
if params[:report_type] == 'inventory'
|
||||
variants.where('spree_variants.count_on_hand > 0')
|
||||
else
|
||||
variants
|
||||
end
|
||||
end
|
||||
|
||||
def filter_to_supplier(variants)
|
||||
if params[:supplier_id].to_i > 0
|
||||
variants.where("spree_products.supplier_id = ?", params[:supplier_id])
|
||||
else
|
||||
variants
|
||||
end
|
||||
end
|
||||
|
||||
def filter_to_distributor(variants)
|
||||
if params[:distributor_id].to_i > 0
|
||||
distributor = Enterprise.find params[:distributor_id]
|
||||
variants.select do |v|
|
||||
Enterprise.distributing_product(v.product_id).include? distributor
|
||||
end
|
||||
else
|
||||
variants
|
||||
end
|
||||
end
|
||||
|
||||
def filter_to_order_cycle(variants)
|
||||
if params[:order_cycle_id].to_i > 0
|
||||
order_cycle = OrderCycle.find params[:order_cycle_id]
|
||||
variants.select { |v| order_cycle.variants.include? v }
|
||||
else
|
||||
variants
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
76
lib/open_food_network/products_and_inventory_report_base.rb
Normal file
76
lib/open_food_network/products_and_inventory_report_base.rb
Normal file
@@ -0,0 +1,76 @@
|
||||
module OpenFoodNetwork
|
||||
class ProductsAndInventoryReportBase
|
||||
attr_reader :params
|
||||
|
||||
def initialize(user, params = {})
|
||||
@user = user
|
||||
@params = params
|
||||
end
|
||||
|
||||
def permissions
|
||||
@permissions ||= OpenFoodNetwork::Permissions.new(@user)
|
||||
end
|
||||
|
||||
def visible_products
|
||||
@visible_products ||= permissions.visible_products
|
||||
end
|
||||
|
||||
def variants
|
||||
filter(child_variants)
|
||||
end
|
||||
|
||||
def child_variants
|
||||
Spree::Variant.
|
||||
where(is_master: false).
|
||||
joins(:product).
|
||||
merge(visible_products).
|
||||
order('spree_products.name')
|
||||
end
|
||||
|
||||
def filter(variants)
|
||||
# NOTE: Ordering matters.
|
||||
# filter_to_order_cycle and filter_to_distributor return arrays not relations
|
||||
filter_to_distributor filter_to_order_cycle filter_on_hand filter_to_supplier filter_not_deleted variants
|
||||
end
|
||||
|
||||
def filter_not_deleted(variants)
|
||||
variants.not_deleted
|
||||
end
|
||||
|
||||
def filter_on_hand(variants)
|
||||
if params[:report_type] == 'inventory'
|
||||
variants.where('spree_variants.count_on_hand > 0')
|
||||
else
|
||||
variants
|
||||
end
|
||||
end
|
||||
|
||||
def filter_to_supplier(variants)
|
||||
if params[:supplier_id].to_i > 0
|
||||
variants.where("spree_products.supplier_id = ?", params[:supplier_id])
|
||||
else
|
||||
variants
|
||||
end
|
||||
end
|
||||
|
||||
def filter_to_distributor(variants)
|
||||
if params[:distributor_id].to_i > 0
|
||||
distributor = Enterprise.find params[:distributor_id]
|
||||
variants.select do |v|
|
||||
Enterprise.distributing_product(v.product_id).include? distributor
|
||||
end
|
||||
else
|
||||
variants
|
||||
end
|
||||
end
|
||||
|
||||
def filter_to_order_cycle(variants)
|
||||
if params[:order_cycle_id].to_i > 0
|
||||
order_cycle = OrderCycle.find params[:order_cycle_id]
|
||||
variants.select { |v| order_cycle.variants.include? v }
|
||||
else
|
||||
variants
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -283,18 +283,27 @@ feature %q{
|
||||
end
|
||||
|
||||
describe "products and inventory report" do
|
||||
it "shows products and inventory report" do
|
||||
product1 = create(:simple_product, name: "Product Name", price: 100)
|
||||
variant1 = product1.variants.first
|
||||
variant2 = create(:variant, product: product1, price: 80.0)
|
||||
product2 = create(:simple_product, name: "Product 2", price: 99.0, variant_unit: 'weight', variant_unit_scale: 1, unit_value: '100')
|
||||
variant3 = product2.variants.first
|
||||
let(:supplier) { create(:supplier_enterprise, name: 'Supplier Name') }
|
||||
let(:taxon) { create(:taxon, name: 'Taxon Name') }
|
||||
let(:product1) { create(:simple_product, name: "Product Name", price: 100, supplier: supplier, primary_taxon: taxon) }
|
||||
let(:product2) { create(:simple_product, name: "Product 2", price: 99.0, variant_unit: 'weight', variant_unit_scale: 1, unit_value: '100', supplier: supplier, primary_taxon: taxon) }
|
||||
let(:variant1) { product1.variants.first }
|
||||
let(:variant2) { create(:variant, product: product1, price: 80.0) }
|
||||
let(:variant3) { product2.variants.first }
|
||||
|
||||
before do
|
||||
product1.set_property 'Organic', 'NASAA 12345'
|
||||
product2.set_property 'Organic', 'NASAA 12345'
|
||||
product1.taxons = [taxon]
|
||||
product2.taxons = [taxon]
|
||||
variant1.update_column(:count_on_hand, 10)
|
||||
variant2.update_column(:count_on_hand, 20)
|
||||
variant3.update_column(:count_on_hand, 9)
|
||||
variant1.option_values = [create(:option_value, :presentation => "Test")]
|
||||
variant2.option_values = [create(:option_value, :presentation => "Something")]
|
||||
end
|
||||
|
||||
it "shows products and inventory report" do
|
||||
login_to_admin_section
|
||||
click_link 'Reports'
|
||||
|
||||
@@ -303,15 +312,19 @@ feature %q{
|
||||
click_link 'Products & Inventory'
|
||||
page.should have_content "Supplier"
|
||||
|
||||
rows = find("table#listing_products").all("tr")
|
||||
table = rows.map { |r| r.all("th,td").map { |c| c.text.strip } }
|
||||
page.should have_table_row ["Supplier", "Producer Suburb", "Product", "Product Properties", "Taxons", "Variant Value", "Price", "Group Buy Unit Quantity", "Amount"]
|
||||
page.should have_table_row [product1.supplier.name, product1.supplier.address.city, "Product Name", product1.properties.map(&:presentation).join(", "), product1.primary_taxon.name, "Test", "100.0", product1.group_buy_unit_size.to_s, ""]
|
||||
page.should have_table_row [product1.supplier.name, product1.supplier.address.city, "Product Name", product1.properties.map(&:presentation).join(", "), product1.primary_taxon.name, "Something", "80.0", product1.group_buy_unit_size.to_s, ""]
|
||||
page.should have_table_row [product2.supplier.name, product1.supplier.address.city, "Product 2", product1.properties.map(&:presentation).join(", "), product2.primary_taxon.name, "100g", "99.0", product1.group_buy_unit_size.to_s, ""]
|
||||
end
|
||||
|
||||
table.sort.should == [
|
||||
["Supplier", "Producer Suburb", "Product", "Product Properties", "Taxons", "Variant Value", "Price", "Group Buy Unit Quantity", "Amount"],
|
||||
[product1.supplier.name, product1.supplier.address.city, "Product Name", product1.properties.join(", "), product1.primary_taxon.name, "Test", "100.0", product1.group_buy_unit_size.to_s, ""],
|
||||
[product1.supplier.name, product1.supplier.address.city, "Product Name", product1.properties.join(", "), product1.primary_taxon.name, "Something", "80.0", product1.group_buy_unit_size.to_s, ""],
|
||||
[product2.supplier.name, product1.supplier.address.city, "Product 2", product1.properties.join(", "), product2.primary_taxon.name, "100g", "99.0", product1.group_buy_unit_size.to_s, ""]
|
||||
].sort
|
||||
it "shows the LettuceShare report" do
|
||||
login_to_admin_section
|
||||
click_link 'Reports'
|
||||
click_link 'LettuceShare'
|
||||
|
||||
page.should have_table_row ['PRODUCT', 'Description', 'Qty', 'Pack Size', 'Unit', 'Unit Price', 'Total', 'GST incl.', 'Grower and growing method', '', '']
|
||||
page.should have_table_row ['Product 2', '100g', '', '100', 'g', '99.0', '99.0', '0', 'Supplier Name', 'Organic (NASAA 12345)', 'Taxon Name']
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user