Fixed FileMaker and FileReviewer access to COMPLETED files

This commit is contained in:
2026-09-01 21:54:04 +03:30
parent ae49031c55
commit cf74d75146
7 changed files with 128 additions and 2 deletions

View File

@@ -0,0 +1,59 @@
import { ForbiddenException } from "@nestjs/common";
import { ClaimRequestManagementService } from "./claim-request-management.service";
import { RoleEnum } from "src/Types&Enums/role.enum";
describe("V2 claim-detail access for split file roles", () => {
const makerId = "maker-id";
const reviewerId = "reviewer-id";
const createService = (blame: Record<string, unknown>) => {
const service = Object.create(
ClaimRequestManagementService.prototype,
) as ClaimRequestManagementService;
(service as any).blameRequestDbService = {
findById: jest.fn().mockResolvedValue(blame),
};
return service;
};
const claim = { blameRequestId: "blame-id" };
it("allows the FileMaker who created a completed V4/V5 file", async () => {
const service = createService({
isMadeByFileMaker: true,
expertInitiated: true,
creationMethod: "IN_PERSON",
initiatedByFieldExpertId: makerId,
});
await expect(
(service as any).assertActorCanViewClaimV2(claim, makerId, {
sub: makerId,
role: RoleEnum.FILE_MAKER,
}),
).resolves.toBeUndefined();
});
it("allows only the assigned FileReviewer", async () => {
const service = createService({
isMadeByFileMaker: true,
expertInitiated: true,
creationMethod: "IN_PERSON",
assignedFileReviewerId: reviewerId,
});
await expect(
(service as any).assertActorCanViewClaimV2(claim, reviewerId, {
sub: reviewerId,
role: RoleEnum.FILE_REVIEWER,
}),
).resolves.toBeUndefined();
await expect(
(service as any).assertActorCanViewClaimV2(claim, "other-reviewer", {
sub: "other-reviewer",
role: RoleEnum.FILE_REVIEWER,
}),
).rejects.toBeInstanceOf(ForbiddenException);
});
});

View File

@@ -8005,6 +8005,37 @@ export class ClaimRequestManagementService {
}
}
if (
(actor?.role === RoleEnum.FILE_MAKER ||
actor?.role === RoleEnum.FILE_REVIEWER) &&
claim.blameRequestId
) {
const blame = await this.blameRequestDbService.findById(
claim.blameRequestId.toString(),
);
const isV4OrV5File =
!!(blame as any)?.isMadeByFileMaker &&
blame?.expertInitiated &&
blame?.creationMethod === "IN_PERSON";
if (
actor.role === RoleEnum.FILE_MAKER &&
isV4OrV5File &&
claimCaseInitiatedByFieldExpert(claim, { sub: currentUserId }, blame)
) {
return;
}
if (
actor.role === RoleEnum.FILE_REVIEWER &&
isV4OrV5File &&
String((blame as any)?.assignedFileReviewerId ?? "") ===
String(currentUserId)
) {
return;
}
}
if (actor?.role === RoleEnum.REGISTRAR && claim.blameRequestId) {
const blame = await this.blameRequestDbService.findById(
claim.blameRequestId.toString(),
@@ -11059,6 +11090,14 @@ export class ClaimRequestManagementService {
carAngles,
damagedParts,
expertResend,
fanavaran:
claim.status === ClaimCaseStatus.COMPLETED &&
(claim.claimNo != null || claim.claimId != null)
? {
claimNo: claim.claimNo,
claimId: claim.claimId,
}
: undefined,
evaluation: mappedEvaluation
? {
damageExpertReply: mappedEvaluation.damageExpertReply,

View File

@@ -117,7 +117,7 @@ export class ClaimRequestManagementV2Controller {
@ApiOperation({
summary: "Get Claim Details (V2)",
description:
"Returns the claim snapshot for **USER** (owner), **FIELD_EXPERT**, or **REGISTRAR** when permitted. Initiating experts/registrars see unmasked money fields; owners get `ownerGuidance`.",
"Returns the claim snapshot for an authorized **USER**, **FIELD_EXPERT**, **REGISTRAR**, **FILE_MAKER**, or assigned **FILE_REVIEWER**. Initiating experts/registrars see unmasked money fields; owners get `ownerGuidance`. Completed claims include Fanavaran `claimNo` / `claimId` when available.",
})
@ApiResponse({
status: 200,

View File

@@ -210,6 +210,16 @@ export class ClaimDetailsV2ResponseDto {
})
expertResend?: ExpertResendDetailsV2Dto;
@ApiPropertyOptional({
description:
'Fanavaran claim reference. Returned only after the local claim reaches COMPLETED and Fanavaran has supplied at least one reference.',
example: { claimNo: 123456, claimId: 987654 },
})
fanavaran?: {
claimNo?: number;
claimId?: number;
};
@ApiPropertyOptional({
description: "Damage expert opinion(s): initial and final (after objection).",
type: Object,