Use FileMaker and FileReviewer Fanavaran expert ids on V4/V5 flows.

Block file create and review when the matching third-party or car-body code is missing, and override GEN.03/GEN.06 ClaimExpertId from those profiles instead of tenant defaults.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-16 16:26:58 +03:30
parent acb5d2a682
commit ebfb4385de
4 changed files with 270 additions and 9 deletions

View File

@@ -141,6 +141,13 @@ import { PublicIdService } from "src/utils/public-id/public-id.service";
import { ImageRequiredModel } from "./entites/schema/image-required.schema";
import { DamageExpertDbService } from "src/users/entities/db-service/damage-expert.db.service";
import { FileMakerDbService } from "src/users/entities/db-service/file-maker.db.service";
import { FileReviewerDbService } from "src/users/entities/db-service/file-reviewer.db.service";
import {
assertFileMakerCanCreateBlameType,
assertFileReviewerCanReviewBlameType,
resolveFileMakerStageOneExpertId,
resolveFileReviewerExpertiseExpertId,
} from "src/fanavaran/fanavaran-file-role-expert-ids";
import { FieldExpertDbService } from "src/users/entities/db-service/field-expert.db.service";
import { FanavaranLocationService } from "src/fanavaran/fanavaran-location.service";
import { ExpertFileActivityDbService } from "src/users/entities/db-service/expert-file-activity.db.service";
@@ -474,6 +481,7 @@ export class ClaimRequestManagementService {
private readonly fanavaranLookupService: FanavaranLookupService,
private readonly smsOrchestrationService: SmsOrchestrationService,
private readonly fileMakerDbService: FileMakerDbService,
private readonly fileReviewerDbService: FileReviewerDbService,
private readonly fieldExpertDbService: FieldExpertDbService,
private readonly plateNormalizer: PlateNormalizerService,
private readonly fanavaranLocationService: FanavaranLocationService,
@@ -5179,6 +5187,55 @@ export class ClaimRequestManagementService {
}
}
/**
* V4/V5 FileMaker flows: GEN.03 ClaimExpertId from file-maker; GEN.06 from file-reviewer.
* Returns null for non–file-maker blames (tenant defaults apply).
*/
private async resolveFanavaranFileRoleExpertIdsForBlame(blame: {
isMadeByFileMaker?: boolean;
type?: BlameRequestType;
initiatedByFieldExpertId?: unknown;
assignedFileReviewerId?: unknown;
}): Promise<{
baseClaimExpertId: number | null;
expertiseClaimExpertId: number | null;
} | null> {
if (!blame?.isMadeByFileMaker || blame.type == null) {
return null;
}
let baseClaimExpertId: number | null = null;
let expertiseClaimExpertId: number | null = null;
if (blame.initiatedByFieldExpertId) {
const fileMaker = await this.fileMakerDbService.findById(
String(blame.initiatedByFieldExpertId),
);
if (fileMaker) {
assertFileMakerCanCreateBlameType(fileMaker, blame.type);
baseClaimExpertId = resolveFileMakerStageOneExpertId(
fileMaker,
blame.type,
);
}
}
if (blame.assignedFileReviewerId) {
const fileReviewer = await this.fileReviewerDbService.findById(
String(blame.assignedFileReviewerId),
);
if (fileReviewer) {
assertFileReviewerCanReviewBlameType(fileReviewer, blame.type);
expertiseClaimExpertId = resolveFileReviewerExpertiseExpertId(
fileReviewer,
blame.type,
);
}
}
return { baseClaimExpertId, expertiseClaimExpertId };
}
private async getPolicyIdFromNationalCode(
nationalCodeOfInsurer: string,
config: {
@@ -6075,6 +6132,19 @@ export class ClaimRequestManagementService {
Object.assign(payload, hull);
}
const fileRoleExpertIds =
await this.resolveFanavaranFileRoleExpertIdsForBlame(blameCase);
if (fileRoleExpertIds) {
if (fileRoleExpertIds.baseClaimExpertId == null) {
throw new BadRequestException({
code: "FILE_MAKER_FANAVARAN_EXPERT_CODE_MISSING",
message:
"This FileMaker file cannot be submitted to Fanavaran: stage-1 claim expert id is missing for this product line.",
});
}
payload.ClaimExpertId = fileRoleExpertIds.baseClaimExpertId;
}
if (persistPayload) {
await this.claimCaseDbService.findByIdAndUpdate(claimCaseId, {
$set: {
@@ -7048,10 +7118,35 @@ export class ClaimRequestManagementService {
const profile = getFanavaranClientProfile(input.clientKey);
const active = getActiveV2ExpertReply(input.claimCase as any);
// GEN.08 ClaimExpertId = tenant ExpertiseClaimExpertId (assessor role).
// Tejaratno: 2709. Parsian: 29. Must NOT reuse GEN.03 ClaimExpertId
// (مسئول پرونده مالی — Tejaratno 4543092 / Parsian 154).
const claimExpertId = profile.defaults.ExpertiseClaimExpertId;
const blameForExpertIds = input.claimCase?.blameRequestId
? await this.blameRequestDbService.findById(
String(input.claimCase.blameRequestId),
)
: null;
// GEN.06 ClaimExpertId = tenant ExpertiseClaimExpertId (assessor role), unless
// V4/V5 FileMaker flow → file-reviewer expertise code for this product line.
let claimExpertId = profile.defaults.ExpertiseClaimExpertId;
if (blameForExpertIds) {
const roleExpertIds =
await this.resolveFanavaranFileRoleExpertIdsForBlame(
blameForExpertIds as {
isMadeByFileMaker?: boolean;
type?: BlameRequestType;
initiatedByFieldExpertId?: unknown;
assignedFileReviewerId?: unknown;
},
);
if (roleExpertIds?.expertiseClaimExpertId != null) {
claimExpertId = roleExpertIds.expertiseClaimExpertId;
} else if (roleExpertIds) {
throw new BadRequestException({
code: "FILE_REVIEWER_FANAVARAN_EXPERT_CODE_MISSING",
message:
"Fanavaran expertise cannot be submitted: assign a FileReviewer with an expertise claim expert id for this product line.",
});
}
}
const warnings: string[] = [];
if (!active?.parts?.length) {
@@ -7106,11 +7201,7 @@ export class ClaimRequestManagementService {
);
if (product === "car-body") {
const blame = input.claimCase?.blameRequestId
? await this.blameRequestDbService.findById(
String(input.claimCase.blameRequestId),
)
: null;
const blame = blameForExpertIds;
return this.buildCarBodyFanavaranExpertisePayload({
clientKey: input.clientKey,
claimCase: input.claimCase,