From 30add67b8cc055de2d4706ebe6ca5468a0ba3e14 Mon Sep 17 00:00:00 2001 From: Dragos-Paul Strat Date: Fri, 27 Sep 2024 11:23:09 +0300 Subject: [PATCH] feat: [contracts] add computed statuses for view one contract --- .../document-contract-web-item.presenter.ts | 6 +- ...0448699-document-client-web-view-status.ts | 113 ++++++++++++++++++ .../document-contract-web-item.entity.ts | 21 +++- .../document-contract-web-item.model.ts | 4 +- .../interfaces/document-contract.interface.ts | 2 +- .../src/components/ContractInfoContent.tsx | 46 +++---- 6 files changed, 160 insertions(+), 32 deletions(-) create mode 100644 backend/src/migrations/1727360448699-document-client-web-view-status.ts diff --git a/backend/src/api/documents/presenters/document-contract-web-item.presenter.ts b/backend/src/api/documents/presenters/document-contract-web-item.presenter.ts index ec6b8bec..98b4372e 100644 --- a/backend/src/api/documents/presenters/document-contract-web-item.presenter.ts +++ b/backend/src/api/documents/presenters/document-contract-web-item.presenter.ts @@ -1,6 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; import { Expose } from 'class-transformer'; -import { DocumentContractStatus } from 'src/modules/documents/enums/contract-status.enum'; +import { DocumentContractComputedStatuses } from 'src/modules/documents/enums/contract-status.enum'; import { IDocumentContractWebItemModel } from 'src/modules/documents/models/document-contract-web-item.model'; export class DocumentContractWebItemPresenter { @@ -66,9 +66,9 @@ export class DocumentContractWebItemPresenter { @Expose() @ApiProperty({ description: 'The status of the document contract', - enum: DocumentContractStatus, + enum: DocumentContractComputedStatuses, }) - status: DocumentContractStatus; + status: DocumentContractComputedStatuses; @Expose() @ApiProperty({ diff --git a/backend/src/migrations/1727360448699-document-client-web-view-status.ts b/backend/src/migrations/1727360448699-document-client-web-view-status.ts new file mode 100644 index 00000000..cffa358f --- /dev/null +++ b/backend/src/migrations/1727360448699-document-client-web-view-status.ts @@ -0,0 +1,113 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class DocumentClientWebViewStatus1727360448699 + implements MigrationInterface +{ + name = 'DocumentClientWebViewStatus1727360448699'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, + ['VIEW', 'DocumentContractWebItemView', 'public'], + ); + await queryRunner.query(`DROP VIEW "DocumentContractWebItemView"`); + await queryRunner.query(`CREATE VIEW "DocumentContractWebItemView" AS + SELECT + dc.id as "document_id", + dc.document_number, + dc.document_start_date, + dc.document_end_date, + CASE + WHEN dc.status = 'APPROVED' AND + dc.document_start_date <= CURRENT_DATE AND + dc.document_end_date >= CURRENT_DATE + THEN 'ACTIVE' + WHEN dc.status = 'APPROVED' AND + dc.document_start_date > CURRENT_DATE + THEN 'NOT_STARTED' + WHEN dc.status = 'APPROVED' AND + dc.document_end_date < CURRENT_DATE + THEN 'EXPIRED' + ELSE dc.status::text + END AS "status", + dc.file_path as "document_file_path", + dc.document_template_id, + dt."name" as "document_template_name", + dc.volunteer_id, + dc.volunteer_data->>'name' as "volunteer_name", + dc.created_by_admin_id, + "adminUser"."name" as "created_by_admin_name", + + dc.rejection_date, + dc.rejection_reason, + dc.rejected_by_id, + "rejectionUser".name as "rejected_by_name", + + dc.organization_id, + + dc.created_on, + dc.updated_on + FROM + document_contract dc + LEFT JOIN volunteer v ON v.id = dc.id + LEFT JOIN document_template dt on dt.id = dc.document_template_id + LEFT JOIN "user" "adminUser" ON dc.created_by_admin_id = "adminUser".id + LEFT JOIN "user" "rejectionUser" ON dc.rejected_by_id = "rejectionUser".id + `); + await queryRunner.query( + `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, + [ + 'public', + 'VIEW', + 'DocumentContractWebItemView', + 'SELECT\n dc.id as "document_id",\n dc.document_number,\n dc.document_start_date,\n dc.document_end_date,\n CASE \n WHEN dc.status = \'APPROVED\' AND \n dc.document_start_date <= CURRENT_DATE AND \n dc.document_end_date >= CURRENT_DATE \n THEN \'ACTIVE\'\n WHEN dc.status = \'APPROVED\' AND \n dc.document_start_date > CURRENT_DATE \n THEN \'NOT_STARTED\'\n WHEN dc.status = \'APPROVED\' AND \n dc.document_end_date < CURRENT_DATE \n THEN \'EXPIRED\'\n ELSE dc.status::text\n END AS "status",\n dc.file_path as "document_file_path",\n dc.document_template_id,\n dt."name" as "document_template_name",\n dc.volunteer_id,\n dc.volunteer_data->>\'name\' as "volunteer_name",\n dc.created_by_admin_id, \n "adminUser"."name" as "created_by_admin_name",\n \n dc.rejection_date,\n dc.rejection_reason,\n dc.rejected_by_id,\n "rejectionUser".name as "rejected_by_name",\n\n dc.organization_id,\n\n dc.created_on, \n dc.updated_on\n FROM\n document_contract dc\n LEFT JOIN volunteer v ON v.id = dc.id\n LEFT JOIN document_template dt on dt.id = dc.document_template_id\n LEFT JOIN "user" "adminUser" ON dc.created_by_admin_id = "adminUser".id\n LEFT JOIN "user" "rejectionUser" ON dc.rejected_by_id = "rejectionUser".id', + ], + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, + ['VIEW', 'DocumentContractWebItemView', 'public'], + ); + await queryRunner.query(`DROP VIEW "DocumentContractWebItemView"`); + await queryRunner.query(`CREATE VIEW "DocumentContractWebItemView" AS SELECT + dc.id as "document_id", + dc.document_number, + dc.document_start_date, + dc.document_end_date, + dc.status, + dc.file_path as "document_file_path", + dc.document_template_id, + dt."name" as "document_template_name", + dc.volunteer_id, + dc.volunteer_data->>'name' as "volunteer_name", + dc.created_by_admin_id, + "adminUser"."name" as "created_by_admin_name", + + dc.rejection_date, + dc.rejection_reason, + dc.rejected_by_id, + "rejectionUser".name as "rejected_by_name", + + dc.organization_id, + + dc.created_on, + dc.updated_on + FROM + document_contract dc + LEFT JOIN volunteer v ON v.id = dc.id + LEFT JOIN document_template dt on dt.id = dc.document_template_id + LEFT JOIN "user" "adminUser" ON dc.created_by_admin_id = "adminUser".id + LEFT JOIN "user" "rejectionUser" ON dc.rejected_by_id = "rejectionUser".id`); + await queryRunner.query( + `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, + [ + 'public', + 'VIEW', + 'DocumentContractWebItemView', + 'SELECT\n dc.id as "document_id",\n dc.document_number,\n dc.document_start_date,\n dc.document_end_date,\n dc.status,\n dc.file_path as "document_file_path",\n dc.document_template_id,\n dt."name" as "document_template_name",\n dc.volunteer_id,\n dc.volunteer_data->>\'name\' as "volunteer_name",\n dc.created_by_admin_id, \n "adminUser"."name" as "created_by_admin_name",\n \n dc.rejection_date,\n dc.rejection_reason,\n dc.rejected_by_id,\n "rejectionUser".name as "rejected_by_name",\n\n dc.organization_id,\n\n dc.created_on, \n dc.updated_on\n FROM\n document_contract dc\n LEFT JOIN volunteer v ON v.id = dc.id\n LEFT JOIN document_template dt on dt.id = dc.document_template_id\n LEFT JOIN "user" "adminUser" ON dc.created_by_admin_id = "adminUser".id\n LEFT JOIN "user" "rejectionUser" ON dc.rejected_by_id = "rejectionUser".id', + ], + ); + } +} diff --git a/backend/src/modules/documents/entities/document-contract-web-item.entity.ts b/backend/src/modules/documents/entities/document-contract-web-item.entity.ts index d784b497..bd5c86d6 100644 --- a/backend/src/modules/documents/entities/document-contract-web-item.entity.ts +++ b/backend/src/modules/documents/entities/document-contract-web-item.entity.ts @@ -1,5 +1,8 @@ import { Column, ViewColumn, ViewEntity } from 'typeorm'; -import { DocumentContractStatus } from '../enums/contract-status.enum'; +import { + DocumentContractComputedStatuses, + DocumentContractStatus, +} from '../enums/contract-status.enum'; @ViewEntity('DocumentContractWebItemView', { /* @@ -35,7 +38,19 @@ import { DocumentContractStatus } from '../enums/contract-status.enum'; dc.document_number, dc.document_start_date, dc.document_end_date, - dc.status, + CASE + WHEN dc.status = 'APPROVED' AND + dc.document_start_date <= CURRENT_DATE AND + dc.document_end_date >= CURRENT_DATE + THEN 'ACTIVE' + WHEN dc.status = 'APPROVED' AND + dc.document_start_date > CURRENT_DATE + THEN 'NOT_STARTED' + WHEN dc.status = 'APPROVED' AND + dc.document_end_date < CURRENT_DATE + THEN 'EXPIRED' + ELSE dc.status::text + END AS "status", dc.file_path as "document_file_path", dc.document_template_id, dt."name" as "document_template_name", @@ -80,7 +95,7 @@ export class DocumentContractWebItemView { documentFilePath: string; @ViewColumn({ name: 'status' }) - status: DocumentContractStatus; + status: DocumentContractComputedStatuses; @ViewColumn({ name: 'document_template_id' }) documentTemplateId: string; diff --git a/backend/src/modules/documents/models/document-contract-web-item.model.ts b/backend/src/modules/documents/models/document-contract-web-item.model.ts index 40cbef8f..353d0e8f 100644 --- a/backend/src/modules/documents/models/document-contract-web-item.model.ts +++ b/backend/src/modules/documents/models/document-contract-web-item.model.ts @@ -1,5 +1,5 @@ import { DocumentContractWebItemView } from '../entities/document-contract-web-item.entity'; -import { DocumentContractStatus } from '../enums/contract-status.enum'; +import { DocumentContractComputedStatuses } from '../enums/contract-status.enum'; export interface IDocumentContractWebItemModel { documentId: string; @@ -7,7 +7,7 @@ export interface IDocumentContractWebItemModel { documentStartDate: Date; documentEndDate: Date; documentFilePath: string; - status: DocumentContractStatus; + status: DocumentContractComputedStatuses; volunteerId: string; volunteerName: string; organizationId: string; diff --git a/frontend/src/common/interfaces/document-contract.interface.ts b/frontend/src/common/interfaces/document-contract.interface.ts index 76f43f41..6320640e 100644 --- a/frontend/src/common/interfaces/document-contract.interface.ts +++ b/frontend/src/common/interfaces/document-contract.interface.ts @@ -43,7 +43,7 @@ export interface IGetDocumentContractResponse { documentStartDate: string; documentEndDate: string; documentFilePath: string | null; - status: DocumentContractStatus; + status: DocumentContractStatusForFilter; volunteerId: string; volunteerName: string; organizationId: string; diff --git a/frontend/src/components/ContractInfoContent.tsx b/frontend/src/components/ContractInfoContent.tsx index 8597052d..6ff65c6c 100644 --- a/frontend/src/components/ContractInfoContent.tsx +++ b/frontend/src/components/ContractInfoContent.tsx @@ -10,7 +10,7 @@ import { formatDate, } from '../common/utils/utils'; import StatusWithMarker from './StatusWithMarker'; -import { DocumentContractStatus } from '../common/enums/document-contract-status.enum'; +import { DocumentContractStatusForFilter } from '../common/enums/document-contract-status.enum'; import Button from './Button'; import { useApproveDocumentContractMutation } from '../services/document-contracts/document-contracts.service'; import Spinner from './Spinner'; @@ -135,39 +135,39 @@ export const ContractInfoContent = ({ label={t('contract.generated_on')} value={formatDate(contract.createdOn, 'dd/MM/yyy')} /> - {contract.status === DocumentContractStatus.APPROVED && ( + {contract.status === DocumentContractStatusForFilter.ACTIVE && ( )} {/* rejection date, by and reason */} - {(contract.status === DocumentContractStatus.REJECTED_NGO || - contract.status === DocumentContractStatus.REJECTED_VOLUNTEER) && ( - - )} - {contract.status === DocumentContractStatus.REJECTED_NGO && ( + {(contract.status === DocumentContractStatusForFilter.REJECTED_NGO || + contract.status === DocumentContractStatusForFilter.REJECTED_VOLUNTEER) && ( + + )} + {contract.status === DocumentContractStatusForFilter.REJECTED_NGO && ( )} - {(contract.status === DocumentContractStatus.REJECTED_NGO || - contract.status === DocumentContractStatus.REJECTED_VOLUNTEER) && ( - - )} + {(contract.status === DocumentContractStatusForFilter.REJECTED_NGO || + contract.status === DocumentContractStatusForFilter.REJECTED_VOLUNTEER) && ( + + )} - {contract.status === DocumentContractStatus.PENDING_NGO_REPRESENTATIVE_SIGNATURE && ( + {contract.status === DocumentContractStatusForFilter.PENDING_NGO_REPRESENTATIVE_SIGNATURE && (
)} - {contract.status === DocumentContractStatus.PENDING_APPROVAL_NGO && ( + {contract.status === DocumentContractStatusForFilter.PENDING_APPROVAL_NGO && (