forked from Shared/esg
initial commit
This commit is contained in:
245
src/inquiry/inquiry.service.ts
Normal file
245
src/inquiry/inquiry.service.ts
Normal file
@@ -0,0 +1,245 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InquiryType } from '../common/enums/inquiry-type.enum';
|
||||
import { InquiryStatus } from '../common/enums/inquiry-status.enum';
|
||||
import { ProviderName } from '../common/enums/provider-name.enum';
|
||||
import { BaseInquiryResponseDto } from '../common/dto/base-inquiry-response.dto';
|
||||
import { NormalizedErrorDto } from '../common/dto/normalized-error.dto';
|
||||
import { generateTrackingCode } from '../common/helpers/tracking-code.helper';
|
||||
import { InquiryException } from '../common/exceptions/inquiry.exception';
|
||||
import { InquiryLogService } from '../logging/inquiry-log.service';
|
||||
import {
|
||||
LegacyInquiryPayload,
|
||||
PersonInquiryPayload,
|
||||
PersonInquiryResult,
|
||||
} from '../providers/shared/legacy-api.provider.abstract';
|
||||
import { ProviderOrchestratorService } from '../providers/strategy/provider-orchestrator.service';
|
||||
import { PersonInquiryRequestDto } from './dto/person-inquiry-request.dto';
|
||||
import { PersonInquiryDataDto } from './dto/person-inquiry-data.dto';
|
||||
|
||||
@Injectable()
|
||||
export class InquiryService {
|
||||
constructor(
|
||||
private readonly orchestrator: ProviderOrchestratorService,
|
||||
private readonly inquiryLogService: InquiryLogService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Person inquiry — unified business flow with provider fallback and audit logging.
|
||||
*/
|
||||
async inquirePerson(
|
||||
dto: PersonInquiryRequestDto,
|
||||
requestId: string,
|
||||
): Promise<BaseInquiryResponseDto<PersonInquiryDataDto>> {
|
||||
const trackingCode = generateTrackingCode();
|
||||
const payload: PersonInquiryPayload = {
|
||||
nationalCode: dto.nationalCode,
|
||||
birthDate: dto.birthDate,
|
||||
dateHasPostfix: (dto as PersonInquiryRequestDto & { dateHasPostfix?: number }).dateHasPostfix,
|
||||
};
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
try {
|
||||
const result = await this.executeInquiry<PersonInquiryPayload, PersonInquiryResult>(
|
||||
InquiryType.PERSON,
|
||||
payload,
|
||||
requestId,
|
||||
trackingCode,
|
||||
);
|
||||
|
||||
const response = this.buildSuccessResponse(
|
||||
result.data,
|
||||
result.provider,
|
||||
trackingCode,
|
||||
result.duration,
|
||||
'Person inquiry completed successfully',
|
||||
);
|
||||
|
||||
await this.persistLog({
|
||||
inquiryType: InquiryType.PERSON,
|
||||
provider: result.provider,
|
||||
requestPayload: payload as unknown as Record<string, unknown>,
|
||||
responsePayload: response.data as unknown as Record<string, unknown>,
|
||||
status: InquiryStatus.SUCCESS,
|
||||
duration: result.duration,
|
||||
requestId,
|
||||
trackingCode,
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
const duration = Date.now() - start;
|
||||
const normalized = this.extractError(error);
|
||||
|
||||
const response: BaseInquiryResponseDto<PersonInquiryDataDto> = {
|
||||
success: false,
|
||||
provider: 'GATEWAY',
|
||||
trackingCode,
|
||||
message: normalized.message,
|
||||
error: normalized,
|
||||
duration,
|
||||
};
|
||||
|
||||
await this.persistLog({
|
||||
inquiryType: InquiryType.PERSON,
|
||||
provider: ProviderName.HAMTA,
|
||||
requestPayload: payload as unknown as Record<string, unknown>,
|
||||
status: InquiryStatus.FAILURE,
|
||||
duration,
|
||||
requestId,
|
||||
trackingCode,
|
||||
error: normalized as unknown as Record<string, unknown>,
|
||||
}).catch(() => undefined);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
async inquire(
|
||||
inquiryType: InquiryType,
|
||||
payload: LegacyInquiryPayload,
|
||||
requestId: string,
|
||||
): Promise<BaseInquiryResponseDto<Record<string, unknown>>> {
|
||||
const trackingCode = generateTrackingCode();
|
||||
const start = Date.now();
|
||||
|
||||
try {
|
||||
const result = await this.executeInquiry<LegacyInquiryPayload, unknown>(
|
||||
inquiryType,
|
||||
payload,
|
||||
requestId,
|
||||
trackingCode,
|
||||
);
|
||||
|
||||
const response = this.buildGenericSuccessResponse(
|
||||
result.data,
|
||||
result.provider,
|
||||
trackingCode,
|
||||
result.duration,
|
||||
`${this.getInquiryLabel(inquiryType)} completed successfully`,
|
||||
);
|
||||
|
||||
await this.persistLog({
|
||||
inquiryType,
|
||||
provider: result.provider,
|
||||
requestPayload: payload,
|
||||
responsePayload: response.data,
|
||||
status: InquiryStatus.SUCCESS,
|
||||
duration: result.duration,
|
||||
requestId,
|
||||
trackingCode,
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
const duration = Date.now() - start;
|
||||
const normalized = this.extractError(error);
|
||||
|
||||
const response: BaseInquiryResponseDto<Record<string, unknown>> = {
|
||||
success: false,
|
||||
provider: 'GATEWAY',
|
||||
trackingCode,
|
||||
message: normalized.message,
|
||||
error: normalized,
|
||||
duration,
|
||||
};
|
||||
|
||||
await this.persistLog({
|
||||
inquiryType,
|
||||
provider: ProviderName.HAMTA,
|
||||
requestPayload: payload,
|
||||
status: InquiryStatus.FAILURE,
|
||||
duration,
|
||||
requestId,
|
||||
trackingCode,
|
||||
error: normalized as unknown as Record<string, unknown>,
|
||||
}).catch(() => undefined);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
private async executeInquiry<TRequest, TResponse>(
|
||||
inquiryType: InquiryType,
|
||||
payload: TRequest,
|
||||
requestId: string,
|
||||
trackingCode: string,
|
||||
) {
|
||||
return this.orchestrator.executeWithFallback<TRequest, TResponse>(inquiryType, payload, {
|
||||
requestId,
|
||||
trackingCode,
|
||||
});
|
||||
}
|
||||
|
||||
private buildSuccessResponse(
|
||||
result: PersonInquiryResult,
|
||||
provider: string,
|
||||
trackingCode: string,
|
||||
duration: number,
|
||||
message: string,
|
||||
): BaseInquiryResponseDto<PersonInquiryDataDto> {
|
||||
return {
|
||||
success: true,
|
||||
provider,
|
||||
trackingCode,
|
||||
message,
|
||||
duration,
|
||||
data: {
|
||||
nationalCode: result.nationalCode,
|
||||
birthDate: result.birthDate,
|
||||
fullName: result.fullName,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private buildGenericSuccessResponse(
|
||||
result: unknown,
|
||||
provider: string,
|
||||
trackingCode: string,
|
||||
duration: number,
|
||||
message: string,
|
||||
): BaseInquiryResponseDto<Record<string, unknown>> {
|
||||
return {
|
||||
success: true,
|
||||
provider,
|
||||
trackingCode,
|
||||
message,
|
||||
duration,
|
||||
data: this.toResponseData(result),
|
||||
};
|
||||
}
|
||||
|
||||
private toResponseData(result: unknown): Record<string, unknown> {
|
||||
if (result && typeof result === 'object' && 'raw' in result) {
|
||||
const raw = (result as { raw: unknown }).raw;
|
||||
return raw && typeof raw === 'object' ? (raw as Record<string, unknown>) : { raw };
|
||||
}
|
||||
|
||||
return result && typeof result === 'object'
|
||||
? (result as Record<string, unknown>)
|
||||
: { raw: result };
|
||||
}
|
||||
|
||||
private getInquiryLabel(inquiryType: InquiryType): string {
|
||||
return inquiryType.replace(/_INQUIRY$/, '').toLowerCase().replace(/_/g, ' ');
|
||||
}
|
||||
|
||||
private extractError(error: unknown): NormalizedErrorDto {
|
||||
if (error instanceof InquiryException) {
|
||||
return error.normalizedError;
|
||||
}
|
||||
if (error && typeof error === 'object' && 'normalizedError' in error) {
|
||||
return (error as { normalizedError: NormalizedErrorDto }).normalizedError;
|
||||
}
|
||||
return {
|
||||
code: 'INQUIRY_FAILED',
|
||||
message: error instanceof Error ? error.message : 'Inquiry failed',
|
||||
};
|
||||
}
|
||||
|
||||
private async persistLog(
|
||||
input: Parameters<InquiryLogService['create']>[0],
|
||||
): Promise<void> {
|
||||
await this.inquiryLogService.create(input);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user