Report Refactor 1: Products & Inventory

This commit is contained in:
Sebastian Castro
2022-03-25 07:12:07 +00:00
committed by Jean-Baptiste Bellet
parent 881a708ecf
commit 3d1b61ae6e
15 changed files with 466 additions and 455 deletions

View File

@@ -1139,7 +1139,7 @@ Style/OptionalBooleanParameter:
- 'lib/open_food_network/order_cycle_management_report.rb'
- 'lib/open_food_network/orders_and_fulfillment_report.rb'
- 'lib/open_food_network/payments_report.rb'
- 'lib/open_food_network/products_and_inventory_report_base.rb'
- 'lib/open_food_network/products_and_inventory_report.rb'
- 'lib/open_food_network/users_and_enterprises_report.rb'
- 'lib/open_food_network/xero_invoices_report.rb'
- 'lib/spree/core/controller_helpers/order.rb'

View File

@@ -86,21 +86,7 @@ module Spree
end
def products_and_inventory
@report_types = report_types[:products_and_inventory]
@report = if params[:report_type] != 'lettuce_share'
OpenFoodNetwork::ProductsAndInventoryReport.new spree_current_user,
raw_params,
render_content?
else
OpenFoodNetwork::LettuceShareReport.new spree_current_user,
raw_params,
render_content?
end
render_report @report.header,
@report.table,
params[:csv],
"products_and_inventory_#{timestamp}.csv"
render_report2
end
def users_and_enterprises

View File

@@ -1,4 +1,4 @@
%ul{style: "margin-left: 12pt"}
- report_types.each do |report_type|
%li
= link_to report_type[0], "#{products_and_inventory_admin_reports_url}?report_type=#{report_type[1]}"
= link_to report_type[0], "#{products_and_inventory_admin_reports_url}?report_subtype=#{report_type[1]}"

View File

@@ -0,0 +1,20 @@
.row
.alpha.two.columns= label_tag nil, t(:report_distributor)
.omega.fourteen.columns
= select_tag(:distributor_id,
options_from_collection_for_select(@distributors, :id, :name, params[:distributor_id]),
{:include_blank => true, :class => "select2 fullwidth light"})
.row
.alpha.two.columns= label_tag nil, t(:report_customers_supplier)
.omega.fourteen.columns
= select_tag(:supplier_id,
options_from_collection_for_select(@suppliers, :id, :name, params[:supplier_id]),
{:include_blank => true, :class => "select2 fullwidth light"})
.row
.alpha.two.columns= label_tag nil, t(:report_order_cycle)
.omega.fourteen.columns
= select_tag(:order_cycle_id,
options_for_select(report_order_cycle_options(@order_cycles), params[:order_cycle_id]),
{:include_blank => true, :class => "select2 fullwidth light"})

View File

@@ -1,34 +0,0 @@
= form_tag spree.products_and_inventory_admin_reports_url do |f|
%br
.row
.four.columns.alpha
= label_tag nil, t(:report_distributor)
= select_tag(:distributor_id,
options_from_collection_for_select(@distributors, :id, :name, params[:distributor_id]),
{:include_blank => true, :class => "select2 fullwidth"})
.four.columns
= label_tag nil, t(:report_customers_supplier)
= select_tag(:supplier_id,
options_from_collection_for_select(@suppliers, :id, :name, params[:supplier_id]),
{:include_blank => true, :class => "select2 fullwidth"})
.six.columns
= label_tag nil, t(:report_order_cycle)
= select_tag(:order_cycle_id,
options_for_select(report_order_cycle_options(@order_cycles), params[:order_cycle_id]),
{:include_blank => true, :class => "select2 fullwidth"})
= label_tag nil, t(:report_type)
%br
= select_tag(:report_type, options_for_select(@report_types, params[:report_type]))
%br
%br
= check_box_tag :csv
= label_tag :csv, t(:report_customers_csv)
%br
= button t(:go)
= render "table", id: "listing_products", msg_option: t(:go)

