import { InquiryParticipantRole } from "src/common/dto/inquiry-participants.dto"; import { participantForStoredPartyRole } from "src/request-management/inquiry-participant-resolver"; import { normalizeNationalCode, parseJalaliDateParts, } from "./fanavaran-driver-inquiry"; import type { FanavaranClaimProduct } from "./fanavaran-claim-product"; /** Fanavaran dummy licence issue date when the user did not supply one. */ export const FANAVARAN_DUMMY_LICENCE_ISSU_DATE = "1394/10/13"; export type FanavaranRoleIdentity = { nationalCode: string | null; birthday: string | number | null; /** Digits-only licence number when known. */ licenseNo: string | null; licenseType: string | null; /** * Jalali `YYYY/MM/DD` from `driverLicenseDate` when present. * Not a persisted model field — read opportunistically from party/person/participant. */ licenseIssuDate: string | null; }; type PartyLike = { participants?: Array>; participantRoles?: Record; person?: Record | null; }; function nonEmptyText(value: unknown): string | null { if (value == null) return null; const text = String(value).trim(); if (!text || text.toLowerCase() === "null" || text.toLowerCase() === "undefined") { return null; } return text; } /** Digits-only licence number, or null when empty / non-digit. */ export function extractLicenceDigits(value: unknown): string | null { const text = nonEmptyText(value); if (!text) return null; const digits = text.replace(/[^\d]/g, ""); return digits || null; } /** * Normalize a stored `driverLicenseDate` (or similar) to Fanavaran Jalali `YYYY/MM/DD`. * Returns null when missing / unparseable so callers can fall back to the dummy. */ export function formatFanavaranLicenceIssuDate(value: unknown): string | null { const parsed = parseJalaliDateParts(value); if (!parsed) return null; const month = String(parsed.month).padStart(2, "0"); const day = String(parsed.day).padStart(2, "0"); return `${parsed.year}/${month}/${day}`; } function readDriverLicenseDate( ...sources: Array | null | undefined> ): string | null { for (const source of sources) { if (!source) continue; const formatted = formatFanavaranLicenceIssuDate( source.driverLicenseDate ?? source.licenseDate ?? source.licenceIssuDate, ); if (formatted) return formatted; } return null; } function fromParticipant( participant: Record | undefined, ): FanavaranRoleIdentity { if (!participant) { return { nationalCode: null, birthday: null, licenseNo: null, licenseType: null, licenseIssuDate: null, }; } return { nationalCode: normalizeNationalCode(participant.nationalCode), birthday: nonEmptyText(participant.birthday) ?? participant.birthday ?? null, licenseNo: extractLicenceDigits(participant.licenseNumber), licenseType: nonEmptyText(participant.licenseType), licenseIssuDate: readDriverLicenseDate(participant), }; } /** * Damaged/guilty party DRIVER: participants first, then legacy person.* fields. * Licence number prefers real user values; callers fall back to the Fanavaran dummy. */ export function resolveDriverFromParty(party: PartyLike | null | undefined): FanavaranRoleIdentity { const fromRole = fromParticipant( participantForStoredPartyRole( party ?? {}, InquiryParticipantRole.DRIVER, ) as Record | undefined, ); const person = party?.person ?? undefined; return { nationalCode: fromRole.nationalCode ?? normalizeNationalCode(person?.nationalCodeOfDriver) ?? normalizeNationalCode(person?.nationalCode), birthday: (fromRole.birthday != null && String(fromRole.birthday).trim() !== "" ? fromRole.birthday : null) ?? nonEmptyText(person?.driverBirthday) ?? nonEmptyText(person?.birthday) ?? person?.driverBirthday ?? person?.birthday ?? null, licenseNo: fromRole.licenseNo ?? extractLicenceDigits(person?.driverLicense) ?? extractLicenceDigits(person?.insurerLicense), licenseType: fromRole.licenseType ?? nonEmptyText(person?.licenseType), licenseIssuDate: fromRole.licenseIssuDate ?? readDriverLicenseDate(person), }; } /** Vehicle owner for OwnerId / DriverIsOwner / Sheba national-code routing. */ export function resolveOwnerFromParty(party: PartyLike | null | undefined): FanavaranRoleIdentity { const fromRole = fromParticipant( participantForStoredPartyRole( party ?? {}, InquiryParticipantRole.VEHICLE_OWNER, ) as Record | undefined, ); if (fromRole.nationalCode || fromRole.birthday) { return fromRole; } // Legacy parties had no dedicated owner fields. return { nationalCode: null, birthday: null, licenseNo: null, licenseType: null, licenseIssuDate: null, }; } /** * Policyholder national code for GEN.03 PolicyId inquiry: * THIRD_PARTY → third-party policyholder; CAR_BODY → car-body policyholder. */ export function resolvePolicyholderFromParty( party: PartyLike | null | undefined, product: FanavaranClaimProduct, ): FanavaranRoleIdentity { const role = product === "car-body" ? InquiryParticipantRole.CAR_BODY_POLICYHOLDER : InquiryParticipantRole.THIRD_PARTY_POLICYHOLDER; const fromRole = fromParticipant( participantForStoredPartyRole(party ?? {}, role) as | Record | undefined, ); const person = party?.person ?? undefined; return { nationalCode: fromRole.nationalCode ?? normalizeNationalCode(person?.nationalCodeOfInsurer) ?? normalizeNationalCode(person?.nationalCode), birthday: (fromRole.birthday != null && String(fromRole.birthday).trim() !== "" ? fromRole.birthday : null) ?? nonEmptyText(person?.insurerBirthday) ?? person?.insurerBirthday ?? null, licenseNo: fromRole.licenseNo ?? extractLicenceDigits(person?.insurerLicense), licenseType: fromRole.licenseType ?? null, licenseIssuDate: fromRole.licenseIssuDate, }; } /** * GEN.12 `DriverIsOwner`: driver national code equals vehicle-owner national code. * Falls back to legacy `person.driverIsInsurer` when owner role is absent. */ export function resolveDriverIsOwner(party: PartyLike | null | undefined): boolean { const driver = resolveDriverFromParty(party); const owner = resolveOwnerFromParty(party); if (driver.nationalCode && owner.nationalCode) { return driver.nationalCode === owner.nationalCode; } return party?.person?.driverIsInsurer === true; } /** Licence number for Fanavaran; never empty — uses `dummy` when user value is missing. */ export function resolveFanavaranLicenceNo( identity: Pick, dummy: string, ): string { return identity.licenseNo || dummy; } /** Licence issue date for Fanavaran; uses dummy when `driverLicenseDate` is absent. */ export function resolveFanavaranLicenceIssuDate( identity: Pick, dummy: string = FANAVARAN_DUMMY_LICENCE_ISSU_DATE, ): string { return identity.licenseIssuDate || dummy; }