Skip to main content
Glama
intake-form.ts8.1 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { addProfileToResource, createReference, getQuestionnaireAnswers } from '@medplum/core'; import type { MedplumClient } from '@medplum/core'; import type { Organization, Patient, Questionnaire, QuestionnaireResponse, Reference } from '@medplum/fhirtypes'; import { addAllergy, addCondition, addConsent, addCoverage, addExtension, addFamilyMemberHistory, addImmunization, addLanguage, addMedication, addPharmacy, consentCategoryMapping, consentPolicyRuleMapping, consentScopeMapping, convertDateToDateTime, extensionURLMapping, getGroupRepeatedAnswers, getHumanName, getPatientAddress, observationCategoryMapping, observationCodeMapping, PROFILE_URLS, upsertObservation, } from './intake-utils'; export async function onboardPatient( medplum: MedplumClient, questionnaire: Questionnaire, response: QuestionnaireResponse ): Promise<Patient> { const answers = getQuestionnaireAnswers(response); let patient: Patient = { resourceType: 'Patient', }; patient = addProfileToResource(patient, PROFILE_URLS.Patient); // Handle demographic information const patientName = getHumanName(answers); if (patientName) { patient.name = [patientName]; } if (answers['dob']?.valueDate) { patient.birthDate = answers['dob'].valueDate; } const patientAddress = getPatientAddress(answers); if (patientAddress) { patient.address = [patientAddress]; } if (answers['gender-identity']?.valueCoding?.code) { patient.gender = answers['gender-identity'].valueCoding.code as Patient['gender']; } if (answers['phone']?.valueString) { patient.telecom = [{ system: 'phone', value: answers['phone'].valueString }]; } if (answers['ssn']?.valueString) { patient.identifier = [ { type: { coding: [ { system: 'http://terminology.hl7.org/CodeSystem/v2-0203', code: 'SS', }, ], }, system: 'http://hl7.org/fhir/sid/us-ssn', value: answers['ssn'].valueString, }, ]; } const emergencyContacts = getGroupRepeatedAnswers(questionnaire, response, 'emergency-contact'); if (emergencyContacts) { patient.contact = []; for (const contact of emergencyContacts) { patient.contact.push({ relationship: [ { coding: [ { system: 'http://terminology.hl7.org/CodeSystem/v2-0131', code: 'EP', display: 'Emergency contact person', }, ], }, ], name: getHumanName(contact, 'emergency-contact-'), telecom: [{ system: 'phone', value: contact['emergency-contact-phone']?.valueString }], }); } } addExtension(patient, extensionURLMapping.race, 'valueCoding', answers['race'], 'ombCategory'); addExtension(patient, extensionURLMapping.ethnicity, 'valueCoding', answers['ethnicity'], 'ombCategory'); addExtension(patient, extensionURLMapping.veteran, 'valueBoolean', answers['veteran-status']); addLanguage(patient, answers['languages-spoken']?.valueCoding); addLanguage(patient, answers['preferred-language']?.valueCoding, true); // Create the patient resource patient = await medplum.createResource(patient); // NOTE: Updating the questionnaire response does not trigger a loop because the bot subscription // is configured for "create"-only event. response.subject = createReference(patient); await medplum.createResource(response); // Handle observations await upsertObservation( medplum, patient, observationCodeMapping.sexualOrientation, observationCategoryMapping.socialHistory, 'valueCodeableConcept', answers['sexual-orientation']?.valueCoding, PROFILE_URLS.ObservationSexualOrientation ); await upsertObservation( medplum, patient, observationCodeMapping.housingStatus, observationCategoryMapping.sdoh, 'valueCodeableConcept', answers['housing-status']?.valueCoding ); await upsertObservation( medplum, patient, observationCodeMapping.educationLevel, observationCategoryMapping.sdoh, 'valueCodeableConcept', answers['education-level']?.valueCoding ); await upsertObservation( medplum, patient, observationCodeMapping.smokingStatus, observationCategoryMapping.socialHistory, 'valueCodeableConcept', answers['smoking-status']?.valueCoding, PROFILE_URLS.ObservationSmokingStatus ); await upsertObservation( medplum, patient, observationCodeMapping.pregnancyStatus, observationCategoryMapping.socialHistory, 'valueCodeableConcept', answers['pregnancy-status']?.valueCoding ); const estimatedDeliveryDate = convertDateToDateTime(answers['estimated-delivery-date']?.valueDate); await upsertObservation( medplum, patient, observationCodeMapping.estimatedDeliveryDate, observationCategoryMapping.socialHistory, 'valueDateTime', estimatedDeliveryDate ? { valueDateTime: estimatedDeliveryDate } : undefined ); // Handle allergies const allergies = getGroupRepeatedAnswers(questionnaire, response, 'allergies'); for (const allergy of allergies) { await addAllergy(medplum, patient, allergy); } // Handle medications const medications = getGroupRepeatedAnswers(questionnaire, response, 'medications'); for (const medication of medications) { await addMedication(medplum, patient, medication); } // Handle medical history const medicalHistory = getGroupRepeatedAnswers(questionnaire, response, 'medical-history'); for (const history of medicalHistory) { await addCondition(medplum, patient, history); } const familyMemberHistory = getGroupRepeatedAnswers(questionnaire, response, 'family-member-history'); for (const history of familyMemberHistory) { await addFamilyMemberHistory(medplum, patient, history); } // Handle vaccination history (immunizations) const vaccinationHistory = getGroupRepeatedAnswers(questionnaire, response, 'vaccination-history'); for (const vaccine of vaccinationHistory) { await addImmunization(medplum, patient, vaccine); } // Handle coverage const insuranceProviders = getGroupRepeatedAnswers(questionnaire, response, 'coverage-information'); for (const provider of insuranceProviders) { await addCoverage(medplum, patient, provider); } // Handle preferred pharmacy const preferredPharmacyReference = answers['preferred-pharmacy-reference']?.valueReference; if (preferredPharmacyReference) { await addPharmacy(medplum, patient, preferredPharmacyReference as Reference<Organization>); } // Handle consents await addConsent( medplum, patient, !!answers['consent-for-treatment-signature']?.valueBoolean, consentScopeMapping.treatment, consentCategoryMapping.med, consentPolicyRuleMapping.cric, convertDateToDateTime(answers['consent-for-treatment-date']?.valueDate) ); await addConsent( medplum, patient, !!answers['agreement-to-pay-for-treatment-help']?.valueBoolean, consentScopeMapping.treatment, consentCategoryMapping.pay, consentPolicyRuleMapping.hipaaSelfPay, convertDateToDateTime(answers['agreement-to-pay-for-treatment-date']?.valueDate) ); await addConsent( medplum, patient, !!answers['notice-of-privacy-practices-signature']?.valueBoolean, consentScopeMapping.patientPrivacy, consentCategoryMapping.nopp, consentPolicyRuleMapping.hipaaNpp, convertDateToDateTime(answers['notice-of-privacy-practices-date']?.valueDate) ); await addConsent( medplum, patient, !!answers['acknowledgement-for-advance-directives-signature']?.valueBoolean, consentScopeMapping.adr, consentCategoryMapping.acd, consentPolicyRuleMapping.adr, convertDateToDateTime(answers['acknowledgement-for-advance-directives-date']?.valueDate) ); return patient; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server