Skip to content

Commit 9f84ab4

Browse files
committed
Fix inconsistent item headers in donation and purchase CSV exports
1 parent b8f7873 commit 9f84ab4

8 files changed

Lines changed: 50 additions & 61 deletions

File tree

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -856,4 +856,4 @@ DEPENDENCIES
856856
webmock (~> 3.26)
857857

858858
BUNDLED WITH
859-
2.7.1
859+
4.0.9

app/controllers/purchases_controller.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ def index
3333
respond_to do |format|
3434
format.html
3535
# format.csv { send_data Purchase.generate_csv(@purchases), filename: "Purchases-#{Time.zone.today}.csv" }
36+
# the fix made in export purchases depends on the use of the current organization
3637
format.csv do
37-
send_data Exports::ExportPurchasesCSVService.new(purchase_ids: @purchases.map(&:id)).generate_csv, filename: "Purchases-#{Time.zone.today}.csv"
38+
send_data Exports::ExportPurchasesCSVService.new(
39+
purchase_ids: @purchases.map(&:id),
40+
organization: current_organization
41+
).generate_csv, filename: "Purchases-#{Time.zone.today}.csv"
3842
end
3943
end
4044
end

app/services/exports/export_donations_csv_service.rb

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,11 @@ def base_headers
9595
base_table.keys
9696
end
9797

98+
#updated to use organization headers instead of just headers with a value when filtered
9899
def item_headers
99100
return @item_headers if @item_headers
100101

101-
item_names = Set.new
102-
103-
donations.each do |donation|
104-
donation.line_items.each do |line_item|
105-
item_names.add(line_item.item.name)
106-
end
107-
end
108-
109-
@item_headers = item_names.sort
102+
@item_headers = @organization.items.pluck(:name).sort_by(&:downcase)
110103

111104
@item_headers = @item_headers.flat_map { |header| [header, "#{header} In-Kind Value"] } if @organization.include_in_kind_values_in_exported_files
112105

app/services/exports/export_purchases_csv_service.rb

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Exports
22
class ExportPurchasesCSVService
3-
def initialize(purchase_ids:)
3+
def initialize(purchase_ids:, organization:)
4+
@organization = organization
45
# Use a where lookup so that I can eager load all the resources
56
# needed rather than depending on external code to do it for me.
67
# This makes this code more self contained and efficient!
@@ -101,18 +102,12 @@ def base_headers
101102
base_table.keys
102103
end
103104

105+
# updated to use organization headers instead of just headers with a value when filtered
106+
# more updates in purchases controller
104107
def item_headers
105108
return @item_headers if @item_headers
106109

107-
item_names = Set.new
108-
109-
purchases.each do |purchase|
110-
purchase.line_items.each do |line_item|
111-
item_names.add(line_item.item.name)
112-
end
113-
end
114-
115-
@item_headers = item_names.sort
110+
@item_headers = @organization.items.pluck(:name).sort_by(&:downcase)
116111
end
117112

118113
def build_row_data(purchase)

config/database.yml

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,27 @@
11
default: &default
22
adapter: postgresql
33
encoding: unicode
4-
host: <%= ENV.fetch("PG_HOST", 'localhost') %>
54
database: diaper_dev
6-
username: <%= ENV.fetch("PG_USERNAME", 'postgres') %>
7-
password: <%= ENV.fetch("PG_PASSWORD", nil) %>
5+
username: aleha
6+
password:
87
pool: 20
98
timeout: 5000
109

11-
development: &development
10+
development:
1211
<<: *default
13-
gssencmode: "disable"
14-
timeout: 5000
15-
16-
staging:
17-
<<: *default
18-
username: <%= ENV['POSTGRESQL_USERNAME'] %>
19-
password: <%= ENV['POSTGRESQL_PASSWORD'] %>
20-
database: <%= ENV['POSTGRESQL_DATABASE'] %>
21-
host: <%= ENV['POSTGRESQL_ADDRESS'] %>
12+
gssencmode: disable
2213

2314
test:
2415
<<: *default
2516
database: diaper_test
26-
timeout: 5000
2717

