Compare commits

..

5 Commits

Author SHA1 Message Date
Kallesh B S
75a537aab4 pay 2 2025-08-18 20:34:44 +05:30
Kallesh B S
a61623b0aa The API has been modified as per the instructions provided on 14-08-2025 2025-08-14 12:37:31 +05:30
Kallesh B S
c670266256 new apis 2025-08-13 11:51:24 +05:30
Kallesh B S
f3cbadebd7 pdf generation 2025-08-12 15:27:32 +05:30
Kallesh B S
3646a80800 7Aug Api modifications 2025-08-08 14:59:59 +05:30
35 changed files with 4465 additions and 1542 deletions

2
.gitignore vendored
View File

@ -3,6 +3,8 @@
/node_modules
/build
# pdf
# Logs
logs
*.log

View File

@ -3,6 +3,13 @@
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
"deleteOutDir": true,
"assets": [
{
"include": "../public/**/**",
"outDir": "dist/public"
}
],
"watchAssets": true
}
}
}

3370
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -43,6 +43,9 @@
"oracledb": "^6.7.2",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"pdf-lib": "^1.17.1",
"pdf-merger-js": "^5.1.2",
"pdfkit": "^0.17.1",
"pg": "^8.13.3",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -6,11 +6,12 @@ import { OriginCheckMiddleware } from './middleware/OriginCheck.middleware';
import { ReqBodyKeysToUppercaseMiddleware } from './middleware/reqBodyKeysToUppercase.middleware';
import { ConfigModule } from '@nestjs/config';
import { MailModule } from './mail/mail.module';
import { PaypalModule } from './paypal/paypal.module';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
AuthModule, DbModule, OracleModule, MailModule
AuthModule, DbModule, OracleModule, MailModule, PaypalModule
],
controllers: [],
providers: [],

View File

