fanavaran added 2 apis for get payload and submit manually

This commit is contained in:
2026-06-23 13:17:30 +03:30
parent d84bd24682
commit 114e5e6604
7 changed files with 282 additions and 109 deletions

View File

@@ -10,6 +10,7 @@ import { AuthModule } from "./auth/auth.module";
import { ClaimRequestManagementModule } from "./claim-request-management/claim-request-management.module"; import { ClaimRequestManagementModule } from "./claim-request-management/claim-request-management.module";
import { ClientModule } from "./client/client.module"; import { ClientModule } from "./client/client.module";
import { ExpertBlameModule } from "./expert-blame/expert-blame.module"; import { ExpertBlameModule } from "./expert-blame/expert-blame.module";
import { FanavaranModule } from "./fanavaran/fanavaran.module";
import { ExpertClaimModule } from "./expert-claim/expert-claim.module"; import { ExpertClaimModule } from "./expert-claim/expert-claim.module";
import { ExpertInsurerModule } from "./expert-insurer/expert-insurer.module"; import { ExpertInsurerModule } from "./expert-insurer/expert-insurer.module";
import { LookupsModule } from "./lookups/lookups.module"; import { LookupsModule } from "./lookups/lookups.module";
@@ -49,6 +50,7 @@ import { AppConfigModule } from "./core/config/config.module";
SystemSettingsModule, SystemSettingsModule,
ExpertBlameModule, ExpertBlameModule,
ClaimRequestManagementModule, ClaimRequestManagementModule,
FanavaranModule,
ExpertClaimModule, ExpertClaimModule,
AiModule, AiModule,
ReportsModule, ReportsModule,

View File

