diff --git a/client/packages/common/src/types/schema.ts b/client/packages/common/src/types/schema.ts index 72508a6d95..095af51317 100644 --- a/client/packages/common/src/types/schema.ts +++ b/client/packages/common/src/types/schema.ts @@ -928,6 +928,26 @@ export type CentralPatientSearchInput = { export type CentralPatientSearchResponse = CentralPatientSearchConnector | CentralPatientSearchError; +export type CentralPluginMutations = { + __typename: 'CentralPluginMutations'; + installUploadedPlugin: PluginInfoNode; +}; + + +export type CentralPluginMutationsInstallUploadedPluginArgs = { + fileId: Scalars['String']['input']; +}; + +export type CentralPluginQueries = { + __typename: 'CentralPluginQueries'; + uploadedPluginInfo: UploadedPluginInfoResponse; +}; + + +export type CentralPluginQueriesUploadedPluginInfoArgs = { + fileId: Scalars['String']['input']; +}; + export type CentralServerMutationNode = { __typename: 'CentralServerMutationNode'; assetCatalogue: AssetCatalogueMutations; @@ -936,9 +956,15 @@ export type CentralServerMutationNode = { general: CentralGeneralMutations; itemVariant: ItemVariantMutations; logReason: AssetLogReasonMutations; + plugins: CentralPluginMutations; vaccineCourse: VaccineCourseMutations; }; +export type CentralServerQueryNode = { + __typename: 'CentralServerQueryNode'; + plugin: CentralPluginQueries; +}; + export type CentralSyncRequired = AuthTokenErrorInterface & { __typename: 'CentralSyncRequired'; description: Scalars['String']['output']; @@ -2885,6 +2911,7 @@ export type InsertPatientInput = { id: Scalars['String']['input']; isDeceased?: InputMaybe; lastName?: InputMaybe; + nextOfKinId?: InputMaybe; phone?: InputMaybe; }; @@ -5360,6 +5387,11 @@ export type PluginDataSortInput = { key: PluginDataSortFieldInput; }; +export type PluginInfoNode = { + __typename: 'PluginInfoNode'; + backendPluginCodes: Array; +}; + export type PluginNode = { __typename: 'PluginNode'; config: Scalars['String']['output']; @@ -5677,6 +5709,7 @@ export type Queries = { authToken: AuthTokenResponse; barcodeByGtin: BarcodeResponse; centralPatientSearch: CentralPatientSearchResponse; + centralServer: CentralServerQueryNode; clinicians: CliniciansResponse; /** Query omSupply "cold_storage_type" entries */ coldStorageTypes: ColdStorageTypesResponse; @@ -8328,6 +8361,7 @@ export type UpdatePatientInput = { id: Scalars['String']['input']; isDeceased?: InputMaybe; lastName?: InputMaybe; + nextOfKinId?: InputMaybe; phone?: InputMaybe; }; @@ -8784,6 +8818,17 @@ export type UpdateVaccineCourseInput = { export type UpdateVaccineCourseResponse = UpdateVaccineCourseError | VaccineCourseNode; +export type UploadedPluginError = { + __typename: 'UploadedPluginError'; + error: UploadedPluginErrorVariant; +}; + +export enum UploadedPluginErrorVariant { + CannotParseFile = 'CANNOT_PARSE_FILE' +} + +export type UploadedPluginInfoResponse = PluginInfoNode | UploadedPluginError; + export type UpsertBundledItemError = { __typename: 'UpsertBundledItemError'; error: UpsertBundledItemErrorInterface; diff --git a/client/packages/programs/src/JsonForms/components/PatientSearch.tsx b/client/packages/programs/src/JsonForms/components/PatientSearch.tsx new file mode 100644 index 0000000000..758b19b67e --- /dev/null +++ b/client/packages/programs/src/JsonForms/components/PatientSearch.tsx @@ -0,0 +1,53 @@ +import React, { useEffect } from 'react'; +import { rankWith, ControlProps, uiTypeIs } from '@jsonforms/core'; +import { withJsonFormsControlProps } from '@jsonforms/react'; +import { Box, DetailInputWithLabelRow } from '@openmsupply-client/common'; +import { DefaultFormRowSx, FORM_GAP, FORM_LABEL_WIDTH } from '../common'; +import { + PatientSearchInput, + SearchInputPatient, + usePatient, +} from '@openmsupply-client/system'; + +export const patientSearchTester = rankWith(10, uiTypeIs('PatientSearch')); + +const UIComponent = (props: ControlProps) => { + const { data, handleChange, label, path } = props; + + const [patient, setPatient] = React.useState(null); + + const onChangePatient = async (patient: SearchInputPatient) => { + setPatient(patient); + handleChange(path, patient.id); + }; + + const { data: patientData } = usePatient.document.get(data); + + useEffect(() => { + if (!patientData) return; + setPatient(patientData); + }, [patientData]); + + return ( + + + + } + /> + ); +}; + +const UIComponentWrapper = (props: ControlProps) => { + if (!props.visible) { + return null; + } + return ; +}; + +export const PatientSearch = withJsonFormsControlProps(UIComponentWrapper); diff --git a/client/packages/programs/src/JsonForms/components/index.ts b/client/packages/programs/src/JsonForms/components/index.ts index fafca9a7ed..381f4fbde0 100644 --- a/client/packages/programs/src/JsonForms/components/index.ts +++ b/client/packages/programs/src/JsonForms/components/index.ts @@ -10,4 +10,5 @@ export * from './Search/Search'; export * from './ProgramEvent'; export * from './HistoricEncounterData'; export * from './BloodPressure'; +export * from './PatientSearch'; export * from './Prescription/Prescription'; diff --git a/client/packages/programs/src/JsonForms/useJsonFormsHandler.tsx b/client/packages/programs/src/JsonForms/useJsonFormsHandler.tsx index c54578da0d..24e3084b07 100644 --- a/client/packages/programs/src/JsonForms/useJsonFormsHandler.tsx +++ b/client/packages/programs/src/JsonForms/useJsonFormsHandler.tsx @@ -37,6 +37,8 @@ import { BloodPressure, Prescription, prescriptionTester, + patientSearchTester, + PatientSearch, } from './components'; import { EnrolmentId, enrolmentIdTester } from './components/EnrolmentId'; import { @@ -83,6 +85,7 @@ const additionalRenderers: JsonFormsRendererRegistryEntry[] = [ { tester: enrolmentIdTester, renderer: EnrolmentId }, { tester: bloodPressureTester, renderer: BloodPressure }, { tester: prescriptionTester, renderer: Prescription }, + { tester: patientSearchTester, renderer: PatientSearch }, ]; /** diff --git a/client/packages/system/src/Patient/PatientView/DefaultPatientSchema.json b/client/packages/system/src/Patient/PatientView/DefaultPatientSchema.json index b9886eba7d..b0bd3b3ce5 100644 --- a/client/packages/system/src/Patient/PatientView/DefaultPatientSchema.json +++ b/client/packages/system/src/Patient/PatientView/DefaultPatientSchema.json @@ -52,6 +52,10 @@ "phone": { "description": "Phone number", "type": "string" + }, + "nextOfKinId": { + "description": "ID of the mSupply name record for the patient's next of kin", + "type": "string" } }, "required": ["id", "code", "firstName", "lastName"], diff --git a/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json b/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json index 0629fdd593..dd2163cd82 100644 --- a/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json +++ b/client/packages/system/src/Patient/PatientView/DefaultPatientUISchema.json @@ -73,6 +73,11 @@ "type": "Control", "scope": "#/properties/phone", "label": "Phone" + }, + { + "type": "PatientSearch", + "scope": "#/properties/nextOfKinId", + "label": "Next of Kin" } ] } diff --git a/client/packages/system/src/Patient/PatientView/PatientView.tsx b/client/packages/system/src/Patient/PatientView/PatientView.tsx index 0af656a60e..3be4c39190 100644 --- a/client/packages/system/src/Patient/PatientView/PatientView.tsx +++ b/client/packages/system/src/Patient/PatientView/PatientView.tsx @@ -151,6 +151,7 @@ const PatientDetailView = ({ isDeceased: currentPatient.isDeceased ?? undefined, phone: currentPatient.phone ?? undefined, address1: currentPatient.address1 ?? undefined, + nextOfKinId: currentPatient.nextOfKinId ?? undefined, }, isCreating: false, }; diff --git a/client/packages/system/src/Patient/api/operations.generated.ts b/client/packages/system/src/Patient/api/operations.generated.ts index 1c03c9a00a..ff6a96c4e0 100644 --- a/client/packages/system/src/Patient/api/operations.generated.ts +++ b/client/packages/system/src/Patient/api/operations.generated.ts @@ -5,7 +5,7 @@ import gql from 'graphql-tag'; type GraphQLClientRequestHeaders = RequestOptions['requestHeaders']; export type PatientRowFragment = { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', name: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } }; -export type ProgramPatientRowFragment = { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } }; +export type ProgramPatientRowFragment = { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } }; export type PatientsQueryVariables = Types.Exact<{ storeId: Types.Scalars['String']['input']; @@ -23,7 +23,7 @@ export type PatientByIdQueryVariables = Types.Exact<{ }>; -export type PatientByIdQuery = { __typename: 'Queries', patients: { __typename: 'PatientConnector', totalCount: number, nodes: Array<{ __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } }> } }; +export type PatientByIdQuery = { __typename: 'Queries', patients: { __typename: 'PatientConnector', totalCount: number, nodes: Array<{ __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } }> } }; export type PatientSearchQueryVariables = Types.Exact<{ input: Types.PatientSearchInput; @@ -31,7 +31,7 @@ export type PatientSearchQueryVariables = Types.Exact<{ }>; -export type PatientSearchQuery = { __typename: 'Queries', patientSearch: { __typename: 'PatientSearchConnector', totalCount: number, nodes: Array<{ __typename: 'PatientSearchNode', score: number, patient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }> } }; +export type PatientSearchQuery = { __typename: 'Queries', patientSearch: { __typename: 'PatientSearchConnector', totalCount: number, nodes: Array<{ __typename: 'PatientSearchNode', score: number, patient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }> } }; export type CentralPatientSearchQueryVariables = Types.Exact<{ input: Types.CentralPatientSearchInput; @@ -55,7 +55,7 @@ export type InsertProgramPatientMutationVariables = Types.Exact<{ }>; -export type InsertProgramPatientMutation = { __typename: 'Mutations', insertProgramPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; +export type InsertProgramPatientMutation = { __typename: 'Mutations', insertProgramPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; export type UpdateProgramPatientMutationVariables = Types.Exact<{ storeId: Types.Scalars['String']['input']; @@ -63,7 +63,7 @@ export type UpdateProgramPatientMutationVariables = Types.Exact<{ }>; -export type UpdateProgramPatientMutation = { __typename: 'Mutations', updateProgramPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; +export type UpdateProgramPatientMutation = { __typename: 'Mutations', updateProgramPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; export type InsertPatientMutationVariables = Types.Exact<{ storeId: Types.Scalars['String']['input']; @@ -71,7 +71,7 @@ export type InsertPatientMutationVariables = Types.Exact<{ }>; -export type InsertPatientMutation = { __typename: 'Mutations', insertPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; +export type InsertPatientMutation = { __typename: 'Mutations', insertPatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; export type UpdatePatientMutationVariables = Types.Exact<{ storeId: Types.Scalars['String']['input']; @@ -79,7 +79,7 @@ export type UpdatePatientMutationVariables = Types.Exact<{ }>; -export type UpdatePatientMutation = { __typename: 'Mutations', updatePatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; +export type UpdatePatientMutation = { __typename: 'Mutations', updatePatient: { __typename: 'PatientNode', id: string, code: string, code2?: string | null, firstName?: string | null, lastName?: string | null, name: string, dateOfBirth?: string | null, address1?: string | null, phone?: string | null, gender?: Types.GenderType | null, email?: string | null, createdDatetime?: string | null, documentDraft?: any | null, isDeceased: boolean, dateOfDeath?: string | null, nextOfKinId?: string | null, document?: { __typename: 'DocumentNode', id: string, name: string, type: string } | null, programEnrolments: { __typename: 'ProgramEnrolmentConnector', totalCount: number, nodes: Array<{ __typename: 'ProgramEnrolmentNode', programEnrolmentId?: string | null, document: { __typename: 'DocumentNode', documentRegistry?: { __typename: 'DocumentRegistryNode', name?: string | null } | null } }> } } }; export type LatestPatientEncounterQueryVariables = Types.Exact<{ storeId: Types.Scalars['String']['input']; @@ -147,6 +147,7 @@ export const ProgramPatientRowFragmentDoc = gql` documentDraft isDeceased dateOfDeath + nextOfKinId programEnrolments { ... on ProgramEnrolmentConnector { __typename diff --git a/client/packages/system/src/Patient/api/operations.graphql b/client/packages/system/src/Patient/api/operations.graphql index 40f2262309..b703a1a0f4 100644 --- a/client/packages/system/src/Patient/api/operations.graphql +++ b/client/packages/system/src/Patient/api/operations.graphql @@ -53,6 +53,7 @@ fragment ProgramPatientRow on PatientNode { documentDraft isDeceased dateOfDeath + nextOfKinId programEnrolments { ... on ProgramEnrolmentConnector { __typename diff --git a/client/packages/system/src/Patient/index.ts b/client/packages/system/src/Patient/index.ts index c697299a5c..d7effe3fe0 100644 --- a/client/packages/system/src/Patient/index.ts +++ b/client/packages/system/src/Patient/index.ts @@ -3,3 +3,4 @@ export * from './ListView'; export * from './Service'; export * from './api'; export * from './Components'; +export * from './utils'; diff --git a/server/graphql/programs/src/mutations/patient/insert.rs b/server/graphql/programs/src/mutations/patient/insert.rs index 54651787ff..e5e2d0d7bf 100644 --- a/server/graphql/programs/src/mutations/patient/insert.rs +++ b/server/graphql/programs/src/mutations/patient/insert.rs @@ -24,6 +24,7 @@ pub struct InsertPatientInput { pub phone: Option, pub is_deceased: Option, pub date_of_death: Option, + pub next_of_kin_id: Option, } #[derive(Union)] @@ -94,6 +95,7 @@ impl InsertPatientInput { phone, date_of_death, is_deceased, + next_of_kin_id, } = self; ServiceInput { @@ -108,6 +110,7 @@ impl InsertPatientInput { phone, date_of_death, is_deceased, + next_of_kin_id, r#type: NameRowType::Patient, } } diff --git a/server/graphql/programs/src/mutations/patient/update.rs b/server/graphql/programs/src/mutations/patient/update.rs index 65bc841631..21f6329bd8 100644 --- a/server/graphql/programs/src/mutations/patient/update.rs +++ b/server/graphql/programs/src/mutations/patient/update.rs @@ -9,7 +9,6 @@ use service::{ auth::{Resource, ResourceAccessRequest}, programs::patient::{UpdatePatient, UpdatePatientError}, }; -use util::inline_init; /// All fields in the input object will be used to update the patient record. /// This means that the caller also has to provide the fields that are not going to change. @@ -27,6 +26,7 @@ pub struct UpdatePatientInput { pub phone: Option, pub is_deceased: Option, pub date_of_death: Option, + pub next_of_kin_id: Option, } #[derive(Union)] @@ -49,6 +49,7 @@ pub fn update_patient( phone, is_deceased, date_of_death, + next_of_kin_id, }: UpdatePatientInput, ) -> Result { let user = validate_auth( @@ -63,19 +64,20 @@ pub fn update_patient( let service_provider = ctx.service_provider(); let service_context = service_provider.basic_context()?; - let update_patient = inline_init(|n: &mut UpdatePatient| { - n.id = id; - n.code = code; - n.code_2 = code_2; - n.first_name = first_name; - n.last_name = last_name; - n.gender = gender.map(|g| g.to_domain()); - n.date_of_birth = date_of_birth; - n.address1 = address1; - n.phone = phone; - n.is_deceased = is_deceased; - n.date_of_death = date_of_death; - }); + let update_patient = UpdatePatient { + id, + code, + code_2, + first_name, + last_name, + gender: gender.map(|g| g.to_domain()), + date_of_birth, + address1, + phone, + is_deceased, + date_of_death, + next_of_kin_id, + }; match service_provider.patient_service.update_patient( &service_context, diff --git a/server/repository/src/migrations/v2_06_00/mod.rs b/server/repository/src/migrations/v2_06_00/mod.rs index 24bd4e805f..19a5f0c518 100644 --- a/server/repository/src/migrations/v2_06_00/mod.rs +++ b/server/repository/src/migrations/v2_06_00/mod.rs @@ -5,6 +5,7 @@ mod add_index_to_sync_buffer; mod add_name_next_of_kin_id; mod add_program_deleted_datetime; mod backend_plugins; + use crate::StorageConnection; pub(crate) struct V2_06_00; diff --git a/server/service/src/programs/patient/insert_patient.rs b/server/service/src/programs/patient/insert_patient.rs index d8902cbdcc..0667a4d9a0 100644 --- a/server/service/src/programs/patient/insert_patient.rs +++ b/server/service/src/programs/patient/insert_patient.rs @@ -22,6 +22,7 @@ pub struct InsertPatient { pub is_deceased: Option, pub date_of_death: Option, pub r#type: NameRowType, + pub next_of_kin_id: Option, } #[derive(PartialEq, Debug)] @@ -65,6 +66,7 @@ fn generate(input: InsertPatient, store_id: &str) -> NameRow { date_of_death, is_deceased, r#type, + next_of_kin_id, } = input; NameRow { @@ -85,6 +87,7 @@ fn generate(input: InsertPatient, store_id: &str) -> NameRow { is_deceased: is_deceased.unwrap_or(false), national_health_number: code_2, created_datetime: Some(Utc::now().naive_utc()), + next_of_kin_id, ..Default::default() } } diff --git a/server/service/src/programs/patient/update_patient.rs b/server/service/src/programs/patient/update_patient.rs index 0cbeef2417..ed4187f90a 100644 --- a/server/service/src/programs/patient/update_patient.rs +++ b/server/service/src/programs/patient/update_patient.rs @@ -48,6 +48,7 @@ fn generate(existing: NameRow, update: UpdatePatient) -> NameRow { phone, is_deceased, date_of_death, + next_of_kin_id, } = update; NameRow { @@ -62,6 +63,7 @@ fn generate(existing: NameRow, update: UpdatePatient) -> NameRow { date_of_death, is_deceased: is_deceased.unwrap_or(false), national_health_number: code_2, + next_of_kin_id, ..existing } } @@ -79,6 +81,7 @@ pub struct UpdatePatient { pub phone: Option, pub is_deceased: Option, pub date_of_death: Option, + pub next_of_kin_id: Option, } pub(crate) fn update_patient(