import { Injectable } from '@nestjs/common'; import { ClientContactControlsDTO, CreateClientContactsDTO, CreateClientDataDTO, CreateClientLocationsDTO, GetClientContactByLacationIdDTO, GetClientDTO, GetPreparersDTO, UpdateClientContactsDTO, UpdateClientDTO, UpdateClientLocationsDTO } from 'src/dto/property.dto'; import { checkPgUserDefinedErrors, handlePgError, releasePgClient, ResponseStatus, toUpperCaseKeys } from 'src/utils/helper'; import { PoolClient } from 'pg'; import { PgDBService } from 'src/db/db.service'; @Injectable() export class ManageClientsService { constructor(private readonly pgDBService: PgDBService) { } CreateClientData = async (body: CreateClientDataDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_createclientdata($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) `; await client.query(callProcQuery, [ body.P_SPID, body.P_CLIENTNAME, body.P_LOOKUPCODE, body.P_ADDRESS1, body.P_ADDRESS2, body.P_CITY, body.P_STATE, body.P_ZIP, body.P_COUNTRY, body.P_ISSUINGREGION, body.P_REVENUELOCATION, body.P_USERID, body.P_INDUSTRYTYPE, cursorName ]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return { statusCode: 201, message: ResponseStatus.created, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } }; UpdateClient = async (body: UpdateClientDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_updateclient($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) `; await client.query(callProcQuery, [ body.P_SPID, body.P_CLIENTID, body.P_PREPARERNAME, body.P_ADDRESS1, body.P_ADDRESS2, body.P_CITY, body.P_STATE, body.P_ZIP, body.P_COUNTRY, body.P_REVENUELOCATION, body.P_USERID, body.P_INDUSTRYTYPE, cursorName ]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return { statusCode: 200, message: ResponseStatus.updated, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } }; UpdateClientContacts = async (body: UpdateClientContactsDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_updateclientcontacts($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) `; await client.query(callProcQuery, [ body.P_SPID, body.P_CLIENTCONTACTID, body.P_FIRSTNAME, body.P_LASTNAME, body.P_MIDDLEINITIAL, body.P_TITLE, body.P_PHONENO, body.P_FAXNO, body.P_MOBILENO, body.P_EMAILADDRESS, body.P_USERID, cursorName ]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return { statusCode: 200, message: ResponseStatus.updated, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } }; UpdateClientLocations = async (body: UpdateClientLocationsDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_updateclientlocations($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) `; await client.query(callProcQuery, [ body.P_SPID, body.P_CLIENTLOCATIONID, body.P_LOCATIONNAME, body.P_ADDRESS1, body.P_ADDRESS2, body.P_CITY, body.P_STATE, body.P_ZIP, body.P_COUNTRY, body.P_USERID, cursorName ]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return { statusCode: 200, message: ResponseStatus.updated, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } }; async CreateClientContact(body: CreateClientContactsDTO) { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); // Helper to escape special characters for Postgres composite fields function escapePostgresCompositeField(str: string): string { if (str == null) return ''; return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); } const contactLiterals = body.P_CONTACTSTABLE.map(c => { const fields = [ c.P_FIRSTNAME || '', c.P_LASTNAME || '', c.P_MIDDLEINITIAL || '', c.P_TITLE || '', c.P_EMAILADDRESS || '', c.P_PHONENO || '', c.P_MOBILENO || '', c.P_FAXNO || '', ].map(field => escapePostgresCompositeField(field)).join(','); return `"(${fields})"`; // Composite literal wrapped in double quotes }); const pgArrayLiteral = `{${contactLiterals.join(',')}}`; const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_createclientcontact($1, $2, $3::"CARNETSYS".contactstable[], $4, $5, $6) `; await client.query(callProcQuery, [ body.P_SPID, body.P_LOCATIONID, pgArrayLiteral, body.P_DEFCONTACTFLAG, body.P_USERID, cursorName ]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return { statusCode: 201, message: ResponseStatus.created, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } } SetDefaultClientContacts = async (body: ClientContactControlsDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_setdefaultclientcontacts($1, $2, $3, $4) `; await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTCONTACTID, body.P_USERID, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return { statusCode: 200, message: ResponseStatus.updated, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } } InactivateClientContacts = async (body: ClientContactControlsDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_inactivateclientcontacts($1, $2, $3, $4) `; await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTCONTACTID, body.P_USERID, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return { statusCode: 200, message: ResponseStatus.inActivate, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } } ReactivateClientContacts = async (body: ClientContactControlsDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_reactivateclientcontacts($1, $2, $3, $4) `; await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTCONTACTID, body.P_USERID, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return { statusCode: 200, message: ResponseStatus.reActivate, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } } CreateClientLocation = async (body: CreateClientLocationsDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); function escapePostgresCompositeField(str: string): string { if (str == null) return ''; return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); } const addressLiterals = body.P_CLIENTLOCADDRESSTABLE.map(c => { const fields = [ c.P_NAMEOF || '', c.P_ADDRESS1 || '', c.P_ADDRESS2 || '', c.P_CITY || '', c.P_STATE || '', c.P_ZIP || '', c.P_COUNTRY || '', ].map(field => escapePostgresCompositeField(field)).join(','); return `"(${fields})"`; // Composite literal wrapped in double quotes }); const pgArrayLiteral = `{${addressLiterals.join(',')}}`; const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_updateclientlocations($1, $2, $3::"CARNETSYS".addresstable[], $4, $5) `; await client.query(callProcQuery, [ body.P_SPID, body.P_CLIENTID, pgArrayLiteral, body.P_USERID, cursorName ]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return { statusCode: 201, message: ResponseStatus.created, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } }; GetPreparers = async (body: GetPreparersDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_getpreparers($1, $2, $3, $4, $5, $6, $7) `; await client.query(callProcQuery, [body.P_SPID, body.P_NAME, body.P_LOOKUPCODE, body.P_CITY, body.P_STATE, body.P_STATUS, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return toUpperCaseKeys(fetchResult.rows); } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } }; GetPreparerByClientid = async (body: GetClientDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_getpreparerlocbyclientid($1, $2, $3) `; await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTID, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return toUpperCaseKeys(fetchResult.rows)[0] ?? []; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } }; GetPreparerContactsByClientid = async (body: GetClientDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_getpreparercontactsbyclientid($1, $2, $3) `; await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTID, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return toUpperCaseKeys(fetchResult.rows); } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } }; GetPreparerContactsbyClientLocationID = async (body: GetClientContactByLacationIdDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_getpreparercontactsbyclientlocationid($1, $2, $3) `; await client.query(callProcQuery, [body.P_SPID, body.P_LOCATIONID, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return toUpperCaseKeys(fetchResult.rows); } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } } GetPreparerLocByClientid = async (body: GetClientDTO) => { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".managepreparer_pkg_getpreparerlocbyclientid($1, $2, $3) `; await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTID, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return toUpperCaseKeys(fetchResult.rows); } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, ManageClientsService.name) } finally { releasePgClient(client) } }; }