Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: upsertRegistrationIdentifier gateway endpoint #8034

Merged
merged 23 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d05ff89
feat: Created an upsertRegistrationIdentifier endpoint to gateway
Hyper3x Nov 27, 2024
57c383c
mod : allowed any state records
Hyper3x Nov 29, 2024
30c0181
mod : removed upsert state-transition
Hyper3x Nov 29, 2024
fb845d1
DRAFT upsertRegistrationIdentifier endpoint to gateway #7908
Hyper3x Nov 21, 2024
db3f93b
feat: Created an upsertRegistrationIdentifier endpoint to gateway
Hyper3x Nov 27, 2024
a8fd674
mod : allowed any state records
Hyper3x Nov 29, 2024
82a4c78
mod : removed upsert state-transition
Hyper3x Nov 29, 2024
3c1f31a
issues fixed
Hyper3x Dec 2, 2024
dede05b
Merge branch 'develop' into ocrvs-7908
tahmidrahman-dsi Dec 4, 2024
9bd25f0
mod : required changes done
Hyper3x Dec 5, 2024
4736229
Merge branch 'develop' into ocrvs-7908
tahmidrahman-dsi Dec 5, 2024
bf5478f
fix: remove upsert stuff from states
tahmidrahman-dsi Dec 6, 2024
13ae4a2
fix: cleanup upsert handler
tahmidrahman-dsi Dec 9, 2024
45fd2e7
fix: small amends
tahmidrahman-dsi Dec 9, 2024
1a0b60e
fix: update wrong transformations
tahmidrahman-dsi Dec 9, 2024
49e4c11
Merge branch 'develop' into ocrvs-7908
naftis Dec 9, 2024
83af2a4
fix: remove unused schema
naftis Dec 9, 2024
497ccf0
Merge branch 'ocrvs-7908' of https://github.com/opencrvs/opencrvs-cor…
naftis Dec 9, 2024
cd96efd
refactor: wording
naftis Dec 9, 2024
f9902f3
fix: remove task history comment
naftis Dec 9, 2024
8575ec0
refactor: for clarity, allow only updating one identifier at time
naftis Dec 9, 2024
7fd261f
fix: remove unnecessary if as 'get' methods should already throw
naftis Dec 9, 2024
071efd3
Merge branch 'develop' into ocrvs-7908
tahmidrahman-dsi Dec 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions packages/gateway/src/features/registration/root-resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ import {
verifyRegistration,
markNotADuplicate,
rejectRegistration,
confirmRegistration
confirmRegistration,
upsertRegistrationIdentifier
} from '@gateway/workflow/index'
import { getRecordById } from '@gateway/records'
import { UnassignError, UserInputError } from '@gateway/utils/graphql-errors'
Expand Down Expand Up @@ -612,7 +613,6 @@ export const resolvers: GQLResolver = {

try {
const taskEntry = await confirmRegistration(id, authHeader, {
error: details.error,
registrationNumber: details.registrationNumber,
identifiers: details.identifiers
})
Expand Down Expand Up @@ -641,6 +641,26 @@ export const resolvers: GQLResolver = {
} catch (error) {
throw new Error(`Error in rejectRegistration: ${error.message}`)
}
},
async upsertRegistrationIdentifier(
_,
{ id, details },
{ headers: authHeader }
) {
if (!hasRecordAccess(authHeader, id)) {
throw new Error('User does not have access to the record')
}

try {
const taskEntry = await upsertRegistrationIdentifier(id, authHeader, {
registrationNumber: details.registrationNumber,
identifiers: details.identifiers
})

return taskEntry.resource.id
} catch (error) {
throw new Error(`Failed to confirm registration: ${error.message}`)
}
}
}
}
Expand Down
10 changes: 9 additions & 1 deletion packages/gateway/src/features/registration/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,6 @@ input IdentifierInput {

input ConfirmRegistrationInput {
registrationNumber: String!
error: String
identifiers: [IdentifierInput!]
}

Expand All @@ -579,6 +578,11 @@ input RejectRegistrationInput {
comment: String
}

input UpsertRegistrationIdentifierInput {
registrationNumber: String
identifiers: [IdentifierInput!]
}

type Mutation {
# Generic correction handlers for all event types
# Applying a correction request is made on a event level as payload is dependant on event type
Expand Down Expand Up @@ -657,4 +661,8 @@ type Mutation {
): ID!
confirmRegistration(id: ID!, details: ConfirmRegistrationInput!): ID!
rejectRegistration(id: ID!, details: RejectRegistrationInput!): ID!
upsertRegistrationIdentifier(
id: ID!
details: UpsertRegistrationIdentifierInput!
): ID!
}
24 changes: 23 additions & 1 deletion packages/gateway/src/graphql/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export interface GQLMutation {
markEventAsDuplicate: string
confirmRegistration: string
rejectRegistration: string
upsertRegistrationIdentifier: string
createOrUpdateUser: GQLUser
activateUser?: string
changePassword?: string
Expand Down Expand Up @@ -601,7 +602,6 @@ export interface GQLReinstated {

export interface GQLConfirmRegistrationInput {
registrationNumber: string
error?: string
identifiers?: Array<GQLIdentifierInput>
}

Expand All @@ -610,6 +610,11 @@ export interface GQLRejectRegistrationInput {
comment?: string
}

export interface GQLUpsertRegistrationIdentifierInput {
registrationNumber?: string
identifiers?: Array<GQLIdentifierInput>
}

export interface GQLUserInput {
id?: string
name: Array<GQLHumanNameInput>
Expand Down Expand Up @@ -2632,6 +2637,7 @@ export interface GQLMutationTypeResolver<TParent = any> {
markEventAsDuplicate?: MutationToMarkEventAsDuplicateResolver<TParent>
confirmRegistration?: MutationToConfirmRegistrationResolver<TParent>
rejectRegistration?: MutationToRejectRegistrationResolver<TParent>
upsertRegistrationIdentifier?: MutationToUpsertRegistrationIdentifierResolver<TParent>
createOrUpdateUser?: MutationToCreateOrUpdateUserResolver<TParent>
activateUser?: MutationToActivateUserResolver<TParent>
changePassword?: MutationToChangePasswordResolver<TParent>
Expand Down Expand Up @@ -3208,6 +3214,22 @@ export interface MutationToRejectRegistrationResolver<
): TResult
}

export interface MutationToUpsertRegistrationIdentifierArgs {
id: string
details: GQLUpsertRegistrationIdentifierInput
}
export interface MutationToUpsertRegistrationIdentifierResolver<
TParent = any,
TResult = any
> {
(
parent: TParent,
args: MutationToUpsertRegistrationIdentifierArgs,
context: Context,
info: GraphQLResolveInfo
): TResult
}

export interface MutationToCreateOrUpdateUserArgs {
user: GQLUserInput
}
Expand Down
10 changes: 9 additions & 1 deletion packages/gateway/src/graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ type Mutation {
): ID!
confirmRegistration(id: ID!, details: ConfirmRegistrationInput!): ID!
rejectRegistration(id: ID!, details: RejectRegistrationInput!): ID!
upsertRegistrationIdentifier(
id: ID!
details: UpsertRegistrationIdentifierInput!
): ID!
createOrUpdateUser(user: UserInput!): User!
activateUser(
userId: String!
Expand Down Expand Up @@ -734,7 +738,6 @@ type Reinstated {

input ConfirmRegistrationInput {
registrationNumber: String!
error: String
identifiers: [IdentifierInput!]
}

Expand All @@ -743,6 +746,11 @@ input RejectRegistrationInput {
comment: String
}

input UpsertRegistrationIdentifierInput {
registrationNumber: String
identifiers: [IdentifierInput!]
}

input UserInput {
id: ID
name: [HumanNameInput!]!
Expand Down
24 changes: 23 additions & 1 deletion packages/gateway/src/workflow/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,6 @@ export async function confirmRegistration(
id: string,
authHeader: IAuthHeader,
details: {
error: string | undefined
registrationNumber: string
identifiers?: IdentifierInput[]
}
Expand Down Expand Up @@ -281,6 +280,29 @@ export async function rejectRegistration(
return taskEntry
}

export async function upsertRegistrationIdentifier(
id: string,
authHeader: IAuthHeader,
details: {
registrationNumber?: string
identifiers?: IdentifierInput[]
}
) {
const res: ReadyForReviewRecord = await createRequest(
'POST',
`/records/${id}/upsert`,
authHeader,
details
)

const taskEntry = res.entry.find((e) => e.resource.resourceType === 'Task')
if (!taskEntry) {
throw new Error('No task entry found in the confirmation response')
}

return taskEntry
}

export async function archiveRegistration(
id: string,
authHeader: IAuthHeader,
Expand Down
11 changes: 11 additions & 0 deletions packages/workflow/src/config/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { approveCorrectionRoute } from '@workflow/records/handler/correction/app
import { requestCorrectionRoute } from '@workflow/records/handler/correction/request'
import { makeCorrectionRoute } from '@workflow/records/handler/correction/make-correction'
import { eventNotificationHandler } from '@workflow/records/handler/eventNotificationHandler'
import { upsertRegistrationHandler } from '@workflow/records/handler/upsert'

export const getRoutes = () => {
const routes = [
Expand Down Expand Up @@ -69,6 +70,16 @@ export const getRoutes = () => {
'Register event based on tracking id and registration number.'
}
},
{
method: 'POST',
path: '/records/{id}/upsert',
handler: upsertRegistrationHandler,
config: {
tags: ['api'],
description:
'Upsert Register event based on tracking id and registration number.'
}
},
{
method: 'POST',
path: '/create-record',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import {
findExtension,
getResourceFromBundleById,
resourceIdentifierToUUID,
SupportedPatientIdentifierCode
SupportedPatientIdentifierCode,
ValidRecord
} from '@opencrvs/commons/types'
import { COUNTRY_CONFIG_URL } from '@workflow/constants'
import {
Expand All @@ -37,6 +38,7 @@ import {
} from '@workflow/features/registration/fhir/fhir-utils'
import { getPractitionerRef } from '@workflow/features/user/utils'
import { ITokenPayload } from '@workflow/utils/auth-utils'
import { isEqual } from 'lodash'
import fetch from 'node-fetch'

export async function invokeRegistrationValidation(
Expand Down Expand Up @@ -204,3 +206,47 @@ export function updatePatientIdentifierWithRN(
return patient
})
}

export function upsertPatientIdentifiers(
record: ValidRecord,
composition: Composition,
sectionCodes: string[],
identifiers: {
type: SupportedPatientIdentifierCode
value: string
}[]
): Saved<Patient>[] {
return sectionCodes.map((sectionCode) => {
const sectionEntry = getSectionEntryBySectionCode(composition, sectionCode)
const patientId = resourceIdentifierToUUID(
sectionEntry.reference as ResourceIdentifier
)
const patient = getResourceFromBundleById<Patient>(record, patientId)

if (!patient.identifier) {
patient.identifier = []
}
identifiers.forEach((id) => {
const existingIdentifier = patient.identifier!.find((existingId) =>
isEqual(existingId.type, id.type)
)
if (existingIdentifier) {
existingIdentifier.value = id.value
} else {
patient.identifier!.push({
type: {
coding: [
{
system: `${OPENCRVS_SPECIFICATION_URL}identifier-type`,
code: id.type
}
]
},
value: id.value
})
}
})

return patient
})
}
67 changes: 67 additions & 0 deletions packages/workflow/src/records/handler/upsert.ts
naftis marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* OpenCRVS is also distributed under the terms of the Civil Registration
* & Healthcare Disclaimer located at http://opencrvs.org/license.
*
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/
import { getToken } from '@workflow/utils/auth-utils'
import * as Hapi from '@hapi/hapi'
import { getRecordById } from '@workflow/records/index'
import { indexBundle } from '@workflow/records/search'
import { toUpserted } from '@workflow/records/state-transitions'
import { SupportedPatientIdentifierCode } from '@opencrvs/commons/types'
import { sendBundleToHearth } from '@workflow/records/fhir'

interface IdentifierInput {
type: SupportedPatientIdentifierCode
value: string
}
export interface EventRegistrationPayload {
trackingId: string
registrationNumber: string
identifiers: IdentifierInput[]
}

export async function upsertRegistrationHandler(
request: Hapi.Request,
h: Hapi.ResponseToolkit
) {
const token = getToken(request)
const compositionId = request.params.id
const { identifiers } = request.payload as EventRegistrationPayload

const savedRecord = await getRecordById(
compositionId,
request.headers.authorization,
[
'ARCHIVED',
'CERTIFIED',
'CORRECTION_REQUESTED',
'IN_PROGRESS',
'READY_FOR_REVIEW',
'ISSUED',
'REGISTERED',
'REJECTED',
'VALIDATED',
'WAITING_VALIDATION'
],
true
)
if (!savedRecord) {
throw new Error(
'Could not find record with composition id: ' + compositionId
)
}

const upsertedRecord = toUpserted(savedRecord, identifiers)

await sendBundleToHearth(upsertedRecord)
await indexBundle(upsertedRecord, token)
// TBD: audit event

return h.response(upsertedRecord).code(200)
}
Loading
Loading