Files
esg/src/inquiry/inquiry.service.ts

183 lines
5.6 KiB
TypeScript

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 { buildInquiryResponse } from '../common/helpers/inquiry-response.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,
) {}
async inquirePerson(
dto: PersonInquiryRequestDto,
requestId: string,
): Promise<BaseInquiryResponseDto<PersonInquiryDataDto>> {
return this.inquire(
InquiryType.PERSON,
{
nationalCode: dto.nationalCode,
birthDate: dto.birthDate,
dateHasPostfix: dto.dateHasPostfix,
},
requestId,
) as unknown as Promise<BaseInquiryResponseDto<PersonInquiryDataDto>>;
}
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 = buildInquiryResponse({
success: true,
provider: result.provider,
trackingCode,
message: `${this.getInquiryLabel(inquiryType)} completed successfully`,
duration: result.duration,
data: this.toResponseData(result.data),
});
await this.persistLog({
inquiryType,
provider: result.provider,
requestPayload: payload,
responsePayload: response.data ?? undefined,
status: InquiryStatus.SUCCESS,
duration: result.duration,
requestId,
trackingCode,
});
return response;
} catch (error) {
const duration = Date.now() - start;
const { normalized, provider } = this.extractFailure(error);
const response = buildInquiryResponse({
success: false,
provider: provider ?? 'GATEWAY',
trackingCode,
message: normalized.message,
duration,
error: normalized,
});
await this.persistLog({
inquiryType,
provider: (provider as ProviderName | undefined) ?? 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 toResponseData(result: unknown): Record<string, unknown> {
if (this.isPersonInquiryResult(result)) {
const raw =
result.raw && typeof result.raw === 'object' && !Array.isArray(result.raw)
? (result.raw as Record<string, unknown>)
: {};
return {
nationalCode: result.nationalCode,
birthDate: result.birthDate,
...(result.fullName ? { fullName: result.fullName } : {}),
...raw,
};
}
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 isPersonInquiryResult(result: unknown): result is PersonInquiryResult {
return (
typeof result === 'object' &&
result !== null &&
'nationalCode' in result &&
'birthDate' in result
);
}
private getInquiryLabel(inquiryType: InquiryType): string {
return inquiryType.replace(/_INQUIRY$/, '').toLowerCase().replace(/_/g, ' ');
}
private extractFailure(error: unknown): {
normalized: NormalizedErrorDto;
provider?: string;
} {
if (error instanceof InquiryException) {
return { normalized: error.normalizedError, provider: error.provider };
}
if (error && typeof error === 'object' && 'normalizedError' in error) {
return {
normalized: (error as { normalizedError: NormalizedErrorDto }).normalizedError,
};
}
return {
normalized: {
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);
}
}