forked from Yara724/api
lookups update per client
This commit is contained in:
58
src/fanavaran/fanavaran-lookup.config.ts
Normal file
58
src/fanavaran/fanavaran-lookup.config.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import type { FanavaranClientKey } from "src/core/config/fanavaran-client.config";
|
||||
|
||||
export const FANAVARAN_LOOKUP_BASE_URL =
|
||||
"https://apimanager.iraneit.com/BimeApiManager/api/BimeApi/v2.0";
|
||||
|
||||
export interface FanavaranRemoteLookupDefinition {
|
||||
name: string;
|
||||
url: string;
|
||||
cacheFile: string;
|
||||
}
|
||||
|
||||
/** Fanavaran API lookups synced per client (Parsian fetches on first call). */
|
||||
export const FANAVARAN_REMOTE_LOOKUPS: FanavaranRemoteLookupDefinition[] = [
|
||||
{
|
||||
name: "accident-causes",
|
||||
url: `${FANAVARAN_LOOKUP_BASE_URL}/car/base-info/accident-causes`,
|
||||
cacheFile: "accident-causes.json",
|
||||
},
|
||||
{
|
||||
name: "accident-report-type",
|
||||
url: `${FANAVARAN_LOOKUP_BASE_URL}/car/code-list/accident-report-type`,
|
||||
cacheFile: "accident-report-type.json",
|
||||
},
|
||||
{
|
||||
name: "vehicle-use-types",
|
||||
url: `${FANAVARAN_LOOKUP_BASE_URL}/car/base-info/vehicle-use-types`,
|
||||
cacheFile: "vehicle-use-types.json",
|
||||
},
|
||||
{
|
||||
name: "dmg-pay-method",
|
||||
url: `${FANAVARAN_LOOKUP_BASE_URL}/car/code-list/dmg-pay-method`,
|
||||
cacheFile: "dmg-pay-method.json",
|
||||
},
|
||||
{
|
||||
name: "driving-licence-types",
|
||||
url: `${FANAVARAN_LOOKUP_BASE_URL}/car/base-info/driving-licence-types`,
|
||||
cacheFile: "driving-licence-types.json",
|
||||
},
|
||||
{
|
||||
name: "accident-culprit-type",
|
||||
url: `${FANAVARAN_LOOKUP_BASE_URL}/car/code-list/accident-culprit-type`,
|
||||
cacheFile: "accident-culprit-type.json",
|
||||
},
|
||||
];
|
||||
|
||||
export const TEJARAT_STATIC_ACCIDENT_FILES = {
|
||||
accidentReason: "ACCIDENT_REASON.json",
|
||||
accidentWay: "ACCIDENT_WAY.json",
|
||||
accidentType: "ACCIDENT_TYPE.json",
|
||||
} as const;
|
||||
|
||||
export function fanavaranLookupCacheDir(clientKey: FanavaranClientKey): string {
|
||||
return `${process.cwd()}/files/fanavaran-lookups/${clientKey}`;
|
||||
}
|
||||
|
||||
export function tejaratStaticAccidentFilePath(fileName: string): string {
|
||||
return `${process.cwd()}/src/static/${fileName}`;
|
||||
}
|
||||
10
src/fanavaran/fanavaran-lookup.module.ts
Normal file
10
src/fanavaran/fanavaran-lookup.module.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { HttpModule } from "@nestjs/axios";
|
||||
import { FanavaranLookupService } from "./fanavaran-lookup.service";
|
||||
|
||||
@Module({
|
||||
imports: [HttpModule],
|
||||
providers: [FanavaranLookupService],
|
||||
exports: [FanavaranLookupService],
|
||||
})
|
||||
export class FanavaranLookupModule {}
|
||||
241
src/fanavaran/fanavaran-lookup.service.ts
Normal file
241
src/fanavaran/fanavaran-lookup.service.ts
Normal file
@@ -0,0 +1,241 @@
|
||||
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { HttpService } from "@nestjs/axios";
|
||||
import {
|
||||
BadGatewayException,
|
||||
Injectable,
|
||||
Logger,
|
||||
NotFoundException,
|
||||
} from "@nestjs/common";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { isAxiosError } from "axios";
|
||||
import {
|
||||
getFanavaranClientProfile,
|
||||
type FanavaranClientKey,
|
||||
} from "src/core/config/fanavaran-client.config";
|
||||
import {
|
||||
fanavaranLookupCacheDir,
|
||||
tejaratStaticAccidentFilePath,
|
||||
} from "./fanavaran-lookup.config";
|
||||
|
||||
@Injectable()
|
||||
export class FanavaranLookupService {
|
||||
private readonly logger = new Logger(FanavaranLookupService.name);
|
||||
|
||||
private readonly getAppTokenUrl =
|
||||
"https://apimanager.iraneit.com/BimeApiManager/api/EITAuthentication/GetAppToken";
|
||||
private readonly loginUrl =
|
||||
"https://apimanager.iraneit.com/BimeApiManager/api/EITAuthentication/Login";
|
||||
|
||||
constructor(private readonly httpService: HttpService) {}
|
||||
|
||||
private cacheFilePath(clientKey: FanavaranClientKey, fileName: string): string {
|
||||
return join(fanavaranLookupCacheDir(clientKey), fileName);
|
||||
}
|
||||
|
||||
async readCacheFile<T>(
|
||||
clientKey: FanavaranClientKey,
|
||||
fileName: string,
|
||||
): Promise<T | null> {
|
||||
try {
|
||||
const content = await readFile(
|
||||
this.cacheFilePath(clientKey, fileName),
|
||||
"utf-8",
|
||||
);
|
||||
return JSON.parse(content) as T;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async writeCacheFile(
|
||||
clientKey: FanavaranClientKey,
|
||||
fileName: string,
|
||||
data: unknown,
|
||||
): Promise<void> {
|
||||
const dir = fanavaranLookupCacheDir(clientKey);
|
||||
await mkdir(dir, { recursive: true });
|
||||
await writeFile(
|
||||
join(dir, fileName),
|
||||
`${JSON.stringify(data, null, 2)}\n`,
|
||||
"utf-8",
|
||||
);
|
||||
this.logger.log(
|
||||
`Cached Fanavaran lookup ${fileName} for client ${clientKey}`,
|
||||
);
|
||||
}
|
||||
|
||||
async readTejaratStaticAccidentFile<T>(fileName: string): Promise<T> {
|
||||
const cached = await readFile(tejaratStaticAccidentFilePath(fileName), "utf-8");
|
||||
return JSON.parse(cached) as T;
|
||||
}
|
||||
|
||||
private async getAppToken(config: {
|
||||
appName: string;
|
||||
secret: string;
|
||||
}): Promise<string> {
|
||||
const response = await firstValueFrom(
|
||||
this.httpService.post(this.getAppTokenUrl, "", {
|
||||
headers: {
|
||||
appname: config.appName,
|
||||
secret: config.secret,
|
||||
"Content-Length": "0",
|
||||
},
|
||||
transformRequest: [
|
||||
(_data, headers) => {
|
||||
if (headers) {
|
||||
delete headers["Content-Type"];
|
||||
delete headers["content-type"];
|
||||
}
|
||||
return _data;
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
const appToken =
|
||||
response.headers.apptoken ||
|
||||
response.headers.appToken ||
|
||||
response.headers["apptoken"] ||
|
||||
response.headers["appToken"];
|
||||
|
||||
if (!appToken) {
|
||||
throw new BadGatewayException("Failed to get Fanavaran appToken");
|
||||
}
|
||||
|
||||
return appToken;
|
||||
}
|
||||
|
||||
private async login(
|
||||
appToken: string,
|
||||
config: { username: string; password: string },
|
||||
): Promise<string> {
|
||||
const response = await firstValueFrom(
|
||||
this.httpService.post(this.loginUrl, "", {
|
||||
headers: {
|
||||
appToken,
|
||||
userName: config.username,
|
||||
password: config.password,
|
||||
"Content-Length": "0",
|
||||
},
|
||||
transformRequest: [
|
||||
(_data, headers) => {
|
||||
if (headers) {
|
||||
delete headers["Content-Type"];
|
||||
delete headers["content-type"];
|
||||
}
|
||||
return _data;
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
const authenticationToken =
|
||||
response.headers.authenticationtoken ||
|
||||
response.headers.authenticationToken ||
|
||||
response.headers["authenticationtoken"] ||
|
||||
response.headers["authenticationToken"] ||
|
||||
response.data?.authenticationtoken ||
|
||||
response.data?.authenticationToken ||
|
||||
response.data?.authentication_token;
|
||||
|
||||
if (!authenticationToken) {
|
||||
throw new BadGatewayException("Failed to get Fanavaran authenticationToken");
|
||||
}
|
||||
|
||||
return authenticationToken;
|
||||
}
|
||||
|
||||
async fetchFromFanavaran(
|
||||
clientKey: FanavaranClientKey,
|
||||
url: string,
|
||||
): Promise<unknown> {
|
||||
const profile = getFanavaranClientProfile(clientKey);
|
||||
|
||||
try {
|
||||
const appToken = await this.getAppToken(profile.auth);
|
||||
const authenticationToken = await this.login(appToken, profile.auth);
|
||||
|
||||
const response = await firstValueFrom(
|
||||
this.httpService.get(url, {
|
||||
headers: {
|
||||
authenticationToken,
|
||||
CorpId: profile.auth.corpId,
|
||||
ContractId: profile.auth.contractId,
|
||||
Location: profile.auth.location,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
timeout: 20000,
|
||||
}),
|
||||
);
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
const message = isAxiosError(error)
|
||||
? error.response?.data?.Message ||
|
||||
error.response?.data?.message ||
|
||||
error.message
|
||||
: error instanceof Error
|
||||
? error.message
|
||||
: "Fanavaran lookup request failed";
|
||||
|
||||
this.logger.error(
|
||||
`Fanavaran lookup fetch failed for ${clientKey} (${url}): ${message}`,
|
||||
);
|
||||
throw new BadGatewayException(String(message));
|
||||
}
|
||||
}
|
||||
|
||||
async getRemoteLookup(
|
||||
clientKey: FanavaranClientKey,
|
||||
url: string,
|
||||
cacheFile: string,
|
||||
fallback?: () => Promise<unknown>,
|
||||
): Promise<unknown> {
|
||||
const cached = await this.readCacheFile(clientKey, cacheFile);
|
||||
if (cached !== null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await this.fetchFromFanavaran(clientKey, url);
|
||||
await this.writeCacheFile(clientKey, cacheFile, data);
|
||||
return data;
|
||||
} catch (error) {
|
||||
if (fallback) {
|
||||
this.logger.warn(
|
||||
`Fanavaran lookup fetch failed for ${clientKey}/${cacheFile}; using fallback`,
|
||||
);
|
||||
const data = await fallback();
|
||||
await this.writeCacheFile(clientKey, cacheFile, data);
|
||||
return data;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
mapFanavaranAccidentCausesToReasonOptions(
|
||||
causes: unknown,
|
||||
): { id: number; label: string; fanavaran: number }[] {
|
||||
if (!Array.isArray(causes)) {
|
||||
throw new NotFoundException("Fanavaran accident-causes response is invalid");
|
||||
}
|
||||
|
||||
return causes
|
||||
.filter(
|
||||
(item) =>
|
||||
item &&
|
||||
typeof item === "object" &&
|
||||
(item as { IsActive?: number }).IsActive === 1 &&
|
||||
typeof (item as { Id?: unknown }).Id === "number",
|
||||
)
|
||||
.map((item) => {
|
||||
const row = item as { Id: number; Caption?: string };
|
||||
return {
|
||||
id: row.Id,
|
||||
label: row.Caption ?? String(row.Id),
|
||||
fanavaran: row.Id,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user