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
1 change: 1 addition & 0 deletions app/controllers/organizations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def organization_params
:signature_for_distribution_pdf, :receive_email_on_requests,
:bank_is_set_up,
:include_in_kind_values_in_exported_files,
:include_packages_in_distribution_export,
partner_form_fields: [],
request_unit_names: []
)
Expand Down
1 change: 1 addition & 0 deletions app/models/organization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# hide_package_column_on_receipt :boolean default(FALSE)
# hide_value_columns_on_receipt :boolean default(FALSE)
# include_in_kind_values_in_exported_files :boolean default(FALSE), not null
# include_packages_in_distribution_export :boolean default(FALSE), not null
# intake_location :integer
# invitation_text :text
# latitude :float
Expand Down
44 changes: 13 additions & 31 deletions app/services/exports/export_distributions_csv_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def generate_csv
def generate_csv_data
csv_data = []

csv_data << headers
csv_data << base_headers + item_headers
distributions.each do |distribution|
csv_data << build_row_data(distribution)
end
Expand All @@ -39,17 +39,6 @@ def generate_csv_data

attr_reader :distributions

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

# Returns a Hash of keys to indexes so that obtaining the index
# doesn't require a linear scan.
def headers_with_indexes
@headers_with_indexes ||= headers.each_with_index.to_h
end

# This method keeps the base headers associated with the lambdas
# for extracting the values for the base columns from the given
# distribution.
Expand Down Expand Up @@ -132,35 +121,28 @@ def base_headers
base_table.keys
end

def item_headers
return @item_headers if @item_headers

@item_headers = @organization.items.select("DISTINCT ON (LOWER(name)) items.name").order("LOWER(name) ASC").map(&:name)
@item_headers = @item_headers.flat_map { |header| [header, "#{header} In-Kind Value"] } if @organization.include_in_kind_values_in_exported_files
def item_names
@item_names ||= @organization.items.pluck(:name).sort_by(&:downcase)
end

@item_headers
def item_headers
in_kind_value_headers = @organization.include_in_kind_values_in_exported_files ? item_names.map { |item| "#{item} In-Kind Value" } : []
package_headers = @organization.include_packages_in_distribution_export ? item_names.map { |item| "#{item} Packages" } : []
item_names.zip(in_kind_value_headers, package_headers).flatten.compact
end

def build_row_data(distribution)
row = base_table.values.map { |closure| closure.call(distribution) }
row += make_item_quantity_and_value_slots

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
item_names.each do |item_name|
line_items = distribution.line_items.where(item: @organization.items.find_by(name: item_name))

row[item_column_idx] += line_item.quantity
row[item_column_idx + 1] += Money.new(line_item.value_per_line_item) if @organization.include_in_kind_values_in_exported_files
row << line_items.sum(&:quantity)
row << Money.new(line_items.sum(&:value_per_line_item)) if @organization.include_in_kind_values_in_exported_files
row << line_items.map(&:has_packages).compact.sum.round(2) if @organization.include_packages_in_distribution_export
end

row
end

def make_item_quantity_and_value_slots
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
end
end
4 changes: 4 additions & 0 deletions app/views/organizations/_details.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@
<p>
<%= humanize_boolean(@organization.include_in_kind_values_in_exported_files) %>
</p>
<h6 class='font-weight-bold'>Include packages in distribution export:</h6>
<p>
<%= humanize_boolean(@organization.include_packages_in_distribution_export) %>
</p>
</div>

<h4>Annual Survey</h4>
Expand Down
1 change: 1 addition & 0 deletions app/views/organizations/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@

<h4>Exports</h4>
<%= f.input :include_in_kind_values_in_exported_files, label: 'Include in-kind value in donation and distribution exports?', as: :radio_buttons, collection: [[true, 'Yes'], [false, 'No']], label_method: :second, value_method: :first %>
<%= f.input :include_packages_in_distribution_export, label: 'Include packages in distribution export?', as: :radio_buttons, collection: [[true, 'Yes'], [false, 'No']], label_method: :second, value_method: :first %>

