forked from Yara724/api
Merge pull request 'main' (#340) from s.yahyaee/yara724-api:main into main
Reviewed-on: Yara724/api#340
This commit is contained in:
@@ -483,6 +483,7 @@ describe("buildInsurerFileReport", () => {
|
|||||||
nationalCode: "0012345678",
|
nationalCode: "0012345678",
|
||||||
birthday: "1370/01/01",
|
birthday: "1370/01/01",
|
||||||
hasDrivingLicense: true,
|
hasDrivingLicense: true,
|
||||||
|
driverLicenseDate: "1400/01/01",
|
||||||
licenseNumber: "123456789",
|
licenseNumber: "123456789",
|
||||||
licenseType: "BASE_2",
|
licenseType: "BASE_2",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -732,7 +732,10 @@ function buildDriverSection(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: PR.licenseDate,
|
label: PR.licenseDate,
|
||||||
value: licenseDate ?? asString(person.driverLicense),
|
value:
|
||||||
|
asString(person.driverLicenseDate) ||
|
||||||
|
licenseDate ||
|
||||||
|
asString(person.driverLicense),
|
||||||
},
|
},
|
||||||
{ label: PR.phone, value: asString(person.phoneNumber) },
|
{ label: PR.phone, value: asString(person.phoneNumber) },
|
||||||
{ label: PR.nationalCode, value: asString(person.nationalCodeOfDriver) },
|
{ label: PR.nationalCode, value: asString(person.nationalCodeOfDriver) },
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ import { RoleEnum } from "src/Types&Enums/role.enum";
|
|||||||
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
||||||
import { InquiryParticipantRole } from "src/common/dto/inquiry-participants.dto";
|
import { InquiryParticipantRole } from "src/common/dto/inquiry-participants.dto";
|
||||||
import { participantForStoredPartyRole } from "src/request-management/inquiry-participant-resolver";
|
import { participantForStoredPartyRole } from "src/request-management/inquiry-participant-resolver";
|
||||||
|
import type { InquiryParticipantRoleAssignments } from "src/request-management/inquiry-participant-resolver";
|
||||||
import { UserRatingDto } from "./dto/user-rating.dto";
|
import { UserRatingDto } from "./dto/user-rating.dto";
|
||||||
import {
|
import {
|
||||||
canFinalizeExpertResend,
|
canFinalizeExpertResend,
|
||||||
@@ -5905,7 +5906,7 @@ export class ClaimRequestManagementService {
|
|||||||
role?: PartyRole;
|
role?: PartyRole;
|
||||||
person?: { userId?: Types.ObjectId; nationalCodeOfInsurer?: string };
|
person?: { userId?: Types.ObjectId; nationalCodeOfInsurer?: string };
|
||||||
participants?: Array<Record<string, any>>;
|
participants?: Array<Record<string, any>>;
|
||||||
participantRoles?: Record<string, string | undefined>;
|
participantRoles?: Partial<InquiryParticipantRoleAssignments>;
|
||||||
statement?: { admitsGuilt?: boolean };
|
statement?: { admitsGuilt?: boolean };
|
||||||
}>,
|
}>,
|
||||||
guiltyPartyId?: Types.ObjectId | string | null,
|
guiltyPartyId?: Types.ObjectId | string | null,
|
||||||
@@ -12560,6 +12561,7 @@ export class ClaimRequestManagementService {
|
|||||||
currentStep: c.workflow?.currentStep || "",
|
currentStep: c.workflow?.currentStep || "",
|
||||||
createdAt: c.createdAt,
|
createdAt: c.createdAt,
|
||||||
blameRequestId: c.blameRequestId?.toString(),
|
blameRequestId: c.blameRequestId?.toString(),
|
||||||
|
partyIdentities: c.parties ?? c.snapshot?.parties,
|
||||||
blameType: blameForItem?.type ?? undefined,
|
blameType: blameForItem?.type ?? undefined,
|
||||||
creationMethod: blameForItem?.creationMethod ?? undefined,
|
creationMethod: blameForItem?.creationMethod ?? undefined,
|
||||||
unifiedFileStatus: resolveUnifiedFileStatus({
|
unifiedFileStatus: resolveUnifiedFileStatus({
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
type FanavaranCarPolicyProduct,
|
type FanavaranCarPolicyProduct,
|
||||||
} from "src/lookups/fanavaran-last-car-policy";
|
} from "src/lookups/fanavaran-last-car-policy";
|
||||||
import { resolvePolicyholderFromParty } from "./fanavaran-party-roles";
|
import { resolvePolicyholderFromParty } from "./fanavaran-party-roles";
|
||||||
|
import type { InquiryParticipantRoleAssignments } from "src/request-management/inquiry-participant-resolver";
|
||||||
|
|
||||||
export type FanavaranClaimProduct = FanavaranCarPolicyProduct;
|
export type FanavaranClaimProduct = FanavaranCarPolicyProduct;
|
||||||
|
|
||||||
@@ -103,7 +104,7 @@ type BlamePartyForCarBodyPolicy = {
|
|||||||
role?: string;
|
role?: string;
|
||||||
person?: { nationalCodeOfInsurer?: unknown };
|
person?: { nationalCodeOfInsurer?: unknown };
|
||||||
participants?: Array<Record<string, any>>;
|
participants?: Array<Record<string, any>>;
|
||||||
participantRoles?: Record<string, string | undefined>;
|
participantRoles?: Partial<InquiryParticipantRoleAssignments>;
|
||||||
insurance?: {
|
insurance?: {
|
||||||
carBodyInsurance?: {
|
carBodyInsurance?: {
|
||||||
policyId?: unknown;
|
policyId?: unknown;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { InquiryParticipantRole } from "src/common/dto/inquiry-participants.dto";
|
import { InquiryParticipantRole } from "src/common/dto/inquiry-participants.dto";
|
||||||
|
import type { InquiryParticipantRoleAssignments } from "src/request-management/inquiry-participant-resolver";
|
||||||
import { participantForStoredPartyRole } from "src/request-management/inquiry-participant-resolver";
|
import { participantForStoredPartyRole } from "src/request-management/inquiry-participant-resolver";
|
||||||
import {
|
import {
|
||||||
normalizeNationalCode,
|
normalizeNationalCode,
|
||||||
@@ -24,7 +25,7 @@ export type FanavaranRoleIdentity = {
|
|||||||
|
|
||||||
type PartyLike = {
|
type PartyLike = {
|
||||||
participants?: Array<Record<string, any>>;
|
participants?: Array<Record<string, any>>;
|
||||||
participantRoles?: Record<string, string | undefined>;
|
participantRoles?: Partial<InquiryParticipantRoleAssignments>;
|
||||||
person?: Record<string, any> | null;
|
person?: Record<string, any> | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,14 @@ export class InquiryParticipantInputDto {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
licenseType?: string;
|
licenseType?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description:
|
||||||
|
"Driver licence issue date. Required only for a driver who has a licence; Jalali YYYY/MM/DD is recommended.",
|
||||||
|
example: "1400/01/15",
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
driverLicenseDate?: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InquiryVehicleInputDto {
|
export class InquiryVehicleInputDto {
|
||||||
@@ -168,6 +176,9 @@ export class InquiryParticipantFieldsDto {
|
|||||||
@ApiHideProperty()
|
@ApiHideProperty()
|
||||||
driverLicense?: string;
|
driverLicense?: string;
|
||||||
|
|
||||||
|
@ApiHideProperty()
|
||||||
|
driverLicenseDate?: string;
|
||||||
|
|
||||||
@ApiHideProperty()
|
@ApiHideProperty()
|
||||||
licenseType?: string;
|
licenseType?: string;
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,26 @@ export class ListQueryV2Dto {
|
|||||||
@MaxLength(64)
|
@MaxLength(64)
|
||||||
search?: string;
|
search?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: "Filter cases by a phone number found on any party.",
|
||||||
|
example: "09121234567",
|
||||||
|
maxLength: 32,
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@MaxLength(32)
|
||||||
|
phoneNumber?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: "Filter cases by a national code found on any party.",
|
||||||
|
example: "0012345678",
|
||||||
|
maxLength: 32,
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@MaxLength(32)
|
||||||
|
nationalCode?: string;
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
enum: UNIFIED_FILE_STATUS_KEYS,
|
enum: UNIFIED_FILE_STATUS_KEYS,
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -778,6 +778,7 @@ export class ExpertClaimService {
|
|||||||
creationMethod?: string;
|
creationMethod?: string;
|
||||||
carBodyFirstForm?: { car?: boolean; object?: boolean };
|
carBodyFirstForm?: { car?: boolean; object?: boolean };
|
||||||
blameStatus?: string;
|
blameStatus?: string;
|
||||||
|
partyIdentities?: Array<Record<string, unknown>>;
|
||||||
} {
|
} {
|
||||||
if (!blame?.type) return {};
|
if (!blame?.type) return {};
|
||||||
const blameRequestType = blame.type as BlameRequestType;
|
const blameRequestType = blame.type as BlameRequestType;
|
||||||
@@ -786,12 +787,26 @@ export class ExpertClaimService {
|
|||||||
creationMethod?: string;
|
creationMethod?: string;
|
||||||
carBodyFirstForm?: { car?: boolean; object?: boolean };
|
carBodyFirstForm?: { car?: boolean; object?: boolean };
|
||||||
blameStatus?: string;
|
blameStatus?: string;
|
||||||
|
partyIdentities?: Array<Record<string, unknown>>;
|
||||||
} = { blameRequestType };
|
} = { blameRequestType };
|
||||||
if (blame.creationMethod) out.creationMethod = blame.creationMethod;
|
if (blame.creationMethod) out.creationMethod = blame.creationMethod;
|
||||||
out.blameStatus = blame.blameStatus;
|
out.blameStatus = blame.blameStatus;
|
||||||
if (blameRequestType !== BlameRequestType.CAR_BODY) return out;
|
|
||||||
|
|
||||||
const parties = blame.parties;
|
const parties = blame.parties;
|
||||||
|
if (Array.isArray(parties) && parties.length > 0) {
|
||||||
|
out.partyIdentities = parties.map((party: any) => ({
|
||||||
|
phoneNumber: party?.person?.phoneNumber,
|
||||||
|
nationalCode: party?.person?.nationalCode,
|
||||||
|
nationalCodeOfInsurer: party?.person?.nationalCodeOfInsurer,
|
||||||
|
nationalCodeOfDriver: party?.person?.nationalCodeOfDriver,
|
||||||
|
inquiryParticipants: Array.isArray(party?.inquiryParticipants)
|
||||||
|
? party.inquiryParticipants.map((participant: any) => ({
|
||||||
|
phoneNumber: participant?.phoneNumber,
|
||||||
|
nationalCode: participant?.nationalCode,
|
||||||
|
}))
|
||||||
|
: undefined,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (blameRequestType !== BlameRequestType.CAR_BODY) return out;
|
||||||
if (!Array.isArray(parties) || parties.length === 0) return out;
|
if (!Array.isArray(parties) || parties.length === 0) return out;
|
||||||
|
|
||||||
const first =
|
const first =
|
||||||
@@ -4393,6 +4408,8 @@ export class ExpertClaimService {
|
|||||||
? { carName: v.carName, carModel: v.carModel, carType: v.carType }
|
? { carName: v.carName, carModel: v.carModel, carType: v.carType }
|
||||||
: undefined,
|
: undefined,
|
||||||
...fileCtx,
|
...fileCtx,
|
||||||
|
partyIdentities:
|
||||||
|
fileCtx.partyIdentities ?? c.parties ?? c.snapshot?.parties,
|
||||||
blameRequestId: c.blameRequestId?.toString(),
|
blameRequestId: c.blameRequestId?.toString(),
|
||||||
createdAt: c.createdAt,
|
createdAt: c.createdAt,
|
||||||
awaitingFactorValidation,
|
awaitingFactorValidation,
|
||||||
@@ -4486,6 +4503,8 @@ export class ExpertClaimService {
|
|||||||
? { carName: v.carName, carModel: v.carModel, carType: v.carType }
|
? { carName: v.carName, carModel: v.carModel, carType: v.carType }
|
||||||
: undefined,
|
: undefined,
|
||||||
...fileCtx,
|
...fileCtx,
|
||||||
|
partyIdentities:
|
||||||
|
fileCtx.partyIdentities ?? c.parties ?? c.snapshot?.parties,
|
||||||
blameRequestId: c.blameRequestId?.toString(),
|
blameRequestId: c.blameRequestId?.toString(),
|
||||||
createdAt: c.createdAt,
|
createdAt: c.createdAt,
|
||||||
awaitingFactorValidation: claimIsAwaitingExpertFactorValidationV2(c),
|
awaitingFactorValidation: claimIsAwaitingExpertFactorValidationV2(c),
|
||||||
@@ -4625,6 +4644,8 @@ export class ExpertClaimService {
|
|||||||
? { carName: v.carName, carModel: v.carModel, carType: v.carType }
|
? { carName: v.carName, carModel: v.carModel, carType: v.carType }
|
||||||
: undefined,
|
: undefined,
|
||||||
...fileCtx,
|
...fileCtx,
|
||||||
|
partyIdentities:
|
||||||
|
fileCtx.partyIdentities ?? c.parties ?? c.snapshot?.parties,
|
||||||
blameRequestId: c.blameRequestId?.toString(),
|
blameRequestId: c.blameRequestId?.toString(),
|
||||||
createdAt: c.createdAt,
|
createdAt: c.createdAt,
|
||||||
awaitingFactorValidation: claimIsAwaitingExpertFactorValidationV2(c),
|
awaitingFactorValidation: claimIsAwaitingExpertFactorValidationV2(c),
|
||||||
@@ -4720,6 +4741,8 @@ export class ExpertClaimService {
|
|||||||
? { carName: v.carName, carModel: v.carModel, carType: v.carType }
|
? { carName: v.carName, carModel: v.carModel, carType: v.carType }
|
||||||
: undefined,
|
: undefined,
|
||||||
...fileCtx,
|
...fileCtx,
|
||||||
|
partyIdentities:
|
||||||
|
fileCtx.partyIdentities ?? c.parties ?? c.snapshot?.parties,
|
||||||
blameRequestId: c.blameRequestId?.toString(),
|
blameRequestId: c.blameRequestId?.toString(),
|
||||||
createdAt: c.createdAt,
|
createdAt: c.createdAt,
|
||||||
awaitingFactorValidation: claimIsAwaitingExpertFactorValidationV2(c),
|
awaitingFactorValidation: claimIsAwaitingExpertFactorValidationV2(c),
|
||||||
|
|||||||
@@ -26,6 +26,45 @@ describe("applyListQueryV2", () => {
|
|||||||
expect(r.list[0].publicId).toBe("A200");
|
expect(r.list[0].publicId).toBe("A200");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("filters nested party identities and normalizes Persian digits", () => {
|
||||||
|
const identityRows = [
|
||||||
|
{
|
||||||
|
publicId: "PHONE",
|
||||||
|
createdAt: "2026-01-01",
|
||||||
|
status: "OPEN",
|
||||||
|
parties: [
|
||||||
|
{
|
||||||
|
person: {
|
||||||
|
phoneNumber: "0912-123-4567",
|
||||||
|
nationalCodeOfDriver: "۰۰۱۲۳۴۵۶۷۸",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
publicId: "OTHER",
|
||||||
|
createdAt: "2026-01-02",
|
||||||
|
status: "OPEN",
|
||||||
|
parties: [{ person: { phoneNumber: "09351234567", nationalCode: "1111111111" } }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const identityGetters = {
|
||||||
|
publicId: (r: (typeof identityRows)[0]) => r.publicId,
|
||||||
|
createdAt: (r: (typeof identityRows)[0]) => r.createdAt,
|
||||||
|
status: (r: (typeof identityRows)[0]) => r.status,
|
||||||
|
};
|
||||||
|
|
||||||
|
const byPhone = applyListQueryV2(identityRows, identityGetters, {
|
||||||
|
phoneNumber: "09121234567",
|
||||||
|
});
|
||||||
|
expect(byPhone.list.map((row) => row.publicId)).toEqual(["PHONE"]);
|
||||||
|
|
||||||
|
const byNationalCode = applyListQueryV2(identityRows, identityGetters, {
|
||||||
|
nationalCode: "0012345678",
|
||||||
|
});
|
||||||
|
expect(byNationalCode.list.map((row) => row.publicId)).toEqual(["PHONE"]);
|
||||||
|
});
|
||||||
|
|
||||||
it("sorts by publicId ascending", () => {
|
it("sorts by publicId ascending", () => {
|
||||||
const r = applyListQueryV2(rows, getters, {
|
const r = applyListQueryV2(rows, getters, {
|
||||||
sortBy: "publicId",
|
sortBy: "publicId",
|
||||||
|
|||||||
@@ -53,6 +53,48 @@ function normalizeSearch(raw?: string): string | undefined {
|
|||||||
return t || undefined;
|
return t || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeIdentityValue(raw?: unknown): string {
|
||||||
|
return String(raw ?? "")
|
||||||
|
.trim()
|
||||||
|
.replace(/[۰-۹]/g, (digit) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(digit)))
|
||||||
|
.replace(/[٠-٩]/g, (digit) => String("٠١٢٣٤٥٦٧٨٩".indexOf(digit)))
|
||||||
|
.replace(/\D/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPhoneKey(key: string): boolean {
|
||||||
|
return /phone|mobile|tel/i.test(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNationalCodeKey(key: string): boolean {
|
||||||
|
return /national[_-]?(code|id)|code[_-]?mell?i|mell?i[_-]?code/i.test(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectIdentityValues(
|
||||||
|
value: unknown,
|
||||||
|
matchKey: (key: string) => boolean,
|
||||||
|
): string[] {
|
||||||
|
const values: string[] = [];
|
||||||
|
const seen = new WeakSet<object>();
|
||||||
|
const visit = (current: unknown, depth: number) => {
|
||||||
|
if (current == null || depth > 8 || typeof current !== "object") return;
|
||||||
|
const object = current as Record<string, unknown>;
|
||||||
|
if (seen.has(object)) return;
|
||||||
|
seen.add(object);
|
||||||
|
for (const [key, child] of Object.entries(object)) {
|
||||||
|
if (
|
||||||
|
matchKey(key) &&
|
||||||
|
(typeof child === "string" || typeof child === "number")
|
||||||
|
) {
|
||||||
|
const normalized = normalizeIdentityValue(child);
|
||||||
|
if (normalized) values.push(normalized);
|
||||||
|
}
|
||||||
|
if (child && typeof child === "object") visit(child, depth + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
visit(value, 0);
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
function toTime(v: Date | string | number | undefined): number {
|
function toTime(v: Date | string | number | undefined): number {
|
||||||
if (v == null) return 0;
|
if (v == null) return 0;
|
||||||
const n = v instanceof Date ? v.getTime() : new Date(v as string | number).getTime();
|
const n = v instanceof Date ? v.getTime() : new Date(v as string | number).getTime();
|
||||||
@@ -75,12 +117,28 @@ export function applyListQueryV2<T>(
|
|||||||
totalPages?: number;
|
totalPages?: number;
|
||||||
} {
|
} {
|
||||||
const search = normalizeSearch(query.search);
|
const search = normalizeSearch(query.search);
|
||||||
|
const phoneNumber = normalizeIdentityValue(query.phoneNumber);
|
||||||
|
const nationalCode = normalizeIdentityValue(query.nationalCode);
|
||||||
let filtered = rows;
|
let filtered = rows;
|
||||||
if (query.fileType && getters.fileType) {
|
if (query.fileType && getters.fileType) {
|
||||||
filtered = filtered.filter(
|
filtered = filtered.filter(
|
||||||
(row) => getters.fileType!(row) === query.fileType,
|
(row) => getters.fileType!(row) === query.fileType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (phoneNumber) {
|
||||||
|
filtered = filtered.filter((row) =>
|
||||||
|
collectIdentityValues(row, isPhoneKey).some((value) =>
|
||||||
|
value.includes(phoneNumber),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (nationalCode) {
|
||||||
|
filtered = filtered.filter((row) =>
|
||||||
|
collectIdentityValues(row, isNationalCodeKey).some((value) =>
|
||||||
|
value.includes(nationalCode),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
if (search) {
|
if (search) {
|
||||||
filtered = filtered.filter((row) => {
|
filtered = filtered.filter((row) => {
|
||||||
const chunks: string[] = [];
|
const chunks: string[] = [];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||||
import { IsNotEmpty, IsOptional, IsString } from "class-validator";
|
import { IsOptional, IsString } from "class-validator";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { AddPlateDto } from "src/profile/dto/user/AddPlateDto";
|
import { AddPlateDto } from "src/profile/dto/user/AddPlateDto";
|
||||||
import { StepsEnum } from "src/Types&Enums/blame-request-management/steps.enum";
|
import { StepsEnum } from "src/Types&Enums/blame-request-management/steps.enum";
|
||||||
@@ -51,8 +51,13 @@ export class FirstPartyFileDto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class DescriptionDto {
|
export class DescriptionDto {
|
||||||
@ApiProperty({ description: "Accident description (required for all types)" })
|
@ApiPropertyOptional({
|
||||||
desc: string;
|
description:
|
||||||
|
"Accident description. Optional for THIRD_PARTY; CAR_BODY requires at least 100 non-whitespace characters.",
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
desc?: string;
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description: "CAR_BODY only. Ignored for THIRD_PARTY.",
|
description: "CAR_BODY only. Ignored for THIRD_PARTY.",
|
||||||
@@ -94,10 +99,13 @@ export class DescriptionDto {
|
|||||||
* front-end can display them consistently regardless of blame type.
|
* front-end can display them consistently regardless of blame type.
|
||||||
*/
|
*/
|
||||||
export class DescriptionV4Dto {
|
export class DescriptionV4Dto {
|
||||||
@ApiProperty({ description: "Accident description" })
|
@ApiPropertyOptional({
|
||||||
|
description:
|
||||||
|
"Accident description. Optional for THIRD_PARTY; CAR_BODY requires at least 100 non-whitespace characters.",
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
desc?: string;
|
||||||
desc: string;
|
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export class Person {
|
|||||||
@Prop() nationalCodeOfDriver?: string;
|
@Prop() nationalCodeOfDriver?: string;
|
||||||
@Prop() insurerLicense?: string;
|
@Prop() insurerLicense?: string;
|
||||||
@Prop() driverLicense?: string;
|
@Prop() driverLicense?: string;
|
||||||
|
@Prop() driverLicenseDate?: string;
|
||||||
/** Driving licence type code from the Fanavaran lookup (GET /lookups/driving-licence-types). */
|
/** Driving licence type code from the Fanavaran lookup (GET /lookups/driving-licence-types). */
|
||||||
@Prop() licenseType?: string;
|
@Prop() licenseType?: string;
|
||||||
|
|
||||||
@@ -66,6 +67,7 @@ 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() driverLicenseDate?: string;
|
||||||
}
|
}
|
||||||
export const InquiryParticipantSchema =
|
export const InquiryParticipantSchema =
|
||||||
SchemaFactory.createForClass(InquiryParticipant);
|
SchemaFactory.createForClass(InquiryParticipant);
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ export class CarDetail {
|
|||||||
insurerBirthday?: string;
|
insurerBirthday?: string;
|
||||||
|
|
||||||
driverBirthday?: string | null;
|
driverBirthday?: string | null;
|
||||||
|
driverLicenseDate?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InsuranceDetail {
|
export class InsuranceDetail {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ describe("inquiry participant persistence", () => {
|
|||||||
nationalCode: "0022324224",
|
nationalCode: "0022324224",
|
||||||
birthday: "1378/04/26",
|
birthday: "1378/04/26",
|
||||||
hasDrivingLicense: true,
|
hasDrivingLicense: true,
|
||||||
|
driverLicenseDate: "1400/01/01",
|
||||||
licenseNumber: "1001011111",
|
licenseNumber: "1001011111",
|
||||||
licenseType: "10",
|
licenseType: "10",
|
||||||
},
|
},
|
||||||
@@ -60,6 +61,9 @@ describe("inquiry participant persistence", () => {
|
|||||||
expect(request.validateSync()).toBeUndefined();
|
expect(request.validateSync()).toBeUndefined();
|
||||||
expect(request.parties[0].person.insurerBirthday).toBe("1378/06/27");
|
expect(request.parties[0].person.insurerBirthday).toBe("1378/06/27");
|
||||||
expect(request.parties[0].person.driverBirthday).toBe("1378/04/26");
|
expect(request.parties[0].person.driverBirthday).toBe("1378/04/26");
|
||||||
|
expect(request.parties[0].participants?.[0].driverLicenseDate).toBe(
|
||||||
|
"1400/01/01",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("recasts populated party subdocuments during an inquiry-audit update", () => {
|
it("recasts populated party subdocuments during an inquiry-audit update", () => {
|
||||||
@@ -89,6 +93,7 @@ describe("inquiry participant persistence", () => {
|
|||||||
nationalCode: "0022324224",
|
nationalCode: "0022324224",
|
||||||
birthday: "1378/04/26",
|
birthday: "1378/04/26",
|
||||||
hasDrivingLicense: true,
|
hasDrivingLicense: true,
|
||||||
|
driverLicenseDate: "1400/01/01",
|
||||||
licenseNumber: "1001011111",
|
licenseNumber: "1001011111",
|
||||||
licenseType: "10",
|
licenseType: "10",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,15 +14,60 @@ import {
|
|||||||
resolveInquiryVehicle,
|
resolveInquiryVehicle,
|
||||||
runCurrentPlateInquiry,
|
runCurrentPlateInquiry,
|
||||||
sanitizeStoredInquiryParticipants,
|
sanitizeStoredInquiryParticipants,
|
||||||
|
validateDriverLicenseDate,
|
||||||
} from "./inquiry-participant-resolver";
|
} from "./inquiry-participant-resolver";
|
||||||
|
|
||||||
describe("inquiry participant resolver", () => {
|
describe("inquiry participant resolver", () => {
|
||||||
|
it("accepts a driver licence date within the ten-year window", () => {
|
||||||
|
expect(validateDriverLicenseDate("2016-09-26", "2026-09-26")).toBe(
|
||||||
|
"2016-09-26",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects future and older-than-ten-year driver licence dates", () => {
|
||||||
|
expect(() =>
|
||||||
|
validateDriverLicenseDate("2026-09-27", "2026-09-26"),
|
||||||
|
).toThrow("نمیتواند در آینده");
|
||||||
|
expect(() =>
|
||||||
|
validateDriverLicenseDate("2016-09-25", "2026-09-26"),
|
||||||
|
).toThrow("بیشتر از ۱۰ سال قبل");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("requires the date only for a licensed driver", () => {
|
||||||
|
expect(() =>
|
||||||
|
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
|
||||||
|
driver: {
|
||||||
|
nationalCode: "0012345678",
|
||||||
|
birthday: "1370/01/01",
|
||||||
|
hasDrivingLicense: true,
|
||||||
|
licenseNumber: "123456789",
|
||||||
|
licenseType: "1",
|
||||||
|
},
|
||||||
|
vehicleOwner: { sameAs: InquiryParticipantRole.DRIVER },
|
||||||
|
thirdPartyPolicyholder: { sameAs: InquiryParticipantRole.DRIVER },
|
||||||
|
}),
|
||||||
|
).toThrow("تاریخ صدور گواهینامه");
|
||||||
|
|
||||||
|
expect(() =>
|
||||||
|
resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
|
||||||
|
driver: {
|
||||||
|
nationalCode: "0012345678",
|
||||||
|
birthday: "1370/01/01",
|
||||||
|
hasDrivingLicense: false,
|
||||||
|
},
|
||||||
|
vehicleOwner: { sameAs: InquiryParticipantRole.DRIVER },
|
||||||
|
thirdPartyPolicyholder: { sameAs: InquiryParticipantRole.DRIVER },
|
||||||
|
}),
|
||||||
|
).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
it("links several roles to one explicitly shared person", () => {
|
it("links several roles to one explicitly shared person", () => {
|
||||||
const resolved = resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
|
const resolved = resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, {
|
||||||
driver: {
|
driver: {
|
||||||
nationalCode: "0012345678",
|
nationalCode: "0012345678",
|
||||||
birthday: "1370/01/01",
|
birthday: "1370/01/01",
|
||||||
hasDrivingLicense: true,
|
hasDrivingLicense: true,
|
||||||
|
driverLicenseDate: "1400/01/01",
|
||||||
licenseNumber: "123456789",
|
licenseNumber: "123456789",
|
||||||
licenseType: "1",
|
licenseType: "1",
|
||||||
},
|
},
|
||||||
@@ -231,6 +276,7 @@ describe("inquiry participant resolver", () => {
|
|||||||
nationalCode: "0012345678",
|
nationalCode: "0012345678",
|
||||||
birthday: "1370/01/01",
|
birthday: "1370/01/01",
|
||||||
hasDrivingLicense: true,
|
hasDrivingLicense: true,
|
||||||
|
driverLicenseDate: "1400/01/01",
|
||||||
licenseNumber: "D-1",
|
licenseNumber: "D-1",
|
||||||
licenseType: "1",
|
licenseType: "1",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export interface ResolvedInquiryParticipant {
|
|||||||
hasDrivingLicense?: boolean;
|
hasDrivingLicense?: boolean;
|
||||||
licenseNumber?: string;
|
licenseNumber?: string;
|
||||||
licenseType?: string;
|
licenseType?: string;
|
||||||
|
driverLicenseDate?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InquiryParticipantRoleAssignments {
|
export interface InquiryParticipantRoleAssignments {
|
||||||
@@ -38,6 +39,7 @@ export interface NormalizedInquirySubmission<T extends Record<string, any>> {
|
|||||||
nationalCodeOfDriver: string;
|
nationalCodeOfDriver: string;
|
||||||
driverBirthday: string;
|
driverBirthday: string;
|
||||||
driverLicense?: string;
|
driverLicense?: string;
|
||||||
|
driverLicenseDate?: string;
|
||||||
licenseType?: string;
|
licenseType?: string;
|
||||||
userNoCertificate?: boolean;
|
userNoCertificate?: boolean;
|
||||||
nationalCodeOfInsurer: string;
|
nationalCodeOfInsurer: string;
|
||||||
@@ -215,6 +217,29 @@ function requiredIdentity(
|
|||||||
"شماره و نوع گواهینامه برای راننده دارای گواهینامه الزامی است.",
|
"شماره و نوع گواهینامه برای راننده دارای گواهینامه الزامی است.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
role !== InquiryParticipantRole.DRIVER &&
|
||||||
|
Object.prototype.hasOwnProperty.call(input, "driverLicenseDate")
|
||||||
|
) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"تاریخ صدور گواهینامه فقط برای راننده قابل ثبت است.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const driverLicenseDate =
|
||||||
|
role === InquiryParticipantRole.DRIVER && input.hasDrivingLicense === true
|
||||||
|
? validateDriverLicenseDate(input.driverLicenseDate)
|
||||||
|
: undefined;
|
||||||
|
if (
|
||||||
|
role === InquiryParticipantRole.DRIVER &&
|
||||||
|
input.hasDrivingLicense === false &&
|
||||||
|
Object.prototype.hasOwnProperty.call(input, "driverLicenseDate") &&
|
||||||
|
input.driverLicenseDate != null &&
|
||||||
|
String(input.driverLicenseDate).trim() !== ""
|
||||||
|
) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"تاریخ صدور گواهینامه برای راننده فاقد گواهینامه قابل ثبت نیست.",
|
||||||
|
);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
participantId: role,
|
participantId: role,
|
||||||
nationalCode,
|
nationalCode,
|
||||||
@@ -225,9 +250,38 @@ function requiredIdentity(
|
|||||||
: {}),
|
: {}),
|
||||||
...(input.licenseNumber ? { licenseNumber: input.licenseNumber } : {}),
|
...(input.licenseNumber ? { licenseNumber: input.licenseNumber } : {}),
|
||||||
...(input.licenseType ? { licenseType: input.licenseType } : {}),
|
...(input.licenseType ? { licenseType: input.licenseType } : {}),
|
||||||
|
...(driverLicenseDate ? { driverLicenseDate } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Validate a driver licence issue date against the current Iran date. */
|
||||||
|
export function validateDriverLicenseDate(
|
||||||
|
value: unknown,
|
||||||
|
todayGregorian: string = gregorianDateInIran(new Date()),
|
||||||
|
): string {
|
||||||
|
const raw = String(value ?? "").trim();
|
||||||
|
const parsed = jalaliToGregorianDate(raw);
|
||||||
|
if (!parsed) {
|
||||||
|
throw new BadRequestException("تاریخ صدور گواهینامه راننده نامعتبر است.");
|
||||||
|
}
|
||||||
|
const today = jalaliToGregorianDate(todayGregorian) ?? todayGregorian;
|
||||||
|
const todayDate = new Date(`${today}T00:00:00Z`);
|
||||||
|
const minimumDate = new Date(todayDate);
|
||||||
|
minimumDate.setUTCFullYear(minimumDate.getUTCFullYear() - 10);
|
||||||
|
const minimum = minimumDate.toISOString().slice(0, 10);
|
||||||
|
if (parsed > today) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"تاریخ صدور گواهینامه راننده نمیتواند در آینده باشد.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (parsed < minimum) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"تاریخ صدور گواهینامه راننده نباید بیشتر از ۱۰ سال قبل باشد.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
export function resolveInquiryParticipants(
|
export function resolveInquiryParticipants(
|
||||||
caseType: BlameRequestType,
|
caseType: BlameRequestType,
|
||||||
input: Partial<InquiryParticipantFieldsDto> & Record<string, any>,
|
input: Partial<InquiryParticipantFieldsDto> & Record<string, any>,
|
||||||
@@ -413,6 +467,7 @@ const LEGACY_INQUIRY_FIELDS = [
|
|||||||
"nationalCodeOfDriver",
|
"nationalCodeOfDriver",
|
||||||
"driverBirthday",
|
"driverBirthday",
|
||||||
"driverLicense",
|
"driverLicense",
|
||||||
|
"driverLicenseDate",
|
||||||
"licenseType",
|
"licenseType",
|
||||||
"nationalCodeOfInsurer",
|
"nationalCodeOfInsurer",
|
||||||
"insurerBirthday",
|
"insurerBirthday",
|
||||||
@@ -555,6 +610,7 @@ export function normalizeInquirySubmission<T extends Record<string, any>>(
|
|||||||
nationalCodeOfDriver: driver.nationalCode,
|
nationalCodeOfDriver: driver.nationalCode,
|
||||||
driverBirthday: driver.birthday,
|
driverBirthday: driver.birthday,
|
||||||
driverLicense: driver.licenseNumber,
|
driverLicense: driver.licenseNumber,
|
||||||
|
driverLicenseDate: driver.driverLicenseDate,
|
||||||
licenseType: driver.licenseType,
|
licenseType: driver.licenseType,
|
||||||
userNoCertificate:
|
userNoCertificate:
|
||||||
driver.hasDrivingLicense == null
|
driver.hasDrivingLicense == null
|
||||||
|
|||||||
@@ -211,6 +211,19 @@ export class RequestManagementService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Keep eligibility rejections distinct from an unavailable CAR_BODY provider. */
|
/** Keep eligibility rejections distinct from an unavailable CAR_BODY provider. */
|
||||||
|
private assertCarBodyDescriptionMinimum(
|
||||||
|
requestType: BlameRequestType | string | undefined,
|
||||||
|
description: unknown,
|
||||||
|
): void {
|
||||||
|
if (requestType !== BlameRequestType.CAR_BODY) return;
|
||||||
|
const length = String(description ?? "").trim().length;
|
||||||
|
if (length < 100) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"CAR_BODY description must contain at least 100 non-whitespace characters.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private throwCarBodyInquiryFailure(
|
private throwCarBodyInquiryFailure(
|
||||||
err: unknown,
|
err: unknown,
|
||||||
context: "carBodyPlate" | "carBodyVin" = "carBodyPlate",
|
context: "carBodyPlate" | "carBodyVin" = "carBodyPlate",
|
||||||
@@ -2021,6 +2034,7 @@ export class RequestManagementService {
|
|||||||
party.person.nationalCodeOfDriver = body.nationalCodeOfDriver;
|
party.person.nationalCodeOfDriver = body.nationalCodeOfDriver;
|
||||||
party.person.insurerLicense = body.insurerLicense;
|
party.person.insurerLicense = body.insurerLicense;
|
||||||
party.person.driverLicense = body.driverLicense;
|
party.person.driverLicense = body.driverLicense;
|
||||||
|
party.person.driverLicenseDate = body.driverLicenseDate;
|
||||||
party.person.driverIsInsurer = body.driverIsInsurer;
|
party.person.driverIsInsurer = body.driverIsInsurer;
|
||||||
party.person.isNewCar = body.isNewCar;
|
party.person.isNewCar = body.isNewCar;
|
||||||
party.person.userNoCertificate = body.userNoCertificate;
|
party.person.userNoCertificate = body.userNoCertificate;
|
||||||
@@ -2448,6 +2462,7 @@ export class RequestManagementService {
|
|||||||
party.person.nationalCodeOfDriver = body.nationalCodeOfDriver;
|
party.person.nationalCodeOfDriver = body.nationalCodeOfDriver;
|
||||||
party.person.insurerLicense = body.insurerLicense;
|
party.person.insurerLicense = body.insurerLicense;
|
||||||
party.person.driverLicense = body.driverLicense;
|
party.person.driverLicense = body.driverLicense;
|
||||||
|
party.person.driverLicenseDate = body.driverLicenseDate;
|
||||||
party.person.driverIsInsurer = body.driverIsInsurer;
|
party.person.driverIsInsurer = body.driverIsInsurer;
|
||||||
party.person.isNewCar = body.isNewCar;
|
party.person.isNewCar = body.isNewCar;
|
||||||
party.person.userNoCertificate = body.userNoCertificate;
|
party.person.userNoCertificate = body.userNoCertificate;
|
||||||
@@ -2817,6 +2832,8 @@ export class RequestManagementService {
|
|||||||
this.isBlameOnBehalfActor(req, user),
|
this.isBlameOnBehalfActor(req, user),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.assertCarBodyDescriptionMinimum(req.type, body.desc);
|
||||||
|
|
||||||
// Set userId for party if not already set (important for second party)
|
// Set userId for party if not already set (important for second party)
|
||||||
if (!party.person) party.person = {} as any;
|
if (!party.person) party.person = {} as any;
|
||||||
if (
|
if (
|
||||||
@@ -4120,6 +4137,8 @@ export class RequestManagementService {
|
|||||||
throw new NotFoundException("Request not found");
|
throw new NotFoundException("Request not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.assertCarBodyDescriptionMinimum(request.type, body.desc);
|
||||||
|
|
||||||
// --- First Party Flow ---
|
// --- First Party Flow ---
|
||||||
if (request.firstPartyDetails.firstPartyId == user.sub) {
|
if (request.firstPartyDetails.firstPartyId == user.sub) {
|
||||||
// Build base update payload with proper MongoDB operators
|
// Build base update payload with proper MongoDB operators
|
||||||
@@ -6611,11 +6630,26 @@ export class RequestManagementService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const obj = req.toObject();
|
const obj = req.toObject();
|
||||||
|
const partyIdentities = Array.isArray(req.parties)
|
||||||
|
? req.parties.map((entry: any) => ({
|
||||||
|
phoneNumber: entry?.person?.phoneNumber,
|
||||||
|
nationalCode: entry?.person?.nationalCode,
|
||||||
|
nationalCodeOfInsurer: entry?.person?.nationalCodeOfInsurer,
|
||||||
|
nationalCodeOfDriver: entry?.person?.nationalCodeOfDriver,
|
||||||
|
inquiryParticipants: Array.isArray(entry?.inquiryParticipants)
|
||||||
|
? entry.inquiryParticipants.map((participant: any) => ({
|
||||||
|
phoneNumber: participant?.phoneNumber,
|
||||||
|
nationalCode: participant?.nationalCode,
|
||||||
|
}))
|
||||||
|
: undefined,
|
||||||
|
}))
|
||||||
|
: [];
|
||||||
|
|
||||||
delete obj.parties;
|
delete obj.parties;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...obj,
|
...obj,
|
||||||
|
partyIdentities,
|
||||||
userSide: party?.role ?? null,
|
userSide: party?.role ?? null,
|
||||||
initiatedByMe: isInitiator,
|
initiatedByMe: isInitiator,
|
||||||
unifiedFileStatus: resolveUnifiedFileStatus({
|
unifiedFileStatus: resolveUnifiedFileStatus({
|
||||||
@@ -7091,9 +7125,10 @@ export class RequestManagementService {
|
|||||||
if (!formData.carBodyForm) {
|
if (!formData.carBodyForm) {
|
||||||
throw new BadRequestException("carBodyForm is required.");
|
throw new BadRequestException("carBodyForm is required.");
|
||||||
}
|
}
|
||||||
if (!formData?.expertDescription?.desc) {
|
this.assertCarBodyDescriptionMinimum(
|
||||||
throw new BadRequestException("expertDescription.desc is required.");
|
req.type,
|
||||||
}
|
formData?.expertDescription?.desc,
|
||||||
|
);
|
||||||
|
|
||||||
const firstPartyUserId = await this.getOrCreateUserByPhoneNumber(
|
const firstPartyUserId = await this.getOrCreateUserByPhoneNumber(
|
||||||
formData.firstPartyPhoneNumber,
|
formData.firstPartyPhoneNumber,
|
||||||
@@ -7272,6 +7307,7 @@ export class RequestManagementService {
|
|||||||
nationalCodeOfDriver: firstPartyPlate.nationalCodeOfDriver,
|
nationalCodeOfDriver: firstPartyPlate.nationalCodeOfDriver,
|
||||||
insurerLicense: firstPartyPlate.insurerLicense,
|
insurerLicense: firstPartyPlate.insurerLicense,
|
||||||
driverLicense: firstPartyPlate.driverLicense,
|
driverLicense: firstPartyPlate.driverLicense,
|
||||||
|
driverLicenseDate: firstPartyPlate.driverLicenseDate,
|
||||||
driverIsInsurer: firstPartyPlate.driverIsInsurer,
|
driverIsInsurer: firstPartyPlate.driverIsInsurer,
|
||||||
isNewCar: firstPartyPlate.isNewCar,
|
isNewCar: firstPartyPlate.isNewCar,
|
||||||
userNoCertificate: firstPartyPlate.userNoCertificate,
|
userNoCertificate: firstPartyPlate.userNoCertificate,
|
||||||
@@ -7560,6 +7596,7 @@ export class RequestManagementService {
|
|||||||
nationalCodeOfDriver: plateDto.nationalCodeOfDriver,
|
nationalCodeOfDriver: plateDto.nationalCodeOfDriver,
|
||||||
insurerLicense: plateDto.insurerLicense,
|
insurerLicense: plateDto.insurerLicense,
|
||||||
driverLicense: plateDto.driverLicense,
|
driverLicense: plateDto.driverLicense,
|
||||||
|
driverLicenseDate: plateDto.driverLicenseDate,
|
||||||
driverIsInsurer: plateDto.driverIsInsurer,
|
driverIsInsurer: plateDto.driverIsInsurer,
|
||||||
isNewCar: plateDto.isNewCar,
|
isNewCar: plateDto.isNewCar,
|
||||||
userNoCertificate: plateDto.userNoCertificate,
|
userNoCertificate: plateDto.userNoCertificate,
|
||||||
@@ -8286,6 +8323,7 @@ export class RequestManagementService {
|
|||||||
carName: sandHubReport?.MapTypNam || sandHubReport?.CarName,
|
carName: sandHubReport?.MapTypNam || sandHubReport?.CarName,
|
||||||
insurerBirthday: firstPartyPlate.insurerBirthday,
|
insurerBirthday: firstPartyPlate.insurerBirthday,
|
||||||
driverBirthday: firstPartyPlate.driverBirthday,
|
driverBirthday: firstPartyPlate.driverBirthday,
|
||||||
|
driverLicenseDate: firstPartyPlate.driverLicenseDate,
|
||||||
carType: `${sandHubReport?.UsageField || ""} / ${sandHubReport?.MapUsageName || "-"}`,
|
carType: `${sandHubReport?.UsageField || ""} / ${sandHubReport?.MapUsageName || "-"}`,
|
||||||
isNewCar: firstPartyPlate.isNewCar,
|
isNewCar: firstPartyPlate.isNewCar,
|
||||||
};
|
};
|
||||||
@@ -8632,6 +8670,11 @@ export class RequestManagementService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.assertCarBodyDescriptionMinimum(
|
||||||
|
request.type,
|
||||||
|
formData.firstPartyDescription?.desc,
|
||||||
|
);
|
||||||
|
|
||||||
this.assertAccidentDateTimeNotInFuture({
|
this.assertAccidentDateTimeNotInFuture({
|
||||||
accidentDate: formData.firstPartyDescription?.accidentDate,
|
accidentDate: formData.firstPartyDescription?.accidentDate,
|
||||||
accidentTime: formData.firstPartyDescription?.accidentTime,
|
accidentTime: formData.firstPartyDescription?.accidentTime,
|
||||||
@@ -8772,6 +8815,7 @@ export class RequestManagementService {
|
|||||||
carName: sandHubReport?.MapTypNam || sandHubReport?.CarName,
|
carName: sandHubReport?.MapTypNam || sandHubReport?.CarName,
|
||||||
insurerBirthday: firstPartyPlate.insurerBirthday,
|
insurerBirthday: firstPartyPlate.insurerBirthday,
|
||||||
driverBirthday: firstPartyPlate.driverBirthday,
|
driverBirthday: firstPartyPlate.driverBirthday,
|
||||||
|
driverLicenseDate: firstPartyPlate.driverLicenseDate,
|
||||||
carType: `${sandHubReport?.UsageField || ""} / ${sandHubReport?.MapUsageName || "-"}`,
|
carType: `${sandHubReport?.UsageField || ""} / ${sandHubReport?.MapUsageName || "-"}`,
|
||||||
isNewCar: firstPartyPlate.isNewCar,
|
isNewCar: firstPartyPlate.isNewCar,
|
||||||
};
|
};
|
||||||
@@ -10107,6 +10151,8 @@ export class RequestManagementService {
|
|||||||
party.person.insurerLicense = partyData.insurerLicense;
|
party.person.insurerLicense = partyData.insurerLicense;
|
||||||
if (partyData.driverLicense)
|
if (partyData.driverLicense)
|
||||||
party.person.driverLicense = partyData.driverLicense;
|
party.person.driverLicense = partyData.driverLicense;
|
||||||
|
if ((partyData as any).driverLicenseDate)
|
||||||
|
party.person.driverLicenseDate = (partyData as any).driverLicenseDate;
|
||||||
if ((partyData as any).licenseType)
|
if ((partyData as any).licenseType)
|
||||||
(party.person as any).licenseType = (partyData as any).licenseType;
|
(party.person as any).licenseType = (partyData as any).licenseType;
|
||||||
|
|
||||||
@@ -11015,6 +11061,8 @@ export class RequestManagementService {
|
|||||||
party.person.insurerLicense = partyData.insurerLicense;
|
party.person.insurerLicense = partyData.insurerLicense;
|
||||||
if (partyData.driverLicense)
|
if (partyData.driverLicense)
|
||||||
party.person.driverLicense = partyData.driverLicense;
|
party.person.driverLicense = partyData.driverLicense;
|
||||||
|
if ((partyData as any).driverLicenseDate)
|
||||||
|
party.person.driverLicenseDate = (partyData as any).driverLicenseDate;
|
||||||
if ((partyData as any).licenseType)
|
if ((partyData as any).licenseType)
|
||||||
(party.person as any).licenseType = (partyData as any).licenseType;
|
(party.person as any).licenseType = (partyData as any).licenseType;
|
||||||
|
|
||||||
@@ -11829,6 +11877,7 @@ export class RequestManagementService {
|
|||||||
await this.verifyExpertAccessForBlameV2(req, actor);
|
await this.verifyExpertAccessForBlameV2(req, actor);
|
||||||
const role = this.resolvePartyRoleV3(req, partyRole);
|
const role = this.resolvePartyRoleV3(req, partyRole);
|
||||||
this.assertBlameV3PartyDetailPhase(req, role);
|
this.assertBlameV3PartyDetailPhase(req, role);
|
||||||
|
this.assertCarBodyDescriptionMinimum(req.type, body.desc);
|
||||||
|
|
||||||
// accidentDate and accidentTime are only required for the first (guilty)
|
// accidentDate and accidentTime are only required for the first (guilty)
|
||||||
// party — the second (damaged) party can skip them.
|
// party — the second (damaged) party can skip them.
|
||||||
@@ -13198,6 +13247,7 @@ export class RequestManagementService {
|
|||||||
driverBirthday: p.person?.driverBirthday,
|
driverBirthday: p.person?.driverBirthday,
|
||||||
insurerLicense: p.person?.insurerLicense,
|
insurerLicense: p.person?.insurerLicense,
|
||||||
driverLicense: p.person?.driverLicense,
|
driverLicense: p.person?.driverLicense,
|
||||||
|
driverLicenseDate: p.person?.driverLicenseDate,
|
||||||
userId: p.person?.userId ? String(p.person.userId) : undefined,
|
userId: p.person?.userId ? String(p.person.userId) : undefined,
|
||||||
clientId: p.person?.clientId ? String(p.person.clientId) : undefined,
|
clientId: p.person?.clientId ? String(p.person.clientId) : undefined,
|
||||||
licenseType: p.person?.licenseType ?? undefined,
|
licenseType: p.person?.licenseType ?? undefined,
|
||||||
@@ -13440,6 +13490,7 @@ export class RequestManagementService {
|
|||||||
driverBirthday: p.person?.driverBirthday,
|
driverBirthday: p.person?.driverBirthday,
|
||||||
insurerLicense: p.person?.insurerLicense,
|
insurerLicense: p.person?.insurerLicense,
|
||||||
driverLicense: p.person?.driverLicense,
|
driverLicense: p.person?.driverLicense,
|
||||||
|
driverLicenseDate: p.person?.driverLicenseDate,
|
||||||
userId: p.person?.userId ? String(p.person.userId) : undefined,
|
userId: p.person?.userId ? String(p.person.userId) : undefined,
|
||||||
clientId: p.person?.clientId ? String(p.person.clientId) : undefined,
|
clientId: p.person?.clientId ? String(p.person.clientId) : undefined,
|
||||||
licenseType: p.person?.licenseType ?? undefined,
|
licenseType: p.person?.licenseType ?? undefined,
|
||||||
|
|||||||
Reference in New Issue
Block a user