Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to control whether "in-kind value" of each item should be added in export of donations and distributions #4897

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion app/controllers/donations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def index
respond_to do |format|
format.html
format.csv do
send_data Exports::ExportDonationsCSVService.new(donation_ids: @donations.map(&:id)).generate_csv, filename: "Donations-#{Time.zone.today}.csv"
send_data Exports::ExportDonationsCSVService.new(donation_ids: @donations.map(&:id), organization: current_organization).generate_csv, filename: "Donations-#{Time.zone.today}.csv"
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/organizations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def organization_params
:enable_individual_requests, :enable_quantity_based_requests,
:ytd_on_distribution_printout, :one_step_partner_invite,
:hide_value_columns_on_receipt, :hide_package_column_on_receipt,
:signature_for_distribution_pdf,
:signature_for_distribution_pdf, :include_in_kind_values_in_exported_files,
partner_form_fields: [],
request_unit_names: []
)
Expand Down
63 changes: 32 additions & 31 deletions app/models/organization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,38 @@
#
# Table name: organizations
#
# id :integer not null, primary key
# city :string
# deadline_day :integer
# default_storage_location :integer
# distribute_monthly :boolean default(FALSE), not null
# email :string
# enable_child_based_requests :boolean default(TRUE), not null
# enable_individual_requests :boolean default(TRUE), not null
# enable_quantity_based_requests :boolean default(TRUE), not null
# hide_package_column_on_receipt :boolean default(FALSE)
# hide_value_columns_on_receipt :boolean default(FALSE)
# intake_location :integer
# invitation_text :text
# latitude :float
# longitude :float
# name :string
# one_step_partner_invite :boolean default(FALSE), not null
# partner_form_fields :text default([]), is an Array
# reminder_day :integer
# repackage_essentials :boolean default(FALSE), not null
# short_name :string
# signature_for_distribution_pdf :boolean default(FALSE)
# state :string
# street :string
# url :string
# ytd_on_distribution_printout :boolean default(TRUE), not null
# zipcode :string
# created_at :datetime not null
# updated_at :datetime not null
# account_request_id :integer
# ndbn_member_id :bigint
# id :integer not null, primary key
# city :string
# deadline_day :integer
# default_storage_location :integer
# distribute_monthly :boolean default(FALSE), not null
# email :string
# enable_child_based_requests :boolean default(TRUE), not null
# enable_individual_requests :boolean default(TRUE), not null
# enable_quantity_based_requests :boolean default(TRUE), not null
# 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)
# intake_location :integer
# invitation_text :text
# latitude :float
# longitude :float
# name :string
# one_step_partner_invite :boolean default(FALSE), not null
# partner_form_fields :text default([]), is an Array
# reminder_day :integer
# repackage_essentials :boolean default(FALSE), not null
# short_name :string
# signature_for_distribution_pdf :boolean default(FALSE)
# state :string
# street :string
# url :string
# ytd_on_distribution_printout :boolean default(TRUE), not null
# zipcode :string
# created_at :datetime not null
# updated_at :datetime not null
# account_request_id :integer
# ndbn_member_id :bigint
#

