import { SandHubService } from "./sand-hub.service"; import { ForbiddenException, NotFoundException, ServiceUnavailableException, } from "@nestjs/common"; import { ExternalInquirySettingsService } from "src/client/external-inquiry-settings.service"; import { SandHubDetailDto } from "./dto/sand-hub.dto"; import { isMappedPolicyCurrent } from "src/request-management/inquiry-participant-resolver"; describe("SandHubService inquiry mocks", () => { const httpService = { post: jest.fn() }; const sandHubDbService = { findOneBySandHubId: jest.fn() }; const externalInquirySettings = { isInquiryLive: jest.fn(), getMockCompanyContext: jest.fn(), }; const plateNormalizer = { normalizePlateText: (text: string) => text, }; const lookupsService = { findLastProcessedCarPolicy: jest.fn(), }; const offlineInquiryService = { findPlateInquiry: 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(); process.env.CLIENT_ID = "8"; delete process.env.FANAVARAN_CLIENT; service = new SandHubService( httpService as any, sandHubDbService as any, externalInquirySettings as unknown as ExternalInquirySettingsService, plateNormalizer as any, offlineInquiryService as any, lookupsService as any, ); externalInquirySettings.isInquiryLive.mockResolvedValue(false); offlineInquiryService.findPlateInquiry.mockResolvedValue(null); externalInquirySettings.getMockCompanyContext.mockResolvedValue({ companyId: "8", companyName: "بیمه پارسیان", }); }); it("keeps disabled-live third-party mock policy usable", async () => { const result = await service.getTejaratBlockInquiry(userDetail, { enforceDeploymentClientMatch: true, }); expect(isMappedPolicyCurrent(result.mapped)).toBe(true); }); 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 the processed ESG CAR_BODY lookup and preserves it as raw data", async () => { process.env.CLIENT_ID = "8"; externalInquirySettings.isInquiryLive.mockResolvedValue(true); lookupsService.findLastProcessedCarPolicy.mockResolvedValue({ product: "car-body", insuranceLine: "CAR_BODY", insuranceLineId: 4, policyId: 15292336, policy: { CINumber: "70019846985", BeginDate: "1405/05/18" }, customer: { Name: "سهيل", LastName: "حاجي زاده" }, vehicle: { VIN: "NAAR03HFFRDE07024", plaque: { leftTwoDigits: "16", serialLetter: "ب", threeDigits: "498", rightTwoDigits: "60", }, }, }); const result = await service.getCarBodyInquiry(userDetail); expect(lookupsService.findLastProcessedCarPolicy).toHaveBeenCalledWith( "car-body", { nationalCode: "1234567890", plaqueLeft: "16", plaqueLetter: "12", plaqueRight: "498", plaqueSerial: "60", }, ); expect(result.source).toBe("ESG_CAR_BODY_INQUIRY"); expect(result.raw.policyId).toBe(15292336); expect(result.mapped.policyNumber).toBe("70019846985"); expect(httpService.post).not.toHaveBeenCalled(); }); it("returns a contextual Persian error when no car-body policy matches", async () => { externalInquirySettings.isInquiryLive.mockResolvedValue(true); lookupsService.findLastProcessedCarPolicy.mockRejectedValue( new NotFoundException("No active Fanavaran car-body policy was found"), ); await expect(service.getCarBodyInquiry(userDetail)).rejects.toThrow( "بیمه‌نامه بدنه فعالی مطابق پلاک و کد ملی واردشده یافت نشد.", ); }); it("does not let an offline third-party seed override a live ESG inquiry", async () => { process.env.CLIENT_ID = "8"; externalInquirySettings.isInquiryLive.mockResolvedValue(true); offlineInquiryService.findPlateInquiry.mockResolvedValue({ source: "OFFLINE_SEED_INQUIRY", raw: { mocked: true }, mapped: { PrntPlcyCmpDocNo: "MOCK-POLICY" }, }); const esg = jest.spyOn(service as any, "makeEsgRequest").mockResolvedValue({ success: true, data: { PrntCmpDocNo: "REAL-ESG-POLICY" }, }); const result = await service.getTejaratBlockInquiry(userDetail); expect(esg).toHaveBeenCalled(); expect(result.raw).not.toEqual({ mocked: true }); expect(result.mapped.PrntPlcyCmpDocNo).toBe("REAL-ESG-POLICY"); }); it("preserves ESG messageFa for a plate inquiry", async () => { process.env.CLIENT_ID = "8"; externalInquirySettings.isInquiryLive.mockResolvedValue(true); jest.spyOn(service as any, "makeEsgRequest").mockResolvedValue({ success: false, error: { code: "RECORD_NOT_FOUND", message: "Provider request failed", messageFa: "رکوردی یافت نشد", providerMessage: "err.record.not.found", providerCode: "RECORD_NOT_FOUND", }, }); const result = await service.getTejaratBlockInquiry(userDetail, { enforceDeploymentClientMatch: true, }); expect(result.mapped.Error.Message).toBe("رکوردی یافت نشد"); }); it("preserves ESG messageFa for a VIN inquiry", async () => { externalInquirySettings.isInquiryLive.mockResolvedValue(true); jest.spyOn(service as any, "makeEsgRequest").mockResolvedValue({ success: false, error: { code: "INQUIRY_NO_MATCH", message: "Inquiry returned no matching result", messageFa: "نتیجه‌ای مطابق با اطلاعات وارد شده یافت نشد", providerMessage: "Inquiry returned no matching result", providerCode: "INQUIRY_NO_MATCH", }, }); const result = await service.getCarByChassisInquiry({ nationalCode: "0012345678", chassis: "NAAR03HFFRDE07024", }); expect(result.mapped.Error.Message).toBe( "نتیجه‌ای مطابق با اطلاعات وارد شده یافت نشد", ); }); it("rejects a guilty third-party policy issued by another insurer", async () => { process.env.CLIENT_ID = "15"; externalInquirySettings.isInquiryLive.mockResolvedValue(true); jest.spyOn(service as any, "makeTejaratRequest").mockResolvedValue({ CompanyCode: "8", CompanyName: "بیمه پارسیان", PrntPlcyCmpDocNo: "OTHER-INSURER-POLICY", }); await expect( service.getTejaratBlockInquiry(userDetail, { enforceDeploymentClientMatch: true, } as any), ).rejects.toBeInstanceOf(ForbiddenException); }); it("allows an unchecked third-party policy from another insurer", async () => { process.env.CLIENT_ID = "15"; externalInquirySettings.isInquiryLive.mockResolvedValue(true); jest.spyOn(service as any, "makeTejaratRequest").mockResolvedValue({ CompanyCode: "8", CompanyName: "بیمه پارسیان", }); await expect(service.getTejaratBlockInquiry(userDetail)).resolves.toEqual( expect.objectContaining({ mapped: expect.objectContaining({ CompanyCode: "8" }), }), ); }); it("rejects a guilty VIN third-party policy issued by another insurer", async () => { process.env.CLIENT_ID = "15"; externalInquirySettings.isInquiryLive.mockResolvedValue(true); jest.spyOn(service as any, "makeEsgRequest").mockResolvedValue({ success: true, data: { CmpCod: "8", CmpNam: "بیمه پارسیان" }, }); await expect( service.getCarByChassisInquiry( { nationalCode: "1234567890", chassis: "NAAR03HFFRDE07024", }, { enforceDeploymentClientMatch: true }, ), ).rejects.toBeInstanceOf(ForbiddenException); }); it("sends the policyholder national code with the VIN inquiry", async () => { externalInquirySettings.isInquiryLive.mockResolvedValue(true); const esg = jest.spyOn(service as any, "makeEsgRequest").mockResolvedValue({ success: true, data: { CmpCod: "8", CmpNam: "بیمه پارسیان" }, }); await service.getCarByChassisInquiry({ nationalCode: "0012345678", chassis: "NAAR03HFFRDE07024", }); expect(esg).toHaveBeenCalledWith( expect.stringContaining("/inquiry/carByChassis"), { nationalCode: "0012345678", chassis: "NAAR03HFFRDE07024", }, "vinChassis", undefined, ); }); it("does not accept a policy when CLIENT_ID is not configured", async () => { delete process.env.CLIENT_ID; externalInquirySettings.isInquiryLive.mockResolvedValue(true); jest.spyOn(service, "getTejaratCarBodyInquiry").mockResolvedValue({ raw: { data: { companyId: "15" } }, mapped: { companyId: "15", CompanyCode: "15" }, }); await expect(service.getCarBodyInquiry(userDetail)).rejects.toBeInstanceOf( ServiceUnavailableException, ); }); it("rejects a CAR_BODY policy from another insurer on the Parsian lookup route", async () => { process.env.CLIENT_ID = "15"; process.env.FANAVARAN_CLIENT = "parsian"; externalInquirySettings.isInquiryLive.mockResolvedValue(true); lookupsService.findLastProcessedCarPolicy.mockResolvedValue({ policy: { CINumber: "70019846985" }, customer: {}, vehicle: {}, }); await expect(service.getCarBodyInquiry(userDetail)).rejects.toBeInstanceOf( ForbiddenException, ); }); it("rejects a CAR_BODY policy from another insurer on the Tejarat lookup route", async () => { process.env.CLIENT_ID = "15"; externalInquirySettings.isInquiryLive.mockResolvedValue(true); jest.spyOn(service, "getTejaratCarBodyInquiry").mockResolvedValue({ raw: { data: { companyId: "8" } }, mapped: { companyId: "8", CompanyCode: "8" }, }); await expect(service.getCarBodyInquiry(userDetail)).rejects.toBeInstanceOf( ForbiddenException, ); }); it("accepts a mocked Parsian CAR_BODY inquiry for the deployment client", async () => { process.env.CLIENT_ID = "15"; process.env.FANAVARAN_CLIENT = "parsian"; externalInquirySettings.isInquiryLive.mockResolvedValue(false); externalInquirySettings.getMockCompanyContext.mockResolvedValue({ companyId: "15", companyName: "بیمه سامان", }); await expect(service.getCarBodyInquiry(userDetail)).resolves.toEqual( expect.objectContaining({ source: "ESG_CAR_BODY_INQUIRY", mapped: expect.objectContaining({ companyId: 15 }), }), ); expect(lookupsService.findLastProcessedCarPolicy).not.toHaveBeenCalled(); }); it("uses the processed CAR_BODY lookup when the active Fanavaran client is Parsian", async () => { process.env.FANAVARAN_CLIENT = "parsian"; externalInquirySettings.isInquiryLive.mockResolvedValue(true); lookupsService.findLastProcessedCarPolicy.mockResolvedValue({ policy: { CINumber: "70019846985" }, customer: {}, vehicle: {}, }); const tejarat = jest .spyOn(service, "getTejaratCarBodyInquiry") .mockResolvedValue({ raw: { mocked: true }, mapped: {} }); const result = await service.getCarBodyInquiry(userDetail); expect(lookupsService.findLastProcessedCarPolicy).toHaveBeenCalledWith( "car-body", expect.objectContaining({ nationalCode: "1234567890" }), ); expect(tejarat).not.toHaveBeenCalled(); expect(result.raw).not.toEqual({ mocked: true }); }); it("keeps ESG car-body inquiry in mock mode when the per-client toggle is off", async () => { process.env.CLIENT_ID = "8"; const result = await service.getCarBodyInquiry(userDetail); expect(lookupsService.findLastProcessedCarPolicy).not.toHaveBeenCalled(); expect(result.source).toBe("ESG_CAR_BODY_INQUIRY"); expect(result.raw?.isSuccess).toBe(true); expect(httpService.post).not.toHaveBeenCalled(); }); it("uses the VIN lookup and VIN audit source for ESG car-body VIN inquiries", async () => { process.env.CLIENT_ID = "8"; externalInquirySettings.isInquiryLive.mockResolvedValue(true); lookupsService.findLastProcessedCarPolicy.mockResolvedValue({ policy: { CINumber: "70019846985" }, customer: {}, vehicle: {}, }); const result = await service.getCarBodyInquiry({ nationalCodeOfInsurer: "1234567890", plate: "NAAR03HFFRDE07024", }); expect(lookupsService.findLastProcessedCarPolicy).toHaveBeenCalledWith( "car-body", { nationalCode: "1234567890", vin: "NAAR03HFFRDE07024" }, ); expect(result.source).toBe("ESG_CAR_BODY_VIN_INQUIRY"); }); it("uses the tenant Fanavaran VIN lookup for non-Parsian car-body inquiries", async () => { process.env.CLIENT_ID = "15"; process.env.FANAVARAN_CLIENT = "tejaratno"; externalInquirySettings.isInquiryLive.mockResolvedValue(true); lookupsService.findLastProcessedCarPolicy.mockResolvedValue({ policy: { CINumber: "BODY-15" }, customer: {}, vehicle: { VIN: "NAAR03HFFRDE07024" }, }); const tejarat = jest.spyOn(service, "getTejaratCarBodyInquiry"); const result = await service.getCarBodyInquiry({ nationalCodeOfInsurer: "0012345678", plate: "NAAR03HFFRDE07024", }); expect(lookupsService.findLastProcessedCarPolicy).toHaveBeenCalledWith( "car-body", { nationalCode: "0012345678", vin: "NAAR03HFFRDE07024" }, ); expect(tejarat).not.toHaveBeenCalled(); expect(result.source).toBe("TEJARAT_CAR_BODY_VIN_INQUIRY"); }); it("returns a VIN-shaped car-body mock without invoking a plate adapter", async () => { process.env.CLIENT_ID = "15"; process.env.FANAVARAN_CLIENT = "tejaratno"; const tejarat = jest.spyOn(service, "getTejaratCarBodyInquiry"); const result = await service.getCarBodyInquiry({ nationalCodeOfInsurer: "0012345678", plate: "NAAR03HFFRDE07024", }); expect(tejarat).not.toHaveBeenCalled(); expect(lookupsService.findLastProcessedCarPolicy).not.toHaveBeenCalled(); expect(result.source).toBe("TEJARAT_CAR_BODY_VIN_INQUIRY"); expect(result.mapped.VinNumberField).toBe("NAAR03HFFRDE07024"); expect(result.mapped.insurerNationalCode).toBe("0012345678"); }); 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"); // PrntPlcyCmpDocNo must be populated from the mock raw field expect(result.mapped?.PrntPlcyCmpDocNo).toBe("1404/1143-70591/200/123"); }); it("maps printNumber → PrntPlcyCmpDocNo when raw response uses new field name", async () => { // Simulate a real-API response where the policy number arrives as printNumber const rawNewFormat = { printNumber: "1405/1143-NEWAPI/200/1", CompanyName: "بیمه آزمایشی", CompanyCode: "99", FinancialCvrCptl: "5000000000", IssueDate: "1405/01/01", EndDate: "1406/01/01", }; const mapped = (service as any).mapNewApiResponseToOldFormat(rawNewFormat); expect(mapped.PrntPlcyCmpDocNo).toBe("1405/1143-NEWAPI/200/1"); }); it("maps insuranceNumber → PrntPlcyCmpDocNo when raw response uses legacy field name", async () => { const rawLegacy = { insuranceNumber: "1405/1143-LEGACY/200/1", CompanyName: "بیمه آزمایشی", CompanyCode: "99", }; const mapped = (service as any).mapNewApiResponseToOldFormat(rawLegacy); expect(mapped.PrntPlcyCmpDocNo).toBe("1405/1143-LEGACY/200/1"); }); it("maps ESG PrntCmpDocNo → PrntPlcyCmpDocNo and preserves begin/end dates", () => { const mapped = (service as any).mapEsgPolicyByPlateToOldFormat({ success: true, data: { PrntCmpDocNo: "1110/111130/404/003412", LastCmpDocNo: "1110/111130/403/002650", PlcyUnqCod: "16018466143", HBgnDte: "1404/10/23", HEndDte: "1405/10/23", HIsuDte: "1404/10/21", VIN: "IRFC891V7D2301065", MtrNum: "13389030167", ShsNum: "NAAP41FD5BJ301065", PrdDte: "1389", CmpCod: "8", CmpNam: "بيمه پارسيان", }, }); expect(mapped.PrntPlcyCmpDocNo).toBe("1110/111130/404/003412"); expect(mapped.ThirdPolicyCode).toBe("16018466143"); expect(mapped.StartDate).toBe("1404/10/23"); expect(mapped.EndDate).toBe("1405/10/23"); expect(mapped.IssueDate).toBe("1404/10/21"); expect(mapped.VIN).toBe("IRFC891V7D2301065"); expect(mapped.ModelField).toBe("1389"); }); });