import { Injectable, BadRequestException } from "@nestjs/common"; import { HttpService } from "@nestjs/axios"; import { Agent } from "https"; import { firstValueFrom } from "rxjs"; import { ETradeCompanyInfo, ETradeBusinessInfo, CompanyRegistrationData, } from "@edr/types"; @Injectable() export class ETradeService { private readonly baseUrl = "https://etrade.gov.et/api"; private readonly referer = "https://etrade.gov.et/business-license-checker"; /** * The eTrade server serves an incomplete TLS chain (it omits the intermediate * CA cert), so Node rejects the handshake with UNABLE_TO_GET_ISSUER_CERT. * Scope a relaxed agent to these outbound calls only — the rest of the app * keeps full certificate verification. */ private readonly httpsAgent = new Agent({ rejectUnauthorized: false }); constructor(private readonly httpService: HttpService) {} async getCompanyInfoByTin(tin: string): Promise { const url = `${this.baseUrl}/Registration/GetRegistrationInfoByTin/${tin}/en`; try { const response = await firstValueFrom( this.httpService.get(url, { headers: { Referer: this.referer }, httpsAgent: this.httpsAgent, }), ); return response.data; } catch (error: any) { throw new BadRequestException( `Failed to fetch company info from eTrade: ${error.message}`, ); } } async getBusinessByLicenseNo( licenseNo: string, tin: string, ): Promise { const url = `${this.baseUrl}/BusinessMain/GetBusinessByLicenseNo`; try { const response = await firstValueFrom( this.httpService.get(url, { params: { LicenseNo: licenseNo, Tin: tin, Lang: "en", }, headers: { Referer: this.referer }, httpsAgent: this.httpsAgent, }), ); return response.data; } catch (error: any) { throw new BadRequestException( `Failed to fetch business info from eTrade: ${error.message}`, ); } } async resolveCompanyData(tin: string): Promise<{ companyInfo: ETradeCompanyInfo; businessInfo: ETradeBusinessInfo | null; }> { const companyInfo = await this.getCompanyInfoByTin(tin); if (!companyInfo.Businesses || companyInfo.Businesses.length === 0) { return { companyInfo, businessInfo: null }; } const latestBusiness = companyInfo.Businesses[0]; try { const businessInfo = await this.getBusinessByLicenseNo( latestBusiness.LicenceNumber, tin, ); return { companyInfo, businessInfo }; } catch { return { companyInfo, businessInfo: null }; } } extractRegistrationData( businessInfo: ETradeBusinessInfo, ): CompanyRegistrationData { const primaryManager = businessInfo.AssociateShortInfos?.[0]; return { licenceNumber: businessInfo.LicenceNumber, statusDescription: businessInfo.StatusDescription, dateRegistered: businessInfo.DateRegistered, renewedFrom: businessInfo.RenewedFrom, renewalDate: businessInfo.RenewalDate, renewedTo: businessInfo.RenewedTo, region: businessInfo.AddressInfo?.Region || "", zone: businessInfo.AddressInfo?.Zone || "", woreda: businessInfo.AddressInfo?.Woreda || "", kebele: businessInfo.AddressInfo?.Kebele || "", houseNo: businessInfo.AddressInfo?.HouseNo || "", mobilePhone: businessInfo.AddressInfo?.MobilePhone || "", regularPhone: businessInfo.AddressInfo?.RegularPhone || "", managerName: primaryManager?.ManagerNameEng || "", managerPhone: primaryManager?.RegularPhone || "", }; } }