Files
yara724-api/src/request-management/inquiry-participant-resolver.spec.ts
2026-09-13 14:13:05 +03:30

509 lines
15 KiB
TypeScript

import { BadRequestException } from "@nestjs/common";
import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum";
import {
InquiryParticipantRole,
VehicleRegistrationState,
} from "src/common/dto/inquiry-participants.dto";
import {
assertPreviousPlateInquiryMatchesVin,
isMappedPolicyCurrent,
normalizeInquirySubmission,
participantForRole,
resolveInquiryParticipants,
resolveInquiryVehicle,
runPlateInquiryWithFallback,
vehiclePlateCandidates,
} from "./inquiry-participant-resolver";
describe("inquiry participant resolver", () => {
it("links several roles to one explicitly shared person", () => {
const resolved = resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
driver: {
nationalCode: "0012345678",
birthday: "1370/01/01",
hasDrivingLicense: true,
licenseNumber: "123456789",
licenseType: "1",
},
vehicleOwner: { sameAs: InquiryParticipantRole.DRIVER },
thirdPartyPolicyholder: {
sameAs: InquiryParticipantRole.VEHICLE_OWNER,
},
});
expect(resolved.participants).toHaveLength(1);
expect(resolved.roles).toEqual({
driver: "DRIVER",
vehicleOwner: "DRIVER",
thirdPartyPolicyholder: "DRIVER",
});
});
it("requires both previous plate and VIN for a recent transfer", () => {
expect(() =>
resolveInquiryVehicle({
registrationState: VehicleRegistrationState.RECENTLY_TRANSFERRED,
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
}),
).toThrow(BadRequestException);
});
it("defaults an omitted registration state to CURRENT", () => {
expect(
resolveInquiryVehicle({
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
}).registrationState,
).toBe(VehicleRegistrationState.CURRENT);
});
it("rejects the removed flat inquiry contract", () => {
expect(() =>
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
nationalCodeOfDriver: "0012345678",
driverBirthday: "1370/01/01",
driverLicense: "123456789",
nationalCodeOfInsurer: "0098765432",
insurerBirthday: "1360/02/02",
driverIsInsurer: false,
} as any),
).toThrow(BadRequestException);
});
it("rejects phone numbers in participant inquiry identity", () => {
expect(() =>
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
driver: {
nationalCode: "0012345678",
birthday: "1370/01/01",
hasDrivingLicense: false,
phoneNumber: "09120000000",
},
vehicleOwner: { sameAs: InquiryParticipantRole.DRIVER },
thirdPartyPolicyholder: {
sameAs: InquiryParticipantRole.DRIVER,
},
} as any),
).toThrow(BadRequestException);
});
it("keeps third-party and car-body policyholders distinct", () => {
const resolved = resolveInquiryParticipants(BlameRequestType.CAR_BODY, {
driver: {
nationalCode: "0012345678",
birthday: "1370/01/01",
hasDrivingLicense: false,
},
vehicleOwner: { sameAs: InquiryParticipantRole.DRIVER },
thirdPartyPolicyholder: {
nationalCode: "0023456789",
birthday: "1360/02/02",
},
carBodyPolicyholder: {
nationalCode: "0034567890",
birthday: "1350/03/03",
},
});
expect(
participantForRole(
resolved,
InquiryParticipantRole.THIRD_PARTY_POLICYHOLDER,
)?.nationalCode,
).toBe("0023456789");
expect(
participantForRole(resolved, InquiryParticipantRole.CAR_BODY_POLICYHOLDER)
?.nationalCode,
).toBe("0034567890");
});
it("projects role-complete input onto the existing inquiry fields", () => {
const normalized = normalizeInquirySubmission(BlameRequestType.CAR_BODY, {
vehicle: {
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
},
driver: {
nationalCode: "0012345678",
birthday: "1370/01/01",
hasDrivingLicense: true,
licenseNumber: "D-1",
licenseType: "1",
},
vehicleOwner: { sameAs: InquiryParticipantRole.DRIVER },
thirdPartyPolicyholder: {
nationalCode: "0023456789",
birthday: "1360/02/02",
},
carBodyPolicyholder: {
nationalCode: "0034567890",
birthday: "1350/03/03",
},
});
expect(normalized.dto.nationalCodeOfInsurer).toBe("0023456789");
expect(normalized.dto.nationalCodeOfDriver).toBe("0012345678");
expect(normalized.carBodyPolicyholder?.nationalCode).toBe("0034567890");
expect(normalized.vehicleOwner?.nationalCode).toBe("0012345678");
});
it("orders the current plate before the previous-plate fallback", () => {
const currentPlate = {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
};
const previousPlate = {
leftDigits: "55",
centerAlphabet: "ج",
centerDigits: "222",
ir: "33",
};
expect(
vehiclePlateCandidates({
registrationState: VehicleRegistrationState.RECENTLY_TRANSFERRED,
currentPlate,
previousPlate,
vin: "NAAM01E15HK123456",
}),
).toEqual([
{ kind: "CURRENT", plate: currentPlate },
{ kind: "PREVIOUS", plate: previousPlate },
]);
});
it("rejects a previous-plate result for another chassis", () => {
expect(() =>
assertPreviousPlateInquiryMatchesVin("NAAM01E15HK123456", {
VinNumberField: "DIFFERENTVIN00001",
}),
).toThrow(BadRequestException);
});
it("requires the driver's licence status in the new contract", () => {
expect(() =>
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
driver: { nationalCode: "0012345678", birthday: "1370/01/01" },
vehicleOwner: { sameAs: InquiryParticipantRole.DRIVER },
thirdPartyPolicyholder: {
sameAs: InquiryParticipantRole.VEHICLE_OWNER,
},
}),
).toThrow(BadRequestException);
});
it("falls back to the previous plate and accepts only a matching VIN", async () => {
const currentPlate = {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
};
const previousPlate = {
leftDigits: "55",
centerAlphabet: "ج",
centerDigits: "222",
ir: "33",
};
const query = jest
.fn()
.mockRejectedValueOnce(new Error("not found"))
.mockResolvedValueOnce({
mapped: { VinNumberField: "NAAM01E15HK123456", CompanyName: "پارسیان" },
});
const result = await runPlateInquiryWithFallback<{
mapped: { VinNumberField?: string; CompanyName?: string };
}>({
vehicle: {
registrationState: VehicleRegistrationState.RECENTLY_TRANSFERRED,
currentPlate,
previousPlate,
vin: "NAAM01E15HK123456",
},
fallbackCurrentPlate: currentPlate,
query,
isUsable: (value) => !!value.mapped.CompanyName,
mappedValue: (value) => value.mapped,
});
expect(query).toHaveBeenCalledTimes(2);
expect(result.plateKind).toBe("PREVIOUS");
expect(result.attempts).toMatchObject([
{ plateKind: "CURRENT", succeeded: false, error: "not found" },
{ plateKind: "PREVIOUS", succeeded: true, usable: true },
]);
expect(result.attempts[0]).toMatchObject({
plate: currentPlate,
vin: "NAAM01E15HK123456",
});
expect(result.attempts[1]).toMatchObject({
plate: previousPlate,
vin: "NAAM01E15HK123456",
});
});
it("rejects a car-body policyholder on a third-party case", () => {
expect(() =>
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
driver: {
nationalCode: "0012345678",
birthday: "1370/01/01",
hasDrivingLicense: false,
},
vehicleOwner: { sameAs: InquiryParticipantRole.DRIVER },
thirdPartyPolicyholder: {
sameAs: InquiryParticipantRole.VEHICLE_OWNER,
},
carBodyPolicyholder: {
nationalCode: "0034567890",
birthday: "1350/03/03",
},
}),
).toThrow(BadRequestException);
});
it("does not accept a previous plate unless recent transfer is declared", () => {
expect(() =>
resolveInquiryVehicle({
registrationState: VehicleRegistrationState.CURRENT,
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
previousPlate: {
leftDigits: "55",
centerAlphabet: "ج",
centerDigits: "222",
ir: "33",
},
}),
).toThrow(BadRequestException);
});
it("rejects sameAs together with any person-specific fields", () => {
expect(() =>
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
driver: {
nationalCode: "0012345678",
birthday: "1370/01/01",
hasDrivingLicense: false,
},
vehicleOwner: {
sameAs: InquiryParticipantRole.DRIVER,
fullName: "Duplicate details must not be silently discarded",
},
thirdPartyPolicyholder: {
sameAs: InquiryParticipantRole.DRIVER,
},
}),
).toThrow(BadRequestException);
});
it("rejects conflicting legacy and structured current plates", () => {
expect(() =>
normalizeInquirySubmission(BlameRequestType.THIRD_PARTY, {
plate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
vehicle: {
registrationState: VehicleRegistrationState.CURRENT,
currentPlate: {
leftDigits: "55",
centerAlphabet: "ج",
centerDigits: "222",
ir: "33",
},
},
driver: {
nationalCode: "0012345678",
birthday: "1370/01/01",
hasDrivingLicense: false,
},
vehicleOwner: { sameAs: InquiryParticipantRole.DRIVER },
thirdPartyPolicyholder: {
sameAs: InquiryParticipantRole.DRIVER,
},
}),
).toThrow(BadRequestException);
});
it("treats an expired policy result as stale", () => {
expect(isMappedPolicyCurrent({ EndDate: "1404/01/01" }, "2026-09-13")).toBe(
false,
);
expect(isMappedPolicyCurrent({ EndDate: "1406/01/01" }, "2026-09-13")).toBe(
true,
);
});
it("falls back from a stale current policy to a current previous-plate policy", async () => {
const currentPlate = {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
};
const previousPlate = {
leftDigits: "55",
centerAlphabet: "ج",
centerDigits: "222",
ir: "33",
};
const query = jest
.fn()
.mockResolvedValueOnce({
mapped: { CompanyName: "پارسیان", EndDate: "1404/01/01" },
})
.mockResolvedValueOnce({
mapped: {
CompanyName: "پارسیان",
EndDate: "1406/01/01",
VinNumberField: "NAAM01E15HK123456",
},
});
const result = await runPlateInquiryWithFallback<{
mapped: Record<string, any>;
}>({
vehicle: resolveInquiryVehicle({
registrationState: VehicleRegistrationState.RECENTLY_TRANSFERRED,
currentPlate,
previousPlate,
vin: "NAAM01E15HK123456",
}),
fallbackCurrentPlate: currentPlate,
query,
isUsable: (value) =>
!!value.mapped.CompanyName &&
isMappedPolicyCurrent(value.mapped, "2026-09-13"),
mappedValue: (value) => value.mapped,
});
expect(result.plateKind).toBe("PREVIOUS");
expect(result.attempts[0]).toMatchObject({
plateKind: "CURRENT",
succeeded: true,
usable: false,
});
});
it("rejects the result and retains audit attempts when every plate is unusable", async () => {
const currentPlate = {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
};
const previousPlate = {
leftDigits: "55",
centerAlphabet: "ج",
centerDigits: "222",
ir: "33",
};
await expect(
runPlateInquiryWithFallback({
vehicle: resolveInquiryVehicle({
registrationState: VehicleRegistrationState.RECENTLY_TRANSFERRED,
currentPlate,
previousPlate,
vin: "NAAM01E15HK123456",
}),
fallbackCurrentPlate: currentPlate,
query: async () => ({ mapped: { CompanyName: "پارسیان" } }),
isUsable: () => false,
mappedValue: (value) => value.mapped,
}),
).rejects.toMatchObject({
attempts: [
{ plateKind: "CURRENT", succeeded: true, usable: false },
{ plateKind: "PREVIOUS", succeeded: true, usable: false },
],
});
});
it("does not use the previous plate after a transport or provider outage", async () => {
const currentPlate = {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
};
const query = jest.fn().mockRejectedValue(
Object.assign(new Error("upstream timeout"), {
code: "ETIMEDOUT",
}),
);
await expect(
runPlateInquiryWithFallback({
vehicle: resolveInquiryVehicle({
registrationState: VehicleRegistrationState.RECENTLY_TRANSFERRED,
currentPlate,
previousPlate: {
leftDigits: "55",
centerAlphabet: "ج",
centerDigits: "222",
ir: "33",
},
vin: "NAAM01E15HK123456",
}),
fallbackCurrentPlate: currentPlate,
query,
isUsable: () => false,
mappedValue: () => ({}),
}),
).rejects.toThrow("upstream timeout");
expect(query).toHaveBeenCalledTimes(1);
});
it("allows an explicitly unknown policyholder only for a damaged-party submission", () => {
const input = {
driver: {
nationalCode: "0012345678",
birthday: "1370/01/01",
hasDrivingLicense: false,
},
vehicleOwner: { sameAs: InquiryParticipantRole.DRIVER },
thirdPartyPolicyholder: { unknown: true },
};
expect(() =>
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, input),
).toThrow(BadRequestException);
const resolved = resolveInquiryParticipants(
BlameRequestType.THIRD_PARTY,
input,
{ allowUnknownThirdPartyPolicyholder: true },
);
expect(
participantForRole(
resolved,
InquiryParticipantRole.THIRD_PARTY_POLICYHOLDER,
),
).toMatchObject({ unknown: true });
});
});