Skip to content

Commit

Permalink
Merge pull request #440 from code4romania/refactor/error_handling-con…
Browse files Browse the repository at this point in the history
…tracts

Refactor: error message updates + client mapping
  • Loading branch information
radulescuandrew authored Oct 3, 2024
2 parents 67e163b + cd4d877 commit f096aaa
Show file tree
Hide file tree
Showing 13 changed files with 103 additions and 43 deletions.
20 changes: 20 additions & 0 deletions backend/src/modules/documents/exceptions/contract.exceptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export enum ContractExceptionCodes {
CONTRACT_013 = 'CONTRACT_013',
CONTRACT_014 = 'CONTRACT_014',
CONTRACT_015 = 'CONTRACT_015',
CONTRACT_016 = 'CONTRACT_016',
CONTRACT_017 = 'CONTRACT_017',
CONTRACT_018 = 'CONTRACT_018',
CONTRACT_019 = 'CONTRACT_019',
}

type ContractExceptionCodeType = keyof typeof ContractExceptionCodes;
Expand Down Expand Up @@ -86,4 +90,20 @@ export const ContractExceptionMessages: Record<
code_error: ContractExceptionCodes.CONTRACT_015,
message: 'Error while deleting the contract',
},
[ContractExceptionCodes.CONTRACT_016]: {
code_error: ContractExceptionCodes.CONTRACT_016,
message: 'Only Pending Contracts can be rejected',
},
[ContractExceptionCodes.CONTRACT_017]: {
code_error: ContractExceptionCodes.CONTRACT_017,
message: 'Error while rejecting the contract by NGO',
},
[ContractExceptionCodes.CONTRACT_018]: {
code_error: ContractExceptionCodes.CONTRACT_018,
message: 'Error while signing the contract by NGO',
},
[ContractExceptionCodes.CONTRACT_019]: {
code_error: ContractExceptionCodes.CONTRACT_019,
message: 'Error while approving the contract by NGO',
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { IVolunteerModel } from 'src/modules/volunteer/model/volunteer.model';
import { VolunteerFacade } from 'src/modules/volunteer/services/volunteer.facade';
import { GetOrganizationUseCaseService } from 'src/usecases/organization/get-organization.usecase';
import * as z from 'zod';
import { DocumentTemplateExceptionMessages } from 'src/modules/documents/exceptions/documente-template.exceptions';

/*
Possible errors thrown:
Expand Down Expand Up @@ -312,11 +313,9 @@ export class CreateDocumentContractUsecase implements IUseCaseService<string> {
});

if (!template) {
this.exceptionsService.notFoundException({
// TODO update this exception
message: 'Template not found',
code_error: 'TEMPLATE_NOT_FOUND',
});
this.exceptionsService.notFoundException(
DocumentTemplateExceptionMessages.TEMPLATE_001,
);
}

return template;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ export class DeleteDocumentContractUsecase implements IUseCaseService<string> {
const deleted = await this.documentContractFacade.delete(id);

if (!deleted) {
throw new Error('Could not delete contract from DB');
this.exceptionService.badRequestException(
ContractExceptionMessages.CONTRACT_015,
);
}

// Delete file from S3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ExceptionsService } from 'src/infrastructure/exceptions/exceptions.serv
import { DocumentContractStatus } from 'src/modules/documents/enums/contract-status.enum';
import { ContractExceptionMessages } from 'src/modules/documents/exceptions/contract.exceptions';
import { DocumentContractFacade } from 'src/modules/documents/services/document-contract.facade';
import { VolunteerExceptionMessages } from 'src/modules/volunteer/exceptions/volunteer.exceptions';
import { VolunteerFacade } from 'src/modules/volunteer/services/volunteer.facade';

// ┌─────────────────────────────────────────────────────────────────────────┐
Expand Down Expand Up @@ -88,10 +89,9 @@ export class RejectDocumentContractByVolunteerUsecase
organizationId,
});
if (!volunteer) {
this.exceptionService.notFoundException({
message: 'Volunteer is not part of the organization',
code_error: 'VOLUNTEER_NOT_PART_OF_ORGANIZATION',
});
this.exceptionService.badRequestException(
VolunteerExceptionMessages.VOLUNTEER_005,
);
}

/* ┌─────────────────────────────────────────────────────────────────────┐
Expand Down Expand Up @@ -137,7 +137,6 @@ export class RejectDocumentContractByVolunteerUsecase
* │ with the rejection reason. │
* └─────────────────────────────────────────────────────────────────────┘
*/
// TODO: Implement audit trail logging
console.log('rejectionReason', rejectionReason);

// TODO: Implement notification to relevant parties
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common';
import { Injectable, Logger } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { IUseCaseService } from 'src/common/interfaces/use-case-service.interface';
import { ExceptionsService } from 'src/infrastructure/exceptions/exceptions.service';
Expand All @@ -12,11 +12,13 @@ import { EVENTS } from 'src/modules/notifications/constants/events.constants';
import RejectContractEvent from 'src/modules/notifications/events/documents/reject-contract.event';
import { IAdminUserModel } from 'src/modules/user/models/admin-user.model';
import { VolunteerFacade } from 'src/modules/volunteer/services/volunteer.facade';
import * as Sentry from '@sentry/node';

@Injectable()
export class RejectDocumentContractByNgoUsecase
implements IUseCaseService<void>
{
private readonly logger = new Logger(RejectDocumentContractByNgoUsecase.name);
constructor(
private readonly documentContractFacade: DocumentContractFacade,
private readonly exceptionService: ExceptionsService,
Expand Down Expand Up @@ -53,11 +55,9 @@ export class RejectDocumentContractByNgoUsecase
DocumentContractStatus.PENDING_NGO_REPRESENTATIVE_SIGNATURE,
].includes(contract.status) !== true
) {
// TODO: update error
this.exceptionService.notFoundException({
message: 'Only Pending Contracts can be rejected',
code_error: 'REJECT_DOCUMENT_CONTRACT_BY_NGO_02',
});
this.exceptionService.badRequestException(
ContractExceptionMessages.CONTRACT_016,
);
}

let updatedContract: IDocumentContractModel;
Expand All @@ -69,11 +69,13 @@ export class RejectDocumentContractByNgoUsecase
admin.id,
);
} catch (error) {
// TODO: Update error
this.exceptionService.internalServerErrorException({
message: `Error while rejecting the contract by NGO ${error?.message}`,
code_error: 'REJECT_DOCUMENT_CONTRACT_BY_NGO_002',
});
Sentry.captureException(error);
this.logger.error(
`Error while rejecting the contract by NGO ${error?.message}`,
);
this.exceptionService.internalServerErrorException(
ContractExceptionMessages.CONTRACT_017,
);
}

