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

@@ -1,4 +1,8 @@
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
import {
ApiHideProperty,
ApiProperty,
ApiPropertyOptional,
} from "@nestjs/swagger";
import { Type } from "class-transformer";
import {
IsBoolean,
@@ -69,11 +73,6 @@ export class InquiryParticipantInputDto {
@IsString()
fullName?: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
phoneNumber?: string;
@ApiPropertyOptional({
description: "Required for a driver who has a licence.",
})
@@ -117,27 +116,31 @@ export class InquiryVehicleInputDto {
@IsString()
@MaxLength(17)
vin?: string;
@ApiPropertyOptional({
description: "Whether the vehicle is newly purchased/registered.",
})
@IsOptional()
@IsBoolean()
isNewCar?: boolean;
}
/** New role-complete contract mixed into every inquiry DTO. Legacy fields remain during rollout. */
/** Structured role-complete contract mixed into every inquiry DTO. */
export class InquiryParticipantFieldsDto {
@ApiPropertyOptional({ type: InquiryParticipantInputDto })
@IsOptional()
@ApiProperty({ type: InquiryParticipantInputDto })
@ValidateNested()
@Type(() => InquiryParticipantInputDto)
driver?: InquiryParticipantInputDto;
driver: InquiryParticipantInputDto;
@ApiPropertyOptional({ type: InquiryParticipantInputDto })
@IsOptional()
@ApiProperty({ type: InquiryParticipantInputDto })
@ValidateNested()
@Type(() => InquiryParticipantInputDto)
vehicleOwner?: InquiryParticipantInputDto;
vehicleOwner: InquiryParticipantInputDto;
@ApiPropertyOptional({ type: InquiryParticipantInputDto })
@IsOptional()
@ApiProperty({ type: InquiryParticipantInputDto })
@ValidateNested()
@Type(() => InquiryParticipantInputDto)
thirdPartyPolicyholder?: InquiryParticipantInputDto;
thirdPartyPolicyholder: InquiryParticipantInputDto;
@ApiPropertyOptional({ type: InquiryParticipantInputDto })
@IsOptional()
@@ -145,9 +148,48 @@ export class InquiryParticipantFieldsDto {
@Type(() => InquiryParticipantInputDto)
carBodyPolicyholder?: InquiryParticipantInputDto;
@ApiPropertyOptional({ type: InquiryVehicleInputDto })
@IsOptional()
@ApiProperty({ type: InquiryVehicleInputDto })
@ValidateNested()
@Type(() => InquiryVehicleInputDto)
vehicle?: InquiryVehicleInputDto;
vehicle: InquiryVehicleInputDto;
/** Internal normalized projections; rejected as request input by the resolver. */
@ApiHideProperty()
nationalCodeOfDriver?: string;
@ApiHideProperty()
driverBirthday?: any;
@ApiHideProperty()
driverLicense?: string;
@ApiHideProperty()
licenseType?: string;
@ApiHideProperty()
nationalCodeOfInsurer?: string;
@ApiHideProperty()
insurerBirthday?: any;
@ApiHideProperty()
insurerLicense?: string;
@ApiHideProperty()
driverIsInsurer?: boolean;
@ApiHideProperty()
userNoCertificate?: boolean;
@ApiHideProperty()
plate?: any;
@ApiHideProperty()
plateId?: string;
@ApiHideProperty()
vin?: string;
@ApiHideProperty()
isNewCar?: boolean;
}

View File

@@ -1,61 +1,9 @@
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
import { ApiProperty } from "@nestjs/swagger";
import { PlatesDto } from "src/plates/dto/plate.dto";
import { Plates } from "src/Types&Enums/plate.interface";
import { InquiryParticipantFieldsDto } from "src/common/dto/inquiry-participants.dto";
export class AddPlateDto extends InquiryParticipantFieldsDto {
plateId: string;
@ApiPropertyOptional({
type: String,
description: "Legacy third-party policyholder national code",
})
nationalCodeOfInsurer: string;
@ApiPropertyOptional({
type: String,
description: "Legacy driver national code",
})
nationalCodeOfDriver: string;
@ApiPropertyOptional({ type: String })
insurerLicense: string;
@ApiPropertyOptional({ type: String })
driverLicense: string;
@ApiPropertyOptional({
type: PlatesDto,
description:
"Legacy/current plate; may be supplied as vehicle.currentPlate",
})
plate: Plates;
@ApiPropertyOptional({
type: Boolean,
description: "Legacy role relationship",
})
driverIsInsurer: boolean;
@ApiProperty({ type: Boolean, required: true, default: false })
isNewCar: boolean;
@ApiPropertyOptional({
type: Boolean,
description: "Legacy; use driver.hasDrivingLicense",
})
userNoCertificate: boolean;
@ApiPropertyOptional({
type: Number,
description: "Legacy third-party policyholder birthday",
})
insurerBirthday: number;
@ApiProperty({
type: String,
required: false,
})
driverBirthday: string | null;
}
export class AddPlateDto extends InquiryParticipantFieldsDto {}
export class AddPlateProfileDto {
plateId: string;

View File

@@ -1,11 +1,5 @@
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
import {
IsNotEmpty,
IsOptional,
IsString,
MaxLength,
ValidateIf,
} from "class-validator";
import { IsNotEmpty, IsOptional, IsString } from "class-validator";
import { Types } from "mongoose";
import { AddPlateDto } from "src/profile/dto/user/AddPlateDto";
import { StepsEnum } from "src/Types&Enums/blame-request-management/steps.enum";
@@ -229,70 +223,8 @@ export class BlameConfessionDtoV2 {
imGuilty?: boolean;
}
/**
* V2 initial-form step submitted with a VIN/chassis number instead of a plate.
* All identity and license fields from {@link AddPlateDto} are preserved; only
* `plate` is replaced by `vin` (the 17-character chassis / VIN string).
*/
export class InitialFormVinDto extends InquiryParticipantFieldsDto {
@ApiPropertyOptional({
type: String,
required: false,
description: "17-character VIN / chassis number (شماره شاسی)",
example: "NAAM01E15HK123456",
maxLength: 17,
})
@IsString()
@IsNotEmpty()
@MaxLength(17)
@ValidateIf((dto) => !dto.vehicle?.vin)
vin: string;
@ApiPropertyOptional({
type: String,
description: "Legacy third-party policyholder national code",
})
@ValidateIf((dto) => !dto.thirdPartyPolicyholder)
nationalCodeOfInsurer: string;
@ApiPropertyOptional({
type: String,
description: "Legacy driver national code",
})
@ValidateIf((dto) => !dto.driver)
nationalCodeOfDriver: string;
@ApiPropertyOptional({ type: String })
insurerLicense: string;
@ApiPropertyOptional({ type: String })
driverLicense: string;
@ApiPropertyOptional({
type: Boolean,
description: "Legacy role relationship",
})
@ValidateIf((dto) => !dto.driver)
driverIsInsurer: boolean;
@ApiPropertyOptional({ type: Boolean, default: false })
isNewCar: boolean;
@ApiPropertyOptional({
type: Boolean,
description: "Legacy; use driver.hasDrivingLicense",
})
userNoCertificate: boolean;
@ApiPropertyOptional({
type: Number,
description: "Legacy policyholder birthday",
})
insurerBirthday: number;
@ApiPropertyOptional({ type: String, required: false })
driverBirthday: string | null;
}
/** V2 initial-form step submitted with the shared structured vehicle contract. */
export class InitialFormVinDto extends InquiryParticipantFieldsDto {}
// export class DocsOfThisFile {
// @ApiProperty()

View File

@@ -1,182 +1,14 @@
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
import {
IsBoolean,
IsNotEmpty,
IsOptional,
IsString,
MaxLength,
ValidateIf,
ValidateNested,
} from "class-validator";
import { Type } from "class-transformer";
import { InquiryParticipantFieldsDto } from "src/common/dto/inquiry-participants.dto";
class PlateV6Dto {
@ApiProperty({ example: "44", description: "Left two digits" })
@IsString()
@IsNotEmpty()
leftDigits: string;
@ApiProperty({ example: "ب", description: "Center alphabet letter" })
@IsString()
@IsNotEmpty()
centerAlphabet: string;
@ApiProperty({ example: "111", description: "Center three digits" })
@IsString()
@IsNotEmpty()
centerDigits: string;
@ApiProperty({
example: "22",
description: "Right two digits (Iran region code)",
})
@IsString()
@IsNotEmpty()
ir: string;
}
/**
* Inquiry body for the V6 call-center flow.
* Same as V3 but without `sheba` — the user adds their own IBAN later via the link.
*/
export class RunCallCenterInquiryV6Dto extends InquiryParticipantFieldsDto {
@ApiPropertyOptional({
type: PlateV6Dto,
description: "Plate segments — Tejarat block / third-party inquiry.",
})
@ValidateNested()
@Type(() => PlateV6Dto)
@ValidateIf((dto) => !dto.vehicle?.currentPlate)
plate: PlateV6Dto;
@ApiPropertyOptional({
example: "1234567890",
description: "Legacy third-party policyholder national code",
})
@IsString()
@IsNotEmpty()
@ValidateIf((dto) => !dto.thirdPartyPolicyholder)
nationalCodeOfInsurer: string;
@ApiPropertyOptional({
example: "1234567890",
description: "Legacy driver national code",
})
@IsString()
@IsNotEmpty()
@ValidateIf((dto) => !dto.driver)
nationalCodeOfDriver: string;
@ApiPropertyOptional({
example: true,
description: "Legacy role relationship",
})
@IsBoolean()
@ValidateIf((dto) => !dto.driver)
driverIsInsurer: boolean;
@ApiPropertyOptional({
example: 13780624,
description: "Legacy policyholder birth date (Jalali)",
})
insurerBirthday: number | string;
@ApiPropertyOptional({
example: 13780624,
description:
"Driver birth date (Jalali). Required when driverIsInsurer is false.",
})
@IsOptional()
driverBirthday?: number | string | null;
@ApiPropertyOptional({
example: "123456789",
description: "Driver license (required when driverIsInsurer is false).",
})
@IsOptional()
@IsString()
driverLicense?: string;
@ApiPropertyOptional({
example: "123456789",
description: "Insurer license (required when driverIsInsurer is true).",
})
@IsOptional()
@IsString()
insurerLicense?: string;
}
export class RunCallCenterInquiryV6Dto extends InquiryParticipantFieldsDto {}
/**
* VIN / chassis variant of the V6 call-center inquiry.
* Identical to `RunCallCenterInquiryV6Dto` but replaces `plate` with `vin`.
* Sheba (IBAN) is intentionally absent — the user provides it themselves via the link.
*/
export class RunCallCenterInquiryVinV6Dto extends InquiryParticipantFieldsDto {
@ApiPropertyOptional({
example: "NAAM01E15HK123456",
description: "17-character VIN / chassis number (شماره شاسی)",
maxLength: 17,
})
@IsString()
@IsNotEmpty()
@MaxLength(17)
@ValidateIf((dto) => !dto.vehicle?.vin)
vin: string;
@ApiPropertyOptional({
example: "1234567890",
description: "Legacy third-party policyholder national code",
})
@IsString()
@IsNotEmpty()
@ValidateIf((dto) => !dto.thirdPartyPolicyholder)
nationalCodeOfInsurer: string;
@ApiPropertyOptional({
example: "1234567890",
description: "Legacy driver national code",
})
@IsString()
@IsNotEmpty()
@ValidateIf((dto) => !dto.driver)
nationalCodeOfDriver: string;
@ApiPropertyOptional({
example: true,
description: "Legacy role relationship",
})
@IsBoolean()
@ValidateIf((dto) => !dto.driver)
driverIsInsurer: boolean;
@ApiPropertyOptional({
example: 13780624,
description: "Legacy policyholder birth date (Jalali)",
})
insurerBirthday: number | string;
@ApiPropertyOptional({
example: 13780624,
description:
"Driver birth date (Jalali). Required when driverIsInsurer is false.",
})
@IsOptional()
driverBirthday?: number | string | null;
@ApiPropertyOptional({
example: "123456789",
description: "Driver license (required when driverIsInsurer is false).",
})
@IsOptional()
@IsString()
driverLicense?: string;
@ApiPropertyOptional({
example: "123456789",
description: "Insurer license (required when driverIsInsurer is true).",
})
@IsOptional()
@IsString()
insurerLicense?: string;
}
export class RunCallCenterInquiryVinV6Dto extends InquiryParticipantFieldsDto {}

View File

@@ -1,95 +1,12 @@
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
import {
IsBoolean,
IsNotEmpty,
IsOptional,
IsString,
MaxLength,
ValidateIf,
ValidateNested,
} from "class-validator";
import { Type } from "class-transformer";
import { ApiPropertyOptional } from "@nestjs/swagger";
import { IsOptional, IsString } from "class-validator";
import { InquiryParticipantFieldsDto } from "src/common/dto/inquiry-participants.dto";
class PlateV3Dto {
@ApiProperty({ example: "44", description: "Left two digits" })
@IsString()
@IsNotEmpty()
leftDigits: string;
@ApiProperty({ example: "ب", description: "Center alphabet letter" })
@IsString()
@IsNotEmpty()
centerAlphabet: string;
@ApiProperty({ example: "111", description: "Center three digits" })
@IsString()
@IsNotEmpty()
centerDigits: string;
@ApiProperty({
example: "22",
description: "Right two digits (Iran region code)",
})
@IsString()
@IsNotEmpty()
ir: string;
}
/**
* Body for `POST run-inquiries/:requestId`.
* First call = guilty party (+ auto claim). Second call = damaged party (THIRD_PARTY only).
*/
export class RunInquiriesV3Dto extends InquiryParticipantFieldsDto {
@ApiPropertyOptional({
type: PlateV3Dto,
description: "Plate segments — Tejarat block / third-party inquiry.",
})
@ValidateNested()
@Type(() => PlateV3Dto)
@ValidateIf((dto) => !dto.vehicle?.currentPlate)
plate: PlateV3Dto;
@ApiPropertyOptional({
example: "1234567890",
description: "Legacy third-party policyholder national code",
})
@IsString()
@IsNotEmpty()
@ValidateIf((dto) => !dto.thirdPartyPolicyholder)
nationalCodeOfInsurer: string;
@ApiPropertyOptional({
example: "1234567890",
description: "Legacy driver national code",
})
@IsString()
@IsNotEmpty()
@ValidateIf((dto) => !dto.driver)
nationalCodeOfDriver: string;
@ApiPropertyOptional({
example: true,
description: "Legacy role relationship",
})
@IsBoolean()
@ValidateIf((dto) => !dto.driver)
driverIsInsurer: boolean;
@ApiPropertyOptional({
example: 13780624,
description: "Legacy policyholder birth date (Jalali)",
})
insurerBirthday: number | string;
@ApiPropertyOptional({
example: 13780624,
description:
"Driver birth date (Jalali). Required when driverIsInsurer is false.",
})
@IsOptional()
driverBirthday?: number | string | null;
@ApiPropertyOptional({
example: "IR123456789012345678901234",
description:
@@ -98,32 +15,6 @@ export class RunInquiriesV3Dto extends InquiryParticipantFieldsDto {
@IsOptional()
@IsString()
sheba?: string;
@ApiPropertyOptional({
example: "123456789",
description: "Driver license (required when driverIsInsurer is false).",
})
@IsOptional()
@IsString()
driverLicense?: string;
@ApiPropertyOptional({
example: "123456789",
description: "Insurer license (required when driverIsInsurer is true).",
})
@IsOptional()
@IsString()
insurerLicense?: string;
@ApiPropertyOptional({
example: "1",
description:
"Driving licence type code from GET /lookups/driving-licence-types. " +
"Optional — used in V4 FileMaker flow.",
})
@IsOptional()
@IsString()
licenseType?: string;
}
/**
@@ -132,57 +23,6 @@ export class RunInquiriesV3Dto extends InquiryParticipantFieldsDto {
* First call = guilty party (+ auto claim). Second call = damaged party (THIRD_PARTY only).
*/
export class RunInquiriesVinV3Dto extends InquiryParticipantFieldsDto {
@ApiPropertyOptional({
example: "NAAM01E15HK123456",
description: "17-character VIN / chassis number (شماره شاسی)",
maxLength: 17,
})
@IsString()
@IsNotEmpty()
@MaxLength(17)
@ValidateIf((dto) => !dto.vehicle?.vin)
vin: string;
@ApiPropertyOptional({
example: "1234567890",
description: "Legacy third-party policyholder national code",
})
@IsString()
@IsNotEmpty()
@ValidateIf((dto) => !dto.thirdPartyPolicyholder)
nationalCodeOfInsurer: string;
@ApiPropertyOptional({
example: "1234567890",
description: "Legacy driver national code",
})
@IsString()
@IsNotEmpty()
@ValidateIf((dto) => !dto.driver)
nationalCodeOfDriver: string;
@ApiPropertyOptional({
example: true,
description: "Legacy role relationship",
})
@IsBoolean()
@ValidateIf((dto) => !dto.driver)
driverIsInsurer: boolean;
@ApiPropertyOptional({
example: 13780624,
description: "Legacy policyholder birth date (Jalali)",
})
insurerBirthday: number | string;
@ApiPropertyOptional({
example: 13780624,
description:
"Driver birth date (Jalali). Required when driverIsInsurer is false.",
})
@IsOptional()
driverBirthday?: number | string | null;
@ApiPropertyOptional({
example: "IR123456789012345678901234",
description:
@@ -191,30 +31,4 @@ export class RunInquiriesVinV3Dto extends InquiryParticipantFieldsDto {
@IsOptional()
@IsString()
sheba?: string;
@ApiPropertyOptional({
example: "123456789",
description: "Driver license (required when driverIsInsurer is false).",
})
@IsOptional()
@IsString()
driverLicense?: string;
@ApiPropertyOptional({
example: "123456789",
description: "Insurer license (required when driverIsInsurer is true).",
})
@IsOptional()
@IsString()
insurerLicense?: string;
@ApiPropertyOptional({
example: "1",
description:
"Driving licence type code from GET /lookups/driving-licence-types. " +
"Optional — used in V4 FileMaker flow.",
})
@IsOptional()
@IsString()
licenseType?: string;
}

View File

@@ -66,22 +66,34 @@ describe("inquiry participant resolver", () => {
).toBe(VehicleRegistrationState.CURRENT);
});
it("keeps legacy driver/policyholder payloads working during rollout", () => {
const resolved = resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
nationalCodeOfDriver: "0012345678",
driverBirthday: "1370/01/01",
driverLicense: "123456789",
nationalCodeOfInsurer: "0098765432",
insurerBirthday: "1360/02/02",
driverIsInsurer: false,
} as any);
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);
});
expect(resolved.legacy).toBe(true);
expect(resolved.roles.driver).toBe("DRIVER");
expect(resolved.roles.thirdPartyPolicyholder).toBe(
"THIRD_PARTY_POLICYHOLDER",
);
expect(resolved.roles.vehicleOwner).toBeUndefined();
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", () => {
@@ -116,11 +128,13 @@ describe("inquiry participant resolver", () => {
it("projects role-complete input onto the existing inquiry fields", () => {
const normalized = normalizeInquirySubmission(BlameRequestType.CAR_BODY, {
plate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
vehicle: {
currentPlate: {
leftDigits: "44",
centerAlphabet: "ب",
centerDigits: "111",
ir: "22",
},
},
driver: {
nationalCode: "0012345678",

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,