class ConsentForm
Schema Information
Table name: consent_forms
id :bigint not null, primary key
address_line_1 :string
address_line_2 :string
address_postcode :string
address_town :string
archived_at :datetime
confirmation_sent_at :datetime
date_of_birth :date
education_setting :integer
ethnic_background :integer
ethnic_background_other :string
ethnic_group :integer
family_name :text
given_name :text
health_answers :jsonb not null
nhs_number :string
notes :text default(""), not null
parent_contact_method_other_details :string
parent_contact_method_type :string
parent_email :string
parent_full_name :string
parent_phone :string
parent_phone_receive_updates :boolean default(FALSE), not null
parent_relationship_other_name :string
parent_relationship_type :string
preferred_family_name :string
preferred_given_name :string
recorded_at :datetime
school_confirmed :boolean
use_preferred_name :boolean
created_at :datetime not null
updated_at :datetime not null
original_session_id :bigint
school_id :bigint
team_location_id :bigint not null
Indexes
index_consent_forms_on_nhs_number (nhs_number) index_consent_forms_on_original_session_id (original_session_id) index_consent_forms_on_recorded (id) WHERE (recorded_at IS NOT NULL) index_consent_forms_on_school_id (school_id) index_consent_forms_on_team_location_id (team_location_id) index_consent_forms_on_unmatched_and_not_archived (id) WHERE ((recorded_at IS NOT NULL) AND (archived_at IS NULL))
Foreign Keys
fk_rails_... (original_session_id => sessions.id) fk_rails_... (school_id => locations.id) fk_rails_... (team_location_id => team_locations.id)
Constants
- ETHNICITY_STEPS
- FOLLOW_UP_REQUIRED_REASONS
Attributes
Public Instance Methods
Source
# File app/models/consent_form.rb, line 421 def can_offer_injection_as_alternative? consent_form_programmes.select(&:response_given?).any?( &:vaccine_method_nasal? ) end
Source
# File app/models/consent_form.rb, line 427 def can_offer_without_gelatine? response_given? && consent_form_programmes.any? do it.programme.vaccine_may_contain_gelatine? && !it.programme.has_multiple_vaccine_methods? end end
Source
# File app/models/consent_form.rb, line 792 def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end
Source
# File app/models/consent_form.rb, line 402 def each_health_answer return if health_answers.empty? return to_enum(:each_health_answer) unless block_given? health_answer = health_answers.first seen_health_answers = Set.new loop do if seen_health_answers.include?(health_answer.object_id) raise "Infinite loop detected" end seen_health_answers << health_answer.object_id yield health_answer next_health_answer_index = health_answer.next_health_answer_index break unless next_health_answer_index health_answer = health_answers[next_health_answer_index] end end
Source
# File app/models/consent_form.rb, line 338 def ethnicity_steps = ETHNICITY_STEPS def wizard_steps refused_and_not_given = response_refused? && !response_given? refused_and_given = response_refused? && response_given? response_steps = ProgrammeGrouper .call(consent_form_programmes) .keys .map { :"response_#{it}" } [ :name, :date_of_birth, (:confirm_school if location_is_school?), (:education_setting if location_is_clinic?), (:school if choose_school?), :parent, (:contact_method if parent_phone.present?) ].compact + response_steps + [ (:without_gelatine if can_offer_without_gelatine?), (:reason_for_refusal if refused_and_not_given), ( if refused_and_not_given && reason_for_refusal_requires_notes? :reason_for_refusal_notes end ), ( if refused_and_not_given && qualifies_for_follow_up_discussion? :follow_up_discussion end ), (:injection_alternative if can_offer_injection_as_alternative?), (:address if response_given?), (:health_question if response_given?), (:reason_for_refusal if refused_and_given), ( if refused_and_given && reason_for_refusal_requires_notes? :reason_for_refusal_notes end ), ( if refused_and_given && qualifies_for_follow_up_discussion? :follow_up_discussion end ) ].compact + (Flipper.enabled?(:ethnicity_capture) && recorded? ? ETHNICITY_STEPS : []) end def recorded? = recorded_at != nil def matched? = consents.exists? def response_given? = consent_form_programmes.any?(&:response_given?) def response_refused? = consent_form_programmes.any?(&:response_refused?) def human_enum_name(attribute) Consent.human_enum_name(attribute, send(attribute)) end def each_health_answer return if health_answers.empty? return to_enum(:each_health_answer) unless block_given? health_answer = health_answers.first seen_health_answers = Set.new loop do if seen_health_answers.include?(health_answer.object_id) raise "Infinite loop detected" end seen_health_answers << health_answer.object_id yield health_answer next_health_answer_index = health_answer.next_health_answer_index break unless next_health_answer_index health_answer = health_answers[next_health_answer_index] end end def can_offer_injection_as_alternative? consent_form_programmes.select(&:response_given?).any?( &:vaccine_method_nasal? ) end def can_offer_without_gelatine? response_given? && consent_form_programmes.any? do it.programme.vaccine_may_contain_gelatine? && !it.programme.has_multiple_vaccine_methods? end end def reason_for_refusal_requires_notes? consent_form_programmes.any?(&:reason_for_refusal_requires_notes?) end def matched_patient @matched_patient ||= (matched_patients.sole if matched?) end def session @session ||= if original_session_is_accurate? original_session else find_appropriate_session || original_session end end def session_dates_are_accurate? # There are some cases where the dates for the session are not considered # accurate enough to show to users. # # Specifically, if the parent indicated that their child goes to a # different school to the one we sent the consent form for, and we've been # unable to match the consent form to a child, we consider the session # and therefore the dates to not be accurate enough to display. original_session_is_accurate? || (session.present? && matched?) end def programmes = consent_form_programmes.map(&:programme) def programme_types = consent_form_programmes.map(&:programme_type) def vaccines @vaccines ||= Vaccine.where(programme_type: programme_types) end def find_or_create_parent_with_relationship_to!(patient:) parent = Parent.match_existing( patient:, email: parent_email, phone: parent_phone, full_name: parent_full_name ) || Parent.new parent.update!( contact_method_other_details: parent_contact_method_other_details, contact_method_type: parent_contact_method_type, email: parent_email, full_name: parent_full_name, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates ) patient .parent_relationships .find_or_initialize_by(parent:) .update!( type: parent_relationship_type, other_name: parent_relationship_other_name ) parent end def summary_with_route if response_given? && response_refused? "Partial consent given (online)" elsif response_given? "Consent given (online)" elsif response_refused? "Consent refused (online)" end end def parent Parent.new( full_name: parent_full_name, email: parent_email, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates, contact_method_type: parent_contact_method_type, contact_method_other_details: parent_contact_method_other_details ) end def parent_relationship ParentRelationship.new( parent:, type: parent_relationship_type, other_name: parent_relationship_other_name ) end def match_with_patient!(patient, current_user:) ActiveRecord::Base.transaction do notify_log_entries.update_all(patient_id: patient.id) school_changed = patient.school_id != school_for_school_move.id if school_changed && !patient.deceased? && !patient.invalidated? SchoolMove.find_or_initialize_by(patient:).update!( school: school_for_school_move, academic_year:, source: :parental_consent_form ) end Consent.from_consent_form!(self, patient:, current_user:).each( &:invalidate_existing_triage_and_patient_specific_directions! ) end end def matches_contact_details_for?(patient:) # We assume `true` if the patient has no parents, otherwise we would send # warnings to these parents about their contact details not matching. return true if patient.parents.empty? patient.parents.any? do |parent| (parent.email.present? && parent_email == parent.email) || (parent.phone.present? && parent_phone == parent.phone) end end def school_for_school_move if school school elsif education_setting_home? team.home_educated_school else team.unknown_school end end def reason_for_refusal consent_form_programmes.find(&:response_refused?)&.reason_for_refusal end def reason_for_refusal=(value) consent_form_programmes .select(&:response_refused?) .each { it.reason_for_refusal = value } end def reset_follow_up_requested consent_form_programmes .select(&:response_refused?) .each { it.follow_up_requested = nil } end def reason_for_refusal_notes consent_form_programmes.find(&:response_refused?)&.notes end def reason_for_refusal_notes=(value) consent_form_programmes .select(&:response_refused?) .each { it.notes = value } end def follow_up_requested consent_form_programmes.find(&:response_refused?)&.follow_up_requested end def follow_up_requested=(value) consent_form_programmes .select(&:response_refused?) .each do it.follow_up_requested = ActiveModel::Type::Boolean.new.cast(value) end end def qualifies_for_follow_up_discussion? reason_for_refusal.in?(FOLLOW_UP_REQUIRED_REASONS) end def update_programme_responses case response when "given" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = false end when "given_injection" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = true # currently flu injection is to avoid gelatine end when "given_nasal" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[nasal] it.without_gelatine = false end when "given_one" consent_form_programmes.each do |consent_form_programme| consent_form_programme.response = if consent_form_programme.programme.type == chosen_programme "given" else "refused" end consent_form_programme.vaccine_methods = %w[injection] consent_form_programme.without_gelatine = false end when "refused" consent_form_programmes.each { it.response = "refused" } end end def update_injection_alternative vaccine_methods = if ActiveModel::Type::Boolean.new.cast(injection_alternative) %w[nasal injection] else %w[nasal] end consent_form_programmes.each do |consent_form_programme| if consent_form_programme.vaccine_method_nasal? consent_form_programme.vaccine_methods = vaccine_methods end end end def update_without_gelatine consent_form_programmes.each do |consent_form_programme| consent_form_programme.without_gelatine = without_gelatine end end def seed_health_questions return unless response_given? # If the health answers change due to the chosen vaccines changing, we # want to try and keep as much as what the parents already wrote intact. # We do this be saving the answers to the question title (as the IDs # and ordering can change). existing_health_answers = health_answers.each_with_object({}) do |health_answer, memo| memo[health_answer.question] = { response: health_answer.response, notes: health_answer.notes } end vaccines = consent_form_programmes.select(&:response_given?).flat_map(&:vaccines) self.health_answers = HealthAnswersDeduplicator .call(vaccines:) .map do |health_answer| if ( existing_health_answer = existing_health_answers[health_answer.question] ) health_answer.response = existing_health_answer[:response] health_answer.notes = existing_health_answer[:notes] end health_answer end end def notifier = Notifier::ConsentForm.new(self) private def original_session_is_accurate? # Some older consent forms don't have an original session. return false if original_session_id.nil? # Parent hasn't answered the question yet. return true if school_confirmed.nil? # Parent confirms the school is correct. school_confirmed || school_id == location_id end def find_appropriate_session # This tries to find the most appropriate session for this consent form. # It's used when generating links to patients in a session, or when # deciding which dates to show in an email. Under the hood, patients # belong to locations, not sessions. # # Although unlikely to happen in production, there can be a scenario # where multiple sessions at the same location offer the same programmes. # In this case, we have to make a guess about which is the most relevant # session. if location_is_clinic? || education_setting_home? || education_setting_none? return end session_location = school || location sessions_to_search = Session.joins(:team_location).where( team_location: { academic_year:, location: session_location, team: } ) year_group = matched_patient&.year_group(academic_year:) || date_of_birth&.academic_year&.to_year_group(academic_year:) sessions_to_search = if year_group sessions_to_search.where( "(?) >= ?", Session::ProgrammeYearGroup .select( "COUNT(DISTINCT session_programme_year_groups.programme_type)" ) .where("sessions.id = session_programme_year_groups.session_id") .where(programme_type: programme_types, year_group:), programme_types.count ) else sessions_to_search.has_all_programme_types_of(programme_types) end sessions_to_search.find(&:scheduled?) || sessions_to_search.find(&:unscheduled?) || sessions_to_search.first end def via_self_consent? = false def health_answers_valid? if health_question_number.present? unless health_answers[health_question_number].valid? errors.add(:base, "Health answer(s) invalid") return false end else each_health_answer do |health_answer| unless health_answer.valid? errors.add(:base, "Health answer(s) invalid") return false end end end true end def location_is_school? = location.gias_school? def location_is_clinic? = location.generic_clinic? || location.generic_school? def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false
Source
# File app/models/consent_form.rb, line 719 def find_appropriate_session # This tries to find the most appropriate session for this consent form. # It's used when generating links to patients in a session, or when # deciding which dates to show in an email. Under the hood, patients # belong to locations, not sessions. # # Although unlikely to happen in production, there can be a scenario # where multiple sessions at the same location offer the same programmes. # In this case, we have to make a guess about which is the most relevant # session. if location_is_clinic? || education_setting_home? || education_setting_none? return end session_location = school || location sessions_to_search = Session.joins(:team_location).where( team_location: { academic_year:, location: session_location, team: } ) year_group = matched_patient&.year_group(academic_year:) || date_of_birth&.academic_year&.to_year_group(academic_year:) sessions_to_search = if year_group sessions_to_search.where( "(?) >= ?", Session::ProgrammeYearGroup .select( "COUNT(DISTINCT session_programme_year_groups.programme_type)" ) .where("sessions.id = session_programme_year_groups.session_id") .where(programme_type: programme_types, year_group:), programme_types.count ) else sessions_to_search.has_all_programme_types_of(programme_types) end sessions_to_search.find(&:scheduled?) || sessions_to_search.find(&:unscheduled?) || sessions_to_search.first end
Source
# File app/models/consent_form.rb, line 472 def find_or_create_parent_with_relationship_to!(patient:) parent = Parent.match_existing( patient:, email: parent_email, phone: parent_phone, full_name: parent_full_name ) || Parent.new parent.update!( contact_method_other_details: parent_contact_method_other_details, contact_method_type: parent_contact_method_type, email: parent_email, full_name: parent_full_name, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates ) patient .parent_relationships .find_or_initialize_by(parent:) .update!( type: parent_relationship_type, other_name: parent_relationship_other_name ) parent end
Source
# File app/models/consent_form.rb, line 596 def follow_up_requested consent_form_programmes.find(&:response_refused?)&.follow_up_requested end
Source
# File app/models/consent_form.rb, line 600 def follow_up_requested=(value) consent_form_programmes .select(&:response_refused?) .each do it.follow_up_requested = ActiveModel::Type::Boolean.new.cast(value) end end
Source
# File app/models/consent_form.rb, line 771 def health_answers_valid? if health_question_number.present? unless health_answers[health_question_number].valid? errors.add(:base, "Health answer(s) invalid") return false end else each_health_answer do |health_answer| unless health_answer.valid? errors.add(:base, "Health answer(s) invalid") return false end end end true end
Source
# File app/models/consent_form.rb, line 398 def human_enum_name(attribute) Consent.human_enum_name(attribute, send(attribute)) end
Source
# File app/models/consent_form.rb, line 790 def location_is_clinic? = location.generic_clinic? || location.generic_school? def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false elsif school self.education_setting = "school" end end
Source
# File app/models/consent_form.rb, line 788 def location_is_school? = location.gias_school? def location_is_clinic? = location.generic_clinic? || location.generic_school? def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false elsif school self.education_setting = "school" end
Source
# File app/models/consent_form.rb, line 530 def match_with_patient!(patient, current_user:) ActiveRecord::Base.transaction do notify_log_entries.update_all(patient_id: patient.id) school_changed = patient.school_id != school_for_school_move.id if school_changed && !patient.deceased? && !patient.invalidated? SchoolMove.find_or_initialize_by(patient:).update!( school: school_for_school_move, academic_year:, source: :parental_consent_form ) end Consent.from_consent_form!(self, patient:, current_user:).each( &:invalidate_existing_triage_and_patient_specific_directions! ) end end
Source
# File app/models/consent_form.rb, line 392 def matched? = consents.exists? def response_given? = consent_form_programmes.any?(&:response_given?) def response_refused? = consent_form_programmes.any?(&:response_refused?) def human_enum_name(attribute) Consent.human_enum_name(attribute, send(attribute)) end def each_health_answer return if health_answers.empty? return to_enum(:each_health_answer) unless block_given? health_answer = health_answers.first seen_health_answers = Set.new loop do if seen_health_answers.include?(health_answer.object_id) raise "Infinite loop detected" end seen_health_answers << health_answer.object_id yield health_answer next_health_answer_index = health_answer.next_health_answer_index break unless next_health_answer_index health_answer = health_answers[next_health_answer_index] end end def can_offer_injection_as_alternative? consent_form_programmes.select(&:response_given?).any?( &:vaccine_method_nasal? ) end def can_offer_without_gelatine? response_given? && consent_form_programmes.any? do it.programme.vaccine_may_contain_gelatine? && !it.programme.has_multiple_vaccine_methods? end end def reason_for_refusal_requires_notes? consent_form_programmes.any?(&:reason_for_refusal_requires_notes?) end def matched_patient @matched_patient ||= (matched_patients.sole if matched?) end def session @session ||= if original_session_is_accurate? original_session else find_appropriate_session || original_session end end def session_dates_are_accurate? # There are some cases where the dates for the session are not considered # accurate enough to show to users. # # Specifically, if the parent indicated that their child goes to a # different school to the one we sent the consent form for, and we've been # unable to match the consent form to a child, we consider the session # and therefore the dates to not be accurate enough to display. original_session_is_accurate? || (session.present? && matched?) end def programmes = consent_form_programmes.map(&:programme) def programme_types = consent_form_programmes.map(&:programme_type) def vaccines @vaccines ||= Vaccine.where(programme_type: programme_types) end def find_or_create_parent_with_relationship_to!(patient:) parent = Parent.match_existing( patient:, email: parent_email, phone: parent_phone, full_name: parent_full_name ) || Parent.new parent.update!( contact_method_other_details: parent_contact_method_other_details, contact_method_type: parent_contact_method_type, email: parent_email, full_name: parent_full_name, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates ) patient .parent_relationships .find_or_initialize_by(parent:) .update!( type: parent_relationship_type, other_name: parent_relationship_other_name ) parent end def summary_with_route if response_given? && response_refused? "Partial consent given (online)" elsif response_given? "Consent given (online)" elsif response_refused? "Consent refused (online)" end end def parent Parent.new( full_name: parent_full_name, email: parent_email, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates, contact_method_type: parent_contact_method_type, contact_method_other_details: parent_contact_method_other_details ) end def parent_relationship ParentRelationship.new( parent:, type: parent_relationship_type, other_name: parent_relationship_other_name ) end def match_with_patient!(patient, current_user:) ActiveRecord::Base.transaction do notify_log_entries.update_all(patient_id: patient.id) school_changed = patient.school_id != school_for_school_move.id if school_changed && !patient.deceased? && !patient.invalidated? SchoolMove.find_or_initialize_by(patient:).update!( school: school_for_school_move, academic_year:, source: :parental_consent_form ) end Consent.from_consent_form!(self, patient:, current_user:).each( &:invalidate_existing_triage_and_patient_specific_directions! ) end end def matches_contact_details_for?(patient:) # We assume `true` if the patient has no parents, otherwise we would send # warnings to these parents about their contact details not matching. return true if patient.parents.empty? patient.parents.any? do |parent| (parent.email.present? && parent_email == parent.email) || (parent.phone.present? && parent_phone == parent.phone) end end def school_for_school_move if school school elsif education_setting_home? team.home_educated_school else team.unknown_school end end def reason_for_refusal consent_form_programmes.find(&:response_refused?)&.reason_for_refusal end def reason_for_refusal=(value) consent_form_programmes .select(&:response_refused?) .each { it.reason_for_refusal = value } end def reset_follow_up_requested consent_form_programmes .select(&:response_refused?) .each { it.follow_up_requested = nil } end def reason_for_refusal_notes consent_form_programmes.find(&:response_refused?)&.notes end def reason_for_refusal_notes=(value) consent_form_programmes .select(&:response_refused?) .each { it.notes = value } end def follow_up_requested consent_form_programmes.find(&:response_refused?)&.follow_up_requested end def follow_up_requested=(value) consent_form_programmes .select(&:response_refused?) .each do it.follow_up_requested = ActiveModel::Type::Boolean.new.cast(value) end end def qualifies_for_follow_up_discussion? reason_for_refusal.in?(FOLLOW_UP_REQUIRED_REASONS) end def update_programme_responses case response when "given" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = false end when "given_injection" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = true # currently flu injection is to avoid gelatine end when "given_nasal" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[nasal] it.without_gelatine = false end when "given_one" consent_form_programmes.each do |consent_form_programme| consent_form_programme.response = if consent_form_programme.programme.type == chosen_programme "given" else "refused" end consent_form_programme.vaccine_methods = %w[injection] consent_form_programme.without_gelatine = false end when "refused" consent_form_programmes.each { it.response = "refused" } end end def update_injection_alternative vaccine_methods = if ActiveModel::Type::Boolean.new.cast(injection_alternative) %w[nasal injection] else %w[nasal] end consent_form_programmes.each do |consent_form_programme| if consent_form_programme.vaccine_method_nasal? consent_form_programme.vaccine_methods = vaccine_methods end end end def update_without_gelatine consent_form_programmes.each do |consent_form_programme| consent_form_programme.without_gelatine = without_gelatine end end def seed_health_questions return unless response_given? # If the health answers change due to the chosen vaccines changing, we # want to try and keep as much as what the parents already wrote intact. # We do this be saving the answers to the question title (as the IDs # and ordering can change). existing_health_answers = health_answers.each_with_object({}) do |health_answer, memo| memo[health_answer.question] = { response: health_answer.response, notes: health_answer.notes } end vaccines = consent_form_programmes.select(&:response_given?).flat_map(&:vaccines) self.health_answers = HealthAnswersDeduplicator .call(vaccines:) .map do |health_answer| if ( existing_health_answer = existing_health_answers[health_answer.question] ) health_answer.response = existing_health_answer[:response] health_answer.notes = existing_health_answer[:notes] end health_answer end end def notifier = Notifier::ConsentForm.new(self) private def original_session_is_accurate? # Some older consent forms don't have an original session. return false if original_session_id.nil? # Parent hasn't answered the question yet. return true if school_confirmed.nil? # Parent confirms the school is correct. school_confirmed || school_id == location_id end def find_appropriate_session # This tries to find the most appropriate session for this consent form. # It's used when generating links to patients in a session, or when # deciding which dates to show in an email. Under the hood, patients # belong to locations, not sessions. # # Although unlikely to happen in production, there can be a scenario # where multiple sessions at the same location offer the same programmes. # In this case, we have to make a guess about which is the most relevant # session. if location_is_clinic? || education_setting_home? || education_setting_none? return end session_location = school || location sessions_to_search = Session.joins(:team_location).where( team_location: { academic_year:, location: session_location, team: } ) year_group = matched_patient&.year_group(academic_year:) || date_of_birth&.academic_year&.to_year_group(academic_year:) sessions_to_search = if year_group sessions_to_search.where( "(?) >= ?", Session::ProgrammeYearGroup .select( "COUNT(DISTINCT session_programme_year_groups.programme_type)" ) .where("sessions.id = session_programme_year_groups.session_id") .where(programme_type: programme_types, year_group:), programme_types.count ) else sessions_to_search.has_all_programme_types_of(programme_types) end sessions_to_search.find(&:scheduled?) || sessions_to_search.find(&:unscheduled?) || sessions_to_search.first end def via_self_consent? = false def health_answers_valid? if health_question_number.present? unless health_answers[health_question_number].valid? errors.add(:base, "Health answer(s) invalid") return false end else each_health_answer do |health_answer| unless health_answer.valid? errors.add(:base, "Health answer(s) invalid") return false end end end true end def location_is_school? = location.gias_school? def location_is_clinic? = location.generic_clinic? || location.generic_school? def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false elsif
Source
# File app/models/consent_form.rb, line 439 def matched_patient @matched_patient ||= (matched_patients.sole if matched?) end
Source
# File app/models/consent_form.rb, line 549 def matches_contact_details_for?(patient:) # We assume `true` if the patient has no parents, otherwise we would send # warnings to these parents about their contact details not matching. return true if patient.parents.empty? patient.parents.any? do |parent| (parent.email.present? && parent_email == parent.email) || (parent.phone.present? && parent_phone == parent.phone) end end
Source
# File app/models/consent_form.rb, line 704 def notifier = Notifier::ConsentForm.new(self) private def original_session_is_accurate? # Some older consent forms don't have an original session. return false if original_session_id.nil? # Parent hasn't answered the question yet. return true if school_confirmed.nil? # Parent confirms the school is correct. school_confirmed || school_id == location_id end def find_appropriate_session # This tries to find the most appropriate session for this consent form. # It's used when generating links to patients in a session, or when # deciding which dates to show in an email. Under the hood, patients # belong to locations, not sessions. # # Although unlikely to happen in production, there can be a scenario # where multiple sessions at the same location offer the same programmes. # In this case, we have to make a guess about which is the most relevant # session. if location_is_clinic? || education_setting_home? || education_setting_none? return end session_location = school || location sessions_to_search = Session.joins(:team_location).where( team_location: { academic_year:, location: session_location, team: } ) year_group = matched_patient&.year_group(academic_year:) || date_of_birth&.academic_year&.to_year_group(academic_year:) sessions_to_search = if year_group sessions_to_search.where( "(?) >= ?", Session::ProgrammeYearGroup .select( "COUNT(DISTINCT session_programme_year_groups.programme_type)" ) .where("sessions.id = session_programme_year_groups.session_id") .where(programme_type: programme_types, year_group:), programme_types.count ) else sessions_to_search.has_all_programme_types_of(programme_types) end sessions_to_search.find(&:scheduled?) || sessions_to_search.find(&:unscheduled?) || sessions_to_search.first end def via_self_consent? = false def health_answers_valid? if health_question_number.present? unless health_answers[health_question_number].valid? errors.add(:base, "Health answer(s) invalid") return false end else each_health_answer do |health_answer| unless health_answer.valid? errors.add(:base, "Health answer(s) invalid") return false end end end true end def location_is_school? = location.gias_school? def location_is_clinic? = location.generic_clinic? || location.generic_school? def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false elsif school self.education_setting = "school"
Source
# File app/models/consent_form.rb, line 708 def original_session_is_accurate? # Some older consent forms don't have an original session. return false if original_session_id.nil? # Parent hasn't answered the question yet. return true if school_confirmed.nil? # Parent confirms the school is correct. school_confirmed || school_id == location_id end
Source
# File app/models/consent_form.rb, line 511 def parent Parent.new( full_name: parent_full_name, email: parent_email, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates, contact_method_type: parent_contact_method_type, contact_method_other_details: parent_contact_method_other_details ) end
Source
# File app/models/consent_form.rb, line 522 def parent_relationship ParentRelationship.new( parent:, type: parent_relationship_type, other_name: parent_relationship_other_name ) end
Source
# File app/models/consent_form.rb, line 466 def programme_types = consent_form_programmes.map(&:programme_type) def vaccines @vaccines ||= Vaccine.where(programme_type: programme_types) end def find_or_create_parent_with_relationship_to!(patient:) parent = Parent.match_existing( patient:, email: parent_email, phone: parent_phone, full_name: parent_full_name ) || Parent.new parent.update!( contact_method_other_details: parent_contact_method_other_details, contact_method_type: parent_contact_method_type, email: parent_email, full_name: parent_full_name, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates ) patient .parent_relationships .find_or_initialize_by(parent:) .update!( type: parent_relationship_type, other_name: parent_relationship_other_name ) parent end def summary_with_route if response_given? && response_refused? "Partial consent given (online)" elsif response_given? "Consent given (online)" elsif response_refused? "Consent refused (online)" end end def parent Parent.new( full_name: parent_full_name, email: parent_email, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates, contact_method_type: parent_contact_method_type, contact_method_other_details: parent_contact_method_other_details ) end def parent_relationship ParentRelationship.new( parent:, type: parent_relationship_type, other_name: parent_relationship_other_name ) end def match_with_patient!(patient, current_user:) ActiveRecord::Base.transaction do notify_log_entries.update_all(patient_id: patient.id) school_changed = patient.school_id != school_for_school_move.id if school_changed && !patient.deceased? && !patient.invalidated? SchoolMove.find_or_initialize_by(patient:).update!( school: school_for_school_move, academic_year:, source: :parental_consent_form ) end Consent.from_consent_form!(self, patient:, current_user:).each( &:invalidate_existing_triage_and_patient_specific_directions! ) end end def matches_contact_details_for?(patient:) # We assume `true` if the patient has no parents, otherwise we would send # warnings to these parents about their contact details not matching. return true if patient.parents.empty? patient.parents.any? do |parent| (parent.email.present? && parent_email == parent.email) || (parent.phone.present? && parent_phone == parent.phone) end end def school_for_school_move if school school elsif education_setting_home? team.home_educated_school else team.unknown_school end end def reason_for_refusal consent_form_programmes.find(&:response_refused?)&.reason_for_refusal end def reason_for_refusal=(value) consent_form_programmes .select(&:response_refused?) .each { it.reason_for_refusal = value } end def reset_follow_up_requested consent_form_programmes .select(&:response_refused?) .each { it.follow_up_requested = nil } end def reason_for_refusal_notes consent_form_programmes.find(&:response_refused?)&.notes end def reason_for_refusal_notes=(value) consent_form_programmes .select(&:response_refused?) .each { it.notes = value } end def follow_up_requested consent_form_programmes.find(&:response_refused?)&.follow_up_requested end def follow_up_requested=(value) consent_form_programmes .select(&:response_refused?) .each do it.follow_up_requested = ActiveModel::Type::Boolean.new.cast(value) end end def qualifies_for_follow_up_discussion? reason_for_refusal.in?(FOLLOW_UP_REQUIRED_REASONS) end def update_programme_responses case response when "given" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = false end when "given_injection" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = true # currently flu injection is to avoid gelatine end when "given_nasal" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[nasal] it.without_gelatine = false end when "given_one" consent_form_programmes.each do |consent_form_programme| consent_form_programme.response = if consent_form_programme.programme.type == chosen_programme "given" else "refused" end consent_form_programme.vaccine_methods = %w[injection] consent_form_programme.without_gelatine = false end when "refused" consent_form_programmes.each { it.response = "refused" } end end def update_injection_alternative vaccine_methods = if ActiveModel::Type::Boolean.new.cast(injection_alternative) %w[nasal injection] else %w[nasal] end consent_form_programmes.each do |consent_form_programme| if consent_form_programme.vaccine_method_nasal? consent_form_programme.vaccine_methods = vaccine_methods end end end def update_without_gelatine consent_form_programmes.each do |consent_form_programme| consent_form_programme.without_gelatine = without_gelatine end end def seed_health_questions return unless response_given? # If the health answers change due to the chosen vaccines changing, we # want to try and keep as much as what the parents already wrote intact. # We do this be saving the answers to the question title (as the IDs # and ordering can change). existing_health_answers = health_answers.each_with_object({}) do |health_answer, memo| memo[health_answer.question] = { response: health_answer.response, notes: health_answer.notes } end vaccines = consent_form_programmes.select(&:response_given?).flat_map(&:vaccines) self.health_answers = HealthAnswersDeduplicator .call(vaccines:) .map do |health_answer| if ( existing_health_answer = existing_health_answers[health_answer.question] ) health_answer.response = existing_health_answer[:response] health_answer.notes = existing_health_answer[:notes] end health_answer end end def notifier = Notifier::ConsentForm.new(self) private def original_session_is_accurate? # Some older consent forms don't have an original session. return false if original_session_id.nil? # Parent hasn't answered the question yet. return true if school_confirmed.nil? # Parent confirms the school is correct. school_confirmed || school_id == location_id end def find_appropriate_session # This tries to find the most appropriate session for this consent form. # It's used when generating links to patients in a session, or when # deciding which dates to show in an email. Under the hood, patients # belong to locations, not sessions. # # Although unlikely to happen in production, there can be a scenario # where multiple sessions at the same location offer the same programmes. # In this case, we have to make a guess about which is the most relevant # session. if location_is_clinic? || education_setting_home? || education_setting_none? return end session_location = school || location sessions_to_search = Session.joins(:team_location).where( team_location: { academic_year:, location: session_location, team: } ) year_group = matched_patient&.year_group(academic_year:) || date_of_birth&.academic_year&.to_year_group(academic_year:) sessions_to_search = if year_group sessions_to_search.where( "(?) >= ?", Session::ProgrammeYearGroup .select( "COUNT(DISTINCT session_programme_year_groups.programme_type)" ) .where("sessions.id = session_programme_year_groups.session_id") .where(programme_type: programme_types, year_group:), programme_types.count ) else sessions_to_search.has_all_programme_types_of(programme_types) end sessions_to_search.find(&:scheduled?) || sessions_to_search.find(&:unscheduled?) || sessions_to_search.first end def via_self_consent? = false def health_answers_valid? if health_question_number.present? unless health_answers[health_question_number].valid? errors.add(:base, "Health answer(s) invalid") return false end else each_health_answer do |health_answer| unless health_answer.valid? errors.add(:base, "Health answer(s) invalid") return false end end end true end def location_is_school? = location.gias_school? def location_is_clinic? = location.generic_clinic? || location.generic_school? def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false elsif school self.education_setting =
Source
# File app/models/consent_form.rb, line 464 def programmes = consent_form_programmes.map(&:programme) def programme_types = consent_form_programmes.map(&:programme_type) def vaccines @vaccines ||= Vaccine.where(programme_type: programme_types) end def find_or_create_parent_with_relationship_to!(patient:) parent = Parent.match_existing( patient:, email: parent_email, phone: parent_phone, full_name: parent_full_name ) || Parent.new parent.update!( contact_method_other_details: parent_contact_method_other_details, contact_method_type: parent_contact_method_type, email: parent_email, full_name: parent_full_name, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates ) patient .parent_relationships .find_or_initialize_by(parent:) .update!( type: parent_relationship_type, other_name: parent_relationship_other_name ) parent end def summary_with_route if response_given? && response_refused? "Partial consent given (online)" elsif response_given? "Consent given (online)" elsif response_refused? "Consent refused (online)" end end def parent Parent.new( full_name: parent_full_name, email: parent_email, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates, contact_method_type: parent_contact_method_type, contact_method_other_details: parent_contact_method_other_details ) end def parent_relationship ParentRelationship.new( parent:, type: parent_relationship_type, other_name: parent_relationship_other_name ) end def match_with_patient!(patient, current_user:) ActiveRecord::Base.transaction do notify_log_entries.update_all(patient_id: patient.id) school_changed = patient.school_id != school_for_school_move.id if school_changed && !patient.deceased? && !patient.invalidated? SchoolMove.find_or_initialize_by(patient:).update!( school: school_for_school_move, academic_year:, source: :parental_consent_form ) end Consent.from_consent_form!(self, patient:, current_user:).each( &:invalidate_existing_triage_and_patient_specific_directions! ) end end def matches_contact_details_for?(patient:) # We assume `true` if the patient has no parents, otherwise we would send # warnings to these parents about their contact details not matching. return true if patient.parents.empty? patient.parents.any? do |parent| (parent.email.present? && parent_email == parent.email) || (parent.phone.present? && parent_phone == parent.phone) end end def school_for_school_move if school school elsif education_setting_home? team.home_educated_school else team.unknown_school end end def reason_for_refusal consent_form_programmes.find(&:response_refused?)&.reason_for_refusal end def reason_for_refusal=(value) consent_form_programmes .select(&:response_refused?) .each { it.reason_for_refusal = value } end def reset_follow_up_requested consent_form_programmes .select(&:response_refused?) .each { it.follow_up_requested = nil } end def reason_for_refusal_notes consent_form_programmes.find(&:response_refused?)&.notes end def reason_for_refusal_notes=(value) consent_form_programmes .select(&:response_refused?) .each { it.notes = value } end def follow_up_requested consent_form_programmes.find(&:response_refused?)&.follow_up_requested end def follow_up_requested=(value) consent_form_programmes .select(&:response_refused?) .each do it.follow_up_requested = ActiveModel::Type::Boolean.new.cast(value) end end def qualifies_for_follow_up_discussion? reason_for_refusal.in?(FOLLOW_UP_REQUIRED_REASONS) end def update_programme_responses case response when "given" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = false end when "given_injection" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = true # currently flu injection is to avoid gelatine end when "given_nasal" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[nasal] it.without_gelatine = false end when "given_one" consent_form_programmes.each do |consent_form_programme| consent_form_programme.response = if consent_form_programme.programme.type == chosen_programme "given" else "refused" end consent_form_programme.vaccine_methods = %w[injection] consent_form_programme.without_gelatine = false end when "refused" consent_form_programmes.each { it.response = "refused" } end end def update_injection_alternative vaccine_methods = if ActiveModel::Type::Boolean.new.cast(injection_alternative) %w[nasal injection] else %w[nasal] end consent_form_programmes.each do |consent_form_programme| if consent_form_programme.vaccine_method_nasal? consent_form_programme.vaccine_methods = vaccine_methods end end end def update_without_gelatine consent_form_programmes.each do |consent_form_programme| consent_form_programme.without_gelatine = without_gelatine end end def seed_health_questions return unless response_given? # If the health answers change due to the chosen vaccines changing, we # want to try and keep as much as what the parents already wrote intact. # We do this be saving the answers to the question title (as the IDs # and ordering can change). existing_health_answers = health_answers.each_with_object({}) do |health_answer, memo| memo[health_answer.question] = { response: health_answer.response, notes: health_answer.notes } end vaccines = consent_form_programmes.select(&:response_given?).flat_map(&:vaccines) self.health_answers = HealthAnswersDeduplicator .call(vaccines:) .map do |health_answer| if ( existing_health_answer = existing_health_answers[health_answer.question] ) health_answer.response = existing_health_answer[:response] health_answer.notes = existing_health_answer[:notes] end health_answer end end def notifier = Notifier::ConsentForm.new(self) private def original_session_is_accurate? # Some older consent forms don't have an original session. return false if original_session_id.nil? # Parent hasn't answered the question yet. return true if school_confirmed.nil? # Parent confirms the school is correct. school_confirmed || school_id == location_id end def find_appropriate_session # This tries to find the most appropriate session for this consent form. # It's used when generating links to patients in a session, or when # deciding which dates to show in an email. Under the hood, patients # belong to locations, not sessions. # # Although unlikely to happen in production, there can be a scenario # where multiple sessions at the same location offer the same programmes. # In this case, we have to make a guess about which is the most relevant # session. if location_is_clinic? || education_setting_home? || education_setting_none? return end session_location = school || location sessions_to_search = Session.joins(:team_location).where( team_location: { academic_year:, location: session_location, team: } ) year_group = matched_patient&.year_group(academic_year:) || date_of_birth&.academic_year&.to_year_group(academic_year:) sessions_to_search = if year_group sessions_to_search.where( "(?) >= ?", Session::ProgrammeYearGroup .select( "COUNT(DISTINCT session_programme_year_groups.programme_type)" ) .where("sessions.id = session_programme_year_groups.session_id") .where(programme_type: programme_types, year_group:), programme_types.count ) else sessions_to_search.has_all_programme_types_of(programme_types) end sessions_to_search.find(&:scheduled?) || sessions_to_search.find(&:unscheduled?) || sessions_to_search.first end def via_self_consent? = false def health_answers_valid? if health_question_number.present? unless health_answers[health_question_number].valid? errors.add(:base, "Health answer(s) invalid") return false end else each_health_answer do |health_answer| unless health_answer.valid? errors.add(:base, "Health answer(s) invalid") return false end end end true end def location_is_school? = location.gias_school? def location_is_clinic? = location.generic_clinic? || location.generic_school? def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false elsif school self.education_setting
Source
# File app/models/consent_form.rb, line 608 def qualifies_for_follow_up_discussion? reason_for_refusal.in?(FOLLOW_UP_REQUIRED_REASONS) end
Source
# File app/models/consent_form.rb, line 570 def reason_for_refusal consent_form_programmes.find(&:response_refused?)&.reason_for_refusal end
Source
# File app/models/consent_form.rb, line 574 def reason_for_refusal=(value) consent_form_programmes .select(&:response_refused?) .each { it.reason_for_refusal = value } end
Source
# File app/models/consent_form.rb, line 586 def reason_for_refusal_notes consent_form_programmes.find(&:response_refused?)&.notes end
Source
# File app/models/consent_form.rb, line 590 def reason_for_refusal_notes=(value) consent_form_programmes .select(&:response_refused?) .each { it.notes = value } end
Source
# File app/models/consent_form.rb, line 435 def reason_for_refusal_requires_notes? consent_form_programmes.any?(&:reason_for_refusal_requires_notes?) end
Source
# File app/models/consent_form.rb, line 390 def recorded? = recorded_at != nil def matched? = consents.exists? def response_given? = consent_form_programmes.any?(&:response_given?) def response_refused? = consent_form_programmes.any?(&:response_refused?) def human_enum_name(attribute) Consent.human_enum_name(attribute, send(attribute)) end def each_health_answer return if health_answers.empty? return to_enum(:each_health_answer) unless block_given? health_answer = health_answers.first seen_health_answers = Set.new loop do if seen_health_answers.include?(health_answer.object_id) raise "Infinite loop detected" end seen_health_answers << health_answer.object_id yield health_answer next_health_answer_index = health_answer.next_health_answer_index break unless next_health_answer_index health_answer = health_answers[next_health_answer_index] end end def can_offer_injection_as_alternative? consent_form_programmes.select(&:response_given?).any?( &:vaccine_method_nasal? ) end def can_offer_without_gelatine? response_given? && consent_form_programmes.any? do it.programme.vaccine_may_contain_gelatine? && !it.programme.has_multiple_vaccine_methods? end end def reason_for_refusal_requires_notes? consent_form_programmes.any?(&:reason_for_refusal_requires_notes?) end def matched_patient @matched_patient ||= (matched_patients.sole if matched?) end def session @session ||= if original_session_is_accurate? original_session else find_appropriate_session || original_session end end def session_dates_are_accurate? # There are some cases where the dates for the session are not considered # accurate enough to show to users. # # Specifically, if the parent indicated that their child goes to a # different school to the one we sent the consent form for, and we've been # unable to match the consent form to a child, we consider the session # and therefore the dates to not be accurate enough to display. original_session_is_accurate? || (session.present? && matched?) end def programmes = consent_form_programmes.map(&:programme) def programme_types = consent_form_programmes.map(&:programme_type) def vaccines @vaccines ||= Vaccine.where(programme_type: programme_types) end def find_or_create_parent_with_relationship_to!(patient:) parent = Parent.match_existing( patient:, email: parent_email, phone: parent_phone, full_name: parent_full_name ) || Parent.new parent.update!( contact_method_other_details: parent_contact_method_other_details, contact_method_type: parent_contact_method_type, email: parent_email, full_name: parent_full_name, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates ) patient .parent_relationships .find_or_initialize_by(parent:) .update!( type: parent_relationship_type, other_name: parent_relationship_other_name ) parent end def summary_with_route if response_given? && response_refused? "Partial consent given (online)" elsif response_given? "Consent given (online)" elsif response_refused? "Consent refused (online)" end end def parent Parent.new( full_name: parent_full_name, email: parent_email, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates, contact_method_type: parent_contact_method_type, contact_method_other_details: parent_contact_method_other_details ) end def parent_relationship ParentRelationship.new( parent:, type: parent_relationship_type, other_name: parent_relationship_other_name ) end def match_with_patient!(patient, current_user:) ActiveRecord::Base.transaction do notify_log_entries.update_all(patient_id: patient.id) school_changed = patient.school_id != school_for_school_move.id if school_changed && !patient.deceased? && !patient.invalidated? SchoolMove.find_or_initialize_by(patient:).update!( school: school_for_school_move, academic_year:, source: :parental_consent_form ) end Consent.from_consent_form!(self, patient:, current_user:).each( &:invalidate_existing_triage_and_patient_specific_directions! ) end end def matches_contact_details_for?(patient:) # We assume `true` if the patient has no parents, otherwise we would send # warnings to these parents about their contact details not matching. return true if patient.parents.empty? patient.parents.any? do |parent| (parent.email.present? && parent_email == parent.email) || (parent.phone.present? && parent_phone == parent.phone) end end def school_for_school_move if school school elsif education_setting_home? team.home_educated_school else team.unknown_school end end def reason_for_refusal consent_form_programmes.find(&:response_refused?)&.reason_for_refusal end def reason_for_refusal=(value) consent_form_programmes .select(&:response_refused?) .each { it.reason_for_refusal = value } end def reset_follow_up_requested consent_form_programmes .select(&:response_refused?) .each { it.follow_up_requested = nil } end def reason_for_refusal_notes consent_form_programmes.find(&:response_refused?)&.notes end def reason_for_refusal_notes=(value) consent_form_programmes .select(&:response_refused?) .each { it.notes = value } end def follow_up_requested consent_form_programmes.find(&:response_refused?)&.follow_up_requested end def follow_up_requested=(value) consent_form_programmes .select(&:response_refused?) .each do it.follow_up_requested = ActiveModel::Type::Boolean.new.cast(value) end end def qualifies_for_follow_up_discussion? reason_for_refusal.in?(FOLLOW_UP_REQUIRED_REASONS) end def update_programme_responses case response when "given" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = false end when "given_injection" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = true # currently flu injection is to avoid gelatine end when "given_nasal" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[nasal] it.without_gelatine = false end when "given_one" consent_form_programmes.each do |consent_form_programme| consent_form_programme.response = if consent_form_programme.programme.type == chosen_programme "given" else "refused" end consent_form_programme.vaccine_methods = %w[injection] consent_form_programme.without_gelatine = false end when "refused" consent_form_programmes.each { it.response = "refused" } end end def update_injection_alternative vaccine_methods = if ActiveModel::Type::Boolean.new.cast(injection_alternative) %w[nasal injection] else %w[nasal] end consent_form_programmes.each do |consent_form_programme| if consent_form_programme.vaccine_method_nasal? consent_form_programme.vaccine_methods = vaccine_methods end end end def update_without_gelatine consent_form_programmes.each do |consent_form_programme| consent_form_programme.without_gelatine = without_gelatine end end def seed_health_questions return unless response_given? # If the health answers change due to the chosen vaccines changing, we # want to try and keep as much as what the parents already wrote intact. # We do this be saving the answers to the question title (as the IDs # and ordering can change). existing_health_answers = health_answers.each_with_object({}) do |health_answer, memo| memo[health_answer.question] = { response: health_answer.response, notes: health_answer.notes } end vaccines = consent_form_programmes.select(&:response_given?).flat_map(&:vaccines) self.health_answers = HealthAnswersDeduplicator .call(vaccines:) .map do |health_answer| if ( existing_health_answer = existing_health_answers[health_answer.question] ) health_answer.response = existing_health_answer[:response] health_answer.notes = existing_health_answer[:notes] end health_answer end end def notifier = Notifier::ConsentForm.new(self) private def original_session_is_accurate? # Some older consent forms don't have an original session. return false if original_session_id.nil? # Parent hasn't answered the question yet. return true if school_confirmed.nil? # Parent confirms the school is correct. school_confirmed || school_id == location_id end def find_appropriate_session # This tries to find the most appropriate session for this consent form. # It's used when generating links to patients in a session, or when # deciding which dates to show in an email. Under the hood, patients # belong to locations, not sessions. # # Although unlikely to happen in production, there can be a scenario # where multiple sessions at the same location offer the same programmes. # In this case, we have to make a guess about which is the most relevant # session. if location_is_clinic? || education_setting_home? || education_setting_none? return end session_location = school || location sessions_to_search = Session.joins(:team_location).where( team_location: { academic_year:, location: session_location, team: } ) year_group = matched_patient&.year_group(academic_year:) || date_of_birth&.academic_year&.to_year_group(academic_year:) sessions_to_search = if year_group sessions_to_search.where( "(?) >= ?", Session::ProgrammeYearGroup .select( "COUNT(DISTINCT session_programme_year_groups.programme_type)" ) .where("sessions.id = session_programme_year_groups.session_id") .where(programme_type: programme_types, year_group:), programme_types.count ) else sessions_to_search.has_all_programme_types_of(programme_types) end sessions_to_search.find(&:scheduled?) || sessions_to_search.find(&:unscheduled?) || sessions_to_search.first end def via_self_consent? = false def health_answers_valid? if health_question_number.present? unless health_answers[health_question_number].valid? errors.add(:base, "Health answer(s) invalid") return false end else each_health_answer do |health_answer| unless health_answer.valid? errors.add(:base, "Health answer(s) invalid") return false end end end true end def location_is_school? = location.gias_school? def location_is_clinic? = location.generic_clinic? || location.generic_school? def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false
Source
# File app/models/consent_form.rb, line 796 def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false elsif school self.education_setting = "school" end end end
Source
# File app/models/consent_form.rb, line 580 def reset_follow_up_requested consent_form_programmes .select(&:response_refused?) .each { it.follow_up_requested = nil } end
Source
# File app/models/consent_form.rb, line 798 def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false elsif school self.education_setting = "school" end end
Source
# File app/models/consent_form.rb, line 394 def response_given? = consent_form_programmes.any?(&:response_given?) def response_refused? = consent_form_programmes.any?(&:response_refused?) def human_enum_name(attribute) Consent.human_enum_name(attribute, send(attribute)) end def each_health_answer return if health_answers.empty? return to_enum(:each_health_answer) unless block_given? health_answer = health_answers.first seen_health_answers = Set.new loop do if seen_health_answers.include?(health_answer.object_id) raise "Infinite loop detected" end seen_health_answers << health_answer.object_id yield health_answer next_health_answer_index = health_answer.next_health_answer_index break unless next_health_answer_index health_answer = health_answers[next_health_answer_index] end end def can_offer_injection_as_alternative? consent_form_programmes.select(&:response_given?).any?( &:vaccine_method_nasal? ) end def can_offer_without_gelatine? response_given? && consent_form_programmes.any? do it.programme.vaccine_may_contain_gelatine? && !it.programme.has_multiple_vaccine_methods? end end def reason_for_refusal_requires_notes? consent_form_programmes.any?(&:reason_for_refusal_requires_notes?) end def matched_patient @matched_patient ||= (matched_patients.sole if matched?) end def session @session ||= if original_session_is_accurate? original_session else find_appropriate_session || original_session end end def session_dates_are_accurate? # There are some cases where the dates for the session are not considered # accurate enough to show to users. # # Specifically, if the parent indicated that their child goes to a # different school to the one we sent the consent form for, and we've been # unable to match the consent form to a child, we consider the session # and therefore the dates to not be accurate enough to display. original_session_is_accurate? || (session.present? && matched?) end def programmes = consent_form_programmes.map(&:programme) def programme_types = consent_form_programmes.map(&:programme_type) def vaccines @vaccines ||= Vaccine.where(programme_type: programme_types) end def find_or_create_parent_with_relationship_to!(patient:) parent = Parent.match_existing( patient:, email: parent_email, phone: parent_phone, full_name: parent_full_name ) || Parent.new parent.update!( contact_method_other_details: parent_contact_method_other_details, contact_method_type: parent_contact_method_type, email: parent_email, full_name: parent_full_name, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates ) patient .parent_relationships .find_or_initialize_by(parent:) .update!( type: parent_relationship_type, other_name: parent_relationship_other_name ) parent end def summary_with_route if response_given? && response_refused? "Partial consent given (online)" elsif response_given? "Consent given (online)" elsif response_refused? "Consent refused (online)" end end def parent Parent.new( full_name: parent_full_name, email: parent_email, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates, contact_method_type: parent_contact_method_type, contact_method_other_details: parent_contact_method_other_details ) end def parent_relationship ParentRelationship.new( parent:, type: parent_relationship_type, other_name: parent_relationship_other_name ) end def match_with_patient!(patient, current_user:) ActiveRecord::Base.transaction do notify_log_entries.update_all(patient_id: patient.id) school_changed = patient.school_id != school_for_school_move.id if school_changed && !patient.deceased? && !patient.invalidated? SchoolMove.find_or_initialize_by(patient:).update!( school: school_for_school_move, academic_year:, source: :parental_consent_form ) end Consent.from_consent_form!(self, patient:, current_user:).each( &:invalidate_existing_triage_and_patient_specific_directions! ) end end def matches_contact_details_for?(patient:) # We assume `true` if the patient has no parents, otherwise we would send # warnings to these parents about their contact details not matching. return true if patient.parents.empty? patient.parents.any? do |parent| (parent.email.present? && parent_email == parent.email) || (parent.phone.present? && parent_phone == parent.phone) end end def school_for_school_move if school school elsif education_setting_home? team.home_educated_school else team.unknown_school end end def reason_for_refusal consent_form_programmes.find(&:response_refused?)&.reason_for_refusal end def reason_for_refusal=(value) consent_form_programmes .select(&:response_refused?) .each { it.reason_for_refusal = value } end def reset_follow_up_requested consent_form_programmes .select(&:response_refused?) .each { it.follow_up_requested = nil } end def reason_for_refusal_notes consent_form_programmes.find(&:response_refused?)&.notes end def reason_for_refusal_notes=(value) consent_form_programmes .select(&:response_refused?) .each { it.notes = value } end def follow_up_requested consent_form_programmes.find(&:response_refused?)&.follow_up_requested end def follow_up_requested=(value) consent_form_programmes .select(&:response_refused?) .each do it.follow_up_requested = ActiveModel::Type::Boolean.new.cast(value) end end def qualifies_for_follow_up_discussion? reason_for_refusal.in?(FOLLOW_UP_REQUIRED_REASONS) end def update_programme_responses case response when "given" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = false end when "given_injection" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = true # currently flu injection is to avoid gelatine end when "given_nasal" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[nasal] it.without_gelatine = false end when "given_one" consent_form_programmes.each do |consent_form_programme| consent_form_programme.response = if consent_form_programme.programme.type == chosen_programme "given" else "refused" end consent_form_programme.vaccine_methods = %w[injection] consent_form_programme.without_gelatine = false end when "refused" consent_form_programmes.each { it.response = "refused" } end end def update_injection_alternative vaccine_methods = if ActiveModel::Type::Boolean.new.cast(injection_alternative) %w[nasal injection] else %w[nasal] end consent_form_programmes.each do |consent_form_programme| if consent_form_programme.vaccine_method_nasal? consent_form_programme.vaccine_methods = vaccine_methods end end end def update_without_gelatine consent_form_programmes.each do |consent_form_programme| consent_form_programme.without_gelatine = without_gelatine end end def seed_health_questions return unless response_given? # If the health answers change due to the chosen vaccines changing, we # want to try and keep as much as what the parents already wrote intact. # We do this be saving the answers to the question title (as the IDs # and ordering can change). existing_health_answers = health_answers.each_with_object({}) do |health_answer, memo| memo[health_answer.question] = { response: health_answer.response, notes: health_answer.notes } end vaccines = consent_form_programmes.select(&:response_given?).flat_map(&:vaccines) self.health_answers = HealthAnswersDeduplicator .call(vaccines:) .map do |health_answer| if ( existing_health_answer = existing_health_answers[health_answer.question] ) health_answer.response = existing_health_answer[:response] health_answer.notes = existing_health_answer[:notes] end health_answer end end def notifier = Notifier::ConsentForm.new(self) private def original_session_is_accurate? # Some older consent forms don't have an original session. return false if original_session_id.nil? # Parent hasn't answered the question yet. return true if school_confirmed.nil? # Parent confirms the school is correct. school_confirmed || school_id == location_id end def find_appropriate_session # This tries to find the most appropriate session for this consent form. # It's used when generating links to patients in a session, or when # deciding which dates to show in an email. Under the hood, patients # belong to locations, not sessions. # # Although unlikely to happen in production, there can be a scenario # where multiple sessions at the same location offer the same programmes. # In this case, we have to make a guess about which is the most relevant # session. if location_is_clinic? || education_setting_home? || education_setting_none? return end session_location = school || location sessions_to_search = Session.joins(:team_location).where( team_location: { academic_year:, location: session_location, team: } ) year_group = matched_patient&.year_group(academic_year:) || date_of_birth&.academic_year&.to_year_group(academic_year:) sessions_to_search = if year_group sessions_to_search.where( "(?) >= ?", Session::ProgrammeYearGroup .select( "COUNT(DISTINCT session_programme_year_groups.programme_type)" ) .where("sessions.id = session_programme_year_groups.session_id") .where(programme_type: programme_types, year_group:), programme_types.count ) else sessions_to_search.has_all_programme_types_of(programme_types) end sessions_to_search.find(&:scheduled?) || sessions_to_search.find(&:unscheduled?) || sessions_to_search.first end def via_self_consent? = false def health_answers_valid? if health_question_number.present? unless health_answers[health_question_number].valid? errors.add(:base, "Health answer(s) invalid") return false end else each_health_answer do |health_answer| unless health_answer.valid? errors.add(:base, "Health answer(s) invalid") return false end end end true end def location_is_school? = location.gias_school? def location_is_clinic? = location.generic_clinic? || location.generic_school? def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false elsif school
Source
# File app/models/consent_form.rb, line 396 def response_refused? = consent_form_programmes.any?(&:response_refused?) def human_enum_name(attribute) Consent.human_enum_name(attribute, send(attribute)) end def each_health_answer return if health_answers.empty? return to_enum(:each_health_answer) unless block_given? health_answer = health_answers.first seen_health_answers = Set.new loop do if seen_health_answers.include?(health_answer.object_id) raise "Infinite loop detected" end seen_health_answers << health_answer.object_id yield health_answer next_health_answer_index = health_answer.next_health_answer_index break unless next_health_answer_index health_answer = health_answers[next_health_answer_index] end end def can_offer_injection_as_alternative? consent_form_programmes.select(&:response_given?).any?( &:vaccine_method_nasal? ) end def can_offer_without_gelatine? response_given? && consent_form_programmes.any? do it.programme.vaccine_may_contain_gelatine? && !it.programme.has_multiple_vaccine_methods? end end def reason_for_refusal_requires_notes? consent_form_programmes.any?(&:reason_for_refusal_requires_notes?) end def matched_patient @matched_patient ||= (matched_patients.sole if matched?) end def session @session ||= if original_session_is_accurate? original_session else find_appropriate_session || original_session end end def session_dates_are_accurate? # There are some cases where the dates for the session are not considered # accurate enough to show to users. # # Specifically, if the parent indicated that their child goes to a # different school to the one we sent the consent form for, and we've been # unable to match the consent form to a child, we consider the session # and therefore the dates to not be accurate enough to display. original_session_is_accurate? || (session.present? && matched?) end def programmes = consent_form_programmes.map(&:programme) def programme_types = consent_form_programmes.map(&:programme_type) def vaccines @vaccines ||= Vaccine.where(programme_type: programme_types) end def find_or_create_parent_with_relationship_to!(patient:) parent = Parent.match_existing( patient:, email: parent_email, phone: parent_phone, full_name: parent_full_name ) || Parent.new parent.update!( contact_method_other_details: parent_contact_method_other_details, contact_method_type: parent_contact_method_type, email: parent_email, full_name: parent_full_name, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates ) patient .parent_relationships .find_or_initialize_by(parent:) .update!( type: parent_relationship_type, other_name: parent_relationship_other_name ) parent end def summary_with_route if response_given? && response_refused? "Partial consent given (online)" elsif response_given? "Consent given (online)" elsif response_refused? "Consent refused (online)" end end def parent Parent.new( full_name: parent_full_name, email: parent_email, phone: parent_phone, phone_receive_updates: parent_phone_receive_updates, contact_method_type: parent_contact_method_type, contact_method_other_details: parent_contact_method_other_details ) end def parent_relationship ParentRelationship.new( parent:, type: parent_relationship_type, other_name: parent_relationship_other_name ) end def match_with_patient!(patient, current_user:) ActiveRecord::Base.transaction do notify_log_entries.update_all(patient_id: patient.id) school_changed = patient.school_id != school_for_school_move.id if school_changed && !patient.deceased? && !patient.invalidated? SchoolMove.find_or_initialize_by(patient:).update!( school: school_for_school_move, academic_year:, source: :parental_consent_form ) end Consent.from_consent_form!(self, patient:, current_user:).each( &:invalidate_existing_triage_and_patient_specific_directions! ) end end def matches_contact_details_for?(patient:) # We assume `true` if the patient has no parents, otherwise we would send # warnings to these parents about their contact details not matching. return true if patient.parents.empty? patient.parents.any? do |parent| (parent.email.present? && parent_email == parent.email) || (parent.phone.present? && parent_phone == parent.phone) end end def school_for_school_move if school school elsif education_setting_home? team.home_educated_school else team.unknown_school end end def reason_for_refusal consent_form_programmes.find(&:response_refused?)&.reason_for_refusal end def reason_for_refusal=(value) consent_form_programmes .select(&:response_refused?) .each { it.reason_for_refusal = value } end def reset_follow_up_requested consent_form_programmes .select(&:response_refused?) .each { it.follow_up_requested = nil } end def reason_for_refusal_notes consent_form_programmes.find(&:response_refused?)&.notes end def reason_for_refusal_notes=(value) consent_form_programmes .select(&:response_refused?) .each { it.notes = value } end def follow_up_requested consent_form_programmes.find(&:response_refused?)&.follow_up_requested end def follow_up_requested=(value) consent_form_programmes .select(&:response_refused?) .each do it.follow_up_requested = ActiveModel::Type::Boolean.new.cast(value) end end def qualifies_for_follow_up_discussion? reason_for_refusal.in?(FOLLOW_UP_REQUIRED_REASONS) end def update_programme_responses case response when "given" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = false end when "given_injection" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = true # currently flu injection is to avoid gelatine end when "given_nasal" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[nasal] it.without_gelatine = false end when "given_one" consent_form_programmes.each do |consent_form_programme| consent_form_programme.response = if consent_form_programme.programme.type == chosen_programme "given" else "refused" end consent_form_programme.vaccine_methods = %w[injection] consent_form_programme.without_gelatine = false end when "refused" consent_form_programmes.each { it.response = "refused" } end end def update_injection_alternative vaccine_methods = if ActiveModel::Type::Boolean.new.cast(injection_alternative) %w[nasal injection] else %w[nasal] end consent_form_programmes.each do |consent_form_programme| if consent_form_programme.vaccine_method_nasal? consent_form_programme.vaccine_methods = vaccine_methods end end end def update_without_gelatine consent_form_programmes.each do |consent_form_programme| consent_form_programme.without_gelatine = without_gelatine end end def seed_health_questions return unless response_given? # If the health answers change due to the chosen vaccines changing, we # want to try and keep as much as what the parents already wrote intact. # We do this be saving the answers to the question title (as the IDs # and ordering can change). existing_health_answers = health_answers.each_with_object({}) do |health_answer, memo| memo[health_answer.question] = { response: health_answer.response, notes: health_answer.notes } end vaccines = consent_form_programmes.select(&:response_given?).flat_map(&:vaccines) self.health_answers = HealthAnswersDeduplicator .call(vaccines:) .map do |health_answer| if ( existing_health_answer = existing_health_answers[health_answer.question] ) health_answer.response = existing_health_answer[:response] health_answer.notes = existing_health_answer[:notes] end health_answer end end def notifier = Notifier::ConsentForm.new(self) private def original_session_is_accurate? # Some older consent forms don't have an original session. return false if original_session_id.nil? # Parent hasn't answered the question yet. return true if school_confirmed.nil? # Parent confirms the school is correct. school_confirmed || school_id == location_id end def find_appropriate_session # This tries to find the most appropriate session for this consent form. # It's used when generating links to patients in a session, or when # deciding which dates to show in an email. Under the hood, patients # belong to locations, not sessions. # # Although unlikely to happen in production, there can be a scenario # where multiple sessions at the same location offer the same programmes. # In this case, we have to make a guess about which is the most relevant # session. if location_is_clinic? || education_setting_home? || education_setting_none? return end session_location = school || location sessions_to_search = Session.joins(:team_location).where( team_location: { academic_year:, location: session_location, team: } ) year_group = matched_patient&.year_group(academic_year:) || date_of_birth&.academic_year&.to_year_group(academic_year:) sessions_to_search = if year_group sessions_to_search.where( "(?) >= ?", Session::ProgrammeYearGroup .select( "COUNT(DISTINCT session_programme_year_groups.programme_type)" ) .where("sessions.id = session_programme_year_groups.session_id") .where(programme_type: programme_types, year_group:), programme_types.count ) else sessions_to_search.has_all_programme_types_of(programme_types) end sessions_to_search.find(&:scheduled?) || sessions_to_search.find(&:unscheduled?) || sessions_to_search.first end def via_self_consent? = false def health_answers_valid? if health_question_number.present? unless health_answers[health_question_number].valid? errors.add(:base, "Health answer(s) invalid") return false end else each_health_answer do |health_answer| unless health_answer.valid? errors.add(:base, "Health answer(s) invalid") return false end end end true end def location_is_school? = location.gias_school? def location_is_clinic? = location.generic_clinic? || location.generic_school? def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false elsif school self
Source
# File app/models/consent_form.rb, line 560 def school_for_school_move if school school elsif education_setting_home? team.home_educated_school else team.unknown_school end end
Source
# File app/models/consent_form.rb, line 669 def seed_health_questions return unless response_given? # If the health answers change due to the chosen vaccines changing, we # want to try and keep as much as what the parents already wrote intact. # We do this be saving the answers to the question title (as the IDs # and ordering can change). existing_health_answers = health_answers.each_with_object({}) do |health_answer, memo| memo[health_answer.question] = { response: health_answer.response, notes: health_answer.notes } end vaccines = consent_form_programmes.select(&:response_given?).flat_map(&:vaccines) self.health_answers = HealthAnswersDeduplicator .call(vaccines:) .map do |health_answer| if ( existing_health_answer = existing_health_answers[health_answer.question] ) health_answer.response = existing_health_answer[:response] health_answer.notes = existing_health_answer[:notes] end health_answer end end
Source
# File app/models/consent_form.rb, line 443 def session @session ||= if original_session_is_accurate? original_session else find_appropriate_session || original_session end end
Source
# File app/models/consent_form.rb, line 452 def session_dates_are_accurate? # There are some cases where the dates for the session are not considered # accurate enough to show to users. # # Specifically, if the parent indicated that their child goes to a # different school to the one we sent the consent form for, and we've been # unable to match the consent form to a child, we consider the session # and therefore the dates to not be accurate enough to display. original_session_is_accurate? || (session.present? && matched?) end
Source
# File app/models/consent_form.rb, line 501 def summary_with_route if response_given? && response_refused? "Partial consent given (online)" elsif response_given? "Consent given (online)" elsif response_refused? "Consent refused (online)" end end
Source
# File app/models/consent_form.rb, line 648 def update_injection_alternative vaccine_methods = if ActiveModel::Type::Boolean.new.cast(injection_alternative) %w[nasal injection] else %w[nasal] end consent_form_programmes.each do |consent_form_programme| if consent_form_programme.vaccine_method_nasal? consent_form_programme.vaccine_methods = vaccine_methods end end end
Source
# File app/models/consent_form.rb, line 612 def update_programme_responses case response when "given" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = false end when "given_injection" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[injection] it.without_gelatine = true # currently flu injection is to avoid gelatine end when "given_nasal" consent_form_programmes.each do it.response = "given" it.vaccine_methods = %w[nasal] it.without_gelatine = false end when "given_one" consent_form_programmes.each do |consent_form_programme| consent_form_programme.response = if consent_form_programme.programme.type == chosen_programme "given" else "refused" end consent_form_programme.vaccine_methods = %w[injection] consent_form_programme.without_gelatine = false end when "refused" consent_form_programmes.each { it.response = "refused" } end end
Source
# File app/models/consent_form.rb, line 663 def update_without_gelatine consent_form_programmes.each do |consent_form_programme| consent_form_programme.without_gelatine = without_gelatine end end
Source
# File app/models/consent_form.rb, line 468 def vaccines @vaccines ||= Vaccine.where(programme_type: programme_types) end
Source
# File app/models/consent_form.rb, line 769 def via_self_consent? = false def health_answers_valid? if health_question_number.present? unless health_answers[health_question_number].valid? errors.add(:base, "Health answer(s) invalid") return false end else each_health_answer do |health_answer| unless health_answer.valid? errors.add(:base, "Health answer(s) invalid") return false end end end true end def location_is_school? = location.gias_school? def location_is_clinic? = location.generic_clinic? || location.generic_school? def choose_school? location_is_clinic? ? education_setting_school? : !school_confirmed end def requires_notes? = archived? def reset_unused_attributes update_programme_responses unless use_preferred_name self.preferred_given_name = nil self.preferred_family_name = nil end if response_refused? && !response_given? self.address_line_1 = nil self.address_line_2 = nil self.address_town = nil self.address_postcode = nil self.health_answers = [] end self.parent_contact_method_type = nil if parent_phone.blank? self.parent_contact_method_other_details = nil unless parent_contact_method_other? self.parent_relationship_other_name = nil unless parent_relationship_other? consent_form_programmes.each do next unless it.response_given? it.reason_for_refusal = nil it.notes = "" it.follow_up_requested = nil end if school_confirmed self.education_setting = "school" self.school = location elsif education_setting_home? || education_setting_none? self.school = nil self.school_confirmed = false elsif school self.education_setting = "school"
Source
# File app/models/consent_form.rb, line 340 def wizard_steps refused_and_not_given = response_refused? && !response_given? refused_and_given = response_refused? && response_given? response_steps = ProgrammeGrouper .call(consent_form_programmes) .keys .map { :"response_#{it}" } [ :name, :date_of_birth, (:confirm_school if location_is_school?), (:education_setting if location_is_clinic?), (:school if choose_school?), :parent, (:contact_method if parent_phone.present?) ].compact + response_steps + [ (:without_gelatine if can_offer_without_gelatine?), (:reason_for_refusal if refused_and_not_given), ( if refused_and_not_given && reason_for_refusal_requires_notes? :reason_for_refusal_notes end ), ( if refused_and_not_given && qualifies_for_follow_up_discussion? :follow_up_discussion end ), (:injection_alternative if can_offer_injection_as_alternative?), (:address if response_given?), (:health_question if response_given?), (:reason_for_refusal if refused_and_given), ( if refused_and_given && reason_for_refusal_requires_notes? :reason_for_refusal_notes end ), ( if refused_and_given && qualifies_for_follow_up_discussion? :follow_up_discussion end ) ].compact + (Flipper.enabled?(:ethnicity_capture) && recorded? ? ETHNICITY_STEPS : []) end