car body policy and sales extended

This commit is contained in:
2026-09-05 18:37:42 +03:30
parent eb072ef080
commit eb636bdbdd
10 changed files with 1097 additions and 14 deletions

View File

@@ -1,5 +1,13 @@
import { Injectable, Logger, NotFoundException } from "@nestjs/common";
import { resolveFanavaranClientKey } from "src/core/config/fanavaran-client.config";
import {
BadRequestException,
Injectable,
Logger,
NotFoundException,
} from "@nestjs/common";
import {
resolveFanavaranClientKey,
resolveFanavaranProductContractId,
} from "src/core/config/fanavaran-client.config";
import {
FANAVARAN_REMOTE_LOOKUPS,
type FanavaranRemoteLookupDefinition,
@@ -7,6 +15,19 @@ import {
} from "src/fanavaran/fanavaran-lookup.config";
import { FanavaranLookupService } from "src/fanavaran/fanavaran-lookup.service";
import { LookupDbService } from "./entities/db-service/lookup.db.service";
import {
asObjectRecord,
filterPoliciesByLine,
insuranceLineIdForProduct,
parseFanavaranId,
parseLastCarPolicyInput,
pickVehicleId,
selectLastAmongCarMatches,
sortPoliciesNewestEndDateFirst,
vehicleMatchesCar,
type FanavaranCarPolicyProduct,
type HydratedFanavaranCarPolicy,
} from "./fanavaran-last-car-policy";
type TejaratAccidentReasonRow = {
id: number;
@@ -170,6 +191,177 @@ export class LookupsService {
);
}
async findLastProcessedCarPolicy(
product: FanavaranCarPolicyProduct,
query: {
nationalCode?: string;
vin?: string;
plaqueLeft?: string;
plaqueLetter?: string;
plaqueRight?: string;
plaqueSerial?: string;
},
): Promise<{
product: FanavaranCarPolicyProduct;
insuranceLineId: number;
policyId: number;
policy: any;
vehicle: Record<string, unknown> | null;
}> {
const parsed = parseLastCarPolicyInput(query);
if ("error" in parsed) {
throw new BadRequestException(parsed.error);
}
const clientKey = this.activeClientKey();
const insuranceLineId = insuranceLineIdForProduct(product);
const contractIdOverride = resolveFanavaranProductContractId(
clientKey,
product,
);
const requestOptions = { contractIdOverride };
const listed = await this.fanavaranLookupService.myPolicies(
clientKey,
parsed.nationalCode,
insuranceLineId,
requestOptions,
);
const candidates = sortPoliciesNewestEndDateFirst(
filterPoliciesByLine(listed, insuranceLineId),
);
let vinVehicleId: number | null = null;
if (parsed.vin) {
try {
const inquired = await this.fanavaranLookupService.inquiryByVin(
clientKey,
parsed.vin,
requestOptions,
);
vinVehicleId = pickVehicleId(inquired);
} catch (error) {
this.logger.warn(
`VIN vehicle helper failed; continuing with policy hydrate: ${
error instanceof Error ? error.message : error
}`,
);
}
}
const matches: HydratedFanavaranCarPolicy[] = [];
let hydrationFailures = 0;
for (const row of candidates) {
const policyId = parseFanavaranId(row.PolicyId);
if (policyId === null) continue;
let policyRaw: unknown;
try {
policyRaw =
product === "car-body"
? await this.fanavaranLookupService.bodyPolicyById(
clientKey,
policyId,
requestOptions,
)
: await this.fanavaranLookupService.thirdPartyPolicyById(
clientKey,
policyId,
requestOptions,
);
} catch (error) {
hydrationFailures += 1;
this.logger.warn(
`Policy GET failed for PolicyId=${policyId}: ${
error instanceof Error ? error.message : error
}`,
);
continue;
}
const policy = asObjectRecord(policyRaw);
if (!policy) continue;
const vehicleId = pickVehicleId(policy.VehicleId ?? policy.vehicleId);
if (
parsed.vin &&
vinVehicleId !== null &&
vehicleId !== null &&
vehicleId !== vinVehicleId
) {
continue;
}
let vehicle: Record<string, unknown> | null = null;
if (vehicleId !== null) {
try {
vehicle = asObjectRecord(
await this.fanavaranLookupService.vehicleById(
clientKey,
vehicleId,
undefined,
requestOptions,
),
);
} catch (error) {
this.logger.warn(
`Vehicle GET failed for VehicleId=${vehicleId} (PolicyId=${policyId}): ${
error instanceof Error ? error.message : error
}`,
);
}
}
const matchedByVinVehicleId =
parsed.vin != null &&
vinVehicleId != null &&
vehicleId != null &&
vinVehicleId === vehicleId;
if (
!matchedByVinVehicleId &&
!vehicleMatchesCar(vehicle, parsed, vinVehicleId)
) {
continue;
}
matches.push({
policyId,
beginDate: policy.BeginDate ?? row.BeginDate,
endDate: policy.EndDate ?? row.EndDate,
vehicleId,
policy,
vehicle,
});
}
const selected = selectLastAmongCarMatches(matches);
if (!selected) {
if (candidates.length === 0) {
throw new NotFoundException(
`No Fanavaran ${product} policy was found for this national code and car.`,
);
}
if (hydrationFailures === candidates.length) {
throw new NotFoundException(
`Fanavaran ${product} policy details could not be loaded for this national code.`,
);
}
throw new NotFoundException(
`No Fanavaran ${product} policy of that line was found for this car.`,
);
}
return {
product,
insuranceLineId,
policyId: selected.policyId,
policy: await this.mapPolicyDetails(selected.policy),
vehicle: selected.vehicle,
};
}
async mapPolicyDetails(policy: any): Promise<any> {
if (!policy || typeof policy !== "object") {
return policy;
@@ -222,13 +414,26 @@ export class LookupsService {
async bodyPolicyById(policyId: number): Promise<unknown> {
const clientKey = this.activeClientKey();
const policy = await this.fanavaranLookupService.bodyPolicyById(clientKey, policyId);
const policy = await this.fanavaranLookupService.bodyPolicyById(
clientKey,
policyId,
{
contractIdOverride: resolveFanavaranProductContractId(
clientKey,
"car-body",
),
},
);
return this.mapPolicyDetails(policy);
}
async vehicleById(vehicleId: number, versionNo: number = 1): Promise<unknown> {
async vehicleById(vehicleId: number, versionNo?: number): Promise<unknown> {
const clientKey = this.activeClientKey();
return this.fanavaranLookupService.vehicleById(clientKey, vehicleId, versionNo);
return this.fanavaranLookupService.vehicleById(
clientKey,
vehicleId,
versionNo,
);
}
async customerById(customerId: number): Promise<unknown> {