Add an option to control whether "in-kind value" of each item should be added in export of donations and distributions#5122
Conversation
…be added in export of donations and distributions
There was a problem hiding this comment.
Hey @nozomirin It still works well!
I can see, though, that we're going to have a conflict with the work in #5116, where we are reorganizing the organizations page..
With that in place, I would want the new field here to be in its own section, "Exports" on those screens. (refer to #5116 for what weight the heading should be)
Ideally, I would want it that section just above the "Annual Survey" section.
This is a change that is needed before merge, but might be easiest to do once #5116 is merged into main (which I anticipate this week).
I don't see any reason that it would hold up our technical re-review, so over to @dorner or @awwaiid.
…-in-export-of-donations-and-distributions-new
|
There were no errors when I ran |
|
@cielf Please check whether it fits your expectations. |
|
Yup -- I saw some things that are out of scope, and will be addressed in a separate issue, but your changes LGTM on manual testing. Over to @dorner for technical input |
|
@nozomirin One very small change to the docs --- please change "Configuring exports" to "Exports" - so it matches what the bank user will be seeing. Thanks |
|
LGTM. |
| class AddIncludeInKindValuesInExportedFilesToOrganizations < ActiveRecord::Migration[8.0] | ||
| def change | ||
| add_column :organizations, :include_in_kind_values_in_exported_files, :boolean | ||
| add_check_constraint :organizations, "include_in_kind_values_in_exported_files IS NOT NULL", name: "include_in_kind_values_in_exported_files_not_null", validate: false |
There was a problem hiding this comment.
This seems a very awkward way of just saying null: false...?
There was a problem hiding this comment.
Adding the NOT NULL constraint directly will lock the table. This method helps avoid that. I don't know how big the table will be, so I think it's better to avoid it.
There was a problem hiding this comment.
Organizations is a tiny table. You can lock it.
| @distribution_totals = DistributionTotalsService.call(Distribution.where(organization:).class_filter(filters)) | ||
|
|
||
| @export_line_item_adder = Exports::ExportLineItemColumnsAdder.new | ||
| @export_line_item_adder.register(Exports::ExportInKindTotalValue) if @organization.include_in_kind_values_in_exported_files |
There was a problem hiding this comment.
This seems like an overly complex way of adding a column to an export. You're basically turning a single if statement into a factory pattern. Can you explain why you did it this way?
There was a problem hiding this comment.
If you have other attributes that need to be added to the exported CSV, just create another class and register it here. There's no need to modify any other code. Since both distribution and donation share the same export functionality, I extracted it to avoid duplication.
There was a problem hiding this comment.
This is a case of unnecessary DRY along with a big helping of YAGNI. As far as we know there are no additional attributes that will need this, and in general the idea that "attributes in a CSV" is a generic feature is probably not a helpful construct. I'd much prefer a simpler approach even if it means a little bit of duplicated code.
| @registry = [] | ||
| end | ||
|
|
||
| def headers(item_headers) |
There was a problem hiding this comment.
In general this code is written in an unusual manner... I'd need to see a bunch more comments here since I can't really understand what some of it is supposed to be doing. What does "registry" contain? What kind of "row" does get_row return? What additional_columns do we need and how does that relate to the registry...?
There was a problem hiding this comment.
The registry contains classes that implement Exports::ExportColumnsBase. Each element in the registry adds a column after each "line_item" column.
get_row returns a row like this:
|item A|col1|col2|item B|col1|col2|...
These col1, col2, etc., are the additional_columns.
There was a problem hiding this comment.
The explanation has to be in comments, not in the PR.
But in general, if you have to explain what the code is doing via comments, it might be doing things in a way that isn't straightforward.
| distribution.created_at.strftime("%m/%d/%Y"), | ||
| distribution.issued_at.strftime("%m/%d/%Y"), | ||
| distribution.storage_location.name, | ||
| distribution.line_items.where(item_id: item_id).total, |
There was a problem hiding this comment.
Using calculated values in specs make it not only hard to follow but also a lot flakier. I've had many instances where a value passed because it happened to match the expected value, but was actually reading the wrong source. Can you explicitly create the things you're trying to test and expect the hardcoded values from those things?
There was a problem hiding this comment.
Ok, I will make some changes.
There was a problem hiding this comment.
It seems really annoying to do that with FactoryBot...
There was a problem hiding this comment.
Please check whether it fits your expectations.
…-in-export-of-donations-and-distributions-new
| "$#{expected_dist[:shipping_cost].to_f}", | ||
| expected_dist[:state], | ||
| expected_dist[:agency_rep], | ||
| expected_dist[:comment], |
There was a problem hiding this comment.
Is there a reason you can't just generate a flat CSV string and compare the results against it instead of going row by row?
There was a problem hiding this comment.
This comment still stands - see e.g.
…-in-export-of-donations-and-distributions-new
|
If you have time, please review this. @dorner |
| let(:duplicate_item) { create(:item, name: "Dupe Item", value_in_cents: 300, organization: organization) } | ||
|
|
||
| let(:items_lists) do | ||
| let(:expected_distributions) { |
There was a problem hiding this comment.
Is there a reason you're not just using FactoryBot.build / FactoryBot.create here?
This feels a lot like a Go table test instead of a Rails test.
There was a problem hiding this comment.
Please check whether it fits your expectations.
| "$#{expected_dist[:shipping_cost].to_f}", | ||
| expected_dist[:state], | ||
| expected_dist[:agency_rep], | ||
| expected_dist[:comment], |
There was a problem hiding this comment.
This comment still stands - see e.g.
…of-donations-and-distributions-new' of https://github.com/nozomirin/human-essentials into 4858-add-an-option-to-include-in-kind-values-in-export-of-donations-and-distributions-new
60d1fee to
6dae33a
Compare
dorner
left a comment
There was a problem hiding this comment.
A bit more explicitness on the tests please!
|
|
||
| it 'should match the expected content without in-kind value of each item for the csv' do | ||
| csv = <<~CSV | ||
| #{expected_headers.join(",")} |
There was a problem hiding this comment.
Can we make the entire value explicit please? We should know/specify the partner names and the storage location names. We should also know the headers.
There was a problem hiding this comment.
OK, I just thought it would be really long.
| expect(subject[idx + 1]).to eq(row) | ||
| csv = CSV.generate do |csv| | ||
| csv << expected_headers | ||
| csv << ["Product Drive", "2025-01-01", source_name(donations[0]), storage_location.name, 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"] |
There was a problem hiding this comment.
Here especially - we're calculating values rather than using them directly.
There was a problem hiding this comment.
The Faker gem generates names with commas, so I used CSV.generate to prevent test failures.
I’ve now replaced the comma in the name with a semicolon—please check if that's OK.
dorner
left a comment
There was a problem hiding this comment.
I'm good with this. In the future, if you need to compare/assert against any value, I'd recommend hardcoding that value instead of relying on Faker.
|
@nozomirin: Your PR |
…be added in export of donations and distributions (rubyforgood#5122) * Add an option to control whether "in-kind value" of each item should be added in export of donations and distributions * Change 'Configuring exports' to 'Exports' in getting_started_customization.md * Fix: Explicitly define test data and address money conversion problems. * fix: linter errors. * Fix: simplify the include_in_kind_values_in_exported_files column migration. * Fix: simplify the way to add In-Kind Total Value in csv file. * Fix: change from asserting each line in the CSV to asserting the entire CSV at once. * Fix: use <<~CSV...CSV to replace array based csv construction. * Fix: solve test error when the donation_site name contains comma. * Fix: make export csv header more explicit in distribution and donation tests.
Resolves #4858
Sorry for leaving it untouched for a long time. Since it is far behind the main branch, I made a new PR.
the original one is #4897.
Description
in-kind valuefor each item in exported donation and distribution files when theInclude in-kind value in donation and distribution exports?is set toyes.Note: I changed the "In-Kind Value" header to "In-Kind Total" in the exported donation file to avoid ambiguity. However, I used "Header + In-Kind Value" for the in-kind value of items, so perhaps the change is unnecessary. If there’s anything incorrect or unclear, please let me know.
Type of change
How Has This Been Tested?
Screenshots