View File

@@ -1,11 +1,17 @@
# frozen_string_literal: true
require 'open_food_network/products_and_inventory_report_base'
require 'variant_units/option_value_namer'
module OpenFoodNetwork
class LettuceShareReport < ProductsAndInventoryReportBase
def header
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",
@@ -21,8 +27,8 @@ module OpenFoodNetwork
]
end
def table
return [] unless @render_table
def table_rows
return [] unless render_table
variants.select(&:in_stock?)
.map do |variant|

View File

@@ -0,0 +1,53 @@
# frozen_string_literal: true
module OpenFoodNetwork
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
return [] unless render_table
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 sku_for(variant)
return variant.sku if variant.sku.present?
variant.product.sku
end
end
end

View File

@@ -1,47 +1,100 @@
# frozen_string_literal: true
require 'open_food_network/products_and_inventory_report_base'
require 'open_food_network/scope_variant_to_hub'
require 'open_food_network/products_and_inventory_default_report'
require 'open_food_network/lettuce_share_report'
module OpenFoodNetwork
class ProductsAndInventoryReport < ProductsAndInventoryReportBase
def header
[
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)
]
class ProductsAndInventoryReport
attr_reader :params, :render_table
delegate :table_rows, :table_headers, :rules, :columns, :sku_for, to: :report
def initialize(user, params = {}, render_table = false)
@user = user
@params = params
@render_table = render_table
end
def table
return [] unless @render_table
def report
@report ||= report_klass.new(self)
end
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)
]
def report_type
params[:report_subtype]
end
def report_klass
if report_type == 'lettuce_share'
OpenFoodNetwork::LettuceShareReport
else
OpenFoodNetwork::ProductsAndInventoryDefaultReport
end
end
def sku_for(variant)
return variant.sku if variant.sku.present?
def permissions
@permissions ||= OpenFoodNetwork::Permissions.new(@user)
end
variant.product.sku
def visible_products
@visible_products ||= permissions.visible_products
end
def variants
filter(child_variants)
end
def child_variants
Spree::Variant.
where(is_master: false).
includes(option_values: :option_type).
joins(:product).
merge(visible_products).
order('spree_products.name')
end
def filter(variants)
filter_on_hand filter_to_distributor filter_to_order_cycle filter_to_supplier variants
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
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]
scoper = OpenFoodNetwork::ScopeVariantToHub.new(distributor)
variants.in_distributor(distributor).each { |v| scoper.scope(v) }
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]
variant_ids = Exchange.in_order_cycle(order_cycle).
joins("INNER JOIN exchange_variants ON exchanges.id = exchange_variants.exchange_id").
select("DISTINCT exchange_variants.variant_id")
variants.where("spree_variants.id IN (#{variant_ids.to_sql})")
else
variants
end
end
end
end

View File

@@ -1,80 +0,0 @@
# frozen_string_literal: true
require 'open_food_network/scope_variant_to_hub'
module OpenFoodNetwork
class ProductsAndInventoryReportBase
attr_reader :params
def initialize(user, params = {}, render_table = false)
@user = user
@params = params
@render_table = render_table
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).
includes(option_values: :option_type).
joins(:product).
merge(visible_products).
order('spree_products.name')
end
def filter(variants)
filter_on_hand filter_to_distributor filter_to_order_cycle filter_to_supplier variants
end
# Using the `in_stock?` method allows overrides by distributors.
def filter_on_hand(variants)
if params[:report_type] == 'inventory'
variants.select(&:in_stock?)
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]
scoper = OpenFoodNetwork::ScopeVariantToHub.new(distributor)
variants.in_distributor(distributor).each { |v| scoper.scope(v) }
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]
variant_ids = Exchange.in_order_cycle(order_cycle).
joins("INNER JOIN exchange_variants ON exchanges.id = exchange_variants.exchange_id").
select("DISTINCT exchange_variants.variant_id")
variants.where("spree_variants.id IN (#{variant_ids.to_sql})")
else
variants
end
end
end
end

