Implemented notification strategy

This commit is contained in:
2026-10-22 22:59:33 +02:00
parent 7071c404f0
commit 46c6ddcc80
11 changed files with 784 additions and 71 deletions
@@ -1,6 +1,19 @@
import axios, { AxiosError } from 'axios';
import { apiClient } from './httpClient';
import { toolsService } from './toolsService';
import {
notifyTenantManagersAndExecutivesOnRecordStatusChange,
notifyInviteApproved,
notifyNewUserCreated,
isApprovedOrActiveStatus,
} from './notificationRulesService';
export {
notifyTenantManagersAndExecutivesOnRecordStatusChange,
notifyInviteApproved,
notifyNewUserCreated,
isApprovedOrActiveStatus,
};
import {
getCurrentUserSub,
getCurrentUserTenantId,
@@ -64,6 +77,7 @@ import {
AuditLog,
ProblemDetails,
ActivityStatus,
ApprovalStatus,
Tenant,
TenantOrganisation,
TenantUser,
@@ -239,6 +253,7 @@ export const createOrganisation = async (payload: CreateOrganisationRequest): Pr
};
export const updateOrganisation = async (payload: UpdateOrganisationRequest): Promise<Organisation> => {
const orgStatus = payload.status !== undefined ? Number(payload.status) : ActivityStatus.Active;
const res = await apiClient.put('/v1/api/governance/organisations', {
organisationId: toIntegerId(payload.organisationId),
name: payload.name,
@@ -247,8 +262,16 @@ export const updateOrganisation = async (payload: UpdateOrganisationRequest): Pr
idNumber: payload.idNumber,
organisationUser: payload.organisationUser,
type: Number(payload.type),
status: payload.status !== undefined ? Number(payload.status) : ActivityStatus.Active,
status: orgStatus,
});
if (isApprovedOrActiveStatus(orgStatus)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Organisation',
recordId: payload.organisationId,
newStatus: orgStatus,
title: payload.name,
}).catch(console.warn);
}
return res.data;
};
@@ -622,6 +645,14 @@ export const updateInstrument = async (payload: UpdateInstrumentRequest): Promis
if (existing) {
saveStoredInstruction(updatedInstrument);
}
if (isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Funding Instrument',
recordId: targetId!,
newStatus: payload.status,
title: payload.name,
}).catch(console.warn);
}
return updatedInstrument;
};
@@ -667,12 +698,21 @@ export const updateProgramme = async (payload: UpdateProgrammeRequest): Promise<
if (ownerId && typeof ownerId === 'string' && ownerId.includes('@')) {
ownerId = getUserIdByEmail(ownerId) || userSub || ownerId;
}
const progStatus = Number(payload.status) || 1;
const res = await apiClient.put('/v1/api/projects/programme', {
programmeId: toIntegerId(payload.programmeId),
name: payload.name,
ownerId: ownerId || userSub || '00000000-0000-0000-0000-000000000000',
status: Number(payload.status) || 1,
status: progStatus,
});
if (isApprovedOrActiveStatus(progStatus)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Programme',
recordId: payload.programmeId,
newStatus: progStatus,
title: payload.name,
}).catch(console.warn);
}
return res.data;
};
@@ -725,6 +765,13 @@ export const updateProjectStatus = async (payload: UpdateProjectStatusRequest):
projectId: toIntegerId(payload.projectId),
status: Number(payload.status),
});
if (isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Project',
recordId: payload.projectId,
newStatus: payload.status,
}).catch(console.warn);
}
};
export const getActivities = async (projectId: string | number): Promise<Activity[]> => {
@@ -826,6 +873,14 @@ export const updateMilestone = async (payload: UpdateMilestoneRequest): Promise<
priority: Number(payload.priority) || 1,
status: Number(payload.status) || 1,
});
if (isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Milestone',
recordId: payload.milestoneId,
newStatus: payload.status,
title: payload.name,
}).catch(console.warn);
}
};
export const getProjectIndicators = async (projectId: string | number): Promise<Indicator[]> => {
@@ -884,6 +939,13 @@ export const updateAward = async (payload: UpdateAwardRequest): Promise<void> =>
amount: Number(payload.amount),
...(payload.status !== undefined ? { status: Number(payload.status) } : {}),
});
if (payload.status === undefined || isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Award',
recordId: payload.awardId,
newStatus: payload.status !== undefined ? payload.status : ApprovalStatus.Approved,
}).catch(console.warn);
}
};
export const fetchHashId = async (id64: number | string): Promise<string> => {
@@ -1018,6 +1080,14 @@ export const updateContract = async (payload: UpdateContractRequest): Promise<vo
contractId: toIntegerId(payload.contractId),
status: Number(payload.status),
});
if (isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Contract',
recordId: payload.contractId,
newStatus: payload.status,
}).catch(console.warn);
}
};
export const uploadContractFile = async (
@@ -1078,6 +1148,13 @@ export const updateBudget = async (payload: UpdateBudgetRequest): Promise<void>
budgetId: toIntegerId(payload.budgetId),
status: Number(payload.status),
});
if (isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Budget',
recordId: payload.budgetId,
newStatus: payload.status,
}).catch(console.warn);
}
};
// ==========================================
@@ -1116,6 +1193,11 @@ export const updateDisbursement = async (payload: UpdateDisbursementRequest): Pr
export const approveDisbursement = async (disbursementId: string | number): Promise<void> => {
const hashedDisbId = await toolsService.encodeId(disbursementId);
await apiClient.post(`/v1/api/execution/disbursements/${hashedDisbId}/approve`, {});
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Disbursement',
recordId: disbursementId,
newStatus: ApprovalStatus.Approved,
}).catch(console.warn);
};
/**
@@ -1316,6 +1398,13 @@ export const updateEvidence = async (payload: UpdateEvidenceRequest): Promise<vo
evidenceType: Number(payload.evidenceType),
status: Number(payload.status),
});
if (isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Evidence',
recordId: payload.evidenceId,
newStatus: payload.status,
}).catch(console.warn);
}
};
// ==========================================
@@ -1689,6 +1778,14 @@ export const updateTenant = async (payload: UpdateTenantRequest): Promise<void>
name: payload.name,
status: Number(payload.status),
});
if (isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Tenant',
recordId: payload.tenantId,
newStatus: payload.status,
title: payload.name,
}).catch(console.warn);
}
};
export const getTenantOrganisations = async (tenantId: string | number): Promise<TenantOrganisation[]> => {
@@ -1854,6 +1951,14 @@ export const updateOutcome = async (payload: UpdateOutcomeRequest): Promise<void
description: payload.description,
status: Number(payload.status),
});
if (isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Outcome',
recordId: payload.outcomeId,
newStatus: payload.status,
title: payload.name,
}).catch(console.warn);
}
};
// ==========================================
@@ -1915,6 +2020,14 @@ export const updateChangeRequest = async (payload: UpdateChangeRequest): Promise
revisedBudget: Number(payload.revisedBudget),
status: Number(payload.status),
});
if (isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Change Request',
recordId: payload.changeRequestId,
newStatus: payload.status,
title: payload.title,
}).catch(console.warn);
}
};
// ==========================================
@@ -1975,6 +2088,14 @@ export const updateComplianceItem = async (payload: UpdateComplianceItemRequest)
status: Number(payload.status),
beneficiaryId: payload.beneficiaryId ? toIntegerId(payload.beneficiaryId) : null,
});
if (isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Compliance Item',
recordId: payload.complianceItemId,
newStatus: payload.status,
title: payload.title,
}).catch(console.warn);
}
};
// ==========================================
@@ -2042,6 +2163,15 @@ export const updateIssue = async (payload: UpdateIssueRequest): Promise<void> =>
status: payload.status !== undefined ? Number(payload.status) : ActivityStatus.Active,
assignedTo: payload.assignedTo,
});
const issueStatus = payload.status !== undefined ? payload.status : ActivityStatus.Active;
if (isApprovedOrActiveStatus(issueStatus)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Issue',
recordId: payload.issueId,
newStatus: issueStatus,
title: payload.title,
}).catch(console.warn);
}
};
// ==========================================
@@ -2106,6 +2236,14 @@ export const updateSiteVisit = async (payload: UpdateSiteVisitRequest): Promise<
status: Number(payload.status),
visitedAt: visitedAtIso,
});
if (isApprovedOrActiveStatus(payload.status)) {
notifyTenantManagersAndExecutivesOnRecordStatusChange({
recordType: 'Site Visit',
recordId: payload.siteVisitId,
newStatus: payload.status,
title: payload.inspectorName,
}).catch(console.warn);
}
};
const LOCAL_RULES_KEY = 'pfm_local_rules';