import { BadRequestException, Body, Controller, Get, Param, Post, Query, UseGuards, } from "@nestjs/common"; import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiQuery, ApiTags, } from "@nestjs/swagger"; import { LocalActorAuthGuard } from "src/auth/guards/actor-local.guard"; import { ClaimRequestManagementService } from "src/claim-request-management/claim-request-management.service"; import { FANAVARAN_CLIENT_KEYS, FANAVARAN_CLIENT_SWAGGER_ENUM, isFanavaranClientKey, listFanavaranClientProfiles, normalizeFanavaranClientKey, resolveFanavaranClientKey, } from "src/core/config/fanavaran-client.config"; @ApiTags("fanavaran") @Controller("v2/fanavaran") @ApiBearerAuth() @UseGuards(LocalActorAuthGuard) export class FanavaranController { constructor( private readonly claimRequestManagementService: ClaimRequestManagementService, ) {} @Get("clients") @ApiOperation({ summary: "List supported Fanavaran insurance clients", description: "Returns configured Fanavaran tenants (parsian, tejaratno, moallem) 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/base-claim/preview") @ApiOperation({ summary: "Preview Fanavaran base claim create payload", description: "GET has no request body. Always rebuilds GEN.03 from live policy + VIN/vehicle inquiries. Does not reuse fanavaranSync lastPayload / PolicyId / UsedId cache. Auth token is still shared until Asia/Tehran midnight.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) @ApiQuery({ name: "debug", required: false, description: "When true, returns payload plus mapping debug steps", }) @ApiQuery({ name: "forceRefreshPolicy", required: false, deprecated: true, description: "Ignored. Preview always re-inquires PolicyId.", }) @ApiQuery({ name: "resolvePolicy", required: false, deprecated: true, description: "Ignored. Preview always re-inquires PolicyId.", }) async preview( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, @Query("debug") debug?: string, @Query("forceRefreshPolicy") _forceRefreshPolicy?: string, @Query("resolvePolicy") _resolvePolicy?: string, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.previewFanavaranSubmitV2( claimCaseId, clientKey, { debug: debug === "1" || debug === "true", forceRefreshPolicy: true, forceRefreshUsedId: true, requirePolicyId: false, }, ); } @Post(":client/claim-cases/:claimCaseId/base-claim/submit") @ApiOperation({ summary: "Submit Fanavaran base claim create request", description: "Swagger JSON body is optional. Always rebuilds GEN.03 from live inquiries, then POSTs that rebuilt payload. Pasting a previous preview JSON does not skip inquiry. Only user-entry keys are applied from the body (EstimateAmount, licence, dates, address, police report). PolicyId and AccidentVehicleUsedId in pasted JSON are ignored.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) @ApiBody({ required: false, description: "Optional. Paste previous preview JSON if you want to tweak user-entry fields. Lookup ids in that JSON are ignored.", schema: { type: "object", additionalProperties: true, example: {} }, }) async submit( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, @Body() body?: Record, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.submitFanavaranV2( claimCaseId, clientKey, body && Object.keys(body).length > 0 ? body : undefined, ); } @Get(":client/claim-cases/:claimCaseId/damage-case/preview") @ApiOperation({ summary: "Preview Fanavaran damage-case payload", description: "GET has no request body. Always rebuilds GEN.12 from live VIN/vehicle/driver inquiries. Does not reuse lastPayload / plaqueKindId / DriverId cache.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) async previewDamageCase( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.previewFanavaranDamageCaseV2( claimCaseId, clientKey, ); } @Post(":client/claim-cases/:claimCaseId/damage-case/submit") @ApiOperation({ summary: "Submit Fanavaran damage-case request", description: "Swagger JSON body is optional. Always rebuilds GEN.12 from live VIN/vehicle/driver inquiries, then POSTs that rebuilt payload. Pasting a previous preview JSON does not skip inquiry. Only Desc, EstimateAmount, LicenceNo, LicenceIssuDate, DriverIsOwner are taken from the body. PlaqueKindId, PlaqueSampleId, VehicleKindId, DriverId, InsuranceCorpId in pasted JSON are ignored.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) @ApiBody({ required: false, description: "Optional. Paste previous preview JSON if you want to tweak Desc / licence / estimate. Lookup-filter ids in that JSON are ignored.", schema: { type: "object", additionalProperties: true, example: {} }, }) async submitDamageCase( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, @Body() body?: Record, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.submitFanavaranDamageCaseV2( claimCaseId, clientKey, body && Object.keys(body).length > 0 ? body : undefined, ); } @Get(":client/claim-cases/:claimCaseId/attachments/preview") @ApiOperation({ summary: "Preview Fanavaran attachment upload plan", description: "Lists local required-document and captured damage images that would be sent to GEN.07. Shows which images are already recorded as uploaded to Fanavaran.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) async previewAttachments( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.previewFanavaranAttachmentsV2( claimCaseId, clientKey, ); } @Post(":client/claim-cases/:claimCaseId/attachments/submit") @ApiOperation({ summary: "Submit missing Fanavaran attachments", description: "Uploads every local image that does not already have a recorded successful GEN.07 Fanavaran file upload. Uses one multipart request per image.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) async submitAttachments( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.submitFanavaranAttachmentsV2( claimCaseId, clientKey, ); } @Get(":client/claim-cases/:claimCaseId/expertise/preview") @ApiOperation({ summary: "Preview Fanavaran expertise payload", description: "GET has no request body. Rebuilds GEN.08 from the active expert reply and lookups on every call. Does not reuse lastPayload cache.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) async previewExpertise( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.previewFanavaranExpertiseV2( claimCaseId, clientKey, ); } @Post(":client/claim-cases/:claimCaseId/expertise/submit") @ApiOperation({ summary: "Submit Fanavaran expertise request", description: "Swagger JSON body is optional. Always rebuilds GEN.08 from the local expert reply and lookups, then POSTs that rebuilt payload. Pasting a previous preview JSON does not skip rebuild. Only money/date fields are taken from the body. DmgCaseId, ClaimExpertId, and DmgSections in pasted JSON are ignored.", }) @ApiParam({ name: "client", description: "Fanavaran tenant key", enum: FANAVARAN_CLIENT_SWAGGER_ENUM, }) @ApiParam({ name: "claimCaseId", description: "Claim case MongoDB ObjectId", }) @ApiBody({ required: false, description: "Optional. Paste previous preview JSON if you want to tweak money/date fields. DmgCaseId / ClaimExpertId / DmgSections in that JSON are ignored.", schema: { type: "object", additionalProperties: true, example: {} }, }) async submitExpertise( @Param("client") client: string, @Param("claimCaseId") claimCaseId: string, @Body() body?: Record, ) { const clientKey = this.parseClientParam(client); return await this.claimRequestManagementService.submitFanavaranExpertiseV2( claimCaseId, clientKey, body && Object.keys(body).length > 0 ? body : undefined, ); } private parseClientParam(client: string) { if (!isFanavaranClientKey(client)) { throw new BadRequestException( `Invalid Fanavaran client "${client}". Expected one of: ${FANAVARAN_CLIENT_KEYS.join(", ")}`, ); } return normalizeFanavaranClientKey(client); } }