diff --git a/packages/client/src/components/interface/DownloadButton.tsx b/packages/client/src/components/interface/DownloadButton.tsx index cf05b3d3bff..eb6efd99d98 100644 --- a/packages/client/src/components/interface/DownloadButton.tsx +++ b/packages/client/src/components/interface/DownloadButton.tsx @@ -34,6 +34,7 @@ import ReactTooltip from 'react-tooltip' import { useModal } from '@client/hooks/useModal' import { usePermissions } from '@client/hooks/useAuthorization' import styled from 'styled-components' +import { useDeclaration } from '@client/declarations/selectors' interface IDownloadConfig { event: string @@ -131,7 +132,12 @@ export function DownloadButton({ status, className, declarationStatus, - downloadConfigs: { assignment, event, compositionId, action } + downloadConfigs: { + assignment: declarationAssignment, + event, + compositionId, + action + } }: DownloadButtonProps) { const intl = useIntl() const client = useApolloClient() @@ -146,6 +152,9 @@ export function DownloadButton({ const [modal, openModal] = useModal() const { isRecordActionable } = usePermissions() + const declaration = useDeclaration(compositionId) + const assignment = declarationAssignment ?? declaration?.assignmentStatus + const assignedToSomeoneElse = assignment && assignment.practitionerId !== practitionerId const assignedToMe = assignment?.practitionerId === practitionerId diff --git a/packages/client/src/views/RecordAudit/RecordAudit.tsx b/packages/client/src/views/RecordAudit/RecordAudit.tsx index f2a5abbd553..4082d3182ca 100644 --- a/packages/client/src/views/RecordAudit/RecordAudit.tsx +++ b/packages/client/src/views/RecordAudit/RecordAudit.tsx @@ -541,10 +541,11 @@ const BodyContent = ({ ...declaration, status: data.fetchRegistration?.registration?.status[0] .type as SUBMISSION_STATUS, - assignment: data.fetchRegistration?.registration?.assignment + assignment: draft?.assignmentStatus } } else { declaration = getGQLDeclaration(data.fetchRegistration, language) + declaration.assignment = draft?.assignmentStatus } return ( diff --git a/packages/workflow/src/records/fhir.ts b/packages/workflow/src/records/fhir.ts index 0fcbd577499..6f9ec38781c 100644 --- a/packages/workflow/src/records/fhir.ts +++ b/packages/workflow/src/records/fhir.ts @@ -52,11 +52,13 @@ import { getResourceFromBundleById, TransactionResponse, TaskIdentifierSystem, - Location + Location, + PractitionerRole, + URLReference } from '@opencrvs/commons/types' import { FHIR_URL } from '@workflow/constants' import fetch from 'node-fetch' -import { getUUID, UUID } from '@opencrvs/commons' +import { getTokenPayload, getUUID, UUID } from '@opencrvs/commons' import { MAKE_CORRECTION_EXTENSION_URL } from '@workflow/features/task/fhir/constants' import { ApproveRequestInput, @@ -69,7 +71,9 @@ import { badRequest, internal } from '@hapi/boom' import { getUserOrSystem, isSystem } from './user' import { getLoggedInPractitionerResource, - getPractitionerOfficeId + getPractitionerOfficeId, + getPractitionerRoleByPractitionerId, + getUser } from '@workflow/features/user/utils' import { z } from 'zod' import { fetchLocationHierarchy } from '@workflow/utils/location' @@ -1162,6 +1166,24 @@ export async function sendBundleToHearth( return responseBundle } +export async function getPractitionerRoleFromToken( + token: string +): Promise> { + const tokenPayload = getTokenPayload(token) + const userDetails = await getUser(tokenPayload.sub, { Authorization: token }) + const practitionerId = userDetails.practitionerId + const practitionerRoleBundle = (await getPractitionerRoleByPractitionerId( + practitionerId as UUID + )) as Bundle + + const practitionerRoleResource = practitionerRoleBundle.entry[0].resource + return { + fullUrl: + `/fhir/PractitionerRole/${practitionerRoleResource.id}/_history/${practitionerRoleResource.meta?.versionId}` as URLReference, + resource: practitionerRoleResource + } +} + function findSavedReference( temporaryReference: URNReference, resourceBundle: Bundle, diff --git a/packages/workflow/src/records/handler/download.ts b/packages/workflow/src/records/handler/download.ts index a01001634c0..35b8bb778b2 100644 --- a/packages/workflow/src/records/handler/download.ts +++ b/packages/workflow/src/records/handler/download.ts @@ -47,10 +47,8 @@ export async function downloadRecordHandler( throw new Error("Task didn't have any status. This should never happen") } - const { downloadedRecordWithTaskOnly, downloadedRecord } = await toDownloaded( - record, - token - ) + const { downloadedBundleWithResources, downloadedRecord } = + await toDownloaded(record, token) const assignment = findAssignment(record) if (assignment) { @@ -69,7 +67,7 @@ export async function downloadRecordHandler( process.nextTick(async () => { try { // Here the sent bundle is saved with task only - await sendBundleToHearth(downloadedRecordWithTaskOnly) + await sendBundleToHearth(downloadedBundleWithResources) await auditEvent('assigned', downloadedRecord, token) await indexBundleToRoute(downloadedRecord, token, '/events/assigned') diff --git a/packages/workflow/src/records/handler/view.ts b/packages/workflow/src/records/handler/view.ts index 3fff6521343..f44488a0eab 100644 --- a/packages/workflow/src/records/handler/view.ts +++ b/packages/workflow/src/records/handler/view.ts @@ -11,7 +11,6 @@ import * as Hapi from '@hapi/hapi' import { getToken } from '@workflow/utils/auth-utils' import { getValidRecordById } from '@workflow/records/index' -import { Bundle } from '@opencrvs/commons/types' import { toViewed } from '@workflow/records/state-transitions' import { sendBundleToHearth } from '@workflow/records/fhir' import { auditEvent } from '@workflow/records/audit' @@ -24,19 +23,10 @@ export async function viewRecordHandler( const recordId = request.params.id const record = await getValidRecordById(recordId, token, true) - const viewedRecord = await toViewed(record, token) - - const viewedRecordWithSpecificEntries: Bundle = { - ...viewedRecord, - entry: [ - ...viewedRecord.entry.filter( - (e) => - e.resource.resourceType === 'Task' || - /* PractitionerRole needs to exist in bundle it's needed for creating history of a record */ - e.resource.resourceType === 'PractitionerRole' - ) - ] - } + const { viewedRecord, viewedRecordWithSpecificEntries } = await toViewed( + record, + token + ) await sendBundleToHearth(viewedRecordWithSpecificEntries) await auditEvent('viewed', viewedRecord, token) diff --git a/packages/workflow/src/records/state-transitions.ts b/packages/workflow/src/records/state-transitions.ts index fb8f3c017f5..ccc746e9753 100644 --- a/packages/workflow/src/records/state-transitions.ts +++ b/packages/workflow/src/records/state-transitions.ts @@ -50,9 +50,10 @@ import { toHistoryResource, TaskHistory, RejectedRecord, - SupportedPatientIdentifierCode + SupportedPatientIdentifierCode, + PractitionerRole } from '@opencrvs/commons/types' -import { getTokenPayload, getUUID, logger, UUID } from '@opencrvs/commons' +import { getUUID, logger, UUID } from '@opencrvs/commons' import { REG_NUMBER_SYSTEM, SECTION_CODE @@ -105,14 +106,11 @@ import { withPractitionerDetails, mergeChangedResourcesIntoRecord, createReinstateTask, - mergeBundles + mergeBundles, + getPractitionerRoleFromToken } from '@workflow/records/fhir' import { REG_NUMBER_GENERATION_FAILED } from '@workflow/features/registration/fhir/constants' import { tokenExchangeHandler } from './token-exchange-handler' -import { - getPractitionerRoleByPractitionerId, - getUser -} from '@workflow/features/user/utils' export async function toCorrected( record: RegisteredRecord | CertifiedRecord | IssuedRecord, @@ -299,7 +297,7 @@ export async function toUpdated( export async function toViewed( record: T, token: string -): Promise { +) { const previousTask: SavedTask = getTaskFromSavedBundle(record) const viewedTask = await createViewTask(previousTask, token) @@ -307,12 +305,7 @@ export async function toViewed( toHistoryResource(previousTask) ) as SavedBundleEntry - const tokenPayload = getTokenPayload(token) - const userDetails = await getUser(tokenPayload.sub, { Authorization: token }) - const practitionerId = userDetails.practitionerId - const practitionerRoleBundle = await getPractitionerRoleByPractitionerId( - practitionerId as UUID - ) + const practitionerRoleEntry = await getPractitionerRoleFromToken(token) const filteredEntries = record.entry.filter( (e) => e.resource.resourceType !== 'Task' @@ -333,11 +326,24 @@ export async function toViewed( /* PractitionerRole resource is saved in the bundle since PractitionerRole is fetched from bundle in the resolvers during readying history of a record */ - practitionerRoleBundle.entry[0] + practitionerRoleEntry ] } as T - return viewedRecord + const viewedRecordWithSpecificEntries: Bundle = { + ...viewedRecord, + entry: [ + { + fullUrl: record.entry.filter( + (e) => e.resource.resourceType === 'Task' + )[0].fullUrl, + resource: viewedTask + }, + practitionerRoleEntry + ] + } + + return { viewedRecord, viewedRecordWithSpecificEntries } } export function toIdentifierUpserted( @@ -379,7 +385,7 @@ export async function toDownloaded( token: string ): Promise<{ downloadedRecord: ValidRecord - downloadedRecordWithTaskOnly: Bundle + downloadedBundleWithResources: Bundle }> { const previousTask = getTaskFromSavedBundle(record) const taskWithoutPractitionerDetails = createDownloadTask(previousTask) @@ -401,9 +407,19 @@ export async function toDownloaded( resource: downloadedTask } + /* + When a user tries to access a record for the first time, + practitionerRoleBundle is necessary to create the history of the record + */ + const practitionerRoleEntry = await getPractitionerRoleFromToken(token) const updatedBundle = { ...record, - entry: [...filteredEntriesWithoutTask, newTaskEntry, taskHistoryEntry] + entry: [ + ...filteredEntriesWithoutTask, + newTaskEntry, + taskHistoryEntry, + practitionerRoleEntry + ] } const downloadedRecord = mergeBundles( @@ -411,13 +427,16 @@ export async function toDownloaded( practitionerDetailsBundle ) as ValidRecord - const downloadedRecordWithTaskOnly: Bundle = { + const downloadedBundleWithResources: Bundle = { resourceType: 'Bundle', type: 'document', - entry: [{ resource: downloadedTask }] + entry: [ + { resource: downloadedTask }, + { resource: practitionerRoleEntry.resource } + ] } - return { downloadedRecord, downloadedRecordWithTaskOnly } + return { downloadedRecord, downloadedBundleWithResources } } export async function toRejected(