export type FanavaranClientKey = "parsian" | "tejaratno" | "moallem"; export const FANAVARAN_CLIENT_KEYS: readonly FanavaranClientKey[] = [ "parsian", "tejaratno", "moallem", ] as const; /** Swagger `@ApiParam({ enum })` value — keep in sync with {@link FANAVARAN_CLIENT_KEYS}. */ export const FANAVARAN_CLIENT_SWAGGER_ENUM: FanavaranClientKey[] = [ ...FANAVARAN_CLIENT_KEYS, ]; export function isFanavaranClientKey( value: string, ): value is FanavaranClientKey { const normalized = value?.trim().toLowerCase(); return (FANAVARAN_CLIENT_KEYS as readonly string[]).includes(normalized); } export function normalizeFanavaranClientKey(value: string): FanavaranClientKey { const normalized = value?.trim().toLowerCase(); if (isFanavaranClientKey(normalized)) { return normalized; } throw new Error( `Invalid Fanavaran client "${value}". Expected one of: ${FANAVARAN_CLIENT_KEYS.join(", ")}`, ); } export interface FanavaranAuthConfig { appName: string; secret: string; username: string; password: string; corpId: string; contractId: string; /** * Vehicle-hull (بدنه) ContractId. Must not be the ثالث contract. * When unset, body lookups fall back to `contractId`. */ hullContractId?: string; location: string; } export interface FanavaranPayloadDefaults { AccidentCityId: number; AccidentReportTypeId: number; AccidentVehicleUsedId: number; /** * GEN.03 base claim — کارشناس مسئول پرونده مالی * (must NOT be the assessor role used on GEN.08). */ ClaimExpertId: number; /** * GEN.08 expertise — کارشناس ارزیاب خسارت ثالث مالی / وکیل معتمد / کارشناس تحقیق * (Parsian: 29; Tejaratno proven: 2709). */ ExpertiseClaimExpertId: number; /** GEN.06 hull RepairDuration when configured per tenant (optional). */ HullExpertiseRepairDuration?: number | null; CompensationReferenceId: number; CulpritLicenceTypeId: number; CulpritTypeId: number; DmgCaseTypeId: number; DmgHistoryStatus: number; PlaqueKindId: number; PlaqueSampleId: number; DriverIsOwner: number; FaultPercent: number; ClaimFileTypeId: number; } export interface FanavaranClientProfile { key: FanavaranClientKey; auth: FanavaranAuthConfig; defaults: FanavaranPayloadDefaults; } /** * Shared codebook-ish defaults. Each tenant must override ClaimExpertId / * ExpertiseClaimExpertId (they are different Fanavaran roles). */ const SHARED_FANAVARAN_DEFAULTS: FanavaranPayloadDefaults = { AccidentCityId: 701, AccidentReportTypeId: 155, AccidentVehicleUsedId: 1, ClaimExpertId: 4543092, ExpertiseClaimExpertId: 2709, CompensationReferenceId: 167, CulpritLicenceTypeId: 2, CulpritTypeId: 337, DmgCaseTypeId: 175, DmgHistoryStatus: 5214, PlaqueKindId: 8, PlaqueSampleId: 10, DriverIsOwner: 0, FaultPercent: 100, ClaimFileTypeId: 23, }; /** * Seed / code fallback profiles. On app boot these are inserted into * `fanavaranClientConfigs` only when a key is missing (never overwrite DB edits). * Runtime reads prefer the in-memory cache loaded from Mongo. */ export const SEED_FANAVARAN_CLIENT_PROFILES: Record< FanavaranClientKey, FanavaranClientProfile > = { tejaratno: { key: "tejaratno", auth: { appName: "fanhab", secret: "5Fa@N#A2B", username: "fanhabUser", password: "Fan#@2U$3er", corpId: "3539", contractId: "263", location: "100", }, defaults: { ...SHARED_FANAVARAN_DEFAULTS, // GEN.03 — کارشناس مسئول پرونده مالی ClaimExpertId: 2721, // GEN.08 — ارزیاب (proven successful submit 2026-07-18 ClaimExpertId: 2709) ExpertiseClaimExpertId: 2709, ClaimFileTypeId: 23, }, }, parsian: { key: "parsian", auth: { appName: "ParsianService", secret: "P@r30@n$erv!ce", username: "ParsianServiceUser", password: "P@r30@n123", corpId: "543", contractId: "28", location: "210050", }, defaults: { ...SHARED_FANAVARAN_DEFAULTS, // GEN.03 — مسئول پرونده مالی (Fanavaran example used 154; west branch 4662) ClaimExpertId: 154, // GEN.08 — ارزیاب خسارت ثالث مالی (رسول کرکی / شعبه غرب → 29) ExpertiseClaimExpertId: 29, // GEN.07 — proven 2026-08-03 (CL68535): 63 = سایر مدارک خسارت in parsian file-types. // Do not use 70 — not in Parsian lookup → "نوع فايل با منبع لوکاپ مطابقت ندارد". ClaimFileTypeId: 63, }, }, moallem: { key: "moallem", auth: { appName: "ItTalie", secret: "itT@l!3@api", username: "itTalieUser", password: "itT@l!3@user", corpId: "5650", contractId: "304", location: "1", }, // Expert role ids not confirmed for Moallem yet — start from shared shape. defaults: { ...SHARED_FANAVARAN_DEFAULTS, }, }, }; /** @deprecated Use SEED_FANAVARAN_CLIENT_PROFILES — kept alias for older imports. */ export const FANAVARAN_CLIENT_PROFILES = SEED_FANAVARAN_CLIENT_PROFILES; /** * Runtime cache filled by FanavaranClientConfigService on boot from Mongo. * Until then (and in unit tests), callers fall back to seed profiles. */ let runtimeProfiles: Partial< Record > | null = null; export function setFanavaranClientProfilesCache( profiles: Partial>, ): void { runtimeProfiles = profiles; } export function clearFanavaranClientProfilesCache(): void { runtimeProfiles = null; } /** Resolve active Fanavaran tenant from env (`FANAVARAN_CLIENT`) with optional CLIENT_ID fallback. */ export function resolveFanavaranClientKey(): FanavaranClientKey { const explicit = process.env.FANAVARAN_CLIENT?.trim().toLowerCase(); if (explicit && isFanavaranClientKey(explicit)) { return explicit; } // Optional deployment hint when FANAVARAN_CLIENT is not set. if (String(process.env.CLIENT_ID ?? "") === "8") { return "parsian"; } return "tejaratno"; } export function resolveFanavaranClientProfile(): FanavaranClientProfile { return getFanavaranClientProfile(resolveFanavaranClientKey()); } export function getFanavaranClientProfile( clientKey: FanavaranClientKey, ): FanavaranClientProfile { return ( runtimeProfiles?.[clientKey] ?? SEED_FANAVARAN_CLIENT_PROFILES[clientKey] ); } /** ثالث uses `contractId`. بدنه uses `hullContractId` when configured. */ export function resolveFanavaranProductContractId( clientKey: FanavaranClientKey, product: "third-party" | "car-body", ): string { const profile = getFanavaranClientProfile(clientKey); if (product === "car-body") { const hull = profile.auth.hullContractId?.trim(); if (hull) return hull; } return profile.auth.contractId; } export function listFanavaranClientProfiles(): FanavaranClientProfile[] { return FANAVARAN_CLIENT_KEYS.map((key) => getFanavaranClientProfile(key)); } export function fanavaranPreviewPath( clientKey: FanavaranClientKey, claimCaseId: string, ): string { return `/v2/fanavaran/${clientKey}/claim-cases/${claimCaseId}/base-claim/preview`; } export function fanavaranSubmitPath( clientKey: FanavaranClientKey, claimCaseId: string, ): string { return `/v2/fanavaran/${clientKey}/claim-cases/${claimCaseId}/base-claim/submit`; } export function fanavaranManualSubmitPath(claimCaseId: string): string { return fanavaranSubmitPath(resolveFanavaranClientKey(), claimCaseId); }