From 7998649a89cf7337910a1a5b0bac3163584dfaaf Mon Sep 17 00:00:00 2001 From: SepehrYahyaee <7heycallmegray@gmail.com> Date: Sat, 9 May 2026 13:48:19 +0330 Subject: [PATCH] Added external APIs inquiries --- .../claim-request-management.service.ts | 71 +++++++++++++++++++ .../request-management.service.ts | 63 +++++++++++++++- src/sand-hub/sand-hub.service.ts | 9 ++- 3 files changed, 137 insertions(+), 6 deletions(-) diff --git a/src/claim-request-management/claim-request-management.service.ts b/src/claim-request-management/claim-request-management.service.ts index 04bd61d..deb7579 100644 --- a/src/claim-request-management/claim-request-management.service.ts +++ b/src/claim-request-management/claim-request-management.service.ts @@ -68,6 +68,7 @@ import { PublicIdService } from "src/utils/public-id/public-id.service"; import { ImageRequiredModel } from "./entites/schema/image-required.schema"; import { DamageExpertDbService } from "src/users/entities/db-service/damage-expert.db.service"; import { ExpertFileActivityDbService } from "src/users/entities/db-service/expert-file-activity.db.service"; +import { SandHubService } from "src/sand-hub/sand-hub.service"; import { ExpertFileActivityType, ExpertFileKind, @@ -76,6 +77,7 @@ import { FactorStatus } from "src/Types&Enums/claim-request-management/factor-st import { BranchDbService } from "src/client/entities/db-service/branch.db.service"; import { CreationMethod } from "src/request-management/entities/schema/request-management.schema"; import { RoleEnum } from "src/Types&Enums/role.enum"; +import { PartyRole } from "src/request-management/entities/schema/partyRole.enum"; import { UserRatingDto } from "./dto/user-rating.dto"; import { canFinalizeExpertResend, @@ -158,8 +160,61 @@ export class ClaimRequestManagementService { private readonly branchDbService: BranchDbService, private readonly claimRequiredDocumentDbService: ClaimRequiredDocumentDbService, private readonly publicIdService: PublicIdService, + private readonly sandHubService: SandHubService, ) {} + private parsePlateFromCompactString( + plateId: string | undefined, + ): { leftDigits: number; centerAlphabet: string; centerDigits: number; ir: number } | null { + if (!plateId) return null; + const parts = String(plateId).split("-"); + if (parts.length !== 4) return null; + const [irRaw, leftRaw, alphaRaw, centerRaw] = parts; + const ir = Number(irRaw); + const leftDigits = Number(leftRaw); + const centerDigits = Number(centerRaw); + const centerAlphabet = String(alphaRaw || "").trim(); + if ( + !Number.isFinite(ir) || + !Number.isFinite(leftDigits) || + !Number.isFinite(centerDigits) || + !centerAlphabet + ) { + return null; + } + return { leftDigits, centerAlphabet, centerDigits, ir }; + } + + private resolveOwnershipPlateForClaim( + claimCase: any, + blameRequest?: any, + ): { leftDigits: number; centerAlphabet: string; centerDigits: number; ir: number } | null { + const p = claimCase?.vehicle?.plate; + if ( + p && + Number.isFinite(Number(p.leftDigits)) && + Number.isFinite(Number(p.centerDigits)) && + Number.isFinite(Number(p.ir)) && + String(p.centerAlphabet || "").trim() + ) { + return { + leftDigits: Number(p.leftDigits), + centerAlphabet: String(p.centerAlphabet).trim(), + centerDigits: Number(p.centerDigits), + ir: Number(p.ir), + }; + } + + if (!blameRequest || !Array.isArray(blameRequest.parties)) return null; + const ownerUserId = claimCase?.owner?.userId?.toString?.(); + const matchedParty = + blameRequest.parties.find( + (party: any) => String(party?.person?.userId || "") === String(ownerUserId || ""), + ) || blameRequest.parties.find((party: any) => party?.role === PartyRole.FIRST); + const compactPlateId = matchedParty?.vehicle?.plateId; + return this.parsePlateFromCompactString(compactPlateId); + } + private delay(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } @@ -4196,6 +4251,22 @@ export class ClaimRequestManagementService { ); } + const blameRequest = claimCase.blameRequestId + ? await this.blameRequestDbService.findById(claimCase.blameRequestId.toString()) + : null; + const ownershipPlate = this.resolveOwnershipPlateForClaim(claimCase, blameRequest); + if (!ownershipPlate) { + throw new BadRequestException( + "Could not resolve vehicle plate for ownership validation.", + ); + } + + // External inquiry checks before moving workflow: + // 1) ownership check for nationalCode + plate + // await this.sandHubService.getCarOwnershipInfo(ownershipPlate, nationalCode); + // 2) sheba check for nationalCode + sheba + await this.sandHubService.getShebaValidation(nationalCode, shebaNumber); + const updatePayload: any = { 'damage.otherParts': otherParts.length > 0 ? otherParts : undefined, 'money.sheba': shebaNumber, diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index 30b1046..3b3df8b 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -869,7 +869,68 @@ export class RequestManagementService { ); } - // NOTE: personal inquiry is not part of Tejarat block inquiry flow. + // ---- External inquiry 2: personal identity check (insurer/driver nationalCode + birthDate) ---- + const personalNationalCode = + body.nationalCodeOfInsurer || body.nationalCodeOfDriver; + const birthDateRaw = + body.insurerBirthday ?? body.driverBirthday ?? null; + const birthDateDigits = String(birthDateRaw ?? "") + .replace(/\D/g, "") + .trim(); + const personalBirthDate = Number(birthDateDigits); + if (!personalNationalCode || !Number.isFinite(personalBirthDate) || personalBirthDate <= 0) { + throw new BadRequestException( + "Valid nationalCode and birthDate are required for personal inquiry.", + ); + } + + try { + const personalInquiry = await this.sandHubService.getPersonalInquiry( + personalNationalCode, + personalBirthDate, + ); + this.logger.log( + `[SANDHUB] personal inquiry success request=${req._id} nationalCode=${personalNationalCode}: ${JSON.stringify( + personalInquiry, + )}`, + ); + } catch (err: any) { + this.logger.error( + `[SANDHUB] personal inquiry failed request=${req._id} nationalCode=${personalNationalCode}: ${err?.message || err}`, + ); + throw new HttpException( + "Personal identity inquiry failed", + HttpStatus.BAD_REQUEST, + ); + } + + // ---- External inquiry 3: driving license check (insurerLicense + nationalCode) ---- + // const licenseNationalCode = body.nationalCodeOfInsurer || body.nationalCodeOfDriver; + // const licenseNumber = body.insurerLicense; + // if (!licenseNationalCode || !licenseNumber) { + // throw new BadRequestException( + // "nationalCode and insurerLicense are required for driving license inquiry.", + // ); + // } + // try { + // const licenseInquiry = await this.sandHubService.getDrivingLicenseInfo( + // licenseNationalCode, + // licenseNumber, + // ); + // this.logger.log( + // `[SANDHUB] license inquiry success request=${req._id} nationalCode=${licenseNationalCode}: ${JSON.stringify( + // licenseInquiry, + // )}`, + // ); + // } catch (err: any) { + // this.logger.error( + // `[SANDHUB] license inquiry failed request=${req._id} nationalCode=${licenseNationalCode}: ${err?.message || err}`, + // ); + // throw new HttpException( + // "Driving license inquiry failed", + // HttpStatus.BAD_REQUEST, + // ); + // } // Find client by company code const clientName = inquiryMapped?.CompanyName; diff --git a/src/sand-hub/sand-hub.service.ts b/src/sand-hub/sand-hub.service.ts index 5f18a09..6505ac6 100644 --- a/src/sand-hub/sand-hub.service.ts +++ b/src/sand-hub/sand-hub.service.ts @@ -577,12 +577,11 @@ export class SandHubService { async getShebaValidation(nationalId: string, shebaId: string) { try { - const requestUrl = `${process.env.SANDHUB_BASE_URL}/sheba`; + const requestUrl = `${process.env.SANDHUB_BASE_URL}/sheba-tejaratno`; const requestPayload = { - accountOwnerType: "1", - nationalId: nationalId, - legalId: "", - shebaId: shebaId, + AccountOwnerType: "1", + NationalId: nationalId, + ShebaId: shebaId, }; this.logger.log(`Validating Sheba ID for national code: ${nationalId}`);