Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 9 additions & 20 deletions app/services/exports/export_donations_csv_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ def initialize(donation_ids:, organization:)
).order(created_at: :asc)

@organization = organization
item_header_names = @organization.items.select("DISTINCT ON (LOWER(name)) items.name").order("LOWER(name) ASC").map(&:name)

@item_headers = if @organization.include_in_kind_values_in_exported_files
Comment thread
awwaiid marked this conversation as resolved.
item_header_names.flat_map { |header| [header, "#{header} In-Kind Value"] }
else
item_header_names
end
end

def generate_csv
Expand Down Expand Up @@ -42,7 +49,7 @@ def generate_csv_data

def headers
# Build the headers in the correct order
base_headers + item_headers
base_headers + @item_headers
end

# Returns a Hash of keys to indexes so that obtaining the index
Expand Down Expand Up @@ -95,24 +102,6 @@ def base_headers
base_table.keys
end

def item_headers
return @item_headers if @item_headers

item_names = Set.new

donations.each do |donation|
donation.line_items.each do |line_item|
item_names.add(line_item.item.name)
end
end

@item_headers = item_names.sort

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

@item_headers
end

def build_row_data(donation)
row = base_table.values.map { |closure| closure.call(donation) }
row += make_item_quantity_and_value_slots
Expand All @@ -128,7 +117,7 @@ def build_row_data(donation)
end

def make_item_quantity_and_value_slots
slots = Array.new(item_headers.size, 0)
slots = Array.new(@item_headers.size, 0)
slots = slots.map.with_index { |value, index| index.odd? ? Money.new(0) : value } if @organization.include_in_kind_values_in_exported_files
slots
end
Expand Down
5 changes: 5 additions & 0 deletions spec/fixtures/files/donations_export.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Source,Date,Details,Storage Location,Quantity of Items,Variety of Items,In-Kind Total,Comments,A Item,B Item,C Item,Dupe Item,E Item
Product Drive,2025-01-01,Test Product Drive,Test Storage Location,15,2,94.0,It's a fine day for diapers.,7,0,0,8,0
Manufacturer,2025-01-01,Test Manufacturer,Test Storage Location,1,1,20.0,It's a fine day for diapers.,0,1,0,0,0
Donation Site,2025-01-01,Test Donation Site,Test Storage Location,2,1,60.0,It's a fine day for diapers.,0,0,2,0,0
Misc. Donation,2025-01-01,It's a fine day for...,Test Storage Location,3,1,120.0,It's a fine day for diapers.,0,0,0,0,3
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Source,Date,Details,Storage Location,Quantity of Items,Variety of Items,In-Kind Total,Comments,apple,Banana,Zebra
Misc. Donation,2025-01-01,It's a fine day for...,Test Storage Location,2,1,3.0,It's a fine day for diapers.,0,2,0
5 changes: 5 additions & 0 deletions spec/fixtures/files/donations_export_with_in_kind_values.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Source,Date,Details,Storage Location,Quantity of Items,Variety of Items,In-Kind Total,Comments,A Item,A Item In-Kind Value,B Item,B Item In-Kind Value,C Item,C Item In-Kind Value,Dupe Item,Dupe Item In-Kind Value,E Item,E Item In-Kind Value
Product Drive,2025-01-01,Test Product Drive,Test Storage Location,15,2,94.0,It's a fine day for diapers.,7,70.00,0,0.00,0,0.00,8,24.00,0,0.00
Manufacturer,2025-01-01,Test Manufacturer,Test Storage Location,1,1,20.0,It's a fine day for diapers.,0,0.00,1,20.00,0,0.00,0,0.00,0,0.00
Donation Site,2025-01-01,Test Donation Site,Test Storage Location,2,1,60.0,It's a fine day for diapers.,0,0.00,0,0.00,2,60.00,0,0.00,0,0.00
Misc. Donation,2025-01-01,It's a fine day for...,Test Storage Location,3,1,120.0,It's a fine day for diapers.,0,0.00,0,0.00,0,0.00,0,0.00,3,120.00
5 changes: 5 additions & 0 deletions spec/fixtures/files/donations_export_with_inactive_item.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Source,Date,Details,Storage Location,Quantity of Items,Variety of Items,In-Kind Total,Comments,A Item,A Item In-Kind Value,B Item,B Item In-Kind Value,C Item,C Item In-Kind Value,Dupe Item,Dupe Item In-Kind Value,E Item,E Item In-Kind Value,Inactive Item,Inactive Item In-Kind Value
Product Drive,2025-01-01,Test Product Drive,Test Storage Location,15,2,94.0,It's a fine day for diapers.,7,70.00,0,0.00,0,0.00,8,24.00,0,0.00,0,0.00
Manufacturer,2025-01-01,Test Manufacturer,Test Storage Location,1,1,20.0,It's a fine day for diapers.,0,0.00,1,20.00,0,0.00,0,0.00,0,0.00,0,0.00
Donation Site,2025-01-01,Test Donation Site,Test Storage Location,2,1,60.0,It's a fine day for diapers.,0,0.00,0,0.00,2,60.00,0,0.00,0,0.00,0,0.00
Misc. Donation,2025-01-01,It's a fine day for...,Test Storage Location,3,1,120.0,It's a fine day for diapers.,0,0.00,0,0.00,0,0.00,0,0.00,3,120.00,0,0.00
5 changes: 5 additions & 0 deletions spec/fixtures/files/donations_export_with_unused_item.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Source,Date,Details,Storage Location,Quantity of Items,Variety of Items,In-Kind Total,Comments,A Item,A Item In-Kind Value,B Item,B Item In-Kind Value,C Item,C Item In-Kind Value,Dupe Item,Dupe Item In-Kind Value,E Item,E Item In-Kind Value,Unused Item,Unused Item In-Kind Value
Product Drive,2025-01-01,Test Product Drive,Test Storage Location,15,2,94.0,It's a fine day for diapers.,7,70.00,0,0.00,0,0.00,8,24.00,0,0.00,0,0.00
Manufacturer,2025-01-01,Test Manufacturer,Test Storage Location,1,1,20.0,It's a fine day for diapers.,0,0.00,1,20.00,0,0.00,0,0.00,0,0.00,0,0.00
Donation Site,2025-01-01,Test Donation Site,Test Storage Location,2,1,60.0,It's a fine day for diapers.,0,0.00,0,0.00,2,60.00,0,0.00,0,0.00,0,0.00
Misc. Donation,2025-01-01,It's a fine day for...,Test Storage Location,3,1,120.0,It's a fine day for diapers.,0,0.00,0,0.00,0,0.00,0,0.00,3,120.00,0,0.00
91 changes: 56 additions & 35 deletions spec/services/exports/export_donations_csv_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,84 +7,105 @@
let(:donation_ids) { donations.map(&:id) }
let(:duplicate_item) { create(:item, name: "Dupe Item", value_in_cents: 300, organization: organization) }

