From e92fd316798412d1d6b977116b93e2e8870cd670 Mon Sep 17 00:00:00 2001 From: Andrew Radulescu Date: Tue, 1 Oct 2024 13:25:00 +0300 Subject: [PATCH] feat: [Contracts] Add rejection on volunteer get one contract --- .../documents-contract.controller.ts | 5 +- ...document-contract-item-mobile.presenter.ts | 115 +++++++++++++ .../documents/document-contract.controller.ts | 8 +- ...ts => document-contract-item.presenter.ts} | 16 +- ...tItem AddOrganizationNameToContractItem.ts | 157 ++++++++++++++++++ .../src/modules/documents/documents.module.ts | 8 +- .../document-contract-list-view.entity.ts | 49 +++--- .../document-contract-web-item.entity.ts | 96 +++++------ ...s => document-contract-item-view.model.ts} | 14 +- .../document-contract-item-view.repository.ts | 31 ++++ .../document-contract-web-item.repository.ts | 32 ---- .../services/document-contract.facade.ts | 23 +-- ...t-one-document-contract-for-ngo.usecase.ts | 6 +- ...document-contract-for-volunteer.usecase.ts | 7 +- 14 files changed, 418 insertions(+), 149 deletions(-) create mode 100644 backend/src/api/_mobile/documents/presenters/document-contract-item-mobile.presenter.ts rename backend/src/api/documents/presenters/{document-contract-web-item.presenter.ts => document-contract-item.presenter.ts} (91%) create mode 100644 backend/src/migrations/1727777526306-AddOrganizationNameToContractItem AddOrganizationNameToContractItem.ts rename backend/src/modules/documents/models/{document-contract-web-item.model.ts => document-contract-item-view.model.ts} (65%) create mode 100644 backend/src/modules/documents/repositories/document-contract-item-view.repository.ts delete mode 100644 backend/src/modules/documents/repositories/document-contract-web-item.repository.ts diff --git a/backend/src/api/_mobile/documents/documents-contract.controller.ts b/backend/src/api/_mobile/documents/documents-contract.controller.ts index 1bec20ec..9e224aff 100644 --- a/backend/src/api/_mobile/documents/documents-contract.controller.ts +++ b/backend/src/api/_mobile/documents/documents-contract.controller.ts @@ -15,6 +15,7 @@ import { GetManyContractsByVolunteerDto } from './dto/get-many-contracts-by-volu import { DocumentContractListViewItemPresenter } from 'src/api/documents/presenters/document-contract-list-view-item.presenter'; import { PaginatedPresenter } from 'src/infrastructure/presenters/generic-paginated.presenter'; import { GetOneDocumentContractForVolunteerUsecase } from 'src/usecases/documents/new_contracts/get-one-document-contract-for-volunteer.usecase'; +import { DocumentContractItemMobilePresenter } from './presenters/document-contract-item-mobile.presenter'; // @UseGuards(MobileJwtAuthGuard, ContractVolunteerGuard) @UseGuards(MobileJwtAuthGuard) @@ -53,7 +54,7 @@ export class MobileDocumentsContractController { @ExtractUser() { id }: IRegularUserModel, @Param('contractId', UuidValidationPipe) contractId: string, @Query('organizationId', UuidValidationPipe) organizationId: string, - ): Promise { + ): Promise { const contract = await this.getOneDocumentContractForVolunteerUsecase.execute({ documentContractId: contractId, @@ -61,7 +62,7 @@ export class MobileDocumentsContractController { organizationId, }); - return new DocumentContractListViewItemPresenter(contract); + return new DocumentContractItemMobilePresenter(contract); } @ApiParam({ name: 'contractId', type: 'string' }) diff --git a/backend/src/api/_mobile/documents/presenters/document-contract-item-mobile.presenter.ts b/backend/src/api/_mobile/documents/presenters/document-contract-item-mobile.presenter.ts new file mode 100644 index 00000000..882ef374 --- /dev/null +++ b/backend/src/api/_mobile/documents/presenters/document-contract-item-mobile.presenter.ts @@ -0,0 +1,115 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Expose } from 'class-transformer'; +import { DocumentContractComputedStatuses } from 'src/modules/documents/enums/contract-status.enum'; +import { IDocumentContractItemModel } from 'src/modules/documents/models/document-contract-item-view.model'; + +export class DocumentContractItemMobilePresenter { + constructor(item: IDocumentContractItemModel) { + this.documentId = item.documentId; + this.documentNumber = item.documentNumber; + this.documentStartDate = item.documentStartDate; + this.documentEndDate = item.documentEndDate; + this.documentFilePath = item.documentFilePath; + this.status = item.status; + this.volunteerId = item.volunteerId; + this.volunteerName = item.volunteerName; + + this.organizationId = item.organizationId; + this.organizationName = item.organizationName; + + this.rejectedByName = item.rejectedByName; + this.rejectionDate = item.rejectionDate; + this.rejectionReason = item.rejectionReason; + } + + @Expose() + @ApiProperty({ + description: 'The uuid of the template', + example: '525dcdf9-4117-443e-a0c3-bf652cdc5c1b', + }) + documentId: string; + + @Expose() + @ApiProperty({ + description: 'The document number', + example: '123456', + }) + documentNumber: string; + + @Expose() + @ApiProperty({ + description: 'The document start date', + example: '2021-01-01', + }) + documentStartDate: Date; + + @Expose() + @ApiProperty({ + description: 'The document end date', + example: '2021-01-01', + }) + documentEndDate: Date; + + @Expose() + @ApiProperty({ + description: 'The document file path', + example: 'https://example.com/document.pdf', + }) + documentFilePath: string; + + @Expose() + @ApiProperty({ + description: 'The document status', + example: 'CREATED', + }) + status: DocumentContractComputedStatuses; + + @Expose() + @ApiProperty({ + description: 'The volunteer id', + example: '525dcdf9-4117-443e-a0c3-bf652cdc5c1b', + }) + volunteerId: string; + + @Expose() + @ApiProperty({ + description: 'The volunteer name', + example: 'John Doe', + }) + volunteerName: string; + + @Expose() + @ApiProperty({ + description: 'The organization id', + example: '525dcdf9-4117-443e-a0c3-bf652cdc5c1b', + }) + organizationId: string; + + @Expose() + @ApiProperty({ + description: 'The organization name', + example: 'John Doe', + }) + organizationName: string; + + @Expose() + @ApiProperty({ + description: 'The rejected by name', + example: 'John Doe', + }) + rejectedByName: string; + + @Expose() + @ApiProperty({ + description: 'The rejection date', + example: '2021-01-01', + }) + rejectionDate: Date; + + @Expose() + @ApiProperty({ + description: 'The rejection reason', + example: 'The personal data is not valid', + }) + rejectionReason: string; +} diff --git a/backend/src/api/documents/document-contract.controller.ts b/backend/src/api/documents/document-contract.controller.ts index 9be80ede..6340aac7 100644 --- a/backend/src/api/documents/document-contract.controller.ts +++ b/backend/src/api/documents/document-contract.controller.ts @@ -28,7 +28,7 @@ import { ValidateDocumentContractByNgoUsecase } from 'src/usecases/documents/new import { SignDocumentContractByNgoUsecase } from 'src/usecases/documents/new_contracts/sign-document-contract-by-ngo.usecase'; import { RejectDocumentContractByNgoUsecase } from 'src/usecases/documents/new_contracts/reject-document-contract-by-ngo.usecase'; import { RejectDocumentContractByNgoDTO } from './dto/reject-document-contract.dto'; -import { DocumentContractWebItemPresenter } from './presenters/document-contract-web-item.presenter'; +import { DocumentContractItemPresenter } from './presenters/document-contract-item.presenter'; import { GetOneDocumentContractForNgoUsecase } from 'src/usecases/documents/new_contracts/get-one-document-contract-for-ngo.usecase'; import { DocumentContractStatisticsPresenter } from './presenters/document-contract-statistics.presenter'; import { GetDocumentContractStatisticsUsecase } from 'src/usecases/documents/new_contracts/get-document-contract-statistics.usecase'; @@ -100,18 +100,18 @@ export class DocumentContractController { @Get(':id') @ApiResponse({ - type: DocumentContractWebItemPresenter, + type: DocumentContractItemPresenter, }) async getDocumentContract( @Param('id', UuidValidationPipe) id: string, @ExtractUser() { organizationId }: IAdminUserModel, - ): Promise { + ): Promise { const documentContract = await this.getOneDocumentContractForNgoUsecase.execute({ documentContractId: id, organizationId, }); - return new DocumentContractWebItemPresenter(documentContract); + return new DocumentContractItemPresenter(documentContract); } @Patch(':id/approve') diff --git a/backend/src/api/documents/presenters/document-contract-web-item.presenter.ts b/backend/src/api/documents/presenters/document-contract-item.presenter.ts similarity index 91% rename from backend/src/api/documents/presenters/document-contract-web-item.presenter.ts rename to backend/src/api/documents/presenters/document-contract-item.presenter.ts index 98b4372e..07ba79c6 100644 --- a/backend/src/api/documents/presenters/document-contract-web-item.presenter.ts +++ b/backend/src/api/documents/presenters/document-contract-item.presenter.ts @@ -1,10 +1,10 @@ import { ApiProperty } from '@nestjs/swagger'; import { Expose } from 'class-transformer'; import { DocumentContractComputedStatuses } from 'src/modules/documents/enums/contract-status.enum'; -import { IDocumentContractWebItemModel } from 'src/modules/documents/models/document-contract-web-item.model'; +import { IDocumentContractItemModel } from 'src/modules/documents/models/document-contract-item-view.model'; -export class DocumentContractWebItemPresenter { - constructor(item: IDocumentContractWebItemModel) { +export class DocumentContractItemPresenter { + constructor(item: IDocumentContractItemModel) { this.documentId = item.documentId; this.documentNumber = item.documentNumber; this.documentStartDate = item.documentStartDate; @@ -13,7 +13,10 @@ export class DocumentContractWebItemPresenter { this.status = item.status; this.volunteerId = item.volunteerId; this.volunteerName = item.volunteerName; + this.organizationId = item.organizationId; + this.organizationName = item.organizationName; + this.createdByAdminId = item.createdByAdminId; this.createdByAdminName = item.createdByAdminName; @@ -91,6 +94,13 @@ export class DocumentContractWebItemPresenter { }) organizationId: string; + @Expose() + @ApiProperty({ + description: 'The name of the organization', + example: 'Code4Romania', + }) + organizationName: string; + @Expose() @ApiProperty({ description: diff --git a/backend/src/migrations/1727777526306-AddOrganizationNameToContractItem AddOrganizationNameToContractItem.ts b/backend/src/migrations/1727777526306-AddOrganizationNameToContractItem AddOrganizationNameToContractItem.ts new file mode 100644 index 00000000..41712356 --- /dev/null +++ b/backend/src/migrations/1727777526306-AddOrganizationNameToContractItem AddOrganizationNameToContractItem.ts @@ -0,0 +1,157 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddOrganizationNameToContractItem1727777526306 + implements MigrationInterface +{ + name = 'AddOrganizationNameToContractItem1727777526306'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, + ['VIEW', 'DocumentContractListView', 'public'], + ); + await queryRunner.query( + `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, + ['VIEW', 'DocumentContractWebItemView', 'public'], + ); + await queryRunner.query(`DROP VIEW "DocumentContractListView"`); + await queryRunner.query(`DROP VIEW "DocumentContractWebItemView"`); + + await queryRunner.query(`CREATE VIEW "DocumentContractItemView" 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, + o.name as "organization_name", + + 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 + LEFT JOIN "organization" o ON dc.organization_id = o.id + `); + await queryRunner.query( + `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, + [ + 'public', + 'VIEW', + 'DocumentContractItemView', + '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 o.name as "organization_name",\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\n LEFT JOIN "organization" o ON dc.organization_id = o.id', + ], + ); + await queryRunner.query(`CREATE VIEW "DocumentContractListView" AS + SELECT document_contract.id AS document_id, + document_contract.document_number, + CASE + WHEN document_contract.status = 'APPROVED'::document_contract_status_enum AND document_contract.document_start_date <= CURRENT_DATE AND document_contract.document_end_date >= CURRENT_DATE THEN 'ACTIVE'::text + WHEN document_contract.status = 'APPROVED'::document_contract_status_enum AND document_contract.document_start_date > CURRENT_DATE THEN 'NOT_STARTED'::text + WHEN document_contract.status = 'APPROVED'::document_contract_status_enum AND document_contract.document_end_date < CURRENT_DATE THEN 'EXPIRED'::text + ELSE document_contract.status::text + END AS status, + document_contract.document_start_date, + document_contract.document_end_date, + document_contract.file_path AS document_file_path, + organization.id AS organization_id, + organization.name AS organization_name, + volunteer.id AS volunteer_id, + "user".name AS volunteer_name + FROM document_contract + JOIN volunteer ON document_contract.volunteer_id = volunteer.id + JOIN "user" ON "user".id = volunteer.user_id + JOIN organization ON document_contract.organization_id = organization.id; + `); + await queryRunner.query( + `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, + [ + 'public', + 'VIEW', + 'DocumentContractListView', + "SELECT document_contract.id AS document_id,\n document_contract.document_number,\n CASE\n WHEN document_contract.status = 'APPROVED'::document_contract_status_enum AND document_contract.document_start_date <= CURRENT_DATE AND document_contract.document_end_date >= CURRENT_DATE THEN 'ACTIVE'::text\n WHEN document_contract.status = 'APPROVED'::document_contract_status_enum AND document_contract.document_start_date > CURRENT_DATE THEN 'NOT_STARTED'::text\n WHEN document_contract.status = 'APPROVED'::document_contract_status_enum AND document_contract.document_end_date < CURRENT_DATE THEN 'EXPIRED'::text\n ELSE document_contract.status::text\n END AS status,\n document_contract.document_start_date,\n document_contract.document_end_date,\n document_contract.file_path AS document_file_path,\n organization.id AS organization_id,\n organization.name AS organization_name,\n volunteer.id AS volunteer_id,\n \"user\".name AS volunteer_name\n FROM document_contract\n JOIN volunteer ON document_contract.volunteer_id = volunteer.id\n JOIN \"user\" ON \"user\".id = volunteer.user_id\n JOIN organization ON document_contract.organization_id = organization.id;", + ], + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, + ['VIEW', 'DocumentContractListView', 'public'], + ); + await queryRunner.query(`DROP VIEW "DocumentContractListView"`); + await queryRunner.query( + `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, + ['VIEW', 'DocumentContractItemView', 'public'], + ); + await queryRunner.query(`DROP VIEW "DocumentContractItemView"`); + await queryRunner.query(`CREATE VIEW "DocumentContractListView" AS SELECT + document_contract.id AS document_id, + document_contract.document_number, + + + CASE + WHEN document_contract.status = 'APPROVED' AND + document_contract.document_start_date <= CURRENT_DATE AND + document_contract.document_end_date >= CURRENT_DATE + THEN 'ACTIVE' + WHEN document_contract.status = 'APPROVED' AND + document_contract.document_start_date > CURRENT_DATE + THEN 'NOT_STARTED' + WHEN document_contract.status = 'APPROVED' AND + document_contract.document_end_date < CURRENT_DATE + THEN 'EXPIRED' + ELSE document_contract.status::text + END AS "status", + + document_contract.document_start_date, + document_contract.document_end_date, + document_contract.file_path AS document_file_path, + organization.id AS organization_id, + organization.name AS organization_name, + volunteer.id AS volunteer_id, + "user".name AS volunteer_name + FROM document_contract + JOIN volunteer ON document_contract.volunteer_id = volunteer.id + JOIN "user" ON "user".id = volunteer.user_id + JOIN organization ON document_contract.organization_id = organization.id;`); + await queryRunner.query( + `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, + [ + 'public', + 'VIEW', + 'DocumentContractListView', + "SELECT \n document_contract.id AS document_id,\n document_contract.document_number,\n\n \n CASE \n WHEN document_contract.status = 'APPROVED' AND \n document_contract.document_start_date <= CURRENT_DATE AND \n document_contract.document_end_date >= CURRENT_DATE \n THEN 'ACTIVE'\n WHEN document_contract.status = 'APPROVED' AND \n document_contract.document_start_date > CURRENT_DATE \n THEN 'NOT_STARTED'\n WHEN document_contract.status = 'APPROVED' AND \n document_contract.document_end_date < CURRENT_DATE \n THEN 'EXPIRED'\n ELSE document_contract.status::text\n END AS \"status\",\n\n document_contract.document_start_date,\n document_contract.document_end_date,\n document_contract.file_path AS document_file_path,\n organization.id AS organization_id,\n organization.name AS organization_name,\n volunteer.id AS volunteer_id,\n \"user\".name AS volunteer_name\n FROM document_contract\n JOIN volunteer ON document_contract.volunteer_id = volunteer.id\n JOIN \"user\" ON \"user\".id = volunteer.user_id\n JOIN organization ON document_contract.organization_id = organization.id;", + ], + ); + } +} diff --git a/backend/src/modules/documents/documents.module.ts b/backend/src/modules/documents/documents.module.ts index 20f68c1e..252ff3af 100644 --- a/backend/src/modules/documents/documents.module.ts +++ b/backend/src/modules/documents/documents.module.ts @@ -20,15 +20,15 @@ import { DocumentTemplateListViewEntity } from './entities/document-template-lis import { DocumentTemplateListViewRepository } from './repositories/document-template-list-view.repository'; import { DocumentSignatureRepository } from './repositories/document-signature.repository'; import { DocumentSignatureFacade } from './services/document-signature.facade'; -import { DocumentContractWebItemView } from './entities/document-contract-web-item.entity'; -import { DocumentContractWebItemRepository } from './repositories/document-contract-web-item.repository'; +import { DocumentContractItemView } from './entities/document-contract-web-item.entity'; +import { DocumentContractItemRepository } from './repositories/document-contract-item-view.repository'; import { CronsService } from './services/crons.service'; @Module({ imports: [ TypeOrmModule.forFeature([ DocumentContractListViewEntity, - DocumentContractWebItemView, + DocumentContractItemView, DocumentTemplateListViewEntity, TemplateEntity, ContractEntity, @@ -46,7 +46,7 @@ import { CronsService } from './services/crons.service'; DocumentSignatureRepository, DocumentContractListViewRepository, DocumentTemplateListViewRepository, - DocumentContractWebItemRepository, + DocumentContractItemRepository, // Facades TemplateFacade, ContractFacade, diff --git a/backend/src/modules/documents/entities/document-contract-list-view.entity.ts b/backend/src/modules/documents/entities/document-contract-list-view.entity.ts index ca3d8dbc..df5f38e7 100644 --- a/backend/src/modules/documents/entities/document-contract-list-view.entity.ts +++ b/backend/src/modules/documents/entities/document-contract-list-view.entity.ts @@ -3,36 +3,25 @@ import { DocumentContractComputedStatuses } from '../enums/contract-status.enum' @ViewEntity('DocumentContractListView', { expression: ` - SELECT - document_contract.id AS document_id, - document_contract.document_number, - - - CASE - WHEN document_contract.status = 'APPROVED' AND - document_contract.document_start_date <= CURRENT_DATE AND - document_contract.document_end_date >= CURRENT_DATE - THEN 'ACTIVE' - WHEN document_contract.status = 'APPROVED' AND - document_contract.document_start_date > CURRENT_DATE - THEN 'NOT_STARTED' - WHEN document_contract.status = 'APPROVED' AND - document_contract.document_end_date < CURRENT_DATE - THEN 'EXPIRED' - ELSE document_contract.status - END AS "status", - - document_contract.document_start_date, - document_contract.document_end_date, - document_contract.file_path AS document_file_path, - organization.id AS organization_id, - organization.name AS organization_name, - volunteer.id AS volunteer_id, - "user".name AS volunteer_name - FROM document_contract - JOIN volunteer ON document_contract.volunteer_id = volunteer.id - JOIN "user" ON "user".id = volunteer.user_id - JOIN organization ON document_contract.organization_id = organization.id; + SELECT document_contract.id AS document_id, + document_contract.document_number, + CASE + WHEN document_contract.status = 'APPROVED'::document_contract_status_enum AND document_contract.document_start_date <= CURRENT_DATE AND document_contract.document_end_date >= CURRENT_DATE THEN 'ACTIVE'::text + WHEN document_contract.status = 'APPROVED'::document_contract_status_enum AND document_contract.document_start_date > CURRENT_DATE THEN 'NOT_STARTED'::text + WHEN document_contract.status = 'APPROVED'::document_contract_status_enum AND document_contract.document_end_date < CURRENT_DATE THEN 'EXPIRED'::text + ELSE document_contract.status::text + END AS status, + document_contract.document_start_date, + document_contract.document_end_date, + document_contract.file_path AS document_file_path, + organization.id AS organization_id, + organization.name AS organization_name, + volunteer.id AS volunteer_id, + "user".name AS volunteer_name + FROM document_contract + JOIN volunteer ON document_contract.volunteer_id = volunteer.id + JOIN "user" ON "user".id = volunteer.user_id + JOIN organization ON document_contract.organization_id = organization.id; `, }) export class DocumentContractListViewEntity { 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 bd5c86d6..a09c2c47 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,10 +1,7 @@ import { Column, ViewColumn, ViewEntity } from 'typeorm'; -import { - DocumentContractComputedStatuses, - DocumentContractStatus, -} from '../enums/contract-status.enum'; +import { DocumentContractComputedStatuses } from '../enums/contract-status.enum'; -@ViewEntity('DocumentContractWebItemView', { +@ViewEntity('DocumentContractItemView', { /* Get one document contract for the web @@ -33,50 +30,52 @@ import { | updated_on | Updated on date | */ expression: ` - 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 + 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, + o.name as "organization_name", + + 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 + LEFT JOIN "organization" o ON dc.organization_id = o.id `, }) -export class DocumentContractWebItemView { +export class DocumentContractItemView { @ViewColumn({ name: 'document_id' }) documentId: string; @@ -130,6 +129,9 @@ export class DocumentContractWebItemView { @ViewColumn({ name: 'organization_id' }) organizationId: string; + @ViewColumn({ name: 'organization_name' }) + organizationName: string; + @ViewColumn({ name: 'created_on' }) createdOn: Date; diff --git a/backend/src/modules/documents/models/document-contract-web-item.model.ts b/backend/src/modules/documents/models/document-contract-item-view.model.ts similarity index 65% rename from backend/src/modules/documents/models/document-contract-web-item.model.ts rename to backend/src/modules/documents/models/document-contract-item-view.model.ts index 353d0e8f..9cbbb670 100644 --- a/backend/src/modules/documents/models/document-contract-web-item.model.ts +++ b/backend/src/modules/documents/models/document-contract-item-view.model.ts @@ -1,7 +1,7 @@ -import { DocumentContractWebItemView } from '../entities/document-contract-web-item.entity'; +import { DocumentContractItemView } from '../entities/document-contract-web-item.entity'; import { DocumentContractComputedStatuses } from '../enums/contract-status.enum'; -export interface IDocumentContractWebItemModel { +export interface IDocumentContractItemModel { documentId: string; documentNumber: string; documentStartDate: Date; @@ -15,6 +15,7 @@ export interface IDocumentContractWebItemModel { createdByAdminName: string; documentTemplateId: string; documentTemplateName: string; + organizationName: string; rejectedById: string; rejectedByName: string; rejectionDate: Date; @@ -23,15 +24,16 @@ export interface IDocumentContractWebItemModel { updatedOn: Date; } -export type FindOneDocumentContractWebItemOptions = { +export type FindOneDocumentContractItemOptions = { documentId: string; organizationId: string; + volunteerId?: string; }; -export const DocumentContractWebItemTransformer = { +export const DocumentContractItemTransformer = { fromEntity: ( - entity: DocumentContractWebItemView, - ): IDocumentContractWebItemModel => { + entity: DocumentContractItemView, + ): IDocumentContractItemModel => { return { ...entity, }; diff --git a/backend/src/modules/documents/repositories/document-contract-item-view.repository.ts b/backend/src/modules/documents/repositories/document-contract-item-view.repository.ts new file mode 100644 index 00000000..b2573d1b --- /dev/null +++ b/backend/src/modules/documents/repositories/document-contract-item-view.repository.ts @@ -0,0 +1,31 @@ +import { Injectable } from '@nestjs/common'; +import { DocumentContractItemView } from '../entities/document-contract-web-item.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { + DocumentContractItemTransformer, + FindOneDocumentContractItemOptions, + IDocumentContractItemModel, +} from '../models/document-contract-item-view.model'; + +@Injectable() +export class DocumentContractItemRepository { + constructor( + @InjectRepository(DocumentContractItemView) + private readonly documentContractItemViewRepository: Repository, + ) {} + + async findOne( + options: FindOneDocumentContractItemOptions, + ): Promise { + const documentContractWebItemView = + await this.documentContractItemViewRepository.findOne({ + where: { + ...options, + }, + }); + return DocumentContractItemTransformer.fromEntity( + documentContractWebItemView, + ); + } +} diff --git a/backend/src/modules/documents/repositories/document-contract-web-item.repository.ts b/backend/src/modules/documents/repositories/document-contract-web-item.repository.ts deleted file mode 100644 index 77ba89ed..00000000 --- a/backend/src/modules/documents/repositories/document-contract-web-item.repository.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { DocumentContractWebItemView } from '../entities/document-contract-web-item.entity'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; -import { - DocumentContractWebItemTransformer, - FindOneDocumentContractWebItemOptions, - IDocumentContractWebItemModel, -} from '../models/document-contract-web-item.model'; - -@Injectable() -export class DocumentContractWebItemRepository { - constructor( - @InjectRepository(DocumentContractWebItemView) - private readonly documentContractWebItemViewRepository: Repository, - ) {} - - async findOne( - options: FindOneDocumentContractWebItemOptions, - ): Promise { - const documentContractWebItemView = - await this.documentContractWebItemViewRepository.findOne({ - where: { - documentId: options.documentId, - organizationId: options.organizationId, - }, - }); - return DocumentContractWebItemTransformer.fromEntity( - documentContractWebItemView, - ); - } -} diff --git a/backend/src/modules/documents/services/document-contract.facade.ts b/backend/src/modules/documents/services/document-contract.facade.ts index 846cd0d7..1d63e34e 100644 --- a/backend/src/modules/documents/services/document-contract.facade.ts +++ b/backend/src/modules/documents/services/document-contract.facade.ts @@ -11,23 +11,22 @@ import { import { DocumentContractListViewRepository } from '../repositories/document-contract-list-view.repository'; import { FindManyDocumentContractListViewPaginatedOptions, - FindOneDocumentContractListViewOptions, IDocumentContractListViewModel, } from '../models/document-contract-list-view.model'; import { Pagination } from 'src/infrastructure/base/repository-with-pagination.class'; import { DocumentContractStatus } from '../enums/contract-status.enum'; import { - FindOneDocumentContractWebItemOptions, - IDocumentContractWebItemModel, -} from '../models/document-contract-web-item.model'; -import { DocumentContractWebItemRepository } from '../repositories/document-contract-web-item.repository'; + FindOneDocumentContractItemOptions, + IDocumentContractItemModel, +} from '../models/document-contract-item-view.model'; +import { DocumentContractItemRepository } from '../repositories/document-contract-item-view.repository'; @Injectable() export class DocumentContractFacade { constructor( private readonly documentContractRepository: DocumentContractRepositoryService, private readonly documentContractListViewRepository: DocumentContractListViewRepository, - private readonly documentContractWebItemRepository: DocumentContractWebItemRepository, + private readonly documentContractWebItemRepository: DocumentContractItemRepository, ) {} async approveDocumentContractByNGO( @@ -86,9 +85,9 @@ export class DocumentContractFacade { return this.documentContractRepository.findOne(options); } - async findOneForWeb( - options: FindOneDocumentContractWebItemOptions, - ): Promise { + async findOneItem( + options: FindOneDocumentContractItemOptions, + ): Promise { return this.documentContractWebItemRepository.findOne(options); } @@ -120,12 +119,6 @@ export class DocumentContractFacade { return this.documentContractListViewRepository.findManyPaginated(options); } - async findOneForVolunteer( - options: FindOneDocumentContractListViewOptions, - ): Promise { - return this.documentContractListViewRepository.findOne(options); - } - async update( id: string, updates: UpdateDocumentContractOptions, diff --git a/backend/src/usecases/documents/new_contracts/get-one-document-contract-for-ngo.usecase.ts b/backend/src/usecases/documents/new_contracts/get-one-document-contract-for-ngo.usecase.ts index 6d7c57ae..0595947c 100644 --- a/backend/src/usecases/documents/new_contracts/get-one-document-contract-for-ngo.usecase.ts +++ b/backend/src/usecases/documents/new_contracts/get-one-document-contract-for-ngo.usecase.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { ExceptionsService } from 'src/infrastructure/exceptions/exceptions.service'; import { S3Service } from 'src/infrastructure/providers/s3/module/s3.service'; import { ContractExceptionMessages } from 'src/modules/documents/exceptions/contract.exceptions'; -import { IDocumentContractWebItemModel } from 'src/modules/documents/models/document-contract-web-item.model'; +import { IDocumentContractItemModel } from 'src/modules/documents/models/document-contract-item-view.model'; import { DocumentContractFacade } from 'src/modules/documents/services/document-contract.facade'; @Injectable() @@ -19,8 +19,8 @@ export class GetOneDocumentContractForNgoUsecase { }: { documentContractId: string; organizationId: string; - }): Promise { - const contract = await this.documentContractFacade.findOneForWeb({ + }): Promise { + const contract = await this.documentContractFacade.findOneItem({ documentId: documentContractId, organizationId, }); diff --git a/backend/src/usecases/documents/new_contracts/get-one-document-contract-for-volunteer.usecase.ts b/backend/src/usecases/documents/new_contracts/get-one-document-contract-for-volunteer.usecase.ts index a9485b71..7694d6a2 100644 --- a/backend/src/usecases/documents/new_contracts/get-one-document-contract-for-volunteer.usecase.ts +++ b/backend/src/usecases/documents/new_contracts/get-one-document-contract-for-volunteer.usecase.ts @@ -1,8 +1,8 @@ import { Injectable } from '@nestjs/common'; import { ExceptionsService } from 'src/infrastructure/exceptions/exceptions.service'; import { S3Service } from 'src/infrastructure/providers/s3/module/s3.service'; -import { DocumentContractListViewEntity } from 'src/modules/documents/entities/document-contract-list-view.entity'; import { ContractExceptionMessages } from 'src/modules/documents/exceptions/contract.exceptions'; +import { IDocumentContractItemModel } from 'src/modules/documents/models/document-contract-item-view.model'; 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'; @@ -24,7 +24,7 @@ export class GetOneDocumentContractForVolunteerUsecase { documentContractId: string; userId: string; organizationId: string; - }): Promise { + }): Promise { const volunteer = await this.volunteerFacade.find({ userId: userId, organizationId, @@ -36,8 +36,9 @@ export class GetOneDocumentContractForVolunteerUsecase { ); } - const contract = await this.documentContractFacade.findOneForVolunteer({ + const contract = await this.documentContractFacade.findOneItem({ documentId: documentContractId, + organizationId, volunteerId: volunteer.id, });