diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index 6f41905..5d94ddf 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -1114,11 +1114,20 @@ export class RequestManagementService { // ---- External inquiry 1: Tejarat block inquiry ---- let inquiryRaw: any; let inquiryMapped: any; + const inquiryClientId = party.person?.clientId + ? String(party.person.clientId) + : undefined; + const inquiryOptions = inquiryClientId + ? { clientId: inquiryClientId } + : undefined; try { - const inquiry = await this.sandHubService.getTejaratBlockInquiry({ - plate: body.plate, - nationalCodeOfInsurer: body.nationalCodeOfInsurer, - }); + const inquiry = await this.sandHubService.getTejaratBlockInquiry( + { + plate: body.plate, + nationalCodeOfInsurer: body.nationalCodeOfInsurer, + }, + inquiryOptions, + ); inquiryRaw = inquiry.raw; inquiryMapped = inquiry.mapped; this.logger.log( @@ -1199,6 +1208,7 @@ export class RequestManagementService { const personalInquiry = await this.sandHubService.getPersonalInquiry( personalNationalCode, personalBirthDate, + inquiryOptions, ); this.recordPartyCaseInquiryStatus( req, @@ -1312,10 +1322,15 @@ export class RequestManagementService { if (req.type === BlameRequestType.CAR_BODY && role === PartyRole.FIRST) { let carBodyInfo: any; try { - carBodyInfo = await this.sandHubService.getTejaratCarBodyInquiry({ - nationalCodeOfInsurer: body.nationalCodeOfInsurer, - plate: body.plate, - }); + carBodyInfo = await this.sandHubService.getTejaratCarBodyInquiry( + { + nationalCodeOfInsurer: body.nationalCodeOfInsurer, + plate: body.plate, + }, + resolvedClientId + ? { clientId: String(resolvedClientId) } + : inquiryOptions, + ); this.recordPartyCaseInquiryStatus(req, "carBody", role, true, { source: "TEJARAT_CAR_BODY_INQUIRY", raw: carBodyInfo.raw, diff --git a/src/sand-hub/sand-hub.service.spec.ts b/src/sand-hub/sand-hub.service.spec.ts new file mode 100644 index 0000000..34dfda8 --- /dev/null +++ b/src/sand-hub/sand-hub.service.spec.ts @@ -0,0 +1,85 @@ +import { SandHubService } from "./sand-hub.service"; +import { ExternalInquirySettingsService } from "src/client/external-inquiry-settings.service"; +import { SandHubDetailDto } from "./dto/sand-hub.dto"; + +describe("SandHubService inquiry mocks", () => { + const httpService = { post: jest.fn() }; + const sandHubDbService = { findOneBySandHubId: jest.fn() }; + const externalInquirySettings = { + isInquiryLive: jest.fn(), + getMockCompanyContext: jest.fn(), + }; + + let service: SandHubService; + + const userDetail = { + nationalCodeOfInsurer: "1234567890", + plate: { + leftDigits: 16, + centerAlphabet: "12", + centerDigits: 498, + ir: 60, + nationalCode: "1234567890", + }, + } as SandHubDetailDto; + + beforeEach(() => { + jest.clearAllMocks(); + delete process.env.CLIENT_ID; + service = new SandHubService( + httpService as any, + sandHubDbService as any, + externalInquirySettings as unknown as ExternalInquirySettingsService, + ); + externalInquirySettings.isInquiryLive.mockResolvedValue(false); + externalInquirySettings.getMockCompanyContext.mockResolvedValue({ + companyId: "8", + companyName: "بیمه پارسیان", + }); + }); + + it("returns car-body mock without HTTP when carBodyPlate is off", async () => { + const result = await service.getTejaratCarBodyInquiry(userDetail); + + expect(httpService.post).not.toHaveBeenCalled(); + expect(externalInquirySettings.isInquiryLive).toHaveBeenCalledWith( + "carBodyPlate", + undefined, + ); + expect(result.raw?.isSuccess).toBe(true); + expect(result.raw?.data?.companyId).toBe(8); + expect(result.raw?.data?.companyName).toBe("بیمه پارسیان"); + expect(result.mapped.policyNumber).toBe("1405/1143-70591/220/1/0"); + expect(result.mapped.CompanyName).toBe("بیمه پارسیان"); + expect(result.mapped.companyId).toBe(8); + expect(result.mapped.insurerNationalCode).toBe("1234567890"); + expect(result.mapped.platePartOne).toBe(16); + expect(result.mapped.platePartThree).toBe(498); + }); + + it("uses car-body mock shape in Tejarat helper when inquiry is off", async () => { + const raw = await (service as any).makeTejaratRequest( + "http://example/block-inquiry-tejarat/badane", + { + part1: 16, + part2: 12, + part3: 498, + part4: 60, + nationalCode: "1234567890", + }, + "carBodyPlate", + ); + + expect(httpService.post).not.toHaveBeenCalled(); + expect(raw?.data?.printNumber).toBe("1405/1143-70591/220/1/0"); + expect(raw?.data?.companyName).toBe("بیمه پارسیان"); + }); + + it("returns third-party plate mock for block inquiry when inquiry is off", async () => { + const result = await service.getTejaratBlockInquiry(userDetail); + + expect(httpService.post).not.toHaveBeenCalled(); + expect(result.mapped?.CompanyName).toBe("بیمه پارسیان"); + expect(result.mapped?.CompanyCode).toBe("8"); + }); +}); diff --git a/src/sand-hub/sand-hub.service.ts b/src/sand-hub/sand-hub.service.ts index 934440f..3df17c4 100644 --- a/src/sand-hub/sand-hub.service.ts +++ b/src/sand-hub/sand-hub.service.ts @@ -142,11 +142,44 @@ export class SandHubService { }; } + /** Build {@link SandHubDetailDto} from Tejarat badane / block-inquiry request bodies. */ + private tejaratPayloadToSandHubDetail(payload: { + nationalCode?: string | number; + part1?: string | number; + part2?: string | number; + part3?: string | number; + part4?: string | number; + leftTwoDigits?: string | number; + serialLetter?: string | number; + threeDigits?: string | number; + rightTwoDigits?: string | number; + }): SandHubDetailDto { + const nationalCode = String(payload.nationalCode ?? ""); + return { + nationalCodeOfInsurer: nationalCode, + plate: { + leftDigits: Number(payload.part1 ?? payload.leftTwoDigits ?? 16), + centerAlphabet: String( + payload.part2 ?? payload.serialLetter ?? "12", + ), + centerDigits: Number(payload.part3 ?? payload.threeDigits ?? 498), + ir: Number(payload.part4 ?? payload.rightTwoDigits ?? 60), + nationalCode, + }, + }; + } + private buildMockCarBodyInquiryRaw( userDetail: SandHubDetailDto, ctx: MockInquiryCompanyContext, ): Record { const companyId = Number(ctx.companyId); + const plate = userDetail?.plate; + const platePartOne = Number(plate?.leftDigits ?? 16); + const platePartThree = Number(plate?.centerDigits ?? 498); + const plateSerialNumber = Number(plate?.ir ?? 60); + const plateLetterid = Number(plate?.centerAlphabet ?? 12); + const nationalCode = String(userDetail?.nationalCodeOfInsurer ?? ""); return { data: { @@ -163,19 +196,19 @@ export class SandHubService { vin: "LFP8C7PC3R1K12157", plateTypeId: 9, plateTypeTitle: "پلاک قدیمی", - platePartOne: 16, - plateSerialNumber: 60, - plateLetterid: 12, + platePartOne, + plateSerialNumber, + plateLetterid, plateLetterTitle: "م ", vehicleSystemTitle: "فائو ( FAW )", vehicleGroupId: 2, vehicleGroupTitle: "سواری چهار سیلندر", - insurerNationalCode: userDetail.nationalCodeOfInsurer, + insurerNationalCode: nationalCode, insurerName: "هانيه کارخانهء", - ownerNationalCode: userDetail.nationalCodeOfInsurer, + ownerNationalCode: nationalCode, previousId: 70006331822, noLossYearsCount: 4, - platePartThree: 498, + platePartThree, lossDocuments: [], }, isSuccess: true, @@ -184,6 +217,23 @@ export class SandHubService { }; } + private buildMockInquiryRaw( + inquiryType: ExternalInquiryType, + ctx: MockInquiryCompanyContext, + payload?: unknown, + userDetail?: SandHubDetailDto, + ): Record { + if (inquiryType === "carBodyPlate") { + const detail = + userDetail ?? + this.tejaratPayloadToSandHubDetail( + (payload ?? {}) as Record, + ); + return this.buildMockCarBodyInquiryRaw(detail, ctx); + } + return this.buildMockPlateInquiryRaw(ctx); + } + /** * Bodies returned from `makeSandHubRequest` in mock mode (same shape callers expect from real API). */ @@ -229,12 +279,27 @@ export class SandHubService { Message: "mock-sheba-ok", }; } + if (u.includes("badane")) { + return ( + plateMock ?? + this.buildMockCarBodyInquiryRaw( + this.tejaratPayloadToSandHubDetail( + (payload ?? {}) as Record, + ), + { + companyId: process.env.CLIENT_ID ?? "15", + companyName: process.env.CLIENT_NAME ?? "بیمه سامان", + }, + ) + ); + } if (u.includes("block-inquiry") || u.includes("tejarat")) { return this.mapNewApiResponseToOldFormat( - plateMock ?? this.buildMockPlateInquiryRaw({ - companyId: process.env.CLIENT_ID ?? "15", - companyName: process.env.CLIENT_NAME ?? "بیمه سامان", - }), + plateMock ?? + this.buildMockPlateInquiryRaw({ + companyId: process.env.CLIENT_ID ?? "15", + companyName: process.env.CLIENT_NAME ?? "بیمه سامان", + }), ); } this.logger.warn( @@ -402,9 +467,6 @@ export class SandHubService { if (!(await this.isInquiryLive(inquiryType, options))) { this.logger.log(`[MOCK] ESG POST skipped (${inquiryType}): ${url}`); const ctx = await this.mockCompanyContext(options); - if (inquiryType === "thirdPartyPlate") { - return this.buildMockPlateInquiryRaw(ctx); - } if (inquiryType === "personalIdentity") { const nin = typeof payload?.nationalCode === "string" @@ -419,7 +481,7 @@ export class SandHubService { Message: "mock-sheba-ok", }; } - return this.buildMockPlateInquiryRaw(ctx); + return this.buildMockInquiryRaw(inquiryType, ctx, payload); } const INITIAL_DELAY = 500; @@ -613,7 +675,7 @@ export class SandHubService { if (!(await this.isInquiryLive(inquiryType, options))) { this.logger.log(`[MOCK] Tejarat POST skipped (${inquiryType}): ${url}`); const ctx = await this.mockCompanyContext(options); - return this.buildMockPlateInquiryRaw(ctx); + return this.buildMockInquiryRaw(inquiryType, ctx, payload); } const INITIAL_DELAY = 500; const BACKOFF_FACTOR = 2; @@ -753,38 +815,19 @@ export class SandHubService { const requestUrl = `${baseUrl}/block-inquiry-tejarat/badane`; const live = await this.isInquiryLive("carBodyPlate", options); - const ctx = await this.mockCompanyContext(options); - - let raw: any; - - if (live) { - const token = await this.getTejaratAccessToken(); - try { - const response = await firstValueFrom( - this.httpService.post(requestUrl, requestPayload, { - headers: { - Accept: "application/json", - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - timeout: 30000, - }), - ); - raw = response.data; - } catch (error) { - this.logger.error( - `[TEJARAT BADANE ERROR] Request failed for ${requestUrl}: ${error?.message || error}`, - error?.stack, - ); - throw error; - } - } else { + if (!live) { this.logger.debug( `[MOCK] getTejaratCarBodyInquiry plate=${JSON.stringify(requestPayload)}`, ); - raw = this.buildMockCarBodyInquiryRaw(userDetail, ctx); } + const raw = await this.makeTejaratRequest( + requestUrl, + requestPayload, + "carBodyPlate", + options, + ); + const mapped = this.mapCarBodyInquiryResponse(raw); return { raw, mapped }; } @@ -863,8 +906,11 @@ export class SandHubService { if (!(await this.isInquiryLive(inquiryType, options))) { this.logger.log(`[MOCK] SandHub POST skipped (${inquiryType}): ${url}`); const ctx = await this.mockCompanyContext(options); + if (inquiryType === "carBodyPlate") { + return this.buildMockInquiryRaw(inquiryType, ctx, payload); + } const plateMock = - inquiryType === "thirdPartyPlate" || inquiryType === "carBodyPlate" + inquiryType === "thirdPartyPlate" ? this.buildMockPlateInquiryRaw(ctx) : undefined; return this.buildMockSandHubResponseForUrl(url, payload, plateMock);