diff --git a/app/controllers/distributions_controller.rb b/app/controllers/distributions_controller.rb index 965fcf3cd7..9f7b48cc97 100644 --- a/app/controllers/distributions_controller.rb +++ b/app/controllers/distributions_controller.rb @@ -66,7 +66,7 @@ def index respond_to do |format| format.html format.csv do - send_data Exports::ExportDistributionsCSVService.new(distributions: @distributions, filters: filter_params).generate_csv, filename: "Distributions-#{Time.zone.today}.csv" + send_data Exports::ExportDistributionsCSVService.new(distributions: @distributions, organization: current_organization, filters: filter_params).generate_csv, filename: "Distributions-#{Time.zone.today}.csv" end end end diff --git a/app/controllers/partners_controller.rb b/app/controllers/partners_controller.rb index fadbf5d213..35f8722e65 100644 --- a/app/controllers/partners_controller.rb +++ b/app/controllers/partners_controller.rb @@ -81,7 +81,7 @@ def show respond_to do |format| format.html format.csv do - send_data Exports::ExportDistributionsCSVService.new(distributions: @partner_distributions, filters: filter_params).generate_csv, filename: "PartnerDistributions-#{Time.zone.today}.csv" + send_data Exports::ExportDistributionsCSVService.new(distributions: @partner_distributions, organization: current_organization, filters: filter_params).generate_csv, filename: "PartnerDistributions-#{Time.zone.today}.csv" end end end diff --git a/app/services/exports/export_distributions_csv_service.rb b/app/services/exports/export_distributions_csv_service.rb index ce64b90520..a0f6569409 100644 --- a/app/services/exports/export_distributions_csv_service.rb +++ b/app/services/exports/export_distributions_csv_service.rb @@ -1,7 +1,7 @@ module Exports class ExportDistributionsCSVService include DistributionHelper - def initialize(distributions:, filters: []) + def initialize(distributions:, organization:, filters: []) # Currently, the @distributions are already loaded by the controllers that are delegating exporting # to this service object; this is happening within the same request/response cycle, so it's already # in memory, so we can pass that collection in directly. Should this be moved to a background / async @@ -10,6 +10,7 @@ def initialize(distributions:, filters: []) # service object. @distributions = distributions @filters = filters + @organization = organization end def generate_csv @@ -114,15 +115,7 @@ def base_headers def item_headers return @item_headers if @item_headers - item_names = Set.new - - distributions.each do |distribution| - distribution.line_items.each do |line_item| - item_names.add(line_item.item.name) - end - end - - @item_headers = item_names.sort + @item_headers = @organization.items.order(:created_at).distinct.select([:created_at, :name]).map(&:name) end def build_row_data(distribution) @@ -133,6 +126,8 @@ def build_row_data(distribution) distribution.line_items.each do |line_item| item_name = line_item.item.name item_column_idx = headers_with_indexes[item_name] + next unless item_column_idx + row[item_column_idx] += line_item.quantity end diff --git a/spec/services/exports/export_distributions_csv_service_spec.rb b/spec/services/exports/export_distributions_csv_service_spec.rb index accc292b5b..8f35ac5314 100644 --- a/spec/services/exports/export_distributions_csv_service_spec.rb +++ b/spec/services/exports/export_distributions_csv_service_spec.rb @@ -1,6 +1,6 @@ describe Exports::ExportDistributionsCSVService do describe '#generate_csv_data' do - subject { described_class.new(distributions: distributions, filters: filters).generate_csv_data } + subject { described_class.new(distributions: distributions, organization: Organization.first, filters: filters).generate_csv_data } let(:distributions) { distributions } let(:duplicate_item) do @@ -51,9 +51,12 @@ let(:item_id) { distributions.flatten.first.line_items.first.item_id } let(:filters) { {by_item_id: item_id} } let(:item_name) { Item.find(item_id).name } + let(:organization) { distributions.first.organization } + + let(:all_org_items) { Item.where(organization:).uniq.sort_by(&:created_at) } let(:total_item_quantities) do - template = item_names.index_with(0) + template = all_org_items.pluck(:name).index_with(0) items_lists.map do |items_list| row = template.dup @@ -64,7 +67,7 @@ end end - let(:expected_headers) do + let(:non_item_headers) do [ "Partner", "Date of Distribution", @@ -76,14 +79,10 @@ "State", "Agency Representative", "Comments" - ] + expected_item_headers + ] end - let(:expected_item_headers) do - expect(item_names).not_to be_empty - - item_names - end + let(:expected_headers) { non_item_headers + all_org_items.pluck(:name) } it 'should match the expected content for the csv' do expect(subject[0]).to eq(expected_headers) @@ -107,5 +106,52 @@ expect(subject[idx + 1]).to eq(row) end end + + context 'when a new item is added' do + let!(:original_columns_count) { organization.items.size + non_item_headers.size } + let(:new_item_name) { "new item" } + before do + create(:item, name: new_item_name, organization:) + end + + it 'should add it to the end of the row' do + expect(subject[0]).to eq(expected_headers) + .and end_with(new_item_name) + .and have_attributes(size: original_columns_count + 1) + end + + it 'should show up with a 0 quantity if there are none of this item in any distribution' do + distributions.zip(total_item_quantities).each_with_index do |(distribution, total_item_quantity), idx| + row = [ + distribution.partner.name, + distribution.issued_at.strftime("%m/%d/%Y"), + distribution.storage_location.name, + distribution.line_items.where(item_id: item_id).total, + distribution.cents_to_dollar(distribution.line_items.total_value), + distribution.delivery_method, + "$#{distribution.shipping_cost.to_f}", + distribution.state, + distribution.agency_rep, + distribution.comment + ] + + row += total_item_quantity + + expect(subject[idx + 1]).to eq(row) + .and end_with(0) + .and have_attributes(size: original_columns_count + 1) + end + end + end + + context 'when there are no distributions but the report is requested' do + subject { described_class.new(distributions: [], organization: Organization.first, filters: filters).generate_csv_data } + it 'returns a csv with only headers and no rows' do + header_row = subject[0] + expect(header_row).to eq(expected_headers) + expect(header_row.last).to eq(all_org_items.last.name) + expect(subject.size).to eq(1) + end + end end end