update the fanavaran which accepts unknown person too

This commit is contained in:
2026-09-14 13:42:53 +03:30
parent 6e5b7cb1fd
commit b13b0211ad
9 changed files with 758 additions and 4 deletions

View File

@@ -185,7 +185,10 @@ import {
import { FanavaranAuditService } from "src/fanavaran/fanavaran-audit.service";
import { FanavaranAuthService } from "src/fanavaran/fanavaran-auth.service";
import { FanavaranLookupService } from "src/fanavaran/fanavaran-lookup.service";
import { FANAVARAN_REMOTE_LOOKUPS } from "src/fanavaran/fanavaran-lookup.config";
import {
FANAVARAN_LOOKUP_BASE_URL,
FANAVARAN_REMOTE_LOOKUPS,
} from "src/fanavaran/fanavaran-lookup.config";
import type { FanavaranAuditSession } from "src/fanavaran/fanavaran-audit.types";
import {
FanavaranAuditSource,
@@ -207,6 +210,10 @@ import {
pickPersonNationalCode,
selectFanavaranDriverId,
} from "./fanavaran-driver-inquiry";
import {
buildFanavaranOtherPeoplePayload,
pickFanavaranRecordId,
} from "./fanavaran-other-people";
import {
asObjectRecord,
collectPartyVinCandidates,
@@ -4127,6 +4134,8 @@ export class ClaimRequestManagementService {
DriverIsOwner: number;
FaultPercent: number;
};
/** GEN.44 write: register the damaged party in Fanavaran when inquiry misses. */
registerMissingPerson?: boolean;
}): Promise<Record<string, unknown>> {
const damagedParty = this.pickDamagedPartyForFanavaran(
input.blameCase,
@@ -4288,9 +4297,11 @@ export class ClaimRequestManagementService {
// Prefer claim-level cache, then party.person.fanavaranDriverId, then live inquiry, then last payload
let driverFanavaranId = this.firstPositiveFanavaranId(
cachedDamage.driverId,
cachedDamage.otherPersonId,
person.fanavaranDriverId,
lastDamagePayload?.DriverId,
);
let otherPersonId = this.firstPositiveFanavaranId(cachedDamage.otherPersonId);
if (driverFanavaranId) {
this.logger.log(
@@ -4304,6 +4315,20 @@ export class ClaimRequestManagementService {
input.claimCase,
);
if (!driverFanavaranId && input.registerMissingPerson) {
const registered = await this.registerFanavaranOtherPerson({
clientKey: input.clientKey,
person,
claimCaseId: input.claimCase?._id
? String(input.claimCase._id)
: undefined,
});
if (registered != null) {
driverFanavaranId = registered;
otherPersonId = registered;
}
}
// Persist the resolved ID back to the blame case party for future use
if (driverFanavaranId && input.blameCase?._id && damagedParty) {
const partyIndex = (input.blameCase.parties ?? []).findIndex(
@@ -4473,6 +4498,9 @@ export class ClaimRequestManagementService {
...(driverFanavaranId != null
? { "fanavaranSync.damageCase.driverId": driverFanavaranId }
: {}),
...(otherPersonId != null
? { "fanavaranSync.damageCase.otherPersonId": otherPersonId }
: {}),
...(vehicleKindId != null
? { "fanavaranSync.damageCase.vehicleKindId": vehicleKindId }
: {}),
@@ -5075,6 +5103,158 @@ export class ClaimRequestManagementService {
return null;
}
private async loadFanavaranOtherPeopleLookups(
clientKey: FanavaranClientKey,
): Promise<{
cities: unknown[];
gender: unknown[];
maritalStatus: unknown[];
ans: unknown[];
countries: unknown[];
personKind: unknown[];
}> {
const [cities, gender, maritalStatus, ans, countries, personKind] =
await Promise.all([
this.getFanavaranLookupRows(clientKey, "cities"),
this.getFanavaranLookupRows(clientKey, "gender"),
this.getFanavaranLookupRows(clientKey, "marital-status"),
this.getFanavaranLookupRows(clientKey, "ans"),
this.getFanavaranLookupRows(clientKey, "countries"),
this.getFanavaranLookupRows(clientKey, "person-kind"),
]);
return { cities, gender, maritalStatus, ans, countries, personKind };
}
/**
* GEN.44: create the damaged party in Fanavaran when parties inquiry has no row.
* Failures stay best-effort — GEN.12 submit continues without DriverId.
*/
private async registerFanavaranOtherPerson(input: {
clientKey: FanavaranClientKey;
person: any;
claimCaseId?: string;
}): Promise<number | null> {
const nationalCode = pickPersonNationalCode(input.person);
const birthday = pickPersonBirthday(input.person);
if (!nationalCode || !parseJalaliDateParts(birthday)) {
this.logger.warn(
`[registerFanavaranOtherPerson] SKIP: missing nationalCode or birthday`,
);
return null;
}
let user: {
fullName?: string;
mobile?: string;
city?: string;
address?: string;
gender?: string;
} | null = null;
const userId = input.person?.userId;
if (userId && Types.ObjectId.isValid(String(userId))) {
try {
user = await this.userDbService.findOne({
_id: new Types.ObjectId(String(userId)),
});
} catch (error) {
this.logger.warn(
`[registerFanavaranOtherPerson] user lookup failed: ${
error instanceof Error ? error.message : error
}`,
);
}
}
const lookups = await this.loadFanavaranOtherPeopleLookups(input.clientKey);
const payload = buildFanavaranOtherPeoplePayload(
{
nationalCode,
birthday,
fullName: input.person?.fullName ?? user?.fullName,
mobile: input.person?.phoneNumber ?? user?.mobile,
address: user?.address,
cityName: user?.city,
gender: user?.gender,
},
lookups,
);
if (!payload) {
this.logger.warn(
`[registerFanavaranOtherPerson] SKIP: could not build GEN.44 payload for nationalCode=${nationalCode}`,
);
return null;
}
const url = `${FANAVARAN_LOOKUP_BASE_URL}/common/other-people`;
const startedAt = Date.now();
const auditSession: FanavaranAuditSession = {
trackingCode: this.fanavaranAuditService.generateTrackingCode(),
clientKey: input.clientKey,
source: FanavaranAuditSource.AUTO_SUBMIT,
claimCaseId: input.claimCaseId,
};
await this.fanavaranAuditService.recordStep({
session: auditSession,
step: FanavaranAuditStep.CREATE_OTHER_PERSON,
status: FanavaranAuditStatus.STARTED,
requestUrl: url,
requestMethod: "POST",
requestBody: payload,
requestMeta: { nationalCode },
});
try {
const created = await this.fanavaranLookupService.createOtherPerson(
input.clientKey,
payload,
);
const personId = pickFanavaranRecordId(created);
await this.fanavaranAuditService.recordStep({
session: auditSession,
step: FanavaranAuditStep.CREATE_OTHER_PERSON,
status: FanavaranAuditStatus.SUCCESS,
requestUrl: url,
requestMethod: "POST",
requestBody: payload,
responseBody: created,
responseMeta: { otherPersonId: personId, nationalCode },
durationMs: Date.now() - startedAt,
});
if (personId != null) {
this.logger.log(
`[registerFanavaranOtherPerson] CREATED Id=${personId} for nationalCode=${nationalCode}`,
);
return personId;
}
this.logger.warn(
`[registerFanavaranOtherPerson] create returned no Id for nationalCode=${nationalCode}; retrying inquiry`,
);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
await this.fanavaranAuditService.recordStep({
session: auditSession,
step: FanavaranAuditStep.CREATE_OTHER_PERSON,
status: FanavaranAuditStatus.FAILURE,
requestUrl: url,
requestMethod: "POST",
requestBody: payload,
errorMessage: message,
durationMs: Date.now() - startedAt,
});
this.logger.warn(
`[registerFanavaranOtherPerson] CREATE failed for nationalCode=${nationalCode}: ${message}; retrying inquiry`,
);
}
return this.resolveDriverFanavaranId(
input.clientKey,
nationalCode,
birthday,
input.person?.driverIsInsurer,
);
}
/**
* زیان‌دیده for GEN.12: claim owner when linked to a blame party,
* else the party that is not the guilty one.
@@ -5521,6 +5701,16 @@ export class ClaimRequestManagementService {
defaults: profile.defaults,
});
const warnings: string[] = [];
if (!claimCase.claimId) {
warnings.push("Fanavaran base claimId is required before submit.");
}
if (payload.DriverId == null) {
warnings.push(
"Damaged party is not in Fanavaran yet; submit will register them via other-people (GEN.44).",
);
}
return {
clientKey,
claimCaseId,
@@ -5529,9 +5719,7 @@ export class ClaimRequestManagementService {
submitUrl: claimCase.claimId
? `${this.FANAVARAN_SUBMIT_URL}/${claimCase.claimId}/dmg-cases`
: null,
warning: claimCase.claimId
? undefined
: "Fanavaran base claimId is required before submit.",
warning: warnings.length ? warnings.join(" ") : undefined,
payload,
};
}
@@ -7021,6 +7209,7 @@ export class ClaimRequestManagementService {
selectedParts: selectedParts ?? claimCase.damage?.selectedParts ?? [],
clientKey,
defaults: profile.defaults,
registerMissingPerson: true,
});
// Guardrail: never send empty/null licence fields even if manual overrides arrive.

View File

@@ -89,6 +89,10 @@ export class FanavaranSyncStage {
@Prop({ type: Number })
driverId?: number;
/** Cached GEN.44 other-people Id when the person was created because inquiry missed. */
@Prop({ type: Number })
otherPersonId?: number;
/** Cached Fanavaran VehicleKindId. */
@Prop({ type: Number })
vehicleKindId?: number;

View File

@@ -0,0 +1,80 @@
import {
buildFanavaranOtherPeoplePayload,
pickFanavaranRecordId,
pickLookupIdByCaption,
splitPersianFullName,
} from "./fanavaran-other-people";
describe("fanavaran other people (GEN.44)", () => {
it("builds a civil-registry create payload from local case + user fields", () => {
const payload = buildFanavaranOtherPeoplePayload(
{
nationalCode: "3392645966",
birthday: "1364/09/01",
fullName: "الهام مهدوی نیا",
mobile: "9366666666",
address: "گاندی ک نهم",
cityName: "تهران",
gender: "female",
},
{
cities: [{ Id: 9131, Caption: "تهران", IsActive: 1 }],
gender: [
{ Id: 26, Caption: "مرد", IsActive: 1 },
{ Id: 27, Caption: "زن", IsActive: 1 },
],
ans: [
{ Id: 1, Caption: "بله", IsActive: 1 },
{ Id: 0, Caption: "خیر", IsActive: 1 },
],
personKind: [{ Id: 46, Caption: "حقیقی", IsActive: 1 }],
},
);
expect(payload).toMatchObject({
NationalCode: "3392645966",
Name: "الهام",
LastName: "مهدوی نیا",
BirthYear: 1364,
BirthMonth: 9,
BirthDay: 1,
Mobile: "09366666666",
Address: "گاندی ک نهم",
CityId: 9131,
GenderId: 27,
IsIranian: 1,
PersonKindId: 46,
ADBirthYear: null,
NationalityId: null,
});
});
it("returns null when national code or birthday is missing", () => {
expect(
buildFanavaranOtherPeoplePayload({
nationalCode: "3392645966",
}),
).toBeNull();
});
it("picks the created person Id from a wrapped Fanavaran response", () => {
expect(pickFanavaranRecordId({ data: { Id: 4553876 } })).toBe(4553876);
expect(pickFanavaranRecordId([{ Id: "4553876" }])).toBe(4553876);
});
it("matches lookup captions ignoring yeh/keheh and extra spaces", () => {
expect(
pickLookupIdByCaption(
[{ Id: 701, Caption: "ايران", IsActive: 1 }],
["ایران"],
),
).toBe(701);
});
it("splits a Persian full name into first and last name", () => {
expect(splitPersianFullName("الهام مهدوی نیا")).toEqual({
name: "الهام",
lastName: "مهدوی نیا",
});
});
});

View File

@@ -0,0 +1,252 @@
import { toEnglishDigits } from "src/lookups/fanavaran-last-car-policy";
import {
parseJalaliDateParts,
pickPersonBirthday,
pickPersonNationalCode,
} from "./fanavaran-driver-inquiry";
export type FanavaranLookupRow = {
Id?: unknown;
Caption?: unknown;
Name?: unknown;
IsActive?: unknown;
};
export type FanavaranOtherPeopleLookups = {
cities?: unknown;
gender?: unknown;
maritalStatus?: unknown;
ans?: unknown;
countries?: unknown;
personKind?: unknown;
};
export type FanavaranOtherPeopleSource = {
nationalCode?: unknown;
birthday?: unknown;
fullName?: unknown;
fatherName?: unknown;
mobile?: unknown;
tel?: unknown;
email?: unknown;
address?: unknown;
jobAddress?: unknown;
postalCode?: unknown;
cityName?: unknown;
gender?: unknown;
isIranian?: boolean;
naturalizedCode?: unknown;
identityNo?: unknown;
identityNoIssuPlace?: unknown;
passportNo?: unknown;
companyCode?: unknown;
economicCode?: unknown;
registerNo?: unknown;
};
export type FanavaranOtherPeoplePayload = {
NationalCode: string | null;
Name: string | null;
LastName: string | null;
FatherName: string | null;
BirthYear: number | null;
BirthMonth: number | null;
BirthDay: number | null;
ADBirthYear: null;
ADBirthMonth: null;
ADBirthDay: null;
IdentityNoIssuPlace: string | null;
PassportNo: string | null;
Address: string | null;
PostalCode: string | null;
Tel: string | null;
Mobile: string | null;
Email: string | null;
JobAddress: string | null;
EconomicCode: string | null;
NaturalizedCode: string | null;
CompanyCode: string | null;
IdentityNo: string | null;
RegisterNo: string | null;
CityId: number | null;
GenderId: number | null;
MaritalStatus: number | null;
IsIranian: number | string | null;
NationalityId: number | null;
PersonKindId: number | null;
};
const GENDER_MALE_TEXTS = ["مرد", "آقا", "male", "m"];
const GENDER_FEMALE_TEXTS = ["زن", "خانم", "female", "f"];
const ANS_YES_TEXTS = ["بله", "بلی", "yes", "1"];
const NATURAL_PERSON_TEXTS = ["حقیقی", "شخص حقیقی", "طبيعي", "natural"];
const IRAN_COUNTRY_TEXTS = ["ایران", "ايران", "iran"];
function asLookupRows(value: unknown): FanavaranLookupRow[] {
if (!Array.isArray(value)) return [];
return value.filter(
(row): row is FanavaranLookupRow =>
!!row && typeof row === "object" && !Array.isArray(row),
);
}
function asPositiveId(value: unknown): number | null {
if (value === null || value === undefined) return null;
const id = Number(value);
return Number.isFinite(id) && id > 0 ? id : null;
}
function normalizeLookupText(value: unknown): string {
return toEnglishDigits(value)
.toLowerCase()
.replace(/[ي]/g, "ی")
.replace(/[ك]/g, "ک")
.replace(/[\u200c\s_\-\/]+/g, "")
.replace(/[^\p{L}\p{N}]/gu, "");
}
function lookupRowId(row: FanavaranLookupRow): number | null {
return asPositiveId(row.Id);
}
function lookupRowTexts(row: FanavaranLookupRow): string[] {
return [row.Caption, row.Name]
.filter((value): value is string => typeof value === "string")
.filter(Boolean);
}
export function pickLookupIdByCaption(
rows: unknown,
texts: unknown[],
): number | null {
const wanted = texts
.map((text) => normalizeLookupText(text))
.filter(Boolean);
if (!wanted.length) return null;
for (const row of asLookupRows(rows)) {
if (row.IsActive === 0) continue;
const rowTexts = lookupRowTexts(row).map(normalizeLookupText);
const matched = rowTexts.some((rowText) =>
wanted.some(
(want) =>
rowText === want || rowText.includes(want) || want.includes(rowText),
),
);
if (matched) return lookupRowId(row);
}
return null;
}
export function splitPersianFullName(
fullName: unknown,
): { name: string | null; lastName: string | null } {
const trimmed = String(fullName ?? "").trim().replace(/\s+/g, " ");
if (!trimmed) return { name: null, lastName: null };
const parts = trimmed.split(" ");
if (parts.length === 1) return { name: parts[0], lastName: null };
return { name: parts[0], lastName: parts.slice(1).join(" ") };
}
export function normalizeIranMobile(value: unknown): string | null {
const digits = toEnglishDigits(value).replace(/\D/g, "");
if (!digits) return null;
if (digits.length === 10 && digits.startsWith("9")) return `0${digits}`;
if (digits.length === 11 && digits.startsWith("09")) return digits;
if (digits.length === 12 && digits.startsWith("989")) {
return `0${digits.slice(2)}`;
}
return digits.length >= 8 ? digits : null;
}
export function pickFanavaranRecordId(value: unknown): number | null {
if (value == null) return null;
if (typeof value === "number" || typeof value === "string") {
return asPositiveId(value);
}
if (Array.isArray(value)) {
for (const item of value) {
const id = pickFanavaranRecordId(item);
if (id != null) return id;
}
return null;
}
if (typeof value !== "object") return null;
const record = value as Record<string, unknown>;
const direct = asPositiveId(record.Id ?? record.id);
if (direct != null) return direct;
for (const key of ["value", "Value", "data", "Data", "item", "Item"]) {
const nested = pickFanavaranRecordId(record[key]);
if (nested != null) return nested;
}
return null;
}
function emptyToNull(value: unknown): string | null {
if (value == null) return null;
const text = String(value).trim();
return text ? text : null;
}
export function buildFanavaranOtherPeoplePayload(
source: FanavaranOtherPeopleSource,
lookups: FanavaranOtherPeopleLookups = {},
): FanavaranOtherPeoplePayload | null {
const nationalCode = pickPersonNationalCode({
nationalCode: source.nationalCode,
nationalCodeOfDriver: source.nationalCode,
});
const birthday = parseJalaliDateParts(
source.birthday ?? pickPersonBirthday({ birthday: source.birthday }),
);
if (!nationalCode || !birthday) return null;
const isIranian =
source.isIranian !== false && !emptyToNull(source.naturalizedCode);
const names = splitPersianFullName(source.fullName);
const genderTexts =
source.gender === "male" || source.gender === "m"
? GENDER_MALE_TEXTS
: source.gender === "female" || source.gender === "f"
? GENDER_FEMALE_TEXTS
: [source.gender];
return {
NationalCode: nationalCode,
Name: names.name,
LastName: names.lastName,
FatherName: emptyToNull(source.fatherName),
BirthYear: birthday.year,
BirthMonth: birthday.month,
BirthDay: birthday.day,
ADBirthYear: null,
ADBirthMonth: null,
ADBirthDay: null,
IdentityNoIssuPlace: emptyToNull(source.identityNoIssuPlace),
PassportNo: emptyToNull(source.passportNo),
Address: emptyToNull(source.address),
PostalCode: emptyToNull(source.postalCode),
Tel: normalizeIranMobile(source.tel) ?? emptyToNull(source.tel),
Mobile: normalizeIranMobile(source.mobile),
Email: emptyToNull(source.email),
JobAddress: emptyToNull(source.jobAddress),
EconomicCode: emptyToNull(source.economicCode),
NaturalizedCode: emptyToNull(source.naturalizedCode),
CompanyCode: emptyToNull(source.companyCode),
IdentityNo: emptyToNull(source.identityNo),
RegisterNo: emptyToNull(source.registerNo),
CityId: pickLookupIdByCaption(lookups.cities, [source.cityName]),
GenderId: pickLookupIdByCaption(lookups.gender, genderTexts),
MaritalStatus: pickLookupIdByCaption(lookups.maritalStatus, []),
IsIranian: isIranian
? (pickLookupIdByCaption(lookups.ans, ANS_YES_TEXTS) ?? 1)
: (pickLookupIdByCaption(lookups.ans, ["خیر", "no", "0"]) ?? 0),
NationalityId: isIranian
? null
: pickLookupIdByCaption(lookups.countries, IRAN_COUNTRY_TEXTS),
PersonKindId: pickLookupIdByCaption(
lookups.personKind,
NATURAL_PERSON_TEXTS,
),
};
}

View File

@@ -117,6 +117,36 @@ export const FANAVARAN_REMOTE_LOOKUPS: FanavaranRemoteLookupDefinition[] = [
url: `${FANAVARAN_LOOKUP_BASE_URL}/car/code-list/dmg-business-line`,
cacheFile: "dmg-business-line.json",
},
{
name: "gender",
url: `${FANAVARAN_LOOKUP_BASE_URL}/common/code-list/gender`,
cacheFile: "gender.json",
},
{
name: "marital-status",
url: `${FANAVARAN_LOOKUP_BASE_URL}/common/code-list/marital-status`,
cacheFile: "marital-status.json",
},
{
name: "ans",
url: `${FANAVARAN_LOOKUP_BASE_URL}/common/code-list/ans`,
cacheFile: "ans.json",
},
{
name: "countries",
url: `${FANAVARAN_LOOKUP_BASE_URL}/common/base-info/countries`,
cacheFile: "countries.json",
},
{
name: "person-kind",
url: `${FANAVARAN_LOOKUP_BASE_URL}/common/code-list/person-kind`,
cacheFile: "person-kind.json",
},
{
name: "cii-validation-status",
url: `${FANAVARAN_LOOKUP_BASE_URL}/common/code-list/cii-validation-status`,
cacheFile: "cii-validation-status.json",
},
];
export const TEJARAT_STATIC_ACCIDENT_FILES = {

View File

@@ -315,6 +315,63 @@ export class FanavaranLookupService {
return this.fetchFromFanavaran(clientKey, url);
}
async getOtherPerson(
clientKey: FanavaranClientKey,
personId: number,
): Promise<unknown> {
const url = `${FANAVARAN_LOOKUP_BASE_URL}/common/other-people/${personId}`;
return this.fetchFromFanavaran(clientKey, url);
}
async createOtherPerson(
clientKey: FanavaranClientKey,
payload: Record<string, unknown>,
): Promise<unknown> {
const url = `${FANAVARAN_LOOKUP_BASE_URL}/common/other-people`;
return this.postToFanavaran(clientKey, url, payload);
}
async postToFanavaran(
clientKey: FanavaranClientKey,
url: string,
payload: Record<string, unknown>,
): Promise<unknown> {
try {
const headers = await this.fanavaranAuthService.getRequestHeaders(
clientKey,
);
this.logger.log(`[${clientKey}] POST Fanavaran: ${url}`);
const response = await firstValueFrom(
this.httpService.post(url, payload, {
headers: {
...headers,
"Content-Type": "application/json",
},
timeout: 20000,
}),
);
this.fanavaranAuthService.clearBackoff(clientKey);
return response.data;
} catch (error) {
this.fanavaranAuthService.registerFailure(clientKey, error);
const message = isAxiosError(error)
? error.response?.data?.Message ||
error.response?.data?.message ||
error.message
: error instanceof Error
? error.message
: "Fanavaran POST request failed";
this.logger.error(
`Fanavaran POST failed for ${clientKey} (${url}): ${message}`,
);
throw new BadGatewayException(String(message));
}
}
async resolveInsuranceCorpId(
clientKey: FanavaranClientKey,
): Promise<number | null> {

View File

@@ -8,6 +8,7 @@ export enum FanavaranAuditStep {
POLICY_INQUIRY = "POLICY_INQUIRY",
BUILD_PAYLOAD = "BUILD_PAYLOAD",
SUBMIT_CLAIM = "SUBMIT_CLAIM",
CREATE_OTHER_PERSON = "CREATE_OTHER_PERSON",
SUBMIT_DAMAGE_CASE = "SUBMIT_DAMAGE_CASE",
SUBMIT_ATTACHMENT = "SUBMIT_ATTACHMENT",
SUBMIT_EXPERTISE = "SUBMIT_EXPERTISE",

View File

@@ -327,6 +327,90 @@ export class LookupsController {
return await this.lookupsService.getDmgBusinessLine();
}
@Get("gender")
@ApiOperation({
summary: "Fanavaran GEN.44 gender lookup",
description:
"Returns values for other-people payload field GenderId from common/code-list/gender.",
})
@ApiOkResponse({
description: "Returns Fanavaran gender lookup data",
schema: { type: "array", items: { type: "object" } },
})
async getGender() {
return await this.lookupsService.getGender();
}
@Get("marital-status")
@ApiOperation({
summary: "Fanavaran GEN.44 marital status lookup",
description:
"Returns values for other-people payload field MaritalStatus from common/code-list/marital-status.",
})
@ApiOkResponse({
description: "Returns Fanavaran marital status lookup data",
schema: { type: "array", items: { type: "object" } },
})
async getMaritalStatus() {
return await this.lookupsService.getMaritalStatus();
}
@Get("ans")
@ApiOperation({
summary: "Fanavaran GEN.44 yes/no lookup",
description:
"Returns values for other-people fields IsIranian / IsValid / IsVerified from common/code-list/ans.",
})
@ApiOkResponse({
description: "Returns Fanavaran yes/no (ans) lookup data",
schema: { type: "array", items: { type: "object" } },
})
async getAns() {
return await this.lookupsService.getAns();
}
@Get("countries")
@ApiOperation({
summary: "Fanavaran GEN.44 countries lookup",
description:
"Returns values for other-people payload field NationalityId from common/base-info/countries.",
})
@ApiOkResponse({
description: "Returns Fanavaran countries lookup data",
schema: { type: "array", items: { type: "object" } },
})
async getCountries() {
return await this.lookupsService.getCountries();
}
@Get("person-kind")
@ApiOperation({
summary: "Fanavaran GEN.44 person kind lookup",
description:
"Returns values for other-people payload field PersonKindId from common/code-list/person-kind.",
})
@ApiOkResponse({
description: "Returns Fanavaran person kind lookup data",
schema: { type: "array", items: { type: "object" } },
})
async getPersonKind() {
return await this.lookupsService.getPersonKind();
}
@Get("cii-validation-status")
@ApiOperation({
summary: "Fanavaran GEN.44 CII validation status lookup",
description:
"Returns values for other-people response fields CIIValidationStatus / CIIMobileStatus from common/code-list/cii-validation-status.",
})
@ApiOkResponse({
description: "Returns Fanavaran CII validation status lookup data",
schema: { type: "array", items: { type: "object" } },
})
async getCiiValidationStatus() {
return await this.lookupsService.getCiiValidationStatus();
}
@Get("inquiry-by-vin")
@ApiOperation({
summary: "Fanavaran vehicle inquiry by VIN",
@@ -382,6 +466,25 @@ export class LookupsController {
});
}
@Get("other-people/:personId")
@ApiOperation({
summary: "Fanavaran GEN.44 other person by id",
description:
"GET common/other-people/{Id}. Use after parties inquiry misses and GEN.44 create, or to inspect a known person Id.",
})
@ApiParam({
name: "personId",
description: "Fanavaran other-people Id",
example: 4553876,
})
@ApiOkResponse({
description: "Returns the Fanavaran other-person record",
schema: { type: "object" },
})
async otherPersonById(@Param("personId", ParseIntPipe) personId: number) {
return await this.lookupsService.otherPersonById(personId);
}
@Get("fanavaran")
@ApiOperation({
summary: "List configured Fanavaran remote lookups",

View File

@@ -182,6 +182,44 @@ export class LookupsService {
return await this.getClientRemoteLookup("dmg-business-line");
}
async getGender(): Promise<any> {
return await this.getClientRemoteLookup("gender");
}
async getMaritalStatus(): Promise<any> {
return await this.getClientRemoteLookup("marital-status");
}
async getAns(): Promise<any> {
return await this.getClientRemoteLookup("ans");
}
async getCountries(): Promise<any> {
return await this.getClientRemoteLookup("countries");
}
async getPersonKind(): Promise<any> {
return await this.getClientRemoteLookup("person-kind");
}
async getCiiValidationStatus(): Promise<any> {
return await this.getClientRemoteLookup("cii-validation-status");
}
async otherPersonById(personId: number): Promise<unknown> {
const clientKey = this.activeClientKey();
const person = await this.fanavaranLookupService.getOtherPerson(
clientKey,
personId,
);
if (person == null) {
throw new NotFoundException(
`Fanavaran other-person ${personId} was not found.`,
);
}
return person;
}
async inquiryByUniqueIdentifier(query: {
nationalCode?: string;
birthday?: string;