Require structured inquiry participant inputs

This commit is contained in:
SepehrYahyaee
2026-09-13 14:13:05 +03:30
parent cc8a96c875
commit 5b77241f28
9 changed files with 162 additions and 602 deletions

View File

@@ -15,7 +15,6 @@ export interface ResolvedInquiryParticipant {
nationalCode: string;
birthday: string;
fullName?: string;
phoneNumber?: string;
hasDrivingLicense?: boolean;
licenseNumber?: string;
licenseType?: string;
@@ -90,6 +89,11 @@ function requiredIdentity(
role: InquiryParticipantRole,
input: InquiryParticipantInputDto,
): ResolvedInquiryParticipant {
if (Object.prototype.hasOwnProperty.call(input, "phoneNumber")) {
throw new BadRequestException(
`${role} does not accept phoneNumber; phone numbers are collected separately from inquiry identity.`,
);
}
const nationalCode = String(input.nationalCode ?? "").trim();
const birthday = String(input.birthday ?? "").trim();
if (!nationalCode || !birthday) {
@@ -118,7 +122,6 @@ function requiredIdentity(
nationalCode,
birthday,
...(input.fullName ? { fullName: input.fullName } : {}),
...(input.phoneNumber ? { phoneNumber: input.phoneNumber } : {}),
...(input.hasDrivingLicense != null
? { hasDrivingLicense: input.hasDrivingLicense }
: {}),
@@ -129,52 +132,17 @@ function requiredIdentity(
export function resolveInquiryParticipants(
caseType: BlameRequestType,
input: InquiryParticipantFieldsDto & Record<string, any>,
input: Partial<InquiryParticipantFieldsDto> & Record<string, any>,
options: InquiryParticipantResolutionOptions = {},
): ResolvedInquiryParticipants {
assertStructuredInquiryInput(input);
const hasRoleCompleteInput = Object.values(ROLE_FIELDS).some(
(field) => input[field] != null,
);
if (!hasRoleCompleteInput) {
const driverId = InquiryParticipantRole.DRIVER;
const policyholderId = input.driverIsInsurer
? driverId
: InquiryParticipantRole.THIRD_PARTY_POLICYHOLDER;
const participants: ResolvedInquiryParticipant[] = [
{
participantId: driverId,
nationalCode: String(input.nationalCodeOfDriver ?? ""),
birthday: String(
input.driverBirthday ??
(input.driverIsInsurer ? input.insurerBirthday : "") ??
"",
),
...(input.driverLicense
? { licenseNumber: String(input.driverLicense) }
: {}),
...(input.licenseType
? { licenseType: String(input.licenseType) }
: {}),
...(input.userNoCertificate != null
? { hasDrivingLicense: !input.userNoCertificate }
: {}),
},
];
if (policyholderId !== driverId) {
participants.push({
participantId: policyholderId,
nationalCode: String(input.nationalCodeOfInsurer ?? ""),
birthday: String(input.insurerBirthday ?? ""),
});
}
return {
participants,
roles: {
driver: driverId,
thirdPartyPolicyholder: policyholderId,
},
legacy: true,
};
throw new BadRequestException(
"driver, vehicleOwner, and thirdPartyPolicyholder are required in the structured inquiry format.",
);
}
if (
caseType === BlameRequestType.THIRD_PARTY &&
@@ -367,6 +335,33 @@ function normalizePlateForComparison(
.join("|");
}
const LEGACY_INQUIRY_FIELDS = [
"nationalCodeOfDriver",
"driverBirthday",
"driverLicense",
"licenseType",
"nationalCodeOfInsurer",
"insurerBirthday",
"insurerLicense",
"driverIsInsurer",
"userNoCertificate",
"plate",
"plateId",
"vin",
"isNewCar",
] as const;
function assertStructuredInquiryInput(input: Record<string, any>): void {
const legacyFields = LEGACY_INQUIRY_FIELDS.filter((field) =>
Object.prototype.hasOwnProperty.call(input, field),
);
if (legacyFields.length > 0) {
throw new BadRequestException(
`Legacy inquiry fields are not accepted: ${legacyFields.join(", ")}. Use driver, vehicleOwner, thirdPartyPolicyholder, carBodyPolicyholder, and vehicle.`,
);
}
}
export function assertPreviousPlateInquiryMatchesVin(
expectedVin: string,
mapped: Record<string, any>,
@@ -517,7 +512,11 @@ export function normalizeInquirySubmission<T extends Record<string, any>>(
input: T,
options: InquiryParticipantResolutionOptions = {},
): NormalizedInquirySubmission<T> {
const participants = resolveInquiryParticipants(caseType, input, options);
const participants = resolveInquiryParticipants(
caseType,
input as any,
options,
);
const driver = participantForRole(
participants,
InquiryParticipantRole.DRIVER,
@@ -539,43 +538,32 @@ export function normalizeInquirySubmission<T extends Record<string, any>>(
participants,
InquiryParticipantRole.CAR_BODY_POLICYHOLDER,
);
const vehicle = input.vehicle
? resolveInquiryVehicle(input.vehicle as InquiryVehicleInputDto)
: undefined;
if (
vehicle &&
input.plate &&
normalizePlateForComparison(vehicle.currentPlate) !==
normalizePlateForComparison(input.plate)
) {
throw new BadRequestException(
"plate and vehicle.currentPlate must identify the same current plate.",
);
}
const vehicle = resolveInquiryVehicle(
input.vehicle as InquiryVehicleInputDto,
);
const sameDriverAndPolicyholder =
participants.roles.driver === participants.roles.thirdPartyPolicyholder;
return {
dto: {
...input,
...(vehicle?.currentPlate && !input.plate
? { plate: vehicle.currentPlate }
: {}),
...(vehicle?.vin && !input.vin ? { vin: vehicle.vin } : {}),
plate: vehicle.currentPlate,
vin: vehicle.vin,
nationalCodeOfDriver: driver.nationalCode,
driverBirthday: driver.birthday,
driverLicense: driver.licenseNumber,
licenseType: driver.licenseType,
userNoCertificate:
driver.hasDrivingLicense == null
? input.userNoCertificate
? undefined
: !driver.hasDrivingLicense,
nationalCodeOfInsurer: thirdPartyPolicyholder.nationalCode,
insurerBirthday: thirdPartyPolicyholder.birthday,
driverIsInsurer: sameDriverAndPolicyholder,
insurerLicense: sameDriverAndPolicyholder
? driver.licenseNumber
: input.insurerLicense,
: undefined,
isNewCar: vehicle.isNewCar,
} as NormalizedInquirySubmission<T>["dto"],
participants,
driver,