From fde5575dfe1fdc565cee86f2cf95967214293e4e Mon Sep 17 00:00:00 2001 From: Georgi 7DIGIT Date: Tue, 17 Sep 2024 21:31:53 +0300 Subject: [PATCH] Add: check if the providers for organization have future scheduled consultations and also refactor the reassigning of providers to org after they have been removed --- service/controllers/organizations.js | 88 +++++++++++++++++++++++-- service/queries/organizations.js | 99 ++++++++++++++++++++++++---- 2 files changed, 170 insertions(+), 17 deletions(-) diff --git a/service/controllers/organizations.js b/service/controllers/organizations.js index d1546e9..b7aadc9 100644 --- a/service/controllers/organizations.js +++ b/service/controllers/organizations.js @@ -1,6 +1,7 @@ import { getMultipleClientsDataByIDs } from "#queries/clients"; import { assignProviderToOrganizationQuery, + checkProvidersFutureConsultationsForOrgQuery, createOrganizationQuery, editOrganizationQuery, getAllOrganizationsQuery, @@ -8,11 +9,14 @@ import { getConsultationsForOrganizationsQuery, getOrganizationByIdQuery, getProviderConsultationsForOrganizationQuery, + getProviderOrganizationLinkQuery, + reassignProviderToOrganizationQuery, removeProviderFromOrganizationQuery, } from "#queries/organizations"; import { getMultipleProvidersDataByIDs } from "#queries/providers"; import { organizationExists, + organizationNotFound, providerAlreadyAssignedToOrg, } from "#utils/errors"; @@ -41,16 +45,51 @@ export const editOrganization = async (data) => { }; export const assignProviderToOrganization = async (data) => { - return await assignProviderToOrganizationQuery(data) + const assignedProviders = await getProviderOrganizationLinkQuery(data) .then((res) => { if (res.rows.length === 0) { - throw providerAlreadyAssignedToOrg(data.language); + return false; } - return res.rows[0]; + return res.rows; }) .catch((err) => { throw err; }); + + const assignedProviderIds = assignedProviders + ? assignedProviders.map((x) => x.provider_detail_id) + : []; + const notAssignedProviders = data.providerDetailIds.filter( + (x) => !assignedProviderIds.includes(x) + ); + + if (notAssignedProviders.length > 0) { + await assignProviderToOrganizationQuery({ + organizationId: data.organizationId, + providerDetailIds: notAssignedProviders, + country: data.country, + }) + .then((res) => { + if (res.rows.length === 0) { + throw providerAlreadyAssignedToOrg(data.language); + } + return res.rows[0]; + }) + .catch((err) => { + throw err; + }); + } + if (assignedProviderIds.length > 0) { + await reassignProviderToOrganizationQuery({ + organizationId: data.organizationId, + providerDetailIds: assignedProviderIds, + country: data.country, + }).catch((err) => { + console.log("err"); + throw err; + }); + } + return { success: true }; }; export const getAllOrganizations = async (data) => { @@ -121,13 +160,23 @@ export const getOrganizationById = async (data) => { (x) => x.provider_detail_id ); - const providersData = await getMultipleProvidersDataByIDs({ + let providersData = await getMultipleProvidersDataByIDs({ providerDetailIds, poolCountry: data.country, }).then((res) => { return res.rows; }); + if (data.search) { + providersData = providersData.filter((x) => { + return ( + x.name.toLowerCase().includes(data.search.toLowerCase()) || + x.surname.toLowerCase().includes(data.search.toLowerCase()) || + x.patronym.toLowerCase().includes(data.search.toLowerCase()) + ); + }); + } + const providerConsultationsForOrg = await getProviderConsultationsForOrganizationQuery({ organizationId: organization.organization_id, @@ -138,10 +187,24 @@ export const getOrganizationById = async (data) => { endTime: data.endTime, weekdays: data.weekdays, weekends: data.weekends, + search: data.search, }).then((res) => { return res.rows; }); + const futureConsultationsForProviders = + await checkProvidersFutureConsultationsForOrgQuery({ + providerDetailIds, + organizationId: organization.organization_id, + country: data.country, + }) + .then((res) => { + return res.rows || []; + }) + .catch((err) => { + throw err; + }); + const allClientIds = Array.from( new Set( providerConsultationsForOrg.reduce((acc, x) => { @@ -165,9 +228,18 @@ export const getOrganizationById = async (data) => { throw err; }); + const includedProvidersDetailIds = providersData.map( + (x) => x.provider_detail_id + ); + for (let i = 0; i < organization.providers.length; i++) { const provider = organization.providers[i]; + if (!includedProvidersDetailIds.includes(provider.provider_detail_id)) { + delete organization.providers[i]; + continue; + } + const dataForProvider = providersData.find( (x) => x.provider_detail_id === provider.provider_detail_id ); @@ -180,6 +252,11 @@ export const getOrganizationById = async (data) => { consultations: [], }; + const futureConsultationsForProvider = + futureConsultationsForProviders.find( + (x) => x.provider_detail_id === provider.provider_detail_id + )?.count || 0; + consultationsDataForProvider.consultations = consultationsDataForProvider.consultations.map((x) => { const consultationClient = allClients.find( @@ -197,9 +274,12 @@ export const getOrganizationById = async (data) => { ...provider, ...dataForProvider, ...consultationsDataForProvider, + future_consultations: futureConsultationsForProvider, }; } + organization.providers = organization.providers.filter((x) => !!x); + return organization; }; diff --git a/service/queries/organizations.js b/service/queries/organizations.js index d5d4d54..434626b 100644 --- a/service/queries/organizations.js +++ b/service/queries/organizations.js @@ -23,9 +23,25 @@ export const getAllOrganizationsQuery = async ({ country: poolCountry }) => { ); }; +export const getProviderOrganizationLinkQuery = async ({ + organizationId, + providerDetailIds, + country: poolCountry, +}) => { + return await getDBPool("piiDb", poolCountry).query( + ` + SELECT * + FROM organization_provider_links + WHERE organization_id = $1 AND provider_detail_id = ANY($2::uuid[]); + `, + [organizationId, providerDetailIds] + ); +}; + export const assignProviderToOrganizationQuery = async ({ organizationId, - providerDetailIds, // Now an array of provider IDs + providerDetailIds, + country: poolCountry, }) => { return await getDBPool("piiDb", poolCountry).query( @@ -48,6 +64,27 @@ export const assignProviderToOrganizationQuery = async ({ ); }; +export const reassignProviderToOrganizationQuery = async ({ + organizationId, + providerDetailIds, + country: poolCountry, +}) => { + return await getDBPool("piiDb", poolCountry).query( + ` + UPDATE + organization_provider_links + SET + deleted_at = NULL, + is_deleted = false, + created_at = NOW() + WHERE + organization_id = $1 + AND provider_detail_id = ANY($2::uuid[]) + `, + [organizationId, providerDetailIds] + ); +}; + export const getAllOrganizationsWithDetailsQuery = async ({ country: poolCountry, }) => { @@ -57,7 +94,7 @@ export const getAllOrganizationsWithDetailsQuery = async ({ organization_provider_links.provider_detail_id ) AS providers FROM organization - JOIN organization_provider_links ON (organization.organization_id = organization_provider_links.organization_id AND organization_provider_links.is_deleted = false) + LEFT JOIN organization_provider_links ON (organization.organization_id = organization_provider_links.organization_id AND organization_provider_links.is_deleted = false) GROUP BY organization.organization_id ORDER BY organization.created_at DESC; ` @@ -74,15 +111,12 @@ export const getOrganizationByIdQuery = async ({ JSON_AGG( JSON_BUILD_OBJECT( 'provider_detail_id', organization_provider_links.provider_detail_id, - 'provider_join_date', organization_provider_links.created_at + 'provider_join_date', organization_provider_links.created_at, + 'provider_leave_date', organization_provider_links.deleted_at ) ) AS providers FROM organization - JOIN organization_provider_links ON ( - organization.organization_id = organization_provider_links.organization_id - AND - organization_provider_links.is_deleted = false - ) + LEFT JOIN organization_provider_links ON organization.organization_id = organization_provider_links.organization_id WHERE organization.organization_id = $1 GROUP BY organization.organization_id; `, @@ -149,6 +183,30 @@ export const getProviderConsultationsForOrganizationQuery = async ({ ); }; +export const checkProvidersFutureConsultationsForOrgQuery = async ({ + providerDetailIds, + organizationId, + country: poolCountry, +}) => { + return await getDBPool("clinicalDb", poolCountry).query( + ` + SELECT + provider_detail_id, + COUNT(DISTINCT consultation_id) AS count + FROM + consultation + WHERE + organization_id = $1 + AND provider_detail_id = ANY($2::uuid[]) + AND status = 'scheduled' + AND time > NOW() + GROUP BY + provider_detail_id; + `, + [organizationId, providerDetailIds] + ); +}; + export const editOrganizationQuery = async ({ name, organizationId, @@ -173,11 +231,26 @@ export const removeProviderFromOrganizationQuery = async ({ }) => { return await getDBPool("piiDb", poolCountry).query( ` - UPDATE organization_provider_links - SET deleted_at = NOW(), - is_deleted = true - WHERE organization_id = $1 AND provider_detail_id = $2 - RETURNING *; + UPDATE organization_provider_links + SET deleted_at = NOW(), + is_deleted = true, + periods = CASE + -- If periods is already an array, append the new object to the array + WHEN jsonb_typeof(periods) = 'array' THEN periods || jsonb_build_object( + 'enrolled_at', created_at, + 'removed_at', NOW() + ) + -- If periods is NULL or not an array, create a new array with the current periods and the new object + ELSE jsonb_build_array( + periods, + jsonb_build_object( + 'enrolled_at', created_at, + 'removed_at', NOW() + ) + ) + END + WHERE organization_id = $1 AND provider_detail_id = $2 + RETURNING *; `, [organizationId, providerDetailId] );