View File

@@ -233,7 +233,7 @@ describe Spree::Admin::ReportsController, type: :controller do
it "assigns report types" do
spree_get :products_and_inventory
expect(assigns(:report_types)).to eq(subject.report_types[:products_and_inventory])
expect(assigns(:report_subtypes)).to eq(subject.report_types[:products_and_inventory])
end
it "creates a ProductAndInventoryReport" do
@@ -242,8 +242,8 @@ describe Spree::Admin::ReportsController, type: :controller do
{ "test" => "foo", "controller" => "spree/admin/reports", "report" => {},
"action" => "products_and_inventory", "use_route" => "main_app" }, false)
.and_return(report = double(:report))
allow(report).to receive(:header).and_return []
allow(report).to receive(:table).and_return []
allow(report).to receive(:table_headers).and_return []
allow(report).to receive(:table_rows).and_return []
spree_get :products_and_inventory, test: "foo"
expect(assigns(:report)).to eq(report)
end

View File

@@ -2,12 +2,15 @@
require 'spec_helper'
require 'open_food_network/lettuce_share_report'
require 'open_food_network/products_and_inventory_report'
module OpenFoodNetwork
describe LettuceShareReport do
let(:user) { create(:user) }
let(:report) { LettuceShareReport.new user, {}, true }
let(:base_report) {
ProductsAndInventoryReport.new(user, { report_subtype: 'lettuce_share' }, true)
}
let(:report) { base_report.report }
let(:variant) { create(:variant) }
describe "grower and method" do
@@ -34,7 +37,7 @@ module OpenFoodNetwork
describe "table" do
it "handles no items" do
expect(report.table).to eq []
expect(report.table_rows).to eq []
end
describe "lists" do
@@ -51,18 +54,18 @@ module OpenFoodNetwork
}
it "all items" do
allow(report).to receive(:child_variants) {
Spree::Variant.where(id: [variant, variant2, variant3])
}
expect(report.table.count).to eq 3
allow(base_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(report).to receive(:child_variants) {
Spree::Variant.where(id: [variant, variant2, variant3, variant4])
}
expect(report.table.count).to eq 3
allow(base_report).to receive(:child_variants) {
Spree::Variant.where(id: [variant, variant2, variant3, variant4])
}
expect(report.table_rows.count).to eq 3
end
it "only available items considering overrides" do
@@ -71,11 +74,13 @@ module OpenFoodNetwork
# create the overrides
variant2_override
variant3_override
allow(report).to receive(:child_variants) {
Spree::Variant.where(id: [variant, variant2, variant3])
}
allow(report).to receive(:params) { { distributor_id: hub.id } }
rows = report.table
allow(base_report).to receive(:child_variants) {
Spree::Variant.where(id: [variant, variant2, variant3])
}
allow(base_report).to receive(:params) {
{ distributor_id: hub.id, report_subtype: 'lettuce_share' }
}
rows = report.table_rows
expect(rows.count).to eq 2
expect(rows.map{ |row| row[0] }).to include variant.product.name, variant2.product.name
end

View File

@@ -0,0 +1,261 @@
# frozen_string_literal: true
require 'spec_helper'
require 'open_food_network/products_and_inventory_report'
describe OpenFoodNetwork::ProductsAndInventoryDefaultReport do
context "As a site admin" do
let(:user) do
user = create(:user)
user.spree_roles << Spree::Role.find_or_create_by!(name: 'admin')
user
end
subject do
OpenFoodNetwork::ProductsAndInventoryReport.new user, {}, true
end
it "Should return headers" do
expect(subject.table_headers).to eq([
"Supplier",
"Producer Suburb",
"Product",
"Product Properties",
"Taxons",
"Variant Value",
"Price",
"Group Buy Unit Quantity",
"Amount",
"SKU"
])
end
it "should build a table from a list of variants" do
variant = double(:variant, sku: "sku",
full_name: "Variant Name",
count_on_hand: 10,
price: 100)
allow(variant).to receive_message_chain(:product, :supplier, :name).and_return("Supplier")
allow(variant).to receive_message_chain(:product, :supplier, :address,
:city).and_return("A city")
allow(variant).to receive_message_chain(:product, :name).and_return("Product Name")
allow(variant).to receive_message_chain(:product,
:properties).and_return [double(name: "property1"),
double(name: "property2")]
allow(variant).to receive_message_chain(:product,
: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]
expect(subject.table_rows).to eq([[
"Supplier",
"A city",
"Product Name",
"property1, property2",
"taxon1, taxon2",
"Variant Name",
100,
21,
"",
"sku"
]])
end
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"])
end
end
context "As an enterprise user" do
let(:supplier) { create(:supplier_enterprise) }
let(:enterprise_user) do
user = create(:user)
user.enterprise_roles.create(enterprise: supplier)
user.spree_roles = []
user.save!
user
end
subject do
OpenFoodNetwork::ProductsAndInventoryReport.new enterprise_user, {}, true
end
describe "fetching child variants" do
it "returns some variants" do
product1 = create(:simple_product, supplier: supplier)
variant1 = product1.variants.first
variant2 = create(:variant, product: product1)
expect(subject.child_variants).to match_array [variant1, variant2]
end
it "should only return variants managed by the user" do
product1 = create(:simple_product, supplier: create(:supplier_enterprise))
product2 = create(:simple_product, supplier: supplier)
variant1 = product1.variants.first
variant2 = product2.variants.first
expect(subject.child_variants).to eq([variant2])
end
end
describe "Filtering variants" do
let(:variants) { Spree::Variant.where(nil).joins(:product).where(is_master: false) }
describe "based on report type" do
it "returns only variants on hand" do
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')
expect(subject.filter(variants)).to eq([product1.variants.first])
end
end
it "filters to a specific supplier" do
supplier2 = create(:supplier_enterprise)
product1 = create(:simple_product, supplier: supplier)
product2 = create(:simple_product, supplier: supplier2)
allow(subject).to receive(:params).and_return(supplier_id: supplier.id)
expect(subject.filter(variants)).to eq([product1.variants.first])
end
it "filters to a specific distributor" do
distributor = create(:distributor_enterprise)
product1 = create(:simple_product, supplier: supplier)
product2 = create(:simple_product, supplier: supplier)
order_cycle = create(:simple_order_cycle, suppliers: [supplier],
distributors: [distributor],
variants: [product2.variants.first])
allow(subject).to receive(:params).and_return(distributor_id: distributor.id)
expect(subject.filter(variants)).to eq([product2.variants.first])
end
it "ignores variant overrides without filter" do
distributor = create(:distributor_enterprise)
product = create(:simple_product, supplier: supplier, price: 5)
variant = product.variants.first
order_cycle = create(:simple_order_cycle, suppliers: [supplier],
distributors: [distributor],
variants: [product.variants.first])
create(:variant_override, hub: distributor, variant: variant, price: 2)
result = subject.filter(variants)
expect(result.first.price).to eq 5
end
it "considers variant overrides with distributor" do
distributor = create(:distributor_enterprise)
product = create(:simple_product, supplier: supplier, price: 5)
variant = product.variants.first
order_cycle = create(:simple_order_cycle, suppliers: [supplier],
distributors: [distributor],
variants: [product.variants.first])
create(:variant_override, hub: distributor, variant: variant, price: 2)
allow(subject).to receive(:params).and_return(distributor_id: distributor.id)
result = subject.filter(variants)
expect(result.first.price).to eq 2
end
it "filters to a specific order cycle" do
distributor = create(:distributor_enterprise)
product1 = create(:simple_product, supplier: supplier)
product2 = create(:simple_product, supplier: supplier)
order_cycle = create(:simple_order_cycle, suppliers: [supplier],
distributors: [distributor],
variants: [product1.variants.first])
allow(subject).to receive(:params).and_return(order_cycle_id: order_cycle.id)
expect(subject.filter(variants)).to eq([product1.variants.first])
end
it "should do all the filters at once" do
# The following data ensures that this spec fails if any of the
# filters fail. It's testing the filters are not impacting each other.
distributor = create(:distributor_enterprise)
other_distributor = create(:distributor_enterprise)
other_supplier = create(:supplier_enterprise)
not_filtered_variant = create(:simple_product, supplier: supplier).variants.first
variant_filtered_by_order_cycle = create(:simple_product,
supplier: supplier).variants.first
variant_filtered_by_distributor = create(:simple_product,
supplier: supplier).variants.first
variant_filtered_by_supplier = create(:simple_product,
supplier: other_supplier).variants.first
variant_filtered_by_stock = create(:simple_product, supplier: supplier,
on_hand: 0).variants.first
# This OC contains all products except the one that should be filtered
# by order cycle. We create a separate OC further down to proof that
# the product is passing all other filters.
order_cycle = create(
:simple_order_cycle,
suppliers: [supplier, other_supplier],
distributors: [distributor, other_distributor],
variants: [
not_filtered_variant,
variant_filtered_by_distributor,
variant_filtered_by_supplier,
variant_filtered_by_stock
]
)
# Remove the distribution of one product for one distributor but still
# sell it through the other distributor.
order_cycle.exchanges.outgoing.find_by(receiver_id: distributor.id).
exchange_variants.
find_by(variant_id: variant_filtered_by_distributor).
destroy
# Make product available to be filtered later. See OC comment above.
create(
:simple_order_cycle,
suppliers: [supplier],
distributors: [distributor, other_distributor],
variants: [
variant_filtered_by_order_cycle
]
)
allow(subject).to receive(:params).and_return(
order_cycle_id: order_cycle.id,
supplier_id: supplier.id,
distributor_id: distributor.id,
report_subtype: 'inventory'
)
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]
end
end
describe "fetching SKU for a variant" do
let(:variant) { create(:variant) }
let(:product) { variant.product }
before { product.update_attribute(:sku, "Product SKU") }
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"
end
end
context "when the variant has bo SKU set" do
before { variant.update_attribute(:sku, "") }
it "returns the product's SKU" do
expect(subject.__send__(:sku_for, variant)).to eq "Product SKU"
end
end
end
end
end