@ -32,6 +32,20 @@ export class CARNETSTATUS_DTO {
P_CARNETSTATUS: string;
}
export class CARNETNO_DTO {
@ApiProperty({ required: true })
@IsString()
@IsDefined({ message: 'Property P_CARNETNO is required' })
P_CARNETNO: string;
}
export class ORDERID_DTO {
@ApiProperty({ required: true })
@IsString()
@IsDefined({ message: 'Property P_ORDERID is required' })
P_ORDERID: string;
}
export class HEADERID_DTO {
@ApiProperty({ required: true })
@Max(999999999, {
@ -52,6 +66,40 @@ export class APPLICATIONNAME_DTO {
P_APPLICATIONNAME: string;
}
export class GOODS_PORT_DTO {
@ApiProperty({ required: true })
@IsString({ message: 'Property P_GOODSPORT must be a string' })
@IsDefined({ message: 'Property P_GOODSPORT is required' })
P_GOODSPORT: string;
}
export class GOODS_COUNTRY_DTO {
@ApiProperty({ required: true })
@IsString({ message: 'Property P_GOODSCOUNTRY must be a string' })
@IsDefined({ message: 'Property P_GOODSCOUNTRY is required' })
P_GOODSCOUNTRY: string;
}
export class REASON_CODE_DTO {
@ApiProperty({ required: true })
@IsString({ message: 'Property P_REASONCODE must be a string' })
@IsDefined({ message: 'Property P_REASONCODE is required' })
P_REASONCODE: string;
}
export class EXTENSION_PERIOD_DTO {
@ApiProperty({ required: true })
@Max(999999999, {
message: 'Property P_EXTENSIONPERIOD must not exceed 999999999',
})
@Min(0, { message: 'Property P_EXTENSIONPERIOD must be at least 0 or more' })
@IsInt({ message: 'Property P_EXTENSIONPERIOD allows only whole numbers' })
@IsNumber({}, { message: 'Property P_EXTENSIONPERIOD must be a number' })
@Transform(({ value }) => Number(value))
@IsDefined({ message: 'Property P_EXTENSIONPERIOD is required' })
P_EXTENSIONPERIOD: number;
}
export class ORDERTYPE_DTO {
@ApiProperty({ required: true })
@IsString({ message: 'Property P_ORDERTYPE must be a string' })
@ -170,6 +218,63 @@ export class GLTABLE_ROW_DTO {
GOODSORIGINCOUNTRY: string;
}
export class GLTABLE_ROW_ADD_DTO {
@ApiProperty({ required: false })
@Max(99999, { message: 'Property ITEMNO must not exceed 99999' })
@Min(0, { message: 'Property ITEMNO must be at least 0 or more' })
@IsInt({ message: 'Property ITEMNO allows only whole numbers' })
@Transform(({ value }) => {
if (value === undefined || value === null || value === '') return 0;
return Number(value);
})
@IsNumber({}, { message: 'Property ITEMNO must be a number' })
@IsOptional()
ITEMNO: number = 0
@ApiProperty({ required: true })
@MaxLength(200, { message: 'Property ITEMDESCRIPTION must not exceed 200 characters' })
@IsString({ message: 'Property ITEMDESCRIPTION must be a string' })
@IsDefined({ message: 'Property ITEMDESCRIPTION is required' })
ITEMDESCRIPTION: string;
@ApiProperty({ required: true })
@Max(999999999.99, { message: 'Property ITEMVALUE must not exceed 999999999.99' })
@Min(0, { message: 'Property ITEMVALUE must be at least 0 or more' })
@Transform(({ value }) => Number(value))
@IsNumber({ maxDecimalPlaces: 2 }, { message: 'Property ITEMVALUE must be a number' })
@IsDefined({ message: 'Property ITEMVALUE is required' })
ITEMVALUE: number;
@ApiProperty({ required: true })
@Max(99999, { message: 'Property NOOFPIECES must not exceed 99999' })
@Min(0, { message: 'Property NOOFPIECES must be at least 0 or more' })
@IsInt({ message: 'Property NOOFPIECES allows only whole numbers' })
@Transform(({ value }) => Number(value))
@IsNumber({}, { message: 'Property NOOFPIECES must be a number' })
@IsDefined({ message: 'Property NOOFPIECES is required' })
NOOFPIECES: number;
@ApiProperty({ required: true })
@Max(99999.9999, { message: 'Property ITEMVALUE must not exceed 999999999.99' })
@Min(0, { message: 'Property ITEMVALUE must be at least 0 or more' })
@Transform(({ value }) => Number(value))
@IsNumber({ maxDecimalPlaces: 2 }, { message: 'Property ITEMVALUE must be a number' })
@IsDefined({ message: 'Property ITEMVALUE is required' })
ITEMWEIGHT: number;
@ApiProperty({ required: true })
@MaxLength(10, { message: 'Property ITEMWEIGHTUOM must not exceed 10 characters' })
@IsString({ message: 'Property ITEMWEIGHTUOM must be a string' })
@IsDefined({ message: 'Property ITEMWEIGHTUOM is required' })
ITEMWEIGHTUOM: string;
@ApiProperty({ required: true })
@MaxLength(2, { message: 'Property GOODSORIGINCOUNTRY must not exceed 2 characters' })
@IsString({ message: 'Property GOODSORIGINCOUNTRY must be a string' })
@IsDefined({ message: 'Property GOODSORIGINCOUNTRY is required' })
GOODSORIGINCOUNTRY: string;
}
export class GLTABLE_DTO {
@ApiProperty({ required: true, type: () => [GLTABLE_ROW_DTO] })
@Type(() => GLTABLE_ROW_DTO)
@ -179,7 +284,16 @@ export class GLTABLE_DTO {
P_GLTABLE: GLTABLE_ROW_DTO[];
}
export class ITEMNO_DTO{
export class GLTABLE_ITEMNO_OPTIONAL_DTO {
@ApiProperty({ required: true, type: () => [GLTABLE_ROW_ADD_DTO] })
@Type(() => GLTABLE_ROW_ADD_DTO)
@ValidateNested({ each: true })
@IsArray({ message: 'Property P_GLTABLE allows only array type' })
@IsDefined({ message: 'Property P_GLTABLE is required' })
P_GLTABLE: GLTABLE_ROW_ADD_DTO[];
}
export class ITEMNO_DTO {
@ApiProperty({ required: true })
@Max(99999, { message: 'Property ITEMNO must not exceed 99999' })
@Min(0, { message: 'Property ITEMNO must be at least 0 or more' })
@ -190,7 +304,7 @@ export class ITEMNO_DTO{
P_ITEMNO: number;
}
export class SHIPCONTACTID_DTO{
export class SHIPCONTACTID_DTO {
@ApiProperty({ required: true })
@Max(99999, { message: 'Property P_SHIPCONTACTID must not exceed 99999' })
@Min(0, { message: 'Property P_SHIPCONTACTID must be at least 0 or more' })

View File

@ -1,12 +1,12 @@
import { IntersectionType, PartialType } from "@nestjs/swagger";
import {
APPLICATIONNAME_DTO, AUTHREP_DTO, AUTO_FLAG_DTO, COMMERCIAL_SAMPLE_FLAG_DTO,
APPLICATIONNAME_DTO, AUTHREP_DTO, AUTO_FLAG_DTO, CARNETNO_DTO, COMMERCIAL_SAMPLE_FLAG_DTO,
COUNTRYTABLE_DTO, CUSTCOURIERNO_DTO, DELIVERYMETHOD_DTO, DELIVERYTYPE_DTO,
EXIBITIONS_FAIR_FLAG_DTO, FORMOFSECURITY_DTO, GLTABLE_DTO, HEADERID_DTO,
HORSE_FLAG_DTO, INSPROTECTION_DTO, ITEMNO_DTO, LDIPROTECTION_DTO, ORDERTYPE_DTO, PAYMENTMETHOD_DTO,
EXIBITIONS_FAIR_FLAG_DTO, EXTENSION_PERIOD_DTO, FORMOFSECURITY_DTO, GLTABLE_DTO, GLTABLE_ITEMNO_OPTIONAL_DTO, GOODS_COUNTRY_DTO, GOODS_PORT_DTO, HEADERID_DTO,
HORSE_FLAG_DTO, INSPROTECTION_DTO, ITEMNO_DTO, LDIPROTECTION_DTO, ORDERID_DTO, ORDERTYPE_DTO, PAYMENTMETHOD_DTO,
PRINTGL_DTO,
PROF_EQUIPMENT_FLAG_DTO, REFNO_DTO, SHIPADDRID_DTO, SHIPCONTACTID_DTO, SHIPNAME_DTO, SHIPTOTYPE_DTO, USSETS_DTO
PROF_EQUIPMENT_FLAG_DTO, REASON_CODE_DTO, REFNO_DTO, SHIPADDRID_DTO, SHIPCONTACTID_DTO, SHIPNAME_DTO, SHIPTOTYPE_DTO, USSETS_DTO
} from "./carnet-application-property.dto";
import { ADDRESS1_DTO, ADDRESS2_DTO, CITY_DTO, COUNTRY_DTO, NOTES_DTO, SPID_DTO, STATE_DTO, USERID_DTO, ZIP_DTO } from "../uscib-managed-sp/sp/sp-property.dto";
@ -52,10 +52,23 @@ export class TransmitApplicationtoProcessDTO extends IntersectionType(
) { }
// processing [ PROCESSINGCENTER_PKG ]
export class CopyCarnetDTO extends (IntersectionType(USERID_DTO, HEADERID_DTO, APPLICATIONNAME_DTO)) { }
export class CarnetProcessingCenterDTO extends (IntersectionType(USERID_DTO, HEADERID_DTO)) { }
export class CarnetProcessingCenterDTO2 extends (IntersectionType(USERID_DTO, CARNETNO_DTO)) { }
export class GetExtendedSectionDTO extends (IntersectionType(SPID_DTO, HEADERID_DTO)) { }
export class SaveExtensionApplicationDTO extends (IntersectionType(
USERID_DTO,
SPID_DTO,
HEADERID_DTO,
GOODS_PORT_DTO,
GOODS_COUNTRY_DTO,
REASON_CODE_DTO,
EXTENSION_PERIOD_DTO
)) { }
export class PrintCarnetDTO extends (IntersectionType(SPID_DTO, HEADERID_DTO, PRINTGL_DTO)){}
export class PrintCarnetDTO extends (IntersectionType(SPID_DTO, HEADERID_DTO, PRINTGL_DTO)) { }
export class PrintGLDTO extends (IntersectionType(SPID_DTO, HEADERID_DTO)) { }
export class CapturePaymentDTO extends (IntersectionType(ORDERID_DTO)) { }
export class CreateApplicationDTO extends IntersectionType(
SPID_DTO, CLIENTID_DTO, LOCATIONID_DTO, USERID_DTO, APPLICATIONNAME_DTO,
@ -73,6 +86,10 @@ export class UpdateExpGoodsAuthRepDTO extends IntersectionType(
) { }
export class AddGenerallistItemsDTO extends IntersectionType(
HEADERID_DTO, GLTABLE_ITEMNO_OPTIONAL_DTO, USERID_DTO
) { }
export class EditGenerallistItemsDTO extends IntersectionType(
HEADERID_DTO, GLTABLE_DTO, USERID_DTO
) { }

View File

@ -0,0 +1,19 @@
import { HttpException, HttpStatus } from '@nestjs/common';
export class NotFoundException extends HttpException {
constructor(
message = 'Not Found',
// errorCode = 'INTERNAL_ERROR',
// data: any = null,
) {
super(
{
statusCode: HttpStatus.NOT_FOUND ,
message,
// errorCode,
// data,
},
HttpStatus.NOT_FOUND,
);
}
}

View File

@ -1,4 +1,4 @@
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, UseGuards } from '@nestjs/common';
import { BadRequestException, Body, Controller, Delete, Get, HttpCode, Param, Patch, Post, Put, Res, StreamableFile, UseGuards } from '@nestjs/common';
import { CarnetApplicationService } from './carnet-application.service';
import { ApiTags } from '@nestjs/swagger';
@ -7,13 +7,20 @@ import {
AddCountriesDTO,
AddGenerallistItemsDTO,
CA_UpdateHolderDTO,
CarnetProcessingCenterDTO, CreateApplicationDTO, DeleteGenerallistItemsDTO, GetCarnetControlCenterDTO, PrintCarnetDTO, SaveCarnetApplicationDTO, TransmitApplicationtoProcessDTO,
CapturePaymentDTO,
CarnetProcessingCenterDTO, CarnetProcessingCenterDTO2, CopyCarnetDTO, CreateApplicationDTO, DeleteGenerallistItemsDTO, EditGenerallistItemsDTO, GetCarnetControlCenterDTO, GetExtendedSectionDTO, PrintCarnetDTO, PrintGLDTO, SaveCarnetApplicationDTO, SaveExtensionApplicationDTO, TransmitApplicationtoProcessDTO,
UpdateExpGoodsAuthRepDTO,
UpdateShippingDetailsDTO
} 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';
import { Response } from 'express';
import { join } from 'path';
import { createReadStream } from 'fs';
import { deleteFilesAsync, generateFinalPDF, replaceSlashWithDash } from 'src/utils/helper';
import { BadRequestException as BR } from 'src/exceptions/badRequest.exception';
import { InternalServerException } from 'src/exceptions/internalServerError.exception';
@ApiTags('Carnet Application - Oracle')
@ -64,7 +71,7 @@ export class CarnetApplicationController {
}
@Put('EditGenerallistItems')
EditGenerallistItems(@Body() body: AddGenerallistItemsDTO) {
EditGenerallistItems(@Body() body: EditGenerallistItemsDTO) {
return this.carnetApplicationService.EditGenerallistItems(body);
}
@ -101,12 +108,38 @@ export class CarnetApplicationController {
return this.carnetApplicationService.VoidCarnet(body);
}
@Patch('CopyCarnet')
CopyCarnet(@Body() body: CopyCarnetDTO) {
return this.carnetApplicationService.CopyCarnet(body);
}
@Patch('DuplicateCarnet')
@Roles('ca')
DuplicateCarnet(@Body() body: CarnetProcessingCenterDTO) {
DuplicateCarnet(@Body() body: CarnetProcessingCenterDTO2) {
return this.carnetApplicationService.DuplicateCarnet(body);
}
@Patch('AddlSets')
AddlSets(@Body() body: CarnetProcessingCenterDTO2) {
return this.carnetApplicationService.AddlSets(body);
}
@Patch('ExtendCarnet')
ExtendCarnet(@Body() body: CarnetProcessingCenterDTO2) {
return this.carnetApplicationService.ExtendCarnet(body);
}
@Get('GetExtendedSection/:P_SPID/:P_HEADERID')
GetExtendedSection(@Param() body: GetExtendedSectionDTO) {
return this.carnetApplicationService.GetExtendedSection(body);
}
@Post('SaveExtensionApplication')
@HttpCode(200)
SaveExtensionApplication(@Body() body: SaveExtensionApplicationDTO) {
return this.carnetApplicationService.SaveExtensionApplication(body);
}
@Patch('CloseCarnet')
@Roles('sa')
CloseCarnet(@Body() body: CarnetProcessingCenterDTO) {
@ -152,8 +185,106 @@ export class CarnetApplicationController {
// [PRINT_PKG]
@Post('PrintCarnet')
PrintCarnet(@Body() body: PrintCarnetDTO) {
return this.carnetApplicationService.PrintCarnet(body);
@HttpCode(200)
async PrintCarnet(@Body() body: PrintCarnetDTO, @Res({ passthrough: true }) res: Response) {
try {
const { finalArray, carnetData }: any = await this.carnetApplicationService.PrintCarnet(body);
// const filterCarnetData = finalArray.filter(item => item !== '2GeneralList.pdf')
let filesArray = [`${replaceSlashWithDash(carnetData.carnetNo)}p1.pdf`, `${replaceSlashWithDash(carnetData.carnetNo)}p2.pdf`];
// await generateFinalPDF([...filesArray, '2GeneralList.pdf', ...carnetData], 'carnet.pdf');
await generateFinalPDF([...filesArray, ...finalArray, '13LastSheetP3.pdf', '13LastSheetP4.pdf'], `${replaceSlashWithDash(carnetData.carnetNo)}carnet.pdf`);
const fileName = `${replaceSlashWithDash(carnetData.carnetNo)}carnet.pdf`;
res.set({
'Content-Type': 'application/pdf',
'Content-Disposition': `attachment; filename="${fileName}"`,
});
const filePath = join(process.cwd(), 'dist/public/carnet-pdf', fileName); //server
// const filePath = join(process.cwd(), 'public/carnet-pdf', fileName); //local
console.log(filePath);
// console.log(filePath);
const stream = createReadStream(filePath);
// Clean up files after response finishes streaming
res.on('finish', async () => {
await deleteFilesAsync([...filesArray, ...finalArray.filter(x => x !== `${replaceSlashWithDash(carnetData.carnetNo)}p2.pdf`), fileName]);
});
return new StreamableFile(stream);
} catch (error) {
if (error instanceof BadRequestException || error instanceof BR) {
throw new BadRequestException("Download failed please check the details")
}
else {
throw new InternalServerException("Error while downloading");
}
}
}
@Post('PrintGL')
@HttpCode(200)
async PrintGL(@Body() body: PrintGLDTO, @Res({ passthrough: true }) res: Response) {
try {
const { finalArray, carnetData }: any = await this.carnetApplicationService.PrintGL(body);
let filesArray = [`${body.P_HEADERID}p2.pdf`];
// await generateFinalPDF([...filesArray, '2GeneralList.pdf', ...carnetData], 'carnet.pdf');
await generateFinalPDF([...filesArray, ...finalArray], `${body.P_HEADERID}-GL.pdf`);
const fileName = `${body.P_HEADERID}-GL.pdf`;
res.set({
'Content-Type': 'application/pdf',
'Content-Disposition': `attachment; filename="${fileName}"`,
});
const filePath = join(process.cwd(), 'dist/public/carnet-pdf', fileName); //server
// const filePath = join(process.cwd(), 'public/carnet-pdf', fileName); //local
// console.log(filePath);
// console.log(filePath);
const stream = createReadStream(filePath);
// Clean up files after response finishes streaming
res.on('finish', async () => {
await deleteFilesAsync([...filesArray, ...finalArray, fileName]);
});
return new StreamableFile(stream);
} catch (error) {
if (error instanceof BadRequestException || error instanceof BR) {
throw new BadRequestException("Download failed please check the details")
}
else {
throw new InternalServerException("Error while downloading");
}
}
}
//[payment]
@Post('InitiatePayment')
@UseGuards()
async InitiatePayment() {
return this.carnetApplicationService.InitiatePayment();
}
@Post('CompletePayment')
@HttpCode(200)
@UseGuards()
async CapturePayment(@Body() body: CapturePaymentDTO) {
return this.carnetApplicationService.CapturePayment(body);
}
}

View File

@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { OracleDBService } from 'src/db/db.service';
import * as oracledb from 'oracledb'
import { InternalServerException } from 'src/exceptions/internalServerError.exception';
import { closeOracleDbConnection, fetchCursor, handleError, setEmptyStringsToNull } from 'src/utils/helper';
import { closeOracleDbConnection, deleteFilesAsync, fetchCursor, fnCounterFoil, fnVochers, generateFinalPDF, generateGL, generateGL1, generateGreenCoverPDF, handleError, pdfCarnetData, pdfGLData, replaceSlashWithDash, setEmptyStringsToNull, tnVochers, tsCounterFoil, usCounterFoil } from 'src/utils/helper';
import {
CarnetProcessingCenterDTO, SaveCarnetApplicationDTO, TransmitApplicationtoProcessDTO,
@ -14,10 +14,20 @@ import {
CA_UpdateHolderDTO,
GetCarnetControlCenterDTO,
DeleteGenerallistItemsDTO,
PrintCarnetDTO
PrintCarnetDTO,
PrintGLDTO,
YON,
CopyCarnetDTO,
GetExtendedSectionDTO,
SaveExtensionApplicationDTO,
CarnetProcessingCenterDTO2,
CapturePaymentDTO
} from 'src/dto/property.dto';
import { OracleService } from '../oracle.service';
import { BadRequestException } from 'src/exceptions/badRequest.exception';
import axios, { AxiosError, AxiosRequestConfig } from 'axios';
import { PaypalService } from 'src/paypal/paypal.service';
import { NotFoundException } from 'src/exceptions/notFound.exception';
@Injectable()
export class CarnetApplicationService {
@ -26,7 +36,8 @@ export class CarnetApplicationService {
constructor(
private readonly oracleDBService: OracleDBService,
private readonly oracleService: OracleService
private readonly oracleService: OracleService,
private readonly payPalService: PaypalService
) { }
// [ CARNETAPPLICATION_PKG ]
@ -325,7 +336,7 @@ export class CarnetApplicationService {
try {
connection = await this.oracleDBService.getConnection();
const GLTABLE_INSTANCE = await this.oracleService.get_GL_TABLE_INSTANCE(body);
const GLTABLE_INSTANCE = await this.oracleService.get_GL_TABLE_OPTIONAL_ITEMNO_INSTANCE(body);
const result = await connection.execute(
`BEGIN
@ -748,7 +759,51 @@ export class CarnetApplicationService {
await closeOracleDbConnection(connection, CarnetApplicationService.name)
}
}
async DuplicateCarnet(body: CarnetProcessingCenterDTO) {
async CopyCarnet(body: CopyCarnetDTO) {
let connection;
try {
connection = await this.oracleDBService.getConnection();
const result = await connection.execute(
`BEGIN
PROCESSINGCENTER_PKG.CopyCarnet(
:P_USERID, :P_HEADERID, :P_APPLICATIONNAME, :P_CURSOR
);
END;`,
{
P_USERID: { val: body.P_USERID, type: oracledb.DB_TYPE_NVARCHAR },
P_HEADERID: { val: body.P_HEADERID, type: oracledb.DB_TYPE_NUMBER },
P_APPLICATIONNAME: { val: body.P_APPLICATIONNAME, type: oracledb.DB_TYPE_NVARCHAR },
P_CURSOR: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR },
// P_CURSOR: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{ outFormat: oracledb.OUT_FORMAT_OBJECT }
);
await connection.commit();
const outBinds = result.outBinds;
if (!outBinds?.P_CURSOR) {
this.logger.error('One or more expected cursors are missing from stored procedure output.');
throw new InternalServerException("Incomplete data received from the database.");
}
const fres: any = await fetchCursor(outBinds.P_CURSOR, CarnetApplicationService.name);
if (fres.length > 0 && fres[0].ERRORMESG) {
this.logger.warn(fres[0].ERRORMESG);
throw new BadRequestException(fres[0].ERRORMESG)
}
return { statusCode: 200, message: "Copied Successfully", ...fres[0] };
} catch (error) {
handleError(error, CarnetApplicationService.name)
} finally {
await closeOracleDbConnection(connection, CarnetApplicationService.name)
}
}
async DuplicateCarnet(body: CarnetProcessingCenterDTO2) {
let connection;
try {
connection = await this.oracleDBService.getConnection();
@ -756,12 +811,12 @@ export class CarnetApplicationService {
const result = await connection.execute(
`BEGIN
PROCESSINGCENTER_PKG.DuplicateCarnet(
:P_USERID, :P_HEADERID, :P_CURSOR
:P_USERID, :P_CARNETNO, :P_CURSOR
);
END;`,
{
P_USERID: { val: body.P_USERID, type: oracledb.DB_TYPE_NVARCHAR },
P_HEADERID: { val: body.P_HEADERID, type: oracledb.DB_TYPE_NUMBER },
P_CARNETNO: { val: body.P_CARNETNO, type: oracledb.DB_TYPE_NVARCHAR },
P_CURSOR: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR },
// P_CURSOR: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
@ -790,6 +845,181 @@ export class CarnetApplicationService {
await closeOracleDbConnection(connection, CarnetApplicationService.name)
}
}
async AddlSets(body: CarnetProcessingCenterDTO2) {
let connection;
try {
connection = await this.oracleDBService.getConnection();
const result = await connection.execute(
`BEGIN
PROCESSINGCENTER_PKG.AddlSets(
:P_USERID, :P_CARNETNO, :P_CURSOR
);
END;`,
{
P_USERID: { val: body.P_USERID, type: oracledb.DB_TYPE_NVARCHAR },
P_CARNETNO: { val: body.P_CARNETNO, type: oracledb.DB_TYPE_NVARCHAR },
P_CURSOR: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR },
// P_CURSOR: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{ outFormat: oracledb.OUT_FORMAT_OBJECT }
);
await connection.commit();
const outBinds = result.outBinds;
if (!outBinds?.P_CURSOR) {
this.logger.error('One or more expected cursors are missing from stored procedure output.');
throw new InternalServerException("Incomplete data received from the database.");
}
const fres: any = await fetchCursor(outBinds.P_CURSOR, CarnetApplicationService.name);
if (fres.length > 0 && fres[0].ERRORMESG) {
this.logger.warn(fres[0].ERRORMESG);
throw new BadRequestException(fres[0].ERRORMESG)
}
return { statusCode: 200, message: "Additional sets completed", ...fres[0] };
} catch (error) {
handleError(error, CarnetApplicationService.name)
} finally {
await closeOracleDbConnection(connection, CarnetApplicationService.name)
}
}
async ExtendCarnet(body: CarnetProcessingCenterDTO2) {
let connection;
try {
connection = await this.oracleDBService.getConnection();
const result = await connection.execute(
`BEGIN
PROCESSINGCENTER_PKG.ExtendCarnet(
:P_USERID, :P_CARNETNO, :P_CURSOR
);
END;`,
{
P_USERID: { val: body.P_USERID, type: oracledb.DB_TYPE_NVARCHAR },
P_CARNETNO: { val: body.P_CARNETNO, type: oracledb.DB_TYPE_NVARCHAR },
P_CURSOR: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR },
// P_CURSOR: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{ outFormat: oracledb.OUT_FORMAT_OBJECT }
);
await connection.commit();
const outBinds = result.outBinds;
if (!outBinds?.P_CURSOR) {
this.logger.error('One or more expected cursors are missing from stored procedure output.');
throw new InternalServerException("Incomplete data received from the database.");
}
const fres: any = await fetchCursor(outBinds.P_CURSOR, CarnetApplicationService.name);
if (fres.length > 0 && fres[0].ERRORMESG) {
this.logger.warn(fres[0].ERRORMESG);
throw new BadRequestException(fres[0].ERRORMESG)
}
return { statusCode: 200, message: "Extended successfully", ...fres[0] };
} catch (error) {
handleError(error, CarnetApplicationService.name)
} finally {
await closeOracleDbConnection(connection, CarnetApplicationService.name)
}
}
async GetExtendedSection(body: GetExtendedSectionDTO) {
let connection;
try {
connection = await this.oracleDBService.getConnection();
const result = await connection.execute(
`BEGIN
PROCESSINGCENTER_PKG.GetExtendedSection(
:P_SPID, :P_HEADERID, :P_CURSOR
);
END;`,
{
P_SPID: { val: body.P_SPID, type: oracledb.DB_TYPE_NUMBER },
P_HEADERID: { val: body.P_HEADERID, type: oracledb.DB_TYPE_NUMBER },
P_CURSOR: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR },
// P_CURSOR: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{ outFormat: oracledb.OUT_FORMAT_OBJECT }
);
await connection.commit();
const outBinds = result.outBinds;
if (!outBinds?.P_CURSOR) {
this.logger.error('One or more expected cursors are missing from stored procedure output.');
throw new InternalServerException("Incomplete data received from the database.");
}
const fres: any = await fetchCursor(outBinds.P_CURSOR, CarnetApplicationService.name);
if (fres.length > 0 && fres[0].ERRORMESG) {
this.logger.warn(fres[0].ERRORMESG);
throw new BadRequestException(fres[0].ERRORMESG)
}
// return { statusCode: 200, message: "Extended successfully", ...fres[0] };
return fres;
} catch (error) {
handleError(error, CarnetApplicationService.name)
} finally {
await closeOracleDbConnection(connection, CarnetApplicationService.name)
}
}
async SaveExtensionApplication(body: SaveExtensionApplicationDTO) {
let connection;
try {
connection = await this.oracleDBService.getConnection();
const result = await connection.execute(
`BEGIN
PROCESSINGCENTER_PKG.SaveExtensionApplication(
:P_USERID, :P_SPID, :P_HEADERID, :P_GOODSPORT, :P_GOODSCOUNTRY, :P_REASONCODE, :P_EXTENSIONPERIOD, :P_CURSOR
);
END;`,
{
P_USERID: { val: body.P_USERID, type: oracledb.DB_TYPE_NVARCHAR },
P_SPID: { val: body.P_SPID, type: oracledb.DB_TYPE_NUMBER },
P_HEADERID: { val: body.P_HEADERID, type: oracledb.DB_TYPE_NUMBER },
P_GOODSPORT: { val: body.P_GOODSPORT, type: oracledb.DB_TYPE_NVARCHAR },
P_GOODSCOUNTRY: { val: body.P_GOODSCOUNTRY, type: oracledb.DB_TYPE_NVARCHAR },
P_REASONCODE: { val: body.P_REASONCODE, type: oracledb.DB_TYPE_NVARCHAR },
P_EXTENSIONPERIOD: { val: body.P_EXTENSIONPERIOD, type: oracledb.DB_TYPE_NUMBER },
P_CURSOR: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR },
// P_CURSOR: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{ outFormat: oracledb.OUT_FORMAT_OBJECT }
);
await connection.commit();
const outBinds = result.outBinds;
if (!outBinds?.P_CURSOR) {
this.logger.error('One or more expected cursors are missing from stored procedure output.');
throw new InternalServerException("Incomplete data received from the database.");
}
const fres: any = await fetchCursor(outBinds.P_CURSOR, CarnetApplicationService.name);
if (fres.length > 0 && fres[0].ERRORMESG) {
this.logger.warn(fres[0].ERRORMESG);
throw new BadRequestException(fres[0].ERRORMESG)
}
return { statusCode: 200, message: "Saved successfully", ...fres[0] };
} catch (error) {
handleError(error, CarnetApplicationService.name)
} finally {
await closeOracleDbConnection(connection, CarnetApplicationService.name)
}
}
async CloseCarnet(body: CarnetProcessingCenterDTO) {
let connection;
try {
@ -1114,7 +1344,8 @@ export class CarnetApplicationService {
}
// [PRINT_PKG]
async PrintCarnet(body: PrintCarnetDTO) {
async getPrintingData(body: PrintCarnetDTO) {
let connection;
try {
connection = await this.oracleDBService.getConnection();
@ -1147,12 +1378,19 @@ export class CarnetApplicationService {
const fres: any = await fetchCursor(outBinds.P_CARNETDATACURSOR, CarnetApplicationService.name);
const fres1: any = await fetchCursor(outBinds.P_GLDATACURSOR, CarnetApplicationService.name);
if (fres.length === 0 || fres1.length === 0) {
throw new BadRequestException("Print failed please check the submitted details");
}
if (fres.length > 0 && fres[0].ERRORMESG) {
this.logger.warn(fres[0].ERRORMESG);
throw new BadRequestException(fres[0].ERRORMESG)
}
return { P_CARNETDATACURSOR: fres, P_GLDATACURSOR: fres1 };
// console.log(fres, "\n", "--------------------", fres1.length > 0 ? fres[0] : []);
return { fres: fres, fres1: fres1 }
} catch (error) {
handleError(error, CarnetApplicationService.name)
} finally {
@ -1160,4 +1398,310 @@ export class CarnetApplicationService {
}
}
async PrintCarnet(body: PrintCarnetDTO) {
try {
const { fres, fres1 }: any = await this.getPrintingData(body);
if (body.P_PRINTGL === 'Y') {
if (fres.length === 0 || !fres[0].CARNETNO || fres1.length === 0) {
throw new BadRequestException("Print failed please check the submitted details");
}
}
else {
if (fres.length === 0 || !fres[0].CARNETNO) {
throw new BadRequestException("Print failed please check the submitted details");
}
}
if (fres.length > 0 && fres[0].ERRORMESG) {
this.logger.warn(fres[0].ERRORMESG);
throw new BadRequestException(fres[0].ERRORMESG)
}
try {
const glData: pdfGLData[] = fres1.map((x: any) => {
return {
itemNo: x.ITEMNO,
description: x.ITEMDESCRIPTION,
noOfPieces: x.NOOFPIECES,
weight: x.WEIGHT,
itemValue: x.ITEMVALUE,
countryOfOrigin: x.GOODSORIGINCOUNTRY
};
});
const carnetData: pdfCarnetData = {
carnetNo: fres[0].CARNETNO ?? "",
ISSUEDBY: fres[0].ISSUEDBY ?? "",
ISSUEDATE: fres[0].ISSUEDATE ?? "",
EXPDATE: fres[0].EXPDATE ?? "",
AUTHREP: fres[0].AUTHREP ?? "",
NOOFUSSETS: fres[0].NOOFUSSETS ?? 0,
NOOFFOREIGNSETS: fres[0].NOOFFOREIGNSETS ?? 0,
NOOFTRANSITSETS: fres[0].NOOFTRANSITSETS ?? 0,
PRINTGOODSTOBEEXPORTED: fres[0].PRINTGOODSTOBEEXPORTED ?? "",
HOLDERDATATOPRINT: fres[0].HOLDERDATATOPRINT ?? "",
CONTINUATIONSHEETS: fres[0].CONTINUATIONSHEETS ?? 0,
NEXTUSCFNO: fres[0].NEXTUSCFNO ?? 0,
NEXTFOREIGNCFNO: fres[0].NEXTFOREIGNCFNO ?? 0,
NEXTTRANSITCFNO: fres[0].NEXTTRANSITCFNO ?? 0,
contPageNo: 0
}
const p1Status = await generateGreenCoverPDF(carnetData);
let p2Status: any = "";
if (body.P_PRINTGL === 'Y') {
p2Status = await generateGL(glData, carnetData, body);
// console.log("-------- p2 --------", p2Status);
// console.log(typeof p2Status.batch, p2Status.batch);
if (p2Status.batch % 2 === 0) {
await generateFinalPDF([...p2Status.fileArray, '2GeneralListVOID.pdf'], `${replaceSlashWithDash(carnetData.carnetNo)}p2.pdf`)
await deleteFilesAsync([...p2Status.fileArray])
}
else {
await generateFinalPDF([...p2Status.fileArray], `${replaceSlashWithDash(carnetData.carnetNo)}p2.pdf`)
await deleteFilesAsync([...p2Status.fileArray])
}
} else {
p2Status = await generateGL1(carnetData);
if (p2Status === 'p2 done') {
await generateFinalPDF([`${replaceSlashWithDash(carnetData.carnetNo)}p2.pdf`, '2GeneralListVOID.pdf'], `${replaceSlashWithDash(carnetData.carnetNo)}p2.pdf`)
}
}
const p3Status = await usCounterFoil(carnetData);
const p4Status = await fnCounterFoil(carnetData);
const p5Status = await tsCounterFoil(carnetData);
const p6Status = await fnVochers(carnetData, body);
const p7Status = await tnVochers(carnetData, body);
const finalArray = [
...p3Status,
...p4Status,
...p5Status,
...p6Status,
...p7Status
]
return { finalArray, carnetData }
} catch (error) {
throw new InternalServerException(error.message)
}
} catch (error) {
handleError(error, CarnetApplicationService.name)
}
}
async PrintGL(body: PrintGLDTO) {
let newBody: PrintCarnetDTO = { ...body, P_PRINTGL: YON.YES }
try {
const { fres, fres1 }: any = await this.getPrintingData(newBody);
if (fres.length === 0 || fres1.length === 0) {
throw new BadRequestException("Print failed please check the submitted details");
}
if (fres.length > 0 && fres[0].ERRORMESG) {
this.logger.warn(fres[0].ERRORMESG);
throw new BadRequestException(fres[0].ERRORMESG)
}
try {
const glData: pdfGLData[] = fres1.map(x => {
return {
itemNo: x.ITEMNO,
description: x.ITEMDESCRIPTION,
noOfPieces: x.NOOFPIECES,
weight: x.WEIGHT,
itemValue: x.ITEMVALUE,
countryOfOrigin: x.GOODSORIGINCOUNTRY
};
});
const carnetData: pdfCarnetData = {
carnetNo: fres[0].CARNETNO ?? "",
ISSUEDBY: fres[0].ISSUEDBY ?? "",
ISSUEDATE: fres[0].ISSUEDATE ?? "",
EXPDATE: fres[0].EXPDATE ?? "",
AUTHREP: fres[0].AUTHREP ?? "",
NOOFUSSETS: fres[0].NOOFUSSETS ?? 0,
NOOFFOREIGNSETS: fres[0].NOOFFOREIGNSETS ?? 0,
NOOFTRANSITSETS: fres[0].NOOFTRANSITSETS ?? 0,
PRINTGOODSTOBEEXPORTED: fres[0].PRINTGOODSTOBEEXPORTED ?? "",
HOLDERDATATOPRINT: fres[0].HOLDERDATATOPRINT ?? "",
CONTINUATIONSHEETS: fres[0].CONTINUATIONSHEETS ?? 0,
NEXTUSCFNO: fres[0].NEXTUSCFNO ?? 0,
NEXTFOREIGNCFNO: fres[0].NEXTFOREIGNCFNO ?? 0,
NEXTTRANSITCFNO: fres[0].NEXTTRANSITCFNO ?? 0,
contPageNo: 0
}
// const p1Status = await generateGreenCoverPDF(carnetData);
let p2Status: any = "";
p2Status = await generateGL(glData, carnetData, body);
// console.log("-------- p2 --------", p2Status);
// console.log(typeof p2Status.batch, p2Status.batch);
if (p2Status.batch % 2 === 0) {
await generateFinalPDF([...p2Status.fileArray, '2GeneralListVOID.pdf'], `${body.P_HEADERID}p2.pdf`)
await deleteFilesAsync([...p2Status.fileArray])
}
else {
await generateFinalPDF([...p2Status.fileArray], `${body.P_HEADERID}p2.pdf`)
await deleteFilesAsync([...p2Status.fileArray])
}
// const p3Status = await usCounterFoil(carnetData);
// const p4Status = await fnCounterFoil(carnetData);
// const p5Status = await tsCounterFoil(carnetData);
// const p6Status = await fnVochers(carnetData);
// const p7Status = await tnVochers(carnetData);
const finalArray = [
// ...p3Status,
// ...p4Status,
// ...p5Status,
// ...p6Status,
// ...p7Status
]
return { finalArray, carnetData }
} catch (error) {
throw new InternalServerException(error.message)
}
} catch (error) {
handleError(error, CarnetApplicationService.name)
}
}
// [payment]
async InitiatePayment() {
try {
const accessToken = await this.payPalService.generateAccessToken();
// return { accessToken, orderid: "1abc" }
const response = await axios({
url: process.env.PAYPAL_BASE_URL + '/v2/checkout/orders',
method: 'post',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + accessToken
},
data: JSON.stringify({
intent: 'CAPTURE',
purchase_units: [
{
items: [
{
name: 'carnet',
description: 'carnet',
quantity: 1,
unit_amount: {
currency_code: 'USD',
value: '100.00'
}
}
],
amount: {
currency_code: 'USD',
value: '100.00',
breakdown: {
item_total: {
currency_code: 'USD',
value: '100.00'
}
}
}
}
],
application_context: {
return_url: process.env.BASE_URL + '/complete-order',
cancel_url: process.env.BASE_URL + '/cancel-order',
shipping_preference: 'NO_SHIPPING',
user_action: 'PAY_NOW',
brand_name: 'test sample',
disable_funding: "card"
}
})
});
// console.log('PayPal create order response headers:', response.headers);
// console.log('PayPal create order response data:', response.data);
return {
id: response.data.id, href: response?.data?.links?.find(obj => obj.rel === 'approve')?.href
};
// return { id: response.data.id };
} catch (error) {
console.error('Error creating PayPal order:', error.response?.data || error.message || error);
// Return a structured error object or throw to be handled by caller
throw new InternalServerException();
// return {
// error: true,
// message: 'Failed to create PayPal order',
// details: error.response?.data || error.message || error
// };
}
}
async CapturePayment(body: CapturePaymentDTO) {
try {
const accessToken = await this.payPalService.generateAccessToken();
const response = await axios({
url: `${process.env.PAYPAL_BASE_URL}/v2/checkout/orders/${body.P_ORDERID}/capture`,
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
},
});
const capture = response?.data?.purchase_units?.[0]?.payments?.captures?.[0];
return {
statusCode: 200,
message: "Payment successful",
amount: `${capture?.amount?.value} ${capture?.amount?.currency_code}`,
};
} catch (error: any) {
const status = error.response?.status || 500;
const message = error.response?.data?.message || "Payment failed due to an unexpected error.";
// Optional: log full error for debugging
console.error("PayPal Capture Error:", {
status,
message,
details: error.response?.data,
});
if (status === 404) {
throw new NotFoundException(error.response?.data?.message || error?.message || "Resource Not Found")
}
throw new InternalServerException();
}
}
}

View File

@ -32,35 +32,43 @@ export class ManageHoldersController {
@Get('SearchHolder/:P_SPID/:P_USERID')
@ApiQuery({ name: "P_HOLDERNAME", type: String, required: false, description: "Optional" })
@ApiQuery({ name: "P_HOLDERID", type: Number, required: false, description: "Optional" })
SearchHolder(
@Param('P_SPID') P_SPID: number,
@Param('P_USERID') P_USERID: string,
@Query('P_HOLDERID') P_HOLDERID?: number,
@Query('P_HOLDERNAME') P_HOLDERNAME?: string | null | undefined,
) {
let rawHolderName: string | null | undefined = P_HOLDERNAME;
if (!P_USERID) {
throw new BadRequestException('User ID is required');
}
if (typeof rawHolderName === 'string') {
rawHolderName = rawHolderName.trim();
rawHolderName = rawHolderName.replace(/^['"]|['"]$/g, '');
// Sanitize holder name
let rawHolderName: string | null = null;
if (rawHolderName === '' || rawHolderName.toLowerCase() === 'null') {
rawHolderName = null;
} else {
const allowedPattern = /^[A-Za-z0-9 _@&.-]+$/;
if (typeof P_HOLDERNAME === 'string') {
const trimmed = P_HOLDERNAME.trim().replace(/^['"]|['"]$/g, '');
rawHolderName = trimmed === '' || trimmed.toLowerCase() === 'null' ? null : trimmed;
}
// uncomment for strict validation
// Validate and coerce P_HOLDERID
let holderId: number | null = null;
// if (!allowedPattern.test(rawHolderName)) {
// rawHolderName = null;
// }
if (P_HOLDERID !== undefined && P_HOLDERID !== null) {
const parsed = Number(P_HOLDERID);
if (isNaN(parsed)) {
throw new BadRequestException('Invalid holder ID');
}
} else {
rawHolderName = null;
holderId = parsed;
}
if(!P_USERID){
return new BadRequestException();
}
const body = { P_SPID,P_USERID,P_HOLDERNAME: rawHolderName }
const body = {
P_SPID,
P_USERID,
P_HOLDERID: holderId,
P_HOLDERNAME: rawHolderName,
};
return this.manageHoldersService.SearchHolder(body)
}

View File

@ -631,7 +631,7 @@ export class ManageHoldersService {
}
};
SearchHolder = async (body: { P_SPID: number, P_USERID: string, P_HOLDERNAME: string | null }) => {
SearchHolder = async (body: { P_SPID: number, P_USERID: string, P_HOLDERID: number | null, P_HOLDERNAME: string | null }) => {
let connection;
try {
@ -640,11 +640,12 @@ export class ManageHoldersService {
const result: Result<any> = await connection.execute(
`BEGIN
MANAGEHOLDER_PKG.SearchHolder(
:P_SPID, :P_HOLDERNAME, :P_USERID, :P_CURSOR
:P_SPID, :P_HOLDERID, :P_HOLDERNAME, :P_USERID, :P_CURSOR
);
END;`,
{
P_SPID: { val: body.P_SPID, type: oracledb.DB_TYPE_NUMBER },
P_HOLDERID: { val: body.P_HOLDERID, type: oracledb.DB_TYPE_NUMBER },
P_HOLDERNAME: { val: body.P_HOLDERNAME, type: oracledb.DB_TYPE_NVARCHAR },
P_USERID: { val: body.P_USERID, type: oracledb.DB_TYPE_NVARCHAR },
P_CURSOR: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }

View File

@ -10,11 +10,13 @@ import { UserMaintenanceModule } from './user-maintenance/user-maintenance.modul
import { CarnetApplicationModule } from './carnet-application/carnet-application.module';
import { OracleService } from './oracle.service';
import { AuthModule } from 'src/auth/auth.module';
import { PaypalModule } from 'src/paypal/paypal.module';
@Global()
@Module({
imports: [
DbModule,
PaypalModule,
CarnetApplicationModule,
UserMaintenanceModule,
HomePageModule,
@ -28,4 +30,4 @@ import { AuthModule } from 'src/auth/auth.module';
controllers: [],
exports: [OracleService, UserMaintenanceModule],
})
export class OracleModule {}
export class OracleModule { }

View File

@ -1,6 +1,6 @@
import { Injectable, Logger } from "@nestjs/common";
import { OracleDBService } from "src/db/db.service";
import { CLIENTLOCADDRESSTABLE_ROW_DTO, CONTACTSTABLE_ROW_DTO, COUNTRYTABLE_DTO, COUNTRYTABLE_ROW_DTO, GLTABLE_DTO, GLTABLE_ROW_DTO } from "src/dto/property.dto";
import { CLIENTLOCADDRESSTABLE_ROW_DTO, CONTACTSTABLE_ROW_DTO, COUNTRYTABLE_DTO, COUNTRYTABLE_ROW_DTO, GLTABLE_DTO, GLTABLE_ITEMNO_OPTIONAL_DTO, GLTABLE_ROW_ADD_DTO, GLTABLE_ROW_DTO } from "src/dto/property.dto";
import { InternalServerException } from "src/exceptions/internalServerError.exception";
import { closeOracleDbConnection, handleError } from "src/utils/helper";
@ -10,6 +10,62 @@ export class OracleService {
constructor(private readonly oracleDBService: OracleDBService) { }
async get_GL_TABLE_OPTIONAL_ITEMNO_INSTANCE(finalBody: any) {
// P_GLTABLE: { val: GLTABLE_INSTANCE, type: 'CARNETSYS.GLTABLE' }
// P_GLTABLE: { val: GLTABLE_INSTANCE, type: oracledb.DB_TYPE_OBJECT }
let connection;
try {
connection = await this.oracleDBService.getConnection();
const GLTABLE = await connection.getDbObjectClass('CARNETSYS.GLTABLE');
if (typeof GLTABLE !== 'function') {
throw new InternalServerException('GLTABLE is not a constructor');
}
async function createGLArrayInstance(
ITEMNO, ITEMDESCRIPTION, ITEMVALUE, NOOFPIECES,
ITEMWEIGHT, ITEMWEIGHTUOM, GOODSORIGINCOUNTRY,
) {
const result = await connection.execute(
`SELECT CARNETSYS.GLARRAY(
:ITEMNO, :ITEMDESCRIPTION, :ITEMVALUE, :NOOFPIECES,
:ITEMWEIGHT, :ITEMWEIGHTUOM, :GOODSORIGINCOUNTRY
) FROM dual`,
{
ITEMNO, ITEMDESCRIPTION, ITEMVALUE, NOOFPIECES,
ITEMWEIGHT, ITEMWEIGHTUOM, GOODSORIGINCOUNTRY,
}
);
return result.rows[0][0];
}
const GLTABLE_ARRAY: GLTABLE_ITEMNO_OPTIONAL_DTO = {
P_GLTABLE: await Promise.all(
(finalBody.P_GLTABLE ?? []).map(async (x: GLTABLE_ROW_ADD_DTO) => {
return await createGLArrayInstance(
x.ITEMNO, x.ITEMDESCRIPTION, x.ITEMVALUE, x.NOOFPIECES,
x.ITEMWEIGHT, x.ITEMWEIGHTUOM, x.GOODSORIGINCOUNTRY,
);
})
)
};
const GLTABLE_INSTANCE = new GLTABLE(GLTABLE_ARRAY.P_GLTABLE ?? []);
return GLTABLE_INSTANCE;
} catch (error) {
console.log("error while creating GL instance : ", error);
throw new Error("Error occured completing this process")
} finally {
await closeOracleDbConnection(connection, OracleService.name)
}
}
async get_GL_TABLE_INSTANCE(finalBody: any) {
// P_GLTABLE: { val: GLTABLE_INSTANCE, type: 'CARNETSYS.GLTABLE' }

View File

@ -1,10 +1,10 @@
import { Body, Controller, Get, Patch, Post, Put, Query, UseGuards } from '@nestjs/common';
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, UpdateParamRecordDTO
getParamValuesDTO, SPID_DTO, UpdateParamRecordDTO
} from 'src/dto/property.dto';
import { Roles } from 'src/decorators/roles.decorator';
import { JwtAuthGuard } from 'src/guards/jwt-auth.guard';
@ -53,10 +53,10 @@ export class ParamTableController {
return this.paramTableService.GETALLPARAMVALUES(body);
}
@Get('GetCountriesAndMessages')
@Get('GetCountriesAndMessages/:P_SPID')
@Roles('ca', 'sa', 'ua')
GET_COUNTRIES_AND_MESSAGES() {
return this.paramTableService.GET_COUNTRIES_AND_MESSAGES();
GET_COUNTRIES_AND_MESSAGES(@Param() body: SPID_DTO) {
return this.paramTableService.GET_COUNTRIES_AND_MESSAGES(body);
}
@Post('/CreateTableRecord')

View File

@ -8,7 +8,7 @@ import { closeOracleDbConnection, fetchCursor, handleError } from 'src/utils/hel
import {
ActivateOrInactivateParamRecordDTO, CreateParamRecordDTO, CreateTableRecordDTO,
getParamValuesDTO, UpdateParamRecordDTO
getParamValuesDTO, SPID_DTO, UpdateParamRecordDTO
} from 'src/dto/property.dto';
@Injectable()
@ -109,16 +109,17 @@ export class ParamTableService {
}
}
async GET_COUNTRIES_AND_MESSAGES() {
async GET_COUNTRIES_AND_MESSAGES(body: SPID_DTO) {
let connection;
try {
connection = await this.oracleDBService.getConnection();
const result = await connection.execute(
`BEGIN
MANAGEPARAMTABLE_PKG.GetCountriesAndMessages(:P_CURSOR);
MANAGEPARAMTABLE_PKG.GetCountriesAndMessages(:P_SPID, :P_CURSOR);
END;`,
{
P_SPID: { val: body.P_SPID, type: oracledb.DB_TYPE_NUMBER },
P_CURSOR: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
},
{ outFormat: oracledb.OUT_FORMAT_OBJECT }

View File

@ -0,0 +1,4 @@
import { Controller } from '@nestjs/common';
@Controller('paypal')
export class PaypalController {}

View File

@ -0,0 +1,10 @@
import { Global, Module } from '@nestjs/common';
import { PaypalController } from './paypal.controller';
import { PaypalService } from './paypal.service';
@Global()
@Module({
providers: [PaypalService],
exports: [PaypalService]
})
export class PaypalModule { }

View File

@ -0,0 +1,69 @@
// paypal.service.ts
import { Injectable, Logger } from '@nestjs/common';
import axios from 'axios';
import { InternalServerException } from 'src/exceptions/internalServerError.exception';
@Injectable()
export class PaypalService {
private accessToken: string | null = null;
private tokenExpiresAt: number = 0; // Unix timestamp in milliseconds
private readonly clientId = process.env.PAYPAL_CLIENT_ID;
private readonly clientSecret = process.env.PAYPAL_CLIENT_SECRET;
private readonly baseUrl = process.env.PAYPAL_BASE_URL; // or live URL
private readonly logger = new Logger(PaypalService.name);
async generateAccessToken(): Promise<any> {
// return process.env.PAYPAL_AT
const now = Date.now();
// Check if token is still valid
if (this.accessToken && now < this.tokenExpiresAt - 60_000) {
return this.accessToken;
}
// Fetch new token
const auth = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64');
try {
const tokenUrl = process.env.PAYPAL_BASE_URL + '/v1/oauth2/token';
const params = new URLSearchParams();
params.append('grant_type', 'client_credentials');
const response = await axios.post(
tokenUrl,
params.toString(), // or use `params` directly
{
auth: {
username: process.env.PAYPAL_CLIENT_ID!,
password: process.env.PAYPAL_SECRET!,
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}
);
const { access_token, expires_in } = response.data;
this.accessToken = access_token;
this.tokenExpiresAt = now + expires_in * 1000; // convert seconds to ms
// this.logger.warn(`Fetched new PayPal access token, expires in ${access_token} seconds`);
// console.log(access_token);
if (this.accessToken) {
return this.accessToken;
}
throw new InternalServerException("Error while getting paypal access token")
} catch (error) {
this.logger.error('Failed to fetch PayPal access token', error);
throw new InternalServerException('PayPal token fetch failed');
}
}
}

File diff suppressed because it is too large Load Diff