diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index d5453f774f..d7db956e20 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -87,7 +87,7 @@ Spree::Admin::ReportsController.class_eval do @search = Spree::Order.complete.managed_by(spree_current_user).search(params[:q]) orders = @search.result - line_items = orders.map { |o| o.line_items }.flatten + @line_items = orders.map { |o| o.line_items.managed_by(spree_current_user) }.flatten @distributors = Enterprise.is_distributor.managed_by(spree_current_user) @report_type = params[:report_type] @@ -217,7 +217,7 @@ Spree::Admin::ReportsController.class_eval do order_grouper = OpenFoodWeb::OrderGrouper.new rules, columns @header = header - @table = order_grouper.table(line_items) + @table = order_grouper.table(@line_items) csv_file_name = "bulk_coop.csv" render_report(@header, @table, params[:csv], csv_file_name) @@ -343,9 +343,9 @@ Spree::Admin::ReportsController.class_eval do @search = Spree::Order.complete.managed_by(spree_current_user).search(params[:q]) orders = @search.result - line_items = orders.map { |o| o.line_items }.flatten + @line_items = orders.map { |o| o.line_items.managed_by(spree_current_user) }.flatten #payments = orders.map { |o| o.payments.select { |payment| payment.completed? } }.flatten # Only select completed payments - + @distributors = Enterprise.is_distributor.managed_by(spree_current_user) #@suppliers = Enterprise.is_primary_producer @order_cycles = OrderCycle.active_or_complete.order('orders_close_at DESC') @@ -353,7 +353,7 @@ Spree::Admin::ReportsController.class_eval do case params[:report_type] when "order_cycle_supplier_totals" - table_items = line_items + table_items = @line_items @include_blank = 'All' header = ["Supplier", "Product", "Variant", "Amount", "Cost per Unit", "Total Cost", "Status", "Incoming Transport"] @@ -375,7 +375,7 @@ Spree::Admin::ReportsController.class_eval do sort_by: proc { |variant| variant.options_text } } ] when "order_cycle_supplier_totals_by_distributor" - table_items = line_items + table_items = @line_items @include_blank = 'All' header = ["Supplier", "Product", "Variant", "To Distributor", "Amount", "Cost per Unit", "Total Cost", "Shipping Method"] @@ -407,7 +407,7 @@ Spree::Admin::ReportsController.class_eval do sort_by: proc { |distributor| distributor.name } } ] when "order_cycle_distributor_totals_by_supplier" - table_items = line_items + table_items = @line_items @include_blank = 'All' header = ["Distributor", "Supplier", "Product", "Variant", "Amount", "Cost per Unit", "Total Cost", "Total Shipping Cost", "Shipping Method"] @@ -441,7 +441,7 @@ Spree::Admin::ReportsController.class_eval do sort_by: proc { |variant| variant.options_text } } ] when "order_cycle_customer_totals" - table_items = line_items + table_items = @line_items @include_blank = 'All' header = ["Distributor", "Customer", "Email", "Phone", "Product", "Variant", "Amount", "Item ($)", "Ship ($)", "Total ($)", "Paid?", "Packed?", "Shipped?"] @@ -483,7 +483,7 @@ Spree::Admin::ReportsController.class_eval do sort_by: proc { |variant| variant.options_text } } ] else - table_items = line_items + table_items = @line_items @include_blank = 'All' header = ["Supplier", "Product", "Variant", "Amount", "Cost per Unit", "Total Cost", "Status", "Incoming Transport"] diff --git a/app/models/spree/line_item_decorator.rb b/app/models/spree/line_item_decorator.rb index 3b7ee891b8..21715e468f 100644 --- a/app/models/spree/line_item_decorator.rb +++ b/app/models/spree/line_item_decorator.rb @@ -1,3 +1,17 @@ Spree::LineItem.class_eval do attr_accessible :max_quantity + + # -- Scopes + scope :managed_by, lambda { |user| + if user.has_spree_role?('admin') + scoped + else + # User has a distributor on the Order or supplier that supplies a LineItem + joins('LEFT OUTER JOIN spree_variants ON (spree_variants.id = spree_line_items.variant_id)'). + joins('LEFT OUTER JOIN spree_products ON (spree_products.id = spree_variants.product_id)'). + joins(:order). + where('spree_orders.distributor_id IN (?) OR spree_products.supplier_id IN (?)', user.enterprises, user.enterprises). + select('spree_line_items.*') + end + } end diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb index 5c28f5f510..8864860bf4 100644 --- a/app/models/spree/order_decorator.rb +++ b/app/models/spree/order_decorator.rb @@ -20,7 +20,13 @@ Spree::Order.class_eval do if user.has_spree_role?('admin') scoped else - where('distributor_id IN (?)', user.enterprises) + # User has a distributor on an Order or supplier that supplies a Product to an Order + # NOTE: supplier Orders should use LineItem.managed_by to ensure they only see their own LineItems! + joins('LEFT OUTER JOIN spree_line_items ON (spree_line_items.order_id = spree_orders.id)'). + joins('LEFT OUTER JOIN spree_variants ON (spree_variants.id = spree_line_items.variant_id)'). + joins('LEFT OUTER JOIN spree_products ON (spree_products.id = spree_variants.product_id)'). + where('spree_orders.distributor_id IN (?) OR spree_products.supplier_id IN (?)', user.enterprises, user.enterprises). + select('DISTINCT spree_orders.*') end } diff --git a/spec/controllers/spree/admin/reports_controller_spec.rb b/spec/controllers/spree/admin/reports_controller_spec.rb index 0705e8fa55..9446524873 100644 --- a/spec/controllers/spree/admin/reports_controller_spec.rb +++ b/spec/controllers/spree/admin/reports_controller_spec.rb @@ -2,26 +2,33 @@ require 'spec_helper' describe Spree::Admin::ReportsController do - # Given two distributors + # Given two distributors and two suppliers let(:ba) { create(:address) } - let(:da) { create(:address, :address1 => "distributor address", :city => 'The Shire', :zipcode => "1234") } let(:si) { "pick up on thursday please" } - let(:d1) { create(:distributor_enterprise, address: da) } - let(:d2) { create(:distributor_enterprise, address: da) } - let(:p1) { create(:product, price: 12.34, distributors: [d1]) } - let(:p2) { create(:product, price: 23.45, distributors: [d2]) } + let(:s1) { create(:supplier_enterprise, address: create(:address)) } + let(:s2) { create(:supplier_enterprise, address: create(:address)) } + let(:s3) { create(:supplier_enterprise, address: create(:address)) } + let(:d1) { create(:distributor_enterprise, address: create(:address)) } + let(:d2) { create(:distributor_enterprise, address: create(:address)) } + let(:d3) { create(:distributor_enterprise, address: create(:address)) } + let(:p1) { create(:product, price: 12.34, distributors: [d1], supplier: s1) } + let(:p2) { create(:product, price: 23.45, distributors: [d2], supplier: s2) } + let(:p3) { create(:product, price: 34.56, distributors: [d3], supplier: s3) } # Given two order cycles with both distributors - let(:ocA) { create(:order_cycle, distributors: [d1, d2], variants:[p1.master]) } - let(:ocB) { create(:order_cycle, distributors: [d1, d2], variants: [p2.master]) } + let(:ocA) { create(:simple_order_cycle, distributors: [d1, d2], suppliers: [s1, s2, s3], variants: [p1.master, p3.master]) } + let(:ocB) { create(:simple_order_cycle, distributors: [d1, d2], suppliers: [s1, s2, s3], variants: [p2.master]) } + # orderA1 can only be accessed by s1, s3 and d1 let!(:orderA1) do order = create(:order, distributor: d1, bill_address: ba, special_instructions: si, order_cycle: ocA) order.line_items << create(:line_item, variant: p1.master) + order.line_items << create(:line_item, variant: p3.master) order.finalize! order.save order end + # orderA2 can only be accessed by s2 and d2 let!(:orderA2) do order = create(:order, distributor: d2, bill_address: ba, special_instructions: si, order_cycle: ocA) order.line_items << create(:line_item, variant: p2.master) @@ -29,13 +36,16 @@ describe Spree::Admin::ReportsController do order.save order end + # orderB1 can only be accessed by s1, s3 and d1 let!(:orderB1) do order = create(:order, distributor: d1, bill_address: ba, special_instructions: si, order_cycle: ocB) order.line_items << create(:line_item, variant: p1.master) + order.line_items << create(:line_item, variant: p3.master) order.finalize! order.save order end + # orderB2 can only be accessed by s2 and d2 let!(:orderB2) do order = create(:order, distributor: d2, bill_address: ba, special_instructions: si, order_cycle: ocB) order.line_items << create(:line_item, variant: p2.master) @@ -44,72 +54,115 @@ describe Spree::Admin::ReportsController do order end - # Given Distributor Enterprise user for d1 - let(:user) do - user = create(:user) - user.spree_roles = [] - d1.enterprise_roles.build(user: user).save - user - end + # As a Distributor Enterprise user for d1 + context "Distributor Enterprise User" do + let(:user) do + user = create(:user) + user.spree_roles = [] + d1.enterprise_roles.build(user: user).save + user + end - before :each do - controller.stub :spree_current_user => user - end + before :each do + controller.stub :spree_current_user => user + end - describe 'Orders and Distributors' do - it "only shows orders that I have access to" do - spree_get :orders_and_distributors - - assigns(:search).result.should include(orderA1, orderB1) - assigns(:search).result.should_not include(orderA2) - assigns(:search).result.should_not include(orderB2) + describe 'Orders and Distributors' do + it "only shows orders that I have access to" do + spree_get :orders_and_distributors + + assigns(:search).result.should include(orderA1, orderB1) + assigns(:search).result.should_not include(orderA2) + assigns(:search).result.should_not include(orderB2) + end + end + + describe 'Group Buys' do + it "only shows orders that I have access to" do + spree_get :group_buys + + assigns(:search).result.should include(orderA1, orderB1) + assigns(:search).result.should_not include(orderA2) + assigns(:search).result.should_not include(orderB2) + end + end + + describe 'Bulk Coop' do + it "only shows orders that I have access to" do + spree_get :bulk_coop + + assigns(:search).result.should include(orderA1, orderB1) + assigns(:search).result.should_not include(orderA2) + assigns(:search).result.should_not include(orderB2) + end + end + + describe 'Payments' do + it "only shows orders that I have access to" do + spree_get :payments + + assigns(:search).result.should include(orderA1, orderB1) + assigns(:search).result.should_not include(orderA2) + assigns(:search).result.should_not include(orderB2) + end + end + + describe 'Order Cycles' do + it "only shows orders that I have access to" do + spree_get :order_cycles + + assigns(:search).result.should include(orderA1, orderB1) + assigns(:search).result.should_not include(orderA2) + assigns(:search).result.should_not include(orderB2) + end + + it "only shows the selected order cycle" do + spree_get :order_cycles, q: {order_cycle_id_eq: ocA.id} + + assigns(:search).result.should include(orderA1) + assigns(:search).result.should_not include(orderB1) + end end end - describe 'Group Buys' do - it "only shows orders that I have access to" do - spree_get :group_buys - - assigns(:search).result.should include(orderA1, orderB1) - assigns(:search).result.should_not include(orderA2) - assigns(:search).result.should_not include(orderB2) - end - end - - describe 'Bulk Coop' do - it "only shows orders that I have access to" do - spree_get :bulk_coop - - assigns(:search).result.should include(orderA1, orderB1) - assigns(:search).result.should_not include(orderA2) - assigns(:search).result.should_not include(orderB2) - end - end - - describe 'Payments' do - it "only shows orders that I have access to" do - spree_get :payments - - assigns(:search).result.should include(orderA1, orderB1) - assigns(:search).result.should_not include(orderA2) - assigns(:search).result.should_not include(orderB2) - end - end - - describe 'Order Cycles' do - it "only shows orders that I have access to" do - spree_get :order_cycles - - assigns(:search).result.should include(orderA1, orderB1) - assigns(:search).result.should_not include(orderA2) - assigns(:search).result.should_not include(orderB2) + # As a Supplier Enterprise user for s1 + context "Supplier" do + let(:user) do + user = create(:user) + user.spree_roles = [] + s1.enterprise_roles.build(user: user).save + user end - it "only shows the selected order cycle" do - spree_get :order_cycles, q: {order_cycle_id_eq: ocA.id} + before :each do + controller.stub :spree_current_user => user + end - assigns(:search).result.should include(orderA1) - assigns(:search).result.should_not include(orderB1) + describe 'Bulk Coop' do + it "only shows product line items that I am supplying" do + spree_get :bulk_coop + + assigns(:line_items).map(&:product).should include(p1) + assigns(:line_items).map(&:product).should_not include(p2) + assigns(:line_items).map(&:product).should_not include(p3) + end + end + + describe 'Order Cycles' do + it "only shows product line items that I am supplying" do + spree_get :order_cycles + + assigns(:line_items).map(&:product).should include(p1) + assigns(:line_items).map(&:product).should_not include(p2) + assigns(:line_items).map(&:product).should_not include(p3) + end + + it "only shows the selected order cycle" do + spree_get :order_cycles, q: {order_cycle_id_eq: ocA.id} + + assigns(:search).result.should include(orderA1) + assigns(:search).result.should_not include(orderB1) + end end end end