forked from Yara724/api
fanavaran driver and owner id (GEN..44 defauts) - culprit type id dynamic
This commit is contained in:
@@ -272,6 +272,7 @@ import {
|
|||||||
resolveFanavaranLicenceNo,
|
resolveFanavaranLicenceNo,
|
||||||
resolveOwnerFromParty,
|
resolveOwnerFromParty,
|
||||||
resolvePolicyholderFromParty,
|
resolvePolicyholderFromParty,
|
||||||
|
resolveThirdPartyCulpritTypeId,
|
||||||
} from "./fanavaran-party-roles";
|
} from "./fanavaran-party-roles";
|
||||||
import {
|
import {
|
||||||
buildFanavaranOtherPeoplePayload,
|
buildFanavaranOtherPeoplePayload,
|
||||||
@@ -4294,10 +4295,10 @@ export class ClaimRequestManagementService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`[resolveDriverFanavaranId] NO MATCH for nationalCode=${nationalCode} driverIsInsurer=${driverIsInsurer}. ` +
|
`[resolveDriverFanavaranId] NO acceptable RoleId 161/166 for nationalCode=${nationalCode} driverIsInsurer=${driverIsInsurer}. ` +
|
||||||
`Available entries: ${asPartyInquiryRows(response)
|
`Available entries: ${asPartyInquiryRows(response)
|
||||||
.map((e) => `{Id=${e.Id}, RoleId=${e.RoleId}, Name=${e.Name} ${e.LastName}}`)
|
.map((e) => `{Id=${e.Id}, RoleId=${e.RoleId}, Name=${e.Name} ${e.LastName}}`)
|
||||||
.join("; ")}`,
|
.join("; ")} — submit will register GEN.44 other-people`,
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -4308,7 +4309,7 @@ export class ClaimRequestManagementService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Best-effort OwnerId from parties inquiry (no GEN.44 create). */
|
/** Best-effort OwnerId from parties inquiry (RoleId 161/166 only; GEN.44 on submit). */
|
||||||
private async resolveOwnerFanavaranId(
|
private async resolveOwnerFanavaranId(
|
||||||
clientKey: FanavaranClientKey,
|
clientKey: FanavaranClientKey,
|
||||||
nationalCode: string | null | undefined,
|
nationalCode: string | null | undefined,
|
||||||
@@ -4327,7 +4328,20 @@ export class ClaimRequestManagementService {
|
|||||||
birthDay: parsed.day,
|
birthDay: parsed.day,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return selectFanavaranOwnerId(response);
|
const ownerId = selectFanavaranOwnerId(response);
|
||||||
|
if (ownerId != null) {
|
||||||
|
this.logger.log(
|
||||||
|
`[resolveOwnerFanavaranId] MATCH: Id=${ownerId} for nationalCode=${nationalCode}`,
|
||||||
|
);
|
||||||
|
return ownerId;
|
||||||
|
}
|
||||||
|
this.logger.warn(
|
||||||
|
`[resolveOwnerFanavaranId] NO acceptable RoleId 161/166 for nationalCode=${nationalCode}. ` +
|
||||||
|
`Available: ${asPartyInquiryRows(response)
|
||||||
|
.map((e) => `{Id=${e.Id}, RoleId=${e.RoleId}}`)
|
||||||
|
.join("; ")} — submit will register GEN.44 other-people`,
|
||||||
|
);
|
||||||
|
return null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`[resolveOwnerFanavaranId] inquiry failed for nationalCode=${nationalCode}: ${
|
`[resolveOwnerFanavaranId] inquiry failed for nationalCode=${nationalCode}: ${
|
||||||
@@ -4877,6 +4891,37 @@ export class ClaimRequestManagementService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
ownerFanavaranId == null &&
|
||||||
|
input.registerMissingPerson &&
|
||||||
|
ownerIdentity.nationalCode &&
|
||||||
|
ownerIdentity.birthday
|
||||||
|
) {
|
||||||
|
const registeredOwner = await this.registerFanavaranOtherPerson({
|
||||||
|
clientKey: input.clientKey,
|
||||||
|
person: {
|
||||||
|
nationalCode: ownerIdentity.nationalCode,
|
||||||
|
nationalCodeOfDriver: ownerIdentity.nationalCode,
|
||||||
|
birthday: ownerIdentity.birthday,
|
||||||
|
driverBirthday: ownerIdentity.birthday,
|
||||||
|
driverIsInsurer: false,
|
||||||
|
fullName: (damagedParty as any)?.person?.fullName,
|
||||||
|
phoneNumber: (damagedParty as any)?.person?.phoneNumber,
|
||||||
|
userId: (damagedParty as any)?.person?.userId,
|
||||||
|
},
|
||||||
|
claimCaseId: input.claimCase?._id
|
||||||
|
? String(input.claimCase._id)
|
||||||
|
: undefined,
|
||||||
|
});
|
||||||
|
if (registeredOwner != null) {
|
||||||
|
ownerFanavaranId = registeredOwner;
|
||||||
|
if (otherPersonId == null) otherPersonId = registeredOwner;
|
||||||
|
this.logger.log(
|
||||||
|
`[buildFanavaranDamageCasePayload] OwnerId=${ownerFanavaranId} from GEN.44 other-people`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (driverFanavaranId && input.blameCase?._id && damagedParty) {
|
if (driverFanavaranId && input.blameCase?._id && damagedParty) {
|
||||||
const partyIndex = (input.blameCase.parties ?? []).findIndex(
|
const partyIndex = (input.blameCase.parties ?? []).findIndex(
|
||||||
(p: any) => p === damagedParty ||
|
(p: any) => p === damagedParty ||
|
||||||
@@ -5726,7 +5771,8 @@ export class ClaimRequestManagementService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GEN.44: create the damaged party in Fanavaran when parties inquiry has no row.
|
* GEN.44: create the damaged party in Fanavaran when parties inquiry has no
|
||||||
|
* RoleId 161/166 row (missing entirely, or only e.g. 162 بیمهشده).
|
||||||
* Failures stay best-effort — GEN.12 submit continues without DriverId.
|
* Failures stay best-effort — GEN.12 submit continues without DriverId.
|
||||||
*/
|
*/
|
||||||
private async registerFanavaranOtherPerson(input: {
|
private async registerFanavaranOtherPerson(input: {
|
||||||
@@ -5736,7 +5782,8 @@ export class ClaimRequestManagementService {
|
|||||||
}): Promise<number | null> {
|
}): Promise<number | null> {
|
||||||
const nationalCode = pickPersonNationalCode(input.person);
|
const nationalCode = pickPersonNationalCode(input.person);
|
||||||
const birthday = pickPersonBirthday(input.person);
|
const birthday = pickPersonBirthday(input.person);
|
||||||
if (!nationalCode || !parseJalaliDateParts(birthday)) {
|
const parsedBirthday = parseJalaliDateParts(birthday);
|
||||||
|
if (!nationalCode || !parsedBirthday) {
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`[registerFanavaranOtherPerson] SKIP: missing nationalCode or birthday`,
|
`[registerFanavaranOtherPerson] SKIP: missing nationalCode or birthday`,
|
||||||
);
|
);
|
||||||
@@ -5765,12 +5812,77 @@ export class ClaimRequestManagementService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Seed GEN.44 from parties inquiry when the person exists under a non-driver role. */
|
||||||
|
let inquirySeed: {
|
||||||
|
name?: string;
|
||||||
|
lastName?: string;
|
||||||
|
fatherName?: string;
|
||||||
|
genderId?: number;
|
||||||
|
identityNo?: string;
|
||||||
|
} = {};
|
||||||
|
try {
|
||||||
|
const inquiryRows =
|
||||||
|
await this.fanavaranLookupService.inquiryByUniqueIdentifier(
|
||||||
|
input.clientKey,
|
||||||
|
{
|
||||||
|
nationalCode,
|
||||||
|
birthYear: parsedBirthday.year,
|
||||||
|
birthMonth: parsedBirthday.month,
|
||||||
|
birthDay: parsedBirthday.day,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const parties = asPartyInquiryRows(inquiryRows);
|
||||||
|
const seedRow =
|
||||||
|
parties.find(
|
||||||
|
(row) =>
|
||||||
|
(typeof row.Name === "string" && row.Name.trim()) ||
|
||||||
|
(typeof row.LastName === "string" && row.LastName.trim()),
|
||||||
|
) ?? parties[0];
|
||||||
|
if (seedRow) {
|
||||||
|
const roleId = Number(seedRow.RoleId);
|
||||||
|
this.logger.log(
|
||||||
|
`[registerFanavaranOtherPerson] inquiry seed Id=${seedRow.Id} RoleId=${roleId} — creating GEN.44 سایر (adds RoleId 166 entry; existing roles stay)`,
|
||||||
|
);
|
||||||
|
inquirySeed = {
|
||||||
|
name:
|
||||||
|
typeof seedRow.Name === "string" ? seedRow.Name : undefined,
|
||||||
|
lastName:
|
||||||
|
typeof seedRow.LastName === "string"
|
||||||
|
? seedRow.LastName
|
||||||
|
: undefined,
|
||||||
|
fatherName:
|
||||||
|
typeof seedRow.FatherName === "string"
|
||||||
|
? seedRow.FatherName
|
||||||
|
: undefined,
|
||||||
|
genderId: (() => {
|
||||||
|
const g = Number(seedRow.GenderId);
|
||||||
|
return Number.isFinite(g) && g > 0 ? g : undefined;
|
||||||
|
})(),
|
||||||
|
identityNo:
|
||||||
|
typeof seedRow.IdentityNo === "string"
|
||||||
|
? seedRow.IdentityNo
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.warn(
|
||||||
|
`[registerFanavaranOtherPerson] pre-create inquiry failed (continuing with local data): ${
|
||||||
|
error instanceof Error ? error.message : error
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const lookups = await this.loadFanavaranOtherPeopleLookups(input.clientKey);
|
const lookups = await this.loadFanavaranOtherPeopleLookups(input.clientKey);
|
||||||
const payload = buildFanavaranOtherPeoplePayload(
|
const payload = buildFanavaranOtherPeoplePayload(
|
||||||
{
|
{
|
||||||
nationalCode,
|
nationalCode,
|
||||||
birthday,
|
birthday,
|
||||||
fullName: input.person?.fullName ?? user?.fullName,
|
fullName: input.person?.fullName ?? user?.fullName,
|
||||||
|
name: inquirySeed.name,
|
||||||
|
lastName: inquirySeed.lastName,
|
||||||
|
fatherName: inquirySeed.fatherName,
|
||||||
|
identityNo: inquirySeed.identityNo,
|
||||||
|
genderId: inquirySeed.genderId,
|
||||||
mobile: input.person?.phoneNumber ?? user?.mobile,
|
mobile: input.person?.phoneNumber ?? user?.mobile,
|
||||||
address: user?.address,
|
address: user?.address,
|
||||||
cityName: user?.city,
|
cityName: user?.city,
|
||||||
@@ -6203,7 +6315,9 @@ export class ClaimRequestManagementService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// GEN.03 CulpritLicence*: guilty-party DRIVER for THIRD_PARTY, FIRST-party DRIVER for CAR_BODY.
|
// GEN.03 CulpritLicence* + CulpritTypeId: guilty-party DRIVER for THIRD_PARTY,
|
||||||
|
// FIRST-party DRIVER for CAR_BODY. CulpritTypeId uses accident-culprit-type
|
||||||
|
// (337 بیمهگذار / 338 راننده غير از بيمه گذار) — hull remaps separately.
|
||||||
{
|
{
|
||||||
const culpritParty =
|
const culpritParty =
|
||||||
blameCase.type === BlameRequestType.CAR_BODY
|
blameCase.type === BlameRequestType.CAR_BODY
|
||||||
@@ -6226,6 +6340,10 @@ export class ClaimRequestManagementService {
|
|||||||
);
|
);
|
||||||
payload.CulpritLicenceIssuDate =
|
payload.CulpritLicenceIssuDate =
|
||||||
resolveFanavaranLicenceIssuDate(culpritDriver);
|
resolveFanavaranLicenceIssuDate(culpritDriver);
|
||||||
|
if (blameCase.type !== BlameRequestType.CAR_BODY) {
|
||||||
|
payload.CulpritTypeId =
|
||||||
|
resolveThirdPartyCulpritTypeId(culpritParty as any);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const carBodyAccidentTime = (
|
const carBodyAccidentTime = (
|
||||||
@@ -6445,7 +6563,7 @@ export class ClaimRequestManagementService {
|
|||||||
}
|
}
|
||||||
if (payload.DriverId == null) {
|
if (payload.DriverId == null) {
|
||||||
warnings.push(
|
warnings.push(
|
||||||
"Damaged party is not in Fanavaran yet; submit will register them via other-people (GEN.44).",
|
"Damaged party has no Fanavaran RoleId 161/166 yet; submit will register them via other-people (GEN.44).",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
pickPersonBirthday,
|
pickPersonBirthday,
|
||||||
pickPersonNationalCode,
|
pickPersonNationalCode,
|
||||||
selectFanavaranDriverId,
|
selectFanavaranDriverId,
|
||||||
|
selectFanavaranOwnerId,
|
||||||
} from "./fanavaran-driver-inquiry";
|
} from "./fanavaran-driver-inquiry";
|
||||||
|
|
||||||
describe("selectFanavaranDriverId", () => {
|
describe("selectFanavaranDriverId", () => {
|
||||||
@@ -21,10 +22,32 @@ describe("selectFanavaranDriverId", () => {
|
|||||||
expect(selectFanavaranDriverId(rows, false)).toBe(20);
|
expect(selectFanavaranDriverId(rows, false)).toBe(20);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses the other role when the preferred role is missing", () => {
|
it("falls back to 166 when preferred 161 is missing", () => {
|
||||||
expect(selectFanavaranDriverId([{ Id: 20, RoleId: 166 }], true)).toBe(20);
|
expect(selectFanavaranDriverId([{ Id: 20, RoleId: 166 }], true)).toBe(20);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("returns null for RoleId 162 (بیمهشده) — GEN.44 required", () => {
|
||||||
|
expect(
|
||||||
|
selectFanavaranDriverId(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Id: 2390312,
|
||||||
|
RoleId: 162,
|
||||||
|
Name: "محمدعلي",
|
||||||
|
LastName: "موسوي",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not fall back to RoleId 163 for DriverId", () => {
|
||||||
|
expect(
|
||||||
|
selectFanavaranDriverId([{ Id: 99, RoleId: 163 }], false),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it("picks 4773521 from a real Fanavaran unique-identifier response", () => {
|
it("picks 4773521 from a real Fanavaran unique-identifier response", () => {
|
||||||
expect(
|
expect(
|
||||||
selectFanavaranDriverId(
|
selectFanavaranDriverId(
|
||||||
@@ -39,6 +62,19 @@ describe("selectFanavaranDriverId", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("selectFanavaranOwnerId", () => {
|
||||||
|
it("accepts only RoleId 161 or 166", () => {
|
||||||
|
expect(
|
||||||
|
selectFanavaranOwnerId([
|
||||||
|
{ Id: 1, RoleId: 162 },
|
||||||
|
{ Id: 2, RoleId: 163 },
|
||||||
|
]),
|
||||||
|
).toBeNull();
|
||||||
|
expect(selectFanavaranOwnerId([{ Id: 10, RoleId: 161 }])).toBe(10);
|
||||||
|
expect(selectFanavaranOwnerId([{ Id: 20, RoleId: 166 }])).toBe(20);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("pickPersonNationalCode / birthday", () => {
|
describe("pickPersonNationalCode / birthday", () => {
|
||||||
it("uses insurer national code when driverIsInsurer", () => {
|
it("uses insurer national code when driverIsInsurer", () => {
|
||||||
expect(
|
expect(
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ export type FanavaranPartyInquiryRow = {
|
|||||||
NationalCode?: unknown;
|
NationalCode?: unknown;
|
||||||
Name?: unknown;
|
Name?: unknown;
|
||||||
LastName?: unknown;
|
LastName?: unknown;
|
||||||
|
FatherName?: unknown;
|
||||||
|
GenderId?: unknown;
|
||||||
|
IdentityNo?: unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
function asPositiveId(value: unknown): number | null {
|
function asPositiveId(value: unknown): number | null {
|
||||||
@@ -34,9 +37,25 @@ export function asPartyInquiryRows(value: unknown): FanavaranPartyInquiryRow[] {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** GEN.12 DriverId is only accepted for بیمهگذار (161) or سایر (166). */
|
||||||
|
export const FANAVARAN_DRIVER_ACCEPTED_ROLE_IDS = [
|
||||||
|
FANAVARAN_INSURER_ROLE_ID,
|
||||||
|
FANAVARAN_DRIVER_ROLE_ID,
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export function isAcceptableFanavaranDriverRole(
|
||||||
|
roleId: unknown,
|
||||||
|
): boolean {
|
||||||
|
const id = asPositiveId(roleId);
|
||||||
|
return (
|
||||||
|
id === FANAVARAN_INSURER_ROLE_ID || id === FANAVARAN_DRIVER_ROLE_ID
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function selectFanavaranIdByRoles(
|
function selectFanavaranIdByRoles(
|
||||||
rows: unknown,
|
rows: unknown,
|
||||||
preferredRoles: number[],
|
preferredRoles: number[],
|
||||||
|
options?: { allowFallbackToFirst?: boolean },
|
||||||
): number | null {
|
): number | null {
|
||||||
const parties = asPartyInquiryRows(rows);
|
const parties = asPartyInquiryRows(rows);
|
||||||
if (parties.length === 0) return null;
|
if (parties.length === 0) return null;
|
||||||
@@ -46,38 +65,38 @@ function selectFanavaranIdByRoles(
|
|||||||
if (match) return asPositiveId(match.Id);
|
if (match) return asPositiveId(match.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options?.allowFallbackToFirst === false) return null;
|
||||||
return asPositiveId(parties[0].Id);
|
return asPositiveId(parties[0].Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DriverId for GEN.12 زیاندیده. Prefer insurer (161) or driver (166)
|
* DriverId for GEN.12 زیاندیده.
|
||||||
* based on driverIsInsurer, then any returned party id.
|
* Only RoleId 161 (بیمهگذار) or 166 (سایر) are accepted by Fanavaran.
|
||||||
|
* Other roles (e.g. 162 بیمهشده) must go through GEN.44 other-people first
|
||||||
|
* (GEN.44 adds a RoleId-166 entry; it does not replace existing role rows).
|
||||||
*/
|
*/
|
||||||
export function selectFanavaranDriverId(
|
export function selectFanavaranDriverId(
|
||||||
rows: unknown,
|
rows: unknown,
|
||||||
driverIsInsurer: boolean | undefined,
|
driverIsInsurer: boolean | undefined,
|
||||||
): number | null {
|
): number | null {
|
||||||
const preferredRoles = driverIsInsurer
|
const preferredRoles = driverIsInsurer
|
||||||
? [
|
? [FANAVARAN_INSURER_ROLE_ID, FANAVARAN_DRIVER_ROLE_ID]
|
||||||
FANAVARAN_INSURER_ROLE_ID,
|
: [FANAVARAN_DRIVER_ROLE_ID, FANAVARAN_INSURER_ROLE_ID];
|
||||||
FANAVARAN_DRIVER_ROLE_ID,
|
return selectFanavaranIdByRoles(rows, preferredRoles, {
|
||||||
FANAVARAN_PLAQUE_OWNER_ROLE_ID,
|
allowFallbackToFirst: false,
|
||||||
]
|
});
|
||||||
: [
|
|
||||||
FANAVARAN_DRIVER_ROLE_ID,
|
|
||||||
FANAVARAN_INSURER_ROLE_ID,
|
|
||||||
FANAVARAN_PLAQUE_OWNER_ROLE_ID,
|
|
||||||
];
|
|
||||||
return selectFanavaranIdByRoles(rows, preferredRoles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** OwnerId: prefer plaque-owner role (163), then insurer / driver. */
|
/**
|
||||||
|
* OwnerId for GEN.12: same accepted roles as DriverId (161 / 166 only).
|
||||||
|
* Prefer بیمهگذار then سایر. RoleId 162/163/… → null → GEN.44 on submit.
|
||||||
|
*/
|
||||||
export function selectFanavaranOwnerId(rows: unknown): number | null {
|
export function selectFanavaranOwnerId(rows: unknown): number | null {
|
||||||
return selectFanavaranIdByRoles(rows, [
|
return selectFanavaranIdByRoles(
|
||||||
FANAVARAN_PLAQUE_OWNER_ROLE_ID,
|
rows,
|
||||||
FANAVARAN_INSURER_ROLE_ID,
|
[FANAVARAN_INSURER_ROLE_ID, FANAVARAN_DRIVER_ROLE_ID],
|
||||||
FANAVARAN_DRIVER_ROLE_ID,
|
{ allowFallbackToFirst: false },
|
||||||
]);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeNationalCode(value: unknown): string | null {
|
export function normalizeNationalCode(value: unknown): string | null {
|
||||||
|
|||||||
@@ -49,6 +49,29 @@ describe("fanavaran other people (GEN.44)", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("defaults CityId=9131 and PersonKindId=46 when lookups miss", () => {
|
||||||
|
const payload = buildFanavaranOtherPeoplePayload({
|
||||||
|
nationalCode: "2002166323",
|
||||||
|
birthday: { year: 1353, month: 2, day: 15 },
|
||||||
|
name: "محمدعلي",
|
||||||
|
lastName: "موسوي",
|
||||||
|
fatherName: "حسن",
|
||||||
|
identityNo: "1205",
|
||||||
|
genderId: 26,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(payload).toMatchObject({
|
||||||
|
NationalCode: "2002166323",
|
||||||
|
CityId: 9131,
|
||||||
|
PersonKindId: 46,
|
||||||
|
GenderId: 26,
|
||||||
|
Name: "محمدعلي",
|
||||||
|
LastName: "موسوي",
|
||||||
|
FatherName: "حسن",
|
||||||
|
IdentityNo: "1205",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("returns null when national code or birthday is missing", () => {
|
it("returns null when national code or birthday is missing", () => {
|
||||||
expect(
|
expect(
|
||||||
buildFanavaranOtherPeoplePayload({
|
buildFanavaranOtherPeoplePayload({
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ export type FanavaranOtherPeopleSource = {
|
|||||||
nationalCode?: unknown;
|
nationalCode?: unknown;
|
||||||
birthday?: unknown;
|
birthday?: unknown;
|
||||||
fullName?: unknown;
|
fullName?: unknown;
|
||||||
|
/** Prefer these over splitting fullName when inquiry already returned them. */
|
||||||
|
name?: unknown;
|
||||||
|
lastName?: unknown;
|
||||||
fatherName?: unknown;
|
fatherName?: unknown;
|
||||||
mobile?: unknown;
|
mobile?: unknown;
|
||||||
tel?: unknown;
|
tel?: unknown;
|
||||||
@@ -33,7 +36,13 @@ export type FanavaranOtherPeopleSource = {
|
|||||||
jobAddress?: unknown;
|
jobAddress?: unknown;
|
||||||
postalCode?: unknown;
|
postalCode?: unknown;
|
||||||
cityName?: unknown;
|
cityName?: unknown;
|
||||||
|
/** Direct Fanavaran CityId when known; else lookup / default 9131. */
|
||||||
|
cityId?: unknown;
|
||||||
gender?: unknown;
|
gender?: unknown;
|
||||||
|
/** Direct Fanavaran GenderId from parties inquiry when available. */
|
||||||
|
genderId?: unknown;
|
||||||
|
/** Direct Fanavaran PersonKindId; else lookup / default 46 (حقیقی). */
|
||||||
|
personKindId?: unknown;
|
||||||
isIranian?: boolean;
|
isIranian?: boolean;
|
||||||
naturalizedCode?: unknown;
|
naturalizedCode?: unknown;
|
||||||
identityNo?: unknown;
|
identityNo?: unknown;
|
||||||
@@ -82,6 +91,10 @@ const ANS_YES_TEXTS = ["بله", "بلی", "yes", "1"];
|
|||||||
const NATURAL_PERSON_TEXTS = ["حقیقی", "شخص حقیقی", "طبيعي", "natural"];
|
const NATURAL_PERSON_TEXTS = ["حقیقی", "شخص حقیقی", "طبيعي", "natural"];
|
||||||
const IRAN_COUNTRY_TEXTS = ["ایران", "ايران", "iran"];
|
const IRAN_COUNTRY_TEXTS = ["ایران", "ايران", "iran"];
|
||||||
|
|
||||||
|
/** Proven Parsian GEN.44 defaults when lookup / city name is missing. */
|
||||||
|
export const FANAVARAN_OTHER_PEOPLE_DEFAULT_CITY_ID = 9131;
|
||||||
|
export const FANAVARAN_OTHER_PEOPLE_DEFAULT_PERSON_KIND_ID = 46;
|
||||||
|
|
||||||
function asLookupRows(value: unknown): FanavaranLookupRow[] {
|
function asLookupRows(value: unknown): FanavaranLookupRow[] {
|
||||||
if (!Array.isArray(value)) return [];
|
if (!Array.isArray(value)) return [];
|
||||||
return value.filter(
|
return value.filter(
|
||||||
@@ -213,8 +226,8 @@ export function buildFanavaranOtherPeoplePayload(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
NationalCode: nationalCode,
|
NationalCode: nationalCode,
|
||||||
Name: names.name,
|
Name: emptyToNull(source.name) ?? names.name,
|
||||||
LastName: names.lastName,
|
LastName: emptyToNull(source.lastName) ?? names.lastName,
|
||||||
FatherName: emptyToNull(source.fatherName),
|
FatherName: emptyToNull(source.fatherName),
|
||||||
BirthYear: birthday.year,
|
BirthYear: birthday.year,
|
||||||
BirthMonth: birthday.month,
|
BirthMonth: birthday.month,
|
||||||
@@ -235,8 +248,13 @@ export function buildFanavaranOtherPeoplePayload(
|
|||||||
CompanyCode: emptyToNull(source.companyCode),
|
CompanyCode: emptyToNull(source.companyCode),
|
||||||
IdentityNo: emptyToNull(source.identityNo),
|
IdentityNo: emptyToNull(source.identityNo),
|
||||||
RegisterNo: emptyToNull(source.registerNo),
|
RegisterNo: emptyToNull(source.registerNo),
|
||||||
CityId: pickLookupIdByCaption(lookups.cities, [source.cityName]),
|
CityId:
|
||||||
GenderId: pickLookupIdByCaption(lookups.gender, genderTexts),
|
asPositiveId(source.cityId) ??
|
||||||
|
pickLookupIdByCaption(lookups.cities, [source.cityName]) ??
|
||||||
|
FANAVARAN_OTHER_PEOPLE_DEFAULT_CITY_ID,
|
||||||
|
GenderId:
|
||||||
|
asPositiveId(source.genderId) ??
|
||||||
|
pickLookupIdByCaption(lookups.gender, genderTexts),
|
||||||
MaritalStatus: pickLookupIdByCaption(lookups.maritalStatus, []),
|
MaritalStatus: pickLookupIdByCaption(lookups.maritalStatus, []),
|
||||||
IsIranian: isIranian
|
IsIranian: isIranian
|
||||||
? (pickLookupIdByCaption(lookups.ans, ANS_YES_TEXTS) ?? 1)
|
? (pickLookupIdByCaption(lookups.ans, ANS_YES_TEXTS) ?? 1)
|
||||||
@@ -244,9 +262,9 @@ export function buildFanavaranOtherPeoplePayload(
|
|||||||
NationalityId: isIranian
|
NationalityId: isIranian
|
||||||
? null
|
? null
|
||||||
: pickLookupIdByCaption(lookups.countries, IRAN_COUNTRY_TEXTS),
|
: pickLookupIdByCaption(lookups.countries, IRAN_COUNTRY_TEXTS),
|
||||||
PersonKindId: pickLookupIdByCaption(
|
PersonKindId:
|
||||||
lookups.personKind,
|
asPositiveId(source.personKindId) ??
|
||||||
NATURAL_PERSON_TEXTS,
|
pickLookupIdByCaption(lookups.personKind, NATURAL_PERSON_TEXTS) ??
|
||||||
),
|
FANAVARAN_OTHER_PEOPLE_DEFAULT_PERSON_KIND_ID,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { InquiryParticipantRole } from "src/common/dto/inquiry-participants.dto";
|
import { InquiryParticipantRole } from "src/common/dto/inquiry-participants.dto";
|
||||||
import {
|
import {
|
||||||
|
FANAVARAN_CULPRIT_TYPE_DRIVER_NOT_INSURER,
|
||||||
|
FANAVARAN_CULPRIT_TYPE_INSURER,
|
||||||
FANAVARAN_DUMMY_LICENCE_ISSU_DATE,
|
FANAVARAN_DUMMY_LICENCE_ISSU_DATE,
|
||||||
formatFanavaranLicenceIssuDate,
|
formatFanavaranLicenceIssuDate,
|
||||||
resolveDriverFromParty,
|
resolveDriverFromParty,
|
||||||
@@ -8,6 +10,7 @@ import {
|
|||||||
resolveFanavaranLicenceNo,
|
resolveFanavaranLicenceNo,
|
||||||
resolveOwnerFromParty,
|
resolveOwnerFromParty,
|
||||||
resolvePolicyholderFromParty,
|
resolvePolicyholderFromParty,
|
||||||
|
resolveThirdPartyCulpritTypeId,
|
||||||
} from "./fanavaran-party-roles";
|
} from "./fanavaran-party-roles";
|
||||||
|
|
||||||
describe("fanavaran-party-roles", () => {
|
describe("fanavaran-party-roles", () => {
|
||||||
@@ -105,6 +108,31 @@ describe("fanavaran-party-roles", () => {
|
|||||||
).toBe("0080086519");
|
).toBe("0080086519");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("maps CulpritTypeId 338 when guilty driver ≠ insurer", () => {
|
||||||
|
expect(resolveThirdPartyCulpritTypeId(partyWithDistinctRoles)).toBe(
|
||||||
|
FANAVARAN_CULPRIT_TYPE_DRIVER_NOT_INSURER,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("maps CulpritTypeId 337 when guilty driver is the insurer", () => {
|
||||||
|
expect(
|
||||||
|
resolveThirdPartyCulpritTypeId({
|
||||||
|
participants: [
|
||||||
|
{
|
||||||
|
participantId: "SAME",
|
||||||
|
nationalCode: "0080086519",
|
||||||
|
birthday: "1364/06/28",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
participantRoles: {
|
||||||
|
driver: "SAME",
|
||||||
|
thirdPartyPolicyholder: "SAME",
|
||||||
|
},
|
||||||
|
person: { driverIsInsurer: true },
|
||||||
|
}),
|
||||||
|
).toBe(FANAVARAN_CULPRIT_TYPE_INSURER);
|
||||||
|
});
|
||||||
|
|
||||||
it("formats compact Jalali driverLicenseDate", () => {
|
it("formats compact Jalali driverLicenseDate", () => {
|
||||||
expect(formatFanavaranLicenceIssuDate(13980601)).toBe("1398/06/01");
|
expect(formatFanavaranLicenceIssuDate(13980601)).toBe("1398/06/01");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -201,6 +201,31 @@ export function resolveDriverIsOwner(party: PartyLike | null | undefined): boole
|
|||||||
return party?.person?.driverIsInsurer === true;
|
return party?.person?.driverIsInsurer === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Lookup: `accident-culprit-type` — بیمهگذار */
|
||||||
|
export const FANAVARAN_CULPRIT_TYPE_INSURER = 337;
|
||||||
|
/** Lookup: `accident-culprit-type` — راننده غير از بيمه گذار */
|
||||||
|
export const FANAVARAN_CULPRIT_TYPE_DRIVER_NOT_INSURER = 338;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GEN.03 ثالث `CulpritTypeId` from whether the guilty party's driver is the insurer.
|
||||||
|
* Never uses 728 (نا معلوم).
|
||||||
|
*/
|
||||||
|
export function resolveThirdPartyCulpritTypeId(
|
||||||
|
party: PartyLike | null | undefined,
|
||||||
|
): number {
|
||||||
|
const driver = resolveDriverFromParty(party);
|
||||||
|
const insurer = resolvePolicyholderFromParty(party, "third-party");
|
||||||
|
if (driver.nationalCode && insurer.nationalCode) {
|
||||||
|
return driver.nationalCode === insurer.nationalCode
|
||||||
|
? FANAVARAN_CULPRIT_TYPE_INSURER
|
||||||
|
: FANAVARAN_CULPRIT_TYPE_DRIVER_NOT_INSURER;
|
||||||
|
}
|
||||||
|
if (party?.person?.driverIsInsurer === false) {
|
||||||
|
return FANAVARAN_CULPRIT_TYPE_DRIVER_NOT_INSURER;
|
||||||
|
}
|
||||||
|
return FANAVARAN_CULPRIT_TYPE_INSURER;
|
||||||
|
}
|
||||||
|
|
||||||
/** Licence number for Fanavaran; never empty — uses `dummy` when user value is missing. */
|
/** Licence number for Fanavaran; never empty — uses `dummy` when user value is missing. */
|
||||||
export function resolveFanavaranLicenceNo(
|
export function resolveFanavaranLicenceNo(
|
||||||
identity: Pick<FanavaranRoleIdentity, "licenseNo">,
|
identity: Pick<FanavaranRoleIdentity, "licenseNo">,
|
||||||
|
|||||||
Reference in New Issue
Block a user