View File

@@ -1,259 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
require 'open_food_network/products_and_inventory_report'
module OpenFoodNetwork
describe ProductsAndInventoryReport do
context "As a site admin" do
let(:user) do
user = create(:user)
user.spree_roles << Spree::Role.find_or_create_by!(name: 'admin')
user
end
subject do
ProductsAndInventoryReport.new user, {}, true
end
it "Should return headers" do
expect(subject.header).to eq([
"Supplier",
"Producer Suburb",
"Product",
"Product Properties",
"Taxons",
"Variant Value",
"Price",
"Group Buy Unit Quantity",
"Amount",
"SKU"
])
end
it "should build a table from a list of variants" do
variant = double(:variant, sku: "sku",
full_name: "Variant Name",
count_on_hand: 10,
price: 100)
allow(variant).to receive_message_chain(:product, :supplier, :name).and_return("Supplier")
allow(variant).to receive_message_chain(:product, :supplier, :address,
:city).and_return("A city")
allow(variant).to receive_message_chain(:product, :name).and_return("Product Name")
allow(variant).to receive_message_chain(:product,
:properties).and_return [double(name: "property1"),
double(name: "property2")]
allow(variant).to receive_message_chain(:product,
: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]
expect(subject.table).to eq([[
"Supplier",
"A city",
"Product Name",
"property1, property2",
"taxon1, taxon2",
"Variant Name",
100,
21,
"",
"sku"
]])
end
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"])
end
end
context "As an enterprise user" do
let(:supplier) { create(:supplier_enterprise) }
let(:enterprise_user) do
user = create(:user)
user.enterprise_roles.create(enterprise: supplier)
user.spree_roles = []
user.save!
user
end
subject do
ProductsAndInventoryReport.new enterprise_user, {}, true
end
describe "fetching child variants" do
it "returns some variants" do
product1 = create(:simple_product, supplier: supplier)
variant1 = product1.variants.first
variant2 = create(:variant, product: product1)
expect(subject.child_variants).to match_array [variant1, variant2]
end
it "should only return variants managed by the user" do
product1 = create(:simple_product, supplier: create(:supplier_enterprise))
product2 = create(:simple_product, supplier: supplier)
variant1 = product1.variants.first
variant2 = product2.variants.first
expect(subject.child_variants).to eq([variant2])
end
end
describe "Filtering variants" do
let(:variants) { Spree::Variant.where(nil).joins(:product).where(is_master: false) }
describe "based on report type" do
it "returns only variants on hand" do
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_type: 'inventory')
expect(subject.filter(variants)).to eq([product1.variants.first])
end
end
it "filters to a specific supplier" do
supplier2 = create(:supplier_enterprise)
product1 = create(:simple_product, supplier: supplier)
product2 = create(:simple_product, supplier: supplier2)
allow(subject).to receive(:params).and_return(supplier_id: supplier.id)
expect(subject.filter(variants)).to eq([product1.variants.first])
end
it "filters to a specific distributor" do
distributor = create(:distributor_enterprise)
product1 = create(:simple_product, supplier: supplier)
product2 = create(:simple_product, supplier: supplier)
order_cycle = create(:simple_order_cycle, suppliers: [supplier],
distributors: [distributor], variants: [product2.variants.first])
allow(subject).to receive(:params).and_return(distributor_id: distributor.id)
expect(subject.filter(variants)).to eq([product2.variants.first])
end
it "ignores variant overrides without filter" do
distributor = create(:distributor_enterprise)
product = create(:simple_product, supplier: supplier, price: 5)
variant = product.variants.first
order_cycle = create(:simple_order_cycle, suppliers: [supplier],
distributors: [distributor], variants: [product.variants.first])
create(:variant_override, hub: distributor, variant: variant, price: 2)
result = subject.filter(variants)
expect(result.first.price).to eq 5
end
it "considers variant overrides with distributor" do
distributor = create(:distributor_enterprise)
product = create(:simple_product, supplier: supplier, price: 5)
variant = product.variants.first
order_cycle = create(:simple_order_cycle, suppliers: [supplier],
distributors: [distributor], variants: [product.variants.first])
create(:variant_override, hub: distributor, variant: variant, price: 2)
allow(subject).to receive(:params).and_return(distributor_id: distributor.id)
result = subject.filter(variants)
expect(result.first.price).to eq 2
end
it "filters to a specific order cycle" do
distributor = create(:distributor_enterprise)
product1 = create(:simple_product, supplier: supplier)
product2 = create(:simple_product, supplier: supplier)
order_cycle = create(:simple_order_cycle, suppliers: [supplier],
distributors: [distributor], variants: [product1.variants.first])
allow(subject).to receive(:params).and_return(order_cycle_id: order_cycle.id)
expect(subject.filter(variants)).to eq([product1.variants.first])
end
it "should do all the filters at once" do
# The following data ensures that this spec fails if any of the
# filters fail. It's testing the filters are not impacting each other.
distributor = create(:distributor_enterprise)
other_distributor = create(:distributor_enterprise)
other_supplier = create(:supplier_enterprise)
not_filtered_variant = create(:simple_product, supplier: supplier).variants.first
variant_filtered_by_order_cycle = create(:simple_product,
supplier: supplier).variants.first
variant_filtered_by_distributor = create(:simple_product,
supplier: supplier).variants.first
variant_filtered_by_supplier = create(:simple_product,
supplier: other_supplier).variants.first
variant_filtered_by_stock = create(:simple_product, supplier: supplier,
on_hand: 0).variants.first
# This OC contains all products except the one that should be filtered
# by order cycle. We create a separate OC further down to proof that
# the product is passing all other filters.
order_cycle = create(
:simple_order_cycle,
suppliers: [supplier, other_supplier],
distributors: [distributor, other_distributor],
variants: [
not_filtered_variant,
variant_filtered_by_distributor,
variant_filtered_by_supplier,
variant_filtered_by_stock
]
)
# Remove the distribution of one product for one distributor but still
# sell it through the other distributor.
order_cycle.exchanges.outgoing.find_by(receiver_id: distributor.id).
exchange_variants.
find_by(variant_id: variant_filtered_by_distributor).
destroy
# Make product available to be filtered later. See OC comment above.
create(
:simple_order_cycle,
suppliers: [supplier],
distributors: [distributor, other_distributor],
variants: [
variant_filtered_by_order_cycle
]
)
allow(subject).to receive(:params).and_return(
order_cycle_id: order_cycle.id,
supplier_id: supplier.id,
distributor_id: distributor.id,
report_type: 'inventory'
)
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]
end
end
describe "fetching SKU for a variant" do
let(:variant) { create(:variant) }
let(:product) { variant.product }
before { product.update_attribute(:sku, "Product SKU") }
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"
end
end
context "when the variant has bo SKU set" do
before { variant.update_attribute(:sku, "") }
it "returns the product's SKU" do
expect(subject.send(:sku_for, variant)).to eq "Product SKU"
end
end
end
end
end
end

