From 6cd825b4f8bd40bb7fdff338bf1cc5490b72777b Mon Sep 17 00:00:00 2001 From: dhruvbaliyan Date: Mon, 4 Dec 2023 15:32:46 +0530 Subject: [PATCH 1/2] feat: add scheme transaction APIs --- .../20231204094144_ste/migration.sql | 34 ++++ packages/bff/prisma/schema.prisma | 29 +++ packages/bff/src/app.module.ts | 6 + packages/bff/src/common/public.decorator.ts | 3 + packages/bff/src/common/ste.auth-guard.ts | 70 ++++++++ packages/bff/src/ste/dto/auth.dto.ts | 9 + .../bff/src/ste/dto/scheme.transaction.dto.ts | 78 ++++++++ packages/bff/src/ste/ste.controller.spec.ts | 18 ++ packages/bff/src/ste/ste.controller.ts | 59 ++++++ packages/bff/src/ste/ste.module.ts | 4 + packages/bff/src/ste/ste.service.spec.ts | 18 ++ packages/bff/src/ste/ste.service.ts | 158 ++++++++++++++++ packages/bff/src/ste/ste.validator.ts | 169 ++++++++++++++++++ 13 files changed, 655 insertions(+) create mode 100644 packages/bff/prisma/migrations/20231204094144_ste/migration.sql create mode 100644 packages/bff/src/common/public.decorator.ts create mode 100644 packages/bff/src/common/ste.auth-guard.ts create mode 100644 packages/bff/src/ste/dto/auth.dto.ts create mode 100644 packages/bff/src/ste/dto/scheme.transaction.dto.ts create mode 100644 packages/bff/src/ste/ste.controller.spec.ts create mode 100644 packages/bff/src/ste/ste.controller.ts create mode 100644 packages/bff/src/ste/ste.module.ts create mode 100644 packages/bff/src/ste/ste.service.spec.ts create mode 100644 packages/bff/src/ste/ste.service.ts create mode 100644 packages/bff/src/ste/ste.validator.ts diff --git a/packages/bff/prisma/migrations/20231204094144_ste/migration.sql b/packages/bff/prisma/migrations/20231204094144_ste/migration.sql new file mode 100644 index 00000000..173af0f7 --- /dev/null +++ b/packages/bff/prisma/migrations/20231204094144_ste/migration.sql @@ -0,0 +1,34 @@ +-- CreateTable +CREATE TABLE "scheme_transaction" ( + "id" SERIAL NOT NULL, + "schemeCode" TEXT NOT NULL, + "aadhaarNumber" TEXT NOT NULL, + "aadhaarReferenceNumber" TEXT NOT NULL, + "uniqueBeneficiaryId" TEXT NOT NULL, + "financialYear" TEXT NOT NULL, + "transactionType" TEXT NOT NULL, + "transactionAmount" INTEGER NOT NULL, + "inKindBenefitDetail" TEXT NOT NULL, + "transactionDate" TEXT NOT NULL, + "remarks" TEXT, + "departmentData" JSONB, + "userId" TEXT NOT NULL, + + CONSTRAINT "scheme_transaction_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "transaction_history_table" ( + "id" UUID NOT NULL DEFAULT gen_random_uuid(), + "requestBody" JSONB[], + "containErrors" BOOLEAN NOT NULL DEFAULT false, + "validRecordsSaved" BOOLEAN NOT NULL DEFAULT false, + "errors" JSONB NOT NULL, + "userId" TEXT NOT NULL, + "transactionStartTime" TIMESTAMP(3) NOT NULL, + "transactionEndTime" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "transaction_history_table_pkey" PRIMARY KEY ("id") +); diff --git a/packages/bff/prisma/schema.prisma b/packages/bff/prisma/schema.prisma index acbec14d..5327f0ac 100644 --- a/packages/bff/prisma/schema.prisma +++ b/packages/bff/prisma/schema.prisma @@ -123,3 +123,32 @@ model VillageData { submissions Json? status VillageDataStatus @default(UNASSIGNED) } + +model scheme_transaction { + id Int @id @default(autoincrement()) + schemeCode String + aadhaarNumber String + aadhaarReferenceNumber String + uniqueBeneficiaryId String + financialYear String + transactionType String + transactionAmount Int + inKindBenefitDetail String + transactionDate String + remarks String? + departmentData Json? + userId String +} + +model transaction_history_table { + id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid + requestBody Json[] + containErrors Boolean @default(false) + validRecordsSaved Boolean @default(false) + errors Json + userId String + transactionStartTime DateTime + transactionEndTime DateTime + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} \ No newline at end of file diff --git a/packages/bff/src/app.module.ts b/packages/bff/src/app.module.ts index 6148b14e..1718f3ec 100644 --- a/packages/bff/src/app.module.ts +++ b/packages/bff/src/app.module.ts @@ -24,6 +24,9 @@ import { MinioHealthIndicator } from './minio/minio.health'; import { HealthController } from './health/health.controller'; import { HealthService } from './health/health.service'; import { HttpModule } from '@nestjs/axios'; +import { SteService } from './ste/ste.service'; +import { SteController } from './ste/ste.controller'; +import { SteModule } from './ste/ste.module'; @Module({ imports: [ ConfigModule.forRoot({ @@ -53,12 +56,14 @@ import { HttpModule } from '@nestjs/axios'; }), SubmissionModule, MinioModule, + SteModule, ], controllers: [ AppController, SubmissionController, UploadController, HealthController, + SteController, ], providers: [ { @@ -75,6 +80,7 @@ import { HttpModule } from '@nestjs/axios'; UploadService, MinioHealthIndicator, HealthService, + SteService, ], }) export class AppModule {} diff --git a/packages/bff/src/common/public.decorator.ts b/packages/bff/src/common/public.decorator.ts new file mode 100644 index 00000000..5b8bb31b --- /dev/null +++ b/packages/bff/src/common/public.decorator.ts @@ -0,0 +1,3 @@ +import { SetMetadata } from '@nestjs/common'; + +export const Public = () => SetMetadata('isPublic', true); diff --git a/packages/bff/src/common/ste.auth-guard.ts b/packages/bff/src/common/ste.auth-guard.ts new file mode 100644 index 00000000..217bd3b8 --- /dev/null +++ b/packages/bff/src/common/ste.auth-guard.ts @@ -0,0 +1,70 @@ +import { + CanActivate, + ExecutionContext, + Injectable, + Scope, +} from '@nestjs/common'; +import { Observable } from 'rxjs'; +import * as jwt from 'jsonwebtoken'; +import * as jwksClient from 'jwks-rsa'; +import { Reflector } from '@nestjs/core'; + +@Injectable({ scope: Scope.DEFAULT }) +export class SteAuthGuard implements CanActivate { + private client: jwksClient.JwksClient; + private getKey: any; + + constructor(private readonly reflector: Reflector) { + this.client = jwksClient({ + jwksUri: process.env.JWKS_URI, + requestHeaders: {}, // Optional + timeout: 30000, // Defaults to 30s + }); + + this.getKey = (header: jwt.JwtHeader, callback: any) => { + this.client.getSigningKey(header.kid, (err, key: any) => { + if (err) { + console.log(`Error fetching signing key: ${err}`); + callback(err); + } else { + const signingKey = key.publicKey || key.rsaPublicKey; + callback(null, signingKey); + } + }); + }; + } + + canActivate( + context: ExecutionContext, + ): boolean | Promise | Observable { + const isPublic = this.reflector.get( + 'isPublic', + context.getHandler(), + ); + if (isPublic) return true; + const request = context.switchToHttp().getRequest(); + + const bearerToken = request.headers.authorization?.split(' ')[1]; + + if (!bearerToken) { + return false; + } + + return new Promise((resolve) => { + jwt.verify(bearerToken, this.getKey, (err, decoded) => { + if (err) { + console.log('JWT verification error:', err); + resolve(false); + } else { + if (decoded['roles'][0] !== 'department') { + resolve(false); + } + request.headers.userId = decoded.sub; + request.headers.username = decoded['preferred_username']; + request.headers.roles = decoded['roles']; + resolve(true); + } + }); + }); + } +} diff --git a/packages/bff/src/ste/dto/auth.dto.ts b/packages/bff/src/ste/dto/auth.dto.ts new file mode 100644 index 00000000..798684b9 --- /dev/null +++ b/packages/bff/src/ste/dto/auth.dto.ts @@ -0,0 +1,9 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class AuthDto { + @ApiProperty() + username: string; + + @ApiProperty() + password: string; +} diff --git a/packages/bff/src/ste/dto/scheme.transaction.dto.ts b/packages/bff/src/ste/dto/scheme.transaction.dto.ts new file mode 100644 index 00000000..2c579115 --- /dev/null +++ b/packages/bff/src/ste/dto/scheme.transaction.dto.ts @@ -0,0 +1,78 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { JsonArray } from '@prisma/client/runtime/library'; + +export class SchemeTransactionEvent { + @ApiProperty({ + example: 'CULC8', + }) + schemeCode: string; + + @ApiProperty({ + example: '123412341234', + description: '12 Digit Aadhaar Number', + }) + aadhaarNumber: string; + + @ApiProperty({ + example: '1234123412345', + description: '13 Digit Aadhaar Reference Number', + }) + aadhaarReferenceNumber: string; + + @ApiProperty({ + example: '123456', + }) + uniqueBeneficiaryId: string; + + @ApiProperty({ + example: '2022-23', + description: 'Financial year in YYYY-YY format', + }) + financialYear: string; + + @ApiProperty({ + example: 'Cash', + }) + transactionType: string; + + @ApiProperty({ + example: 5000, + description: 'Transaction Amount', + }) + transactionAmount: number; + + @ApiProperty({ + example: 'Training', + }) + inKindBenefitDetail: string; + + @ApiProperty({ + example: '12-05-2023', + description: 'Transaction date in DD-MM-YYYY format', + }) + transactionDate: string; + + @ApiProperty({ + type: String, + }) + remarks = ''; + + @ApiProperty({ + type: [], + example: [ + { + marker: 'Date of Birth', + value: '21-01-1999', + }, + ], + description: 'These are department specific marker-value pairs', + }) + departmentData: JsonArray = []; +} + +export class SchemeTransactionEventDto { + @ApiProperty({ + type: [SchemeTransactionEvent], + }) + data: SchemeTransactionEvent[]; +} diff --git a/packages/bff/src/ste/ste.controller.spec.ts b/packages/bff/src/ste/ste.controller.spec.ts new file mode 100644 index 00000000..5d5857ae --- /dev/null +++ b/packages/bff/src/ste/ste.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SteController } from './ste.controller'; + +describe('SteController', () => { + let controller: SteController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [SteController], + }).compile(); + + controller = module.get(SteController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/packages/bff/src/ste/ste.controller.ts b/packages/bff/src/ste/ste.controller.ts new file mode 100644 index 00000000..81eaad8e --- /dev/null +++ b/packages/bff/src/ste/ste.controller.ts @@ -0,0 +1,59 @@ +import { + Body, + Controller, + Get, + Param, + Post, + Req, + UseGuards, +} from '@nestjs/common'; +import { SteService } from './ste.service'; +import { SchemeTransactionEventDto } from './dto/scheme.transaction.dto'; +import { Public } from 'src/common/public.decorator'; +import { Request } from 'express'; +import { SteAuthGuard } from 'src/common/ste.auth-guard'; +import { AuthDto } from './dto/auth.dto'; + +@UseGuards(SteAuthGuard) +@Controller('ste') +export class SteController { + constructor(private readonly steService: SteService) {} + + @Public() + @Post('/authenticate') + async authenticate(@Body() authDto: AuthDto) { + return await this.steService.authenticate( + authDto.username, + authDto.password, + ); + } + + @Post('/saveSchemeTransaction') + async saveSchemeTransaction( + @Body() schemeTransactionDetail: SchemeTransactionEventDto, + @Req() request: Request, + ) { + const userIdHeader = request.headers.userId; + const userId: string = Array.isArray(userIdHeader) + ? userIdHeader[0] + : userIdHeader; + return await this.steService.saveSchemeTransaction( + schemeTransactionDetail.data, + userId, + ); + } + + @Get('/transactionHistory/:id') + async getTransactionHistory(@Param('id') transactionHistoryid: string) { + return await this.steService.getTransactionHistory(transactionHistoryid); + } + + @Get('/progress') + async getProgress(@Req() request: Request) { + const userIdHeader = request.headers.userId; + const userId: string = Array.isArray(userIdHeader) + ? userIdHeader[0] + : userIdHeader; + return await this.steService.getProgress(userId); + } +} diff --git a/packages/bff/src/ste/ste.module.ts b/packages/bff/src/ste/ste.module.ts new file mode 100644 index 00000000..7d3969fb --- /dev/null +++ b/packages/bff/src/ste/ste.module.ts @@ -0,0 +1,4 @@ +import { Module } from '@nestjs/common'; + +@Module({}) +export class SteModule {} diff --git a/packages/bff/src/ste/ste.service.spec.ts b/packages/bff/src/ste/ste.service.spec.ts new file mode 100644 index 00000000..81a85046 --- /dev/null +++ b/packages/bff/src/ste/ste.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SteService } from './ste.service'; + +describe('SteService', () => { + let service: SteService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [SteService], + }).compile(); + + service = module.get(SteService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/packages/bff/src/ste/ste.service.ts b/packages/bff/src/ste/ste.service.ts new file mode 100644 index 00000000..a6696625 --- /dev/null +++ b/packages/bff/src/ste/ste.service.ts @@ -0,0 +1,158 @@ +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { PrismaService } from 'src/prisma/prisma.service'; +import { SchemeTransactionEvent } from './dto/scheme.transaction.dto'; +import axios from 'axios'; +import { SteValidator } from './ste.validator'; +import { map } from 'lodash'; + +@Injectable() +export class SteService { + constructor(private readonly prismaService: PrismaService) {} + + private steValidator = new SteValidator(); + private userServiceBaseUrl = process.env.USER_SERVICE; + private steApplicationId = process.env.STE_APPLICATION_ID; + + async authenticate(username: string, password: string) { + let response; + try { + response = await axios.post(`${this.userServiceBaseUrl}/api/login`, { + password: password, + loginId: username, + applicationId: this.steApplicationId, + }); + if (response.data.responseCode === 'FAILURE') { + return { + status: 'failure', + message: response.data.params.err, + }; + } + const token = response.data.result.data.user.token; + return { + status: 'success', + message: 'Authenticated', + token: token, + }; + } catch (err) { + console.log(err); + return err; + } + } + + async transformSchemeTransaction( + schemeTransactions: SchemeTransactionEvent[], + deptUsername: string, + ): Promise { + return await Promise.all( + map(schemeTransactions, async (transaction) => { + return { + userId: deptUsername, + ...transaction, + }; + }), + ); + } + + async saveSchemeTransaction( + schemetransactions: SchemeTransactionEvent[], + userId: string, + ) { + const transactionStartTime = new Date(); + const schemeTransactionEvents = JSON.parse( + JSON.stringify(schemetransactions), + ); + const validatedSchemeTransactionEventBody = + await this.validateSchemeTransactionEventBody(schemeTransactionEvents); + const validSchemeTransactions = + validatedSchemeTransactionEventBody.validSchemeTransactions; + + let validSchemeTransactionsSaved = false; + try { + const records = await this.transformSchemeTransaction( + validSchemeTransactions, + userId, + ); + await this.prismaService.scheme_transaction.createMany({ + data: records, + }); + validSchemeTransactionsSaved = true; + } catch (error) {} + let transactionHistory; + try { + transactionHistory = + await this.prismaService.transaction_history_table.create({ + data: { + requestBody: schemeTransactionEvents, + containErrors: validatedSchemeTransactionEventBody.errorCount !== 0, + errors: validatedSchemeTransactionEventBody.errors, + userId, + validRecordsSaved: validSchemeTransactionsSaved, + transactionStartTime: transactionStartTime, + transactionEndTime: new Date(), + }, + }); + } catch (error) { + console.log( + `Transaction History Save Failed for ${userId}`, + validatedSchemeTransactionEventBody, + ); + } + return { + transactionId: transactionHistory.id, + savedTransactionsCount: + validatedSchemeTransactionEventBody.validSchemeTransactions.length, + errorTransactionsCount: validatedSchemeTransactionEventBody.errorCount, + }; + } + + async getTransactionHistory(transactionHistoryid: string) { + const transactionHistory = + await this.prismaService.transaction_history_table.findUnique({ + where: { + id: transactionHistoryid, + }, + }); + if (!transactionHistory) { + throw new HttpException( + `No transaction history found with id ${transactionHistoryid}`, + HttpStatus.BAD_REQUEST, + ); + } + return transactionHistory; + } + + async getProgress(userId: string) { + const recordCount = await this.prismaService.scheme_transaction.count({ + where: { + userId: userId, + }, + }); + return { records_saved: recordCount }; + } + + async validateSchemeTransactionEventBody( + schemeTransactionEvents: any[], + ): Promise { + const validatedArray = {}; + validatedArray['validSchemeTransactions'] = []; + validatedArray['errors'] = {}; + let errorCount = 0; + for (let i = 0; i < schemeTransactionEvents.length; i++) { + const errors = this.steValidator.validateSchemeTransactionEvent( + schemeTransactionEvents[i], + ); + if (Object.keys(errors).length === 0) { + validatedArray['validSchemeTransactions'].push( + schemeTransactionEvents[i], + ); + } else { + errorCount++; + validatedArray['errors'][`${i}`] = errors; + } + } + validatedArray['errorCount'] = errorCount; + validatedArray['validSchemeTransactionsCount'] = + validatedArray['validSchemeTransactions'].length; + return validatedArray; + } +} diff --git a/packages/bff/src/ste/ste.validator.ts b/packages/bff/src/ste/ste.validator.ts new file mode 100644 index 00000000..195a5d13 --- /dev/null +++ b/packages/bff/src/ste/ste.validator.ts @@ -0,0 +1,169 @@ +export class SteValidator { + validateSchemeCode(schemeCode: string): string[] { + const error = []; + if (!schemeCode) { + error.push('EMPTY SCHEME CODE'); + return error; + } + if (schemeCode.length === 0) { + error.push('SCHEME CODE CANNOT BE EMPTY STRING'); + return error; + } + return error; + } + + validateAadhaarNumber(aadhaarNumber: string): string[] { + const error = []; + if (!aadhaarNumber) { + error.push('EMPTY AADHAAR NUMBER'); + return error; + } + if (isNaN(Number(aadhaarNumber))) { + error.push('AADHAAR NUMBER IS NOT A NUMBER'); + return error; + } + if (aadhaarNumber.length !== 12) { + error.push('AADHAAR NUMBER SHOULD BE OF LENGTH 12'); + return error; + } + return error; + } + + validateAadhaarReferenceNumber(aadhaarReferenceNumber: string): string[] { + const error = []; + if (!aadhaarReferenceNumber) { + error.push('EMPTY AADHAAR REFERENCE NUMBER'); + return error; + } + if (isNaN(Number(aadhaarReferenceNumber))) { + error.push('AADHAAR REFERENCE NUMBER IS NOT A NUMBER'); + return error; + } + if (aadhaarReferenceNumber.length !== 13) { + error.push('AADHAAR REFERENCE NUMBER SHOULD BE OF LENGTH 13'); + return error; + } + return error; + } + + validateUniqueBeneficiaryId(uniqueBeneficiaryId: string): string[] { + const error = []; + if (!uniqueBeneficiaryId) { + error.push('EMPTY UNIQUE BENEFICIARY ID'); + return error; + } + if (uniqueBeneficiaryId.length === 0) { + error.push('UNIQUE BENEFICIARY ID CANNOT BE EMPTY STRING'); + return error; + } + return error; + } + + validateFinancialYear(financialYear: string): string[] { + const error = []; + if (!financialYear) { + error.push('EMPTY FINANCIAL YEAR'); + return error; + } + const regex = /^\d{4}-\d{2}$/; // for YYYY-YY pattern + if (!regex.test(financialYear)) { + error.push('FINANCIAL NOT IN FORMAT OF YYYY-YY'); + return error; + } + return error; + } + + validateTransactionType(transactionType: string): string[] { + const error = []; + if (!transactionType) { + error.push('EMPTY TRANSACTION TYPE'); + return error; + } + if (transactionType.length === 0) { + error.push('TRANSACTION TYPE CANNOT BE EMPTY STRING'); + return error; + } + return error; + } + + validateTransactionAmount(transactionAmount): string[] { + const error = []; + if (!transactionAmount) { + error.push('EMPTY TRANSACTION AMOUNT'); + return error; + } + if (typeof transactionAmount !== 'number') { + error.push('TRANSACTION AMOUNT SHOULD BE AN INTEGER'); + return error; + } + return error; + } + + validateInKindBenefitDetail(inKindBenefitDetail: string): string[] { + const error = []; + if (!inKindBenefitDetail) { + error.push('EMPTY IN KIND BENEFIT DETAIL'); + return error; + } + if (inKindBenefitDetail.length === 0) { + error.push('IN KIND BENEFIT DETAIL CANNOT BE EMPTY STRING'); + return error; + } + return error; + } + + validateTransactionDate(transactionDate: string): string[] { + const error = []; + if (!transactionDate) { + error.push('EMPTY TRANSACTION DATE'); + return error; + } + const regex = /^(0[1-9]|[12][0-9]|3[01])-(0[1-9]|1[0-2])-\d{4}$/; // for DD-MM-YYYY pattern + if (!regex.test(transactionDate)) { + error.push('TRANSACTION DATE NOT IN FORMAT OF DD-MM-YYYY'); + return error; + } + return error; + } + + validateSchemeTransactionEvent(schemeTransaction: any): any { + type ErrorObject = { + [key: string]: any[]; + }; + const errors: ErrorObject = {}; + errors['schemeCode'] = this.validateSchemeCode( + schemeTransaction.schemeCode, + ); + errors['aadhaarNumber'] = this.validateAadhaarNumber( + schemeTransaction.aadhaarNumber, + ); + errors['aadhaarReferenceNumber'] = this.validateAadhaarReferenceNumber( + schemeTransaction.aadhaarReferenceNumber, + ); + errors['uniqueBeneficiaryId'] = this.validateUniqueBeneficiaryId( + schemeTransaction.uniqueBeneficiaryId, + ); + errors['financialYear'] = this.validateFinancialYear( + schemeTransaction.financialYear, + ); + errors['transactionType'] = this.validateTransactionType( + schemeTransaction.transactionType, + ); + errors['transactionAmount'] = this.validateTransactionAmount( + schemeTransaction.transactionAmount, + ); + errors['inKindBenefitDetail'] = this.validateInKindBenefitDetail( + schemeTransaction.inKindBenefitDetail, + ); + errors['transactionDate'] = this.validateTransactionDate( + schemeTransaction.transactionDate, + ); + const resError = {}; + Object.entries(errors).forEach(([key, value]) => { + if (value.length > 0) { + resError[key] = value[0]; + } + }); + return resError; + } +} From d2b8fdb9f44bd9fc58d0f11e589e1b1fdc340edd Mon Sep 17 00:00:00 2001 From: dhruvbaliyan Date: Mon, 4 Dec 2023 16:38:00 +0530 Subject: [PATCH 2/2] refactor: change table col names to snake_case --- .../20231204094144_ste/migration.sql | 34 ----------- .../20231204115049_ste/migration.sql | 37 +++++++++++ packages/bff/prisma/schema.prisma | 51 ++++++++-------- packages/bff/src/common/ste.auth-guard.ts | 2 +- packages/bff/src/ste/ste.service.ts | 61 ++++++++++--------- 5 files changed, 96 insertions(+), 89 deletions(-) delete mode 100644 packages/bff/prisma/migrations/20231204094144_ste/migration.sql create mode 100644 packages/bff/prisma/migrations/20231204115049_ste/migration.sql diff --git a/packages/bff/prisma/migrations/20231204094144_ste/migration.sql b/packages/bff/prisma/migrations/20231204094144_ste/migration.sql deleted file mode 100644 index 173af0f7..00000000 --- a/packages/bff/prisma/migrations/20231204094144_ste/migration.sql +++ /dev/null @@ -1,34 +0,0 @@ --- CreateTable -CREATE TABLE "scheme_transaction" ( - "id" SERIAL NOT NULL, - "schemeCode" TEXT NOT NULL, - "aadhaarNumber" TEXT NOT NULL, - "aadhaarReferenceNumber" TEXT NOT NULL, - "uniqueBeneficiaryId" TEXT NOT NULL, - "financialYear" TEXT NOT NULL, - "transactionType" TEXT NOT NULL, - "transactionAmount" INTEGER NOT NULL, - "inKindBenefitDetail" TEXT NOT NULL, - "transactionDate" TEXT NOT NULL, - "remarks" TEXT, - "departmentData" JSONB, - "userId" TEXT NOT NULL, - - CONSTRAINT "scheme_transaction_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "transaction_history_table" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "requestBody" JSONB[], - "containErrors" BOOLEAN NOT NULL DEFAULT false, - "validRecordsSaved" BOOLEAN NOT NULL DEFAULT false, - "errors" JSONB NOT NULL, - "userId" TEXT NOT NULL, - "transactionStartTime" TIMESTAMP(3) NOT NULL, - "transactionEndTime" TIMESTAMP(3) NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "transaction_history_table_pkey" PRIMARY KEY ("id") -); diff --git a/packages/bff/prisma/migrations/20231204115049_ste/migration.sql b/packages/bff/prisma/migrations/20231204115049_ste/migration.sql new file mode 100644 index 00000000..8f05ac1c --- /dev/null +++ b/packages/bff/prisma/migrations/20231204115049_ste/migration.sql @@ -0,0 +1,37 @@ +-- CreateTable +CREATE TABLE "scheme_transaction" ( + "id" SERIAL NOT NULL, + "scheme_code" TEXT NOT NULL, + "aadhaar_number" VARCHAR(12) NOT NULL, + "aadhaar_reference_number" VARCHAR(13) NOT NULL, + "unique_beneficiary_id" VARCHAR(127) NOT NULL, + "financial_year" VARCHAR(15) NOT NULL, + "transaction_type" VARCHAR(127) NOT NULL, + "transaction_amount" INTEGER NOT NULL, + "in_kind_benefit_detail" VARCHAR(127) NOT NULL, + "transaction_date" VARCHAR(15) NOT NULL, + "remarks" TEXT, + "department_data" JSONB, + "user_id" UUID NOT NULL, + + CONSTRAINT "scheme_transaction_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "transaction_history_table" ( + "id" UUID NOT NULL DEFAULT gen_random_uuid(), + "request_body" JSONB[], + "total_records" INTEGER NOT NULL, + "valid_records" INTEGER NOT NULL, + "invalid_records" INTEGER NOT NULL, + "contain_errors" BOOLEAN NOT NULL DEFAULT false, + "valid_records_saved" BOOLEAN NOT NULL DEFAULT false, + "errors" JSONB NOT NULL, + "user_id" UUID NOT NULL, + "transaction_start_time" TIMESTAMP(3) NOT NULL, + "transaction_end_time" TIMESTAMP(3) NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "transaction_history_table_pkey" PRIMARY KEY ("id") +); diff --git a/packages/bff/prisma/schema.prisma b/packages/bff/prisma/schema.prisma index 5327f0ac..97d04fca 100644 --- a/packages/bff/prisma/schema.prisma +++ b/packages/bff/prisma/schema.prisma @@ -125,30 +125,33 @@ model VillageData { } model scheme_transaction { - id Int @id @default(autoincrement()) - schemeCode String - aadhaarNumber String - aadhaarReferenceNumber String - uniqueBeneficiaryId String - financialYear String - transactionType String - transactionAmount Int - inKindBenefitDetail String - transactionDate String - remarks String? - departmentData Json? - userId String + id Int @id @default(autoincrement()) + scheme_code String + aadhaar_number String @db.VarChar(12) + aadhaar_reference_number String @db.VarChar(13) + unique_beneficiary_id String @db.VarChar(127) + financial_year String @db.VarChar(15) + transaction_type String @db.VarChar(127) + transaction_amount Int + in_kind_benefit_detail String @db.VarChar(127) + transaction_date String @db.VarChar(15) + remarks String? + department_data Json? + user_id String @db.Uuid } model transaction_history_table { - id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid - requestBody Json[] - containErrors Boolean @default(false) - validRecordsSaved Boolean @default(false) - errors Json - userId String - transactionStartTime DateTime - transactionEndTime DateTime - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} \ No newline at end of file + id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid + request_body Json[] + total_records Int + valid_records Int + invalid_records Int + contain_errors Boolean @default(false) + valid_records_saved Boolean @default(false) + errors Json + user_id String @db.Uuid + transaction_start_time DateTime + transaction_end_time DateTime + created_at DateTime @default(now()) + updated_at DateTime @updatedAt +} diff --git a/packages/bff/src/common/ste.auth-guard.ts b/packages/bff/src/common/ste.auth-guard.ts index 217bd3b8..896373b8 100644 --- a/packages/bff/src/common/ste.auth-guard.ts +++ b/packages/bff/src/common/ste.auth-guard.ts @@ -56,7 +56,7 @@ export class SteAuthGuard implements CanActivate { console.log('JWT verification error:', err); resolve(false); } else { - if (decoded['roles'][0] !== 'department') { + if (!decoded['roles'].includes('department')) { resolve(false); } request.headers.userId = decoded.sub; diff --git a/packages/bff/src/ste/ste.service.ts b/packages/bff/src/ste/ste.service.ts index a6696625..7946c463 100644 --- a/packages/bff/src/ste/ste.service.ts +++ b/packages/bff/src/ste/ste.service.ts @@ -3,7 +3,6 @@ import { PrismaService } from 'src/prisma/prisma.service'; import { SchemeTransactionEvent } from './dto/scheme.transaction.dto'; import axios from 'axios'; import { SteValidator } from './ste.validator'; -import { map } from 'lodash'; @Injectable() export class SteService { @@ -39,20 +38,6 @@ export class SteService { } } - async transformSchemeTransaction( - schemeTransactions: SchemeTransactionEvent[], - deptUsername: string, - ): Promise { - return await Promise.all( - map(schemeTransactions, async (transaction) => { - return { - userId: deptUsername, - ...transaction, - }; - }), - ); - } - async saveSchemeTransaction( schemetransactions: SchemeTransactionEvent[], userId: string, @@ -68,27 +53,42 @@ export class SteService { let validSchemeTransactionsSaved = false; try { - const records = await this.transformSchemeTransaction( - validSchemeTransactions, - userId, - ); await this.prismaService.scheme_transaction.createMany({ - data: records, + data: validSchemeTransactions.map((entry) => ({ + scheme_code: entry.schemeCode, + aadhaar_number: entry.aadhaarNumber, + aadhaar_reference_number: entry.aadhaarReferenceNumber, + unique_beneficiary_id: entry.uniqueBeneficiaryId, + financial_year: entry.financialYear, + transaction_type: entry.transactionType, + transaction_amount: parseInt(entry.transactionAmount), // validator ensures transactionAmount is always a number + in_kind_benefit_detail: entry.inKindBenefitDetail, + transaction_date: entry.transactionDate, + remarks: entry.remarks, + department_data: entry.departmentData, + user_id: userId, + })), }); validSchemeTransactionsSaved = true; - } catch (error) {} + } catch (error) { + console.log(error.data); + } let transactionHistory; try { transactionHistory = await this.prismaService.transaction_history_table.create({ data: { - requestBody: schemeTransactionEvents, - containErrors: validatedSchemeTransactionEventBody.errorCount !== 0, + request_body: schemeTransactionEvents, + total_records: schemetransactions.length, + valid_records: validSchemeTransactions.length, + invalid_records: validatedSchemeTransactionEventBody.errorCount, + contain_errors: + validatedSchemeTransactionEventBody.errorCount !== 0, errors: validatedSchemeTransactionEventBody.errors, - userId, - validRecordsSaved: validSchemeTransactionsSaved, - transactionStartTime: transactionStartTime, - transactionEndTime: new Date(), + user_id: userId, + valid_records_saved: validSchemeTransactionsSaved, + transaction_start_time: transactionStartTime, + transaction_end_time: new Date(), }, }); } catch (error) { @@ -99,8 +99,9 @@ export class SteService { } return { transactionId: transactionHistory.id, - savedTransactionsCount: - validatedSchemeTransactionEventBody.validSchemeTransactions.length, + savedTransactionsCount: validSchemeTransactionsSaved + ? validatedSchemeTransactionEventBody.validSchemeTransactions.length + : 0, errorTransactionsCount: validatedSchemeTransactionEventBody.errorCount, }; } @@ -124,7 +125,7 @@ export class SteService { async getProgress(userId: string) { const recordCount = await this.prismaService.scheme_transaction.count({ where: { - userId: userId, + user_id: userId, }, }); return { records_saved: recordCount };