@@ -163,6 +163,12 @@ import {
import { HttpService } from "@nestjs/axios"; import { HttpService } from "@nestjs/axios";
import { firstValueFrom } from "rxjs"; import { firstValueFrom } from "rxjs";
import { buildEnrichedDamagedParts } from "src/expert-claim/dto/claim-damaged-part.enricher"; import { buildEnrichedDamagedParts } from "src/expert-claim/dto/claim-damaged-part.enricher";
import {
type FanavaranClientKey,
fanavaranSubmitPath,
getFanavaranClientProfile,
resolveFanavaranClientKey,
} from "src/core/config/fanavaran-client.config";
export interface FanavaranAutoSubmitResult { export interface FanavaranAutoSubmitResult {
attempted: boolean; attempted: boolean;
@@ -175,6 +181,9 @@ export interface FanavaranAutoSubmitResult {
fanavaranResponse?: unknown; fanavaranResponse?: unknown;
} }
/** Placeholder for Fanavaran fields not yet mapped from claim/blame data. */
const FANAVARAN_UNMAPPED_FIELD = "empty";
@Injectable() @Injectable()
export class ClaimRequestManagementService { export class ClaimRequestManagementService {
private readonly logger = new Logger(ClaimRequestManagementService.name); private readonly logger = new Logger(ClaimRequestManagementService.name);
@@ -3349,9 +3358,15 @@ export class ClaimRequestManagementService {
} }
private applyFanavaranDefaultFields(result: Record<string, unknown>): void { private applyFanavaranDefaultFields(result: Record<string, unknown>): void {
result.ActualPremium = FANAVARAN_UNMAPPED_FIELD;
result.ArchiveNo = FANAVARAN_UNMAPPED_FIELD;
result.AuthorityCulpritId = FANAVARAN_UNMAPPED_FIELD;
result.AccidentCulpritId = null; result.AccidentCulpritId = null;
result.ClaimCompletionDate = FANAVARAN_UNMAPPED_FIELD;
result.CostSeparationToDmgSections = FANAVARAN_UNMAPPED_FIELD;
result.CouponNo = null; result.CouponNo = null;
result.CourtArchiveNo = null; result.CourtArchiveNo = null;
result.CustomerFaultPercent = FANAVARAN_UNMAPPED_FIELD;
result.CulpritLicenceCityId = null; result.CulpritLicenceCityId = null;
result.CulpritLicenceCountryId = null; result.CulpritLicenceCountryId = null;
result.CulpritLicenceForeignCityName = null; result.CulpritLicenceForeignCityName = null;
@@ -3360,11 +3375,14 @@ export class ClaimRequestManagementService {
result.DamagedCount = 1; result.DamagedCount = 1;
result.DmgAssessorFirstCreationTime = null; result.DmgAssessorFirstCreationTime = null;
result.EntryDate = null; result.EntryDate = null;
result.GlassBreakReasonId = FANAVARAN_UNMAPPED_FIELD;
result.IsLicenseMatchWithVehicleKind = 1; result.IsLicenseMatchWithVehicleKind = 1;
result.HasOtherCulprit = 0; result.HasOtherCulprit = 0;
result.IsAccidentOutOfBorder = 0; result.IsAccidentOutOfBorder = 0;
result.IsFatalAccident = 0; result.IsFatalAccident = 0;
result.IsOwnerChanged = FANAVARAN_UNMAPPED_FIELD;
result.IsPlaqueChanged = 0; result.IsPlaqueChanged = 0;
result.IsSurplusArticleEighthLaw = FANAVARAN_UNMAPPED_FIELD;
result.PlaqueCityId = null; result.PlaqueCityId = null;
result.PlaqueKindId = null; result.PlaqueKindId = null;
result.PlaqueLeftNo = null; result.PlaqueLeftNo = null;
@@ -3379,6 +3397,7 @@ export class ClaimRequestManagementService {
result.PoliceReportSerial = null; result.PoliceReportSerial = null;
result.PolicyId = null; result.PolicyId = null;
result.PreviousPolicyEndDate = ""; result.PreviousPolicyEndDate = "";
result.StatusChangeDate = FANAVARAN_UNMAPPED_FIELD;
result.TrackingCode = null; result.TrackingCode = null;
result.IsLicenseReplacement = 0; result.IsLicenseReplacement = 0;
result.UnknownCulpritCauseId = null; result.UnknownCulpritCauseId = null;
@@ -3610,39 +3629,7 @@ export class ClaimRequestManagementService {
} }
// Keep other fields from template with default values // Keep other fields from template with default values
result.AccidentCulpritId = null; //todo this.applyFanavaranDefaultFields(result);
result.CouponNo = null;
result.CourtArchiveNo = null;
result.CulpritLicenceCityId = null;
result.CulpritLicenceCountryId = null;
result.CulpritLicenceForeignCityName = null;
result.CulpritLicenceIssuDate = "1394/10/13"; //todo
result.CulpritLicenceNo = "1124242";
result.DamagedCount = 1;
result.DmgAssessorFirstCreationTime = null;
result.EntryDate = null;
result.IsLicenseMatchWithVehicleKind = 1;
result.HasOtherCulprit = 0;
result.IsAccidentOutOfBorder = 0;
result.IsFatalAccident = 0;
result.IsPlaqueChanged = 0;
result.PlaqueCityId = null;
result.PlaqueKindId = null;
result.PlaqueLeftNo = null;
result.PlaqueMiddleCodeId = null;
result.PlaqueNo = null;
result.PlaqueRightNo = null;
result.PlaqueSampleId = null;
result.PlaqueSerial = null;
result.PoliceOfficerId = 1;
result.PoliceReportDesc = null;
result.PoliceReportSeri = null;
result.PoliceReportSerial = null;
result.PolicyId = null;
result.PreviousPolicyEndDate = "";
result.TrackingCode = null;
result.IsLicenseReplacement = 0;
result.UnknownCulpritCauseId = null;
// Get PolicyId from external API // Get PolicyId from external API
try { try {
@@ -3964,14 +3951,19 @@ export class ClaimRequestManagementService {
} }
/** /**
* Fanavaran Submit (Parsian / V2) - Map data from claimCases + blameCases * Preview Fanavaran submit body (V2 claimCases + blameCases) for a specific client.
*/ */
async fanavaranSubmitParsianV2( async previewFanavaranSubmitV2(
claimCaseId: string, claimCaseId: string,
clientKey: FanavaranClientKey,
options?: { debug?: boolean }, options?: { debug?: boolean },
): Promise<any> { ): Promise<any> {
const profile = getFanavaranClientProfile(clientKey);
const logPrefix = `[Fanavaran ${clientKey} V2] claimCaseId=${claimCaseId}`;
try { try {
const debug = { const debug = {
clientKey,
claimCaseId, claimCaseId,
steps: { steps: {
claimCaseFound: false, claimCaseFound: false,
@@ -4022,7 +4014,8 @@ export class ClaimRequestManagementService {
const expertDecision = blameCase.expert?.decision; const expertDecision = blameCase.expert?.decision;
debug.steps.expertDecisionFound = !!expertDecision; debug.steps.expertDecisionFound = !!expertDecision;
const fallbackAccidentReason = claimCase.snapshot?.accident?.classification?.accidentReason; const fallbackAccidentReason =
claimCase.snapshot?.accident?.classification?.accidentReason;
if (!expertDecision?.fields?.accidentReason && fallbackAccidentReason) { if (!expertDecision?.fields?.accidentReason && fallbackAccidentReason) {
debug.steps.accidentReasonFallbackFromSnapshot = true; debug.steps.accidentReasonFallbackFromSnapshot = true;
} }
@@ -4051,8 +4044,8 @@ export class ClaimRequestManagementService {
createdAt: (blameCase as { createdAt?: Date }).createdAt, createdAt: (blameCase as { createdAt?: Date }).createdAt,
location: firstParty?.location, location: firstParty?.location,
damageParts, damageParts,
defaults: this.PARSIAN_FANAVARAN_DEFAULTS, defaults: profile.defaults,
logPrefix: `[Fanavaran Parsian V2] claimCaseId=${claimCaseId}`, logPrefix,
resolvePolicyId: async () => { resolvePolicyId: async () => {
const guiltyPartyId = this.resolveGuiltyPartyIdV2( const guiltyPartyId = this.resolveGuiltyPartyIdV2(
blameCase.parties ?? [], blameCase.parties ?? [],
@@ -4065,16 +4058,17 @@ export class ClaimRequestManagementService {
debug.values.guiltyPartyId = guiltyPartyId debug.values.guiltyPartyId = guiltyPartyId
? guiltyPartyId.toString() ? guiltyPartyId.toString()
: null; : null;
const nationalCodeOfInsurer = this.getNationalCodeOfInsurerForGuiltyPartyV2( const nationalCodeOfInsurer =
blameCase.parties ?? [], this.getNationalCodeOfInsurerForGuiltyPartyV2(
guiltyPartyId, blameCase.parties ?? [],
); guiltyPartyId,
);
debug.steps.nationalCodeOfInsurerFound = !!nationalCodeOfInsurer; debug.steps.nationalCodeOfInsurerFound = !!nationalCodeOfInsurer;
debug.values.nationalCodeOfInsurer = nationalCodeOfInsurer; debug.values.nationalCodeOfInsurer = nationalCodeOfInsurer;
if (!guiltyPartyId) { if (!guiltyPartyId) {
this.logger.warn( this.logger.warn(
`[Fanavaran Parsian V2] guiltyPartyId not found in expert.decision`, `${logPrefix} guiltyPartyId not found in expert.decision`,
); );
debug.failureReason = "expert.decision.guiltyPartyId is missing"; debug.failureReason = "expert.decision.guiltyPartyId is missing";
return null; return null;
@@ -4082,7 +4076,7 @@ export class ClaimRequestManagementService {
if (!nationalCodeOfInsurer) { if (!nationalCodeOfInsurer) {
this.logger.warn( this.logger.warn(
`[Fanavaran Parsian V2] nationalCodeOfInsurer not found for guiltyPartyId: ${guiltyPartyId}`, `${logPrefix} nationalCodeOfInsurer not found for guiltyPartyId: ${guiltyPartyId}`,
); );
debug.failureReason = debug.failureReason =
"nationalCodeOfInsurer not found for guilty party in blameCase.parties"; "nationalCodeOfInsurer not found for guilty party in blameCase.parties";
@@ -4092,8 +4086,8 @@ export class ClaimRequestManagementService {
debug.steps.policyInquiryAttempted = true; debug.steps.policyInquiryAttempted = true;
const policyId = await this.getPolicyIdFromNationalCode( const policyId = await this.getPolicyIdFromNationalCode(
nationalCodeOfInsurer, nationalCodeOfInsurer,
this.PARSIAN_FANAVARAN_CONFIG, profile.auth,
`[Fanavaran Parsian V2] claimCaseId=${claimCaseId}`, logPrefix,
); );
debug.values.policyId = policyId; debug.values.policyId = policyId;
debug.steps.policyInquirySucceeded = policyId !== null; debug.steps.policyInquirySucceeded = policyId !== null;
@@ -4108,6 +4102,7 @@ export class ClaimRequestManagementService {
if (options?.debug) { if (options?.debug) {
return { return {
clientKey,
payload, payload,
debug, debug,
}; };
@@ -4115,34 +4110,52 @@ export class ClaimRequestManagementService {
return payload; return payload;
} catch (error) { } catch (error) {
this.logger.error("Error in fanavaranSubmitParsianV2", error); this.logger.error(`Error in previewFanavaranSubmitV2 (${clientKey})`, error);
throw error; throw error;
} }
} }
/** @deprecated Use previewFanavaranSubmitV2(claimCaseId, "parsian", options) */
async fanavaranSubmitParsianV2(
claimCaseId: string,
options?: { debug?: boolean },
): Promise<any> {
return this.previewFanavaranSubmitV2(claimCaseId, "parsian", options);
}
/** /**
* Submit Parsian fanavaran data (V2 collections) to external API * Submit Fanavaran data (V2 claimCases + blameCases) for a specific client.
*/ */
async submitToFanavaranParsianV2(claimCaseId: string): Promise<any> { async submitFanavaranV2(
claimCaseId: string,
clientKey: FanavaranClientKey,
): Promise<any> {
try { try {
return await this.executeFanavaranParsianV2Submit(claimCaseId); return await this.executeFanavaranV2Submit(claimCaseId, clientKey);
} catch (error) { } catch (error) {
this.logger.error( this.logger.error(
`[Fanavaran Parsian V2] Error submitting to Fanavaran`, `[Fanavaran ${clientKey} V2] Error submitting to Fanavaran`,
error, error,
); );
throw new BadGatewayException(this.extractFanavaranErrorMessage(error)); throw new BadGatewayException(this.extractFanavaranErrorMessage(error));
} }
} }
/** @deprecated Use submitFanavaranV2(claimCaseId, "parsian") */
async submitToFanavaranParsianV2(claimCaseId: string): Promise<any> {
return this.submitFanavaranV2(claimCaseId, "parsian");
}
/** /**
* Auto-submit to Fanavaran when a claim case reaches COMPLETED. * Auto-submit to Fanavaran when a claim case reaches COMPLETED.
* Uses FANAVARAN_CLIENT env (or CLIENT_ID fallback) to pick the tenant.
* Never throws — failures are returned as warnings so the main flow continues. * Never throws — failures are returned as warnings so the main flow continues.
*/ */
async autoSubmitToFanavaranParsianV2OnClaimCompleted( async autoSubmitToFanavaranV2OnClaimCompleted(
claimCaseId: string, claimCaseId: string,
): Promise<FanavaranAutoSubmitResult> { ): Promise<FanavaranAutoSubmitResult> {
const logPrefix = `[Fanavaran Parsian V2 Auto] claimCaseId=${claimCaseId}`; const clientKey = resolveFanavaranClientKey();
const logPrefix = `[Fanavaran ${clientKey} V2 Auto] claimCaseId=${claimCaseId}`;
try { try {
const claimCase = await this.claimCaseDbService.findById(claimCaseId); const claimCase = await this.claimCaseDbService.findById(claimCaseId);
@@ -4166,8 +4179,9 @@ export class ClaimRequestManagementService {
}; };
} }
const fanavaranResponse = await this.executeFanavaranParsianV2Submit( const fanavaranResponse = await this.executeFanavaranV2Submit(
claimCaseId, claimCaseId,
clientKey,
); );
await this.claimCaseDbService.findByIdAndUpdate(claimCaseId, { await this.claimCaseDbService.findByIdAndUpdate(claimCaseId, {
@@ -4177,6 +4191,7 @@ export class ClaimRequestManagementService {
actor: { actorType: "system" }, actor: { actorType: "system" },
timestamp: new Date(), timestamp: new Date(),
metadata: { metadata: {
clientKey,
claimNo: fanavaranResponse?.ClaimNo, claimNo: fanavaranResponse?.ClaimNo,
claimId: fanavaranResponse?.Id, claimId: fanavaranResponse?.Id,
}, },
@@ -4202,7 +4217,7 @@ export class ClaimRequestManagementService {
type: "FANAVARAN_AUTO_SUBMIT_FAILED", type: "FANAVARAN_AUTO_SUBMIT_FAILED",
actor: { actorType: "system" }, actor: { actorType: "system" },
timestamp: new Date(), timestamp: new Date(),
metadata: { error: warning }, metadata: { clientKey, error: warning },
}, },
}, },
}); });
@@ -4216,11 +4231,18 @@ export class ClaimRequestManagementService {
return { return {
attempted: true, attempted: true,
submitted: false, submitted: false,
warning: `${warning} Case was not sent to Fanavaran. Retry manually via POST /v2/claim-request-management/fanavaran-submit/parsian/${claimCaseId}.`, warning: `${warning} Case was not sent to Fanavaran. Retry manually via POST ${fanavaranSubmitPath(clientKey, claimCaseId)}.`,
}; };
} }
} }
/** @deprecated Use autoSubmitToFanavaranV2OnClaimCompleted */
async autoSubmitToFanavaranParsianV2OnClaimCompleted(
claimCaseId: string,
): Promise<FanavaranAutoSubmitResult> {
return this.autoSubmitToFanavaranV2OnClaimCompleted(claimCaseId);
}
private extractFanavaranErrorMessage(error: unknown): string { private extractFanavaranErrorMessage(error: unknown): string {
if (isAxiosError(error)) { if (isAxiosError(error)) {
return ( return (
@@ -4247,16 +4269,20 @@ export class ClaimRequestManagementService {
return "Failed to submit data to Fanavaran API"; return "Failed to submit data to Fanavaran API";
} }
private async executeFanavaranParsianV2Submit( private async executeFanavaranV2Submit(
claimCaseId: string, claimCaseId: string,
clientKey: FanavaranClientKey,
): Promise<any> { ): Promise<any> {
const config = this.PARSIAN_FANAVARAN_CONFIG; const profile = getFanavaranClientProfile(clientKey);
const logPrefix = `[Fanavaran Parsian V2]`; const logPrefix = `[Fanavaran ${clientKey} V2]`;
this.logger.log( this.logger.log(
`${logPrefix} Starting submission for claimCaseId: ${claimCaseId}`, `${logPrefix} Starting submission for claimCaseId: ${claimCaseId}`,
); );
const fanavaranData = await this.fanavaranSubmitParsianV2(claimCaseId); const fanavaranData = await this.previewFanavaranSubmitV2(
claimCaseId,
clientKey,
);
this.logger.log( this.logger.log(
`${logPrefix} Mapped data prepared:`, `${logPrefix} Mapped data prepared:`,
JSON.stringify(fanavaranData, null, 2), JSON.stringify(fanavaranData, null, 2),
@@ -4275,16 +4301,16 @@ export class ClaimRequestManagementService {
); );
} }
const appToken = await this.getAppToken(config); const appToken = await this.getAppToken(profile.auth);
const authenticationToken = await this.login(appToken, config); const authenticationToken = await this.login(appToken, profile.auth);
const response = await firstValueFrom( const response = await firstValueFrom(
this.httpService.post(this.FANAVARAN_SUBMIT_URL, fanavaranData, { this.httpService.post(this.FANAVARAN_SUBMIT_URL, fanavaranData, {
headers: { headers: {
authenticationToken: authenticationToken, authenticationToken: authenticationToken,
CorpId: config.corpId, CorpId: profile.auth.corpId,
ContractId: config.contractId, ContractId: profile.auth.contractId,
Location: config.location, Location: profile.auth.location,
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}), }),
@@ -4319,6 +4345,13 @@ export class ClaimRequestManagementService {
return response.data; return response.data;
} }
/** @deprecated Use executeFanavaranV2Submit(claimCaseId, "parsian") */
private async executeFanavaranParsianV2Submit(
claimCaseId: string,
): Promise<any> {
return this.executeFanavaranV2Submit(claimCaseId, "parsian");
}
/** /**
* Submit fanavaran data to external API * Submit fanavaran data to external API
*/ */
@@ -7419,7 +7452,7 @@ export class ClaimRequestManagementService {
}); });
const fanavaran = const fanavaran =
await this.autoSubmitToFanavaranParsianV2OnClaimCompleted(claimRequestId); await this.autoSubmitToFanavaranV2OnClaimCompleted(claimRequestId);
let message = "Your signature has been recorded. The claim is completed."; let message = "Your signature has been recorded. The claim is completed.";
if (fanavaran.submitted) { if (fanavaran.submitted) {

View File

@@ -1030,43 +1030,4 @@ Returns status of each item (uploaded/captured or not).
} }
} }
@Get("fanavaran-submit/parsian/:claimCaseId")
@ApiOperation({
summary: "Preview Fanavaran submit body (Parsian / V2)",
description:
"Builds the third-party-car-financial-claims payload from claimCases + blameCases without calling Fanavaran.",
})
@ApiParam({
name: "claimCaseId",
description: "The claim case ID (MongoDB ObjectId)",
})
async fanavaranSubmitParsianV2(
@Param("claimCaseId") claimCaseId: string,
@Query("debug") debug?: string,
) {
return await this.claimRequestManagementService.fanavaranSubmitParsianV2(
claimCaseId,
{
debug: debug === "1" || debug === "true",
},
);
}
@Post("fanavaran-submit/parsian/:claimCaseId")
@ApiOperation({
summary: "Submit claim to Fanavaran (Parsian / V2)",
description:
"Authenticates with Parsian Fanavaran credentials and submits the mapped claimCases + blameCases payload.",
})
@ApiParam({
name: "claimCaseId",
description: "The claim case ID (MongoDB ObjectId)",
})
async submitToFanavaranParsianV2(
@Param("claimCaseId") claimCaseId: string,
) {
return await this.claimRequestManagementService.submitToFanavaranParsianV2(
claimCaseId,
);
}
} }

View File

@@ -1,5 +1,25 @@
export type FanavaranClientKey = "parsian" | "tejaratno"; export type FanavaranClientKey = "parsian" | "tejaratno";
export const FANAVARAN_CLIENT_KEYS: readonly FanavaranClientKey[] = [
"parsian",
"tejaratno",
] as const;
export function isFanavaranClientKey(value: string): value is FanavaranClientKey {
const normalized = value?.trim().toLowerCase();
return normalized === "parsian" || normalized === "tejaratno";
}
export function normalizeFanavaranClientKey(value: string): FanavaranClientKey {
const normalized = value?.trim().toLowerCase();
if (normalized === "parsian" || normalized === "tejaratno") {
return normalized;
}
throw new Error(
`Invalid Fanavaran client "${value}". Expected one of: ${FANAVARAN_CLIENT_KEYS.join(", ")}`,
);
}
export interface FanavaranAuthConfig { export interface FanavaranAuthConfig {
appName: string; appName: string;
secret: string; secret: string;
@@ -93,6 +113,30 @@ export function resolveFanavaranClientProfile(): FanavaranClientProfile {
return FANAVARAN_CLIENT_PROFILES[resolveFanavaranClientKey()]; return FANAVARAN_CLIENT_PROFILES[resolveFanavaranClientKey()];
} }
export function fanavaranManualSubmitPath(claimCaseId: string): string { export function getFanavaranClientProfile(
return `/v2/claim-request-management/fanavaran-submit/${claimCaseId}`; clientKey: FanavaranClientKey,
): FanavaranClientProfile {
return FANAVARAN_CLIENT_PROFILES[clientKey];
}
export function listFanavaranClientProfiles(): FanavaranClientProfile[] {
return FANAVARAN_CLIENT_KEYS.map((key) => FANAVARAN_CLIENT_PROFILES[key]);
}
export function fanavaranPreviewPath(
clientKey: FanavaranClientKey,
claimCaseId: string,
): string {
return `/v2/fanavaran/${clientKey}/claim-cases/${claimCaseId}`;
}
export function fanavaranSubmitPath(
clientKey: FanavaranClientKey,
claimCaseId: string,
): string {
return `/v2/fanavaran/${clientKey}/claim-cases/${claimCaseId}`;
}
export function fanavaranManualSubmitPath(claimCaseId: string): string {
return fanavaranSubmitPath(resolveFanavaranClientKey(), claimCaseId);
} }

View File

@@ -2364,7 +2364,7 @@ export class ExpertClaimService {
{ replyField }, { replyField },
); );
const fanavaran = const fanavaran =
await this.claimRequestManagementService.autoSubmitToFanavaranParsianV2OnClaimCompleted( await this.claimRequestManagementService.autoSubmitToFanavaranV2OnClaimCompleted(
claimRequestId, claimRequestId,
); );
return { return {
@@ -2390,7 +2390,7 @@ export class ExpertClaimService {
); );
const fanavaran = const fanavaran =
await this.claimRequestManagementService.autoSubmitToFanavaranParsianV2OnClaimCompleted( await this.claimRequestManagementService.autoSubmitToFanavaranV2OnClaimCompleted(
claimRequestId, claimRequestId,
); );

View File

@@ -0,0 +1,124 @@
import {
BadRequestException,
Controller,
Get,
Param,
Post,
Query,
UseGuards,
} from "@nestjs/common";
import {
ApiBearerAuth,
ApiOperation,
ApiParam,
ApiQuery,
ApiTags,
} from "@nestjs/swagger";
import { LocalActorAuthGuard } from "src/auth/guards/actor-local.guard";
import { RolesGuard } from "src/auth/guards/role.guard";
import { Roles } from "src/decorators/roles.decorator";
import { RoleEnum } from "src/Types&Enums/role.enum";
import { ClaimRequestManagementService } from "src/claim-request-management/claim-request-management.service";
import {
isFanavaranClientKey,
listFanavaranClientProfiles,
normalizeFanavaranClientKey,
resolveFanavaranClientKey,
} from "src/core/config/fanavaran-client.config";
@ApiTags("fanavaran")
@Controller("v2/fanavaran")
@ApiBearerAuth()
@UseGuards(LocalActorAuthGuard, RolesGuard)
@Roles(RoleEnum.ADMIN, RoleEnum.FIELD_EXPERT)
export class FanavaranController {
constructor(
private readonly claimRequestManagementService: ClaimRequestManagementService,
) {}
@Get("clients")
@ApiOperation({
summary: "List supported Fanavaran insurance clients",
description:
"Returns configured Fanavaran tenants (parsian, tejaratno) and which client is active for this deployment.",
})
listClients() {
const activeClient = resolveFanavaranClientKey();
return {
activeClient,
clients: listFanavaranClientProfiles().map((profile) => ({
key: profile.key,
defaults: profile.defaults,
isActive: profile.key === activeClient,
})),
};
}
@Get(":client/claim-cases/:claimCaseId")
@ApiOperation({
summary: "Preview Fanavaran submit payload (V2)",
description:
"Builds the third-party-car-financial-claims body from claimCases + blameCases without calling Fanavaran.",
})
@ApiParam({
name: "client",
description: "Fanavaran tenant key",
enum: ["parsian", "tejaratno"],
})
@ApiParam({
name: "claimCaseId",
description: "Claim case MongoDB ObjectId",
})
@ApiQuery({
name: "debug",
required: false,
description: "When true, returns payload plus mapping debug steps",
})
async preview(
@Param("client") client: string,
@Param("claimCaseId") claimCaseId: string,
@Query("debug") debug?: string,
) {
const clientKey = this.parseClientParam(client);
return await this.claimRequestManagementService.previewFanavaranSubmitV2(
claimCaseId,
clientKey,
{ debug: debug === "1" || debug === "true" },
);
}
@Post(":client/claim-cases/:claimCaseId")
@ApiOperation({
summary: "Submit claim to Fanavaran (V2)",
description:
"Authenticates with the selected client credentials and submits the mapped claimCases + blameCases payload.",
})
@ApiParam({
name: "client",
description: "Fanavaran tenant key",
enum: ["parsian", "tejaratno"],
})
@ApiParam({
name: "claimCaseId",
description: "Claim case MongoDB ObjectId",
})
async submit(
@Param("client") client: string,
@Param("claimCaseId") claimCaseId: string,
) {
const clientKey = this.parseClientParam(client);
return await this.claimRequestManagementService.submitFanavaranV2(
claimCaseId,
clientKey,
);
}
private parseClientParam(client: string) {
if (!isFanavaranClientKey(client)) {
throw new BadRequestException(
`Invalid Fanavaran client "${client}". Expected one of: parsian, tejaratno`,
);
}
return normalizeFanavaranClientKey(client);
}
}

View File

@@ -0,0 +1,9 @@
import { Module } from "@nestjs/common";
import { ClaimRequestManagementModule } from "src/claim-request-management/claim-request-management.module";
import { FanavaranController } from "./fanavaran.controller";
@Module({
imports: [ClaimRequestManagementModule],
controllers: [FanavaranController],
})
export class FanavaranModule {}