View File

@@ -46,7 +46,7 @@ describe "Packing Reports", js: true do
click_link "Pack By Customer"
fill_in 'q_completed_at_gt', with: '2013-04-25 13:00:00'
fill_in 'q_completed_at_lt', with: '2013-04-25 16:00:00'
click_button 'Search'
click_button 'Go'
rows = find("table.report__table").all("thead tr")
table = rows.map { |r| r.all("th").map { |c| c.text.strip } }
@@ -59,7 +59,7 @@ describe "Packing Reports", js: true do
it "sorts alphabetically" do
click_link "Pack By Customer"
click_button 'Search'
click_button 'Go'
rows = find("table.report__table").all("tr")
table = rows.map { |r| r.all("th,td").map { |c| c.text.strip }[3] }
@@ -79,7 +79,7 @@ describe "Packing Reports", js: true do
click_link "Pack By Supplier"
fill_in 'q_completed_at_gt', with: '2013-04-25 13:00:00'
fill_in 'q_completed_at_lt', with: '2013-04-25 16:00:00'
click_button 'Search'
click_button 'Go'
rows = find("table.report__table").all("thead tr")
table = rows.map { |r| r.all("th").map { |c| c.text.strip } }

View File

@@ -94,7 +94,7 @@ describe '
it "orders and distributors report" do
login_as_admin_and_visit spree.admin_reports_path
click_link 'Orders And Distributors'
click_button 'Search'
click_button 'Go'
expect(page).to have_content 'ORDER DATE'
end
@@ -102,7 +102,7 @@ describe '
it "payments reports" do
login_as_admin_and_visit spree.admin_reports_path
click_link 'Payment Reports'
click_button 'Search'
click_button 'Go'
expect(page).to have_content 'PAYMENT STATE'
end
@@ -176,7 +176,7 @@ describe '
# When I filter to just one distributor
select user1.enterprises.first.name, from: 'q_distributor_id_eq'
click_button 'Search'
click_button 'Go'
# Then I should see the relevant order
expect(page).to have_content order1.number.to_s
@@ -243,7 +243,7 @@ describe '
pick_datetime "#q_completed_at_lt", datetime_end
select 'Order Cycle Customer Totals', from: 'report_subtype'
click_button 'Search'
click_button 'Go'
# Then I should see the rows for the first order but not the second
expect(all('table.report__table tbody tr').count).to eq(4) # Two rows per order
end