From 2a45c0b522a9c2ee5aa19d0fb4e3b70d5f7eb6d4 Mon Sep 17 00:00:00 2001 From: Kallesh B S Date: Thu, 18 Sep 2025 15:45:53 +0530 Subject: [PATCH] added holders and client --- src/app.module.ts | 4 +- .../manage-holders-property.dto.ts | 4 +- src/main.ts | 3 +- .../manage-clients.controller.ts | 92 +++ .../manage-clients/manage-clients.module.ts | 9 + .../manage-clients/manage-clients.service.ts | 642 ++++++++++++++++++ .../manage-holder/manage-holder.controller.ts | 32 +- src/pg/manage-holder/manage-holder.service.ts | 489 ++++++++++++- src/pg/pg.module.ts | 3 +- 9 files changed, 1248 insertions(+), 30 deletions(-) create mode 100644 src/pg/manage-clients/manage-clients.controller.ts create mode 100644 src/pg/manage-clients/manage-clients.module.ts create mode 100644 src/pg/manage-clients/manage-clients.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index 27a47dc..cc70e0e 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -11,8 +11,8 @@ import { PgModule } from './pg/pg.module'; @Module({ imports: [ - ConfigModule.forRoot({ isGlobal: true }), PgModule, - AuthModule, DbModule, OracleModule, MailModule, PaypalModule + ConfigModule.forRoot({ isGlobal: true }), + AuthModule, PgModule, DbModule, OracleModule, MailModule, PaypalModule ], controllers: [], providers: [], diff --git a/src/dto/manage-holders/manage-holders-property.dto.ts b/src/dto/manage-holders/manage-holders-property.dto.ts index 18f7de1..5356f25 100644 --- a/src/dto/manage-holders/manage-holders-property.dto.ts +++ b/src/dto/manage-holders/manage-holders-property.dto.ts @@ -100,7 +100,9 @@ export class CONTACTSTABLE_ROW_DTO extends IntersectionType( PHONE_NO_DTO, MOBILE_NO_DTO, PartialType(FAX_NO_DTO) -) { } +) { + FAX_NO: null; +} export class CONTACTSTABLE_DTO { @ApiProperty({ required: true, type: () => [CONTACTSTABLE_ROW_DTO] }) diff --git a/src/main.ts b/src/main.ts index 60c13aa..f3da58a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -89,7 +89,8 @@ async function bootstrap() { .addTag('SPContacts - PG') .addTag('User Maintenance - PG') .addTag('Manage Fee - PG') - // .addTag('Manage Holders - PG') + .addTag('Manage Holders - PG') + .addTag('Manage Clients - PG') .addTag('User Maintenance - Oracle') .addTag('Carnet Application - Oracle') .addTag('HomePage - Oracle') diff --git a/src/pg/manage-clients/manage-clients.controller.ts b/src/pg/manage-clients/manage-clients.controller.ts new file mode 100644 index 0000000..c20ef13 --- /dev/null +++ b/src/pg/manage-clients/manage-clients.controller.ts @@ -0,0 +1,92 @@ +import { Body, Controller, Get, Param, Patch, Post, Put, Query, UseGuards } from '@nestjs/common'; +import { ClientContactControlsDTO, CreateClientContactsDTO, CreateClientDataDTO, CreateClientLocationsDTO, GetClientContactByLacationIdDTO, GetClientDTO, GetPreparersParamDTO, GetPreparersQueryDTO, UpdateClientContactsDTO, UpdateClientDTO, UpdateClientLocationsDTO } from 'src/dto/property.dto'; +import { ManageClientsService } from './manage-clients.service'; +import { Roles } from 'src/decorators/roles.decorator'; +import { ApiTags } from '@nestjs/swagger'; +import { JwtAuthGuard } from 'src/guards/jwt-auth.guard'; +import { RolesGuard } from 'src/guards/roles.guard'; + +@ApiTags('Manage Clients - PG') +// @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('sa') +@Controller('1') +export class ManageClientsController { + constructor(private readonly manageClientsService: ManageClientsService) { } + + @Post('CreateNewClients') + async CreateClientData(@Body() body: CreateClientDataDTO) { + return this.manageClientsService.CreateClientData(body); + } + + @Put('UpdateClient') + async UpdateClient(@Body() body: UpdateClientDTO) { + return this.manageClientsService.UpdateClient(body); + } + + @Put('UpdateClientContacts') + @Roles('ca', 'sa') + UpdateClientContacts(@Body() body: UpdateClientContactsDTO) { + return this.manageClientsService.UpdateClientContacts(body); + } + + @Put('UpdateClientLocations') + @Roles('ca', 'sa') + UpdateClientLocations(@Body() body: UpdateClientLocationsDTO) { + return this.manageClientsService.UpdateClientLocations(body); + } + + @Post('CreateClientContacts') + @Roles('ca', 'sa') + CreateClientContact(@Body() body: CreateClientContactsDTO) { + return this.manageClientsService.CreateClientContact(body); + } + + @Patch('SetDefaultClientContacts/:P_SPID/:P_CLIENTCONTACTID/:P_USERID') + SetDefaultClientContacts(@Param() param: ClientContactControlsDTO) { + return this.manageClientsService.SetDefaultClientContacts(param); + } + + @Patch('InactivateClientContacts/:P_SPID/:P_CLIENTCONTACTID/:P_USERID') + InactivateClientContacts(@Param() param: ClientContactControlsDTO) { + return this.manageClientsService.InactivateClientContacts(param); + } + + @Patch('ReactivateClientContacts/:P_SPID/:P_CLIENTCONTACTID/:P_USERID') + ReactivateClientContacts(@Param() param: ClientContactControlsDTO) { + return this.manageClientsService.ReactivateClientContacts(param); + } + + @Post('CreateClientLocations') + @Roles('ca', 'sa') + CreateClientLocation(@Body() body: CreateClientLocationsDTO) { + return this.manageClientsService.CreateClientLocation(body); + } + + @Get('GetPreparers/:P_SPID/:P_STATUS') + async GetPreparers(@Param() param: GetPreparersParamDTO, @Query() query: GetPreparersQueryDTO) { + return await this.manageClientsService.GetPreparers({ ...param, ...query }); + } + + @Get('GetPreparerByClientid/:P_SPID/:P_CLIENTID') + GetPreparerByClientid(@Param() body: GetClientDTO) { + return this.manageClientsService.GetPreparerByClientid(body); + } + + @Get('GetPreparerContactsByClientid/:P_SPID/:P_CLIENTID') + @Roles('ca', 'sa') + GetPreparerContactsByClientid(@Param() body: GetClientDTO) { + return this.manageClientsService.GetPreparerContactsByClientid(body); + } + + @Get('GetPreparerContactsbyClientLocationID/:P_SPID/:P_LOCATIONID') + @Roles('ca', 'sa') + GetPreparerContactsbyClientLocationID(@Param() body: GetClientContactByLacationIdDTO) { + return this.manageClientsService.GetPreparerContactsbyClientLocationID(body); + } + + @Get('GetPreparerLocByClientid/:P_SPID/:P_CLIENTID') + @Roles('ca', 'sa') + GetPreparerLocByClientid(@Param() body: GetClientDTO) { + return this.manageClientsService.GetPreparerLocByClientid(body); + } +} diff --git a/src/pg/manage-clients/manage-clients.module.ts b/src/pg/manage-clients/manage-clients.module.ts new file mode 100644 index 0000000..72b2df6 --- /dev/null +++ b/src/pg/manage-clients/manage-clients.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { ManageClientsController } from './manage-clients.controller'; +import { ManageClientsService } from './manage-clients.service'; + +@Module({ + controllers: [ManageClientsController], + providers: [ManageClientsService] +}) +export class ManageClientsModule {} diff --git a/src/pg/manage-clients/manage-clients.service.ts b/src/pg/manage-clients/manage-clients.service.ts new file mode 100644 index 0000000..e816231 --- /dev/null +++ b/src/pg/manage-clients/manage-clients.service.ts @@ -0,0 +1,642 @@ +import { Injectable } from '@nestjs/common'; +import { ClientContactControlsDTO, CreateClientContactsDTO, CreateClientDataDTO, CreateClientLocationsDTO, GetClientContactByLacationIdDTO, GetClientDTO, GetPreparersDTO, UpdateClientContactsDTO, UpdateClientDTO, UpdateClientLocationsDTO } from 'src/dto/property.dto'; +import { checkPgUserDefinedErrors, handlePgError, releasePgClient, ResponseStatus } from 'src/utils/helper'; +import { PoolClient } from 'pg'; +import { PgDBService } from 'src/db/db.service'; + +@Injectable() +export class ManageClientsService { + + constructor(private readonly pgDBService: PgDBService) { } + + CreateClientData = async (body: CreateClientDataDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_createclientdata($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_CLIENTNAME, + body.P_LOOKUPCODE, + body.P_ADDRESS1, + body.P_ADDRESS2, + body.P_CITY, + body.P_STATE, + body.P_ZIP, + body.P_COUNTRY, + body.P_ISSUINGREGION, + body.P_REVENUELOCATION, + body.P_USERID, + body.P_INDUSTRYTYPE, + cursorName + ]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 201, + message: ResponseStatus.created, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + }; + + UpdateClient = async (body: UpdateClientDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_updateclient($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_CLIENTID, + body.P_PREPARERNAME, + body.P_ADDRESS1, + body.P_ADDRESS2, + body.P_CITY, + body.P_STATE, + body.P_ZIP, + body.P_COUNTRY, + body.P_REVENUELOCATION, + body.P_USERID, + body.P_INDUSTRYTYPE, + cursorName + ]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 201, + message: ResponseStatus.updated, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + }; + + UpdateClientContacts = async (body: UpdateClientContactsDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_updateclientcontacts($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_CLIENTCONTACTID, + body.P_FIRSTNAME, + body.P_LASTNAME, + body.P_MIDDLEINITIAL, + body.P_TITLE, + body.P_PHONENO, + body.P_FAXNO, + body.P_MOBILENO, + body.P_EMAILADDRESS, + body.P_USERID, + cursorName + ]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 201, + message: ResponseStatus.updated, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + }; + + UpdateClientLocations = async (body: UpdateClientLocationsDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_updateclientlocations($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_CLIENTLOCATIONID, + body.P_LOCATIONNAME, + body.P_ADDRESS1, + body.P_ADDRESS2, + body.P_CITY, + body.P_STATE, + body.P_ZIP, + body.P_COUNTRY, + body.P_USERID, + cursorName + ]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 201, + message: ResponseStatus.updated, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + }; + + async CreateClientContact(body: CreateClientContactsDTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + // Helper to escape special characters for Postgres composite fields + function escapePostgresCompositeField(str: string): string { + if (str == null) return ''; + return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); + } + + const contactLiterals = body.P_CONTACTSTABLE.map(c => { + const fields = [ + c.P_FIRSTNAME || '', + c.P_LASTNAME || '', + c.P_MIDDLEINITIAL || '', + c.P_TITLE || '', + c.P_EMAILADDRESS || '', + c.P_PHONENO || '', + c.P_MOBILENO || '', + c.P_FAXNO || '', + ].map(field => escapePostgresCompositeField(field)).join(','); + + + return `"(${fields})"`; // Composite literal wrapped in double quotes + }); + + const pgArrayLiteral = `{${contactLiterals.join(',')}}`; + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_createclientcontact($1, $2, $3::"CARNETSYS".contactstable[], $4, $5, $6) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_LOCATIONID, + pgArrayLiteral, + body.P_DEFCONTACTFLAG, + body.P_USERID, + cursorName + ]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 201, + message: ResponseStatus.created, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + } + + SetDefaultClientContacts = async (body: ClientContactControlsDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_setdefaultclientcontacts($1, $2, $3, $4) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTCONTACTID, body.P_USERID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 200, + message: ResponseStatus.updated, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + } + + InactivateClientContacts = async (body: ClientContactControlsDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_inactivateclientcontacts($1, $2, $3, $4) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTCONTACTID, body.P_USERID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 200, + message: ResponseStatus.inActivate, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + } + + ReactivateClientContacts = async (body: ClientContactControlsDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_reactivateclientcontacts($1, $2, $3, $4) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTCONTACTID, body.P_USERID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 200, + message: ResponseStatus.reActivate, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + } + + CreateClientLocation = async (body: CreateClientLocationsDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + function escapePostgresCompositeField(str: string): string { + if (str == null) return ''; + return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); + } + + const addressLiterals = body.P_CLIENTLOCADDRESSTABLE.map(c => { + const fields = [ + c.P_NAMEOF || '', + c.P_ADDRESS1 || '', + c.P_ADDRESS2 || '', + c.P_CITY || '', + c.P_STATE || '', + c.P_ZIP || '', + c.P_COUNTRY || '', + ].map(field => escapePostgresCompositeField(field)).join(','); + + + return `"(${fields})"`; // Composite literal wrapped in double quotes + }); + + const pgArrayLiteral = `{${addressLiterals.join(',')}}`; + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_updateclientlocations($1, $2, $3::"CARNETSYS".addresstable[], $4, $5) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_CLIENTID, + pgArrayLiteral, + body.P_USERID, + cursorName + ]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 201, + message: ResponseStatus.created, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + }; + + GetPreparers = async (body: GetPreparersDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_getpreparers($1, $2, $3, $4, $5, $6, $7) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_NAME, body.P_LOOKUPCODE, body.P_CITY, body.P_STATE, body.P_STATUS, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return fetchResult?.rows ? fetchResult?.rows : [] + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + }; + + GetPreparerByClientid = async (body: GetClientDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_getpreparerlocbyclientid($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return fetchResult?.rows ? fetchResult?.rows : [] + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + }; + + GetPreparerContactsByClientid = async (body: GetClientDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_getpreparercontactsbyclientid($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return fetchResult?.rows ? fetchResult?.rows : [] + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + }; + + GetPreparerContactsbyClientLocationID = async (body: GetClientContactByLacationIdDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_getpreparercontactsbyclientlocationid($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_LOCATIONID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return fetchResult?.rows ? fetchResult?.rows : [] + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + } + + GetPreparerLocByClientid = async (body: GetClientDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managepreparer_pkg_getpreparerlocbyclientid($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return fetchResult?.rows ? fetchResult?.rows : [] + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageClientsService.name) + } finally { + releasePgClient(client) + } + }; +} diff --git a/src/pg/manage-holder/manage-holder.controller.ts b/src/pg/manage-holder/manage-holder.controller.ts index eb6a647..4a8517a 100644 --- a/src/pg/manage-holder/manage-holder.controller.ts +++ b/src/pg/manage-holder/manage-holder.controller.ts @@ -1,15 +1,21 @@ -import { Body, Controller, Get, Param, Patch, Post, Put, Query } from '@nestjs/common'; -import { ApiQuery } from '@nestjs/swagger'; +import { Body, Controller, Get, Param, Patch, Post, Put, Query, UseGuards } from '@nestjs/common'; +import { ApiQuery, ApiTags } from '@nestjs/swagger'; import { CreateHolderContactsDTO, CreateHoldersDTO, GetHolderDTO, HolderActivateOrInactivateDTO, HolderContactActivateOrInactivateDTO, UpdateHolderContactDTO, UpdateHolderDTO } from 'src/dto/property.dto'; import { BadRequestException } from 'src/exceptions/badRequest.exception'; import { ManageHolderService } from './manage-holder.service'; +import { Roles } from 'src/decorators/roles.decorator'; +import { JwtAuthGuard } from 'src/guards/jwt-auth.guard'; +import { RolesGuard } from 'src/guards/roles.guard'; +@ApiTags('Manage Holders - PG') +// @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('ca', 'sa') @Controller('manage-holder') export class ManageHolderController { constructor(private readonly manageHoldersService: ManageHolderService) { } - // @Get('SearchHolder/:P_SPID/:P_USERID') + @Get('SearchHolder/:P_SPID/:P_USERID') @ApiQuery({ name: "P_HOLDERNAME", type: String, required: false, description: "Optional" }) @ApiQuery({ name: "P_HOLDERID", type: Number, required: false, description: "Optional" }) SearchHolder( @@ -51,52 +57,52 @@ export class ManageHolderController { return this.manageHoldersService.SearchHolder(body) } - // @Post('/CreateHolderData') + @Post('/CreateHolderData') CreateHolders(@Body() body: CreateHoldersDTO) { return this.manageHoldersService.CreateHolders(body); } - // @Post('CreateHoldercontact') + @Post('CreateHoldercontact') CreateHoldercontact(@Body() body: CreateHolderContactsDTO) { return this.manageHoldersService.CreateHoldercontact(body); } - // @Put('/UpdateHolder') + @Put('/UpdateHolder') UpdateHolder(@Body() body: UpdateHolderDTO) { return this.manageHoldersService.UpdateHolder(body); } - // @Put('/UpdateHolderContact') + @Put('/UpdateHolderContact') UpdateHolderContact(@Body() body: UpdateHolderContactDTO) { return this.manageHoldersService.UpdateHolderContact(body); } - // @Get('/GetHolderRecord/:P_SPID/:P_HOLDERID') + @Get('/GetHolderRecord/:P_SPID/:P_HOLDERID') GetHolderMaster(@Param() body: GetHolderDTO) { return this.manageHoldersService.GetHolderRecord(body); } - // @Get('/GetHolderContacts/:P_SPID/:P_HOLDERID') + @Get('/GetHolderContacts/:P_SPID/:P_HOLDERID') GetHolderContacts(@Param() body: GetHolderDTO) { return this.manageHoldersService.GetHolderContacts(body); } - // @Patch('/InactivateHolder/:P_SPID/:P_HOLDERID/:P_USERID') + @Patch('/InactivateHolder/:P_SPID/:P_HOLDERID/:P_USERID') InactivateHolder(@Param() body: HolderActivateOrInactivateDTO) { return this.manageHoldersService.InactivateHolder(body); } - // @Patch('/ReactivateHolder/:P_SPID/:P_HOLDERID/:P_USERID') + @Patch('/ReactivateHolder/:P_SPID/:P_HOLDERID/:P_USERID') ReactivateHolder(@Param() body: HolderActivateOrInactivateDTO) { return this.manageHoldersService.ReactivateHolder(body); } - // @Patch('/InactivateHolderContact/:P_SPID/:P_HOLDERCONTACTID/:P_USERID') + @Patch('/InactivateHolderContact/:P_SPID/:P_HOLDERCONTACTID/:P_USERID') InactivateHolderContact(@Param() body: HolderContactActivateOrInactivateDTO) { return this.manageHoldersService.InactivateHolderContact(body); } - // @Patch('/ReactivateHolderContact/:P_SPID/:P_HOLDERCONTACTID/:P_USERID') + @Patch('/ReactivateHolderContact/:P_SPID/:P_HOLDERCONTACTID/:P_USERID') ReactivateHolderContact(@Param() body: HolderContactActivateOrInactivateDTO) { return this.manageHoldersService.ReactivateHolderContact(body); } diff --git a/src/pg/manage-holder/manage-holder.service.ts b/src/pg/manage-holder/manage-holder.service.ts index 96bcc7a..8e8513b 100644 --- a/src/pg/manage-holder/manage-holder.service.ts +++ b/src/pg/manage-holder/manage-holder.service.ts @@ -1,33 +1,498 @@ import { Injectable } from '@nestjs/common'; import { PgDBService } from 'src/db/db.service'; -import { CreateHolderContactsDTO, CreateHoldersDTO, GetHolderDTO, HolderActivateOrInactivateDTO, HolderContactActivateOrInactivateDTO, UpdateHolderContactDTO, UpdateHolderDTO } from 'src/dto/property.dto'; +import { CONTACTSTABLE_ROW_DTO, CreateHolderContactsDTO, CreateHoldersDTO, GetHolderDTO, HolderActivateOrInactivateDTO, HolderContactActivateOrInactivateDTO, UpdateHolderContactDTO, UpdateHolderDTO } from 'src/dto/property.dto'; +import { PoolClient } from 'pg'; +import { checkPgUserDefinedErrors, handlePgError, releasePgClient, ResponseStatus } from 'src/utils/helper'; @Injectable() export class ManageHolderService { constructor(private readonly pgDBService: PgDBService) { } - async CreateHolders(body: CreateHoldersDTO) { } + async CreateHolders(body: CreateHoldersDTO) { + let client: PoolClient | null = null; - async CreateHoldercontact(body: CreateHolderContactsDTO) { + const cursorName = 'p_cursor'; + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageholder_pkg_createholderdata($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_CLIENTLOCATIONID, + body.P_HOLDERNO, + body.P_HOLDERTYPE, + body.P_USCIBMEMBERFLAG, + body.P_GOVAGENCYFLAG, + body.P_HOLDERNAME, + body.P_NAMEQUALIFIER, + body.P_ADDLNAME, + body.P_ADDRESS1, + body.P_ADDRESS2, + body.P_CITY, + body.P_STATE, + body.P_ZIP, + body.P_COUNTRY, + body.P_USERID, + cursorName + ]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 201, + message: ResponseStatus.created, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageHolderService.name) + } finally { + releasePgClient(client) + } } - UpdateHolder = async (body: UpdateHolderDTO) => { }; + async CreateHoldercontact(body: CreateHolderContactsDTO) { + let client: PoolClient | null = null; + const cursorName = 'p_cursor'; - GetHolderRecord = async (body: GetHolderDTO) => { }; + // Helper to escape special characters for Postgres composite fields + function escapePostgresCompositeField(str: string): string { + if (str == null) return ''; + return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); + } - UpdateHolderContact = async (body: UpdateHolderContactDTO) => { }; + try { + client = await this.pgDBService.getConnection(); + await client.query('BEGIN'); - GetHolderContacts = async (body: GetHolderDTO) => { }; + const contactLiterals = body.P_CONTACTSTABLE.map(c => { + const fields = [ + c.P_FIRSTNAME || '', + c.P_LASTNAME || '', + c.P_MIDDLEINITIAL || '', + c.P_TITLE || '', + c.P_EMAILADDRESS || '', + c.P_PHONENO || '', + c.P_MOBILENO || '', + c.P_FAXNO || '', + ].map(field => escapePostgresCompositeField(field)).join(','); - InactivateHolder = async (body: HolderActivateOrInactivateDTO) => { }; - ReactivateHolder = async (body: HolderActivateOrInactivateDTO) => { }; + return `"(${fields})"`; // Composite literal wrapped in double quotes + }); - InactivateHolderContact = async (body: HolderContactActivateOrInactivateDTO) => { }; + const pgArrayLiteral = `{${contactLiterals.join(',')}}`; - ReactivateHolderContact = async (body: HolderContactActivateOrInactivateDTO) => { }; + const callProcQuery = ` + CALL "CARNETSYS".manageholder_pkg_createholdercontact($1, $2, $3::"CARNETSYS".contactstable[], $4, $5) + `; - SearchHolder = async (body: { P_SPID: number, P_USERID: string, P_HOLDERID: number | null, P_HOLDERNAME: string | null }) => { } + await client.query(callProcQuery, [ + body.P_SPID, + body.P_HOLDERID, + pgArrayLiteral, + body.P_USERID, + cursorName, + ]); + + // Fetch results from cursor (do NOT quote cursor name) + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // Close cursor + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 201, + message: ResponseStatus.created, + ...fetchResult?.rows?.[0] || {}, + }; + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageHolderService.name); + } finally { + releasePgClient(client); + } + } + + UpdateHolder = async (body: UpdateHolderDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageholder_pkg_updateholder($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) + `; + await client.query(callProcQuery, + [ + body.P_HOLDERID, + body.P_SPID, + body.P_LOCATIONID, + body.P_HOLDERNO, + body.P_HOLDERTYPE, + body.P_USCIBMEMBERFLAG, + body.P_GOVAGENCYFLAG, + body.P_HOLDERNAME, + body.P_NAMEQUALIFIER, + body.P_ADDLNAME, + body.P_ADDRESS1, + body.P_ADDRESS2, + body.P_CITY, + body.P_STATE, + body.P_ZIP, + body.P_COUNTRY, + body.P_USERID, + cursorName + ]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 201, + message: ResponseStatus.updated, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageHolderService.name) + } finally { + releasePgClient(client) + } + }; + + GetHolderRecord = async (body: GetHolderDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageholder_pkg_getholdermaster($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_HOLDERID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return fetchResult?.rows ? fetchResult?.rows : [] + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageHolderService.name) + } finally { + releasePgClient(client) + } + }; + + UpdateHolderContact = async (body: UpdateHolderContactDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageholder_pkg_updateholder($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) + `; + await client.query(callProcQuery, + [ + body.P_HOLDERCONTACTID, + body.P_SPID, + body.P_FIRSTNAME, + body.P_LASTNAME, + body.P_MIDDLEINITIAL, + body.P_TITLE, + body.P_PHONENO, + body.P_MOBILENO, + body.P_FAXNO, + body.P_EMAILADDRESS, + body.P_USERID, + cursorName + ]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 201, + message: ResponseStatus.updated, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageHolderService.name) + } finally { + releasePgClient(client) + } + }; + + GetHolderContacts = async (body: GetHolderDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageholder_pkg_getholdercontacts($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_HOLDERID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return fetchResult?.rows ? fetchResult?.rows : [] + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageHolderService.name) + } finally { + releasePgClient(client) + } + }; + + InactivateHolder = async (body: HolderActivateOrInactivateDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageholder_pkg_inactivateholder($1, $2, $3, $4) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_HOLDERID, body.P_USERID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 200, + message: ResponseStatus.inActivate, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageHolderService.name) + } finally { + releasePgClient(client) + } + }; + + ReactivateHolder = async (body: HolderActivateOrInactivateDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageholder_pkg_reactivateholder($1, $2, $3, $4) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_HOLDERID, body.P_USERID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 200, + message: ResponseStatus.reActivate, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageHolderService.name) + } finally { + releasePgClient(client) + } + }; + + InactivateHolderContact = async (body: HolderContactActivateOrInactivateDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageholder_pkg_inactivateholdercontact($1, $2, $3, $4) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_HOLDERCONTACTID, body.P_USERID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 200, + message: ResponseStatus.inActivate, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageHolderService.name) + } finally { + releasePgClient(client) + } + }; + + ReactivateHolderContact = async (body: HolderContactActivateOrInactivateDTO) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageholder_pkg_reactivateholdercontact($1, $2, $3, $4) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_HOLDERCONTACTID, body.P_USERID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return { + statusCode: 200, + message: ResponseStatus.reActivate, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageHolderService.name) + } finally { + releasePgClient(client) + } + }; + + SearchHolder = async (body: { P_SPID: number, P_USERID: string, P_HOLDERID: number | null, P_HOLDERNAME: string | null }) => { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageholder_pkg_searchholder($1, $2, $3, $4, $5) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_HOLDERID, body.P_HOLDERNAME, body.P_USERID, cursorName]); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + return fetchResult?.rows ? fetchResult?.rows : [] + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ManageHolderService.name) + } finally { + releasePgClient(client) + } + } } diff --git a/src/pg/pg.module.ts b/src/pg/pg.module.ts index 652cc30..e6653dc 100644 --- a/src/pg/pg.module.ts +++ b/src/pg/pg.module.ts @@ -5,10 +5,11 @@ import { UscibManagedSpModule } from './uscib-managed-sp/uscib-managed-sp.module import { UserMaintenanceModule } from './user-maintenance/user-maintenance.module'; import { ManageFeeModule } from './manage-fee/manage-fee.module'; import { ManageHolderModule } from './manage-holder/manage-holder.module'; +import { ManageClientsModule } from './manage-clients/manage-clients.module'; @Global() @Module({ - imports: [DbModule, ParamTableModule, UscibManagedSpModule, UserMaintenanceModule, ManageFeeModule, ManageHolderModule], + imports: [DbModule, ParamTableModule, UscibManagedSpModule, UserMaintenanceModule, ManageFeeModule, ManageHolderModule, ManageClientsModule], providers: [], exports: [UserMaintenanceModule] })