forked from Yara724/api
Compare commits
12 Commits
b7857a40f5
...
395e3dbe63
| Author | SHA1 | Date | |
|---|---|---|---|
| 395e3dbe63 | |||
|
|
9fc7198f40 | ||
| d860e94dee | |||
| 6100ac80f3 | |||
|
|
229957e283 | ||
| 0724d66727 | |||
|
|
7e3b308572 | ||
| 4423b7fa25 | |||
|
|
519967855e | ||
| 01346f950c | |||
| 584a550ce2 | |||
|
|
8b34e94de3 |
@@ -135,6 +135,45 @@ describe("LookupsService.findLastProcessedCarPolicy", () => {
|
|||||||
expect(lookup.inquiryByVin).not.toHaveBeenCalled();
|
expect(lookup.inquiryByVin).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("rejects an expired car-body policy instead of treating it as active coverage", async () => {
|
||||||
|
const lookup = {
|
||||||
|
myPolicies: jest.fn().mockResolvedValue([
|
||||||
|
{
|
||||||
|
PolicyId: 44,
|
||||||
|
InsuranceLineId: 4,
|
||||||
|
BeginDate: "1400/01/01",
|
||||||
|
EndDate: "1401/01/01",
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
inquiryByVin: jest.fn(),
|
||||||
|
bodyPolicyById: jest.fn().mockResolvedValue({
|
||||||
|
PolicyId: 44,
|
||||||
|
VehicleId: 8,
|
||||||
|
BeginDate: "1400/01/01",
|
||||||
|
EndDate: "1401/01/01",
|
||||||
|
}),
|
||||||
|
vehicleById: jest.fn().mockResolvedValue({
|
||||||
|
Id: 8,
|
||||||
|
PlaqueLeftNo: "12",
|
||||||
|
PlaqueMiddleCodeId: 2,
|
||||||
|
PlaqueRightNo: "345",
|
||||||
|
PlaqueSerial: "67",
|
||||||
|
}),
|
||||||
|
getRemoteLookup: jest.fn().mockResolvedValue([]),
|
||||||
|
customerById: jest.fn().mockResolvedValue(null),
|
||||||
|
};
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
createService(lookup).findLastProcessedCarPolicy("car-body", {
|
||||||
|
nationalCode: "0012345678",
|
||||||
|
plaqueLeft: "12",
|
||||||
|
plaqueLetter: "ب",
|
||||||
|
plaqueRight: "345",
|
||||||
|
plaqueSerial: "67",
|
||||||
|
}),
|
||||||
|
).rejects.toBeInstanceOf(NotFoundException);
|
||||||
|
});
|
||||||
|
|
||||||
it("accepts the policy when VIN inquiry VehicleId matches and GEN.15 VIN is empty", async () => {
|
it("accepts the policy when VIN inquiry VehicleId matches and GEN.15 VIN is empty", async () => {
|
||||||
const lookup = {
|
const lookup = {
|
||||||
myPolicies: jest.fn().mockResolvedValue([
|
myPolicies: jest.fn().mockResolvedValue([
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
filterPoliciesByLine,
|
filterPoliciesByLine,
|
||||||
insuranceLineIdForProduct,
|
insuranceLineIdForProduct,
|
||||||
insuranceLineLabel,
|
insuranceLineLabel,
|
||||||
|
isPolicyActiveOn,
|
||||||
parseFanavaranId,
|
parseFanavaranId,
|
||||||
parseLastCarPolicyInput,
|
parseLastCarPolicyInput,
|
||||||
pickVehicleId,
|
pickVehicleId,
|
||||||
@@ -34,6 +35,7 @@ import {
|
|||||||
type FanavaranCarPolicyProduct,
|
type FanavaranCarPolicyProduct,
|
||||||
type HydratedFanavaranCarPolicy,
|
type HydratedFanavaranCarPolicy,
|
||||||
} from "./fanavaran-last-car-policy";
|
} from "./fanavaran-last-car-policy";
|
||||||
|
import { gregorianDateInIran } from "src/helpers/iran-datetime";
|
||||||
|
|
||||||
type TejaratAccidentReasonRow = {
|
type TejaratAccidentReasonRow = {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -433,6 +435,18 @@ export class LookupsService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A CAR_BODY case is payable only with current hull coverage. The generic
|
||||||
|
// selector may intentionally return the latest expired policy for history;
|
||||||
|
// that fallback is not valid for a new CAR_BODY case.
|
||||||
|
if (
|
||||||
|
product === "car-body" &&
|
||||||
|
!isPolicyActiveOn(selected, gregorianDateInIran(new Date()))
|
||||||
|
) {
|
||||||
|
throw new NotFoundException(
|
||||||
|
"No active Fanavaran car-body policy was found for this car.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
product,
|
product,
|
||||||
insuranceLine: insuranceLineLabel(insuranceLineId),
|
insuranceLine: insuranceLineLabel(insuranceLineId),
|
||||||
|
|||||||
@@ -134,6 +134,40 @@ function formatJalaliCompact(raw: number | string | null | undefined): string |
|
|||||||
export class RequestManagementService {
|
export class RequestManagementService {
|
||||||
private readonly logger = new Logger(RequestManagementService.name);
|
private readonly logger = new Logger(RequestManagementService.name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only the guilty (currently first) party's THIRD_PARTY policy must belong
|
||||||
|
* to this deployment. CAR_BODY flows deliberately do not constrain that
|
||||||
|
* separate third-party policy; their car-body lookup is checked on its own.
|
||||||
|
*/
|
||||||
|
private policyInquiryOptions(
|
||||||
|
requestType: BlameRequestType | string,
|
||||||
|
partyRole: PartyRole,
|
||||||
|
clientId?: string,
|
||||||
|
) {
|
||||||
|
const enforceDeploymentClientMatch =
|
||||||
|
requestType === BlameRequestType.THIRD_PARTY &&
|
||||||
|
partyRole === PartyRole.FIRST;
|
||||||
|
|
||||||
|
if (!clientId && !enforceDeploymentClientMatch) return undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...(clientId ? { clientId } : {}),
|
||||||
|
...(enforceDeploymentClientMatch
|
||||||
|
? { enforceDeploymentClientMatch: true }
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Keep eligibility rejections distinct from an unavailable CAR_BODY provider. */
|
||||||
|
private throwCarBodyInquiryFailure(err: unknown): never {
|
||||||
|
if (err instanceof ForbiddenException) throw err;
|
||||||
|
|
||||||
|
throw new HttpException(
|
||||||
|
"Car body inquiry failed",
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private stepKeyToPartyRole(stepKey: WorkflowStep): PartyRole {
|
private stepKeyToPartyRole(stepKey: WorkflowStep): PartyRole {
|
||||||
if (String(stepKey).startsWith("FIRST_")) return PartyRole.FIRST;
|
if (String(stepKey).startsWith("FIRST_")) return PartyRole.FIRST;
|
||||||
if (String(stepKey).startsWith("SECOND_")) return PartyRole.SECOND;
|
if (String(stepKey).startsWith("SECOND_")) return PartyRole.SECOND;
|
||||||
@@ -1283,9 +1317,11 @@ export class RequestManagementService {
|
|||||||
const inquiryClientId = party.person?.clientId
|
const inquiryClientId = party.person?.clientId
|
||||||
? String(party.person.clientId)
|
? String(party.person.clientId)
|
||||||
: undefined;
|
: undefined;
|
||||||
const inquiryOptions = inquiryClientId
|
const inquiryOptions = this.policyInquiryOptions(
|
||||||
? { clientId: inquiryClientId }
|
req.type,
|
||||||
: undefined;
|
role,
|
||||||
|
inquiryClientId,
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
const inquiry = await this.sandHubService.getTejaratBlockInquiry(
|
const inquiry = await this.sandHubService.getTejaratBlockInquiry(
|
||||||
{
|
{
|
||||||
@@ -1513,15 +1549,10 @@ export class RequestManagementService {
|
|||||||
if (req.type === BlameRequestType.CAR_BODY && role === PartyRole.FIRST) {
|
if (req.type === BlameRequestType.CAR_BODY && role === PartyRole.FIRST) {
|
||||||
let carBodyInfo: any;
|
let carBodyInfo: any;
|
||||||
try {
|
try {
|
||||||
carBodyInfo = await this.sandHubService.getCarBodyInquiry(
|
carBodyInfo = await this.sandHubService.getCarBodyInquiry({
|
||||||
{
|
nationalCodeOfInsurer: body.nationalCodeOfInsurer,
|
||||||
nationalCodeOfInsurer: body.nationalCodeOfInsurer,
|
plate: body.plate,
|
||||||
plate: body.plate,
|
});
|
||||||
},
|
|
||||||
resolvedClientId
|
|
||||||
? { clientId: String(resolvedClientId) }
|
|
||||||
: inquiryOptions,
|
|
||||||
);
|
|
||||||
this.recordPartyCaseInquiryStatus(req, "carBody", role, true, {
|
this.recordPartyCaseInquiryStatus(req, "carBody", role, true, {
|
||||||
source: carBodyInfo.source,
|
source: carBodyInfo.source,
|
||||||
raw: carBodyInfo.raw,
|
raw: carBodyInfo.raw,
|
||||||
@@ -1542,10 +1573,7 @@ export class RequestManagementService {
|
|||||||
await this.blameRequestDbService.findByIdAndUpdate(req._id, {
|
await this.blameRequestDbService.findByIdAndUpdate(req._id, {
|
||||||
$set: { inquiries: req.inquiries },
|
$set: { inquiries: req.inquiries },
|
||||||
});
|
});
|
||||||
throw new HttpException(
|
this.throwCarBodyInquiryFailure(err);
|
||||||
"Car body inquiry failed",
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw + mapped stored under vehicle
|
// Raw + mapped stored under vehicle
|
||||||
@@ -1763,9 +1791,11 @@ export class RequestManagementService {
|
|||||||
const inquiryClientId = party.person?.clientId
|
const inquiryClientId = party.person?.clientId
|
||||||
? String(party.person.clientId)
|
? String(party.person.clientId)
|
||||||
: undefined;
|
: undefined;
|
||||||
const inquiryOptions = inquiryClientId
|
const inquiryOptions = this.policyInquiryOptions(
|
||||||
? { clientId: inquiryClientId }
|
req.type,
|
||||||
: undefined;
|
role,
|
||||||
|
inquiryClientId,
|
||||||
|
);
|
||||||
|
|
||||||
let inquiryRaw: any;
|
let inquiryRaw: any;
|
||||||
let inquiryMapped: any;
|
let inquiryMapped: any;
|
||||||
@@ -1952,6 +1982,76 @@ export class RequestManagementService {
|
|||||||
inquiryMapped?.HEndDte ||
|
inquiryMapped?.HEndDte ||
|
||||||
inquiryMapped?.persianEndDate;
|
inquiryMapped?.persianEndDate;
|
||||||
|
|
||||||
|
// CAR_BODY eligibility is independent of the third-party policy above.
|
||||||
|
// The VIN flow must make the same deployment-scoped lookup as the plate
|
||||||
|
// flow before the case is allowed to advance.
|
||||||
|
if (req.type === BlameRequestType.CAR_BODY && role === PartyRole.FIRST) {
|
||||||
|
try {
|
||||||
|
const carBodyInfo = await this.sandHubService.getCarBodyInquiry({
|
||||||
|
nationalCodeOfInsurer: body.nationalCodeOfInsurer,
|
||||||
|
plate: body.vin,
|
||||||
|
});
|
||||||
|
this.recordPartyCaseInquiryStatus(req, "carBody", role, true, {
|
||||||
|
source: carBodyInfo.source,
|
||||||
|
raw: carBodyInfo.raw,
|
||||||
|
mapped: carBodyInfo.mapped,
|
||||||
|
});
|
||||||
|
party.vehicle.inquiry = {
|
||||||
|
...party.vehicle.inquiry,
|
||||||
|
carBody: {
|
||||||
|
source: carBodyInfo.source,
|
||||||
|
raw: carBodyInfo.raw,
|
||||||
|
mapped: carBodyInfo.mapped,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const m = carBodyInfo.mapped as any;
|
||||||
|
(party.insurance as any).carBodyInsurance = {
|
||||||
|
policyNumber: m.policyNumber ?? null,
|
||||||
|
companyId: m.companyId ?? m.CompanyCode ?? null,
|
||||||
|
companyName: m.CompanyName ?? null,
|
||||||
|
insurerName: m.insurerName ?? null,
|
||||||
|
chassisNumber: m.ChassisNumberField ?? null,
|
||||||
|
vin: m.VinNumberField ?? null,
|
||||||
|
motorNumber: m.EngineNumberField ?? null,
|
||||||
|
startDate: m.StartDate ?? null,
|
||||||
|
endDate: m.EndDate ?? null,
|
||||||
|
issueDate: m.IssueDate ?? null,
|
||||||
|
noLossYearsCount: m.noLossYearsCount ?? null,
|
||||||
|
lossDocuments: m.lossDocuments ?? [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const carBodyCompanyCode = m.companyId ?? m.CompanyCode;
|
||||||
|
const carBodyCompanyName = m.CompanyName ?? m.companyPersianName;
|
||||||
|
if (carBodyCompanyCode && carBodyCompanyName) {
|
||||||
|
const carBodyClient =
|
||||||
|
await this.clientService.findOrCreateClientByCompanyCode(
|
||||||
|
carBodyCompanyCode,
|
||||||
|
carBodyCompanyName,
|
||||||
|
);
|
||||||
|
const carBodyClientId =
|
||||||
|
(carBodyClient as any)?._id ?? (carBodyClient as any)?._doc?._id;
|
||||||
|
if (carBodyClientId) party.person.clientId = carBodyClientId;
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
this.logger.error(
|
||||||
|
`[CAR_BODY] VIN inquiry failed for request=${req._id}: ${err?.message || err}`,
|
||||||
|
);
|
||||||
|
this.recordPartyCaseInquiryStatus(
|
||||||
|
req,
|
||||||
|
"carBody",
|
||||||
|
role,
|
||||||
|
false,
|
||||||
|
{},
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
await this.blameRequestDbService.findByIdAndUpdate(req._id, {
|
||||||
|
$set: { inquiries: req.inquiries },
|
||||||
|
});
|
||||||
|
this.throwCarBodyInquiryFailure(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Advance workflow
|
// Advance workflow
|
||||||
await this.advanceWorkflowToNext(req, stepKey);
|
await this.advanceWorkflowToNext(req, stepKey);
|
||||||
|
|
||||||
@@ -2934,6 +3034,13 @@ export class RequestManagementService {
|
|||||||
body: AddPlateDto,
|
body: AddPlateDto,
|
||||||
partyType: "firstParty" | "secondParty",
|
partyType: "firstParty" | "secondParty",
|
||||||
) {
|
) {
|
||||||
|
if (request.type === "THIRD_PARTY" && partyType === "firstParty") {
|
||||||
|
this.sandHubService.assertInsuranceMatchesDeployment(
|
||||||
|
sandHubReport,
|
||||||
|
"THIRD_PARTY",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const clientName = sandHubReport?.CompanyName;
|
const clientName = sandHubReport?.CompanyName;
|
||||||
const companyCode = sandHubReport?.CompanyCode;
|
const companyCode = sandHubReport?.CompanyCode;
|
||||||
|
|
||||||
@@ -3024,12 +3131,10 @@ export class RequestManagementService {
|
|||||||
|
|
||||||
// For CAR_BODY type, persist the provider response and its mapped fields.
|
// For CAR_BODY type, persist the provider response and its mapped fields.
|
||||||
if (request.type === "CAR_BODY" && partyType === "firstParty") {
|
if (request.type === "CAR_BODY" && partyType === "firstParty") {
|
||||||
const carBodyInquiry = await this.sandHubService.getCarBodyInquiry(
|
const carBodyInquiry = await this.sandHubService.getCarBodyInquiry({
|
||||||
{
|
nationalCodeOfInsurer: body.nationalCodeOfInsurer,
|
||||||
nationalCodeOfInsurer: body.nationalCodeOfInsurer,
|
plate: body.plate,
|
||||||
plate: body.plate,
|
} as any);
|
||||||
} as any,
|
|
||||||
);
|
|
||||||
const carBodyInfo = carBodyInquiry.mapped as any;
|
const carBodyInfo = carBodyInquiry.mapped as any;
|
||||||
|
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
@@ -3073,6 +3178,7 @@ export class RequestManagementService {
|
|||||||
);
|
);
|
||||||
} catch (er) {
|
} catch (er) {
|
||||||
this.logger.error(er);
|
this.logger.error(er);
|
||||||
|
if (er instanceof HttpException) throw er;
|
||||||
throw new InternalServerErrorException(
|
throw new InternalServerErrorException(
|
||||||
"Failed to update request with plate details.",
|
"Failed to update request with plate details.",
|
||||||
);
|
);
|
||||||
@@ -6470,6 +6576,13 @@ export class RequestManagementService {
|
|||||||
"secondParty and guiltyPartyPhoneNumber are required.",
|
"secondParty and guiltyPartyPhoneNumber are required.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
formData.guiltyPartyPhoneNumber !== formData.firstPartyPhoneNumber
|
||||||
|
) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"The first party is the guilty party in this flow.",
|
||||||
|
);
|
||||||
|
}
|
||||||
if (!formData?.expertDescription?.desc) {
|
if (!formData?.expertDescription?.desc) {
|
||||||
throw new BadRequestException("expertDescription.desc is required.");
|
throw new BadRequestException("expertDescription.desc is required.");
|
||||||
}
|
}
|
||||||
@@ -6508,6 +6621,12 @@ export class RequestManagementService {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
const sandHubReport = (sandHubResponse["_doc"] || sandHubResponse) as any;
|
const sandHubReport = (sandHubResponse["_doc"] || sandHubResponse) as any;
|
||||||
|
if (role === PartyRole.FIRST) {
|
||||||
|
this.sandHubService.assertInsuranceMatchesDeployment(
|
||||||
|
sandHubReport,
|
||||||
|
"THIRD_PARTY",
|
||||||
|
);
|
||||||
|
}
|
||||||
this.recordPartyCaseInquiryStatus(
|
this.recordPartyCaseInquiryStatus(
|
||||||
req,
|
req,
|
||||||
"thirdParty",
|
"thirdParty",
|
||||||
@@ -7119,15 +7238,13 @@ export class RequestManagementService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate guilty party phone number matches one of the parties
|
// The first party is the guilty party in every supported THIRD_PARTY flow.
|
||||||
if (request.type === "THIRD_PARTY") {
|
if (request.type === "THIRD_PARTY") {
|
||||||
const guiltyMatchesFirst =
|
if (
|
||||||
formData.guiltyPartyPhoneNumber === formData.firstPartyPhoneNumber;
|
formData.guiltyPartyPhoneNumber !== formData.firstPartyPhoneNumber
|
||||||
const guiltyMatchesSecond =
|
) {
|
||||||
formData.guiltyPartyPhoneNumber === formData.secondParty.phoneNumber;
|
|
||||||
if (!guiltyMatchesFirst && !guiltyMatchesSecond) {
|
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
"Guilty party phone number must match either first or second party phone number",
|
"The first party is the guilty party in this flow.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7199,6 +7316,10 @@ export class RequestManagementService {
|
|||||||
nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer,
|
nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer,
|
||||||
});
|
});
|
||||||
const sandHubReport = sandHubResponse["_doc"] || sandHubResponse;
|
const sandHubReport = sandHubResponse["_doc"] || sandHubResponse;
|
||||||
|
this.sandHubService.assertInsuranceMatchesDeployment(
|
||||||
|
sandHubReport,
|
||||||
|
"THIRD_PARTY",
|
||||||
|
);
|
||||||
|
|
||||||
const clientName =
|
const clientName =
|
||||||
sandHubReport?.CompanyName || sandHubReport?.LastCompanyName;
|
sandHubReport?.CompanyName || sandHubReport?.LastCompanyName;
|
||||||
@@ -7253,6 +7374,7 @@ export class RequestManagementService {
|
|||||||
stepsToAdd.push(StepsEnum.F_addPlate);
|
stepsToAdd.push(StepsEnum.F_addPlate);
|
||||||
} catch (plateError) {
|
} catch (plateError) {
|
||||||
this.logger.error("Error processing first party plate:", plateError);
|
this.logger.error("Error processing first party plate:", plateError);
|
||||||
|
if (plateError instanceof HttpException) throw plateError;
|
||||||
throw new InternalServerErrorException(
|
throw new InternalServerErrorException(
|
||||||
"Failed to process first party plate information",
|
"Failed to process first party plate information",
|
||||||
);
|
);
|
||||||
@@ -8693,7 +8815,7 @@ export class RequestManagementService {
|
|||||||
const roleLabel = partyRole === PartyRole.FIRST ? "FIRST" : "SECOND";
|
const roleLabel = partyRole === PartyRole.FIRST ? "FIRST" : "SECOND";
|
||||||
let clientId: string | undefined;
|
let clientId: string | undefined;
|
||||||
const inquiryOptions = (cid?: string) =>
|
const inquiryOptions = (cid?: string) =>
|
||||||
cid ? { clientId: cid } : undefined;
|
this.policyInquiryOptions(req.type, partyRole, cid);
|
||||||
|
|
||||||
let inquiryRaw: any;
|
let inquiryRaw: any;
|
||||||
let inquiryMapped: any;
|
let inquiryMapped: any;
|
||||||
@@ -8813,13 +8935,10 @@ export class RequestManagementService {
|
|||||||
partyRole === PartyRole.FIRST
|
partyRole === PartyRole.FIRST
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const carBodyInfo = await this.sandHubService.getCarBodyInquiry(
|
const carBodyInfo = await this.sandHubService.getCarBodyInquiry({
|
||||||
{
|
nationalCodeOfInsurer: partyData.nationalCodeOfInsurer,
|
||||||
nationalCodeOfInsurer: partyData.nationalCodeOfInsurer,
|
plate: partyData.plate as any,
|
||||||
plate: partyData.plate as any,
|
});
|
||||||
},
|
|
||||||
clientId ? { clientId } : undefined,
|
|
||||||
);
|
|
||||||
this.recordPartyCaseInquiryStatus(req, "carBody", partyRole, true, {
|
this.recordPartyCaseInquiryStatus(req, "carBody", partyRole, true, {
|
||||||
source: carBodyInfo.source,
|
source: carBodyInfo.source,
|
||||||
raw: carBodyInfo.raw,
|
raw: carBodyInfo.raw,
|
||||||
@@ -8896,9 +9015,7 @@ export class RequestManagementService {
|
|||||||
{},
|
{},
|
||||||
err,
|
err,
|
||||||
);
|
);
|
||||||
throw new BadRequestException(
|
this.throwCarBodyInquiryFailure(err);
|
||||||
`CAR_BODY inquiry failed: ${err?.message || "استعلام در دسترس نیست"}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9548,7 +9665,7 @@ export class RequestManagementService {
|
|||||||
const roleLabel = partyRole === PartyRole.FIRST ? "FIRST" : "SECOND";
|
const roleLabel = partyRole === PartyRole.FIRST ? "FIRST" : "SECOND";
|
||||||
let clientId: string | undefined;
|
let clientId: string | undefined;
|
||||||
const inquiryOptions = (cid?: string) =>
|
const inquiryOptions = (cid?: string) =>
|
||||||
cid ? { clientId: cid } : undefined;
|
this.policyInquiryOptions(req.type, partyRole, cid);
|
||||||
|
|
||||||
let inquiryRaw: any;
|
let inquiryRaw: any;
|
||||||
let inquiryMapped: any;
|
let inquiryMapped: any;
|
||||||
@@ -9668,13 +9785,10 @@ export class RequestManagementService {
|
|||||||
partyRole === PartyRole.FIRST
|
partyRole === PartyRole.FIRST
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const carBodyInfo = await this.sandHubService.getCarBodyInquiry(
|
const carBodyInfo = await this.sandHubService.getCarBodyInquiry({
|
||||||
{
|
nationalCodeOfInsurer: partyData.nationalCodeOfInsurer,
|
||||||
nationalCodeOfInsurer: partyData.nationalCodeOfInsurer,
|
plate: partyData.vin as any, // VIN used as identifier for CAR_BODY
|
||||||
plate: partyData.vin as any, // VIN used as identifier for CAR_BODY
|
});
|
||||||
},
|
|
||||||
clientId ? { clientId } : undefined,
|
|
||||||
);
|
|
||||||
this.recordPartyCaseInquiryStatus(req, "carBody", partyRole, true, {
|
this.recordPartyCaseInquiryStatus(req, "carBody", partyRole, true, {
|
||||||
source: carBodyInfo.source,
|
source: carBodyInfo.source,
|
||||||
raw: carBodyInfo.raw,
|
raw: carBodyInfo.raw,
|
||||||
@@ -9751,9 +9865,7 @@ export class RequestManagementService {
|
|||||||
{},
|
{},
|
||||||
err,
|
err,
|
||||||
);
|
);
|
||||||
throw new BadRequestException(
|
this.throwCarBodyInquiryFailure(err);
|
||||||
`CAR_BODY VIN inquiry failed: ${err?.message || "استعلام در دسترس نیست"}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ export class SandHubInquiryOptionsDto {
|
|||||||
"Insurer client Mongo ObjectId. When omitted, resolves from deployment CLIENT_ID env.",
|
"Insurer client Mongo ObjectId. When omitted, resolves from deployment CLIENT_ID env.",
|
||||||
})
|
})
|
||||||
clientId?: string;
|
clientId?: string;
|
||||||
|
|
||||||
|
/** Require the returned policy insurer to match the deployment CLIENT_ID. */
|
||||||
|
enforceDeploymentClientMatch?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SandHubInquiryOptions = SandHubInquiryOptionsDto;
|
export type SandHubInquiryOptions = SandHubInquiryOptionsDto;
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { SandHubService } from "./sand-hub.service";
|
import { SandHubService } from "./sand-hub.service";
|
||||||
|
import {
|
||||||
|
ForbiddenException,
|
||||||
|
ServiceUnavailableException,
|
||||||
|
} from "@nestjs/common";
|
||||||
import { ExternalInquirySettingsService } from "src/client/external-inquiry-settings.service";
|
import { ExternalInquirySettingsService } from "src/client/external-inquiry-settings.service";
|
||||||
import { SandHubDetailDto } from "./dto/sand-hub.dto";
|
import { SandHubDetailDto } from "./dto/sand-hub.dto";
|
||||||
|
|
||||||
@@ -15,6 +19,9 @@ describe("SandHubService inquiry mocks", () => {
|
|||||||
const lookupsService = {
|
const lookupsService = {
|
||||||
findLastProcessedCarPolicy: jest.fn(),
|
findLastProcessedCarPolicy: jest.fn(),
|
||||||
};
|
};
|
||||||
|
const offlineInquiryService = {
|
||||||
|
findPlateInquiry: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
let service: SandHubService;
|
let service: SandHubService;
|
||||||
|
|
||||||
@@ -31,18 +38,18 @@ describe("SandHubService inquiry mocks", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
delete process.env.CLIENT_ID;
|
process.env.CLIENT_ID = "8";
|
||||||
|
delete process.env.FANAVARAN_CLIENT;
|
||||||
service = new SandHubService(
|
service = new SandHubService(
|
||||||
httpService as any,
|
httpService as any,
|
||||||
sandHubDbService as any,
|
sandHubDbService as any,
|
||||||
externalInquirySettings as unknown as ExternalInquirySettingsService,
|
externalInquirySettings as unknown as ExternalInquirySettingsService,
|
||||||
plateNormalizer as any,
|
plateNormalizer as any,
|
||||||
{
|
offlineInquiryService as any,
|
||||||
findPlateInquiry: jest.fn().mockResolvedValue(null),
|
|
||||||
} as any,
|
|
||||||
lookupsService as any,
|
lookupsService as any,
|
||||||
);
|
);
|
||||||
externalInquirySettings.isInquiryLive.mockResolvedValue(false);
|
externalInquirySettings.isInquiryLive.mockResolvedValue(false);
|
||||||
|
offlineInquiryService.findPlateInquiry.mockResolvedValue(null);
|
||||||
externalInquirySettings.getMockCompanyContext.mockResolvedValue({
|
externalInquirySettings.getMockCompanyContext.mockResolvedValue({
|
||||||
companyId: "8",
|
companyId: "8",
|
||||||
companyName: "بیمه پارسیان",
|
companyName: "بیمه پارسیان",
|
||||||
@@ -107,6 +114,131 @@ describe("SandHubService inquiry mocks", () => {
|
|||||||
expect(httpService.post).not.toHaveBeenCalled();
|
expect(httpService.post).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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("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.getPolicyByChassisInquiry("NAAR03HFFRDE07024", {
|
||||||
|
enforceDeploymentClientMatch: true,
|
||||||
|
}),
|
||||||
|
).rejects.toBeInstanceOf(ForbiddenException);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not accept a policy when CLIENT_ID is not configured", async () => {
|
||||||
|
delete process.env.CLIENT_ID;
|
||||||
|
|
||||||
|
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";
|
||||||
|
jest.spyOn(service, "getTejaratCarBodyInquiry").mockResolvedValue({
|
||||||
|
raw: { data: { companyId: "8" } },
|
||||||
|
mapped: { companyId: "8", CompanyCode: "8" },
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(service.getCarBodyInquiry(userDetail)).rejects.toBeInstanceOf(
|
||||||
|
ForbiddenException,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 () => {
|
it("keeps ESG car-body inquiry in mock mode when the per-client toggle is off", async () => {
|
||||||
process.env.CLIENT_ID = "8";
|
process.env.CLIENT_ID = "8";
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { HttpService } from "@nestjs/axios";
|
|||||||
import {
|
import {
|
||||||
BadGatewayException,
|
BadGatewayException,
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
|
ForbiddenException,
|
||||||
GatewayTimeoutException,
|
GatewayTimeoutException,
|
||||||
Injectable,
|
Injectable,
|
||||||
Logger,
|
Logger,
|
||||||
@@ -80,6 +81,69 @@ export class SandHubService {
|
|||||||
return String(process.env.CLIENT_ID ?? "") === "8";
|
return String(process.env.CLIENT_ID ?? "") === "8";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The processed Fanavaran CAR_BODY lookup belongs only to the Parsian
|
||||||
|
* Fanavaran profile. Do not use the deployment-wide ESG selector here:
|
||||||
|
* `FANAVARAN_CLIENT=parsian` is valid even when CLIENT_ID is not 8.
|
||||||
|
*/
|
||||||
|
private shouldUseParsianCarBodyLookup(): boolean {
|
||||||
|
return resolveFanavaranClientKey() === "parsian";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A case may proceed only when the policy belongs to the insurer served by
|
||||||
|
* this deployment. Callers opt in for the guilty/first-party policy only.
|
||||||
|
*/
|
||||||
|
assertInsuranceMatchesDeployment(
|
||||||
|
mapped: Record<string, unknown> | null | undefined,
|
||||||
|
insuranceLine: "THIRD_PARTY" | "CAR_BODY",
|
||||||
|
): void {
|
||||||
|
const expectedClientCode = String(process.env.CLIENT_ID ?? "").trim();
|
||||||
|
if (!expectedClientCode) {
|
||||||
|
throw new ServiceUnavailableException(
|
||||||
|
"CLIENT_ID must be configured before insurance eligibility can be checked.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const actualClientCode = String(
|
||||||
|
mapped?.CompanyCode ?? mapped?.companyId ?? mapped?.CompanyId ?? "",
|
||||||
|
).trim();
|
||||||
|
if (actualClientCode === expectedClientCode) return;
|
||||||
|
|
||||||
|
throw new ForbiddenException(
|
||||||
|
`${insuranceLine} policy insurer does not match this deployment.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private enforceDeploymentClientMatch(
|
||||||
|
mapped: Record<string, unknown>,
|
||||||
|
insuranceLine: "THIRD_PARTY" | "CAR_BODY",
|
||||||
|
options?: SandHubInquiryOptions,
|
||||||
|
): void {
|
||||||
|
if (options?.enforceDeploymentClientMatch) {
|
||||||
|
this.assertInsuranceMatchesDeployment(mapped, insuranceLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The processed Fanavaran CAR_BODY endpoint is a Parsian-only source and its
|
||||||
|
* response does not contain a reliable insurer company code. Treat the source
|
||||||
|
* itself as proof that the returned policy is Parsian.
|
||||||
|
*/
|
||||||
|
private assertParsianCarBodyLookupMatchesDeployment(): void {
|
||||||
|
const expectedClientCode = String(process.env.CLIENT_ID ?? "").trim();
|
||||||
|
if (!expectedClientCode) {
|
||||||
|
throw new ServiceUnavailableException(
|
||||||
|
"CLIENT_ID must be configured before insurance eligibility can be checked.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (expectedClientCode === "8") return;
|
||||||
|
|
||||||
|
throw new ForbiddenException(
|
||||||
|
"CAR_BODY policy insurer does not match this deployment.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/** Fixed plate/insurance inquiry payload used everywhere we mock block-inquiry style APIs. */
|
/** Fixed plate/insurance inquiry payload used everywhere we mock block-inquiry style APIs. */
|
||||||
private buildMockPlateInquiryRaw(
|
private buildMockPlateInquiryRaw(
|
||||||
ctx: MockInquiryCompanyContext,
|
ctx: MockInquiryCompanyContext,
|
||||||
@@ -757,25 +821,35 @@ export class SandHubService {
|
|||||||
person?: Record<string, unknown>;
|
person?: Record<string, unknown>;
|
||||||
};
|
};
|
||||||
}> {
|
}> {
|
||||||
const offlineHit = await this.offlineInquiryService.findPlateInquiry({
|
const live = await this.isInquiryLive("thirdPartyPlate", options);
|
||||||
clientKey: resolveFanavaranClientKey(),
|
// Offline records are a fallback for disabled inquiry mode only. They must
|
||||||
nationalCode: String(userDetail.nationalCodeOfInsurer),
|
// never override a configured live ESG/Tejarat inquiry.
|
||||||
leftDigits: String(userDetail.plate.leftDigits),
|
if (!live) {
|
||||||
centerAlphabet: String(userDetail.plate.centerAlphabet),
|
const offlineHit = await this.offlineInquiryService.findPlateInquiry({
|
||||||
centerDigits: String(userDetail.plate.centerDigits),
|
clientKey: resolveFanavaranClientKey(),
|
||||||
ir: String(userDetail.plate.ir),
|
nationalCode: String(userDetail.nationalCodeOfInsurer),
|
||||||
});
|
leftDigits: String(userDetail.plate.leftDigits),
|
||||||
if (offlineHit) {
|
centerAlphabet: String(userDetail.plate.centerAlphabet),
|
||||||
return {
|
centerDigits: String(userDetail.plate.centerDigits),
|
||||||
raw: offlineHit.raw,
|
ir: String(userDetail.plate.ir),
|
||||||
mapped: offlineHit.mapped,
|
});
|
||||||
offline: {
|
if (offlineHit) {
|
||||||
source: offlineHit.source,
|
this.enforceDeploymentClientMatch(
|
||||||
fanavaranDriverId: offlineHit.fanavaranDriverId,
|
offlineHit.mapped,
|
||||||
insurance: offlineHit.insurance,
|
"THIRD_PARTY",
|
||||||
person: offlineHit.person,
|
options,
|
||||||
},
|
);
|
||||||
};
|
return {
|
||||||
|
raw: offlineHit.raw,
|
||||||
|
mapped: offlineHit.mapped,
|
||||||
|
offline: {
|
||||||
|
source: offlineHit.source,
|
||||||
|
fanavaranDriverId: offlineHit.fanavaranDriverId,
|
||||||
|
insurance: offlineHit.insurance,
|
||||||
|
person: offlineHit.person,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ctx = await this.mockCompanyContext(options);
|
const ctx = await this.mockCompanyContext(options);
|
||||||
@@ -790,7 +864,6 @@ export class SandHubService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const requestUrl = `${baseUrl}/inquiry/policyByPlate`;
|
const requestUrl = `${baseUrl}/inquiry/policyByPlate`;
|
||||||
const live = await this.isInquiryLive("thirdPartyPlate", options);
|
|
||||||
const raw = live
|
const raw = live
|
||||||
? await this.makeEsgRequest(
|
? await this.makeEsgRequest(
|
||||||
requestUrl,
|
requestUrl,
|
||||||
@@ -805,6 +878,7 @@ export class SandHubService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const mapped = this.mapEsgPolicyByPlateToOldFormat(raw);
|
const mapped = this.mapEsgPolicyByPlateToOldFormat(raw);
|
||||||
|
this.enforceDeploymentClientMatch(mapped, "THIRD_PARTY", options);
|
||||||
return { raw, mapped };
|
return { raw, mapped };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -819,7 +893,6 @@ export class SandHubService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const requestUrl = `${baseUrl}/block-inquiry-tejarat`;
|
const requestUrl = `${baseUrl}/block-inquiry-tejarat`;
|
||||||
const live = await this.isInquiryLive("thirdPartyPlate", options);
|
|
||||||
const raw = live
|
const raw = live
|
||||||
? await this.makeTejaratRequest(
|
? await this.makeTejaratRequest(
|
||||||
requestUrl,
|
requestUrl,
|
||||||
@@ -834,6 +907,7 @@ export class SandHubService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const mapped = this.mapNewApiResponseToOldFormat(raw);
|
const mapped = this.mapNewApiResponseToOldFormat(raw);
|
||||||
|
this.enforceDeploymentClientMatch(mapped, "THIRD_PARTY", options);
|
||||||
return { raw, mapped };
|
return { raw, mapped };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -857,11 +931,12 @@ export class SandHubService {
|
|||||||
raw: any;
|
raw: any;
|
||||||
mapped: Record<string, unknown>;
|
mapped: Record<string, unknown>;
|
||||||
}> {
|
}> {
|
||||||
if (!this.shouldUseEsgInquiryProvider()) {
|
if (!this.shouldUseParsianCarBodyLookup()) {
|
||||||
const result = await this.getTejaratCarBodyInquiry(
|
const result = await this.getTejaratCarBodyInquiry(
|
||||||
userDetail as SandHubDetailDto,
|
userDetail as SandHubDetailDto,
|
||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
|
this.assertInsuranceMatchesDeployment(result.mapped, "CAR_BODY");
|
||||||
return {
|
return {
|
||||||
source:
|
source:
|
||||||
typeof userDetail.plate === "string"
|
typeof userDetail.plate === "string"
|
||||||
@@ -878,6 +953,7 @@ export class SandHubService {
|
|||||||
userDetail as SandHubDetailDto,
|
userDetail as SandHubDetailDto,
|
||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
|
this.assertParsianCarBodyLookupMatchesDeployment();
|
||||||
return {
|
return {
|
||||||
source:
|
source:
|
||||||
typeof userDetail.plate === "string"
|
typeof userDetail.plate === "string"
|
||||||
@@ -905,6 +981,7 @@ export class SandHubService {
|
|||||||
"car-body",
|
"car-body",
|
||||||
query,
|
query,
|
||||||
);
|
);
|
||||||
|
this.assertParsianCarBodyLookupMatchesDeployment();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
source:
|
source:
|
||||||
@@ -1045,6 +1122,7 @@ export class SandHubService {
|
|||||||
`[MOCK] getPolicyByChassisInquiry chassisNo=${chassisNo}`,
|
`[MOCK] getPolicyByChassisInquiry chassisNo=${chassisNo}`,
|
||||||
);
|
);
|
||||||
const mapped = this.mapEsgPolicyByPlateToOldFormat(raw);
|
const mapped = this.mapEsgPolicyByPlateToOldFormat(raw);
|
||||||
|
this.enforceDeploymentClientMatch(mapped, "THIRD_PARTY", options);
|
||||||
return { raw, mapped };
|
return { raw, mapped };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1055,6 +1133,7 @@ export class SandHubService {
|
|||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
const mapped = this.mapEsgPolicyByPlateToOldFormat(raw);
|
const mapped = this.mapEsgPolicyByPlateToOldFormat(raw);
|
||||||
|
this.enforceDeploymentClientMatch(mapped, "THIRD_PARTY", options);
|
||||||
return { raw, mapped };
|
return { raw, mapped };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1285,6 +1364,7 @@ export class SandHubService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = this.mapNewApiResponseToOldFormat(response);
|
const result = this.mapNewApiResponseToOldFormat(response);
|
||||||
|
this.enforceDeploymentClientMatch(result, "THIRD_PARTY", options);
|
||||||
|
|
||||||
// if (result.usgCod !== "8") {
|
// if (result.usgCod !== "8") {
|
||||||
// throw new Error("خودرو شما شخصی / سواری نمی باشد")
|
// throw new Error("خودرو شما شخصی / سواری نمی باشد")
|
||||||
@@ -1292,6 +1372,12 @@ export class SandHubService {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (
|
||||||
|
err instanceof ForbiddenException ||
|
||||||
|
err instanceof ServiceUnavailableException
|
||||||
|
) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
throw new Error(err);
|
throw new Error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user