From a0247d77693ea5c6f2d038d7a943c75f1be7ea4b Mon Sep 17 00:00:00 2001 From: SepehrYahyaee <7heycallmegray@gmail.com> Date: Mon, 1 Jun 2026 16:37:23 +0330 Subject: [PATCH] Centralized car body inquiry --- .../request-management.service.ts | 35 +++++- src/sand-hub/sand-hub.service.ts | 106 ++++++++++++++++-- 2 files changed, 130 insertions(+), 11 deletions(-) diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index a598ce7..9f0a4d3 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -1118,13 +1118,44 @@ export class RequestManagementService { party.insurance.startDate = inquiryMapped?.IssueDate; party.insurance.endDate = inquiryMapped?.EndDate; - // CAR_BODY: persist mocked car-body insurance in party's insurance (same place as usual inquiry) + // CAR BODY EXTERNAL API INQUIRY if (req.type === BlameRequestType.CAR_BODY && role === PartyRole.FIRST) { const carBodyInfo = await this.sandHubService.getTejaratCarBodyInquiry({ nationalCodeOfInsurer: body.nationalCodeOfInsurer, plate: body.plate, }); - (party.insurance as any).carBodyInsurance = carBodyInfo; + + // Raw + mapped stored under vehicle (same pattern as third-party inquiry) + party.vehicle.inquiry = { + ...party.vehicle.inquiry, // preserve existing third-party inquiry if present + carBody: { + source: "TEJARAT_CAR_BODY_INQUIRY", + raw: carBodyInfo.raw, + mapped: carBodyInfo.mapped, + }, + }; + + // Flat key fields extracted alongside third-party insurance fields + const m = carBodyInfo.mapped; + (party.insurance as any).carBodyInsurance = { + policyNumber: m.policyNumber ?? null, + companyId: m.companyId ?? null, + companyName: m.CompanyName ?? null, + insurerName: m.insurerName ?? null, + insurerNationalCode: m.insurerNationalCode ?? null, + ownerNationalCode: m.ownerNationalCode ?? null, + chassisNumber: m.ChassisNumberField ?? null, + vin: m.VinNumberField ?? null, + motorNumber: m.EngineNumberField ?? null, + vehicleGroup: m.vehicleGroupTitle ?? null, + vehicleSystem: m.vehicleSystemTitle ?? null, + startDate: m.StartDate ?? null, + endDate: m.EndDate ?? null, + issueDate: m.IssueDate ?? null, + noLossYearsCount: m.noLossYearsCount ?? null, + lossDocuments: m.lossDocuments ?? [], + hasEndorsement: m.hasEndorsement ?? null, + }; } // Advance workflow diff --git a/src/sand-hub/sand-hub.service.ts b/src/sand-hub/sand-hub.service.ts index b156e41..a8122b6 100644 --- a/src/sand-hub/sand-hub.service.ts +++ b/src/sand-hub/sand-hub.service.ts @@ -355,17 +355,13 @@ export class SandHubService { return await this.sandHubDbService.findOneBySandHubId(sandHubId); } - /** - * Tejarat block inquiry for Car Body Insurance (Badane). - * Returns both raw API response and mapped old-format response structure. - */ async getTejaratCarBodyInquiry(userDetail: SandHubDetailDto): Promise<{ raw: any; + mapped: Record; }> { const baseUrl = process.env.TEJARAT_INQUIRY_BASE_URL ?? "http://82.99.202.245:3027"; - // 1. Build payload following the strict data requirements of the external API const requestPayload = { part1: Number(userDetail.plate.leftDigits), part2: String(userDetail.plate.centerAlphabet), @@ -380,11 +376,8 @@ export class SandHubService { let raw: any; if (live) { - // 2. Safely obtain a fresh or cached access token using your helper const token = await this.getTejaratAccessToken(); - try { - // 3. Make the live call using NestJS HttpService + firstValueFrom pattern const response = await firstValueFrom( this.httpService.post(requestUrl, requestPayload, { headers: { @@ -403,8 +396,103 @@ export class SandHubService { ); throw error; } + } else { + // Mock — reuse the default mock and adapt it to the car-body shape + this.logger.debug( + `[MOCK] getTejaratCarBodyInquiry plate=${JSON.stringify(requestPayload)}`, + ); + raw = { + data: { + printNumber: "MOCK-BADANE-001", + companyId: 34, + companyName: "بیمه تجارت نو", + beginDate: "1404/06/15", + endDate: "1405/06/15", + issueDate: "1404/06/13", + hasEndorsement: null, + motorNumber: "MOCK-ENGINE", + chassisNumber: "MOCK-CHASSIS", + vin: "MOCK-VIN", + vehicleSystemTitle: "سایپا", + vehicleGroupTitle: "سواری چهار سیلندر", + insurerNationalCode: userDetail.nationalCodeOfInsurer, + insurerName: "نام آزمایشی", + ownerNationalCode: userDetail.nationalCodeOfInsurer, + noLossYearsCount: 0, + lossDocuments: [], + }, + isSuccess: true, + statusCode: 200, + message: "mock-ok", + }; } - return { raw }; + + const mapped = this.mapCarBodyInquiryResponse(raw); + return { raw, mapped }; + } + + /** + * Maps the Tejarat car-body (badane) API response to a consistent + * shape that mirrors the third-party inquiry mapped format. + * Callers should always use `mapped` for display; `raw` is kept for audit. + */ + private mapCarBodyInquiryResponse(raw: any): Record { + if (!raw) return {}; + + const data = raw?.data ?? raw; // some responses nest under `data` + + return { + // Identity + policyNumber: data.printNumber ?? data.insuranceNumber ?? null, + companyId: data.companyId ?? null, + CompanyCode: data.companyId ?? null, + CompanyName: data.companyName ?? data.companyPersianName ?? null, + + // Insurer + insurerNationalCode: + data.insurerNationalCode ?? data.ownerNationalCode ?? null, + insurerName: data.insurerName ?? null, + ownerNationalCode: data.ownerNationalCode ?? null, + InsuranceFullName: data.insurerName ?? data.ownerName ?? null, + + // Vehicle + motorNumber: data.motorNumber ?? data.EngineNumberField ?? null, + EngineNumberField: data.motorNumber ?? data.EngineNumberField ?? null, + chassisNumber: data.chassisNumber ?? data.ChassisNumberField ?? null, + ChassisNumberField: data.chassisNumber ?? data.ChassisNumberField ?? null, + vin: data.vin ?? data.VinNumberField ?? null, + VinNumberField: data.vin ?? data.VinNumberField ?? null, + vehicleGroupTitle: data.vehicleGroupTitle ?? null, + vehicleSystemTitle: data.vehicleSystemTitle ?? null, + MapTypNam: data.vehicleGroupTitle ?? data.vehicleSystemTitle ?? null, + + // Policy dates (Jalali strings from the API) + IssueDate: data.issueDate ?? data.persianStartDate ?? null, + StartDate: data.beginDate ?? data.persianStartDate ?? null, + EndDate: data.endDate ?? data.persianEndDate ?? null, + + // Plate + plateTypeTitle: data.plateTypeTitle ?? null, + platePartOne: data.platePartOne ?? null, + platePartThree: data.platePartThree ?? null, + plateSerialNumber: data.plateSerialNumber ?? null, + plateLetterTitle: data.plateLetterTitle ?? null, + + // Loss / no-claim history + noLossYearsCount: data.noLossYearsCount ?? null, + lossDocuments: Array.isArray(data.lossDocuments) + ? data.lossDocuments + : [], + + // Misc + hasEndorsement: data.hasEndorsement ?? null, + previousId: data.previousId ?? null, + + // Status passthrough + isSuccess: raw?.isSuccess ?? true, + statusCode: raw?.statusCode ?? 200, + message: raw?.message ?? null, + }; } private async makeSandHubRequest(url: string, payload: any, maxRetries = 3) {