28-
# These env vars live in Cloud66 application settings. Don't change
29-
# the names of the vars we're looking for without ensuring you've
30-
# updated/duplicated the vars there!
31-
#
32-
# Solid Cache is only configured for production, where it uses
33-
# the primary database.
18+
staging:
19+
<<: *default
20+
3421
production:
3522
primary: &primary_production
3623
<<: *default
37-
adapter: postgresql
38-
encoding: unicode
39-
host: <%= ENV["DIAPER_DB_HOST"] %>
40-
pool: 20
41-
username: <%= ENV["DIAPER_DB_USERNAME"] %>
42-
password: <%= ENV["DIAPER_DB_PASSWORD"] %>
43-
database: <%= ENV["DIAPER_DB_DATABASE"] %>
44-
timeout: 5000
24+
database: diaper_production
4525
cache:
4626
<<: *primary_production
4727
migrations_paths: db/cache_migrate
48-

db/schema.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema[8.0].define(version: 2025_10_07_141240) do
13+
ActiveRecord::Schema[8.0].define(version: 2025_10_17_194543) do
1414
# These are extensions that must be enabled in order to support this database
1515
enable_extension "pg_catalog.plpgsql"
1616

spec/services/exports/export_donations_csv_service_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ def source_name(donation)
7171
CSV
7272
expect(subject).to eq(csv)
7373
end
74+
# new donations export regression test
75+
it "includes all organization item headers even when exported donations only use a subset of items" do
76+
unused_item = create(:item, name: "Z Unused Item", organization: organization)
77+
78+
csv_rows = CSV.parse(subject, headers: true)
79+
headers = csv_rows.headers
80+
81+
expect(headers).to include("A Item", "B Item", "C Item", "Dupe Item", "E Item", "Z Unused Item")
82+
end
7483
end
7584

7685
context 'while "Include in-kind value in donation and distribution exports?" is set to yes' do

spec/services/exports/export_purchases_csv_service_spec.rb

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
RSpec.describe Exports::ExportPurchasesCSVService do
22
describe "#generate_csv_data" do
3-
subject { described_class.new(purchase_ids: purchase_ids).generate_csv_data }
3+
let(:organization) { create(:organization) }
44
let(:purchase_ids) { purchases.map(&:id) }
5+
let(:storage_location) { create(:storage_location, organization: organization) }
6+
subject { described_class.new(purchase_ids: purchase_ids, organization: organization).generate_csv_data }
7+
58
let(:duplicate_item) do
6-
FactoryBot.create(
7-
:item, name: Faker::Appliance.unique.equipment
8-
)
9+
create(:item, name: Faker::Appliance.unique.equipment, organization: organization)
910
end
11+
1012
let(:items_lists) do
1113
[
1214
[
1315
[duplicate_item, 5],
1416
[
15-
FactoryBot.create(
16-
:item, name: Faker::Appliance.unique.equipment
17-
),
17+
FactoryBot.create(:item, name: Faker::Appliance.unique.equipment,
18+
organization: organization),
1819
7
1920
],
2021
[duplicate_item, 3]
@@ -35,9 +36,9 @@
3536
items_lists.each_with_index.map do |items, i|
3637
purchase = create(
3738
:purchase,
38-
vendor: create(
39-
:vendor, business_name: "Vendor Name #{i}"
40-
),
39+
organization: organization,
40+
storage_location: storage_location,
41+
vendor: create(:vendor, business_name: "Vendor Name #{i}", organization: organization),
4142
issued_at: start_time + i.days,
4243
comment: "This is the #{i}-th purchase in the test.",
4344
amount_spent_in_cents: i * 4 + 555,
@@ -114,5 +115,13 @@
114115
expect(subject[idx + 1]).to eq(row)
115116
end
116117
end
118+
# new purchase export regression test
119+
it "includes all organization item headers even when exported purchases only use a subset of items" do
120+
unused_item = create(:item, name: "Z Unused Item", organization: organization)
121+
122+
headers = subject[0]
123+
124+
expect(headers).to include("Z Unused Item")
125+
end
117126
end
118127
end

0 commit comments

Comments
 (0)