forked from Shared/esg
183 lines
5.6 KiB
TypeScript
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);
|
|
}
|
|
}
|