diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index cc43f5c524..6c6882e90f 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -161,7 +161,6 @@ Metrics/ModuleLength: - 'app/models/spree/order/checkout.rb' - 'app/models/spree/payment/processing.rb' - 'lib/open_food_network/column_preference_defaults.rb' - - 'spec/lib/reports/customers_report_spec.rb' - 'spec/lib/reports/enterprise_fee_summary/authorizer_spec.rb' - 'spec/lib/reports/order_cycle_management_report_spec.rb' - 'spec/lib/reports/products_and_inventory_report_spec.rb' diff --git a/spec/lib/reports/customers_report_spec.rb b/spec/lib/reports/customers_report_spec.rb index 9705260873..295dd53174 100644 --- a/spec/lib/reports/customers_report_spec.rb +++ b/spec/lib/reports/customers_report_spec.rb @@ -2,297 +2,291 @@ require 'spec_helper' -module Reporting - module Reports - module Customers - RSpec.describe Base do - context "as a site admin" do - let(:user) { create(:admin_user) } - subject { Base.new user, {} } +RSpec.describe Reporting::Reports::Customers::Base do + context "as a site admin" do + let(:user) { create(:admin_user) } + subject { described_class.new user, {} } - describe "addresses report" do - it "returns headers for addresses" do - expect(subject.table_headers).to eq(["First Name", "Last Name", "Billing Address", - "Email", "Phone", "Hub", "Hub Address", - "Shipping Method", "Total Number of Orders", - "Total incl. tax ($)", - "Last completed order date"]) - end + describe "addresses report" do + it "returns headers for addresses" do + expect(subject.table_headers).to eq(["First Name", "Last Name", "Billing Address", + "Email", "Phone", "Hub", "Hub Address", + "Shipping Method", "Total Number of Orders", + "Total incl. tax ($)", + "Last completed order date"]) + end - it "builds a table from a list of variants" do - a = create(:address) - d = create(:distributor_enterprise) - o = create(:order, distributor: d, bill_address: a) - o.shipments << create(:shipment) + it "builds a table from a list of variants" do + a = create(:address) + d = create(:distributor_enterprise) + o = create(:order, distributor: d, bill_address: a) + o.shipments << create(:shipment) - allow(subject).to receive(:query_result).and_return [[o]] - expect(subject.table_rows).to eq([[ - a.firstname, a.lastname, - [a.address1, a.address2, a.city].join(" "), - o.email, a.phone, d.name, - [d.address.address1, d.address.address2, - d.address.city].join(" "), - o.shipping_method.name, 1, o.total, "none" - ]]) - end + allow(subject).to receive(:query_result).and_return [[o]] + expect(subject.table_rows).to eq([[ + a.firstname, a.lastname, + [a.address1, a.address2, a.city].join(" "), + o.email, a.phone, d.name, + [d.address.address1, d.address.address2, + d.address.city].join(" "), + o.shipping_method.name, 1, o.total, "none" + ]]) + end - context "when there are multiple orders for the same customer" do - let!(:a) { create(:bill_address) } - let!(:d){ create(:distributor_enterprise) } - let!(:sm) { create(:shipping_method, distributors: [d]) } - let!(:customer) { create(:customer) } - let!(:o1) { - create(:order_with_totals_and_distribution, :completed, distributor: d, - bill_address: a, - shipping_method: sm, - customer:) - } - let!(:o2) { - create(:order_with_totals_and_distribution, :completed, distributor: d, - bill_address: a, - shipping_method: sm, - customer:) - } - before do - o1.update(completed_at: "2023-01-01") - o2.update(completed_at: "2023-01-02") - [o1, o2].each do |order| - order.update!(email: "test@test.com") - end - end - - it "returns only one row per customer with the right data" do - expect(subject.query_result).to match_array [[o1, o2]] - expect(subject.table_rows.size).to eq(1) - expect(subject.table_rows) - .to eq([[ - a.firstname, a.lastname, - [a.address1, a.address2, a.city].join(" "), - o1.email, a.phone, d.name, - [d.address.address1, d.address.address2, d.address.city].join(" "), - o1.shipping_method.name, 2, o1.total + o2.total, "2023-01-02" - ]]) - end - - context "orders from different hubs" do - let!(:d2) { create(:distributor_enterprise) } - let!(:sm2) { create(:shipping_method, distributors: [d2]) } - let!(:o2) { - create(:order_with_totals_and_distribution, :completed, distributor: d2, - bill_address: a, - shipping_method: sm2) - } - - it "returns one row per customer per hub" do - expect(subject.query_result.size).to eq(2) - expect(subject.table_rows.size).to eq(2) - expect(subject.table_rows) - .to eq([[ - a.firstname, a.lastname, - [a.address1, a.address2, a.city].join(" "), - o1.email, a.phone, d.name, - [d.address.address1, d.address.address2, d.address.city].join(" "), - o1.shipping_method.name, 1, o1.total, "2023-01-01" - ], [ - a.firstname, a.lastname, - [a.address1, a.address2, a.city].join(" "), - o2.email, a.phone, d2.name, - [d2.address.address1, d2.address.address2, d2.address.city].join(" "), - o2.shipping_method.name, 1, o2.total, "2023-01-02" - ]]) - end - end - - context "orders with different shipping methods" do - let!(:sm2) { create(:shipping_method, distributors: [d], name: "Bike") } - let!(:o2) { - create(:order_with_totals_and_distribution, :completed, distributor: d, - bill_address: a, - shipping_method: sm2) - } - before do - o2.select_shipping_method(sm2.id) - end - - context "when the shipping method column is being included" do - let(:fields_to_show) do - [:first_name, :last_name, :billing_address, :email, :phone, :hub, :hub_address, - :shipping_method, :total_orders, :total_incl_tax, :last_completed_order_date] - end - subject { Base.new(user, { fields_to_show: }) } - - it "returns one row per customer per shipping method" do - expect(subject.query_result.size).to eq(2) - expect(subject.table_rows.size).to eq(2) - expect(subject.table_rows).to eq( - [ - [ - a.firstname, - a.lastname, - [a.address1, a.address2, a.city].join(" "), - o1.email, - a.phone, - d.name, - [d.address.address1, d.address.address2, d.address.city].join(" "), - o1.shipping_method.name, 1, o1.total, o1.completed_at.strftime("%Y-%m-%d") - ], - [ - a.firstname, - a.lastname, - [a.address1, a.address2, a.city].join(" "), - o2.email, - a.phone, - d.name, - [d.address.address1, d.address.address2, d.address.city].join(" "), - sm2.name, 1, o2.total, o2.completed_at.strftime("%Y-%m-%d") - ] - ] - ) - end - end - - context "when the shipping method column is not included in the report" do - let(:fields_to_show) do - [:first_name, :last_name, :billing_address, :email, :phone, :hub, :hub_address] - end - subject { Base.new(user, { fields_to_show: }) } - - it "returns a single row for the customer, otherwise it would return two identical - rows" do - expect(subject.query_result.size).to eq(2) - expect(subject.table_rows.size).to eq(1) - expect(subject.table_rows).to eq( - [[ - a.firstname, - a.lastname, - [a.address1, a.address2, a.city].join(" "), - o1.email, - a.phone, - d.name, - [d.address.address1, d.address.address2, d.address.city].join(" ") - ]] - ) - end - end - end - end - end - - describe "fetching orders" do - it "fetches completed orders" do - o1 = create(:order) - o2 = create(:order, completed_at: 1.day.ago) - expect(subject.query_result).to eq([[o2]]) - end - - it "does not show cancelled orders" do - o1 = create(:order, state: "canceled", completed_at: 1.day.ago) - o2 = create(:order, completed_at: 1.day.ago) - expect(subject.query_result).to eq([[o2]]) - end + context "when there are multiple orders for the same customer" do + let!(:a) { create(:bill_address) } + let!(:d){ create(:distributor_enterprise) } + let!(:sm) { create(:shipping_method, distributors: [d]) } + let!(:customer) { create(:customer) } + let!(:o1) { + create(:order_with_totals_and_distribution, :completed, distributor: d, + bill_address: a, + shipping_method: sm, + customer:) + } + let!(:o2) { + create(:order_with_totals_and_distribution, :completed, distributor: d, + bill_address: a, + shipping_method: sm, + customer:) + } + before do + o1.update(completed_at: "2023-01-01") + o2.update(completed_at: "2023-01-02") + [o1, o2].each do |order| + order.update!(email: "test@test.com") end end - context "as an enterprise user" do - let(:user) { create(:user) } + it "returns only one row per customer with the right data" do + expect(subject.query_result).to match_array [[o1, o2]] + expect(subject.table_rows.size).to eq(1) + expect(subject.table_rows) + .to eq([[ + a.firstname, a.lastname, + [a.address1, a.address2, a.city].join(" "), + o1.email, a.phone, d.name, + [d.address.address1, d.address.address2, d.address.city].join(" "), + o1.shipping_method.name, 2, o1.total + o2.total, "2023-01-02" + ]]) + end - subject { Base.new user, {} } + context "orders from different hubs" do + let!(:d2) { create(:distributor_enterprise) } + let!(:sm2) { create(:shipping_method, distributors: [d2]) } + let!(:o2) { + create(:order_with_totals_and_distribution, :completed, distributor: d2, + bill_address: a, + shipping_method: sm2) + } - describe "fetching orders" do - let(:supplier) { create(:supplier_enterprise) } - let(:product) { create(:simple_product, supplier_id: supplier.id) } - let(:order) { create(:order, completed_at: 1.day.ago) } + it "returns one row per customer per hub" do + expect(subject.query_result.size).to eq(2) + expect(subject.table_rows.size).to eq(2) + expect(subject.table_rows) + .to eq([[ + a.firstname, a.lastname, + [a.address1, a.address2, a.city].join(" "), + o1.email, a.phone, d.name, + [d.address.address1, d.address.address2, d.address.city].join(" "), + o1.shipping_method.name, 1, o1.total, "2023-01-01" + ], [ + a.firstname, a.lastname, + [a.address1, a.address2, a.city].join(" "), + o2.email, a.phone, d2.name, + [d2.address.address1, d2.address.address2, d2.address.city].join(" "), + o2.shipping_method.name, 1, o2.total, "2023-01-02" + ]]) + end + end - it "only shows orders managed by the current user" do - d1 = create(:distributor_enterprise) - d1.enterprise_roles.build(user:).save - d2 = create(:distributor_enterprise) - d2.enterprise_roles.build(user: create(:user)).save + context "orders with different shipping methods" do + let!(:sm2) { create(:shipping_method, distributors: [d], name: "Bike") } + let!(:o2) { + create(:order_with_totals_and_distribution, :completed, distributor: d, + bill_address: a, + shipping_method: sm2) + } + before do + o2.select_shipping_method(sm2.id) + end - o1 = create(:order, distributor: d1, completed_at: 1.day.ago) - o2 = create(:order, distributor: d2, completed_at: 1.day.ago) - - expect(subject).to receive(:filter).with([o1]).and_return([o1]) - expect(subject.query_result).to eq([[o1]]) + context "when the shipping method column is being included" do + let(:fields_to_show) do + [:first_name, :last_name, :billing_address, :email, :phone, :hub, :hub_address, + :shipping_method, :total_orders, :total_incl_tax, :last_completed_order_date] end + subject { described_class.new(user, { fields_to_show: }) } - it "does not show orders through a hub that the current user does not manage" do - # Given a supplier enterprise with an order for one of its products - supplier.enterprise_roles.build(user:).save - order.line_items << create(:line_item_with_shipment, product:) - - # When I fetch orders, I should see no orders - expect(subject).to receive(:filter).with([]).and_return([]) - expect(subject.query_result).to eq([]) + it "returns one row per customer per shipping method" do + expect(subject.query_result.size).to eq(2) + expect(subject.table_rows.size).to eq(2) + expect(subject.table_rows).to eq( + [ + [ + a.firstname, + a.lastname, + [a.address1, a.address2, a.city].join(" "), + o1.email, + a.phone, + d.name, + [d.address.address1, d.address.address2, d.address.city].join(" "), + o1.shipping_method.name, 1, o1.total, o1.completed_at.strftime("%Y-%m-%d") + ], + [ + a.firstname, + a.lastname, + [a.address1, a.address2, a.city].join(" "), + o2.email, + a.phone, + d.name, + [d.address.address1, d.address.address2, d.address.city].join(" "), + sm2.name, 1, o2.total, o2.completed_at.strftime("%Y-%m-%d") + ] + ] + ) end end - describe "filtering orders" do - let(:orders) { Spree::Order.where(nil) } - let(:supplier) { create(:supplier_enterprise) } - - it "returns all orders sans-params" do - expect(subject.filter(orders)).to eq(orders) + context "when the shipping method column is not included in the report" do + let(:fields_to_show) do + [:first_name, :last_name, :billing_address, :email, :phone, :hub, :hub_address] end + subject { described_class.new(user, { fields_to_show: }) } - describe "filters to a specific completed_at date range" do - let!(:o1) { create(:order, completed_at: 1.day.ago) } - let!(:o2) { create(:order, completed_at: 3.days.ago) } - let!(:o3) { create(:order, completed_at: 5.days.ago) } - - it do - allow(subject).to receive(:params).and_return( - q: { - completed_at_gt: 1.day.before(o2.completed_at), - completed_at_lt: 1.day.after(o2.completed_at) - } - ) - expect(subject.filter(orders)).to eq([o2]) - end - - it "when completed_at_gt param is missing" do - allow(subject).to receive(:params).and_return( - q: { - completed_at_gt: "", - completed_at_lt: 1.day.after(o2.completed_at) - } - ) - expect(subject.filter(orders)).to match_array [o2, o3] - end - - it "when completed_at_lt param is missing" do - allow(subject).to receive(:params).and_return( - q: { - completed_at_gt: 1.day.before(o2.completed_at), - completed_at_lt: "" - } - ) - expect(subject.filter(orders)).to match_array [o1, o2] - end - end - - it "filters to a specific distributor" do - d1 = create(:distributor_enterprise) - d2 = create(:distributor_enterprise) - order1 = create(:order, distributor: d1) - order2 = create(:order, distributor: d2) - - allow(subject).to receive(:params).and_return(distributor_id: d1.id) - expect(subject.filter(orders)).to eq([order1]) - end - - it "filters to a specific cycle" do - oc1 = create(:simple_order_cycle) - oc2 = create(:simple_order_cycle) - order1 = create(:order, order_cycle: oc1) - order2 = create(:order, order_cycle: oc2) - - allow(subject).to receive(:params).and_return(order_cycle_id: oc1.id) - expect(subject.filter(orders)).to eq([order1]) + it "returns a single row for the customer, otherwise it would return two identical + rows" do + expect(subject.query_result.size).to eq(2) + expect(subject.table_rows.size).to eq(1) + expect(subject.table_rows).to eq( + [[ + a.firstname, + a.lastname, + [a.address1, a.address2, a.city].join(" "), + o1.email, + a.phone, + d.name, + [d.address.address1, d.address.address2, d.address.city].join(" ") + ]] + ) end end end end end + + describe "fetching orders" do + it "fetches completed orders" do + o1 = create(:order) + o2 = create(:order, completed_at: 1.day.ago) + expect(subject.query_result).to eq([[o2]]) + end + + it "does not show cancelled orders" do + o1 = create(:order, state: "canceled", completed_at: 1.day.ago) + o2 = create(:order, completed_at: 1.day.ago) + expect(subject.query_result).to eq([[o2]]) + end + end + end + + context "as an enterprise user" do + let(:user) { create(:user) } + + subject { described_class.new user, {} } + + describe "fetching orders" do + let(:supplier) { create(:supplier_enterprise) } + let(:product) { create(:simple_product, supplier_id: supplier.id) } + let(:order) { create(:order, completed_at: 1.day.ago) } + + it "only shows orders managed by the current user" do + d1 = create(:distributor_enterprise) + d1.enterprise_roles.build(user:).save + d2 = create(:distributor_enterprise) + d2.enterprise_roles.build(user: create(:user)).save + + o1 = create(:order, distributor: d1, completed_at: 1.day.ago) + o2 = create(:order, distributor: d2, completed_at: 1.day.ago) + + expect(subject).to receive(:filter).with([o1]).and_return([o1]) + expect(subject.query_result).to eq([[o1]]) + end + + it "does not show orders through a hub that the current user does not manage" do + # Given a supplier enterprise with an order for one of its products + supplier.enterprise_roles.build(user:).save + order.line_items << create(:line_item_with_shipment, product:) + + # When I fetch orders, I should see no orders + expect(subject).to receive(:filter).with([]).and_return([]) + expect(subject.query_result).to eq([]) + end + end + + describe "filtering orders" do + let(:orders) { Spree::Order.where(nil) } + let(:supplier) { create(:supplier_enterprise) } + + it "returns all orders sans-params" do + expect(subject.filter(orders)).to eq(orders) + end + + describe "filters to a specific completed_at date range" do + let!(:o1) { create(:order, completed_at: 1.day.ago) } + let!(:o2) { create(:order, completed_at: 3.days.ago) } + let!(:o3) { create(:order, completed_at: 5.days.ago) } + + it do + allow(subject).to receive(:params).and_return( + q: { + completed_at_gt: 1.day.before(o2.completed_at), + completed_at_lt: 1.day.after(o2.completed_at) + } + ) + expect(subject.filter(orders)).to eq([o2]) + end + + it "when completed_at_gt param is missing" do + allow(subject).to receive(:params).and_return( + q: { + completed_at_gt: "", + completed_at_lt: 1.day.after(o2.completed_at) + } + ) + expect(subject.filter(orders)).to match_array [o2, o3] + end + + it "when completed_at_lt param is missing" do + allow(subject).to receive(:params).and_return( + q: { + completed_at_gt: 1.day.before(o2.completed_at), + completed_at_lt: "" + } + ) + expect(subject.filter(orders)).to match_array [o1, o2] + end + end + + it "filters to a specific distributor" do + d1 = create(:distributor_enterprise) + d2 = create(:distributor_enterprise) + order1 = create(:order, distributor: d1) + order2 = create(:order, distributor: d2) + + allow(subject).to receive(:params).and_return(distributor_id: d1.id) + expect(subject.filter(orders)).to eq([order1]) + end + + it "filters to a specific cycle" do + oc1 = create(:simple_order_cycle) + oc2 = create(:simple_order_cycle) + order1 = create(:order, order_cycle: oc1) + order2 = create(:order, order_cycle: oc2) + + allow(subject).to receive(:params).and_return(order_cycle_id: oc1.id) + expect(subject.filter(orders)).to eq([order1]) + end + end end end