// Track Rejection Event including Rejection Reason
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common';
import { Injectable, Logger } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { IUseCaseService } from 'src/common/interfaces/use-case-service.interface';
import { ExceptionsService } from 'src/infrastructure/exceptions/exceptions.service';
Expand All @@ -14,9 +14,11 @@ import { IAdminUserModel } from 'src/modules/user/models/admin-user.model';
import { VolunteerFacade } from 'src/modules/volunteer/services/volunteer.facade';
import { IDocumentContractModel } from 'src/modules/documents/models/document-contract.model';
import SignContractEvent from 'src/modules/notifications/events/documents/sign-contract.event';
import * as Sentry from '@sentry/nestjs';

@Injectable()
export class SignDocumentContractByNgoUsecase implements IUseCaseService<void> {
private readonly logger = new Logger(SignDocumentContractByNgoUsecase.name);
constructor(
private readonly documentContractFacade: DocumentContractFacade,
private readonly documentSignatureFacade: DocumentSignatureFacade,
Expand Down Expand Up @@ -56,11 +58,13 @@ export class SignDocumentContractByNgoUsecase implements IUseCaseService<void> {
signatureId,
);
} catch (error) {
// TODO: Update error
this.exceptionService.internalServerErrorException({
message: `Error while sigining the contract by NGO ${error?.message}`,
code_error: 'SIGN_DOCUMENT_CONTRACT_BY_NGO_003',
});
Sentry.captureException(error);
this.logger.error(
`Error while sigining the contract by NGO ${error?.message}`,
);
this.exceptionService.internalServerErrorException(
ContractExceptionMessages.CONTRACT_018,
);
}

await this.documentPDFGenerator.generateContractPDF(documentContractId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { DocumentContractFacade } from 'src/modules/documents/services/document-
import { DocumentSignatureFacade } from 'src/modules/documents/services/document-signature.facade';
import { DocumentPDFGenerator } from 'src/modules/documents/services/document-pdf-generator';
import { VolunteerFacade } from 'src/modules/volunteer/services/volunteer.facade';
import { VolunteerExceptionMessages } from 'src/modules/volunteer/exceptions/volunteer.exceptions';

// ┌─────────────────────────────────────────────────────────────────────────┐
// │ Business Rules for SignDocumentContractByVolunteerUsecase: │
Expand Down Expand Up @@ -100,10 +101,9 @@ export class SignDocumentContractByVolunteerUsecase
organizationId,
});
if (!volunteer) {
this.exceptionService.notFoundException({
message: 'Volunteer is not part of the organization',
code_error: 'VOLUNTEER_NOT_PART_OF_ORGANIZATION',
});
this.exceptionService.notFoundException(
VolunteerExceptionMessages.VOLUNTEER_001,
);
}

