feat: finish working on mocking inquire application api

This commit is contained in:
Abdalhamid Alhamad
2025-05-26 16:34:09 +03:00
parent 9aa6c487ed
commit d4fe3b3fc3
10 changed files with 318 additions and 5 deletions

View File

@ -12,6 +12,7 @@ import { AllowanceModule } from './allowance/allowance.module';
import { AuthModule } from './auth/auth.module';
import { CacheModule } from './common/modules/cache/cache.module';
import { LookupModule } from './common/modules/lookup/lookup.module';
import { NeoLeapModule } from './common/modules/neoleap/neoleap.module';
import { NotificationModule } from './common/modules/notification/notification.module';
import { OtpModule } from './common/modules/otp/otp.module';
import { AllExceptionsFilter, buildI18nValidationExceptionFilter } from './core/filters';
@ -80,6 +81,7 @@ import { UserModule } from './user/user.module';
UserModule,
CronModule,
NeoLeapModule,
],
providers: [
// Global Pipes

View File

@ -0,0 +1 @@
export * from './inquire-application.mock';

View File

@ -0,0 +1,91 @@
export const INQUIRE_APPLICATION_MOCK = {
ResponseHeader: {
Version: '1.0.0',
MsgUid: 'stringstringstringstringstringstring',
Source: 'string',
ServiceId: 'string',
ReqDateTime: '2025-05-26T10:23:13.812Z',
RspDateTime: '2025-05-26T10:23:13.812Z',
ResponseCode: 'string',
ResponseType: 'Validation Error',
ProcessingTime: 0,
EncryptionKey: 'string',
ResponseDescription: 'string',
LocalizedResponseDescription: {
Locale: 'string',
LocalizedDescription: 'string',
},
CustomerSpecificResponseDescriptionList: [
{
Locale: 'string',
ResponseDescription: 'string',
},
],
HeaderUserDataList: [
{
Tag: 'string',
Value: 'string',
},
],
},
InquireApplicationResponseDetails: {
InstitutionCode: 'stri',
ApplicationTypeDetails: {
TypeCode: 'st',
Description: 'string',
Additional: true,
Corporate: true,
UserData: 'string',
},
ApplicationDetails: {
ApplicationNumber: 'string',
ExternalApplicationNumber: 'string',
ApplicationStatus: 'st',
Organization: 0,
Product: 'stri',
ApplicatonDate: '2025-05-26',
ApplicationSource: 's',
SalesSource: 'string',
DeliveryMethod: 's',
ProgramCode: 'string',
Campaign: 'string',
Plastic: 'string',
Design: 'string',
ProcessStage: 'st',
ProcessStageStatus: 's',
Score: 'string',
ExternalScore: 'string',
RequestedLimit: 0,
SuggestedLimit: 0,
AssignedLimit: 0,
AllowedLimitList: [
{
CreditLimit: 0,
EvaluationCode: 'string',
},
],
EligibilityCheckResult: 'string',
EligibilityCheckDescription: 'string',
Title: 'string',
FirstName: 'string',
SecondName: 'string',
ThirdName: 'string',
LastName: 'string',
FullName: 'string',
EmbossName: 'string',
PlaceOfBirth: 'string',
DateOfBirth: '2025-05-26',
LocalizedDateOfBirth: '2025-05-26',
Age: 20,
Gender: 'M',
Married: 'S',
Nationality: 'str',
IdType: 'st',
IdNumber: 'string',
IdExpiryDate: '2025-05-26',
EducationLevel: 'stri',
ProfessionCode: 0,
},
},
};

View File

@ -0,0 +1,14 @@
import { Controller, Get } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { NeoLeapService } from '../services/neoleap.service';
@Controller('neotest')
@ApiTags('NeoTest')
export class NeoTestController {
constructor(private readonly neoleapService: NeoLeapService) {}
@Get('inquire-application')
async inquireApplication() {
return this.neoleapService.inquireApplication('1234567890');
}
}

View File

@ -0,0 +1 @@
export * from './inquire-application.response';

View File

@ -0,0 +1,133 @@
import { Expose, Transform } from 'class-transformer';
export class InquireApplicationResponse {
@Transform(({ obj }) => obj.ApplicationDetails?.ApplicationNumber)
@Expose()
applicationNumber!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.ExternalApplicationNumber)
@Expose()
externalApplicationNumber!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.ApplicationStatus)
@Expose()
applicationStatus!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.Organization)
@Expose()
organization!: number;
@Transform(({ obj }) => obj.ApplicationDetails?.Product)
@Expose()
product!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.ApplicatonDate)
@Expose()
applicationDate!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.ApplicationSource)
@Expose()
applicationSource!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.SalesSource)
@Expose()
salesSource!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.DeliveryMethod)
@Expose()
deliveryMethod!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.ProgramCode)
@Expose()
ProgramCode!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.Plastic)
@Expose()
plastic!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.Design)
@Expose()
design!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.ProcessStage)
@Expose()
processStage!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.ProcessStageStatus)
@Expose()
processStageStatus!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.EligibilityCheckResult)
@Expose()
eligibilityCheckResult!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.EligibilityCheckDescription)
@Expose()
eligibilityCheckDescription!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.Title)
@Expose()
title!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.FirstName)
@Expose()
firstName!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.SecondName)
@Expose()
secondName!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.ThirdName)
@Expose()
thirdName!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.LastName)
@Expose()
lastName!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.FullName)
@Expose()
fullName!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.EmbossName)
@Expose()
embossName!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.PlaceOfBirth)
@Expose()
placeOfBirth!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.DateOfBirth)
@Expose()
dateOfBirth!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.LocalizedDateOfBirth)
@Expose()
localizedDateOfBirth!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.Age)
@Expose()
age!: number;
@Transform(({ obj }) => obj.ApplicationDetails?.Gender)
@Expose()
gender!: string;
@Transform(({ obj }) => obj.ApplicationDetails?.Married)
@Expose()
married!: string;
@Transform(({ obj }) => obj.ApplicationDetails.Nationality)
@Expose()
nationality!: string;
@Transform(({ obj }) => obj.ApplicationDetails.IdType)
@Expose()
idType!: string;
@Transform(({ obj }) => obj.ApplicationDetails.IdNumber)
@Expose()
idNumber!: string;
@Transform(({ obj }) => obj.ApplicationDetails.IdExpiryDate)
@Expose()
idExpiryDate!: string;
}

