Files
yara724-api/src/request-management/inquiry-participant-resolver.spec.ts
2026-09-19 12:11:43 +03:30

575 lines
17 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 {
isMappedPolicyCurrent,
normalizeInquirySubmission,
participantForRole,
participantForStoredPartyRole,
resolveInquiryParticipants,
resolveInquirySubjects,
resolveInquiryVehicle,
runCurrentPlateInquiry,
sanitizeStoredInquiryParticipants,
} 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("requires the previous policyholder national code for a recent transfer", () => {
expect(() =>
resolveInquiryVehicle({
registrationState: VehicleRegistrationState.RECENTLY_TRANSFERRED,
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
previousPlate: {
leftDigits: "55",
centerAlphabet: "ج",
centerDigits: "222",
ir: "33",
},
vin: "NAAM01E15HK123456",
}),
).toThrow("کد ملی بیمه‌گذار قبلی");
});
it("defaults an omitted registration state to CURRENT", () => {
expect(
resolveInquiryVehicle({
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
}).registrationState,
).toBe(VehicleRegistrationState.CURRENT);
});
it("requires an exact 17-character VIN whenever VIN is provided", () => {
expect(() =>
resolveInquiryVehicle({
registrationState: VehicleRegistrationState.CURRENT,
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
vin: "TOO-SHORT",
}),
).toThrow("شماره شاسی (VIN) باید دقیقاً ۱۷ کاراکتر باشد.");
});
it("rejects an incomplete current plate", () => {
expect(() =>
resolveInquiryVehicle({
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "",
ir: "22",
},
}),
).toThrow("سه رقم میانی پلاک در پلاک فعلی الزامی است.");
});
it("rejects invalid vehicle choice values", () => {
expect(() =>
resolveInquiryVehicle({
registrationState: "SOLD" as any,
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
}),
).toThrow("وضعیت پلاک خودرو باید «فعلی» یا «تازه تعویض‌شده» باشد.");
expect(() =>
resolveInquiryVehicle({
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
isNewCar: "false" as any,
}),
).toThrow("وضعیت صفر بودن خودرو نامعتبر است.");
});
it("rejects a previous policyholder national code for a current registration", () => {
expect(() =>
resolveInquiryVehicle({
registrationState: VehicleRegistrationState.CURRENT,
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
previousPolicyholderNationalCode: "0098765432",
}),
).toThrow(BadRequestException);
});
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("routes each inquiry to its domain participant", () => {
const normalized = normalizeInquirySubmission(BlameRequestType.CAR_BODY, {
vehicle: {
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
},
driver: {
nationalCode: "0011111111",
birthday: "1370/01/01",
hasDrivingLicense: false,
},
vehicleOwner: {
nationalCode: "0022222222",
birthday: "1365/02/02",
},
thirdPartyPolicyholder: {
nationalCode: "0033333333",
birthday: "1360/03/03",
},
carBodyPolicyholder: {
nationalCode: "0044444444",
birthday: "1355/04/04",
},
});
expect(resolveInquirySubjects(normalized)).toEqual({
thirdPartyPolicyNationalCode: "0033333333",
carBodyPolicyNationalCode: "0044444444",
shebaNationalCode: "0022222222",
driverNationalCode: "0011111111",
});
});
it("resolves a persisted vehicle owner for later Sheba validation", () => {
const party = {
participants: [
{ participantId: "DRIVER", nationalCode: "0011111111" },
{ participantId: "VEHICLE_OWNER", nationalCode: "0022222222" },
],
participantRoles: {
driver: "DRIVER",
vehicleOwner: "VEHICLE_OWNER",
thirdPartyPolicyholder: "DRIVER",
},
};
expect(
participantForStoredPartyRole(party, InquiryParticipantRole.VEHICLE_OWNER)
?.nationalCode,
).toBe("0022222222");
});
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("runs only one inquiry for the current plate", async () => {
const currentPlate = {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
};
const query = jest.fn().mockResolvedValue({
mapped: { CompanyName: "پارسیان" },
});
const result = await runCurrentPlateInquiry<{
mapped: { CompanyName?: string };
}>({
currentPlate,
vin: "NAAM01E15HK123456",
query,
isUsable: (value) => !!value.mapped.CompanyName,
});
expect(query).toHaveBeenCalledTimes(1);
expect(query).toHaveBeenCalledWith(currentPlate);
expect(result.plateKind).toBe("CURRENT");
expect(result.attempts).toMatchObject([
{ plateKind: "CURRENT", succeeded: true, usable: true },
]);
expect(result.attempts[0]).toMatchObject({
plate: currentPlate,
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("rejects a stale current policy without trying another plate", async () => {
const currentPlate = {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
};
const query = jest.fn().mockResolvedValue({
mapped: { CompanyName: "پارسیان", EndDate: "1404/01/01" },
});
await expect(
runCurrentPlateInquiry<{ mapped: Record<string, any> }>({
currentPlate,
query,
isUsable: (value) =>
!!value.mapped.CompanyName &&
isMappedPolicyCurrent(value.mapped, "2026-09-13"),
}),
).rejects.toMatchObject({
attempts: [{ plateKind: "CURRENT", succeeded: true, usable: false }],
});
expect(query).toHaveBeenCalledTimes(1);
});
it("retains the current-plate audit attempt when the result is unusable", async () => {
const currentPlate = {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
};
await expect(
runCurrentPlateInquiry({
currentPlate,
vin: "NAAM01E15HK123456",
query: async () => ({ mapped: { CompanyName: "پارسیان" } }),
isUsable: () => false,
}),
).rejects.toMatchObject({
attempts: [{ plateKind: "CURRENT", succeeded: true, usable: false }],
});
});
it("preserves a mapped provider message when the current result is unusable", async () => {
const currentPlate = {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
};
await expect(
runCurrentPlateInquiry({
currentPlate,
query: async () => ({
mapped: { Error: { Message: "رکوردی یافت نشد" } },
}),
isUsable: () => false,
errorMessage: (value) => value.mapped.Error.Message,
}),
).rejects.toThrow("رکوردی یافت نشد");
});
it("retains one failed current-plate attempt after a 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(
runCurrentPlateInquiry({
currentPlate,
vin: "NAAM01E15HK123456",
query,
isUsable: () => false,
}),
).rejects.toThrow("upstream timeout");
expect(query).toHaveBeenCalledTimes(1);
});
it("rejects the removed unknown policyholder option", () => {
const input = {
driver: {
nationalCode: "0012345678",
birthday: "1370/01/01",
hasDrivingLicense: false,
},
vehicleOwner: { sameAs: InquiryParticipantRole.DRIVER },
thirdPartyPolicyholder: { unknown: true },
};
expect(() =>
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, input as any),
).toThrow("ثبت بیمه‌گذار شخص ثالث به‌صورت نامشخص امکان‌پذیر نیست.");
});
it("strips the removed unknown field from historical participant output", () => {
expect(
sanitizeStoredInquiryParticipants([
{
participantId: "THIRD_PARTY_POLICYHOLDER",
nationalCode: "0012345678",
unknown: true,
},
]),
).toEqual([
{
participantId: "THIRD_PARTY_POLICYHOLDER",
nationalCode: "0012345678",
},
]);
});
});