forked from Yara724/api
Merge pull request 'Fixed Participants' (#314) from s.yahyaee/yara724-api:main into main
Reviewed-on: Yara724/api#314
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
|||||||
} from "src/helpers/blame-damaged-party";
|
} from "src/helpers/blame-damaged-party";
|
||||||
import { toJalaliDateAndTime } from "src/helpers/date-jalali";
|
import { toJalaliDateAndTime } from "src/helpers/date-jalali";
|
||||||
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
||||||
|
import { sanitizeStoredInquiryParticipants } from "src/request-management/inquiry-participant-resolver";
|
||||||
import {
|
import {
|
||||||
InsurerFileReportField,
|
InsurerFileReportField,
|
||||||
InsurerFileReportSection,
|
InsurerFileReportSection,
|
||||||
@@ -611,9 +612,8 @@ function buildParticipantRolesSection(
|
|||||||
title: string,
|
title: string,
|
||||||
party: ReportParty | null | undefined,
|
party: ReportParty | null | undefined,
|
||||||
): InsurerFileReportSection | undefined {
|
): InsurerFileReportSection | undefined {
|
||||||
const participants = Array.isArray(party?.participants)
|
const participants =
|
||||||
? party.participants
|
sanitizeStoredInquiryParticipants(party?.participants) ?? [];
|
||||||
: [];
|
|
||||||
const assignments = party?.participantRoles;
|
const assignments = party?.participantRoles;
|
||||||
if (!assignments || participants.length === 0) return undefined;
|
if (!assignments || participants.length === 0) return undefined;
|
||||||
|
|
||||||
@@ -627,9 +627,7 @@ function buildParticipantRolesSection(
|
|||||||
const participant = participants.find(
|
const participant = participants.find(
|
||||||
(candidate) => String(candidate.participantId) === String(participantId),
|
(candidate) => String(candidate.participantId) === String(participantId),
|
||||||
);
|
);
|
||||||
const value = participant?.unknown
|
const value = [
|
||||||
? PR.unknown
|
|
||||||
: [
|
|
||||||
asString(participant?.fullName),
|
asString(participant?.fullName),
|
||||||
participant?.nationalCode
|
participant?.nationalCode
|
||||||
? `${PR.nationalCode}: ${asString(participant.nationalCode)}`
|
? `${PR.nationalCode}: ${asString(participant.nationalCode)}`
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ export const PR = {
|
|||||||
vehicleOwnerRole: "مالک وسیله نقلیه",
|
vehicleOwnerRole: "مالک وسیله نقلیه",
|
||||||
thirdPartyPolicyholderRole: "بیمهگذار شخص ثالث",
|
thirdPartyPolicyholderRole: "بیمهگذار شخص ثالث",
|
||||||
carBodyPolicyholderRole: "بیمهگذار بدنه",
|
carBodyPolicyholderRole: "بیمهگذار بدنه",
|
||||||
unknown: "نامشخص",
|
|
||||||
data: "اطلاعات",
|
data: "اطلاعات",
|
||||||
date: "تاریخ",
|
date: "تاریخ",
|
||||||
time: "زمان",
|
time: "زمان",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
IsNotEmpty,
|
IsNotEmpty,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString,
|
||||||
MaxLength,
|
Length,
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from "class-validator";
|
} from "class-validator";
|
||||||
|
|
||||||
@@ -51,14 +51,6 @@ export class InquiryParticipantInputDto {
|
|||||||
@IsEnum(InquiryParticipantRole)
|
@IsEnum(InquiryParticipantRole)
|
||||||
sameAs?: InquiryParticipantRole;
|
sameAs?: InquiryParticipantRole;
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
|
||||||
description:
|
|
||||||
"Only for the damaged party's third-party policyholder when the identity is genuinely unknown.",
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsBoolean()
|
|
||||||
unknown?: boolean;
|
|
||||||
|
|
||||||
@ApiPropertyOptional({ example: "0012345678" })
|
@ApiPropertyOptional({ example: "0012345678" })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
@@ -111,10 +103,23 @@ export class InquiryVehicleInputDto {
|
|||||||
@Type(() => InquiryPlateDto)
|
@Type(() => InquiryPlateDto)
|
||||||
previousPlate?: InquiryPlateDto;
|
previousPlate?: InquiryPlateDto;
|
||||||
|
|
||||||
@ApiPropertyOptional({ maxLength: 17, example: "NAAM01E15HK123456" })
|
@ApiPropertyOptional({
|
||||||
|
description:
|
||||||
|
"National code of the policyholder associated with previousPlate. Required only for RECENTLY_TRANSFERRED vehicles.",
|
||||||
|
example: "0012345678",
|
||||||
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
@MaxLength(17)
|
previousPolicyholderNationalCode?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
minLength: 17,
|
||||||
|
maxLength: 17,
|
||||||
|
example: "NAAM01E15HK123456",
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@Length(17, 17)
|
||||||
vin?: string;
|
vin?: string;
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ import { ClaimWorkflowStep } from "src/Types&Enums/claim-request-management/clai
|
|||||||
import { ClaimRequiredDocumentType } from "src/Types&Enums/claim-request-management/required-document-type.enum";
|
import { ClaimRequiredDocumentType } from "src/Types&Enums/claim-request-management/required-document-type.enum";
|
||||||
import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum";
|
import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum";
|
||||||
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
||||||
|
import { sanitizeStoredInquiryParticipants } from "src/request-management/inquiry-participant-resolver";
|
||||||
import {
|
import {
|
||||||
GetClaimListV2ResponseDto,
|
GetClaimListV2ResponseDto,
|
||||||
ClaimListItemV2Dto,
|
ClaimListItemV2Dto,
|
||||||
@@ -4551,7 +4552,12 @@ export class ExpertClaimService {
|
|||||||
(doc as Record<string, unknown>).updatedAtFormatted =
|
(doc as Record<string, unknown>).updatedAtFormatted =
|
||||||
`${updatedDate} ${updatedTime}`;
|
`${updatedDate} ${updatedTime}`;
|
||||||
|
|
||||||
docRec.parties = enrichBlamePartiesForAgreementView(docRec);
|
docRec.parties = enrichBlamePartiesForAgreementView(docRec).map(
|
||||||
|
(party) => ({
|
||||||
|
...party,
|
||||||
|
participants: sanitizeStoredInquiryParticipants(party.participants),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
return docRec;
|
return docRec;
|
||||||
}
|
}
|
||||||
@@ -4577,7 +4583,11 @@ export class ExpertClaimService {
|
|||||||
if (Array.isArray(parties)) {
|
if (Array.isArray(parties)) {
|
||||||
out.parties = parties.map((p: any) =>
|
out.parties = parties.map((p: any) =>
|
||||||
p && typeof p === "object"
|
p && typeof p === "object"
|
||||||
? { ...p, vehicle: this.sanitizeVehicleInquiryForApi(p.vehicle) }
|
? {
|
||||||
|
...p,
|
||||||
|
participants: sanitizeStoredInquiryParticipants(p.participants),
|
||||||
|
vehicle: this.sanitizeVehicleInquiryForApi(p.vehicle),
|
||||||
|
}
|
||||||
: p,
|
: p,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import { toJalaliDateAndTime } from "src/helpers/date-jalali";
|
|||||||
import { enrichBlamePartiesForAgreementView } from "src/helpers/blame-party-agreement-decision";
|
import { enrichBlamePartiesForAgreementView } from "src/helpers/blame-party-agreement-decision";
|
||||||
import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum";
|
import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum";
|
||||||
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
||||||
|
import { sanitizeStoredInquiryParticipants } from "src/request-management/inquiry-participant-resolver";
|
||||||
import { ListQueryV2Dto } from "src/common/dto/list-query-v2.dto";
|
import { ListQueryV2Dto } from "src/common/dto/list-query-v2.dto";
|
||||||
import {
|
import {
|
||||||
UnifiedFileStatusReportDto,
|
UnifiedFileStatusReportDto,
|
||||||
@@ -449,6 +450,7 @@ export class ExpertInsurerService {
|
|||||||
if (!party || typeof party !== "object") return party;
|
if (!party || typeof party !== "object") return party;
|
||||||
return {
|
return {
|
||||||
...party,
|
...party,
|
||||||
|
participants: sanitizeStoredInquiryParticipants(party.participants),
|
||||||
person: this.mapPersonForInsurer(party.person, clientNames),
|
person: this.mapPersonForInsurer(party.person, clientNames),
|
||||||
vehicle: this.sanitizeVehicleInquiry(party.vehicle),
|
vehicle: this.sanitizeVehicleInquiry(party.vehicle),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ export class InquiryParticipant {
|
|||||||
@Prop({ type: Boolean }) hasDrivingLicense?: boolean;
|
@Prop({ type: Boolean }) hasDrivingLicense?: boolean;
|
||||||
@Prop() licenseNumber?: string;
|
@Prop() licenseNumber?: string;
|
||||||
@Prop() licenseType?: string;
|
@Prop() licenseType?: string;
|
||||||
@Prop({ type: Boolean }) unknown?: boolean;
|
|
||||||
}
|
}
|
||||||
export const InquiryParticipantSchema =
|
export const InquiryParticipantSchema =
|
||||||
SchemaFactory.createForClass(InquiryParticipant);
|
SchemaFactory.createForClass(InquiryParticipant);
|
||||||
@@ -94,6 +93,7 @@ export class Vehicle {
|
|||||||
@Prop({ enum: ["CURRENT", "RECENTLY_TRANSFERRED"] })
|
@Prop({ enum: ["CURRENT", "RECENTLY_TRANSFERRED"] })
|
||||||
registrationState?: "CURRENT" | "RECENTLY_TRANSFERRED";
|
registrationState?: "CURRENT" | "RECENTLY_TRANSFERRED";
|
||||||
@Prop() previousPlateId?: string;
|
@Prop() previousPlateId?: string;
|
||||||
|
@Prop() previousPolicyholderNationalCode?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Full external inquiry payload (Tejarat/SandHub) stored as-is
|
* Full external inquiry payload (Tejarat/SandHub) stored as-is
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ export class FirstPartyDetail {
|
|||||||
|
|
||||||
@Prop() registrationState?: string;
|
@Prop() registrationState?: string;
|
||||||
@Prop() previousPlateId?: string;
|
@Prop() previousPlateId?: string;
|
||||||
|
@Prop() previousPolicyholderNationalCode?: string;
|
||||||
@Prop() vehicleVin?: string;
|
@Prop() vehicleVin?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +210,7 @@ export class SecondPartyDetail {
|
|||||||
|
|
||||||
@Prop() registrationState?: string;
|
@Prop() registrationState?: string;
|
||||||
@Prop() previousPlateId?: string;
|
@Prop() previousPlateId?: string;
|
||||||
|
@Prop() previousPolicyholderNationalCode?: string;
|
||||||
@Prop() vehicleVin?: string;
|
@Prop() vehicleVin?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -115,4 +115,34 @@ describe("inquiry participant persistence", () => {
|
|||||||
|
|
||||||
expect(() => (query as any)._castUpdate(query.getUpdate())).not.toThrow();
|
expect(() => (query as any)._castUpdate(query.getUpdate())).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("stores the previous policyholder national code with transferred vehicle data", () => {
|
||||||
|
const BlameRequestModel = model<BlameRequest>(
|
||||||
|
"PreviousPolicyholderPersistenceTest",
|
||||||
|
BlameRequestSchema,
|
||||||
|
);
|
||||||
|
const request = new BlameRequestModel({
|
||||||
|
requestNo: "BL-PREVIOUS-POLICYHOLDER",
|
||||||
|
publicId: "PREVIOUS-POLICYHOLDER",
|
||||||
|
type: BlameRequestType.THIRD_PARTY,
|
||||||
|
parties: [
|
||||||
|
{
|
||||||
|
role: PartyRole.FIRST,
|
||||||
|
person: {},
|
||||||
|
vehicle: {
|
||||||
|
plateId: "22-44-ب-111",
|
||||||
|
previousPlateId: "33-55-ج-222",
|
||||||
|
previousPolicyholderNationalCode: "0098765432",
|
||||||
|
registrationState: "RECENTLY_TRANSFERRED",
|
||||||
|
vin: "NAAM01E15HK123456",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(request.validateSync()).toBeUndefined();
|
||||||
|
expect(request.parties[0].vehicle?.previousPolicyholderNationalCode).toBe(
|
||||||
|
"0098765432",
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
resolveInquirySubjects,
|
resolveInquirySubjects,
|
||||||
resolveInquiryVehicle,
|
resolveInquiryVehicle,
|
||||||
runPlateInquiryWithFallback,
|
runPlateInquiryWithFallback,
|
||||||
|
sanitizeStoredInquiryParticipants,
|
||||||
vehiclePlateCandidates,
|
vehiclePlateCandidates,
|
||||||
} from "./inquiry-participant-resolver";
|
} from "./inquiry-participant-resolver";
|
||||||
|
|
||||||
@@ -55,6 +56,27 @@ describe("inquiry participant resolver", () => {
|
|||||||
).toThrow(BadRequestException);
|
).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("previousPolicyholderNationalCode");
|
||||||
|
});
|
||||||
|
|
||||||
it("defaults an omitted registration state to CURRENT", () => {
|
it("defaults an omitted registration state to CURRENT", () => {
|
||||||
expect(
|
expect(
|
||||||
resolveInquiryVehicle({
|
resolveInquiryVehicle({
|
||||||
@@ -68,6 +90,75 @@ describe("inquiry participant resolver", () => {
|
|||||||
).toBe(VehicleRegistrationState.CURRENT);
|
).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("vehicle.vin must contain exactly 17 characters.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects an incomplete current plate", () => {
|
||||||
|
expect(() =>
|
||||||
|
resolveInquiryVehicle({
|
||||||
|
currentPlate: {
|
||||||
|
leftDigits: "44",
|
||||||
|
centerAlphabet: "ب",
|
||||||
|
centerDigits: "",
|
||||||
|
ir: "22",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toThrow("vehicle.currentPlate.centerDigits is required.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects invalid vehicle choice values", () => {
|
||||||
|
expect(() =>
|
||||||
|
resolveInquiryVehicle({
|
||||||
|
registrationState: "SOLD" as any,
|
||||||
|
currentPlate: {
|
||||||
|
leftDigits: "44",
|
||||||
|
centerAlphabet: "ب",
|
||||||
|
centerDigits: "111",
|
||||||
|
ir: "22",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toThrow("vehicle.registrationState must be CURRENT or RECENTLY_TRANSFERRED.");
|
||||||
|
|
||||||
|
expect(() =>
|
||||||
|
resolveInquiryVehicle({
|
||||||
|
currentPlate: {
|
||||||
|
leftDigits: "44",
|
||||||
|
centerAlphabet: "ب",
|
||||||
|
centerDigits: "111",
|
||||||
|
ir: "22",
|
||||||
|
},
|
||||||
|
isNewCar: "false" as any,
|
||||||
|
}),
|
||||||
|
).toThrow("vehicle.isNewCar must be a boolean.");
|
||||||
|
});
|
||||||
|
|
||||||
|
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", () => {
|
it("rejects the removed flat inquiry contract", () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
|
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
|
||||||
@@ -238,6 +329,7 @@ describe("inquiry participant resolver", () => {
|
|||||||
currentPlate,
|
currentPlate,
|
||||||
previousPlate,
|
previousPlate,
|
||||||
vin: "NAAM01E15HK123456",
|
vin: "NAAM01E15HK123456",
|
||||||
|
previousPolicyholderNationalCode: "0098765432",
|
||||||
}),
|
}),
|
||||||
).toEqual([
|
).toEqual([
|
||||||
{ kind: "CURRENT", plate: currentPlate },
|
{ kind: "CURRENT", plate: currentPlate },
|
||||||
@@ -293,6 +385,7 @@ describe("inquiry participant resolver", () => {
|
|||||||
currentPlate,
|
currentPlate,
|
||||||
previousPlate,
|
previousPlate,
|
||||||
vin: "NAAM01E15HK123456",
|
vin: "NAAM01E15HK123456",
|
||||||
|
previousPolicyholderNationalCode: "0098765432",
|
||||||
},
|
},
|
||||||
fallbackCurrentPlate: currentPlate,
|
fallbackCurrentPlate: currentPlate,
|
||||||
query,
|
query,
|
||||||
@@ -301,6 +394,8 @@ describe("inquiry participant resolver", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(query).toHaveBeenCalledTimes(2);
|
expect(query).toHaveBeenCalledTimes(2);
|
||||||
|
expect(query).toHaveBeenNthCalledWith(1, currentPlate, "CURRENT");
|
||||||
|
expect(query).toHaveBeenNthCalledWith(2, previousPlate, "PREVIOUS");
|
||||||
expect(result.plateKind).toBe("PREVIOUS");
|
expect(result.plateKind).toBe("PREVIOUS");
|
||||||
expect(result.attempts).toMatchObject([
|
expect(result.attempts).toMatchObject([
|
||||||
{ plateKind: "CURRENT", succeeded: false, error: "not found" },
|
{ plateKind: "CURRENT", succeeded: false, error: "not found" },
|
||||||
@@ -449,6 +544,7 @@ describe("inquiry participant resolver", () => {
|
|||||||
currentPlate,
|
currentPlate,
|
||||||
previousPlate,
|
previousPlate,
|
||||||
vin: "NAAM01E15HK123456",
|
vin: "NAAM01E15HK123456",
|
||||||
|
previousPolicyholderNationalCode: "0098765432",
|
||||||
}),
|
}),
|
||||||
fallbackCurrentPlate: currentPlate,
|
fallbackCurrentPlate: currentPlate,
|
||||||
query,
|
query,
|
||||||
@@ -487,6 +583,7 @@ describe("inquiry participant resolver", () => {
|
|||||||
currentPlate,
|
currentPlate,
|
||||||
previousPlate,
|
previousPlate,
|
||||||
vin: "NAAM01E15HK123456",
|
vin: "NAAM01E15HK123456",
|
||||||
|
previousPolicyholderNationalCode: "0098765432",
|
||||||
}),
|
}),
|
||||||
fallbackCurrentPlate: currentPlate,
|
fallbackCurrentPlate: currentPlate,
|
||||||
query: async () => ({ mapped: { CompanyName: "پارسیان" } }),
|
query: async () => ({ mapped: { CompanyName: "پارسیان" } }),
|
||||||
@@ -526,6 +623,7 @@ describe("inquiry participant resolver", () => {
|
|||||||
ir: "33",
|
ir: "33",
|
||||||
},
|
},
|
||||||
vin: "NAAM01E15HK123456",
|
vin: "NAAM01E15HK123456",
|
||||||
|
previousPolicyholderNationalCode: "0098765432",
|
||||||
}),
|
}),
|
||||||
fallbackCurrentPlate: currentPlate,
|
fallbackCurrentPlate: currentPlate,
|
||||||
query,
|
query,
|
||||||
@@ -536,7 +634,7 @@ describe("inquiry participant resolver", () => {
|
|||||||
expect(query).toHaveBeenCalledTimes(1);
|
expect(query).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("allows an explicitly unknown policyholder only for a damaged-party submission", () => {
|
it("rejects the removed unknown policyholder option", () => {
|
||||||
const input = {
|
const input = {
|
||||||
driver: {
|
driver: {
|
||||||
nationalCode: "0012345678",
|
nationalCode: "0012345678",
|
||||||
@@ -548,19 +646,24 @@ describe("inquiry participant resolver", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, input),
|
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, input as any),
|
||||||
).toThrow(BadRequestException);
|
).toThrow("THIRD_PARTY_POLICYHOLDER does not support the unknown option.");
|
||||||
|
});
|
||||||
|
|
||||||
const resolved = resolveInquiryParticipants(
|
it("strips the removed unknown field from historical participant output", () => {
|
||||||
BlameRequestType.THIRD_PARTY,
|
|
||||||
input,
|
|
||||||
{ allowUnknownThirdPartyPolicyholder: true },
|
|
||||||
);
|
|
||||||
expect(
|
expect(
|
||||||
participantForRole(
|
sanitizeStoredInquiryParticipants([
|
||||||
resolved,
|
{
|
||||||
InquiryParticipantRole.THIRD_PARTY_POLICYHOLDER,
|
participantId: "THIRD_PARTY_POLICYHOLDER",
|
||||||
),
|
nationalCode: "0012345678",
|
||||||
).toMatchObject({ unknown: true });
|
unknown: true,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
participantId: "THIRD_PARTY_POLICYHOLDER",
|
||||||
|
nationalCode: "0012345678",
|
||||||
|
},
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,11 +18,6 @@ export interface ResolvedInquiryParticipant {
|
|||||||
hasDrivingLicense?: boolean;
|
hasDrivingLicense?: boolean;
|
||||||
licenseNumber?: string;
|
licenseNumber?: string;
|
||||||
licenseType?: string;
|
licenseType?: string;
|
||||||
unknown?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InquiryParticipantResolutionOptions {
|
|
||||||
allowUnknownThirdPartyPolicyholder?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InquiryParticipantRoleAssignments {
|
export interface InquiryParticipantRoleAssignments {
|
||||||
@@ -96,6 +91,22 @@ export type ResolvedInquiryVehicle = InquiryVehicleInputDto & {
|
|||||||
registrationState: VehicleRegistrationState;
|
registrationState: VehicleRegistrationState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function assertCompleteInquiryPlate(
|
||||||
|
plate: InquiryVehicleInputDto["currentPlate"],
|
||||||
|
path: "vehicle.currentPlate" | "vehicle.previousPlate",
|
||||||
|
): void {
|
||||||
|
for (const field of [
|
||||||
|
"leftDigits",
|
||||||
|
"centerAlphabet",
|
||||||
|
"centerDigits",
|
||||||
|
"ir",
|
||||||
|
] as const) {
|
||||||
|
if (plate?.[field] == null || String(plate[field]).trim() === "") {
|
||||||
|
throw new BadRequestException(`${path}.${field} is required.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function participantForRole(
|
export function participantForRole(
|
||||||
resolved: ResolvedInquiryParticipants,
|
resolved: ResolvedInquiryParticipants,
|
||||||
role: InquiryParticipantRole,
|
role: InquiryParticipantRole,
|
||||||
@@ -127,6 +138,23 @@ export function participantForStoredPartyRole(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Remove fields retired from the participant contract from historical records. */
|
||||||
|
export function sanitizeStoredInquiryParticipants(
|
||||||
|
participants: unknown,
|
||||||
|
): Array<Record<string, any>> | undefined {
|
||||||
|
if (!Array.isArray(participants)) return undefined;
|
||||||
|
return participants.map((participant) => {
|
||||||
|
const plain =
|
||||||
|
participant &&
|
||||||
|
typeof participant === "object" &&
|
||||||
|
typeof (participant as { toObject?: unknown }).toObject === "function"
|
||||||
|
? (participant as { toObject: () => Record<string, any> }).toObject()
|
||||||
|
: { ...(participant as Record<string, any>) };
|
||||||
|
delete plain.unknown;
|
||||||
|
return plain;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const ROLE_FIELDS: Record<
|
const ROLE_FIELDS: Record<
|
||||||
InquiryParticipantRole,
|
InquiryParticipantRole,
|
||||||
keyof InquiryParticipantFieldsDto
|
keyof InquiryParticipantFieldsDto
|
||||||
@@ -185,7 +213,6 @@ function requiredIdentity(
|
|||||||
export function resolveInquiryParticipants(
|
export function resolveInquiryParticipants(
|
||||||
caseType: BlameRequestType,
|
caseType: BlameRequestType,
|
||||||
input: Partial<InquiryParticipantFieldsDto> & Record<string, any>,
|
input: Partial<InquiryParticipantFieldsDto> & Record<string, any>,
|
||||||
options: InquiryParticipantResolutionOptions = {},
|
|
||||||
): ResolvedInquiryParticipants {
|
): ResolvedInquiryParticipants {
|
||||||
assertStructuredInquiryInput(input);
|
assertStructuredInquiryInput(input);
|
||||||
const hasRoleCompleteInput = Object.values(ROLE_FIELDS).some(
|
const hasRoleCompleteInput = Object.values(ROLE_FIELDS).some(
|
||||||
@@ -232,32 +259,7 @@ export function resolveInquiryParticipants(
|
|||||||
|
|
||||||
resolving.add(role);
|
resolving.add(role);
|
||||||
let participantId: string;
|
let participantId: string;
|
||||||
if (
|
if (Object.prototype.hasOwnProperty.call(value, "unknown")) {
|
||||||
role === InquiryParticipantRole.THIRD_PARTY_POLICYHOLDER &&
|
|
||||||
value.unknown === true
|
|
||||||
) {
|
|
||||||
if (!options.allowUnknownThirdPartyPolicyholder) {
|
|
||||||
throw new BadRequestException(
|
|
||||||
"An unknown third-party policyholder is allowed only for the damaged party.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const hasIdentityFields = Object.entries(value).some(
|
|
||||||
([field, fieldValue]) => field !== "unknown" && fieldValue != null,
|
|
||||||
);
|
|
||||||
if (hasIdentityFields) {
|
|
||||||
throw new BadRequestException(
|
|
||||||
`${role} must contain either unknown=true or person fields, not both.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const participant: ResolvedInquiryParticipant = {
|
|
||||||
participantId: role,
|
|
||||||
nationalCode: "",
|
|
||||||
birthday: "",
|
|
||||||
unknown: true,
|
|
||||||
};
|
|
||||||
participants.set(participant.participantId, participant);
|
|
||||||
participantId = participant.participantId;
|
|
||||||
} else if (value.unknown != null) {
|
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
`${role} does not support the unknown option.`,
|
`${role} does not support the unknown option.`,
|
||||||
);
|
);
|
||||||
@@ -314,28 +316,59 @@ export function resolveInquiryParticipants(
|
|||||||
export function resolveInquiryVehicle(
|
export function resolveInquiryVehicle(
|
||||||
input: InquiryVehicleInputDto,
|
input: InquiryVehicleInputDto,
|
||||||
): ResolvedInquiryVehicle {
|
): ResolvedInquiryVehicle {
|
||||||
|
if (!input) {
|
||||||
|
throw new BadRequestException("vehicle is required.");
|
||||||
|
}
|
||||||
const registrationState =
|
const registrationState =
|
||||||
input.registrationState ?? VehicleRegistrationState.CURRENT;
|
input.registrationState ?? VehicleRegistrationState.CURRENT;
|
||||||
|
if (!Object.values(VehicleRegistrationState).includes(registrationState)) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"vehicle.registrationState must be CURRENT or RECENTLY_TRANSFERRED.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (input.isNewCar != null && typeof input.isNewCar !== "boolean") {
|
||||||
|
throw new BadRequestException("vehicle.isNewCar must be a boolean.");
|
||||||
|
}
|
||||||
|
const previousPolicyholderNationalCode = String(
|
||||||
|
input.previousPolicyholderNationalCode ?? "",
|
||||||
|
).trim();
|
||||||
if (!input.currentPlate) {
|
if (!input.currentPlate) {
|
||||||
throw new BadRequestException("vehicle.currentPlate is required.");
|
throw new BadRequestException("vehicle.currentPlate is required.");
|
||||||
}
|
}
|
||||||
|
assertCompleteInquiryPlate(input.currentPlate, "vehicle.currentPlate");
|
||||||
|
const vin = String(input.vin ?? "").trim();
|
||||||
|
if (vin && vin.length !== 17) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"vehicle.vin must contain exactly 17 characters.",
|
||||||
|
);
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
registrationState === VehicleRegistrationState.RECENTLY_TRANSFERRED &&
|
registrationState === VehicleRegistrationState.RECENTLY_TRANSFERRED &&
|
||||||
(!input.previousPlate || !String(input.vin ?? "").trim())
|
(!input.previousPlate || !vin || !previousPolicyholderNationalCode)
|
||||||
) {
|
) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
"RECENTLY_TRANSFERRED requires previousPlate and vin.",
|
"RECENTLY_TRANSFERRED requires previousPlate, vin, and previousPolicyholderNationalCode.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
registrationState !== VehicleRegistrationState.RECENTLY_TRANSFERRED &&
|
registrationState !== VehicleRegistrationState.RECENTLY_TRANSFERRED &&
|
||||||
input.previousPlate
|
(input.previousPlate || input.previousPolicyholderNationalCode != null)
|
||||||
) {
|
) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
"previousPlate is only allowed for RECENTLY_TRANSFERRED vehicles.",
|
"previousPlate and previousPolicyholderNationalCode are only allowed for RECENTLY_TRANSFERRED vehicles.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return { ...input, registrationState };
|
if (input.previousPlate) {
|
||||||
|
assertCompleteInquiryPlate(input.previousPlate, "vehicle.previousPlate");
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...input,
|
||||||
|
registrationState,
|
||||||
|
...(vin ? { vin } : {}),
|
||||||
|
...(previousPolicyholderNationalCode
|
||||||
|
? { previousPolicyholderNationalCode }
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function vehiclePlateCandidates(input?: ResolvedInquiryVehicle): Array<{
|
export function vehiclePlateCandidates(input?: ResolvedInquiryVehicle): Array<{
|
||||||
@@ -459,7 +492,10 @@ export function isPolicyNotFoundError(error: unknown): boolean {
|
|||||||
export async function runPlateInquiryWithFallback<T>(options: {
|
export async function runPlateInquiryWithFallback<T>(options: {
|
||||||
vehicle?: ResolvedInquiryVehicle;
|
vehicle?: ResolvedInquiryVehicle;
|
||||||
fallbackCurrentPlate: InquiryVehicleInputDto["currentPlate"];
|
fallbackCurrentPlate: InquiryVehicleInputDto["currentPlate"];
|
||||||
query: (plate: InquiryVehicleInputDto["currentPlate"]) => Promise<T>;
|
query: (
|
||||||
|
plate: InquiryVehicleInputDto["currentPlate"],
|
||||||
|
plateKind: "CURRENT" | "PREVIOUS",
|
||||||
|
) => Promise<T>;
|
||||||
isUsable: (value: T) => boolean;
|
isUsable: (value: T) => boolean;
|
||||||
mappedValue: (value: T) => Record<string, any>;
|
mappedValue: (value: T) => Record<string, any>;
|
||||||
shouldFallbackOnError?: (error: unknown) => boolean;
|
shouldFallbackOnError?: (error: unknown) => boolean;
|
||||||
@@ -492,7 +528,7 @@ export async function runPlateInquiryWithFallback<T>(options: {
|
|||||||
const candidate = candidates[index];
|
const candidate = candidates[index];
|
||||||
const isLast = index === candidates.length - 1;
|
const isLast = index === candidates.length - 1;
|
||||||
try {
|
try {
|
||||||
const value = await options.query(candidate.plate);
|
const value = await options.query(candidate.plate, candidate.kind);
|
||||||
const usable = options.isUsable(value);
|
const usable = options.isUsable(value);
|
||||||
if (!usable) {
|
if (!usable) {
|
||||||
attempts.push({
|
attempts.push({
|
||||||
@@ -562,13 +598,8 @@ export async function runPlateInquiryWithFallback<T>(options: {
|
|||||||
export function normalizeInquirySubmission<T extends Record<string, any>>(
|
export function normalizeInquirySubmission<T extends Record<string, any>>(
|
||||||
caseType: BlameRequestType,
|
caseType: BlameRequestType,
|
||||||
input: T,
|
input: T,
|
||||||
options: InquiryParticipantResolutionOptions = {},
|
|
||||||
): NormalizedInquirySubmission<T> {
|
): NormalizedInquirySubmission<T> {
|
||||||
const participants = resolveInquiryParticipants(
|
const participants = resolveInquiryParticipants(caseType, input as any);
|
||||||
caseType,
|
|
||||||
input as any,
|
|
||||||
options,
|
|
||||||
);
|
|
||||||
const driver = participantForRole(
|
const driver = participantForRole(
|
||||||
participants,
|
participants,
|
||||||
InquiryParticipantRole.DRIVER,
|
InquiryParticipantRole.DRIVER,
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { RequestManagementService } from "./request-management.service";
|
||||||
|
|
||||||
|
describe("damaged-party inquiry requirements", () => {
|
||||||
|
const getService = () => {
|
||||||
|
const service = Object.create(
|
||||||
|
RequestManagementService.prototype,
|
||||||
|
) as RequestManagementService;
|
||||||
|
(service as any).sandHubService = {
|
||||||
|
getShebaValidation: jest.fn().mockResolvedValue({ valid: true }),
|
||||||
|
};
|
||||||
|
return service;
|
||||||
|
};
|
||||||
|
|
||||||
|
it("requires Sheba when the claimant/damaged-party validation runs", async () => {
|
||||||
|
const service = getService();
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
(service as any).validateShebaV3(
|
||||||
|
undefined,
|
||||||
|
"0012345678",
|
||||||
|
"client-id",
|
||||||
|
),
|
||||||
|
).rejects.toThrow("sheba is required for the damaged party.");
|
||||||
|
expect(
|
||||||
|
(service as any).sandHubService.getShebaValidation,
|
||||||
|
).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validates damaged-party Sheba against the vehicle owner's national code", async () => {
|
||||||
|
const service = getService();
|
||||||
|
|
||||||
|
await (service as any).validateShebaV3(
|
||||||
|
"IR123456789012345678901234",
|
||||||
|
"0012345678",
|
||||||
|
"client-id",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
(service as any).sandHubService.getShebaValidation,
|
||||||
|
).toHaveBeenCalledWith("0012345678", "IR123456789012345678901234", {
|
||||||
|
clientId: "client-id",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum";
|
||||||
|
import { RequestManagementService } from "./request-management.service";
|
||||||
|
|
||||||
|
describe("RequestManagementService previous policyholder routing", () => {
|
||||||
|
const currentPlate = {
|
||||||
|
leftDigits: "44",
|
||||||
|
centerAlphabet: "ب",
|
||||||
|
centerDigits: "111",
|
||||||
|
ir: "22",
|
||||||
|
};
|
||||||
|
const previousPlate = {
|
||||||
|
leftDigits: "55",
|
||||||
|
centerAlphabet: "ج",
|
||||||
|
centerDigits: "222",
|
||||||
|
ir: "33",
|
||||||
|
};
|
||||||
|
const vehicle = {
|
||||||
|
registrationState: "RECENTLY_TRANSFERRED",
|
||||||
|
currentPlate,
|
||||||
|
previousPlate,
|
||||||
|
previousPolicyholderNationalCode: "0098765432",
|
||||||
|
vin: "NAAM01E15HK123456",
|
||||||
|
};
|
||||||
|
|
||||||
|
function participantInput(caseType: BlameRequestType) {
|
||||||
|
return {
|
||||||
|
driver: {
|
||||||
|
nationalCode: "0011111111",
|
||||||
|
birthday: "1370/01/01",
|
||||||
|
hasDrivingLicense: false,
|
||||||
|
},
|
||||||
|
vehicleOwner: { sameAs: "DRIVER" },
|
||||||
|
thirdPartyPolicyholder: {
|
||||||
|
nationalCode: "0022222222",
|
||||||
|
birthday: "1360/02/02",
|
||||||
|
},
|
||||||
|
...(caseType === BlameRequestType.CAR_BODY
|
||||||
|
? {
|
||||||
|
carBodyPolicyholder: {
|
||||||
|
nationalCode: "0033333333",
|
||||||
|
birthday: "1350/03/03",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
vehicle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
it("uses the previous code only for the previous-plate third-party lookup", async () => {
|
||||||
|
const service = Object.create(RequestManagementService.prototype) as any;
|
||||||
|
service.sandHubService = {
|
||||||
|
getTejaratBlockInquiry: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce({ raw: {}, mapped: {} })
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
raw: {},
|
||||||
|
mapped: {
|
||||||
|
CompanyName: "پارسیان",
|
||||||
|
VinNumberField: vehicle.vin,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const submission = service.normalizeInquiryInput(
|
||||||
|
BlameRequestType.THIRD_PARTY,
|
||||||
|
participantInput(BlameRequestType.THIRD_PARTY),
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await service.getThirdPartyPlateInquiry(submission);
|
||||||
|
|
||||||
|
expect(result.plateKind).toBe("PREVIOUS");
|
||||||
|
expect(
|
||||||
|
service.sandHubService.getTejaratBlockInquiry,
|
||||||
|
).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
expect.objectContaining({
|
||||||
|
plate: currentPlate,
|
||||||
|
nationalCodeOfInsurer: "0022222222",
|
||||||
|
}),
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
service.sandHubService.getTejaratBlockInquiry,
|
||||||
|
).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
expect.objectContaining({
|
||||||
|
plate: previousPlate,
|
||||||
|
nationalCodeOfInsurer: "0098765432",
|
||||||
|
}),
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses the previous code only for the previous-plate car-body lookup", async () => {
|
||||||
|
const service = Object.create(RequestManagementService.prototype) as any;
|
||||||
|
service.sandHubService = {
|
||||||
|
getCarBodyInquiry: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce({ raw: {}, mapped: {} })
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
raw: {},
|
||||||
|
mapped: {
|
||||||
|
policyNumber: "BODY-1",
|
||||||
|
VinNumberField: vehicle.vin,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const submission = service.normalizeInquiryInput(
|
||||||
|
BlameRequestType.CAR_BODY,
|
||||||
|
participantInput(BlameRequestType.CAR_BODY),
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await service.getCarBodyPlateInquiry(submission);
|
||||||
|
|
||||||
|
expect(result.plateKind).toBe("PREVIOUS");
|
||||||
|
expect(service.sandHubService.getCarBodyInquiry).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
expect.objectContaining({
|
||||||
|
plate: currentPlate,
|
||||||
|
nationalCodeOfInsurer: "0033333333",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(service.sandHubService.getCarBodyInquiry).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
expect.objectContaining({
|
||||||
|
plate: previousPlate,
|
||||||
|
nationalCodeOfInsurer: "0098765432",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -130,6 +130,7 @@ import {
|
|||||||
normalizeInquirySubmission,
|
normalizeInquirySubmission,
|
||||||
resolveInquirySubjects,
|
resolveInquirySubjects,
|
||||||
runPlateInquiryWithFallback,
|
runPlateInquiryWithFallback,
|
||||||
|
sanitizeStoredInquiryParticipants,
|
||||||
} from "./inquiry-participant-resolver";
|
} from "./inquiry-participant-resolver";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -311,12 +312,8 @@ export class RequestManagementService {
|
|||||||
private normalizeInquiryInput<T extends Record<string, any>>(
|
private normalizeInquiryInput<T extends Record<string, any>>(
|
||||||
type: BlameRequestType,
|
type: BlameRequestType,
|
||||||
input: T,
|
input: T,
|
||||||
partyRole?: PartyRole,
|
|
||||||
): NormalizedInquirySubmission<T> {
|
): NormalizedInquirySubmission<T> {
|
||||||
return normalizeInquirySubmission(type, input, {
|
return normalizeInquirySubmission(type, input);
|
||||||
allowUnknownThirdPartyPolicyholder:
|
|
||||||
type === BlameRequestType.THIRD_PARTY && partyRole === PartyRole.SECOND,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private applyInquiryParticipantsToParty(
|
private applyInquiryParticipantsToParty(
|
||||||
@@ -334,6 +331,8 @@ export class RequestManagementService {
|
|||||||
party.vehicle.previousPlateId = submission.vehicle.previousPlate
|
party.vehicle.previousPlateId = submission.vehicle.previousPlate
|
||||||
? this.plateToPlateIdString(submission.vehicle.previousPlate)
|
? this.plateToPlateIdString(submission.vehicle.previousPlate)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
party.vehicle.previousPolicyholderNationalCode =
|
||||||
|
submission.vehicle.previousPolicyholderNationalCode;
|
||||||
if (submission.vehicle.vin) party.vehicle.vin = submission.vehicle.vin;
|
if (submission.vehicle.vin) party.vehicle.vin = submission.vehicle.vin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,24 +353,18 @@ export class RequestManagementService {
|
|||||||
submission: NormalizedInquirySubmission<Record<string, any>>,
|
submission: NormalizedInquirySubmission<Record<string, any>>,
|
||||||
options?: Record<string, any>,
|
options?: Record<string, any>,
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
if (submission.thirdPartyPolicyholder.unknown) {
|
|
||||||
return {
|
|
||||||
raw: null,
|
|
||||||
mapped: {},
|
|
||||||
skipped: true,
|
|
||||||
plateKind: "CURRENT",
|
|
||||||
attempts: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const subjects = resolveInquirySubjects(submission);
|
const subjects = resolveInquirySubjects(submission);
|
||||||
const result = await runPlateInquiryWithFallback({
|
const result = await runPlateInquiryWithFallback({
|
||||||
vehicle: submission.vehicle,
|
vehicle: submission.vehicle,
|
||||||
fallbackCurrentPlate: submission.dto.plate,
|
fallbackCurrentPlate: submission.dto.plate,
|
||||||
query: (plate) =>
|
query: (plate, plateKind) =>
|
||||||
this.sandHubService.getTejaratBlockInquiry(
|
this.sandHubService.getTejaratBlockInquiry(
|
||||||
{
|
{
|
||||||
plate: plate as any,
|
plate: plate as any,
|
||||||
nationalCodeOfInsurer: subjects.thirdPartyPolicyNationalCode,
|
nationalCodeOfInsurer:
|
||||||
|
plateKind === "PREVIOUS"
|
||||||
|
? submission.vehicle!.previousPolicyholderNationalCode!
|
||||||
|
: subjects.thirdPartyPolicyNationalCode,
|
||||||
},
|
},
|
||||||
options,
|
options,
|
||||||
),
|
),
|
||||||
@@ -401,9 +394,12 @@ export class RequestManagementService {
|
|||||||
const result = await runPlateInquiryWithFallback({
|
const result = await runPlateInquiryWithFallback({
|
||||||
vehicle: submission.vehicle,
|
vehicle: submission.vehicle,
|
||||||
fallbackCurrentPlate: submission.dto.plate,
|
fallbackCurrentPlate: submission.dto.plate,
|
||||||
query: (plate) =>
|
query: (plate, plateKind) =>
|
||||||
this.sandHubService.getCarBodyInquiry({
|
this.sandHubService.getCarBodyInquiry({
|
||||||
nationalCodeOfInsurer: policyholderNationalCode,
|
nationalCodeOfInsurer:
|
||||||
|
plateKind === "PREVIOUS"
|
||||||
|
? submission.vehicle!.previousPolicyholderNationalCode!
|
||||||
|
: policyholderNationalCode,
|
||||||
plate: plate as any,
|
plate: plate as any,
|
||||||
}),
|
}),
|
||||||
isUsable: (value) =>
|
isUsable: (value) =>
|
||||||
@@ -435,9 +431,6 @@ export class RequestManagementService {
|
|||||||
"vehicle.vin is required for a VIN/chassis inquiry.",
|
"vehicle.vin is required for a VIN/chassis inquiry.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (submission.thirdPartyPolicyholder.unknown) {
|
|
||||||
return { raw: null, mapped: {}, skipped: true };
|
|
||||||
}
|
|
||||||
const subjects = resolveInquirySubjects(submission);
|
const subjects = resolveInquirySubjects(submission);
|
||||||
const result = await this.sandHubService.getPolicyByChassisInquiry(
|
const result = await this.sandHubService.getPolicyByChassisInquiry(
|
||||||
{
|
{
|
||||||
@@ -446,7 +439,7 @@ export class RequestManagementService {
|
|||||||
},
|
},
|
||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
return { ...result, skipped: false };
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async runParticipantPersonalInquiries(
|
private async runParticipantPersonalInquiries(
|
||||||
@@ -457,9 +450,7 @@ export class RequestManagementService {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const participants = submission.participants.legacy
|
const participants = submission.participants.legacy
|
||||||
? [submission.thirdPartyPolicyholder]
|
? [submission.thirdPartyPolicyholder]
|
||||||
: submission.participants.participants.filter(
|
: submission.participants.participants;
|
||||||
(participant) => !participant.unknown,
|
|
||||||
);
|
|
||||||
const results: Record<string, unknown> = {};
|
const results: Record<string, unknown> = {};
|
||||||
|
|
||||||
for (const participant of participants) {
|
for (const participant of participants) {
|
||||||
@@ -598,7 +589,6 @@ export class RequestManagementService {
|
|||||||
|
|
||||||
const personal: Record<string, unknown> = {};
|
const personal: Record<string, unknown> = {};
|
||||||
for (const participant of submission.participants.participants) {
|
for (const participant of submission.participants.participants) {
|
||||||
if (participant.unknown) continue;
|
|
||||||
personal[participant.participantId] =
|
personal[participant.participantId] =
|
||||||
await this.sandHubService.getPersonalInquiry(
|
await this.sandHubService.getPersonalInquiry(
|
||||||
participant.nationalCode,
|
participant.nationalCode,
|
||||||
@@ -664,6 +654,8 @@ export class RequestManagementService {
|
|||||||
[`${prefix}.previousPlateId`]: submission.vehicle?.previousPlate
|
[`${prefix}.previousPlateId`]: submission.vehicle?.previousPlate
|
||||||
? this.plateToPlateIdString(submission.vehicle.previousPlate)
|
? this.plateToPlateIdString(submission.vehicle.previousPlate)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
[`${prefix}.previousPolicyholderNationalCode`]:
|
||||||
|
submission.vehicle?.previousPolicyholderNationalCode,
|
||||||
[`${prefix}.vehicleVin`]: submission.vehicle?.vin,
|
[`${prefix}.vehicleVin`]: submission.vehicle?.vin,
|
||||||
[`${prefix}.policyInquiry`]: audit,
|
[`${prefix}.policyInquiry`]: audit,
|
||||||
},
|
},
|
||||||
@@ -1732,12 +1724,9 @@ export class RequestManagementService {
|
|||||||
const inquirySubmission = this.normalizeInquiryInput(
|
const inquirySubmission = this.normalizeInquiryInput(
|
||||||
req.type,
|
req.type,
|
||||||
body,
|
body,
|
||||||
role,
|
|
||||||
);
|
);
|
||||||
body = inquirySubmission.dto as unknown as AddPlateDto;
|
body = inquirySubmission.dto as unknown as AddPlateDto;
|
||||||
this.applyInquiryParticipantsToParty(party, inquirySubmission);
|
this.applyInquiryParticipantsToParty(party, inquirySubmission);
|
||||||
const policyholderUnknown =
|
|
||||||
inquirySubmission.thirdPartyPolicyholder.unknown === true;
|
|
||||||
|
|
||||||
// Validation: driver/insurer sameness rules
|
// Validation: driver/insurer sameness rules
|
||||||
if (body.driverIsInsurer === false) {
|
if (body.driverIsInsurer === false) {
|
||||||
@@ -1801,19 +1790,13 @@ export class RequestManagementService {
|
|||||||
req,
|
req,
|
||||||
"thirdParty",
|
"thirdParty",
|
||||||
role,
|
role,
|
||||||
!inquiry.skipped,
|
true,
|
||||||
{
|
{
|
||||||
source: inquirySource,
|
source: inquirySource,
|
||||||
plateKind: inquiry.plateKind,
|
plateKind: inquiry.plateKind,
|
||||||
attempts: inquiry.attempts,
|
attempts: inquiry.attempts,
|
||||||
raw: inquiryRaw,
|
raw: inquiryRaw,
|
||||||
mapped: inquiryMapped,
|
mapped: inquiryMapped,
|
||||||
...(inquiry.skipped
|
|
||||||
? {
|
|
||||||
skipped: true,
|
|
||||||
reason: "Third-party policyholder is unknown",
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (inquiry.offline?.fanavaranDriverId != null) {
|
if (inquiry.offline?.fanavaranDriverId != null) {
|
||||||
@@ -1882,7 +1865,7 @@ export class RequestManagementService {
|
|||||||
|
|
||||||
// Find client by company code
|
// Find client by company code
|
||||||
const clientName = inquiryMapped?.CompanyName;
|
const clientName = inquiryMapped?.CompanyName;
|
||||||
if (!clientName && !policyholderUnknown) {
|
if (!clientName) {
|
||||||
const error = new BadRequestException(
|
const error = new BadRequestException(
|
||||||
`CompanyName missing from inquiry response`,
|
`CompanyName missing from inquiry response`,
|
||||||
);
|
);
|
||||||
@@ -2183,13 +2166,10 @@ export class RequestManagementService {
|
|||||||
const inquirySubmission = this.normalizeInquiryInput(
|
const inquirySubmission = this.normalizeInquiryInput(
|
||||||
req.type,
|
req.type,
|
||||||
body,
|
body,
|
||||||
role,
|
|
||||||
);
|
);
|
||||||
body = inquirySubmission.dto as unknown as InitialFormVinDto;
|
body = inquirySubmission.dto as unknown as InitialFormVinDto;
|
||||||
const subjects = resolveInquirySubjects(inquirySubmission);
|
const subjects = resolveInquirySubjects(inquirySubmission);
|
||||||
this.applyInquiryParticipantsToParty(party, inquirySubmission);
|
this.applyInquiryParticipantsToParty(party, inquirySubmission);
|
||||||
const policyholderUnknown =
|
|
||||||
inquirySubmission.thirdPartyPolicyholder.unknown === true;
|
|
||||||
|
|
||||||
// Validation: driver/insurer sameness rules (identical to plate path)
|
// Validation: driver/insurer sameness rules (identical to plate path)
|
||||||
if (body.driverIsInsurer === false) {
|
if (body.driverIsInsurer === false) {
|
||||||
@@ -2246,17 +2226,11 @@ export class RequestManagementService {
|
|||||||
req,
|
req,
|
||||||
"thirdParty",
|
"thirdParty",
|
||||||
role,
|
role,
|
||||||
!inquiry.skipped,
|
true,
|
||||||
{
|
{
|
||||||
source: "ESG_VIN_INQUIRY",
|
source: "ESG_VIN_INQUIRY",
|
||||||
raw: inquiryRaw,
|
raw: inquiryRaw,
|
||||||
mapped: inquiryMapped,
|
mapped: inquiryMapped,
|
||||||
...(inquiry.skipped
|
|
||||||
? {
|
|
||||||
skipped: true,
|
|
||||||
reason: "Third-party policyholder is unknown",
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
@@ -2319,7 +2293,7 @@ export class RequestManagementService {
|
|||||||
|
|
||||||
// Resolve insurer client from inquiry response
|
// Resolve insurer client from inquiry response
|
||||||
const clientName = inquiryMapped?.CompanyName;
|
const clientName = inquiryMapped?.CompanyName;
|
||||||
if (!clientName && !policyholderUnknown) {
|
if (!clientName) {
|
||||||
const error = new BadRequestException(
|
const error = new BadRequestException(
|
||||||
"CompanyName missing from VIN inquiry response",
|
"CompanyName missing from VIN inquiry response",
|
||||||
);
|
);
|
||||||
@@ -3482,8 +3456,6 @@ export class RequestManagementService {
|
|||||||
const clientName = sandHubReport?.CompanyName;
|
const clientName = sandHubReport?.CompanyName;
|
||||||
const companyCode = sandHubReport?.CompanyCode;
|
const companyCode = sandHubReport?.CompanyCode;
|
||||||
|
|
||||||
const policyholderUnknown =
|
|
||||||
inquirySubmission?.thirdPartyPolicyholder.unknown === true;
|
|
||||||
const client = clientName
|
const client = clientName
|
||||||
? await this.clientService.findOrCreateClientByCompanyCode(
|
? await this.clientService.findOrCreateClientByCompanyCode(
|
||||||
companyCode,
|
companyCode,
|
||||||
@@ -3491,7 +3463,7 @@ export class RequestManagementService {
|
|||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (!client && !policyholderUnknown) {
|
if (!client) {
|
||||||
throw new HttpException("Client not found", HttpStatus.CONFLICT);
|
throw new HttpException("Client not found", HttpStatus.CONFLICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3529,9 +3501,7 @@ export class RequestManagementService {
|
|||||||
plate: body.plate,
|
plate: body.plate,
|
||||||
nationalCode: body.nationalCodeOfInsurer,
|
nationalCode: body.nationalCodeOfInsurer,
|
||||||
};
|
};
|
||||||
const sandHubDoc = policyInquiry?.skipped
|
const sandHubDoc = await this.sandHubService.sandHubDocumentCreator(
|
||||||
? null
|
|
||||||
: await this.sandHubService.sandHubDocumentCreator(
|
|
||||||
user.sub,
|
user.sub,
|
||||||
request["_doc"]._id,
|
request["_doc"]._id,
|
||||||
sandHubDocData,
|
sandHubDocData,
|
||||||
@@ -3592,6 +3562,8 @@ export class RequestManagementService {
|
|||||||
?.previousPlate
|
?.previousPlate
|
||||||
? this.plateToPlateIdString(inquirySubmission.vehicle.previousPlate)
|
? this.plateToPlateIdString(inquirySubmission.vehicle.previousPlate)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
setFields[`${partyDetails}.previousPolicyholderNationalCode`] =
|
||||||
|
inquirySubmission.vehicle?.previousPolicyholderNationalCode;
|
||||||
setFields[`${partyDetails}.vehicleVin`] =
|
setFields[`${partyDetails}.vehicleVin`] =
|
||||||
inquirySubmission.vehicle?.vin;
|
inquirySubmission.vehicle?.vin;
|
||||||
}
|
}
|
||||||
@@ -3704,7 +3676,6 @@ export class RequestManagementService {
|
|||||||
const inquirySubmission = this.normalizeInquiryInput(
|
const inquirySubmission = this.normalizeInquiryInput(
|
||||||
request.type as BlameRequestType,
|
request.type as BlameRequestType,
|
||||||
body,
|
body,
|
||||||
partyRole,
|
|
||||||
);
|
);
|
||||||
body = inquirySubmission.dto as unknown as AddPlateDto;
|
body = inquirySubmission.dto as unknown as AddPlateDto;
|
||||||
|
|
||||||
@@ -6641,7 +6612,6 @@ export class RequestManagementService {
|
|||||||
participantId: participant.participantId,
|
participantId: participant.participantId,
|
||||||
fullName: participant.fullName,
|
fullName: participant.fullName,
|
||||||
hasDrivingLicense: participant.hasDrivingLicense,
|
hasDrivingLicense: participant.hasDrivingLicense,
|
||||||
unknown: participant.unknown,
|
|
||||||
}))
|
}))
|
||||||
: undefined;
|
: undefined;
|
||||||
const evidenceRaw = party.evidence as Record<string, unknown> | undefined;
|
const evidenceRaw = party.evidence as Record<string, unknown> | undefined;
|
||||||
@@ -6951,7 +6921,6 @@ export class RequestManagementService {
|
|||||||
const inquirySubmission = this.normalizeInquiryInput(
|
const inquirySubmission = this.normalizeInquiryInput(
|
||||||
req.type,
|
req.type,
|
||||||
formData.firstPartyPlate,
|
formData.firstPartyPlate,
|
||||||
PartyRole.FIRST,
|
|
||||||
);
|
);
|
||||||
this.recordInquiryParticipantContext(
|
this.recordInquiryParticipantContext(
|
||||||
req,
|
req,
|
||||||
@@ -7139,6 +7108,8 @@ export class RequestManagementService {
|
|||||||
previousPlateId: inquirySubmission.vehicle?.previousPlate
|
previousPlateId: inquirySubmission.vehicle?.previousPlate
|
||||||
? this.plateToPlateIdString(inquirySubmission.vehicle.previousPlate)
|
? this.plateToPlateIdString(inquirySubmission.vehicle.previousPlate)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
previousPolicyholderNationalCode:
|
||||||
|
inquirySubmission.vehicle?.previousPolicyholderNationalCode,
|
||||||
vin: inquirySubmission.vehicle?.vin,
|
vin: inquirySubmission.vehicle?.vin,
|
||||||
inquiry: {
|
inquiry: {
|
||||||
...sandHubReport,
|
...sandHubReport,
|
||||||
@@ -7279,7 +7250,6 @@ export class RequestManagementService {
|
|||||||
const inquirySubmission = this.normalizeInquiryInput(
|
const inquirySubmission = this.normalizeInquiryInput(
|
||||||
req.type,
|
req.type,
|
||||||
plateDto,
|
plateDto,
|
||||||
role,
|
|
||||||
);
|
);
|
||||||
this.recordInquiryParticipantContext(req, role, inquirySubmission);
|
this.recordInquiryParticipantContext(req, role, inquirySubmission);
|
||||||
const existingPartyIndex = this.getPartyIndex(req, role);
|
const existingPartyIndex = this.getPartyIndex(req, role);
|
||||||
@@ -7290,8 +7260,6 @@ export class RequestManagementService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
plateDto = inquirySubmission.dto;
|
plateDto = inquirySubmission.dto;
|
||||||
const policyholderUnknown =
|
|
||||||
inquirySubmission.thirdPartyPolicyholder.unknown === true;
|
|
||||||
let inquiry: any;
|
let inquiry: any;
|
||||||
try {
|
try {
|
||||||
if (inquirySubmission.participants.legacy) {
|
if (inquirySubmission.participants.legacy) {
|
||||||
@@ -7332,19 +7300,13 @@ export class RequestManagementService {
|
|||||||
req,
|
req,
|
||||||
"thirdParty",
|
"thirdParty",
|
||||||
role,
|
role,
|
||||||
!inquiry.skipped,
|
true,
|
||||||
{
|
{
|
||||||
source: inquiry.offline?.source ?? "TEJARAT_BLOCK_INQUIRY",
|
source: inquiry.offline?.source ?? "TEJARAT_BLOCK_INQUIRY",
|
||||||
plateKind: inquiry.plateKind,
|
plateKind: inquiry.plateKind,
|
||||||
attempts: inquiry.attempts,
|
attempts: inquiry.attempts,
|
||||||
raw: inquiry.raw,
|
raw: inquiry.raw,
|
||||||
mapped: inquiry.mapped,
|
mapped: inquiry.mapped,
|
||||||
...(inquiry.skipped
|
|
||||||
? {
|
|
||||||
skipped: true,
|
|
||||||
reason: "Third-party policyholder is unknown",
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const clientName =
|
const clientName =
|
||||||
@@ -7358,7 +7320,7 @@ export class RequestManagementService {
|
|||||||
)
|
)
|
||||||
: await this.clientService.findOne({ clientName })
|
: await this.clientService.findOne({ clientName })
|
||||||
: null;
|
: null;
|
||||||
if (!client && !policyholderUnknown) {
|
if (!client) {
|
||||||
const error = new NotFoundException(
|
const error = new NotFoundException(
|
||||||
`Client not found for company: ${clientName}`,
|
`Client not found for company: ${clientName}`,
|
||||||
);
|
);
|
||||||
@@ -7434,6 +7396,8 @@ export class RequestManagementService {
|
|||||||
previousPlateId: inquirySubmission.vehicle?.previousPlate
|
previousPlateId: inquirySubmission.vehicle?.previousPlate
|
||||||
? this.plateToPlateIdString(inquirySubmission.vehicle.previousPlate)
|
? this.plateToPlateIdString(inquirySubmission.vehicle.previousPlate)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
previousPolicyholderNationalCode:
|
||||||
|
inquirySubmission.vehicle?.previousPolicyholderNationalCode,
|
||||||
vin: inquirySubmission.vehicle?.vin,
|
vin: inquirySubmission.vehicle?.vin,
|
||||||
inquiry: sandHubReport,
|
inquiry: sandHubReport,
|
||||||
},
|
},
|
||||||
@@ -8071,7 +8035,6 @@ export class RequestManagementService {
|
|||||||
const firstInquirySubmission = this.normalizeInquiryInput(
|
const firstInquirySubmission = this.normalizeInquiryInput(
|
||||||
BlameRequestType.THIRD_PARTY,
|
BlameRequestType.THIRD_PARTY,
|
||||||
formData.firstPartyPlate,
|
formData.firstPartyPlate,
|
||||||
PartyRole.FIRST,
|
|
||||||
);
|
);
|
||||||
const firstPartyPlate = firstInquirySubmission.dto;
|
const firstPartyPlate = firstInquirySubmission.dto;
|
||||||
let firstPolicyInquiry: any;
|
let firstPolicyInquiry: any;
|
||||||
@@ -8179,6 +8142,8 @@ export class RequestManagementService {
|
|||||||
firstInquirySubmission.vehicle.previousPlate,
|
firstInquirySubmission.vehicle.previousPlate,
|
||||||
)
|
)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
firstPartyDetails.previousPolicyholderNationalCode =
|
||||||
|
firstInquirySubmission.vehicle?.previousPolicyholderNationalCode;
|
||||||
firstPartyDetails.vehicleVin = firstInquirySubmission.vehicle?.vin;
|
firstPartyDetails.vehicleVin = firstInquirySubmission.vehicle?.vin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8209,7 +8174,6 @@ export class RequestManagementService {
|
|||||||
const secondInquirySubmission = this.normalizeInquiryInput(
|
const secondInquirySubmission = this.normalizeInquiryInput(
|
||||||
BlameRequestType.THIRD_PARTY,
|
BlameRequestType.THIRD_PARTY,
|
||||||
formData.secondParty.plate,
|
formData.secondParty.plate,
|
||||||
PartyRole.SECOND,
|
|
||||||
);
|
);
|
||||||
let secondPolicyInquiry: any;
|
let secondPolicyInquiry: any;
|
||||||
try {
|
try {
|
||||||
@@ -8243,8 +8207,6 @@ export class RequestManagementService {
|
|||||||
const companyCode = sandHubReport?.CompanyCode;
|
const companyCode = sandHubReport?.CompanyCode;
|
||||||
|
|
||||||
// Try to find client by company code first (more reliable)
|
// Try to find client by company code first (more reliable)
|
||||||
const policyholderUnknown =
|
|
||||||
secondInquirySubmission.thirdPartyPolicyholder.unknown === true;
|
|
||||||
const client = clientName
|
const client = clientName
|
||||||
? companyCode
|
? companyCode
|
||||||
? await this.clientService.findOrCreateClientByCompanyCode(
|
? await this.clientService.findOrCreateClientByCompanyCode(
|
||||||
@@ -8254,7 +8216,7 @@ export class RequestManagementService {
|
|||||||
: await this.clientService.findOne({ clientName: clientName })
|
: await this.clientService.findOne({ clientName: clientName })
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (!client && !policyholderUnknown) {
|
if (!client) {
|
||||||
const error = new NotFoundException(
|
const error = new NotFoundException(
|
||||||
`Client not found for company: ${clientName}${companyCode ? ` (code: ${companyCode})` : ""}`,
|
`Client not found for company: ${clientName}${companyCode ? ` (code: ${companyCode})` : ""}`,
|
||||||
);
|
);
|
||||||
@@ -8319,6 +8281,8 @@ export class RequestManagementService {
|
|||||||
secondInquirySubmission.vehicle.previousPlate,
|
secondInquirySubmission.vehicle.previousPlate,
|
||||||
)
|
)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
secondPartyDetails.previousPolicyholderNationalCode =
|
||||||
|
secondInquirySubmission.vehicle?.previousPolicyholderNationalCode;
|
||||||
secondPartyDetails.vehicleVin = secondInquirySubmission.vehicle?.vin;
|
secondPartyDetails.vehicleVin = secondInquirySubmission.vehicle?.vin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8554,7 +8518,6 @@ export class RequestManagementService {
|
|||||||
const firstInquirySubmission = this.normalizeInquiryInput(
|
const firstInquirySubmission = this.normalizeInquiryInput(
|
||||||
BlameRequestType.CAR_BODY,
|
BlameRequestType.CAR_BODY,
|
||||||
formData.firstPartyPlate,
|
formData.firstPartyPlate,
|
||||||
PartyRole.FIRST,
|
|
||||||
);
|
);
|
||||||
const firstPartyPlate = firstInquirySubmission.dto;
|
const firstPartyPlate = firstInquirySubmission.dto;
|
||||||
let thirdPartyPolicyInquiry: any;
|
let thirdPartyPolicyInquiry: any;
|
||||||
@@ -8687,6 +8650,8 @@ export class RequestManagementService {
|
|||||||
firstInquirySubmission.vehicle.previousPlate,
|
firstInquirySubmission.vehicle.previousPlate,
|
||||||
)
|
)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
firstPartyDetails.previousPolicyholderNationalCode =
|
||||||
|
firstInquirySubmission.vehicle?.previousPolicyholderNationalCode;
|
||||||
firstPartyDetails.vehicleVin = firstInquirySubmission.vehicle?.vin;
|
firstPartyDetails.vehicleVin = firstInquirySubmission.vehicle?.vin;
|
||||||
}
|
}
|
||||||
firstPartyDetails.firstPartyClient.clientId =
|
firstPartyDetails.firstPartyClient.clientId =
|
||||||
@@ -9805,13 +9770,10 @@ export class RequestManagementService {
|
|||||||
const inquirySubmission = this.normalizeInquiryInput(
|
const inquirySubmission = this.normalizeInquiryInput(
|
||||||
req.type,
|
req.type,
|
||||||
partyData,
|
partyData,
|
||||||
partyRole,
|
|
||||||
);
|
);
|
||||||
partyData = inquirySubmission.dto as RunInquiriesV3Dto;
|
partyData = inquirySubmission.dto as RunInquiriesV3Dto;
|
||||||
const subjects = resolveInquirySubjects(inquirySubmission);
|
const subjects = resolveInquirySubjects(inquirySubmission);
|
||||||
this.applyInquiryParticipantsToParty(party, inquirySubmission);
|
this.applyInquiryParticipantsToParty(party, inquirySubmission);
|
||||||
const policyholderUnknown =
|
|
||||||
inquirySubmission.thirdPartyPolicyholder.unknown === true;
|
|
||||||
const roleLabel = partyRole === PartyRole.FIRST ? "FIRST" : "SECOND";
|
const roleLabel = partyRole === PartyRole.FIRST ? "FIRST" : "SECOND";
|
||||||
let clientId: string | undefined;
|
let clientId: string | undefined;
|
||||||
const inquiryOptions = (cid?: string) =>
|
const inquiryOptions = (cid?: string) =>
|
||||||
@@ -9838,19 +9800,13 @@ export class RequestManagementService {
|
|||||||
req,
|
req,
|
||||||
"thirdParty",
|
"thirdParty",
|
||||||
partyRole,
|
partyRole,
|
||||||
!inquiry.skipped,
|
true,
|
||||||
{
|
{
|
||||||
source: inquirySource,
|
source: inquirySource,
|
||||||
plateKind: inquiry.plateKind,
|
plateKind: inquiry.plateKind,
|
||||||
attempts: inquiry.attempts,
|
attempts: inquiry.attempts,
|
||||||
raw: inquiryRaw,
|
raw: inquiryRaw,
|
||||||
mapped: inquiryMapped,
|
mapped: inquiryMapped,
|
||||||
...(inquiry.skipped
|
|
||||||
? {
|
|
||||||
skipped: true,
|
|
||||||
reason: "Third-party policyholder is unknown",
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (inquiry.offline?.fanavaranDriverId != null) {
|
if (inquiry.offline?.fanavaranDriverId != null) {
|
||||||
@@ -9900,7 +9856,7 @@ export class RequestManagementService {
|
|||||||
|
|
||||||
const clientName = inquiryMapped?.CompanyName;
|
const clientName = inquiryMapped?.CompanyName;
|
||||||
const companyCode = inquiryMapped?.CompanyCode;
|
const companyCode = inquiryMapped?.CompanyCode;
|
||||||
if (!clientName && !policyholderUnknown) {
|
if (!clientName) {
|
||||||
const error = new BadRequestException(
|
const error = new BadRequestException(
|
||||||
`CompanyName missing from ${roleLabel} party inquiry response`,
|
`CompanyName missing from ${roleLabel} party inquiry response`,
|
||||||
);
|
);
|
||||||
@@ -10162,10 +10118,14 @@ export class RequestManagementService {
|
|||||||
vehicleOwnerNationalCode: string,
|
vehicleOwnerNationalCode: string,
|
||||||
clientId?: string,
|
clientId?: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!sheba) return;
|
if (!String(sheba ?? "").trim()) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"sheba is required for the damaged party.",
|
||||||
|
);
|
||||||
|
}
|
||||||
await this.sandHubService.getShebaValidation(
|
await this.sandHubService.getShebaValidation(
|
||||||
vehicleOwnerNationalCode,
|
vehicleOwnerNationalCode,
|
||||||
sheba,
|
sheba!.trim(),
|
||||||
clientId ? { clientId } : undefined,
|
clientId ? { clientId } : undefined,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -10738,13 +10698,10 @@ export class RequestManagementService {
|
|||||||
const inquirySubmission = this.normalizeInquiryInput(
|
const inquirySubmission = this.normalizeInquiryInput(
|
||||||
req.type,
|
req.type,
|
||||||
partyData,
|
partyData,
|
||||||
partyRole,
|
|
||||||
);
|
);
|
||||||
partyData = inquirySubmission.dto as RunInquiriesVinV3Dto;
|
partyData = inquirySubmission.dto as RunInquiriesVinV3Dto;
|
||||||
const subjects = resolveInquirySubjects(inquirySubmission);
|
const subjects = resolveInquirySubjects(inquirySubmission);
|
||||||
this.applyInquiryParticipantsToParty(party, inquirySubmission);
|
this.applyInquiryParticipantsToParty(party, inquirySubmission);
|
||||||
const policyholderUnknown =
|
|
||||||
inquirySubmission.thirdPartyPolicyholder.unknown === true;
|
|
||||||
const roleLabel = partyRole === PartyRole.FIRST ? "FIRST" : "SECOND";
|
const roleLabel = partyRole === PartyRole.FIRST ? "FIRST" : "SECOND";
|
||||||
let clientId: string | undefined;
|
let clientId: string | undefined;
|
||||||
const inquiryOptions = (cid?: string) =>
|
const inquiryOptions = (cid?: string) =>
|
||||||
@@ -10763,17 +10720,11 @@ export class RequestManagementService {
|
|||||||
req,
|
req,
|
||||||
"thirdParty",
|
"thirdParty",
|
||||||
partyRole,
|
partyRole,
|
||||||
!inquiry.skipped,
|
true,
|
||||||
{
|
{
|
||||||
source: "ESG_VIN_INQUIRY",
|
source: "ESG_VIN_INQUIRY",
|
||||||
raw: inquiryRaw,
|
raw: inquiryRaw,
|
||||||
mapped: inquiryMapped,
|
mapped: inquiryMapped,
|
||||||
...(inquiry.skipped
|
|
||||||
? {
|
|
||||||
skipped: true,
|
|
||||||
reason: "Third-party policyholder is unknown",
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
@@ -10817,7 +10768,7 @@ export class RequestManagementService {
|
|||||||
|
|
||||||
const clientName = inquiryMapped?.CompanyName;
|
const clientName = inquiryMapped?.CompanyName;
|
||||||
const companyCode = inquiryMapped?.CompanyCode;
|
const companyCode = inquiryMapped?.CompanyCode;
|
||||||
if (!clientName && !policyholderUnknown) {
|
if (!clientName) {
|
||||||
const error = new BadRequestException(
|
const error = new BadRequestException(
|
||||||
`CompanyName missing from ${roleLabel} party VIN inquiry response`,
|
`CompanyName missing from ${roleLabel} party VIN inquiry response`,
|
||||||
);
|
);
|
||||||
@@ -12320,12 +12271,16 @@ export class RequestManagementService {
|
|||||||
message:
|
message:
|
||||||
"استعلام طرف مقصر با موفقیت انجام شد. اکنون میتوانید لینک تقصیر را برای کاربر ارسال کنید.",
|
"استعلام طرف مقصر با موفقیت انجام شد. اکنون میتوانید لینک تقصیر را برای کاربر ارسال کنید.",
|
||||||
guiltyParty: {
|
guiltyParty: {
|
||||||
participants: firstPartyAfter?.participants,
|
participants: sanitizeStoredInquiryParticipants(
|
||||||
|
firstPartyAfter?.participants,
|
||||||
|
),
|
||||||
participantRoles: firstPartyAfter?.participantRoles,
|
participantRoles: firstPartyAfter?.participantRoles,
|
||||||
vehicle: firstPartyAfter?.vehicle
|
vehicle: firstPartyAfter?.vehicle
|
||||||
? {
|
? {
|
||||||
plateId: firstPartyAfter.vehicle.plateId,
|
plateId: firstPartyAfter.vehicle.plateId,
|
||||||
previousPlateId: firstPartyAfter.vehicle.previousPlateId,
|
previousPlateId: firstPartyAfter.vehicle.previousPlateId,
|
||||||
|
previousPolicyholderNationalCode:
|
||||||
|
firstPartyAfter.vehicle.previousPolicyholderNationalCode,
|
||||||
registrationState: firstPartyAfter.vehicle.registrationState,
|
registrationState: firstPartyAfter.vehicle.registrationState,
|
||||||
vin: firstPartyAfter.vehicle.vin,
|
vin: firstPartyAfter.vehicle.vin,
|
||||||
name: firstPartyAfter.vehicle.name,
|
name: firstPartyAfter.vehicle.name,
|
||||||
@@ -12435,13 +12390,17 @@ export class RequestManagementService {
|
|||||||
message:
|
message:
|
||||||
"استعلام VIN طرف مقصر با موفقیت انجام شد. اکنون میتوانید لینک تقصیر را برای کاربر ارسال کنید.",
|
"استعلام VIN طرف مقصر با موفقیت انجام شد. اکنون میتوانید لینک تقصیر را برای کاربر ارسال کنید.",
|
||||||
guiltyParty: {
|
guiltyParty: {
|
||||||
participants: firstPartyAfter?.participants,
|
participants: sanitizeStoredInquiryParticipants(
|
||||||
|
firstPartyAfter?.participants,
|
||||||
|
),
|
||||||
participantRoles: firstPartyAfter?.participantRoles,
|
participantRoles: firstPartyAfter?.participantRoles,
|
||||||
vehicle: firstPartyAfter?.vehicle
|
vehicle: firstPartyAfter?.vehicle
|
||||||
? {
|
? {
|
||||||
vin: firstPartyAfter.vehicle.vin,
|
vin: firstPartyAfter.vehicle.vin,
|
||||||
plateId: firstPartyAfter.vehicle.plateId,
|
plateId: firstPartyAfter.vehicle.plateId,
|
||||||
previousPlateId: firstPartyAfter.vehicle.previousPlateId,
|
previousPlateId: firstPartyAfter.vehicle.previousPlateId,
|
||||||
|
previousPolicyholderNationalCode:
|
||||||
|
firstPartyAfter.vehicle.previousPolicyholderNationalCode,
|
||||||
registrationState: firstPartyAfter.vehicle.registrationState,
|
registrationState: firstPartyAfter.vehicle.registrationState,
|
||||||
name: firstPartyAfter.vehicle.name,
|
name: firstPartyAfter.vehicle.name,
|
||||||
type: firstPartyAfter.vehicle.type,
|
type: firstPartyAfter.vehicle.type,
|
||||||
@@ -12684,7 +12643,7 @@ export class RequestManagementService {
|
|||||||
skipInitialFormStep: (req as any).skipInitialFormStep,
|
skipInitialFormStep: (req as any).skipInitialFormStep,
|
||||||
parties: ((req as any).parties ?? []).map((p: any) => ({
|
parties: ((req as any).parties ?? []).map((p: any) => ({
|
||||||
role: p.role,
|
role: p.role,
|
||||||
participants: p.participants,
|
participants: sanitizeStoredInquiryParticipants(p.participants),
|
||||||
participantRoles: p.participantRoles,
|
participantRoles: p.participantRoles,
|
||||||
person: {
|
person: {
|
||||||
phoneNumber: p.person?.phoneNumber,
|
phoneNumber: p.person?.phoneNumber,
|
||||||
@@ -12709,6 +12668,8 @@ export class RequestManagementService {
|
|||||||
? {
|
? {
|
||||||
plateId: p.vehicle.plateId,
|
plateId: p.vehicle.plateId,
|
||||||
previousPlateId: p.vehicle.previousPlateId,
|
previousPlateId: p.vehicle.previousPlateId,
|
||||||
|
previousPolicyholderNationalCode:
|
||||||
|
p.vehicle.previousPolicyholderNationalCode,
|
||||||
registrationState: p.vehicle.registrationState,
|
registrationState: p.vehicle.registrationState,
|
||||||
vin: p.vehicle.vin,
|
vin: p.vehicle.vin,
|
||||||
name: p.vehicle.name,
|
name: p.vehicle.name,
|
||||||
@@ -12844,7 +12805,7 @@ export class RequestManagementService {
|
|||||||
requiresFileMakerApproval: plain.requiresFileMakerApproval,
|
requiresFileMakerApproval: plain.requiresFileMakerApproval,
|
||||||
parties: (plain.parties ?? []).map((p: any) => ({
|
parties: (plain.parties ?? []).map((p: any) => ({
|
||||||
role: p.role,
|
role: p.role,
|
||||||
participants: p.participants,
|
participants: sanitizeStoredInquiryParticipants(p.participants),
|
||||||
participantRoles: p.participantRoles,
|
participantRoles: p.participantRoles,
|
||||||
person: {
|
person: {
|
||||||
fullName: p.person?.fullName,
|
fullName: p.person?.fullName,
|
||||||
@@ -12873,6 +12834,8 @@ export class RequestManagementService {
|
|||||||
? {
|
? {
|
||||||
plateId: p.vehicle.plateId,
|
plateId: p.vehicle.plateId,
|
||||||
previousPlateId: p.vehicle.previousPlateId,
|
previousPlateId: p.vehicle.previousPlateId,
|
||||||
|
previousPolicyholderNationalCode:
|
||||||
|
p.vehicle.previousPolicyholderNationalCode,
|
||||||
registrationState: p.vehicle.registrationState,
|
registrationState: p.vehicle.registrationState,
|
||||||
vin: p.vehicle.vin,
|
vin: p.vehicle.vin,
|
||||||
name: p.vehicle.name,
|
name: p.vehicle.name,
|
||||||
@@ -13027,7 +12990,7 @@ export class RequestManagementService {
|
|||||||
: null,
|
: null,
|
||||||
parties: (plain.parties ?? []).map((p: any) => ({
|
parties: (plain.parties ?? []).map((p: any) => ({
|
||||||
role: p.role,
|
role: p.role,
|
||||||
participants: p.participants,
|
participants: sanitizeStoredInquiryParticipants(p.participants),
|
||||||
participantRoles: p.participantRoles,
|
participantRoles: p.participantRoles,
|
||||||
person: {
|
person: {
|
||||||
fullName: p.person?.fullName,
|
fullName: p.person?.fullName,
|
||||||
@@ -13056,6 +13019,8 @@ export class RequestManagementService {
|
|||||||
? {
|
? {
|
||||||
plateId: p.vehicle.plateId,
|
plateId: p.vehicle.plateId,
|
||||||
previousPlateId: p.vehicle.previousPlateId,
|
previousPlateId: p.vehicle.previousPlateId,
|
||||||
|
previousPolicyholderNationalCode:
|
||||||
|
p.vehicle.previousPolicyholderNationalCode,
|
||||||
registrationState: p.vehicle.registrationState,
|
registrationState: p.vehicle.registrationState,
|
||||||
vin: p.vehicle.vin,
|
vin: p.vehicle.vin,
|
||||||
name: p.vehicle.name,
|
name: p.vehicle.name,
|
||||||
|
|||||||
Reference in New Issue
Block a user