From 9ae4c06d47ae908f10fa789f106321849df867f5 Mon Sep 17 00:00:00 2001 From: elasticspoon Date: Thu, 4 Jul 2024 14:49:22 -0400 Subject: [PATCH 1/2] feat: improve child functionality Co-authored-by: isidzukuri --- .../partners/children_controller.rb | 4 +- .../partners/family_requests_controller.rb | 4 +- app/helpers/partners_helper.rb | 7 +++ app/models/partners/child.rb | 5 +- .../partners/children/_child.json.jbuilder | 2 +- app/views/partners/children/_form.html.erb | 31 ++++++---- app/views/partners/children/show.html.erb | 2 +- .../partners/family_requests/_list.html.erb | 6 +- ...174254_create_join_table_children_items.rb | 8 +++ ..._backfill_partner_child_requested_items.rb | 7 +++ db/schema.rb | 9 ++- db/seeds.rb | 4 +- spec/factories/partners/child.rb | 3 +- spec/models/partners/child_spec.rb | 1 + .../partners/children_requests_spec.rb | 10 ++-- .../family_requests_controller_spec.rb | 2 +- spec/system/partners/children_system_spec.rb | 36 ++++++++++++ .../partners/family_requests_system_spec.rb | 58 ++++++++++++++----- 18 files changed, 153 insertions(+), 46 deletions(-) create mode 100644 db/migrate/20240703174254_create_join_table_children_items.rb create mode 100644 db/migrate/20240704214509_backfill_partner_child_requested_items.rb create mode 100644 spec/system/partners/children_system_spec.rb diff --git a/app/controllers/partners/children_controller.rb b/app/controllers/partners/children_controller.rb index b0e6047557..74b842f7bd 100644 --- a/app/controllers/partners/children_controller.rb +++ b/app/controllers/partners/children_controller.rb @@ -82,11 +82,11 @@ def child_params :first_name, :gender, :health_insurance, - :item_needed_diaperid, :last_name, :race, :archived, - child_lives_with: [] + child_lives_with: [], + requested_item_ids: [] ) end diff --git a/app/controllers/partners/family_requests_controller.rb b/app/controllers/partners/family_requests_controller.rb index ff91b4b9bc..6b8dc44051 100644 --- a/app/controllers/partners/family_requests_controller.rb +++ b/app/controllers/partners/family_requests_controller.rb @@ -23,9 +23,9 @@ def create end end - children = current_partner.children.active.where(id: children_ids).where.not(item_needed_diaperid: [nil, 0]) + children = current_partner.children.active.where(id: children_ids).joins(:requested_items).select('children.*', :item_id) - children_grouped_by_item_id = children.group_by(&:item_needed_diaperid) + children_grouped_by_item_id = children.group_by(&:item_id) family_requests_attributes = children_grouped_by_item_id.map do |item_id, item_requested_children| { item_id: item_id, person_count: item_requested_children.size, children: item_requested_children } end diff --git a/app/helpers/partners_helper.rb b/app/helpers/partners_helper.rb index 6a8e8b87b3..fcf9f498c9 100644 --- a/app/helpers/partners_helper.rb +++ b/app/helpers/partners_helper.rb @@ -1,5 +1,12 @@ # Encapsulates methods that need some business logic module PartnersHelper + def display_requested_items(partner, child) + ids = child.requested_item_ids + ids.map do |item_id| + partner.organization.item_id_to_display_string_map[item_id] + end.join(', ') + end + def show_header_column_class(partner, additional_classes: "") if partner.quota.present? "col-sm-3 col-3 #{additional_classes}" diff --git a/app/models/partners/child.rb b/app/models/partners/child.rb index 1421bd47a1..c64eba620c 100644 --- a/app/models/partners/child.rb +++ b/app/models/partners/child.rb @@ -25,6 +25,7 @@ class Child < Base serialize :child_lives_with, Array belongs_to :family has_many :child_item_requests, dependent: :destroy + has_and_belongs_to_many :requested_items, class_name: 'Item' include Filterable include Exportable @@ -88,7 +89,7 @@ def display_name def self.csv_export_headers %w[ id first_name last_name date_of_birth gender child_lives_with race agency_child_id - health_insurance comments created_at updated_at family_id item_needed_diaperid active archived + health_insurance comments created_at updated_at family_id requested_item_ids active archived ].freeze end @@ -107,7 +108,7 @@ def csv_export_attributes created_at, updated_at, family_id, - item_needed_diaperid, + requested_item_ids, active, archived ] diff --git a/app/views/partners/children/_child.json.jbuilder b/app/views/partners/children/_child.json.jbuilder index 63ae89cc65..98be8b3f55 100644 --- a/app/views/partners/children/_child.json.jbuilder +++ b/app/views/partners/children/_child.json.jbuilder @@ -1,2 +1,2 @@ -json.extract! child, :id, :first_name, :last_name, :date_of_birth, :gender, :child_lives_with, :race, :agency_child_id, :health_insurance, :item_needed_diaperid, :comments, :created_at, :updated_at +json.extract! child, :id, :first_name, :last_name, :date_of_birth, :gender, :child_lives_with, :race, :agency_child_id, :health_insurance, :requested_item_ids, :comments, :created_at, :updated_at json.url child_url(child, format: :json) diff --git a/app/views/partners/children/_form.html.erb b/app/views/partners/children/_form.html.erb index 8bd2ac2725..434551dbdf 100644 --- a/app/views/partners/children/_form.html.erb +++ b/app/views/partners/children/_form.html.erb @@ -16,11 +16,21 @@ <%= form.label :last_name, "Last Name" %> <%= form.text_field :last_name, class: "form-control" %> - <%= form.label :item_needed, "Diaper/Item Used" %> - <%= form.select :item_needed_diaperid, @requestable_items, - {include_blank: 'Select an item'}, - {class: 'form-control'} %> +
+ <%= form.label :item_needed, "Items Requested" %> + <%= form.select( + :requested_item_ids, + @requestable_items, + { include_hidden: true }, + { + multiple: true, + class: "form-control custom-select", + "data-controller": "select2", + "data-select2-config-value": "{}", + }, + ) %>
+
<%= form.input :date_of_birth, as: :date, start_year: 20.years.ago.year, end_year: Time.current.year, label: "Date of Birth" %> <%= form.input :gender, collection: ["Male", "Female"], class: "form-control" %> @@ -53,16 +63,15 @@ <%= form.label "Archived?" %>  <%= form.check_box :archived %> - - <% end %> - - + + - - - + + + + diff --git a/app/views/partners/children/show.html.erb b/app/views/partners/children/show.html.erb index 45e28aa0ed..e76fc86cd4 100644 --- a/app/views/partners/children/show.html.erb +++ b/app/views/partners/children/show.html.erb @@ -59,7 +59,7 @@
<%= @child.health_insurance %>
Item needed:
-
<%= current_partner.organization.item_id_to_display_string_map[@child.item_needed_diaperid] %>
+
<%= display_requested_items(current_partner, @child) %>
Comments:
<%= @child.comments %>
diff --git a/app/views/partners/family_requests/_list.html.erb b/app/views/partners/family_requests/_list.html.erb index 2b350f25b1..9be1448a55 100644 --- a/app/views/partners/family_requests/_list.html.erb +++ b/app/views/partners/family_requests/_list.html.erb @@ -18,15 +18,15 @@ <%= child.first_name %> <%= child.last_name %> - <% if child.item_needed_diaperid %> - <%= current_partner.organization.item_id_to_display_string_map[child.item_needed_diaperid] %> + <% if child.requested_item_ids.any? %> + <%= display_requested_items(current_partner, child) %> <% else %> <%= "N/A" %> <% end %>
- <% if child.item_needed_diaperid %> + <% if child.requested_item_ids.any? %> <%= check_box_tag "child-#{child.id}", child.active, child.active, class: "custom-control-input", id: "child-#{child.id}" %> diff --git a/db/migrate/20240703174254_create_join_table_children_items.rb b/db/migrate/20240703174254_create_join_table_children_items.rb new file mode 100644 index 0000000000..6250f20a04 --- /dev/null +++ b/db/migrate/20240703174254_create_join_table_children_items.rb @@ -0,0 +1,8 @@ +class CreateJoinTableChildrenItems < ActiveRecord::Migration[7.1] + def change + create_join_table :children, :items do |t| + t.index [:child_id, :item_id], unique: true + t.index [:item_id, :child_id], unique: true + end + end +end diff --git a/db/migrate/20240704214509_backfill_partner_child_requested_items.rb b/db/migrate/20240704214509_backfill_partner_child_requested_items.rb new file mode 100644 index 0000000000..9e4cdba70d --- /dev/null +++ b/db/migrate/20240704214509_backfill_partner_child_requested_items.rb @@ -0,0 +1,7 @@ +class BackfillPartnerChildRequestedItems < ActiveRecord::Migration[7.1] + def change + Partners::Child.unscoped.where.not(item_needed_diaperid: nil).each do |child| + child.requested_items << Item.find_by(id: child.item_needed_diaperid) + end + end +end diff --git a/db/schema.rb b/db/schema.rb index bcbb2930f3..8cf2594a08 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_06_24_185108) do +ActiveRecord::Schema[7.1].define(version: 2024_07_04_214509) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -188,6 +188,13 @@ t.index ["family_id"], name: "index_children_on_family_id" end + create_table "children_items", id: false, force: :cascade do |t| + t.bigint "child_id", null: false + t.bigint "item_id", null: false + t.index ["child_id", "item_id"], name: "index_children_items_on_child_id_and_item_id", unique: true + t.index ["item_id", "child_id"], name: "index_children_items_on_item_id_and_child_id", unique: true + end + create_table "counties", force: :cascade do |t| t.string "name" t.string "region" diff --git a/db/seeds.rb b/db/seeds.rb index 0a138b6301..1ae3d95ad3 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -316,7 +316,7 @@ def random_record_for_org(org, klass) comments: Faker::Lorem.paragraph, active: Faker::Boolean.boolean, archived: false, - item_needed_diaperid: p.organization.item_id_to_display_string_map.key(Partners::Child::CHILD_ITEMS.sample) + requested_item_ids: [p.organization.item_id_to_display_string_map.key(Partners::Child::CHILD_ITEMS.sample)] ) end @@ -334,7 +334,7 @@ def random_record_for_org(org, klass) comments: Faker::Lorem.paragraph, active: Faker::Boolean.boolean, archived: false, - item_needed_diaperid: p.organization.item_id_to_display_string_map.key(Partners::Child::CHILD_ITEMS.sample) + requested_item_ids: [p.organization.item_id_to_display_string_map.key(Partners::Child::CHILD_ITEMS.sample)] ) end end diff --git a/spec/factories/partners/child.rb b/spec/factories/partners/child.rb index cf6a20204f..ea035bf620 100644 --- a/spec/factories/partners/child.rb +++ b/spec/factories/partners/child.rb @@ -9,7 +9,6 @@ first_name { Faker::Name.first_name } last_name { Faker::Name.last_name } gender { Faker::Gender.binary_type } - # TODO: change when closing #4199 - item_needed_diaperid { Item.all.sample&.id || create(:item, organization: family.partner.organization).id } + requested_item_ids { [create(:item, organization: family.partner.organization).id] } end end diff --git a/spec/models/partners/child_spec.rb b/spec/models/partners/child_spec.rb index 3e58946bb1..c95bec16de 100644 --- a/spec/models/partners/child_spec.rb +++ b/spec/models/partners/child_spec.rb @@ -25,6 +25,7 @@ describe 'associations' do it { should belong_to(:family) } it { should have_many(:child_item_requests).dependent(:destroy) } + it { should have_and_belong_to_many(:requested_items).class_name('Item') } end describe "#display_name" do diff --git a/spec/requests/partners/children_requests_spec.rb b/spec/requests/partners/children_requests_spec.rb index ca42e7386a..3deb22b3cf 100644 --- a/spec/requests/partners/children_requests_spec.rb +++ b/spec/requests/partners/children_requests_spec.rb @@ -4,6 +4,8 @@ let(:partner_user) { partner.primary_user } let(:partner) { create(:partner) } let(:family) { create(:partners_family, partner: partner) } + let(:item1) { create(:item, organization: partner.organization) } + let(:item2) { create(:item, organization: partner.organization) } let!(:child1) do create(:partners_child, first_name: "John", @@ -15,7 +17,7 @@ agency_child_id: "Agency McAgence", health_insurance: "Private insurance", comments: "Some comment", - item_needed_diaperid: nil, + requested_item_ids: nil, active: true, archived: false, family: family) @@ -31,9 +33,9 @@ agency_child_id: "Agency McAgence", health_insurance: "Private insurance", comments: "Some comment", - item_needed_diaperid: nil, active: true, archived: false, + requested_item_ids: [item1.id, item2.id], family: family) end @@ -51,9 +53,9 @@ headers = {"Accept" => "text/csv", "Content-Type" => "text/csv"} get partners_children_path, headers: headers csv = <<~CSV - id,first_name,last_name,date_of_birth,gender,child_lives_with,race,agency_child_id,health_insurance,comments,created_at,updated_at,family_id,item_needed_diaperid,active,archived + id,first_name,last_name,date_of_birth,gender,child_lives_with,race,agency_child_id,health_insurance,comments,created_at,updated_at,family_id,requested_item_ids,active,archived #{child1.id},John,Smith,2019-01-01,Male,"mother,grandfather",Other,Agency McAgence,Private insurance,Some comment,#{child1.created_at},#{child1.updated_at},#{family.id},"",true,false - #{child2.id},Jane,Smith,2018-01-01,Female,father,Hispanic,Agency McAgence,Private insurance,Some comment,#{child2.created_at},#{child2.updated_at},#{family.id},"",true,false + #{child2.id},Jane,Smith,2018-01-01,Female,father,Hispanic,Agency McAgence,Private insurance,Some comment,#{child2.created_at},#{child2.updated_at},#{family.id},"#{item1.id},#{item2.id}",true,false CSV expect(response.body).to eq(csv) end diff --git a/spec/requests/partners/family_requests_controller_spec.rb b/spec/requests/partners/family_requests_controller_spec.rb index 04b17f75f2..47e9c603ed 100644 --- a/spec/requests/partners/family_requests_controller_spec.rb +++ b/spec/requests/partners/family_requests_controller_spec.rb @@ -34,7 +34,7 @@ # Set one child as deactivated and the other as active but # without a item_needed_diaperid children[0].update(active: false) - children[1].update(item_needed_diaperid: nil) + children[1].update(requested_item_ids: []) end subject { post partners_family_requests_path, params: params } diff --git a/spec/system/partners/children_system_spec.rb b/spec/system/partners/children_system_spec.rb new file mode 100644 index 0000000000..25b2531138 --- /dev/null +++ b/spec/system/partners/children_system_spec.rb @@ -0,0 +1,36 @@ +RSpec.describe "Creating a parner child", type: :system, js: true do + let(:organization) { create(:organization) } + let(:partner) { FactoryBot.create(:partner, organization: organization) } + let(:partner_user) { partner.primary_user } + let(:family) { create(:partners_family, guardian_first_name: "Main", guardian_last_name: "Family", partner: partner) } + + before do + partner.update(status: :approved) + login_as(partner_user) + create(:item, name: "Item 1", organization: organization) + create(:item, name: "Item 2", organization: organization) + end + + describe "creating a child for a family" do + it "creates a child with correct info" do + visit new_partners_child_path(family_id: family.id) + fill_in "First Name", with: "Child First Name" + fill_in "Last Name", with: "Child Last Name" + select "Other", from: "Race" + fill_in "Agency Child ID", with: "01234" + fill_in "Comments", with: "Some Comment" + + select2(page, "requestable-items-container", "Item 2") + select2(page, "requestable-items-container", "Item 1") + + click_button "Create Child" + + expect(page).to have_text("Child was successfully created.") + expect(page).to have_text("Child First Name") + expect(page).to have_text("Child Last Name") + expect(page).to have_text("01234") + expect(page).to have_text("Some Comment") + expect(page).to have_text("Item 1, Item 2") + end + end +end diff --git a/spec/system/partners/family_requests_system_spec.rb b/spec/system/partners/family_requests_system_spec.rb index e1030f284a..08b416506c 100644 --- a/spec/system/partners/family_requests_system_spec.rb +++ b/spec/system/partners/family_requests_system_spec.rb @@ -1,8 +1,8 @@ RSpec.describe "Family requests", type: :system, js: true do let(:partner) { FactoryBot.create(:partner) } let(:partner_user) { partner.primary_user } - let(:family) { create(:partners_family, guardian_last_name: "Morales", partner: partner) } - let(:other_family) { create(:partners_family, partner: partner) } + let(:family) { create(:partners_family, guardian_first_name: "Main", guardian_last_name: "Family", partner: partner) } + let(:other_family) { create(:partners_family, partner: partner, guardian_first_name: "Other", guardian_last_name: "Family") } before do partner.update(status: :approved) @@ -10,26 +10,56 @@ end describe "for children with different items, from different families" do - let(:item_id) { Item.all.sample.id } - let!(:children) do - [ - create(:partners_child, family: family), - create(:partners_child, family: family, item_needed_diaperid: item_id), - create(:partners_child, family: family, item_needed_diaperid: item_id), - create(:partners_child, family: other_family, item_needed_diaperid: item_id), - create(:partners_child, family: other_family) - ] + let(:item1) { create(:item, name: "Item 1") } + let(:item2) { create(:item, name: "Item 2") } + let(:item3) { create(:item, name: "Item 3") } + + before do + create(:partners_child, family: family, first_name: "Main", last_name: "No Items", requested_item_ids: nil) + create(:partners_child, family: family, first_name: "Main", last_name: "Items1", requested_item_ids: [item1.id, item2.id]) + create(:partners_child, family: family, first_name: "Main", last_name: "Items2", requested_item_ids: [item2.id, item3.id]) + create(:partners_child, first_name: "Other", last_name: "Items", family: other_family, requested_item_ids: [item1.id, item2.id]) + create(:partners_child, first_name: "Other", last_name: "No Items", family: other_family, requested_item_ids: nil) end scenario "it creates family requests" do visit partners_requests_path find('a[aria-label="Create a request for a child or family"]').click + + within("table tbody tr", text: "Main Items1") do |row| + expect(row).to have_css("td", text: "Main Family") + expect(row).to have_css("td", text: "Main Items1") + expect(row).to have_css("td", text: "Item 1, Item 2") + end + + within("table tbody tr", text: "Main Items2") do |row| + expect(row).to have_css("td", text: "Main Family") + expect(row).to have_css("td", text: "Main Items2") + expect(row).to have_css("td", text: "Item 2, Item 3") + end + + within("table tbody tr", text: "Main No Items") do |row| + expect(row).to have_css("td", text: "Main Family") + expect(row).to have_css("td", text: "Main No Items") + expect(row).to have_css("td", text: "N/A") + end + + within("table tbody tr", text: "Other Items") do |row| + expect(row).to have_css("td", text: "Other Family") + expect(row).to have_css("td", text: "Other Items") + expect(row).to have_css("td", text: "Item 1, Item 2") + end + + within("table tbody tr", text: "Other No Items") do |row| + expect(row).to have_css("td", text: "Other Family") + expect(row).to have_css("td", text: "Other No Items") + expect(row).to have_css("td", text: "N/A") + end + find('input[type="submit"]').click expect(page).to have_text("Request Details") click_link "Your Previous Requests" expect(page).to have_text("Request History") - expect(Partners::ChildItemRequest.pluck(:child_id)).to match_array(children.pluck(:id)) - expect(Partners::ItemRequest.pluck(:item_id)).to match_array(children.pluck(:item_needed_diaperid).uniq) end end @@ -53,7 +83,7 @@ visit partners_requests_path find('a[aria-label="Create a request for a child or family"]').click expect(page).to have_css("table tbody tr", count: 3) - fill_in "Search By Guardian Name", with: "Morales" + fill_in "Search By Guardian Name", with: "Main Family" expect(page).to have_text("Zeno") expect(page).to have_text("Arthur") expect(page).to_not have_text("Louis") From e930b709dda5bac8c077743ce815f61c0c6c1c8d Mon Sep 17 00:00:00 2001 From: elasticspoon Date: Tue, 9 Jul 2024 23:41:56 -0400 Subject: [PATCH 2/2] fix: review comments fix seen to ensure only requestable items seeded fix item to items --- app/views/partners/children/_form.html.erb | 3 ++- app/views/partners/children/show.html.erb | 2 +- db/seeds.rb | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/views/partners/children/_form.html.erb b/app/views/partners/children/_form.html.erb index 434551dbdf..3f11457e9f 100644 --- a/app/views/partners/children/_form.html.erb +++ b/app/views/partners/children/_form.html.erb @@ -16,8 +16,9 @@ <%= form.label :last_name, "Last Name" %> <%= form.text_field :last_name, class: "form-control" %> + <%= @requestable_items.map(&:last).intersect?(child.requested_item_ids) %>
- <%= form.label :item_needed, "Items Requested" %> + <%= form.label :item_needed, "Item(s) Requested" %> <%= form.select( :requested_item_ids, @requestable_items, diff --git a/app/views/partners/children/show.html.erb b/app/views/partners/children/show.html.erb index e76fc86cd4..3b5eb21949 100644 --- a/app/views/partners/children/show.html.erb +++ b/app/views/partners/children/show.html.erb @@ -58,7 +58,7 @@
Health insurance:
<%= @child.health_insurance %>
-
Item needed:
+
Item(s) needed:
<%= display_requested_items(current_partner, @child) %>
Comments:
diff --git a/db/seeds.rb b/db/seeds.rb index 1ae3d95ad3..e5ab8f6030 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -292,6 +292,8 @@ def random_record_for_org(org, klass) ) end + requestable_items = PartnerFetchRequestableItemsService.new(partner_id: p.id).call.map(&:last) + families.each do |family| Partners::AuthorizedFamilyMember.create!( first_name: Faker::Name.first_name, @@ -316,7 +318,7 @@ def random_record_for_org(org, klass) comments: Faker::Lorem.paragraph, active: Faker::Boolean.boolean, archived: false, - requested_item_ids: [p.organization.item_id_to_display_string_map.key(Partners::Child::CHILD_ITEMS.sample)] + requested_item_ids: requestable_items.sample(rand(4)) ) end @@ -334,7 +336,7 @@ def random_record_for_org(org, klass) comments: Faker::Lorem.paragraph, active: Faker::Boolean.boolean, archived: false, - requested_item_ids: [p.organization.item_id_to_display_string_map.key(Partners::Child::CHILD_ITEMS.sample)] + requested_item_ids: requestable_items.sample(rand(4)) ) end end