class Organization < ApplicationRecord
Expand Down
23 changes: 19 additions & 4 deletions app/services/exports/export_distributions_csv_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def base_table
end
},
"Total Value" => ->(distribution) {
distribution.cents_to_dollar(distribution.line_items.total_value)
Money.from_cents(distribution.line_items.total_value)
},
"Delivery Method" => ->(distribution) {
distribution.delivery_method
Expand Down Expand Up @@ -119,22 +119,37 @@ 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 { |h| [h, "#{h} In-Kind Value"] } if @organization.include_in_kind_values_in_exported_files

@item_headers
end

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

row += Array.new(item_headers.size, 0)

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

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
end

row
convert_to_dollar(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

def convert_to_dollar(row)
row.map do |column|
column.is_a?(Money) ? column.to_f : column
end
end
end
end
25 changes: 21 additions & 4 deletions app/services/exports/export_donations_csv_service.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Exports
class ExportDonationsCSVService
def initialize(donation_ids:)
def initialize(donation_ids:, organization:)
# Use a where lookup so that I can eager load all the resources
# needed rather than depending on external code to do it for me.
# This makes this code more self contained and efficient!
Expand All @@ -13,6 +13,7 @@ def initialize(donation_ids:)
).where(
id: donation_ids,
).order(created_at: :asc)
@organization = organization
end

def generate_csv
Expand Down Expand Up @@ -80,7 +81,7 @@ def base_table
"Variety of Items" => ->(donation) {
donation.line_items.map(&:name).uniq.size
},
"In-Kind Value" => ->(donation) {
"In-Kind Total" => ->(donation) {
donation.in_kind_value_money
},
"Comments" => ->(donation) {
Expand All @@ -105,20 +106,36 @@ def item_headers
end

@item_headers = item_names.sort
@item_headers = @item_headers.flat_map { |h| [h, "#{h} 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 += Array.new(item_headers.size, 0)
row += make_item_quantity_and_value_slots

donation.line_items.each do |line_item|
item_name = line_item.item.name
item_column_idx = headers_with_indexes[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
end

row
convert_to_dollar(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

def convert_to_dollar(row)
row.map do |column|
column.is_a?(Money) ? column.to_f : column
end
end
end
end
6 changes: 6 additions & 0 deletions app/views/organizations/_details.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@
<%= humanize_boolean(@organization.hide_package_column_on_receipt) %>
</p>
</div>
<div class="mb-4">
<h3 class='font-bold'>Include in-kind value in donation and distribution exports:</h3>
<p>
<%= humanize_boolean(@organization.include_in_kind_values_in_exported_files) %>
</p>
</div>
<% if @organization.logo.attached? %>
<div class="mb-4">
<h3 class='font-bold'>Logo</h3>
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 @@ -131,6 +131,7 @@
<%= f.input :one_step_partner_invite, label: 'Use One Step Invite and Approve partner process?', as: :radio_buttons, collection: [[true, 'Yes'], [false, 'No']], label_method: :second, value_method: :first %>
<%= f.input :hide_value_columns_on_receipt, label: 'Hide both value columns on distribution receipts?', as: :radio_buttons, collection: [[true, 'Yes'], [false, 'No']], label_method: :second, value_method: :first %>
<%= f.input :hide_package_column_on_receipt, label: 'Hide the package column on distribution receipts?', as: :radio_buttons, collection: [[true, 'Yes'], [false, 'No']], label_method: :second, value_method: :first %>
<%= 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 %>

<% default_email_text_hint = "You can use the variables <code>%{partner_name}</code>, <code>%{delivery_method}</code>, <code>%{distribution_date}</code>, and <code>%{comment}</code> to include the partner's name, delivery method, distribution date, and comments sent in the request." %>
<%= f.input :default_email_text, label: "Distribution Email Content", hint: default_email_text_hint.html_safe do %>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddIncludeInKindValuesInExportedFilesToOrganizations < ActiveRecord::Migration[7.2]
def change
add_column :organizations, :include_in_kind_values_in_exported_files, :boolean
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should be NOT NULL. Otherwise it's got three values, true false and null. :)

change_column_default :organizations, :include_in_kind_values_in_exported_files, false
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class BackfillAddIncludeInKindValuesInExportedFilesToOrganizations < ActiveRecord::Migration[7.2]
disable_ddl_transaction!
def change
Organization.unscoped.in_batches do |relation|
relation.update_all include_in_kind_values_in_exported_files: false
sleep(0.01)
end
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.2].define(version: 2024_12_20_020009) do
ActiveRecord::Schema[7.2].define(version: 2024_12_30_044251) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

Expand Down Expand Up @@ -491,6 +491,7 @@
t.boolean "hide_value_columns_on_receipt", default: false
t.boolean "hide_package_column_on_receipt", default: false
t.boolean "signature_for_distribution_pdf", default: false
t.boolean "include_in_kind_values_in_exported_files", default: false
t.index ["latitude", "longitude"], name: "index_organizations_on_latitude_and_longitude"
t.index ["short_name"], name: "index_organizations_on_short_name"
end
Expand Down
12 changes: 12 additions & 0 deletions docs/user_guide/bank/exports.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ For each of the distributions in the filtered list:

[!NOTE] This includes inactive Items as well as active ones.

### Add In-Kind Value for each item
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add something like "The default export includes the number of items exported, but not the values. If you want to also have the export include the in-kind value for each item in the distributions, you can set that option." before the instructions.

And after, please add a "[!NOTE] Setting this affects both the donation and distribution exports."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK.

The default export includes the number of items exported, but not the values. If you want to also have the export include the in-kind value 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 in-kind value in donation and distribution exports?" to "yes", then click "Save".

Copy link
Collaborator

Choose a reason for hiding this comment

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

to "yes", then click "Save".

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

## Donations

### Navigating to export Donations
Expand Down Expand Up @@ -157,6 +163,12 @@ For each of the Donations in the filtered list:
- Comments,
- and the quantity of each of your organization's Items in the Donations.

### Add In-Kind Value for each item
The default export includes the number of items exported, but not the values. If you want to also have the export include the in-kind value 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 in-kind value in donation and distribution exports?" to "yes", then click "Save".

Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add similar text as noted above in the distribution section.

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

## Donation Sites
### Navigating to export Donation Sites
Click "Community", then "Donation Sites" in the left hand menu. Then click "Export Donation Sites"
Expand Down
10 changes: 10 additions & 0 deletions docs/user_guide/bank/getting_started_customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,16 @@ Partners can't submit Requests until they are approved by the bank.
The full partner approval process requires the partner to fill in their profile and submit it for approval. Some banks handle that for their partners, gather the information through other means (such as a phone conversation).
Checking this will change the process so that the partners are automatically approved when they are invited. Note that any invited partners that are not yet approved will still need to be approved by the bank.

## Configuring exports

### Include in-kind value in donation and distribution exports?

You can configure whether the exports for donations and distributions include the "In-Kind Value" column for each item. By default, these values are excluded. To include them, set the "Include in-kind value in donation and distribution exports?" option to "Yes".

Click "My Organization" in the left hand menu. Click "Edit" button. Set the "Include in-kind value in donation and distribution exports?" to "yes", then click "Save".

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

#### Distribution Email Content
Note that there is a checkbox on the partner for them to receive Distribution emails. We recommend you do customize this content, as the default text is abrupt.
You can customize this quite a bit!
Expand Down
1 change: 1 addition & 0 deletions spec/factories/items.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
sequence(:name) { |n| "#{n}T Diapers" }
organization { Organization.try(:first) || create(:organization) }
partner_key { BaseItem.first&.partner_key || create(:base_item).partner_key }
value_in_cents { 0 }
kit { nil }

trait :active do
Expand Down
63 changes: 32 additions & 31 deletions spec/factories/organizations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,38 @@
#
# Table name: organizations
#
# id :integer not null, primary key
# city :string
# deadline_day :integer
# default_storage_location :integer
# distribute_monthly :boolean default(FALSE), not null
# email :string
# enable_child_based_requests :boolean default(TRUE), not null
# enable_individual_requests :boolean default(TRUE), not null
# enable_quantity_based_requests :boolean default(TRUE), not null
# hide_package_column_on_receipt :boolean default(FALSE)
# hide_value_columns_on_receipt :boolean default(FALSE)
# intake_location :integer
# invitation_text :text
# latitude :float
# longitude :float
# name :string
# one_step_partner_invite :boolean default(FALSE), not null
# partner_form_fields :text default([]), is an Array
# reminder_day :integer
# repackage_essentials :boolean default(FALSE), not null
# short_name :string
# signature_for_distribution_pdf :boolean default(FALSE)
# state :string
# street :string
# url :string
# ytd_on_distribution_printout :boolean default(TRUE), not null
# zipcode :string
# created_at :datetime not null
# updated_at :datetime not null
# account_request_id :integer
# ndbn_member_id :bigint
# id :integer not null, primary key
# city :string
# deadline_day :integer
# default_storage_location :integer
# distribute_monthly :boolean default(FALSE), not null
# email :string
# enable_child_based_requests :boolean default(TRUE), not null
# enable_individual_requests :boolean default(TRUE), not null
# enable_quantity_based_requests :boolean default(TRUE), not null
# 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)
# intake_location :integer
# invitation_text :text
# latitude :float
# longitude :float
# name :string
# one_step_partner_invite :boolean default(FALSE), not null
# partner_form_fields :text default([]), is an Array
# reminder_day :integer
# repackage_essentials :boolean default(FALSE), not null
# short_name :string
# signature_for_distribution_pdf :boolean default(FALSE)
# state :string
# street :string
# url :string
# ytd_on_distribution_printout :boolean default(TRUE), not null
# zipcode :string
# created_at :datetime not null
# updated_at :datetime not null
# account_request_id :integer
# ndbn_member_id :bigint
#
require 'seeds'

Expand Down
Loading
Loading