diff --git a/package-lock.json b/package-lock.json index 10e6c88..fb9eaa6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,7 @@ "pdf-lib": "^1.17.1", "pdf-merger-js": "^5.1.2", "pdfkit": "^0.17.1", - "pg": "^8.13.3", + "pg": "^8.16.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", "typeorm": "^0.3.20", @@ -56,6 +56,7 @@ "@types/mssql": "^9.1.7", "@types/node": "^22.10.7", "@types/oracledb": "^6.5.4", + "@types/pg": "^8.15.5", "@types/supertest": "^6.0.2", "@types/uuid": "^10.0.0", "eslint": "^9.31.0", @@ -3873,6 +3874,18 @@ "@types/node": "*" } }, + "node_modules/@types/pg": { + "version": "8.15.5", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.5.tgz", + "integrity": "sha512-LF7lF6zWEKxuT3/OR8wAZGzkg4ENGXFNyiV/JeOt9z5B+0ZVwbql9McqX5c/WStFq1GaGso7H1AzP/qSzmlCKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, "node_modules/@types/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", diff --git a/package.json b/package.json index 29cece9..9828e92 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "pdf-lib": "^1.17.1", "pdf-merger-js": "^5.1.2", "pdfkit": "^0.17.1", - "pg": "^8.13.3", + "pg": "^8.16.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", "typeorm": "^0.3.20", @@ -67,6 +67,7 @@ "@types/mssql": "^9.1.7", "@types/node": "^22.10.7", "@types/oracledb": "^6.5.4", + "@types/pg": "^8.15.5", "@types/supertest": "^6.0.2", "@types/uuid": "^10.0.0", "eslint": "^9.31.0", diff --git a/src/app.module.ts b/src/app.module.ts index f7caa7c..27a47dc 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -7,10 +7,11 @@ import { ReqBodyKeysToUppercaseMiddleware } from './middleware/reqBodyKeysToUppe import { ConfigModule } from '@nestjs/config'; import { MailModule } from './mail/mail.module'; import { PaypalModule } from './paypal/paypal.module'; +import { PgModule } from './pg/pg.module'; @Module({ imports: [ - ConfigModule.forRoot({ isGlobal: true }), + ConfigModule.forRoot({ isGlobal: true }), PgModule, AuthModule, DbModule, OracleModule, MailModule, PaypalModule ], controllers: [], diff --git a/src/db/db.config.ts b/src/db/db.config.ts index d1dae6f..44e3ac8 100644 --- a/src/db/db.config.ts +++ b/src/db/db.config.ts @@ -18,3 +18,28 @@ export const getMssqlConfig = (configService: ConfigService) => ({ encrypt: true, }, }); + +interface PgConfig { + user: string; + host: string; + database: string; + password: string; + port: number; + max: number; + idleTimeoutMillis: number; + connectionTimeoutMillis: number; + query_timeout: number; +} + + +export const getPgConfig = (configService: ConfigService): PgConfig => ({ + user: configService.get('PG_USER', ''), + host: configService.get('PG_HOST', ''), + database: configService.get('PG_DB', ''), + password: configService.get('PG_PWD', ''), // Password can be optional, e.g., if using environment variables or other auth + port: parseInt(configService.get('PG_PORT', '5432'), 10), + max: parseInt(configService.get('PG_MAX_CLIENTS_IN_POOL', '10'), 10), // Maximum number of clients in the pool + idleTimeoutMillis: parseInt(configService.get('PG_CLIENT_IDLE', '10000'), 10), // How long a client is allowed to remain idle before being closed + connectionTimeoutMillis: parseInt(configService.get('PG_CONNECTION_TIMEOUT', '0'), 10), // How long to try to establish a new connection before throwing an error + query_timeout: parseInt(configService.get('PG_QUERY_TIMEOUT', '5000'), 10), // Add this line, default 5000ms (5 seconds) +}); \ No newline at end of file diff --git a/src/db/db.module.ts b/src/db/db.module.ts index b1431ab..a673519 100644 --- a/src/db/db.module.ts +++ b/src/db/db.module.ts @@ -1,9 +1,9 @@ import { Global, Module } from '@nestjs/common'; -import { MssqlDBService, OracleDBService } from './db.service'; +import { MssqlDBService, OracleDBService, PgDBService } from './db.service'; @Global() @Module({ - providers: [OracleDBService, MssqlDBService], - exports: [OracleDBService, MssqlDBService], + providers: [OracleDBService, MssqlDBService, PgDBService], + exports: [OracleDBService, MssqlDBService, PgDBService], }) -export class DbModule {} +export class DbModule { } diff --git a/src/db/db.service.ts b/src/db/db.service.ts index 3ce3634..fc40b2c 100644 --- a/src/db/db.service.ts +++ b/src/db/db.service.ts @@ -1,9 +1,10 @@ import { createPool, Pool, Connection } from 'oracledb'; import { ConnectionPool } from 'mssql'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable, Logger, OnModuleDestroy } from '@nestjs/common'; import { InternalServerException } from 'src/exceptions/internalServerError.exception'; import { ConfigService } from '@nestjs/config'; -import { getMssqlConfig, getOracleConfig } from './db.config'; +import { getMssqlConfig, getOracleConfig, getPgConfig } from './db.config'; +import { Pool as pgPool, PoolClient } from 'pg'; @Injectable() export class OracleDBService { @@ -99,3 +100,103 @@ export class MssqlDBService { } } +@Injectable() +export class PgDBService implements OnModuleDestroy { + private pool: pgPool | null = null; + private readonly logger = new Logger(PgDBService.name); + + constructor(private readonly configService: ConfigService) { + this.initializePool().catch(err => { + this.logger.error('Error initializing PostgreSQL DB pool', err); + // Re-throw to indicate a critical startup failure, preventing the application from starting + throw new InternalServerException('Failed to initialize database pool'); + }); + } + + /** + * Initializes the PostgreSQL connection pool. + * This method is called once when the service is instantiated. + * It attempts to create the pool and test a connection to ensure connectivity. + */ + private async initializePool(): Promise { + try { + const config = getPgConfig(this.configService); + + this.pool = new pgPool({ + user: config.user, + host: config.host, + database: config.database, + password: config.password, + port: config.port, + max: config.max, + idleTimeoutMillis: config.idleTimeoutMillis, + connectionTimeoutMillis: config.connectionTimeoutMillis, + query_timeout: config.query_timeout + }); + + // Optional: Add an error listener to the pool. + // This listener catches errors on idle clients that might occur due to database restarts + // or network issues, allowing the pool to recover by discarding the faulty client. + this.pool.on('error', (err: Error, client: PoolClient) => { + this.logger.error('Unexpected error on idle PostgreSQL client', err, client); + // In production, you might want more sophisticated error handling, + // but for an idle client error, the pool usually handles replacing it. + }); + + // Test connection: Acquire and immediately release a client to confirm the pool is functional. + const client = await this.pool.connect(); + client.release(); // Release the client back to the pool after successful test + this.logger.log('PostgreSQL connection pool created and tested successfully'); + } catch (error) { + this.logger.error('Failed to create PostgreSQL DB pool:', error); + // Re-throw to propagate the error up to the constructor, which will halt startup + throw error; + } + } + + /** + * Retrieves a client from the connection pool. + * This method is used by consumers of the service to get a database connection. + * + * IMPORTANT: The caller is responsible for releasing the client back to the pool + * using `client.release()` in a `finally` block to prevent connection leaks. + * + * @returns A promise that resolves to a PoolClient. + * @throws InternalServerException if the pool is not initialized or if + * it fails to acquire a connection within the configured timeout. + */ + async getConnection(): Promise { + if (!this.pool) { + this.logger.error('Attempted to get a connection before pool was initialized'); + throw new InternalServerException('Database connection pool not initialized'); + } + + try { + // pool.connect() acquires a client from the pool. If no clients are available + // and the pool is at its max, it will wait until one is released or timeout occurs. + const client = await this.pool.connect(); + return client; + } catch (error) { + this.logger.error('Failed to get PostgreSQL DB connection from pool:', error); + throw new InternalServerException('Failed to acquire database connection'); + } + } + + /** + * Closes the PostgreSQL connection pool gracefully. + * This method is part of the NestJS `OnModuleDestroy` lifecycle hook, + * ensuring that the pool is drained and all connections are closed when the application shuts down. + */ + async onModuleDestroy(): Promise { + if (this.pool) { + try { + await this.pool.end(); // Drains the pool of all active and idle clients, then closes them. + this.logger.log('PostgreSQL DB pool closed successfully'); + } catch (error) { + this.logger.error('Error closing PostgreSQL DB pool:', error); + // Rethrowing here will not necessarily stop the shutdown, but logs the error. + throw new InternalServerException('Failed to gracefully close database pool'); + } + } + } +} \ No newline at end of file diff --git a/src/oracle/param-table/param-table.service.ts b/src/oracle/param-table/param-table.service.ts index f85cc49..e7b76fe 100644 --- a/src/oracle/param-table/param-table.service.ts +++ b/src/oracle/param-table/param-table.service.ts @@ -175,7 +175,7 @@ export class ParamTableService { throw new BadRequestException(fres[0].ERRORMESG) } - return { statusCode: 201, message: "Createdted Successfully", ...fres[0] }; + return { statusCode: 201, message: "Created Successfully", ...fres[0] }; } catch (error) { handleError(error, ParamTableService.name) @@ -230,7 +230,7 @@ export class ParamTableService { throw new BadRequestException(fres[0].ERRORMESG) } - return { statusCode: 201, message: "Createdted Successfully", ...fres[0] }; + return { statusCode: 201, message: "Created Successfully", ...fres[0] }; } catch (error) { handleError(error, ParamTableService.name) diff --git a/src/pg/manage-fee/manage-fee.controller.ts b/src/pg/manage-fee/manage-fee.controller.ts new file mode 100644 index 0000000..34f5fbe --- /dev/null +++ b/src/pg/manage-fee/manage-fee.controller.ts @@ -0,0 +1,139 @@ +import { Body, Controller, Get, Param, Patch, Post, UseGuards } from '@nestjs/common'; +import { ManageFeeService } from './manage-fee.service'; +import { ApiTags } from '@nestjs/swagger'; +import { JwtAuthGuard } from 'src/guards/jwt-auth.guard'; +import { RolesGuard } from 'src/guards/roles.guard'; +import { Roles } from 'src/decorators/roles.decorator'; +import { CreateBasicFeeDTO, CreateBondRateDTO, CreateCargoRateDTO, CreateCfFeeDTO, CreateCsFeeDTO, CreateEfFeeDTO, CreateFeeCommDTO, GetFeeGeneralDTO, UpdateBasicFeeDTO, UpdateBondRateDTO, UpdateCargoRateDTO, UpdateCfFeeDTO, UpdateCsFeeDTO, UpdateEfFeeDTO, UpdateFeeCommDTO } from 'src/dto/property.dto'; + +@ApiTags('Manage Fee - PG') +// @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('sa', 'ua') +@Controller('2') +export class ManageFeeController { + + constructor(private readonly manageFeeService: ManageFeeService) { } + + @Get('/GetBasicFeeRates/:P_SPID/:P_ACTIVE_INACTIVE') + GetBasicFeeRates(@Param() body: GetFeeGeneralDTO) { + return this.manageFeeService.GETBASICFEERATES(body); + } + + @Post('/CreateBasicFee') + CreateBasicFee(@Body() body: CreateBasicFeeDTO) { + return this.manageFeeService.CREATEBASICFEE(body); + } + + @Patch('/UpdateBasicFee') + UpdateBasicFee(@Body() body: UpdateBasicFeeDTO) { + return this.manageFeeService.UPDATEBASICFEE(body); + } + + // bond rate + + @Get('/GetBondRates/:P_SPID/:P_ACTIVE_INACTIVE') + GetBondRates(@Param() body: GetFeeGeneralDTO) { + return this.manageFeeService.GETBONDRATES(body); + } + + @Post('/CreateBondRate') + CreateBondRate(@Body() body: CreateBondRateDTO) { + return this.manageFeeService.CREATEBONDRATE(body); + } + + + @Patch('/UpdateBondRate') + UpdateBondRate(@Body() body: UpdateBondRateDTO) { + return this.manageFeeService.UPDATEBONDRATE(body); + } + + // cargo rate + + @Get('/GetCargoRates/:P_SPID/:P_ACTIVE_INACTIVE') + GetCargoRates(@Param() body: GetFeeGeneralDTO) { + return this.manageFeeService.GETCARGORATES(body); + } + + + @Post('/CreateCargoRate') + CreateCargoRate(@Body() body: CreateCargoRateDTO) { + return this.manageFeeService.CREATECARGORATE(body); + } + + + @Patch('/UpdateCargoRate') + UpdateCargoRate(@Body() body: UpdateCargoRateDTO) { + return this.manageFeeService.UPDATECARGORATE(body); + } + + // cf fee rate + + @Get('/GetCfFeeRates/:P_SPID/:P_ACTIVE_INACTIVE') + GetCfFeeRates(@Param() body: GetFeeGeneralDTO) { + return this.manageFeeService.GETCFFEERATES(body); + } + + + @Post('/CreateCfFee') + CreateCfFee(@Body() body: CreateCfFeeDTO) { + return this.manageFeeService.CREATECFFEE(body); + } + + @Patch('/UpdateCfFee') + UpdateCfFee(@Body() body: UpdateCfFeeDTO) { + return this.manageFeeService.UPDATECFFEE(body); + } + + // cs fee rate + + @Get('/GetCsFeeRates/:P_SPID/:P_ACTIVE_INACTIVE') + GetCsFeeRates(@Param() body: GetFeeGeneralDTO) { + return this.manageFeeService.GETCSFEERATES(body); + } + + @Post('/CreateCsFee') + CreateCsFee(@Body() body: CreateCsFeeDTO) { + return this.manageFeeService.CREATECSFEE(body); + } + + @Patch('/UpdateCsFee') + UpdateCsFee(@Body() body: UpdateCsFeeDTO) { + return this.manageFeeService.UPDATECSFEE(body); + } + + // ef fee rate + + @Get('/GetEfFeeRates/:P_SPID/:P_ACTIVE_INACTIVE') + GetEfFeeRates(@Param() body: GetFeeGeneralDTO) { + return this.manageFeeService.GETEFFEERATES(body); + } + + @Post('/CreateEfFee') + CreateEeFee(@Body() body: CreateEfFeeDTO) { + return this.manageFeeService.CREATEEFFEE(body); + } + + @Patch('/UpdateEfFee') + UpdateEfFee(@Body() body: UpdateEfFeeDTO) { + return this.manageFeeService.UPDATEEFFEE(body); + } + + // fee comm + + @Get('/GetFeeComm/:P_SPID/:P_ACTIVE_INACTIVE') + GetFeeComm(@Param() body: GetFeeGeneralDTO) { + return this.manageFeeService.GETFEECOMM(body); + } + + + @Post('/CreateFeeComm') + CreateFeeComm(@Body() body: CreateFeeCommDTO) { + return this.manageFeeService.CREATEFEECOMM(body); + } + + + @Patch('/UpdateFeeComm') + UpdateFeeComm(@Body() body: UpdateFeeCommDTO) { + return this.manageFeeService.UPDATEFEECOMM(body); + } +} diff --git a/src/pg/manage-fee/manage-fee.module.ts b/src/pg/manage-fee/manage-fee.module.ts new file mode 100644 index 0000000..a92b621 --- /dev/null +++ b/src/pg/manage-fee/manage-fee.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { ManageFeeController } from './manage-fee.controller'; +import { ManageFeeService } from './manage-fee.service'; + +@Module({ + controllers: [ManageFeeController], + providers: [ManageFeeService] +}) +export class ManageFeeModule {} diff --git a/src/pg/manage-fee/manage-fee.service.ts b/src/pg/manage-fee/manage-fee.service.ts new file mode 100644 index 0000000..741cd3f --- /dev/null +++ b/src/pg/manage-fee/manage-fee.service.ts @@ -0,0 +1,947 @@ +import { Injectable } from '@nestjs/common'; +import { PgDBService } from 'src/db/db.service'; +import { CreateBasicFeeDTO, CreateBondRateDTO, CreateCargoRateDTO, CreateCfFeeDTO, CreateCsFeeDTO, CreateEfFeeDTO, CreateFeeCommDTO, GetFeeGeneralDTO, UpdateBasicFeeDTO, UpdateBondRateDTO, UpdateCargoRateDTO, UpdateCfFeeDTO, UpdateCsFeeDTO, UpdateEfFeeDTO, UpdateFeeCommDTO } from 'src/dto/property.dto'; + +import { PoolClient } from 'pg'; +import { checkPgUserDefinedErrors, handlePgError, releasePgClient, ResponseStatus } from 'src/utils/helper'; + +@Injectable() +export class ManageFeeService { + + constructor(private readonly pgDBService: PgDBService) { } + + async GETBASICFEERATES(body: GetFeeGeneralDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_getbasicfeerates($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_ACTIVE_INACTIVE, 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + async CREATEBASICFEE(body: CreateBasicFeeDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_createbasicfee($1, $2, $3, $4, $5, $6, $7) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_STARTNUMBER, + body.P_ENDNUMBER, + body.P_EFFDATE, + body.P_FEES, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + + } + + async UPDATEBASICFEE(body: UpdateBasicFeeDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_updatebasicfee($1, $2, $3, $4, $5) + `; + await client.query(callProcQuery, + [ + body.P_BASICFEESETUPID, + body.P_FEES, + body.P_EFFDATE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + // bond rate + + async GETBONDRATES(body: GetFeeGeneralDTO) { + + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_getbondrates($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_ACTIVE_INACTIVE, 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + + } + + async CREATEBONDRATE(body: CreateBondRateDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_createbondrate($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_HOLDERTYPE, + body.P_USCIBMEMBERFLAG, + body.P_SPCLCOMMODITY, + body.P_SPCLCOUNTRY, + body.P_EFFDATE, + body.P_RATE, + body.P_USERID, + body.P_PCT_VALUE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + async UPDATEBONDRATE(body: UpdateBondRateDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_updatebondrate($1, $2, $3, $4, $5, $6) + `; + await client.query(callProcQuery, + [ + body.P_BONDRATESETUPID, + body.P_RATE, + body.P_EFFDATE, + body.P_USERID, + body.P_PCT_VALUE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + + } + + // cargo rate + + async GETCARGORATES(body: GetFeeGeneralDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_getcargorates($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_ACTIVE_INACTIVE, 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + async CREATECARGORATE(body: CreateCargoRateDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_createcargorate($1, $2, $3, $4, $5, $6, $7, $8) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_CARNETTYPE, + body.P_STARTSETS, + body.P_ENDSETS, + body.P_EFFDATE, + body.P_RATE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + + } + + async UPDATECARGORATE(body: UpdateCargoRateDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_updatecargorate($1, $2, $3, $4, $5) + `; + await client.query(callProcQuery, + [ + body.P_CARGORATESETUPID, + body.P_RATE, + body.P_EFFDATE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + // counter foil + + async GETCFFEERATES(body: GetFeeGeneralDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_getcffeerates($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_ACTIVE_INACTIVE, 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + + } + + async CREATECFFEE(body: CreateCfFeeDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_createcffee($1, $2, $3, $4, $5, $6, $7, $8, $9) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_STARTSETS, + body.P_ENDSETS, + body.P_EFFDATE, + body.P_CUSTOMERTYPE, + body.P_CARNETTYPE, + body.P_RATE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + + } + + async UPDATECFFEE(body: UpdateCfFeeDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_updatecffee($1, $2, $3, $4, $5) + `; + await client.query(callProcQuery, + [ + body.P_CFFEESETUPID, + body.P_RATE, + body.P_EFFDATE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + + } + + + // continuation sheet + + async GETCSFEERATES(body: GetFeeGeneralDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_getcsfeerates($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_ACTIVE_INACTIVE, 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + async CREATECSFEE(body: CreateCsFeeDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_createcsfee($1, $2, $3, $4, $5, $6, $7) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_CUSTOMERTYPE, + body.P_CARNETTYPE, + body.P_EFFDATE, + body.P_RATE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + async UPDATECSFEE(body: UpdateCsFeeDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_updatecsfee($1, $2, $3, $4, $5) + `; + await client.query(callProcQuery, + [ + body.P_CSFEESETUPID, + body.P_RATE, + body.P_EFFDATE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + + } + + // expedited fee + + async GETEFFEERATES(body: GetFeeGeneralDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_geteffeerates($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_ACTIVE_INACTIVE, 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + async CREATEEFFEE(body: CreateEfFeeDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_createeffee($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_CUSTOMERTYPE, + body.P_DELIVERYTYPE, + body.P_STARTTIME, + body.P_ENDTIME, + body.P_TIMEZONE, + body.P_EFFDATE, + body.P_FEES, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + async UPDATEEFFEE(body: UpdateEfFeeDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_updateeffee($1, $2, $3, $4, $5) + `; + await client.query(callProcQuery, + [ + body.P_EFFEESETUPID, + body.P_FEES, + body.P_EFFDATE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + // fee comm + + async GETFEECOMM(body: GetFeeGeneralDTO) { + + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_getfeecomm($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_ACTIVE_INACTIVE, 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + async CREATEFEECOMM(body: CreateFeeCommDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_createfeecomm($1, $2, $3, $4, $5, $6) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_PARAMID, + body.P_COMMRATE, + body.P_EFFDATE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } + + async UPDATEFEECOMM(body: UpdateFeeCommDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".managefee_setup_pkg_updatefeecomm($1, $2, $3, $4, $5) + `; + await client.query(callProcQuery, + [ + body.P_FEECOMMID, + body.P_RATE, + body.P_EFFDATE, + 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, ManageFeeService.name) + } finally { + releasePgClient(client) + } + } +} diff --git a/src/pg/param-table/param-table.controller.ts b/src/pg/param-table/param-table.controller.ts new file mode 100644 index 0000000..3f11218 --- /dev/null +++ b/src/pg/param-table/param-table.controller.ts @@ -0,0 +1,86 @@ +import { Body, Controller, Get, Param, Patch, Post, Put, Query, UseGuards } from '@nestjs/common'; +import { ApiQuery, ApiTags } from '@nestjs/swagger'; +import { ParamTableService } from './param-table.service'; + +import { + ActivateOrInactivateParamRecordDTO, CreateParamRecordDTO, CreateTableRecordDTO, + getParamValuesDTO, SPID_DTO, UpdateParamRecordDTO +} from 'src/dto/property.dto'; +import { Roles } from 'src/decorators/roles.decorator'; +import { JwtAuthGuard } from 'src/guards/jwt-auth.guard'; +import { RolesGuard } from 'src/guards/roles.guard'; + +@ApiTags('Param Table - PG') +// @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('sa', 'ua') +@Controller('2') +export class ParamTableController { + + constructor(private readonly paramTableService: ParamTableService) { } + + @Get('/GetParamValues') + @Roles('ca', 'sa', 'ua') + @ApiQuery({ + name: 'P_SPID', + required: false, + type: Number, + description: 'The ID of the parameter', + }) + @ApiQuery({ + name: 'P_PARAMTYPE', + required: false, + type: String, + description: 'The type of the parameter', + }) + getParamValues(@Query() body: getParamValuesDTO) { + return this.paramTableService.GETPARAMVALUES(body); + } + + @Get('/GetAllParamValues') + @ApiQuery({ + name: 'P_SPID', + required: false, + type: Number, + description: 'The ID of the parameter', + }) + @ApiQuery({ + name: 'P_PARAMTYPE', + required: false, + type: String, + description: 'The type of the parameter', + }) + getAllParamValues(@Query() body: getParamValuesDTO) { + return this.paramTableService.GETALLPARAMVALUES(body); + } + + @Get('GetCountriesAndMessages/:P_SPID') + @Roles('ca', 'sa', 'ua') + GET_COUNTRIES_AND_MESSAGES(@Param() body: SPID_DTO) { + return this.paramTableService.GET_COUNTRIES_AND_MESSAGES(body); + } + + @Post('/CreateTableRecord') + createTableRecord(@Body() body: CreateTableRecordDTO) { + return this.paramTableService.CREATETABLERECORD(body); + } + + @Post('/CreateParamRecord') + createParamRecord(@Body() body: CreateParamRecordDTO) { + return this.paramTableService.CREATEPARAMRECORD(body); + } + + @Patch('/UpdateParamRecord') + UpdateParamRecord(@Body() body: UpdateParamRecordDTO) { + return this.paramTableService.UPDATEPARAMRECORD(body); + } + + @Patch('/InActivateParamRecord') + inActivateParamRecord(@Body() body: ActivateOrInactivateParamRecordDTO) { + return this.paramTableService.INACTIVATEPARAMRECORD(body); + } + + @Patch('/ReActivateParamRecord') + reActivateParamRecord(@Body() body: ActivateOrInactivateParamRecordDTO) { + return this.paramTableService.REACTIVATEPARAMRECORD(body); + } +} diff --git a/src/pg/param-table/param-table.module.ts b/src/pg/param-table/param-table.module.ts new file mode 100644 index 0000000..6bea9f5 --- /dev/null +++ b/src/pg/param-table/param-table.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ParamTableController } from './param-table.controller'; +import { ParamTableService } from './param-table.service'; +import { AuthModule } from 'src/auth/auth.module'; + +@Module({ + controllers: [ParamTableController], + providers: [ParamTableService] +}) +export class ParamTableModule { } diff --git a/src/pg/param-table/param-table.service.ts b/src/pg/param-table/param-table.service.ts new file mode 100644 index 0000000..83aab86 --- /dev/null +++ b/src/pg/param-table/param-table.service.ts @@ -0,0 +1,308 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { PoolClient } from 'pg'; +import { PgDBService } from 'src/db/db.service'; +import { ActivateOrInactivateParamRecordDTO, CreateParamRecordDTO, CreateTableRecordDTO, getParamValuesDTO, SPID_DTO, UpdateParamRecordDTO } from 'src/dto/property.dto'; +import { checkPgUserDefinedErrors, handlePgError, releasePgClient, ResponseStatus } from 'src/utils/helper'; + +@Injectable() +export class ParamTableService { + private readonly logger = new Logger(ParamTableService.name); + + constructor(private readonly pgDBService: PgDBService) { } + + async GETPARAMVALUES(body: getParamValuesDTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageparamtable_pkg_getparamvalues($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_PARAMTYPE, 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'); + + return fetchResult.rows; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ParamTableService.name) + } finally { + releasePgClient(client) + } + } + + async GETALLPARAMVALUES(body: getParamValuesDTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageparamtable_pkg_getallparamvalues($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_PARAMTYPE, 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'); + + return fetchResult.rows; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ParamTableService.name) + } finally { + releasePgClient(client) + } + } + + async GET_COUNTRIES_AND_MESSAGES(body: SPID_DTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageparamtable_pkg_getcountriesandmessages($1, $2) + `; + await client.query(callProcQuery, [body.P_SPID, 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'); + + return fetchResult.rows; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ParamTableService.name) + } finally { + releasePgClient(client) + } + } + + async CREATETABLERECORD(body: CreateTableRecordDTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageparamtable_pkg_createtablerecord($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_USERID, body.P_TABLEFULLDESC, 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; + return { statusCode: 201, message: ResponseStatus.created, ...fetchResult?.rows[0] }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ParamTableService.name) + } finally { + releasePgClient(client) + } + } + + async CREATEPARAMRECORD(body: CreateParamRecordDTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + // Call the stored procedure + const callProcQuery = ` + CALL "CARNETSYS".manageparamtable_pkg_createparamrecord( + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 + ) + `; + + await client.query(callProcQuery, [ + body.P_SPID, + body.P_PARAMTYPE, + body.P_PARAMDESC, + body.P_PARAMVALUE, + body.P_ADDLPARAMVALUE1, + body.P_ADDLPARAMVALUE2, + body.P_ADDLPARAMVALUE3, + body.P_ADDLPARAMVALUE4, + body.P_ADDLPARAMVALUE5, + body.P_SORTSEQ, + body.P_USERID, + cursorName + ]); + + // ✅ Correct: quote the cursor name when using it in SQL + const fetchResult = await client.query(`FETCH ALL FROM "${cursorName}"`); + + // ✅ Always close the cursor + await client.query(`CLOSE "${cursorName}"`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + // Return response + return { + statusCode: 201, + message: ResponseStatus.created, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ParamTableService.name) + } finally { + releasePgClient(client) + } + } + + async UPDATEPARAMRECORD(body: UpdateParamRecordDTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageparamtable_pkg_updateparamrecord( + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11 + ) + `; + + await client.query(callProcQuery, [ + body.P_SPID, + body.P_PARAMID, + body.P_PARAMDESC, + body.P_ADDLPARAMVALUE1, + body.P_ADDLPARAMVALUE2, + body.P_ADDLPARAMVALUE3, + body.P_ADDLPARAMVALUE4, + body.P_ADDLPARAMVALUE5, + body.P_SORTSEQ, + body.P_USERID, + cursorName + ]); + + // ✅ Correct: quote the cursor name when using it in SQL + const fetchResult = await client.query(`FETCH ALL FROM "${cursorName}"`); + + // ✅ Always close the cursor + await client.query(`CLOSE "${cursorName}"`); + await client.query('COMMIT'); + + checkPgUserDefinedErrors(fetchResult); + + // Return response + return { + statusCode: 200, + message: ResponseStatus.updated, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ParamTableService.name) + } finally { + releasePgClient(client) + } + } + + async INACTIVATEPARAMRECORD(body: ActivateOrInactivateParamRecordDTO) { + let client: PoolClient | null = null; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageparamtable_pkg_inactivateparamrecord($1, $2) + `; + await client.query(callProcQuery, [body.P_PARAMID, body.P_USERID]); + + await client.query('COMMIT'); + + return { + statusCode: 200, + message: ResponseStatus.inActivate + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ParamTableService.name) + } finally { + releasePgClient(client) + } + } + + async REACTIVATEPARAMRECORD(body: ActivateOrInactivateParamRecordDTO) { + let client: PoolClient | null = null; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".manageparamtable_pkg_reactivateparamrecord($1, $2) + `; + await client.query(callProcQuery, [body.P_PARAMID, body.P_USERID]); + + await client.query('COMMIT'); + + return { + statusCode: 200, + message: ResponseStatus.reActivate + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, ParamTableService.name) + } finally { + releasePgClient(client) + } + } +} diff --git a/src/pg/pg.module.ts b/src/pg/pg.module.ts new file mode 100644 index 0000000..9a4d2a4 --- /dev/null +++ b/src/pg/pg.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { ParamTableModule } from './param-table/param-table.module'; +import { DbModule } from 'src/db/db.module'; +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'; + +@Module({ + imports: [DbModule, ParamTableModule, UscibManagedSpModule, UserMaintenanceModule, ManageFeeModule], +}) +export class PgModule { } diff --git a/src/pg/uscib-managed-sp/carnet-sequence/carnet-sequence.controller.ts b/src/pg/uscib-managed-sp/carnet-sequence/carnet-sequence.controller.ts new file mode 100644 index 0000000..5906552 --- /dev/null +++ b/src/pg/uscib-managed-sp/carnet-sequence/carnet-sequence.controller.ts @@ -0,0 +1,25 @@ +import { Body, Controller, Get, Param, Post, UseGuards } from '@nestjs/common'; +import { CarnetSequenceService } from './carnet-sequence.service'; +import { CreateCarnetSequenceDTO, SPID_DTO } from 'src/dto/property.dto'; +import { ApiTags } from '@nestjs/swagger'; +import { JwtAuthGuard } from 'src/guards/jwt-auth.guard'; +import { RolesGuard } from 'src/guards/roles.guard'; +import { Roles } from 'src/decorators/roles.decorator'; + +@ApiTags('Carnet Sequence - PG') +// @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('sa', 'ua') +@Controller('2') +export class CarnetSequenceController { + constructor(private readonly carnetSequenceService: CarnetSequenceService) { } + + @Post('/CreateCarnetSequence/') + createCarnetSequence(@Body() body: CreateCarnetSequenceDTO) { + return this.carnetSequenceService.createCarnetSequence(body); + } + + @Get('/GetCarnetSequence/:P_SPID') + getCarnetSequence(@Param() params: SPID_DTO) { + return this.carnetSequenceService.getCarnetSequence(params); + } +} diff --git a/src/pg/uscib-managed-sp/carnet-sequence/carnet-sequence.module.ts b/src/pg/uscib-managed-sp/carnet-sequence/carnet-sequence.module.ts new file mode 100644 index 0000000..64f6ca9 --- /dev/null +++ b/src/pg/uscib-managed-sp/carnet-sequence/carnet-sequence.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { CarnetSequenceController } from './carnet-sequence.controller'; +import { CarnetSequenceService } from './carnet-sequence.service'; + +@Module({ + controllers: [CarnetSequenceController], + providers: [CarnetSequenceService] +}) +export class CarnetSequenceModule {} diff --git a/src/pg/uscib-managed-sp/carnet-sequence/carnet-sequence.service.ts b/src/pg/uscib-managed-sp/carnet-sequence/carnet-sequence.service.ts new file mode 100644 index 0000000..cb97120 --- /dev/null +++ b/src/pg/uscib-managed-sp/carnet-sequence/carnet-sequence.service.ts @@ -0,0 +1,81 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { PgDBService } from 'src/db/db.service'; +import { CreateCarnetSequenceDTO, SPID_DTO } from 'src/dto/property.dto'; +import { InternalServerException } from 'src/exceptions/internalServerError.exception'; + +import { PoolClient } from 'pg'; +import { checkPgUserDefinedErrors, handlePgError, releasePgClient, ResponseStatus } from 'src/utils/helper'; + + +@Injectable() +export class CarnetSequenceService { + private readonly logger = new Logger(CarnetSequenceService.name); + + constructor(private readonly pgDBService: PgDBService) { } + + async createCarnetSequence(body: CreateCarnetSequenceDTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_createcarnetsequence($1, $2, $3, $4, $5, $6) + `; + await client.query(callProcQuery, [body.P_SPID, body.P_REGIONID, body.P_STARTNUMBER, body.P_ENDNUMBER, body.P_CARNETTYPE, 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, CarnetSequenceService.name) + } finally { + releasePgClient(client) + } + } + + async getCarnetSequence(body: SPID_DTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_getcarnetsequence($1, $2) + `; + await client.query(callProcQuery, [body.P_SPID, 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'); + + return fetchResult.rows; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, CarnetSequenceService.name) + } finally { + releasePgClient(client) + } + } +} diff --git a/src/pg/uscib-managed-sp/region/region.controller.ts b/src/pg/uscib-managed-sp/region/region.controller.ts new file mode 100644 index 0000000..8254a23 --- /dev/null +++ b/src/pg/uscib-managed-sp/region/region.controller.ts @@ -0,0 +1,30 @@ +import { Body, Controller, Get, Param, Patch, Post, UseGuards } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { Roles } from 'src/decorators/roles.decorator'; +import { JwtAuthGuard } from 'src/guards/jwt-auth.guard'; +import { RolesGuard } from 'src/guards/roles.guard'; +import { RegionService } from './region.service'; +import { InsertRegionsDto, SPID_DTO, UpdateRegionDto } from 'src/dto/property.dto'; + +@ApiTags('Regions - PG') +// @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('sa', 'ua') +@Controller('2') +export class RegionController { + constructor(private readonly regionService: RegionService) { } + + @Post('/InsertRegions') + insertRegions(@Body() body: InsertRegionsDto) { + return this.regionService.insertRegions(body); + } + + @Patch('/UpdateRegion') + updateRegions(@Body() body: UpdateRegionDto) { + return this.regionService.updateRegions(body); + } + + @Get('/GetRegions/:P_SPID') + getRegions(@Param() param: SPID_DTO) { + return this.regionService.getRegions(param); + } +} diff --git a/src/pg/uscib-managed-sp/region/region.module.ts b/src/pg/uscib-managed-sp/region/region.module.ts new file mode 100644 index 0000000..d776aee --- /dev/null +++ b/src/pg/uscib-managed-sp/region/region.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { RegionController } from './region.controller'; +import { RegionService } from './region.service'; + +@Module({ + controllers: [RegionController], + providers: [RegionService] +}) +export class RegionModule {} diff --git a/src/pg/uscib-managed-sp/region/region.service.ts b/src/pg/uscib-managed-sp/region/region.service.ts new file mode 100644 index 0000000..cb24d32 --- /dev/null +++ b/src/pg/uscib-managed-sp/region/region.service.ts @@ -0,0 +1,120 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { PgDBService } from 'src/db/db.service'; +import { InsertRegionsDto, SPID_DTO, UpdateRegionDto } from 'src/dto/property.dto'; +import { InternalServerException } from 'src/exceptions/internalServerError.exception'; + +import { PoolClient } from 'pg'; +import { checkPgUserDefinedErrors, handlePgError, releasePgClient, ResponseStatus } from 'src/utils/helper'; + +@Injectable() +export class RegionService { + private readonly logger = new Logger(RegionService.name); + + constructor(private readonly pgDBService: PgDBService) { } + + async insertRegions(body: InsertRegionsDto) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_insertnewregion($1, $2, $3, $4) + `; + await client.query(callProcQuery, [body.P_REGION, body.P_NAME, body.P_SPID, 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, RegionService.name) + } finally { + releasePgClient(client) + } + } + + async updateRegions(body: UpdateRegionDto) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_updateregion($1, $2, $3) + `; + await client.query(callProcQuery, [body.P_REGIONID, body.P_NAME, 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, RegionService.name) + } finally { + releasePgClient(client) + } + } + + async getRegions(body: SPID_DTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_getregions($1, $2) + `; + await client.query(callProcQuery, [body.P_SPID, 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'); + + return fetchResult.rows; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, RegionService.name) + } finally { + releasePgClient(client) + } + + } +} diff --git a/src/pg/uscib-managed-sp/sp-contacts/sp-contacts.controller.ts b/src/pg/uscib-managed-sp/sp-contacts/sp-contacts.controller.ts new file mode 100644 index 0000000..4a287ee --- /dev/null +++ b/src/pg/uscib-managed-sp/sp-contacts/sp-contacts.controller.ts @@ -0,0 +1,48 @@ +import { Body, Controller, Get, Param, Patch, Post, Put, UseGuards } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { Roles } from 'src/decorators/roles.decorator'; +import { JwtAuthGuard } from 'src/guards/jwt-auth.guard'; +import { RolesGuard } from 'src/guards/roles.guard'; +import { SpContactsService } from './sp-contacts.service'; +import { InsertSPContactsDTO, SP_CONTACTID_DTO, SPID_DTO, UpdateSPContactsDTO } from 'src/dto/property.dto'; + +@ApiTags('SPContacts - PG') +// @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('sa', 'ua') +@Controller('2') +export class SpContactsController { + + constructor(private readonly spContactsService: SpContactsService) { } + + + @Post('/InsertSPContacts') + insertSPContacts(@Body() body: InsertSPContactsDTO) { + return this.spContactsService.insertSPContacts(body); + } + + @Patch('/SetSPDefaultContact/:P_SPCONTACTID') + @Roles('ua') + setSPDefaultcontact(@Param() param: SP_CONTACTID_DTO) { + return this.spContactsService.setSPDefaultcontact(param); + } + + @Put('/UpdateSPContacts') + updateSPContacts(@Body() body: UpdateSPContactsDTO) { + return this.spContactsService.updateSPContacts(body); + } + + // @Patch('/InactivateSPContact/:P_SPCONTACTID') + inactivateSPContact(@Param() param: SP_CONTACTID_DTO) { + return this.spContactsService.inactivateSPContact(param); + } + + @Get('/GetSPDefaultContact/:P_SPID') + getSPDefaultcontact(@Param() param: SPID_DTO) { + return this.spContactsService.getSPDefaultcontacts(param); + } + + @Get('/GetSPAllContacts/:P_SPID') + getSPAllContacts(@Param() param: SPID_DTO) { + return this.spContactsService.getSPAllContacts(param); + } +} diff --git a/src/pg/uscib-managed-sp/sp-contacts/sp-contacts.module.ts b/src/pg/uscib-managed-sp/sp-contacts/sp-contacts.module.ts new file mode 100644 index 0000000..abbcf60 --- /dev/null +++ b/src/pg/uscib-managed-sp/sp-contacts/sp-contacts.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { SpContactsController } from './sp-contacts.controller'; +import { SpContactsService } from './sp-contacts.service'; + +@Module({ + controllers: [SpContactsController], + providers: [SpContactsService] +}) +export class SpContactsModule {} diff --git a/src/pg/uscib-managed-sp/sp-contacts/sp-contacts.service.ts b/src/pg/uscib-managed-sp/sp-contacts/sp-contacts.service.ts new file mode 100644 index 0000000..333bd04 --- /dev/null +++ b/src/pg/uscib-managed-sp/sp-contacts/sp-contacts.service.ts @@ -0,0 +1,240 @@ +import { Injectable } from '@nestjs/common'; +import { InsertSPContactsDTO, SP_CONTACTID_DTO, SPID_DTO, UpdateSPContactsDTO } from 'src/dto/property.dto'; +import { InternalServerException } from 'src/exceptions/internalServerError.exception'; + +import { PoolClient } from 'pg'; +import { PgDBService } from 'src/db/db.service'; +import { checkPgUserDefinedErrors, handlePgError, releasePgClient, ResponseStatus } from 'src/utils/helper'; + +@Injectable() +export class SpContactsService { + + constructor(private readonly pgDBService: PgDBService) { } + + async insertSPContacts(body: InsertSPContactsDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_insertspcontacts($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_DEFCONTACTFLAG, + 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_USER_ID, + 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, SpContactsService.name) + } finally { + releasePgClient(client) + } + + } + + async setSPDefaultcontact(body: SP_CONTACTID_DTO) { + let client: PoolClient | null = null; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_setdefaultcontact($1) + `; + await client.query(callProcQuery, [body.P_SPCONTACTID]); + + await client.query('COMMIT'); + + return { statusCode: 200, message: ResponseStatus.defaultSpContactAdded }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, SpContactsService.name) + } finally { + releasePgClient(client) + } + } + + async updateSPContacts(body: UpdateSPContactsDTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_updatespcontacts($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) + `; + await client.query(callProcQuery, + [ + body.P_SPCONTACTID, + 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_USER_ID, + 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, SpContactsService.name) + } finally { + releasePgClient(client) + } + } + + async inactivateSPContact(body: SP_CONTACTID_DTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_setdefaultcontact($1) + `; + await client.query(callProcQuery, [body.P_SPCONTACTID]); + + // 🚫 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'); + + return { statusCode: 200, message: ResponseStatus.inActivate }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, SpContactsService.name) + } finally { + releasePgClient(client) + } + } + + async getSPDefaultcontacts(body: SPID_DTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_getspdefaultcontacts($1, $2) + `; + await client.query(callProcQuery, [body.P_SPID, 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'); + + return fetchResult.rows; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, SpContactsService.name) + } finally { + releasePgClient(client) + } + + } + + async getSPAllContacts(body: SPID_DTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_getspallcontacts($1, $2) + `; + await client.query(callProcQuery, [body.P_SPID, 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'); + + return fetchResult.rows; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, SpContactsService.name) + } finally { + releasePgClient(client) + } + } +} diff --git a/src/pg/uscib-managed-sp/sp/sp.controller.ts b/src/pg/uscib-managed-sp/sp/sp.controller.ts new file mode 100644 index 0000000..5c01257 --- /dev/null +++ b/src/pg/uscib-managed-sp/sp/sp.controller.ts @@ -0,0 +1,37 @@ +import { Body, Controller, Get, Param, Post, Put, UseGuards } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { Roles } from 'src/decorators/roles.decorator'; +import { JwtAuthGuard } from 'src/guards/jwt-auth.guard'; +import { RolesGuard } from 'src/guards/roles.guard'; +import { SpService } from './sp.service'; +import { InsertNewServiceProviderDTO, SPID_DTO, UpdateServiceProviderDTO } from 'src/dto/property.dto'; + +@ApiTags('SP - PG') +// @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('sa', 'ua') +@Controller('2') +export class SpController { + constructor(private readonly spService: SpService) { } + + @Post('/InsertNewServiceProvider') + @Roles('ua') + insertNewServiceProvider(@Body() body: InsertNewServiceProviderDTO) { + return this.spService.insertNewServiceProvider(body); + } + + @Put('/UpdateServiceProvider') + updateServiceProider(@Body() body: UpdateServiceProviderDTO) { + return this.spService.updateServiceProvider(body); + } + + @Get('/GetAllServiceproviders') + @Roles('ua') + getAllServiceproviders() { + return this.spService.getAllServiceproviders(); + } + + @Get('/GetSelectedServiceprovider/:P_SPID') + getSelectedServiceprovider(@Param() param: SPID_DTO) { + return this.spService.getServiceproviderByID(param); + } +} diff --git a/src/pg/uscib-managed-sp/sp/sp.module.ts b/src/pg/uscib-managed-sp/sp/sp.module.ts new file mode 100644 index 0000000..774e3e0 --- /dev/null +++ b/src/pg/uscib-managed-sp/sp/sp.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { SpController } from './sp.controller'; +import { SpService } from './sp.service'; + +@Module({ + controllers: [SpController], + providers: [SpService] +}) +export class SpModule {} diff --git a/src/pg/uscib-managed-sp/sp/sp.service.ts b/src/pg/uscib-managed-sp/sp/sp.service.ts new file mode 100644 index 0000000..7b583cb --- /dev/null +++ b/src/pg/uscib-managed-sp/sp/sp.service.ts @@ -0,0 +1,205 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { PgDBService } from 'src/db/db.service'; +import { InsertNewServiceProviderDTO, SPID_DTO, UpdateServiceProviderDTO } from 'src/dto/property.dto'; +import { InternalServerException } from 'src/exceptions/internalServerError.exception'; + +import { PoolClient } from 'pg'; +import { checkPgUserDefinedErrors, handlePgError, releasePgClient, ResponseStatus } from 'src/utils/helper'; + +@Injectable() +export class SpService { + + private readonly logger = new Logger(SpService.name); + + constructor(private readonly pgDBService: PgDBService) { } + + async insertNewServiceProvider(body: InsertNewServiceProviderDTO) { + + console.log(" i got executed here ...."); + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + console.log(" pg connection successfull ..... "); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_insertnewsp($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) + `; + await client.query(callProcQuery, + [ + body.P_NAME, + 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_REPLACEMENTREGION, + body.P_BONDSURETY, + body.P_CARGOPOLICYNO, + body.P_CARGOSURETY, + body.P_USER_ID, + body.P_NOTES, + body.P_FILEIDS, + cursorName + ]); + + console.log("Procedure called"); + + // 🚫 DON'T quote the cursor name in FETCH + const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); + + console.log("Fetch done", fetchResult?.rows); + + // 🚫 DON'T quote the cursor name in CLOSE + await client.query(`CLOSE ${cursorName}`); + console.log("Cursor closed"); + await client.query('COMMIT'); + console.log("Transaction committed"); + + checkPgUserDefinedErrors(fetchResult); + + return { statusCode: 201, message: ResponseStatus.created, ...fetchResult?.rows[0] || {} }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + console.log(" i went through here ... "); + + handlePgError(error, SpService.name) + } finally { + releasePgClient(client) + } + + } + + async updateServiceProvider(body: UpdateServiceProviderDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_updatesp($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_NAME, + body.P_LOOKUPCODE, + body.P_ADDRESS1, + body.P_ADDRESS2, + body.P_CITY, + body.P_STATE, + body.P_ZIP, + body.P_COUNTRY, + body.P_BONDSURETY, + body.P_CARGOPOLICYNO, + body.P_CARGOSURETY, + body.P_REPLACEMENTREGION, + body.P_ISSUINGREGION, + body.P_USER_ID, + body.P_NOTES, + body.P_FILEIDS, + 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, SpService.name) + } finally { + releasePgClient(client) + } + } + + async getAllServiceproviders() { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_getallsps($1) + `; + await client.query(callProcQuery, [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'); + + return fetchResult.rows; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, SpService.name) + } finally { + releasePgClient(client) + } + + } + + async getServiceproviderByID(body: SPID_DTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".uscib_managed_pkg_getspbyspid($1, $2) + `; + await client.query(callProcQuery, [body.P_SPID, 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'); + + return fetchResult.rows; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, SpService.name) + } finally { + releasePgClient(client) + } + + } +} diff --git a/src/pg/uscib-managed-sp/uscib-managed-sp.module.ts b/src/pg/uscib-managed-sp/uscib-managed-sp.module.ts new file mode 100644 index 0000000..ffca1c4 --- /dev/null +++ b/src/pg/uscib-managed-sp/uscib-managed-sp.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { CarnetSequenceModule } from './carnet-sequence/carnet-sequence.module'; +import { RegionModule } from './region/region.module'; +import { SpModule } from './sp/sp.module'; +import { SpContactsModule } from './sp-contacts/sp-contacts.module'; + +@Module({ + imports: [CarnetSequenceModule, RegionModule, SpModule, SpContactsModule] +}) +export class UscibManagedSpModule {} diff --git a/src/pg/user-maintenance/user-maintenance.controller.ts b/src/pg/user-maintenance/user-maintenance.controller.ts new file mode 100644 index 0000000..8baaca2 --- /dev/null +++ b/src/pg/user-maintenance/user-maintenance.controller.ts @@ -0,0 +1,89 @@ +import { Body, Controller, Get, Param, Patch, Post, UseGuards } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { Roles } from 'src/decorators/roles.decorator'; +import { JwtAuthGuard } from 'src/guards/jwt-auth.guard'; +import { RolesGuard } from 'src/guards/roles.guard'; +import { UserMaintenanceService } from './user-maintenance.service'; +import { CreateClientLoginsDTO, CreateSPLoginsDTO, CreateUSCIBLoginsDTO, EMAIL_DTO, SPID_CLIENTID_DTO, SPID_DTO, SPID_EMAIL_DTO, USERID_DTO } from 'src/dto/property.dto'; + +@ApiTags('User Maintenance - PG') +// @UseGuards(JwtAuthGuard, RolesGuard) +@Roles('ca', 'sa', 'ua') +@Controller('2') +export class UserMaintenanceController { + + constructor(private readonly userMaintenanceService: UserMaintenanceService) { } + + // SP_USER_DETAILS + + // @Get('GetUserDetails/:P_USERID') + async GetPreparers(@Param() params: USERID_DTO) { + return await this.userMaintenanceService.GetSPUserDetails(params); + } + + @Patch('LockUserAccount') + async LockUserAccount(@Body() body: SPID_EMAIL_DTO) { + return await this.userMaintenanceService.LockUserAccount(body); + } + + // USCIB_LOGINS + + @Get('GetUSCIBLogins') + @Roles('ua') + async GetUSCIBLogins() { + return await this.userMaintenanceService.GetUSCIBLogins(); + } + + @Post('CreateUSCIBLogins') + @Roles('ua') + async CreateUSCIBLogins(@Body() body: CreateUSCIBLoginsDTO) { + return await this.userMaintenanceService.CreateUSCIBLogins(body); + } + + // SP LOGINS + + @Get('GetSPLogins/:P_SPID') + @Roles('sa') + async GetSPLogins(@Param() params: SPID_DTO) { + return await this.userMaintenanceService.GetSPLogins(params); + } + + @Post('CreateSPLogins') + @Roles('sa') + async CreateSPLogins(@Body() body: CreateSPLoginsDTO) { + return await this.userMaintenanceService.CreateSPLogins(body); + } + + // CLIENT LOGINS + + @Get('GetClientloginsBySPID/:P_SPID') + @Roles('sa') + async GetClientloginsBySPID(@Param() params: SPID_DTO) { + return await this.userMaintenanceService.GetSPLogins(params); + } + + @Get('GetClientloginsByClientID/:P_SPID/:P_CLIENTID') + @Roles('sa') + async GetClientloginsByClientID(@Param() params: SPID_CLIENTID_DTO) { + return await this.userMaintenanceService.GetSPLogins(params); + } + + @Post('CreateClientLogins') + @Roles('sa') + async CreateClientLogins(@Body() body: CreateClientLoginsDTO) { + return await this.userMaintenanceService.CreateClientLogins(body); + } + + // validate email + + @Get('ValidateEmail/:P_EMAILADDR') + async ValidateEmail(@Param() params: EMAIL_DTO) { + return await this.userMaintenanceService.ValidateEmail(params); + } + + // get carnet summary data + @Get('GetCarnetSummaryData/:P_USERID') + GetCarnetSummaryData(@Param() params: USERID_DTO) { + return this.userMaintenanceService.GetCarnetSummaryData(params); + } +} diff --git a/src/pg/user-maintenance/user-maintenance.module.ts b/src/pg/user-maintenance/user-maintenance.module.ts new file mode 100644 index 0000000..0e707d6 --- /dev/null +++ b/src/pg/user-maintenance/user-maintenance.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { UserMaintenanceController } from './user-maintenance.controller'; +import { UserMaintenanceService } from './user-maintenance.service'; + +@Module({ + controllers: [UserMaintenanceController], + providers: [UserMaintenanceService] +}) +export class UserMaintenanceModule {} diff --git a/src/pg/user-maintenance/user-maintenance.service.ts b/src/pg/user-maintenance/user-maintenance.service.ts new file mode 100644 index 0000000..feeb4d1 --- /dev/null +++ b/src/pg/user-maintenance/user-maintenance.service.ts @@ -0,0 +1,479 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { CreateClientLoginsDTO, CreateSPLoginsDTO, CreateUSCIBLoginsDTO, EMAIL_DTO, SPID_CLIENTID_DTO, SPID_DTO, SPID_EMAIL_DTO, USERID_DTO } 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'; +import { InternalServerException } from 'src/exceptions/internalServerError.exception'; +import { AuthService } from 'src/auth/auth.service'; +import { MailTypeDTO } from 'src/auth/auth.dto'; + +@Injectable() +export class UserMaintenanceService { + + private readonly logger = new Logger(UserMaintenanceService.name); + + constructor( + private readonly pgDBService: PgDBService, + // @Inject(forwardRef(() => AuthService)) + private readonly authService: AuthService + ) { } + + async GetSPUserDetails(body: USERID_DTO): Promise { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".userlogin_pkg_createclientlogins($1, $2, $3, $4, $5) + `; + await client.query(callProcQuery, + [ + 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); + + const mailRes = await this.authService.sendMail({ P_TO: body.P_USERID, P_MAIL_TYPE: MailTypeDTO.REGISTER_CLIENT }) + + if (mailRes.statusCode !== 200) { + throw new InternalServerException(); + } + + return { + statusCode: 201, + message: ResponseStatus.clientRegistrationDone, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, UserMaintenanceService.name) + } finally { + releasePgClient(client) + } + } + + async LockUserAccount(body: SPID_EMAIL_DTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".userlogin_pkg_lockuseraccount($1, $2, $3) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_EMAILADDR, + 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.lockedUserDone, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, UserMaintenanceService.name) + } finally { + releasePgClient(client) + } + + } + + // USCIB_LOGINS + + async GetUSCIBLogins() { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".userlogin_pkg_getusciblogins($1) + `; + await client.query(callProcQuery, [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, UserMaintenanceService.name) + } finally { + releasePgClient(client) + } + } + + async CreateUSCIBLogins(body: CreateUSCIBLoginsDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".userlogin_pkg_createusciblogins($1, $2, $3, $4, $5) + `; + await client.query(callProcQuery, + [ + body.P_USERID, + body.P_EMAILADDR, + body.P_LOOKUPCODE, + body.P_ENABLEPASSWORDPOLICY, + 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, UserMaintenanceService.name) + } finally { + releasePgClient(client) + } + } + + // SP LOGINS + + async GetSPLogins(body: SPID_DTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".userlogin_pkg_getsplogins($1, $2) + `; + await client.query(callProcQuery, [body.P_SPID, 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, UserMaintenanceService.name) + } finally { + releasePgClient(client) + } + + } + + async CreateSPLogins(body: CreateSPLoginsDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".userlogin_pkg_createsplogins($1, $2, $3, $4, $5, $6, $7) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_USERID, + body.P_DOMAIN, + body.P_EMAILADDR, + body.P_LOOKUPCODE, + body.P_ENABLEPASSWORDPOLICY, + 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, UserMaintenanceService.name) + } finally { + releasePgClient(client) + } + } + + // CLIENT LOGINS + + async GetClientloginsBySPID(body: SPID_DTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".userlogin_pkg_getclientloginsbyspid($1, $2) + `; + await client.query(callProcQuery, [body.P_SPID, 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, UserMaintenanceService.name) + } finally { + releasePgClient(client) + } + } + + async GetClientloginsByClientID(body: SPID_CLIENTID_DTO) { + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".userlogin_pkg_getclientloginsbyclientid($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, UserMaintenanceService.name) + } finally { + releasePgClient(client) + } + } + + async CreateClientLogins(body: CreateClientLoginsDTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".userlogin_pkg_createclientlogins($1, $2, $3, $4, $5) + `; + await client.query(callProcQuery, + [ + body.P_SPID, + body.P_USERID, + body.P_CLIENTCONTACTID, + body.P_ENABLEPASSWORDPOLICY, + 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); + + const mailRes = await this.authService.sendMail({ P_TO: body.P_USERID, P_MAIL_TYPE: MailTypeDTO.REGISTER_CLIENT }) + + if (mailRes.statusCode !== 200) { + throw new InternalServerException(); + } + + return { + statusCode: 201, + message: ResponseStatus.clientRegistrationDone, + ...fetchResult?.rows?.[0] || {} + }; + + } catch (error) { + if (client) await client.query('ROLLBACK'); + handlePgError(error, UserMaintenanceService.name) + } finally { + releasePgClient(client) + } + } + + // validate email + + async ValidateEmail(body: EMAIL_DTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".userlogin_pkg_validateemail($1, $2) + `; + await client.query(callProcQuery, [body.P_EMAILADDR, 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, UserMaintenanceService.name) + } finally { + releasePgClient(client) + } + + } + + //carnet summary data + async GetCarnetSummaryData(body: USERID_DTO) { + + let client: PoolClient | null = null; + + const cursorName = 'p_cursor'; + + try { + client = await this.pgDBService.getConnection(); + + await client.query('BEGIN'); + + const callProcQuery = ` + CALL "CARNETSYS".userlogin_pkg_getcarnetsummarydata($1, $2) + `; + await client.query(callProcQuery, [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, UserMaintenanceService.name) + } finally { + releasePgClient(client) + } + } +} diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 13f0d2b..10ce65c 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -17,6 +17,16 @@ import { PrintCarnetDTO, PrintGLDTO } from 'src/dto/property.dto'; const logger = new Logger('Helper'); +export enum ResponseStatus { + created = 'Created Successfully', + updated = 'Updated Successfully', + defaultSpContactAdded = "Default contact was added successfully for SP", + inActivate = 'Inactivated Successfully', + reActivate = 'Reactivated Successfully', + clientRegistrationDone = 'Client registration initiated successfully', + lockedUserDone = 'Locked Successfully' +} + export const handleError = (error: any, context: string = 'UnknownService'): never => { if (error instanceof BadRequestException || error instanceof BR) { logger.warn(`[${context}] ${error.message}`); @@ -37,6 +47,32 @@ export const handleError = (error: any, context: string = 'UnknownService'): nev throw new InternalServerErrorException(error.message || 'Internal error'); }; +export const handlePgError = (error: any, context: string = 'UnknownService'): never => { + if (error instanceof BadRequestException || error instanceof BR) { + logger.warn(`[${context}] ${error.message}`); + throw error; + } + logger.error(`[${context}] Unexpected error:`, error.message); + throw new InternalServerErrorException(error.message || 'Internal error'); +} + +export function releasePgClient(client: any) { + if (client && typeof client.release === 'function') { + try { + client.release(); + } catch (err) { + console.error('Error releasing client:', err); + } + } +} + +export const checkPgUserDefinedErrors = (fetchResult: any) => { + if (fetchResult?.rows?.[0]?.errormesg) { + throw new BadRequestException(fetchResult?.rows?.[0]?.errormesg); + } +} + + export const closeOracleDbConnection = async (connection: any, context: string = 'UnknownService'): Promise => { if (connection) { try {