forked from Yara724/api
Implemented CAR_BODY fanavaran inquiry
This commit is contained in:
65
src/sand-hub/esg-car-body-inquiry.mapper.spec.ts
Normal file
65
src/sand-hub/esg-car-body-inquiry.mapper.spec.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { mapEsgCarBodyPolicyToInquiry } from "./esg-car-body-inquiry.mapper";
|
||||
|
||||
describe("mapEsgCarBodyPolicyToInquiry", () => {
|
||||
it("maps the processed CAR_BODY lookup while retaining useful policy, customer, and vehicle fields", () => {
|
||||
const mapped = mapEsgCarBodyPolicyToInquiry({
|
||||
product: "car-body",
|
||||
insuranceLine: "CAR_BODY",
|
||||
insuranceLineId: 4,
|
||||
policyId: 15292336,
|
||||
policy: {
|
||||
CINumber: "70019846985",
|
||||
ContractId: 12525,
|
||||
BeginDate: "1405/05/18",
|
||||
EndDate: "1406/05/18",
|
||||
PolicyIssuDate: "1405/05/18",
|
||||
VehicleValue: 18510000000,
|
||||
TotalPremium: 73299600,
|
||||
EndoNo: 0,
|
||||
},
|
||||
customer: {
|
||||
Name: "سهيل",
|
||||
LastName: "حاجي زاده",
|
||||
NationalCode: "4311402422",
|
||||
Mobile: "09226187419",
|
||||
},
|
||||
vehicle: {
|
||||
BuiltYear: 1403,
|
||||
ChassisNo: "NAAR03HFFRDE07024",
|
||||
MotorNo: "172B0222818",
|
||||
VIN: "NAAR03HFFRDE07024",
|
||||
vehicleKind: {
|
||||
Caption: "پژو 207I",
|
||||
VehicleSystemCaption: "پژو",
|
||||
CylinderCount: 4,
|
||||
PassengerCount: 5,
|
||||
},
|
||||
used: { Caption: "شخصي" },
|
||||
plaque: {
|
||||
leftTwoDigits: "29",
|
||||
serialLetter: "د",
|
||||
threeDigits: "782",
|
||||
rightTwoDigits: "60",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(mapped).toMatchObject({
|
||||
policyNumber: "70019846985",
|
||||
policyId: 15292336,
|
||||
contractId: 12525,
|
||||
insurerName: null,
|
||||
insurerNationalCode: null,
|
||||
ownerName: "سهيل حاجي زاده",
|
||||
ownerNationalCode: "4311402422",
|
||||
VinNumberField: "NAAR03HFFRDE07024",
|
||||
MapTypNam: "پژو 207I",
|
||||
vehicleValue: 18510000000,
|
||||
totalPremium: 73299600,
|
||||
platePartOne: "29",
|
||||
plateLetterTitle: "د",
|
||||
platePartThree: "782",
|
||||
plateSerialNumber: "60",
|
||||
});
|
||||
});
|
||||
});
|
||||
79
src/sand-hub/esg-car-body-inquiry.mapper.ts
Normal file
79
src/sand-hub/esg-car-body-inquiry.mapper.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Converts the processed CAR_BODY policy returned by the ESG/Fanavaran lookup
|
||||
* into the same mapped contract used by the existing car-body inquiry flow.
|
||||
* The original response is deliberately kept separately as `raw` by the
|
||||
* caller, so newly exposed provider fields are never discarded.
|
||||
*/
|
||||
export function mapEsgCarBodyPolicyToInquiry(
|
||||
response: Record<string, any>,
|
||||
): Record<string, unknown> {
|
||||
const policy = response.policy ?? {};
|
||||
const customer = response.customer ?? {};
|
||||
const vehicle = response.vehicle ?? {};
|
||||
const vehicleKind = vehicle.vehicleKind ?? {};
|
||||
const usage = vehicle.used ?? {};
|
||||
const plaque = vehicle.plaque ?? {};
|
||||
|
||||
const ownerName =
|
||||
[customer.Name, customer.LastName]
|
||||
.filter((value) => typeof value === "string" && value.trim())
|
||||
.join(" ") || null;
|
||||
|
||||
return {
|
||||
policyNumber: policy.CINumber ?? policy.PolicyNo ?? null,
|
||||
policyId: response.policyId ?? policy.PolicyId ?? null,
|
||||
contractId: policy.ContractId ?? null,
|
||||
insuranceLine: response.insuranceLine ?? "CAR_BODY",
|
||||
insuranceLineId: response.insuranceLineId ?? 4,
|
||||
|
||||
// Provider responses do not currently include an insurer company identity.
|
||||
companyId: policy.CompanyId ?? null,
|
||||
CompanyCode: policy.CompanyId ?? null,
|
||||
CompanyName: policy.CompanyName ?? null,
|
||||
|
||||
// The lookup's customer is the policyholder/owner, not the insurer.
|
||||
insurerName: null,
|
||||
InsuranceFullName: null,
|
||||
insurerNationalCode: null,
|
||||
ownerNationalCode: customer.NationalCode ?? null,
|
||||
ownerName,
|
||||
customerName: customer.Name ?? null,
|
||||
customerLastName: customer.LastName ?? null,
|
||||
customerFatherName: customer.FatherName ?? null,
|
||||
customerMobile: customer.Mobile ?? null,
|
||||
customerAddress: customer.Address ?? null,
|
||||
customerPostalCode: customer.PostalCode ?? null,
|
||||
|
||||
motorNumber: vehicle.MotorNo ?? null,
|
||||
EngineNumberField: vehicle.MotorNo ?? null,
|
||||
chassisNumber: vehicle.ChassisNo ?? null,
|
||||
ChassisNumberField: vehicle.ChassisNo ?? null,
|
||||
vin: vehicle.VIN ?? vehicle.ChassisNo ?? null,
|
||||
VinNumberField: vehicle.VIN ?? vehicle.ChassisNo ?? null,
|
||||
vehicleGroupTitle: vehicleKind.VehicleCategoryCaption ?? null,
|
||||
vehicleSystemTitle: vehicleKind.VehicleSystemCaption ?? null,
|
||||
vehicleKind: vehicleKind.Caption ?? null,
|
||||
MapTypNam: vehicleKind.Caption ?? vehicleKind.VehicleSystemCaption ?? null,
|
||||
builtYear: vehicle.BuiltYear ?? null,
|
||||
cylinderCount: vehicleKind.CylinderCount ?? null,
|
||||
passengerCount: vehicleKind.PassengerCount ?? null,
|
||||
usage: usage.Caption ?? null,
|
||||
|
||||
IssueDate: policy.PolicyIssuDate ?? policy.IssuDate ?? null,
|
||||
StartDate: policy.BeginDate ?? null,
|
||||
EndDate: policy.EndDate ?? null,
|
||||
vehicleValue: policy.VehicleValue ?? null,
|
||||
totalPremium: policy.TotalPremium ?? null,
|
||||
noLossYearsCount:
|
||||
policy.YearsCountWithoutLoss ??
|
||||
policy.AdditionalCovYearsCountWithoutLoss ??
|
||||
null,
|
||||
lossDocuments: [],
|
||||
hasEndorsement: Number(policy.EndoNo ?? 0) > 0,
|
||||
|
||||
platePartOne: plaque.leftTwoDigits ?? vehicle.PlaqueLeftNo ?? null,
|
||||
plateLetterTitle: plaque.serialLetter ?? null,
|
||||
platePartThree: plaque.threeDigits ?? vehicle.PlaqueRightNo ?? null,
|
||||
plateSerialNumber: plaque.rightTwoDigits ?? vehicle.PlaqueSerial ?? null,
|
||||
};
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { ClientModule } from "src/client/client.module";
|
||||
import { SystemSettingsModule } from "src/system-settings/system-settings.module";
|
||||
import { PlateNormalizerModule } from "src/utils/plate-normalizer/plate-normalizer.module";
|
||||
import { OfflineInquiryModule } from "src/offline-inquiry/offline-inquiry.module";
|
||||
import { LookupsModule } from "src/lookups/lookups.module";
|
||||
import { SandHubDbService } from "src/sand-hub/entity/db-service/sand-hub.db.service";
|
||||
import { SandHubModel, SandHubSchema } from "./entity/schema/sand-hub.schema";
|
||||
import { SandHubService } from "./sand-hub.service";
|
||||
@@ -22,6 +23,7 @@ import { SandHubService } from "./sand-hub.service";
|
||||
PlateNormalizerModule,
|
||||
ClientModule,
|
||||
OfflineInquiryModule,
|
||||
LookupsModule,
|
||||
MongooseModule.forFeature([
|
||||
{ name: SandHubModel.name, schema: SandHubSchema },
|
||||
]),
|
||||
|
||||
@@ -12,6 +12,9 @@ describe("SandHubService inquiry mocks", () => {
|
||||
const plateNormalizer = {
|
||||
normalizePlateText: (text: string) => text,
|
||||
};
|
||||
const lookupsService = {
|
||||
findLastProcessedCarPolicy: jest.fn(),
|
||||
};
|
||||
|
||||
let service: SandHubService;
|
||||
|
||||
@@ -37,6 +40,7 @@ describe("SandHubService inquiry mocks", () => {
|
||||
{
|
||||
findPlateInquiry: jest.fn().mockResolvedValue(null),
|
||||
} as any,
|
||||
lookupsService as any,
|
||||
);
|
||||
externalInquirySettings.isInquiryLive.mockResolvedValue(false);
|
||||
externalInquirySettings.getMockCompanyContext.mockResolvedValue({
|
||||
@@ -64,6 +68,77 @@ describe("SandHubService inquiry mocks", () => {
|
||||
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("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 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",
|
||||
|
||||
@@ -16,10 +16,17 @@ import { PlateNormalizerService } from "src/utils/plate-normalizer/plate-normali
|
||||
import type { ExternalInquiryType } from "src/common/types/external-inquiry.types";
|
||||
import type { MockInquiryCompanyContext } from "src/common/types/external-inquiry.types";
|
||||
import { OfflineInquiryService } from "src/offline-inquiry/offline-inquiry.service";
|
||||
import { LookupsService } from "src/lookups/lookups.service";
|
||||
import { resolveFanavaranClientKey } from "src/core/config/fanavaran-client.config";
|
||||
import { SandHubDetailDto, SandHubInquiryOptions } from "./dto/sand-hub.dto";
|
||||
import { jalaliToGregorianDate } from "src/helpers/date-jalali";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { mapEsgCarBodyPolicyToInquiry } from "./esg-car-body-inquiry.mapper";
|
||||
import type { Plates } from "src/Types&Enums/plate.interface";
|
||||
|
||||
type CarBodyInquiryDetail = Omit<SandHubDetailDto, "plate"> & {
|
||||
plate: Plates | string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class SandHubService {
|
||||
@@ -44,6 +51,7 @@ export class SandHubService {
|
||||
private readonly externalInquirySettings: ExternalInquirySettingsService,
|
||||
private readonly plateNormalizer: PlateNormalizerService,
|
||||
private readonly offlineInquiryService: OfflineInquiryService,
|
||||
private readonly lookupsService: LookupsService,
|
||||
) {}
|
||||
|
||||
private clientRefFrom(options?: SandHubInquiryOptions): string | undefined {
|
||||
@@ -833,6 +841,81 @@ export class SandHubService {
|
||||
return await this.sandHubDbService.findOneBySandHubId(sandHubId);
|
||||
}
|
||||
|
||||
/**
|
||||
* CAR_BODY is the only ESG product that uses the processed Fanavaran lookup.
|
||||
* THIRD_PARTY remains on its established provider-specific inquiry path.
|
||||
*/
|
||||
async getCarBodyInquiry(
|
||||
userDetail: CarBodyInquiryDetail,
|
||||
options?: SandHubInquiryOptions,
|
||||
): Promise<{
|
||||
source:
|
||||
| "ESG_CAR_BODY_INQUIRY"
|
||||
| "ESG_CAR_BODY_VIN_INQUIRY"
|
||||
| "TEJARAT_CAR_BODY_INQUIRY"
|
||||
| "TEJARAT_CAR_BODY_VIN_INQUIRY";
|
||||
raw: any;
|
||||
mapped: Record<string, unknown>;
|
||||
}> {
|
||||
if (!this.shouldUseEsgInquiryProvider()) {
|
||||
const result = await this.getTejaratCarBodyInquiry(
|
||||
userDetail as SandHubDetailDto,
|
||||
options,
|
||||
);
|
||||
return {
|
||||
source:
|
||||
typeof userDetail.plate === "string"
|
||||
? "TEJARAT_CAR_BODY_VIN_INQUIRY"
|
||||
: "TEJARAT_CAR_BODY_INQUIRY",
|
||||
...result,
|
||||
};
|
||||
}
|
||||
|
||||
const live = await this.isInquiryLive("carBodyPlate", options);
|
||||
if (!live) {
|
||||
// Reuse the established local mock contract without sending an HTTP request.
|
||||
const result = await this.getTejaratCarBodyInquiry(
|
||||
userDetail as SandHubDetailDto,
|
||||
options,
|
||||
);
|
||||
return {
|
||||
source:
|
||||
typeof userDetail.plate === "string"
|
||||
? "ESG_CAR_BODY_VIN_INQUIRY"
|
||||
: "ESG_CAR_BODY_INQUIRY",
|
||||
...result,
|
||||
};
|
||||
}
|
||||
|
||||
const plateOrVin = userDetail.plate;
|
||||
const query =
|
||||
typeof plateOrVin === "string"
|
||||
? {
|
||||
nationalCode: String(userDetail.nationalCodeOfInsurer),
|
||||
vin: plateOrVin,
|
||||
}
|
||||
: {
|
||||
nationalCode: String(userDetail.nationalCodeOfInsurer),
|
||||
plaqueLeft: String(plateOrVin.leftDigits),
|
||||
plaqueLetter: String(plateOrVin.centerAlphabet),
|
||||
plaqueRight: String(plateOrVin.centerDigits),
|
||||
plaqueSerial: String(plateOrVin.ir),
|
||||
};
|
||||
const raw = await this.lookupsService.findLastProcessedCarPolicy(
|
||||
"car-body",
|
||||
query,
|
||||
);
|
||||
|
||||
return {
|
||||
source:
|
||||
typeof plateOrVin === "string"
|
||||
? "ESG_CAR_BODY_VIN_INQUIRY"
|
||||
: "ESG_CAR_BODY_INQUIRY",
|
||||
raw,
|
||||
mapped: mapEsgCarBodyPolicyToInquiry(raw),
|
||||
};
|
||||
}
|
||||
|
||||
async getTejaratCarBodyInquiry(
|
||||
userDetail: SandHubDetailDto,
|
||||
options?: SandHubInquiryOptions,
|
||||
|
||||
Reference in New Issue
Block a user