let(:donation_items_and_quantities) {
let(:donation_definitions) {
[
{
source: :product_drive_donation,
factory: :product_drive_donation,
attributes: {product_drive: create(:product_drive, name: "Test Product Drive", organization: organization)},
items: [
[duplicate_item, 5],
[create(:item, name: "A Item", value_in_cents: 1000, organization: organization), 7],
[duplicate_item, 3]
]
},
{
source: :manufacturer_donation,
factory: :manufacturer_donation,
attributes: {manufacturer: create(:manufacturer, name: "Test Manufacturer", organization: organization)},
items: [[create(:item, name: "B Item", value_in_cents: 2000, organization: organization), 1]]
},
{
source: :donation_site_donation,
factory: :donation_site_donation,
attributes: {donation_site: create(:donation_site, name: "Test Donation Site", organization: organization)},
items: [[create(:item, name: "C Item", value_in_cents: 3000, organization: organization), 2]]
},
{
source: :donation,
factory: :donation,
attributes: {},
items: [[create(:item, name: "E Item", value_in_cents: 4000, organization: organization), 3]]
}
]
}

let(:donations) do
donation_items_and_quantities.each_with_index.map do |items_quantities, i|
donation_definitions.map do |definition|
donation = create(
items_quantities[:source],
definition[:factory],
storage_location: storage_location,
organization: organization,
issued_at: "2025-01-01",
comment: "It's a fine day for diapers."
comment: "It's a fine day for diapers.",
**definition[:attributes]
)

items_quantities[:items].each do |line_item|
donation.line_items << create(:line_item, item: line_item[0], quantity: line_item[1])
definition[:items].each do |(item, quantity)|
donation.line_items << create(:line_item, item: item, quantity: quantity)
end

donation
end
end

def source_name(donation)
if !donation.product_drive.nil?
donation.product_drive.name
elsif !donation.manufacturer.nil?
donation.manufacturer.name
elsif !donation.donation_site.nil?
donation.donation_site.name
end
def expected_csv(fixture_name)
Rails.root.join("spec/fixtures/files", fixture_name).read
end

context 'while "Include in-kind value in donation and distribution exports?" is set to no' do
it 'should match the expected content without in-kind value of each item for the csv' do
csv = <<~CSV
Source,Date,Details,Storage Location,Quantity of Items,Variety of Items,In-Kind Total,Comments,A Item,B Item,C Item,Dupe Item,E Item
Product Drive,2025-01-01,#{source_name(donations[0])},Test Storage Location,15,2,94.0,It's a fine day for diapers.,7,0,0,8,0
Manufacturer,2025-01-01,#{source_name(donations[1])},Test Storage Location,1,1,20.0,It's a fine day for diapers.,0,1,0,0,0
Donation Site,2025-01-01,#{source_name(donations[2])},Test Storage Location,2,1,60.0,It's a fine day for diapers.,0,0,2,0,0
Misc. Donation,2025-01-01,It's a fine day for...,Test Storage Location,3,1,120.0,It's a fine day for diapers.,0,0,0,0,3
CSV
expect(subject).to eq(csv)
expect(subject).to eq(expected_csv("donations_export.csv"))
end
end

context 'while "Include in-kind value in donation and distribution exports?" is set to yes' do
it 'should match the expected content with in-kind value of each item for the csv' do
before do
allow(organization).to receive(:include_in_kind_values_in_exported_files).and_return(true)
end

it 'should match the expected content with in-kind value of each item for the csv' do
expect(subject).to eq(expected_csv("donations_export_with_in_kind_values.csv"))
end

it 'should include inactive items in the export with zero quantities' do
create(:item, :inactive, name: "Inactive Item", organization: organization)

expect(subject).to eq(expected_csv("donations_export_with_inactive_item.csv"))
end

it 'should include items that are not in any donation with zero quantities' do
create(:item, name: "Unused Item", organization: organization)

expect(subject).to eq(expected_csv("donations_export_with_unused_item.csv"))
end
end

context 'when item names differ only by case' do
let(:donation_definitions) {
[
{
factory: :donation,
attributes: {},
items: [[create(:item, name: "Banana", value_in_cents: 150, organization: organization), 2]]
}
]
}

it 'should sort item columns case-insensitively, ASC' do
# Create the other items in reverse-ASCII order to prove the sort is
# case-insensitive rather than relying on creation order or ASCII order
# (which would put "Zebra" before "apple").
create(:item, name: "apple", organization: organization)
create(:item, name: "Zebra", organization: organization)

csv = <<~CSV
Source,Date,Details,Storage Location,Quantity of Items,Variety of Items,In-Kind Total,Comments,A Item,A Item In-Kind Value,B Item,B Item In-Kind Value,C Item,C Item In-Kind Value,Dupe Item,Dupe Item In-Kind Value,E Item,E Item In-Kind Value
Product Drive,2025-01-01,#{source_name(donations[0])},Test Storage Location,15,2,94.0,It's a fine day for diapers.,7,70.00,0,0.00,0,0.00,8,24.00,0,0.00
Manufacturer,2025-01-01,#{source_name(donations[1])},Test Storage Location,1,1,20.0,It's a fine day for diapers.,0,0.00,1,20.00,0,0.00,0,0.00,0,0.00
Donation Site,2025-01-01,#{source_name(donations[2])},Test Storage Location,2,1,60.0,It's a fine day for diapers.,0,0.00,0,0.00,2,60.00,0,0.00,0,0.00
Misc. Donation,2025-01-01,It's a fine day for...,Test Storage Location,3,1,120.0,It's a fine day for diapers.,0,0.00,0,0.00,0,0.00,0,0.00,3,120.00
CSV
expect(subject).to eq(csv)
expect(subject).to eq(expected_csv("donations_export_case_insensitive_sort.csv"))
end

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comments re hardcoded CSVs.

end
end
Expand Down
Loading