// ┌─────────────────────────────────────────────────────────────────────┐
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common';
import { Injectable, Logger } from '@nestjs/common';
import { ExceptionsService } from 'src/infrastructure/exceptions/exceptions.service';
import { ActionsArchiveFacade } from 'src/modules/actions-archive/actions-archive.facade';
import { TrackedEventName } from 'src/modules/actions-archive/enums/action-resource-types.enum';
Expand All @@ -7,9 +7,14 @@ import { ContractExceptionMessages } from 'src/modules/documents/exceptions/cont
import { IDocumentContractModel } from 'src/modules/documents/models/document-contract.model';
import { DocumentContractFacade } from 'src/modules/documents/services/document-contract.facade';
import { IAdminUserModel } from 'src/modules/user/models/admin-user.model';
import * as Sentry from '@sentry/node';

@Injectable()
export class ValidateDocumentContractByNgoUsecase {
private readonly logger = new Logger(
ValidateDocumentContractByNgoUsecase.name,
);

constructor(
private readonly documentContractFacade: DocumentContractFacade,
private readonly exceptionService: ExceptionsService,
Expand Down Expand Up @@ -39,11 +44,13 @@ export class ValidateDocumentContractByNgoUsecase {
documentContractId,
);
} catch (error) {
// TODO: Update error
this.exceptionService.internalServerErrorException({
message: `Error while approving the contract by NGO ${error?.message}`,
code_error: 'APPROVE_DOCUMENT_CONTRACT_BY_NGO_001',
});
Sentry.captureException(error);
this.logger.error(
`Error while approving the contract by NGO ${error?.message}`,
);
this.exceptionService.internalServerErrorException(
ContractExceptionMessages.CONTRACT_019,
);
}

// Track APPROVE contract event
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/assets/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@
"submit": {
"success": "The template has been created!",
"errors": {
"TEMPLATE_001": "Document upload error"
"TEMPLATE_002": "Document upload error"
}
}
}
Expand All @@ -896,8 +896,8 @@
"submit": {
"success": "The template has been updated!",
"errors": {
"TEMPLATE_001": "Document upload error",
"TEMPLATE_002": "Template not found"
"TEMPLATE_002": "Document upload error",
"TEMPLATE_001": "Template not found"
}
}
}
Expand Down Expand Up @@ -1313,4 +1313,4 @@
"clear": "Clear",
"apply_all": "Apply to all"
}
}
}
6 changes: 5 additions & 1 deletion frontend/src/assets/locales/ro/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1004,7 +1004,11 @@
"CONTRACT_003": "Eroare la upload-ul documentului!",
"CONTRACT_006": "Nu se poate șterge un contract deja aprobat!",
"CONTRACT_014": "Nu se poate șterge un contract care a fost semnat de una dintre părți!",
"CONTRACT_015": "Eroare la ștergerea contractului!"
"CONTRACT_015": "Eroare la ștergerea contractului!",
"CONTRACT_016": "Doar un contract in așteptare poate fi șters!",
"CONTRACT_017": "Eroare la respingerea contractului!",
"CONTRACT_018": "Eroare la semnarea contractului!",
"CONTRACT_019": "Eroare la validarea contractului!"
}
},
"upload": {
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/common/errors/entities/contract.errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ErrorClass } from '../base-error.class';

