diff --git a/src/request-management/dto/run-inquiries-v3.dto.ts b/src/request-management/dto/run-inquiries-v3.dto.ts index 42d1a00..b165b37 100644 --- a/src/request-management/dto/run-inquiries-v3.dto.ts +++ b/src/request-management/dto/run-inquiries-v3.dto.ts @@ -4,6 +4,7 @@ import { IsNotEmpty, IsOptional, IsString, + MaxLength, ValidateNested, } from "class-validator"; import { Type } from "class-transformer"; @@ -89,3 +90,66 @@ export class RunInquiriesV3Dto { @IsString() insurerLicense?: string; } + +/** + * Body for `POST run-inquiries-vin/:requestId`. + * Identical to RunInquiriesV3Dto but uses `vin` (17-char chassis number) instead of `plate`. + * First call = guilty party (+ auto claim). Second call = damaged party (THIRD_PARTY only). + */ +export class RunInquiriesVinV3Dto { + @ApiProperty({ + example: "NAAM01E15HK123456", + description: "17-character VIN / chassis number (شماره شاسی)", + maxLength: 17, + }) + @IsString() + @IsNotEmpty() + @MaxLength(17) + vin: string; + + @ApiProperty({ example: "1234567890", description: "National code of the policyholder (insurer)" }) + @IsString() + @IsNotEmpty() + nationalCodeOfInsurer: string; + + @ApiProperty({ example: "1234567890", description: "National code of the driver" }) + @IsString() + @IsNotEmpty() + nationalCodeOfDriver: string; + + @ApiProperty({ example: true, description: "Whether the driver is the same person as the insurer" }) + @IsBoolean() + driverIsInsurer: boolean; + + @ApiProperty({ example: 13780624, description: "Insurer birth date (Jalali)" }) + insurerBirthday: number | string; + + @ApiPropertyOptional({ example: 13780624, description: "Driver birth date (Jalali). Required when driverIsInsurer is false." }) + @IsOptional() + driverBirthday?: number | string | null; + + @ApiPropertyOptional({ + example: "IR123456789012345678901234", + description: + "Sheba (IBAN). Required on the damaged party call (CAR_BODY first call; THIRD_PARTY second call).", + }) + @IsOptional() + @IsString() + sheba?: string; + + @ApiPropertyOptional({ + example: "123456789", + description: "Driver license (required when driverIsInsurer is false).", + }) + @IsOptional() + @IsString() + driverLicense?: string; + + @ApiPropertyOptional({ + example: "123456789", + description: "Insurer license (required when driverIsInsurer is true).", + }) + @IsOptional() + @IsString() + insurerLicense?: string; +} diff --git a/src/request-management/expert-initiated-blame-v3.mirror.controller.ts b/src/request-management/expert-initiated-blame-v3.mirror.controller.ts index c4d7728..59cf0c4 100644 --- a/src/request-management/expert-initiated-blame-v3.mirror.controller.ts +++ b/src/request-management/expert-initiated-blame-v3.mirror.controller.ts @@ -31,7 +31,7 @@ import { RoleEnum } from "src/Types&Enums/role.enum"; import { CreationMethod } from "./entities/schema/request-management.schema"; import { CreateExpertInitiatedFileDto } from "./dto/expert-initiated.dto"; import { SendPartyOtpDto, VerifyPartyOtpDto } from "./dto/party-otp.dto"; -import { RunInquiriesV3Dto } from "./dto/run-inquiries-v3.dto"; +import { RunInquiriesV3Dto, RunInquiriesVinV3Dto } from "./dto/run-inquiries-v3.dto"; import { CarBodyFormDto, DescriptionDto, @@ -181,6 +181,23 @@ export class ExpertInitiatedBlameV3MirrorController { return this.requestManagementService.runInquiriesV3(requestId, expert, dto); } + @Post("run-inquiries-vin/:requestId") + @ApiParam({ name: "requestId" }) + @ApiBody({ type: RunInquiriesVinV3Dto }) + @ApiOperation({ + summary: "Run VIN/chassis inquiries for the current party (V3)", + description: + "VIN alternative to run-inquiries. Uses ESG chassis lookup instead of plate-based inquiry. " + + "1st call = guilty party (+ auto claim). 2nd call = damaged party (THIRD_PARTY, after guilty sign).", + }) + async runInquiriesVin( + @CurrentUser() expert: any, + @Param("requestId") requestId: string, + @Body() dto: RunInquiriesVinV3Dto, + ) { + return this.requestManagementService.runInquiriesVinV3(requestId, expert, dto); + } + @Post("add-detail-location/:requestId") @ApiParam({ name: "requestId" }) @ApiBody({ type: LocationDto }) diff --git a/src/request-management/expert-initiated-blame.mirror.controller.ts b/src/request-management/expert-initiated-blame.mirror.controller.ts index c1e70b2..9b95886 100644 --- a/src/request-management/expert-initiated-blame.mirror.controller.ts +++ b/src/request-management/expert-initiated-blame.mirror.controller.ts @@ -27,6 +27,7 @@ import { MediaPolicyService } from "src/media-policy/media-policy.service"; import { DEFAULT_MEDIA_MAX_BYTES } from "src/client/client.service"; import { RoleEnum } from "src/Types&Enums/role.enum"; import { AddPlateDto } from "src/profile/dto/user/AddPlateDto"; +import { InitialFormVinDto } from "./dto/create-request-management.dto"; import { BlameConfessionDtoV2, CarBodyFormDto, @@ -181,6 +182,29 @@ export class ExpertInitiatedBlameMirrorController { ); } + @Post("/run-inquiries-vin/:requestId") + @ApiParam({ name: "requestId" }) + @ApiBody({ type: InitialFormVinDto }) + @ApiOperation({ + summary: "[Expert mirror] Initial form via VIN/chassis inquiry for current party", + description: + "VIN alternative to run-inquiries. Uses ESG chassis lookup instead of plate-based inquiry. " + + "Fills the FIRST or SECOND party insurance/vehicle data depending on the current workflow step.", + }) + async initialFormVin( + @Param("requestId") requestId: string, + @Body() body: InitialFormVinDto, + @CurrentUser() expert: any, + @Body("partyRole") partyRole?: string, + ) { + return this.requestManagementService.initialFormVinV2( + requestId, + body, + expert, + partyRole, + ); + } + @ApiBody({ schema: { type: "object", diff --git a/src/request-management/file-maker-blame-v4.controller.ts b/src/request-management/file-maker-blame-v4.controller.ts index 856881d..d3b7fa7 100644 --- a/src/request-management/file-maker-blame-v4.controller.ts +++ b/src/request-management/file-maker-blame-v4.controller.ts @@ -30,7 +30,7 @@ import { RoleEnum } from "src/Types&Enums/role.enum"; import { CreationMethod } from "./entities/schema/request-management.schema"; import { CreateExpertInitiatedFileDto } from "./dto/expert-initiated.dto"; import { SendPartyOtpDto, VerifyPartyOtpDto } from "./dto/party-otp.dto"; -import { RunInquiriesV3Dto } from "./dto/run-inquiries-v3.dto"; +import { RunInquiriesV3Dto, RunInquiriesVinV3Dto } from "./dto/run-inquiries-v3.dto"; import { CarBodyFormDto, DescriptionDto, @@ -193,6 +193,27 @@ export class FileMakerBlameV4Controller { ); } + @Post("run-inquiries-vin/:requestId") + @ApiParam({ name: "requestId" }) + @ApiBody({ type: RunInquiriesVinV3Dto }) + @ApiOperation({ + summary: "Run VIN/chassis inquiries for the current party (V4)", + description: + "VIN alternative to run-inquiries. Uses ESG chassis lookup instead of plate-based inquiry. " + + "1st call = guilty party (+ auto claim). 2nd call = damaged party (THIRD_PARTY, after guilty sign).", + }) + async runInquiriesVin( + @CurrentUser() fileMaker: any, + @Param("requestId") requestId: string, + @Body() dto: RunInquiriesVinV3Dto, + ) { + return this.requestManagementService.runInquiriesVinV3( + requestId, + fileMaker, + dto, + ); + } + // ─── Party details ──────────────────────────────────────────────────────────── @Post("add-detail-location/:requestId") diff --git a/src/request-management/file-maker-blame-v5.controller.ts b/src/request-management/file-maker-blame-v5.controller.ts index 3dffb2a..fcad7b4 100644 --- a/src/request-management/file-maker-blame-v5.controller.ts +++ b/src/request-management/file-maker-blame-v5.controller.ts @@ -30,7 +30,7 @@ import { RoleEnum } from "src/Types&Enums/role.enum"; import { CreationMethod } from "./entities/schema/request-management.schema"; import { CreateExpertInitiatedFileDto } from "./dto/expert-initiated.dto"; import { SendPartyOtpDto, VerifyPartyOtpDto } from "./dto/party-otp.dto"; -import { RunInquiriesV3Dto } from "./dto/run-inquiries-v3.dto"; +import { RunInquiriesV3Dto, RunInquiriesVinV3Dto } from "./dto/run-inquiries-v3.dto"; import { CarBodyFormDto, DescriptionDto, @@ -192,6 +192,27 @@ export class FileMakerBlameV5Controller { ); } + @Post("run-inquiries-vin/:requestId") + @ApiParam({ name: "requestId" }) + @ApiBody({ type: RunInquiriesVinV3Dto }) + @ApiOperation({ + summary: "Run VIN/chassis inquiries for the current party (V5)", + description: + "VIN alternative to run-inquiries. Uses ESG chassis lookup instead of plate-based inquiry. " + + "1st call = guilty party (+ auto claim). 2nd call = damaged party (THIRD_PARTY, after guilty sign).", + }) + async runInquiriesVin( + @CurrentUser() fileMaker: any, + @Param("requestId") requestId: string, + @Body() dto: RunInquiriesVinV3Dto, + ) { + return this.requestManagementService.runInquiriesVinV3( + requestId, + fileMaker, + dto, + ); + } + // ─── Party details ──────────────────────────────────────────────────────────── @Post("add-detail-location/:requestId") diff --git a/src/request-management/registrar-blame.mirror.controller.ts b/src/request-management/registrar-blame.mirror.controller.ts index f6a3150..02b7a4b 100644 --- a/src/request-management/registrar-blame.mirror.controller.ts +++ b/src/request-management/registrar-blame.mirror.controller.ts @@ -28,6 +28,7 @@ import { MediaPolicyService } from "src/media-policy/media-policy.service"; import { DEFAULT_MEDIA_MAX_BYTES } from "src/client/client.service"; import { RoleEnum } from "src/Types&Enums/role.enum"; import { AddPlateDto } from "src/profile/dto/user/AddPlateDto"; +import { InitialFormVinDto } from "./dto/create-request-management.dto"; import { CarBodyFormDto, DescriptionDto, @@ -165,6 +166,29 @@ export class RegistrarBlameMirrorController { ); } + @Post("/initial-form-vin/:requestId") + @ApiParam({ name: "requestId" }) + @ApiBody({ type: InitialFormVinDto }) + @ApiOperation({ + summary: "[Registrar mirror] Initial form via VIN/chassis inquiry for current party", + description: + "VIN alternative to initial-form. Uses ESG chassis lookup instead of plate-based inquiry. " + + "Fills the FIRST or SECOND party insurance/vehicle data depending on the current workflow step.", + }) + async initialFormVin( + @Param("requestId") requestId: string, + @Body() body: InitialFormVinDto, + @CurrentUser() registrar: any, + @Body("partyRole") partyRole?: string, + ) { + return this.requestManagementService.initialFormVinV2( + requestId, + body, + registrar, + partyRole, + ); + } + @ApiBody({ schema: { type: "object", diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index 734f8c5..1cb1637 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -42,7 +42,7 @@ import { ClaimStatus } from "src/Types&Enums/claim-request-management/claimStatu import { ClaimWorkflowStep } from "src/Types&Enums/claim-request-management/claim-workflow-steps.enum"; import { resolveClaimOwnerFieldsFromBlame } from "src/helpers/blame-damaged-party"; import { ExpertAccidentFieldsDto } from "./dto/expert-accident-fields.dto"; -import { RunInquiriesV3Dto } from "./dto/run-inquiries-v3.dto"; +import { RunInquiriesV3Dto, RunInquiriesVinV3Dto } from "./dto/run-inquiries-v3.dto"; import { SandHubService } from "src/sand-hub/sand-hub.service"; import { ReqBlameStatus } from "src/Types&Enums/blame-request-management/status.enum"; import { StepsEnum } from "src/Types&Enums/blame-request-management/steps.enum"; @@ -9153,6 +9153,399 @@ export class RequestManagementService { }; } + /** + * VIN variant of `runInquiriesV3`. + * Identical flow, but calls `getPolicyByChassisInquiry` instead of + * `getTejaratBlockInquiry` for the primary policy lookup. + */ + async runInquiriesVinV3( + requestId: string, + actor: any, + dto: RunInquiriesVinV3Dto, + ): Promise<{ + blameRequestId: string; + partyRole: PartyRole; + claimRequestId?: string; + claimPublicId?: string; + message: string; + }> { + const req = await this.blameRequestDbService.findById(requestId); + if (!req) throw new NotFoundException("Blame request not found"); + this.assertBlameV3ExpertInPerson(req); + await this.verifyExpertAccessForBlameV2(req, actor); + + const partyRole = this.resolveV3InquiryPartyRole(req); + if (!partyRole) { + throw new ConflictException("All party inquiries are already complete."); + } + + if (partyRole === PartyRole.FIRST) { + const firstIdx = this.getPartyIndex(req, PartyRole.FIRST); + if (firstIdx === -1) + throw new BadRequestException("First party not found"); + const firstParty = req.parties[firstIdx]; + if (!firstParty?.person?.userId) { + throw new BadRequestException( + "Guilty party OTP must be verified before running inquiries.", + ); + } + if (req.type === BlameRequestType.CAR_BODY) { + const form = firstParty.carBodyFirstForm as any; + if (form?.car == null && form?.object == null) { + throw new BadRequestException( + "Submit car-body-form before running inquiries (CAR_BODY).", + ); + } + } + + await this.runPartyInquiriesVinV3Internal( + req, + dto, + PartyRole.FIRST, + firstParty, + ); + if (req.type === BlameRequestType.CAR_BODY) { + await this.validateShebaV3( + dto as any, + firstParty.person?.clientId?.toString(), + ); + } + + this.markPartyInquiriesCompleteOnBlame(req, PartyRole.FIRST, actor); + await (req as any).save(); + + const nationalCode = + dto.nationalCodeOfInsurer || dto.nationalCodeOfDriver || ""; + const newClaim = await this.createV3ClaimFromBlame(req, actor, { + sheba: req.type === BlameRequestType.CAR_BODY ? dto.sheba : undefined, + nationalCode: + req.type === BlameRequestType.CAR_BODY ? nationalCode : undefined, + interimThirdParty: req.type === BlameRequestType.THIRD_PARTY, + }); + + return { + blameRequestId: requestId, + partyRole: PartyRole.FIRST, + claimRequestId: String(newClaim._id), + claimPublicId: req.publicId, + message: + "Guilty-party inquiries complete and claim created. Proceed with location, description, voice, and signature.", + }; + } + + // Damaged party (THIRD_PARTY only) + if (!this.partyHasSigned(req, PartyRole.FIRST)) { + throw new BadRequestException( + "Guilty party must sign before running damaged-party inquiries.", + ); + } + const secondIdx = this.getPartyIndex(req, PartyRole.SECOND); + if (secondIdx === -1 || !req.parties[secondIdx]?.person?.userId) { + throw new BadRequestException( + "Damaged party OTP must be verified before running inquiries.", + ); + } + + const secondParty = req.parties[secondIdx]; + const firstIdx = this.getPartyIndex(req, PartyRole.FIRST); + const firstUserId = + firstIdx !== -1 ? req.parties[firstIdx]?.person?.userId : null; + const secondUserId = secondParty.person?.userId; + if ( + firstUserId && + secondUserId && + String(firstUserId) === String(secondUserId) + ) { + throw new BadRequestException( + "Guilty and damaged parties are bound to the same user account. " + + "Re-verify the second party OTP using a different phone number.", + ); + } + + await this.runPartyInquiriesVinV3Internal( + req, + dto, + PartyRole.SECOND, + secondParty, + ); + await this.validateShebaV3( + dto as any, + secondParty.person?.clientId?.toString(), + ); + + this.ensureV3GuiltyPartyDecision(req); + if (typeof (req as any).markModified === "function") { + (req as any).markModified("parties"); + } + await (req as any).save(); + + await this.syncV3ClaimDamagedPartyFromBlame(req, dto as any); + + this.markPartyInquiriesCompleteOnBlame(req, PartyRole.SECOND, actor); + await (req as any).save(); + + return { + blameRequestId: requestId, + partyRole: PartyRole.SECOND, + message: + "Damaged-party inquiries complete. Proceed with location, description, voice, and signature.", + }; + } + + /** + * VIN variant of `runPartyInquiriesV3Internal`. + * Calls `getPolicyByChassisInquiry` (ESG chassis lookup) instead of + * `getTejaratBlockInquiry` (plate-based). All other inquiries (personal, + * driving licence, car-body for CAR_BODY) are unchanged. + */ + private async runPartyInquiriesVinV3Internal( + req: any, + partyData: RunInquiriesVinV3Dto, + partyRole: PartyRole, + party: any, + ): Promise<{ clientId?: string }> { + const roleLabel = partyRole === PartyRole.FIRST ? "FIRST" : "SECOND"; + let clientId: string | undefined; + const inquiryOptions = (cid?: string) => + cid ? { clientId: cid } : undefined; + + let inquiryRaw: any; + let inquiryMapped: any; + try { + const inquiry = await this.sandHubService.getPolicyByChassisInquiry( + partyData.vin, + inquiryOptions(party?.person?.clientId?.toString()), + ); + inquiryRaw = inquiry.raw; + inquiryMapped = inquiry.mapped; + this.recordPartyCaseInquiryStatus(req, "thirdParty", partyRole, true, { + source: "ESG_VIN_INQUIRY", + raw: inquiryRaw, + mapped: inquiryMapped, + }); + } catch (err: any) { + this.logger.error( + `[V3-VIN] vin inquiry failed for ${roleLabel} party (request=${req._id}): ${err?.message || err}`, + ); + this.recordPartyCaseInquiryStatus( + req, + "thirdParty", + partyRole, + false, + {}, + err, + ); + throw new BadRequestException( + `${roleLabel} party VIN inquiry failed: ${err?.message || "استعلام در دسترس نیست"}`, + ); + } + + if (inquiryMapped?.Error) { + throw new BadRequestException( + inquiryMapped.Error.Message || + `${roleLabel} party VIN inquiry returned an error`, + ); + } + + const clientName = inquiryMapped?.CompanyName; + const companyCode = inquiryMapped?.CompanyCode; + if (!clientName) { + throw new BadRequestException( + `CompanyName missing from ${roleLabel} party VIN inquiry response`, + ); + } + const client = await this.clientService.findOrCreateClientByCompanyCode( + companyCode, + clientName, + ); + if (!client) { + throw new BadRequestException( + `CompanyCode missing or invalid in ${roleLabel} party VIN inquiry response`, + ); + } + const resolvedClientId = (client as any)?._id ?? (client as any)?._doc?._id; + clientId = resolvedClientId ? String(resolvedClientId) : undefined; + + if (!party.person) party.person = {} as any; + party.person.clientId = resolvedClientId; + party.person.nationalCodeOfInsurer = partyData.nationalCodeOfInsurer; + party.person.nationalCodeOfDriver = partyData.nationalCodeOfDriver; + party.person.driverIsInsurer = partyData.driverIsInsurer; + party.person.insurerBirthday = partyData.insurerBirthday; + party.person.driverBirthday = + partyData.driverBirthday ?? + (partyData.driverIsInsurer ? String(partyData.insurerBirthday) : null); + if (partyData.insurerLicense) + party.person.insurerLicense = partyData.insurerLicense; + if (partyData.driverLicense) + party.person.driverLicense = partyData.driverLicense; + + if (!party.vehicle) party.vehicle = {} as any; + party.vehicle.plateId = partyData.vin; // store VIN as vehicle identifier + party.vehicle.name = inquiryMapped?.MapTypNam; + party.vehicle.type = `${inquiryMapped?.UsageField ?? ""} / ${inquiryMapped?.UsageName ?? inquiryMapped?.MapUsageName ?? "-"}`; + party.vehicle.inquiry = { + source: "ESG_VIN_INQUIRY", + raw: inquiryRaw, + mapped: inquiryMapped, + }; + + if (!party.insurance) party.insurance = {} as any; + party.insurance.policyNumber = inquiryMapped?.PrntPlcyCmpDocNo; + party.insurance.company = clientName; + party.insurance.financialCeiling = inquiryMapped?.FinancialCvrCptl; + party.insurance.startDate = inquiryMapped?.IssueDate; + party.insurance.endDate = inquiryMapped?.EndDate; + + if ( + req.type === BlameRequestType.CAR_BODY && + partyRole === PartyRole.FIRST + ) { + try { + const carBodyInfo = await this.sandHubService.getTejaratCarBodyInquiry( + { + nationalCodeOfInsurer: partyData.nationalCodeOfInsurer, + plate: partyData.vin as any, // VIN used as identifier for CAR_BODY + }, + clientId ? { clientId } : undefined, + ); + this.recordPartyCaseInquiryStatus(req, "carBody", partyRole, true, { + source: "TEJARAT_CAR_BODY_VIN_INQUIRY", + raw: carBodyInfo.raw, + mapped: carBodyInfo.mapped, + }); + party.vehicle.inquiry = { + ...party.vehicle.inquiry, + carBody: { + source: "TEJARAT_CAR_BODY_VIN_INQUIRY", + raw: carBodyInfo.raw, + mapped: carBodyInfo.mapped, + }, + }; + const m = carBodyInfo.mapped; + (party.insurance as any).carBodyInsurance = { + policyNumber: m.policyNumber ?? null, + companyId: m.companyId ?? null, + companyName: m.CompanyName ?? null, + }; + const cbCompanyCode = m.companyId ?? m.CompanyCode; + const cbCompanyName = m.CompanyName ?? m.companyPersianName; + if (cbCompanyCode && cbCompanyName) { + const cbClient = + await this.clientService.findOrCreateClientByCompanyCode( + Number(cbCompanyCode), + String(cbCompanyName), + ); + const cbClientId = + (cbClient as any)?._id ?? (cbClient as any)?._doc?._id; + if (cbClientId) { + party.person.clientId = cbClientId; + clientId = String(cbClientId); + } + } + } catch (err: any) { + this.logger.error( + `[V3-VIN] car body inquiry failed for request=${req._id}: ${err?.message || err}`, + ); + this.recordPartyCaseInquiryStatus( + req, + "carBody", + partyRole, + false, + {}, + err, + ); + throw new BadRequestException( + `CAR_BODY VIN inquiry failed: ${err?.message || "استعلام در دسترس نیست"}`, + ); + } + } + + const nationalCode = + partyData.nationalCodeOfInsurer || partyData.nationalCodeOfDriver; + const birthDate = partyData.insurerBirthday ?? partyData.driverBirthday; + if (nationalCode && birthDate != null) { + try { + const personalInquiry = await this.sandHubService.getPersonalInquiry( + nationalCode, + birthDate as string | number, + clientId ? { clientId } : undefined, + ); + this.recordPartyCaseInquiryStatus( + req, + "person", + partyRole, + true, + personalInquiry, + ); + } catch (err: any) { + this.logger.error( + `[V3-VIN] personal inquiry failed for ${roleLabel} party request=${req._id}: ${err?.message || err}`, + ); + this.recordPartyCaseInquiryStatus( + req, + "person", + partyRole, + false, + {}, + err, + ); + throw new BadRequestException( + `${roleLabel} party personal identity inquiry failed: ${err?.message || "استعلام در دسترس نیست"}`, + ); + } + } + + const licenseNationalCode = partyData.driverIsInsurer + ? partyData.nationalCodeOfInsurer + : partyData.nationalCodeOfDriver; + const licenseNumber = partyData.driverIsInsurer + ? partyData.insurerLicense + : partyData.driverLicense; + + if (!licenseNumber) { + this.recordPartyCaseInquiryStatus( + req, + "drivingLicence", + partyRole, + false, + { skipped: true, reason: "No license number provided" }, + ); + } else { + try { + const licenseInquiry = await this.sandHubService.getDrivingLicenseInfo( + licenseNationalCode, + licenseNumber, + clientId ? { clientId } : undefined, + ); + this.recordPartyCaseInquiryStatus( + req, + "drivingLicence", + partyRole, + true, + licenseInquiry, + ); + } catch (err: any) { + this.logger.error( + `[V3-VIN] driving license inquiry failed for ${roleLabel} party request=${req._id}: ${err?.message || err}`, + ); + this.recordPartyCaseInquiryStatus( + req, + "drivingLicence", + partyRole, + false, + {}, + err, + ); + throw new BadRequestException( + `${roleLabel} party driving license inquiry failed: ${err?.message || "استعلام در دسترس نیست"}`, + ); + } + } + + return { clientId }; + } + private assertBlameV3PartyDetailPhase(req: any, partyRole: PartyRole): void { this.assertBlameV3ExpertInPerson(req); if (partyRole === PartyRole.FIRST) {