<h4>Annual Survey</h4>
<%= f.input :repackage_essentials, label: 'Does your Bank repackage essentials?', as: :radio_buttons, collection: [[true, 'Yes'], [false, 'No']], label_method: :second, value_method: :first %>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddIncludePackagesInDistributionExportToOrganizations < ActiveRecord::Migration[8.0]
def change
add_column :organizations, :include_packages_in_distribution_export, :boolean, default: false, null: false
end
end
1 change: 1 addition & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@
t.boolean "receive_email_on_requests", default: false, null: false
t.boolean "include_in_kind_values_in_exported_files", default: false, null: false
t.string "reminder_schedule_definition"
t.boolean "include_packages_in_distribution_export", default: false, null: false
t.boolean "bank_is_set_up", default: false, null: false
t.index ["latitude", "longitude"], name: "index_organizations_on_latitude_and_longitude"
end
Expand Down
7 changes: 7 additions & 0 deletions docs/user_guide/bank/exports.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ Click "My Organization" in the left hand menu. Click "Edit" button. Set the "Inc

[!NOTE] Setting this affects both the donation and distribution exports.

### Add Package Counts for each item
If you want to also have the export include the package count for each item in the distributions, you can set that option.
- Click "My Organization" in the left hand menu.
- Click "Edit" button.
- Set the "Include packages in distribution export" to "yes"
- Click "Save"

## Donations

### Navigating to export Donations
Expand Down
1 change: 1 addition & 0 deletions spec/factories/organizations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# hide_package_column_on_receipt :boolean default(FALSE)
# hide_value_columns_on_receipt :boolean default(FALSE)
# include_in_kind_values_in_exported_files :boolean default(FALSE), not null
# include_packages_in_distribution_export :boolean default(FALSE), not null
# intake_location :integer
# invitation_text :text
# latitude :float
Expand Down
1 change: 1 addition & 0 deletions spec/models/organization_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# hide_package_column_on_receipt :boolean default(FALSE)
# hide_value_columns_on_receipt :boolean default(FALSE)
# include_in_kind_values_in_exported_files :boolean default(FALSE), not null
# include_packages_in_distribution_export :boolean default(FALSE), not null
# intake_location :integer
# invitation_text :text
# latitude :float
Expand Down
9 changes: 9 additions & 0 deletions spec/requests/organization_requests_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@
expect(html.text).to include("Logo")
expect(html.text).to include("Use one-step Partner invite and approve process?")
expect(html.text).to include("Receive email when Partner makes a Request?")
expect(html.text).to include("Include packages in distribution export:")
end

context "when enable_packs flipper is on" do
Expand Down Expand Up @@ -446,6 +447,14 @@
expect(response.body).to include("Yes")
end
end

context "can enable if package count is included in distribution exports" do
let(:update_param) { { organization: { include_packages_in_distribution_export: true } } }

it "can update include_packages_in_distribution_export" do
expect { subject }.to change { organization.reload.include_packages_in_distribution_export }.to true
end
end
end

describe "POST #promote_to_org_admin" do
Expand Down
47 changes: 40 additions & 7 deletions spec/services/exports/export_distributions_csv_service_spec.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
RSpec.describe Exports::ExportDistributionsCSVService do
let(:organization) { create(:organization) }
let(:organization) { create(:organization, include_in_kind_values_in_exported_files: include_in_kind_values, include_packages_in_distribution_export: include_packages) }
let(:storage_location) { create(:storage_location, organization: organization) }
let(:partner) { create(:partner, name: "first partner", email: "[email protected]", notes: "just a note.", organization_id: organization.id) }
let(:include_in_kind_values) { false }
let(:include_packages) { false }

describe '#generate_csv' do
subject { described_class.new(distributions: distributions, organization: organization, filters: filters).generate_csv }

let(:duplicate_item) { create(:item, name: "Dupe Item", value_in_cents: 300, organization: organization) }
let(:duplicate_item) { create(:item, name: "Dupe Item", value_in_cents: 300, organization: organization, package_size: 2) }