export enum CONTRACT_ERRORS {
ORG_001 = 'ORG_001',
TEMPLATE_001 = 'TEMPLATE_001',
VOLUNTEER_001 = 'VOLUNTEER_001',
TEMPLATE_002 = 'TEMPLATE_002',
CONTRACT_004 = 'CONTRACT_004',
Expand All @@ -14,6 +15,10 @@ export enum CONTRACT_ERRORS {

CONTRACT_014 = 'CONTRACT_014',
CONTRACT_015 = 'CONTRACT_015',
CONTRACT_016 = 'CONTRACT_016',
CONTRACT_017 = 'CONTRACT_017',
CONTRACT_018 = 'CONTRACT_018',
CONTRACT_019 = 'CONTRACT_019',
}

export class ContractError extends ErrorClass<CONTRACT_ERRORS> {
Expand All @@ -22,6 +27,9 @@ export class ContractError extends ErrorClass<CONTRACT_ERRORS> {
private constructor() {
super({
[CONTRACT_ERRORS.ORG_001]: i18n.t('organization:errors.ORG_001'),
[CONTRACT_ERRORS.TEMPLATE_001]: i18n.t(
'documents:template.edit.form.submit.errors.TEMPLATE_001',
),
[CONTRACT_ERRORS.VOLUNTEER_001]: i18n.t('volunteers:errors.VOLUNTEER_001'),
[CONTRACT_ERRORS.TEMPLATE_002]: i18n.t(
'documents:template.edit.form.submit.errors.TEMPLATE_002',
Expand All @@ -35,6 +43,10 @@ export class ContractError extends ErrorClass<CONTRACT_ERRORS> {

[CONTRACT_ERRORS.CONTRACT_014]: i18n.t('documents:contract.submit.errors.CONTRACT_014'),
[CONTRACT_ERRORS.CONTRACT_015]: i18n.t('documents:contract.submit.errors.CONTRACT_015'),
[CONTRACT_ERRORS.CONTRACT_016]: i18n.t('documents:contract.submit.errors.CONTRACT_016'),
[CONTRACT_ERRORS.CONTRACT_017]: i18n.t('documents:contract.submit.errors.CONTRACT_017'),
[CONTRACT_ERRORS.CONTRACT_018]: i18n.t('documents:contract.submit.errors.CONTRACT_018'),
[CONTRACT_ERRORS.CONTRACT_019]: i18n.t('documents:contract.submit.errors.CONTRACT_019'),
});
}

Expand Down
7 changes: 7 additions & 0 deletions frontend/src/common/utils/document-contracts.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ export const mapErrorCodeToTranslationKey = (errorCode: string): string => {
CONTRACT_008: 'doc_templates:errors.legal_guardian_required',
CONTRACT_011: 'doc_templates:errors.invalid_legal_guardian_data',
CONTRACT_009: 'doc_templates:errors.db_error',
VOLUNTEER_001: 'volunteers:errors.VOLUNTEER_001',
CONTRACT_014: 'documents:contract.submit.errors.CONTRACT_014',
CONTRACT_015: 'documents:contract.submit.errors.CONTRACT_015',
CONTRACT_016: 'documents:contract.submit.errors.CONTRACT_016',
CONTRACT_017: 'documents:contract.submit.errors.CONTRACT_017',
CONTRACT_018: 'documents:contract.submit.errors.CONTRACT_018',
CONTRACT_019: 'documents:contract.submit.errors.CONTRACT_019',
};

return errorMap[errorCode] || 'doc_templates:errors.unknown_error';
Expand Down
4 changes: 4 additions & 0 deletions mobile/src/common/errors/entities/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export enum CONTRACT_ERRORS {
CONTRACT_003 = 'CONTRACT_003',
CONTRACT_007 = 'CONTRACT_007',
TEMPLATE_002 = 'TEMPLATE_002',
VOLUNTEER_005 = 'VOLUNTEER_005',
VOLUNTEER_001 = 'VOLUNTEER_001',
}

export class ContractErrors extends ErrorClass<CONTRACT_ERRORS> {
Expand All @@ -19,6 +21,8 @@ export class ContractErrors extends ErrorClass<CONTRACT_ERRORS> {
[CONTRACT_ERRORS.CONTRACT_003]: i18n.t('documents:contract.errors.CONTRACT_003'),
[CONTRACT_ERRORS.CONTRACT_007]: i18n.t('documents:contract.errors.CONTRACT_007'),
[CONTRACT_ERRORS.TEMPLATE_002]: i18n.t('documents:contract.errors.TEMPLATE_002'),
[CONTRACT_ERRORS.VOLUNTEER_005]: i18n.t('volunteer:errors.VOLUNTEER_005'),
[CONTRACT_ERRORS.VOLUNTEER_001]: i18n.t('volunteer:errors.VOLUNTEER_001'),
});
}

Expand Down

0 comments on commit f096aaa

Please sign in to comment.