mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Report Refactor 3: Products & Inventory
This commit is contained in:
committed by
Jean-Baptiste Bellet
parent
71aca960ee
commit
b3e1ffe9e2
@@ -190,7 +190,7 @@ Layout/LineLength:
|
||||
- 'spec/lib/reports/order_grouper_spec.rb'
|
||||
- 'spec/lib/reports/orders_and_fulfillment/orders_and_fulfillment_report_spec.rb'
|
||||
- 'spec/lib/reports/packing/packing_report_spec.rb'
|
||||
- 'spec/lib/reports/products_and_inventory_default_report_spec.rb'
|
||||
- 'spec/lib/reports/products_and_inventory_report_spec.rb'
|
||||
- 'spec/lib/reports/users_and_enterprises_report_spec.rb'
|
||||
- 'spec/lib/reports/xero_invoices_report_spec.rb'
|
||||
- 'spec/lib/stripe/authorize_response_patcher_spec.rb'
|
||||
@@ -646,7 +646,7 @@ Metrics/ModuleLength:
|
||||
- 'spec/lib/reports/order_grouper_spec.rb'
|
||||
- 'spec/lib/reports/orders_and_fulfillment/customer_totals_report_spec.rb'
|
||||
- 'spec/lib/reports/orders_and_fulfillment/orders_and_fulfillment_report_spec.rb'
|
||||
- 'spec/lib/reports/products_and_inventory_default_report_spec.rb'
|
||||
- 'spec/lib/reports/products_and_inventory_report_spec.rb'
|
||||
- 'spec/lib/reports/users_and_enterprises_report_spec.rb'
|
||||
- 'spec/models/spree/adjustment_spec.rb'
|
||||
- 'spec/models/spree/credit_card_spec.rb'
|
||||
|
||||
13
lib/reporting/reports/products_and_inventory/all_products.rb
Normal file
13
lib/reporting/reports/products_and_inventory/all_products.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Reporting
|
||||
module Reports
|
||||
module ProductsAndInventory
|
||||
class AllProducts < Base
|
||||
def filter_on_hand(variants)
|
||||
variants # do not filter
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,37 +5,32 @@ require 'open_food_network/scope_variant_to_hub'
|
||||
module Reporting
|
||||
module Reports
|
||||
module ProductsAndInventory
|
||||
class ProductsAndInventoryReport < ReportObjectTemplate
|
||||
delegate :table_rows, :table_headers, :rules, :columns, :sku_for, to: :report
|
||||
|
||||
def report
|
||||
@report ||= report_klass.new(self)
|
||||
end
|
||||
|
||||
def report_type
|
||||
params[:report_subtype]
|
||||
end
|
||||
|
||||
def report_klass
|
||||
if report_type == 'lettuce_share'
|
||||
LettuceShareReport
|
||||
else
|
||||
ProductsAndInventoryDefaultReport
|
||||
end
|
||||
end
|
||||
|
||||
def permissions
|
||||
@permissions ||= OpenFoodNetwork::Permissions.new(@user)
|
||||
end
|
||||
|
||||
def visible_products
|
||||
@visible_products ||= permissions.visible_products
|
||||
end
|
||||
|
||||
def variants
|
||||
class Base < ReportObjectTemplate
|
||||
def query_result
|
||||
filter(child_variants)
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
def columns
|
||||
{
|
||||
supplier: proc { |variant| variant.product.supplier.name },
|
||||
producer_suburb: proc { |variant| variant.product.supplier.address.city },
|
||||
product: proc { |variant| variant.product.name },
|
||||
product_properties: proc { |v| v.product.properties.map(&:name).join(", ") },
|
||||
taxons: proc { |variant| variant.product.taxons.map(&:name).join(", ") },
|
||||
variant_value: proc { |variant| variant.full_name },
|
||||
price: proc { |variant| variant.price },
|
||||
group_buy_unit_quantity: proc { |variant| variant.product.group_buy_unit_size },
|
||||
amount: proc { |_variant| "" },
|
||||
sku: proc { |variant| variant.sku.presence || variant.product.sku },
|
||||
}
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
|
||||
def filter(variants)
|
||||
filter_on_hand filter_to_distributor filter_to_order_cycle filter_to_supplier variants
|
||||
end
|
||||
|
||||
def child_variants
|
||||
Spree::Variant.
|
||||
where(is_master: false).
|
||||
@@ -45,17 +40,23 @@ module Reporting
|
||||
order('spree_products.name')
|
||||
end
|
||||
|
||||
def filter(variants)
|
||||
filter_on_hand filter_to_distributor filter_to_order_cycle filter_to_supplier variants
|
||||
private
|
||||
|
||||
def report_type
|
||||
params[:report_subtype]
|
||||
end
|
||||
|
||||
def visible_products
|
||||
@visible_products ||= permissions.visible_products
|
||||
end
|
||||
|
||||
def permissions
|
||||
@permissions ||= OpenFoodNetwork::Permissions.new(@user)
|
||||
end
|
||||
|
||||
# Using the `in_stock?` method allows overrides by distributors.
|
||||
def filter_on_hand(variants)
|
||||
if report_type == 'inventory'
|
||||
variants.select(&:in_stock?)
|
||||
else
|
||||
variants
|
||||
end
|
||||
variants.select(&:in_stock?)
|
||||
end
|
||||
|
||||
def filter_to_supplier(variants)
|
||||
10
lib/reporting/reports/products_and_inventory/inventory.rb
Normal file
10
lib/reporting/reports/products_and_inventory/inventory.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Reporting
|
||||
module Reports
|
||||
module ProductsAndInventory
|
||||
class Inventory < Base
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,59 +1,39 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# require 'variant_units/option_value_namer'
|
||||
|
||||
module Reporting
|
||||
module Reports
|
||||
module ProductsAndInventory
|
||||
class LettuceShareReport
|
||||
attr_reader :context
|
||||
|
||||
delegate :variants, :render_table, to: :context
|
||||
|
||||
def initialize(context)
|
||||
@context = context
|
||||
end
|
||||
|
||||
def table_headers
|
||||
# NOTE: These are NOT to be translated, they need to be in this exact format to work with LettucShare
|
||||
[
|
||||
"PRODUCT",
|
||||
"Description",
|
||||
"Qty",
|
||||
"Pack Size",
|
||||
"Unit",
|
||||
"Unit Price",
|
||||
"Total",
|
||||
"GST incl.",
|
||||
"Grower and growing method",
|
||||
"Taxon"
|
||||
]
|
||||
end
|
||||
|
||||
def table_rows
|
||||
variants.select(&:in_stock?)
|
||||
.map do |variant|
|
||||
[
|
||||
variant.product.name,
|
||||
variant.full_name,
|
||||
'',
|
||||
VariantUnits::OptionValueNamer.new(variant).value,
|
||||
VariantUnits::OptionValueNamer.new(variant).unit,
|
||||
variant.price,
|
||||
'',
|
||||
gst(variant),
|
||||
grower_and_method(variant),
|
||||
variant.product.primary_taxon.name
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
def rules
|
||||
[]
|
||||
class LettuceShare < Base
|
||||
# NOTE: These are NOT to be translated, they need to be in this exact format
|
||||
# to work with LettucShare
|
||||
def custom_headers
|
||||
{
|
||||
product: "PRODUCT",
|
||||
description: "Description",
|
||||
quantity: "Qty",
|
||||
pack_size: "Pack Size",
|
||||
unit: "Unit",
|
||||
unit_price: "Unit Price",
|
||||
total: "Total",
|
||||
gst: "GST incl.",
|
||||
grower: "Grower and growing method",
|
||||
taxon: "Taxon"
|
||||
}
|
||||
end
|
||||
|
||||
def columns
|
||||
{}
|
||||
{
|
||||
product: proc { |variant| variant.product.name },
|
||||
description: proc { |variant| variant.full_name },
|
||||
quantity: proc { |_variant| '' },
|
||||
pack_size: proc { |variant| VariantUnits::OptionValueNamer.new(variant).value },
|
||||
unit: proc { |variant| VariantUnits::OptionValueNamer.new(variant).unit },
|
||||
unit_price: proc { |variant| variant.price },
|
||||
total: proc { |_variant| '' },
|
||||
gst: proc { |variant| gst(variant) },
|
||||
grower: proc { |variant| grower_and_method(variant) },
|
||||
taxon: proc { |variant| variant.product.primary_taxon.name }
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
@@ -1,63 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Reporting
|
||||
module Reports
|
||||
module ProductsAndInventory
|
||||
class ProductsAndInventoryDefaultReport
|
||||
attr_reader :context
|
||||
|
||||
delegate :variants, :render_table, to: :context
|
||||
|
||||
def initialize(context)
|
||||
@context = context
|
||||
end
|
||||
|
||||
def table_headers
|
||||
[
|
||||
I18n.t(:report_header_supplier),
|
||||
I18n.t(:report_header_producer_suburb),
|
||||
I18n.t(:report_header_product),
|
||||
I18n.t(:report_header_product_properties),
|
||||
I18n.t(:report_header_taxons),
|
||||
I18n.t(:report_header_variant_value),
|
||||
I18n.t(:report_header_price),
|
||||
I18n.t(:report_header_group_buy_unit_quantity),
|
||||
I18n.t(:report_header_amount),
|
||||
I18n.t(:report_header_sku)
|
||||
]
|
||||
end
|
||||
|
||||
def table_rows
|
||||
variants.map do |variant|
|
||||
[
|
||||
variant.product.supplier.name,
|
||||
variant.product.supplier.address.city,
|
||||
variant.product.name,
|
||||
variant.product.properties.map(&:name).join(", "),
|
||||
variant.product.taxons.map(&:name).join(", "),
|
||||
variant.full_name,
|
||||
variant.price,
|
||||
variant.product.group_buy_unit_size,
|
||||
"",
|
||||
sku_for(variant)
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
def rules
|
||||
[]
|
||||
end
|
||||
|
||||
def columns
|
||||
{}
|
||||
end
|
||||
|
||||
def sku_for(variant)
|
||||
return variant.sku if variant.sku.present?
|
||||
|
||||
variant.product.sku
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -246,7 +246,7 @@ describe Admin::ReportsController, type: :controller do
|
||||
end
|
||||
|
||||
it "creates a ProductAndInventoryReport" do
|
||||
allow(Reporting::Reports::ProductsAndInventory::ProductsAndInventoryReport).to receive(:new)
|
||||
allow(Reporting::Reports::ProductsAndInventory::Base).to receive(:new)
|
||||
.and_return(report = double(:report))
|
||||
allow(report).to receive(:table_headers).and_return []
|
||||
allow(report).to receive(:table_rows).and_return []
|
||||
|
||||
@@ -5,12 +5,9 @@ require 'spec_helper'
|
||||
module Reporting
|
||||
module Reports
|
||||
module ProductsAndInventory
|
||||
describe LettuceShareReport do
|
||||
describe LettuceShare do
|
||||
let(:user) { create(:user) }
|
||||
let(:base_report) {
|
||||
ProductsAndInventoryReport.new(user, { report_subtype: 'lettuce_share' })
|
||||
}
|
||||
let(:report) { base_report.report }
|
||||
let(:report) { LettuceShare.new(user) }
|
||||
let(:variant) { create(:variant) }
|
||||
|
||||
describe "grower and method" do
|
||||
@@ -54,18 +51,17 @@ module Reporting
|
||||
}
|
||||
|
||||
it "all items" do
|
||||
allow(base_report).to receive(:child_variants) {
|
||||
Spree::Variant.where(id: [variant, variant2, variant3])
|
||||
}
|
||||
allow(report).to receive(:child_variants) {
|
||||
Spree::Variant.where(id: [variant, variant2, variant3])
|
||||
}
|
||||
expect(report.table_rows.count).to eq 3
|
||||
end
|
||||
|
||||
it "only available items" do
|
||||
variant.on_hand = 0
|
||||
allow(base_report).to receive(:child_variants) {
|
||||
Spree::Variant.where(id: [variant, variant2, variant3,
|
||||
variant4])
|
||||
}
|
||||
allow(report).to receive(:child_variants) {
|
||||
Spree::Variant.where(id: [variant, variant2, variant3, variant4])
|
||||
}
|
||||
expect(report.table_rows.count).to eq 3
|
||||
end
|
||||
|
||||
@@ -75,10 +71,10 @@ module Reporting
|
||||
# create the overrides
|
||||
variant2_override
|
||||
variant3_override
|
||||
allow(base_report).to receive(:child_variants) {
|
||||
Spree::Variant.where(id: [variant, variant2, variant3])
|
||||
}
|
||||
allow(base_report).to receive(:params) {
|
||||
allow(report).to receive(:child_variants) {
|
||||
Spree::Variant.where(id: [variant, variant2, variant3])
|
||||
}
|
||||
allow(report).to receive(:params) {
|
||||
{ distributor_id: hub.id, report_subtype: 'lettuce_share' }
|
||||
}
|
||||
rows = report.table_rows
|
||||
|
||||
@@ -5,7 +5,7 @@ require 'spec_helper'
|
||||
module Reporting
|
||||
module Reports
|
||||
module ProductsAndInventory
|
||||
describe ProductsAndInventoryDefaultReport do
|
||||
describe Base do
|
||||
context "As a site admin" do
|
||||
let(:user) do
|
||||
user = create(:user)
|
||||
@@ -13,7 +13,7 @@ module Reporting
|
||||
user
|
||||
end
|
||||
subject do
|
||||
ProductsAndInventoryReport.new user, {}
|
||||
Base.new user, {}
|
||||
end
|
||||
|
||||
it "Should return headers" do
|
||||
@@ -48,7 +48,7 @@ module Reporting
|
||||
:taxons).and_return [double(name: "taxon1"),
|
||||
double(name: "taxon2")]
|
||||
allow(variant).to receive_message_chain(:product, :group_buy_unit_size).and_return(21)
|
||||
allow(subject).to receive(:variants).and_return [variant]
|
||||
allow(subject).to receive(:query_result).and_return [variant]
|
||||
|
||||
expect(subject.table_rows).to eq([[
|
||||
"Supplier",
|
||||
@@ -67,7 +67,7 @@ module Reporting
|
||||
it "fetches variants for some params" do
|
||||
expect(subject).to receive(:child_variants).and_return ["children"]
|
||||
expect(subject).to receive(:filter).with(['children']).and_return ["filter_children"]
|
||||
expect(subject.variants).to eq(["filter_children"])
|
||||
expect(subject.query_result).to eq(["filter_children"])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -82,7 +82,7 @@ module Reporting
|
||||
end
|
||||
|
||||
subject do
|
||||
ProductsAndInventoryReport.new enterprise_user, {}
|
||||
Base.new enterprise_user, {}
|
||||
end
|
||||
|
||||
describe "fetching child variants" do
|
||||
@@ -112,7 +112,7 @@ module Reporting
|
||||
product1 = create(:simple_product, supplier: supplier, on_hand: 99)
|
||||
product2 = create(:simple_product, supplier: supplier, on_hand: 0)
|
||||
|
||||
allow(subject).to receive(:params).and_return(report_subtype: 'inventory')
|
||||
subject = Inventory.new enterprise_user
|
||||
expect(subject.filter(variants)).to eq([product1.variants.first])
|
||||
end
|
||||
end
|
||||
@@ -225,17 +225,17 @@ module Reporting
|
||||
]
|
||||
)
|
||||
|
||||
subject = Inventory.new enterprise_user
|
||||
allow(subject).to receive(:params).and_return(
|
||||
order_cycle_id: order_cycle.id,
|
||||
supplier_id: supplier.id,
|
||||
distributor_id: distributor.id,
|
||||
report_subtype: 'inventory'
|
||||
distributor_id: distributor.id
|
||||
)
|
||||
|
||||
expect(subject.filter(variants)).to match_array [not_filtered_variant]
|
||||
|
||||
# And it integrates with the ordering of the `variants` method.
|
||||
expect(subject.variants).to match_array [not_filtered_variant]
|
||||
expect(subject.query_result).to match_array [not_filtered_variant]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -243,12 +243,15 @@ module Reporting
|
||||
let(:variant) { create(:variant) }
|
||||
let(:product) { variant.product }
|
||||
|
||||
before { product.update_attribute(:sku, "Product SKU") }
|
||||
before {
|
||||
product.update_attribute(:sku, "Product SKU")
|
||||
allow(subject).to receive(:query_result).and_return([variant])
|
||||
}
|
||||
|
||||
context "when the variant has an SKU set" do
|
||||
before { variant.update_attribute(:sku, "Variant SKU") }
|
||||
it "returns it" do
|
||||
expect(subject.__send__(:sku_for, variant)).to eq "Variant SKU"
|
||||
expect(subject.rows.first.sku).to eq "Variant SKU"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -256,7 +259,7 @@ module Reporting
|
||||
before { variant.update_attribute(:sku, "") }
|
||||
|
||||
it "returns the product's SKU" do
|
||||
expect(subject.__send__(:sku_for, variant)).to eq "Product SKU"
|
||||
expect(subject.rows.first.sku).to eq "Product SKU"
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user