Files
openfoodnetwork/spec/lib/reports/customers_report_spec.rb
2025-06-17 13:48:22 +02:00

293 lines
12 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
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
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
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 { described_class.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 { described_class.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
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