forked from Yara724/api
511 lines
18 KiB
TypeScript
511 lines
18 KiB
TypeScript
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");
|
|
});
|
|
});
|