let(:distribution_items_and_quantities) {
[
[
[duplicate_item, 5],
[create(:item, name: "A Item", value_in_cents: 1000, organization: organization), 7],
[create(:item, name: "A Item", value_in_cents: 1000, organization: organization, package_size: 6), 7],
[duplicate_item, 3]
],
[[create(:item, name: "B Item", value_in_cents: 2000, organization: organization), 1]],
Expand Down Expand Up @@ -49,8 +51,8 @@
let(:item_name) { duplicate_item.name }
let(:filters) { {by_item_id: item_id} }

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
context 'while both in-kind values and package count are disabled for export' do
it 'should match the expected content without in-kind value or package count for each item for the csv' do
csv = <<~CSV
Partner,Initial Allocation,Scheduled for,Source Inventory,Total Number of #{item_name},Total Value of #{item_name},Delivery Method,Shipping Cost,Status,Agency Representative,Comments,A Item,B Item,C Item,Dupe Item,E Item
#{partner.name},04/04/2025,04/04/2025,#{storage_location.name},8,24.0,shipped,$15.01,scheduled,"",comment 0,7,0,0,8,0
Expand All @@ -63,9 +65,9 @@
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
allow(organization).to receive(:include_in_kind_values_in_exported_files).and_return(true)
let(:include_in_kind_values) { true }

it 'should match the expected content with in-kind value of each item for the csv' do
csv = <<~CSV
Partner,Initial Allocation,Scheduled for,Source Inventory,Total Number of #{item_name},Total Value of #{item_name},Delivery Method,Shipping Cost,Status,Agency Representative,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
#{partner.name},04/04/2025,04/04/2025,#{storage_location.name},8,24.0,shipped,$15.01,scheduled,"",comment 0,7,70.00,0,0.00,0,0.00,8,24.00,0,0.00
Expand All @@ -77,6 +79,37 @@
end
end

context 'while "Include packages in distribution export" is set to yes' do
let(:include_packages) { true }

it 'should match the expected content with package count of each item for the csv' do
csv = <<~CSV
Partner,Initial Allocation,Scheduled for,Source Inventory,Total Number of #{item_name},Total Value of #{item_name},Delivery Method,Shipping Cost,Status,Agency Representative,Comments,A Item,A Item Packages,B Item,B Item Packages,C Item,C Item Packages,Dupe Item,Dupe Item Packages,E Item,E Item Packages
#{partner.name},04/04/2025,04/04/2025,#{storage_location.name},8,24.0,shipped,$15.01,scheduled,"",comment 0,7,1.17,0,0,0,0,8,4.0,0,0
#{partner.name},04/04/2025,04/04/2025,#{storage_location.name},0,0.0,shipped,$15.01,scheduled,"",comment 1,0,0,1,0,0,0,0,0,0,0
#{partner.name},04/04/2025,04/04/2025,#{storage_location.name},0,0.0,shipped,$15.01,scheduled,"",comment 2,0,0,0,0,2,0,0,0,0,0
#{partner.name},04/04/2025,04/04/2025,#{storage_location.name},0,0.0,shipped,$15.01,scheduled,"",comment 3,0,0,0,0,0,0,0,0,3,0
CSV
expect(subject).to eq(csv)
end
end

context 'while both in-kind values and package count are enabled for export' do
let(:include_in_kind_values) { true }
let(:include_packages) { true }

it 'should match the expected content with in-kind value and package count of each item for the csv' do
csv = <<~CSV
Partner,Initial Allocation,Scheduled for,Source Inventory,Total Number of #{item_name},Total Value of #{item_name},Delivery Method,Shipping Cost,Status,Agency Representative,Comments,A Item,A Item In-Kind Value,A Item Packages,B Item,B Item In-Kind Value,B Item Packages,C Item,C Item In-Kind Value,C Item Packages,Dupe Item,Dupe Item In-Kind Value,Dupe Item Packages,E Item,E Item In-Kind Value,E Item Packages
#{partner.name},04/04/2025,04/04/2025,#{storage_location.name},8,24.0,shipped,$15.01,scheduled,"",comment 0,7,70.00,1.17,0,0.00,0,0,0.00,0,8,24.00,4.0,0,0.00,0
#{partner.name},04/04/2025,04/04/2025,#{storage_location.name},0,0.0,shipped,$15.01,scheduled,"",comment 1,0,0.00,0,1,20.00,0,0,0.00,0,0,0.00,0,0,0.00,0
#{partner.name},04/04/2025,04/04/2025,#{storage_location.name},0,0.0,shipped,$15.01,scheduled,"",comment 2,0,0.00,0,0,0.00,0,2,60.00,0,0,0.00,0,0,0.00,0
#{partner.name},04/04/2025,04/04/2025,#{storage_location.name},0,0.0,shipped,$15.01,scheduled,"",comment 3,0,0.00,0,0,0.00,0,0,0.00,0,0,0.00,0,3,120.00,0
CSV
expect(subject).to eq(csv)
end
end

context 'when a new item is added' do
let(:new_item_name) { "New Item" }
let(:original_columns_count) { 15 }
Expand Down