diff --git a/app/models/concerns/family_linkable.rb b/app/models/concerns/family_linkable.rb index 252211e161..3271f64f6c 100644 --- a/app/models/concerns/family_linkable.rb +++ b/app/models/concerns/family_linkable.rb @@ -76,24 +76,23 @@ def update_family_fields(properties) def update_family_members(properties) return unless family.present? && properties.key?('family_details_section') - family_details_section_data = properties.delete('family_details_section') - return unless family_details_section_data.present? + new_family_details_section = properties.delete('family_details_section') + return unless new_family_details_section.present? - family_members = FamilyLinkageService.build_or_update_family_members( - family_details_section_data, - family.family_members || [] + family_members_changes = FamilyLinkageService.build_family_members_for_details( + family_details_section, new_family_details_section ) - family.family_members = family_members if family_members.present? - update_local_family_details(family_details_section_data) + family.family_members = RecordMergeDataHashService.merge_data(family.family_members || [], family_members_changes) + update_local_family_details(new_family_details_section) end - def update_local_family_details(family_details_section_data) - self.family_details_section = family_details_section_data.map do |family_detail| - existing_detail = family_details_section&.find { |existing| existing['unique_id'] == family_detail['unique_id'] } - next(FamilyLinkageService.local_family_detail_data(family_detail)) unless existing_detail.present? + def update_local_family_details(new_family_details_section) + return unless new_family_details_section.present? - existing_detail.merge(FamilyLinkageService.local_family_detail_data(family_detail)) - end + local_family_details_section = FamilyLinkageService.family_details_local_changes(new_family_details_section) + self.family_details_section = RecordMergeDataHashService.merge_data( + family_details_section || [], local_family_details_section + ) end def family_members_details @@ -125,11 +124,10 @@ def family_changes(changes) return FamilyLinkageService::GLOBAL_FAMILY_FIELDS + ['family_details_section'] end - field_names = [] - return field_names unless family.present? + return [] unless family.present? + field_names = FamilyLinkageService::GLOBAL_FAMILY_FIELDS & family.saved_changes_to_record.keys field_names << 'family_details_section' if family.family_members_changed? - field_names += FamilyLinkageService::GLOBAL_FAMILY_FIELDS & family.saved_changes_to_record.keys field_names end end diff --git a/app/services/family_linkage_service.rb b/app/services/family_linkage_service.rb index dd82b1aa07..c147ff67e0 100644 --- a/app/services/family_linkage_service.rb +++ b/app/services/family_linkage_service.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true # Generates a case from the family -# rubocop:disable Metrics/ClassLength class FamilyLinkageService LOCAL_FAMILY_MEMBER_FIELDS = %w[ family_relationship family_relation_is_caregiver family_relationship_notes family_relationship_notes_additional @@ -53,7 +52,7 @@ def new_family_linked_child(user, source_case, family_detail_id) def link_child_to_new_family(user, child) family = Family.new_with_user(user, child_to_family(child)) family.module_id = child.module_id - family.family_members = build_or_update_family_members(child.family_details_section, []) + family.family_members = build_family_members_for_details([], child.family_details_section) family_member = child_to_family_member(child) family.family_members << family_member @@ -118,43 +117,31 @@ def local_family_detail_data(family_detail) family_detail.slice('unique_id', *LOCAL_FAMILY_DETAIL_FIELDS) end - def build_or_update_family_members(family_details_section, family_members) - added_family_members = build_family_members(family_details_section, family_members) - updated_family_members = update_family_members(family_details_section, family_members) - - updated_family_members + added_family_members - end - - def build_family_members(family_details_section, family_members) - family_member_ids = family_members.map { |member| member['unique_id'] } - - family_details_section.each_with_object([]) do |detail, memo| - next unless family_member_ids.exclude?(detail['unique_id']) - - memo << family_detail_to_family_member(detail) + def build_family_members_for_details(old_family_details, new_family_details) + existing_unique_ids = old_family_details&.map { |detail| detail['unique_id'] } + new_family_details.map do |family_detail| + if existing_unique_ids&.any? { |id| id == family_detail['unique_id'] } + global_family_detail_data(family_detail) + else + family_detail_to_family_member(family_detail) + end end end - def update_family_members(family_details_section, family_members) - family_members.map do |family_member| - family_detail = family_details_section.find { |detail| family_member['unique_id'] == detail['unique_id'] } - next(family_member) unless family_detail.present? + def family_details_local_changes(family_details) + family_details.each_with_object([]) do |family_detail, memo| + next unless (family_detail.keys & LOCAL_FAMILY_DETAIL_FIELDS).present? - family_member.merge(global_family_detail_data(family_detail)) + memo << local_family_detail_data(family_detail) end end def family_detail_to_family_member(family_detail) FAMILY_DETAIL_MAPPING.each_with_object(global_family_detail_data(family_detail)) do |elem, memo| - next unless family_detail[elem['source']].present? + next unless family_detail.key?(elem['source']) memo[elem['target']] = family_detail[elem['source']] end end - - def family_details_section_local_data(family_details_section) - family_details_section.map { |family_detail| local_family_detail_data(family_detail) } - end end end -# rubocop:enable Metrics/ClassLength diff --git a/spec/models/concerns/family_linkable_spec.rb b/spec/models/concerns/family_linkable_spec.rb index 99ea0ac081..711f207bea 100644 --- a/spec/models/concerns/family_linkable_spec.rb +++ b/spec/models/concerns/family_linkable_spec.rb @@ -16,8 +16,8 @@ { family_number: '5fba4918', family_members: [ - { 'unique_id' => 'f5775818', 'relation_sex' => 'male' }, - { 'unique_id' => '14397418', 'relation_sex' => 'female' } + { 'unique_id' => '00001', 'relation_sex' => 'male' }, + { 'unique_id' => '00002', 'relation_sex' => 'female' } ] } ) @@ -30,8 +30,8 @@ child.family = family2 child.family_member_id = 'f5775818' child.family_details_section = [ - { 'unique_id' => 'f5775818' }, - { 'unique_id' => '14397418', 'relation' => 'mother', 'relation_name' => 'Name1' } + { 'unique_id' => '00001' }, + { 'unique_id' => '00002', 'relation' => 'mother', 'relation_name' => 'Name1' } ] child.save! child @@ -40,51 +40,149 @@ describe 'family_members_details' do it 'returns fields from family members and family details not including itself' do expect(child.family_members_details).to eq( - [{ 'unique_id' => '14397418', 'relation' => 'mother', 'relation_sex' => 'female', 'relation_name' => 'Name1' }] + [ + { 'unique_id' => '00001', 'relation_sex' => 'male' }, + { 'unique_id' => '00002', 'relation' => 'mother', 'relation_sex' => 'female', 'relation_name' => 'Name1' } + ] ) end + end + describe 'update_family_members' do it 'updates the family_members and does not change the family_details_section' do child.update_properties( - user, - { - 'family_details_section' => [ - { 'unique_id' => 'f5775818' }, - { 'unique_id' => '14397418', 'relation_name' => 'Name2' } - ] - } + user, { 'family_details_section' => [{ 'unique_id' => '00002', 'relation_name' => 'Name2' }] } ) child.save! child.reload expect( - child.family_members_details.find { |member| member['unique_id'] == '14397418' }['relation_name'] + child.family_members_details.find { |member| member['unique_id'] == '00002' }['relation_name'] ).to eq('Name2') expect( - child.family_details_section.find { |member| member['unique_id'] == '14397418' }['relation_name'] + child.family_details_section.find { |member| member['unique_id'] == '00002' }['relation_name'] ).to eq('Name1') end it 'updates the local family_details_section fields and does not change the family_members' do child.update_properties( - user, - { - 'family_details_section' => [ - { 'unique_id' => 'f5775818' }, - { 'unique_id' => '14397418', 'relation' => 'father' } - ] - } + user, { 'family_details_section' => [{ 'unique_id' => '00002', 'relation' => 'father' }] } ) child.save! child.reload expect( - child.family.family_members.find { |member| member['unique_id'] == '14397418' }['relation'] + child.family.family_members.find { |member| member['unique_id'] == '00002' }['relation'] ).to be_nil expect( - child.family_details_section.find { |member| member['unique_id'] == '14397418' }['relation'] + child.family_details_section.find { |member| member['unique_id'] == '00002' }['relation'] ).to eq('father') end + + context 'when the family detail is new' do + it 'maps family details to family members and leaves the family details only with local fields' do + child.update_properties( + user, + { + 'family_details_section' => [ + { + 'unique_id' => '00003', + 'relation_name' => 'Name3', + 'relation' => 'mother', + 'relation_is_caregiver' => false + } + ] + } + ) + child.save! + child.reload + + expect(child.family.family_members.find { |member| member['unique_id'] == '00003' }).to eq( + { + 'unique_id' => '00003', + 'relation_name' => 'Name3', + 'family_relationship' => 'mother', + 'family_relation_is_caregiver' => false + } + ) + expect(child.family_details_section.find { |member| member['unique_id'] == '00003' }).to eq( + { + 'unique_id' => '00003', + 'relation' => 'mother', + 'relation_is_caregiver' => false + } + ) + end + + it 'updates global fields in the family member and leaves the family details unchanged' do + child.update_properties( + user, { 'family_details_section' => [{ 'unique_id' => '00003', 'relation_name' => 'Name3' }] } + ) + child.save! + child.reload + + expect(child.family.family_members.find { |member| member['unique_id'] == '00003' }).to eq( + { 'unique_id' => '00003', 'relation_name' => 'Name3' } + ) + expect(child.family_details_section.size).to eq(2) + expect(child.family_details_section.find { |member| member['unique_id'] == '00003' }).to be_nil + end + end + + context 'when is a existing family detail' do + it 'updates local and global fields in the family details and family members' do + child.update_properties( + user, + { + 'family_details_section' => [ + { 'unique_id' => '00002', 'relation_name' => 'OtherName2', 'relation' => 'aunt' } + ] + } + ) + child.save! + child.reload + + expect(child.family.family_members.find { |member| member['unique_id'] == '00002' }).to eq( + { 'unique_id' => '00002', 'relation_name' => 'OtherName2', 'relation_sex' => 'female' } + ) + expect(child.family_details_section.size).to eq(2) + expect(child.family_details_section.find { |member| member['unique_id'] == '00002' }).to eq( + { 'unique_id' => '00002', 'relation_name' => 'Name1', 'relation' => 'aunt' } + ) + end + + it 'updates global fields in the family member and leaves the family detail unchanged' do + child.update_properties( + user, { 'family_details_section' => [{ 'unique_id' => '00002', 'relation_name' => 'OtherName2' }] } + ) + child.save! + child.reload + + expect(child.family.family_members.find { |member| member['unique_id'] == '00002' }).to eq( + { 'unique_id' => '00002', 'relation_name' => 'OtherName2', 'relation_sex' => 'female' } + ) + expect(child.family_details_section.size).to eq(2) + expect(child.family_details_section.find { |member| member['unique_id'] == '00002' }).to eq( + { 'unique_id' => '00002', 'relation_name' => 'Name1', 'relation' => 'mother' } + ) + end + + it 'updates local fields in the family details and leaves the family member unchanged' do + child.update_properties( + user, { 'family_details_section' => [{ 'unique_id' => '00002', 'relation' => 'aunt' }] } + ) + child.save! + child.reload + + expect(child.family.family_members.find { |member| member['unique_id'] == '00002' }).to eq( + { 'unique_id' => '00002', 'relation_sex' => 'female' } + ) + expect(child.family_details_section.size).to eq(2) + expect(child.family_details_section.find { |member| member['unique_id'] == '00002' }).to eq( + { 'unique_id' => '00002', 'relation_name' => 'Name1', 'relation' => 'aunt' } + ) + end + end end describe 'disassociate_from_family' do