View File

@ -1,2 +1,3 @@
export * from './create-application.request.interface';
export * from './inquire-application.request.interface';
export * from './neoleap-header.request.interface';

View File

@ -0,0 +1,22 @@
import { INeoleapHeaderRequest } from './neoleap-header.request.interface';
export interface IInquireApplicationRequest extends INeoleapHeaderRequest {
InquireApplicationRequestDetails: {
ApplicationIdentifier: {
InstitutionCode: string;
ExternalApplicationNumber: string;
};
AdditionalData?: {
ReturnApplicationType?: boolean;
ReturnApplicationStatus?: boolean;
ReturnAddresses?: boolean;
ReturnBranch?: boolean;
ReturnHistory?: boolean;
ReturnCard?: boolean;
ReturnCustomer?: boolean;
ReturnAccount?: boolean;
ReturnDirectDebitDetails?: boolean;
};
HistoryTypeFilterList?: number[];
};
}

View File

@ -1,8 +1,11 @@
import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { NeoTestController } from './controllers/neotest.controller';
import { NeoLeapService } from './services/neoleap.service';
@Module({
imports: [],
controllers: [],
providers: [],
imports: [HttpModule],
controllers: [NeoTestController],
providers: [NeoLeapService],
})
export class NeoLeapModule {}

View File

@ -1,11 +1,14 @@
import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { plainToInstance } from 'class-transformer';
import moment from 'moment';
import { v4 as uuid } from 'uuid';
import { CountriesNumericISO } from '~/common/constants';
import { Customer } from '~/customer/entities';
import { Gender } from '~/customer/enums';
import { INQUIRE_APPLICATION_MOCK } from '../__mocks__/';
import { InquireApplicationResponse } from '../dtos/response';
import { ICreateApplicationRequest, INeoleapHeaderRequest } from '../interfaces';
@Injectable()
export class NeoLeapService {
@ -55,7 +58,7 @@ export class NeoLeapService {
Title: customer.gender === Gender.MALE ? 'Mr' : 'Ms',
Gender: customer.gender === Gender.MALE ? 'M' : 'F',
LocalizedDateOfBirth: moment(customer.dateOfBirth).format('YYYY-MM-DD'),
Nationality: '682',
Nationality: CountriesNumericISO[customer.countryOfResidence],
},
ApplicationAddress: {
City: customer.city,
@ -75,7 +78,7 @@ export class NeoLeapService {
...this.prepareHeaders('CreateNewApplication'),
};
const response = await this.httpService.axiosRef.post(`${this.baseUrl}/create-application`, payload, {
const response = await this.httpService.axiosRef.post(`${this.baseUrl}/application/CreateNewApplication`, payload, {
headers: {
'Content-Type': 'application/json',
Authorization: `${this.apiKey}`,
@ -85,6 +88,48 @@ export class NeoLeapService {
//@TODO handle response
}
async inquireApplication(externalApplicationNumber: string) {
const responseKey = 'InquireApplicationResponseDetails';
if (this.useMock) {
return plainToInstance(InquireApplicationResponse, INQUIRE_APPLICATION_MOCK[responseKey], {
excludeExtraneousValues: true,
});
}
const payload = {
InquireApplicationRequestDetails: {
ApplicationIdentifier: {
InstitutionCode: this.institutionCode,
ExternalApplicationNumber: externalApplicationNumber,
},
AdditionalData: {
ReturnApplicationType: true,
ReturnApplicationStatus: true,
ReturnCard: true,
ReturnCustomer: true,
},
},
...this.prepareHeaders('InquireApplication'),
};
const response = await this.httpService.axiosRef.post(`${this.baseUrl}/application/InquireApplication`, payload, {
headers: {
'Content-Type': 'application/json',
Authorization: `${this.apiKey}`,
},
});
if (response.data?.[responseKey]) {
return plainToInstance(InquireApplicationResponse, response.data[responseKey], {
excludeExtraneousValues: true,
});
} else {
throw new Error('Invalid response from NeoLeap API');
}
//@TODO handle response
}
private prepareHeaders(serviceName: string): INeoleapHeaderRequest {
return {
RequestHeader: {