forked from Yara724/api
Merge pull request 'Fixed FileMaker and FileReviewer access to COMPLETED files' (#283) from s.yahyaee/yara724-api:main into main
Reviewed-on: Yara724/api#283
This commit is contained in:
59
src/claim-request-management/claim-details-access.v2.spec.ts
Normal file
59
src/claim-request-management/claim-details-access.v2.spec.ts
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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) {
|
if (actor?.role === RoleEnum.REGISTRAR && claim.blameRequestId) {
|
||||||
const blame = await this.blameRequestDbService.findById(
|
const blame = await this.blameRequestDbService.findById(
|
||||||
claim.blameRequestId.toString(),
|
claim.blameRequestId.toString(),
|
||||||
@@ -11059,6 +11090,14 @@ export class ClaimRequestManagementService {
|
|||||||
carAngles,
|
carAngles,
|
||||||
damagedParts,
|
damagedParts,
|
||||||
expertResend,
|
expertResend,
|
||||||
|
fanavaran:
|
||||||
|
claim.status === ClaimCaseStatus.COMPLETED &&
|
||||||
|
(claim.claimNo != null || claim.claimId != null)
|
||||||
|
? {
|
||||||
|
claimNo: claim.claimNo,
|
||||||
|
claimId: claim.claimId,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
evaluation: mappedEvaluation
|
evaluation: mappedEvaluation
|
||||||
? {
|
? {
|
||||||
damageExpertReply: mappedEvaluation.damageExpertReply,
|
damageExpertReply: mappedEvaluation.damageExpertReply,
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ export class ClaimRequestManagementV2Controller {
|
|||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Get Claim Details (V2)",
|
summary: "Get Claim Details (V2)",
|
||||||
description:
|
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({
|
@ApiResponse({
|
||||||
status: 200,
|
status: 200,
|
||||||
|
|||||||
@@ -210,6 +210,16 @@ export class ClaimDetailsV2ResponseDto {
|
|||||||
})
|
})
|
||||||
expertResend?: ExpertResendDetailsV2Dto;
|
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({
|
@ApiPropertyOptional({
|
||||||
description: "Damage expert opinion(s): initial and final (after objection).",
|
description: "Damage expert opinion(s): initial and final (after objection).",
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -163,6 +163,16 @@ export class ClaimDetailV2ResponseDto {
|
|||||||
})
|
})
|
||||||
fileMakerApprovalActorId?: string;
|
fileMakerApprovalActorId?: string;
|
||||||
|
|
||||||
|
@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({
|
@ApiPropertyOptional({
|
||||||
description:
|
description:
|
||||||
"Slice of `claim.evaluation` exposed to the damage expert. " +
|
"Slice of `claim.evaluation` exposed to the damage expert. " +
|
||||||
|
|||||||
@@ -5141,6 +5141,14 @@ export class ExpertClaimService {
|
|||||||
fileMakerApprovalActorId: (claim as any).fileMakerApprovalActorId
|
fileMakerApprovalActorId: (claim as any).fileMakerApprovalActorId
|
||||||
? String((claim as any).fileMakerApprovalActorId)
|
? String((claim as any).fileMakerApprovalActorId)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
fanavaran:
|
||||||
|
claim.status === ClaimCaseStatus.COMPLETED &&
|
||||||
|
(claim.claimNo != null || claim.claimId != null)
|
||||||
|
? {
|
||||||
|
claimNo: claim.claimNo,
|
||||||
|
claimId: claim.claimId,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
evaluation:
|
evaluation:
|
||||||
(evaluationForApi as
|
(evaluationForApi as
|
||||||
| ClaimDetailV2ResponseDto["evaluation"]
|
| ClaimDetailV2ResponseDto["evaluation"]
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ export class ExpertClaimV2Controller {
|
|||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Get claim request detail for damage expert",
|
summary: "Get claim request detail for damage expert",
|
||||||
description:
|
description:
|
||||||
"Returns full claim details including captured images, required documents, damage selections, `evaluation.priceDrop` (included whenever saved, regardless of current status), `videoCapture` (from claim-video-capture via media.videoCaptureId), and `blameCase` (linked blameCases document with party video/voice URLs like expert-blame detail). `evaluation.damageExpertReply` / `damageExpertReplyFinal` are always returned once submitted. Allowed when status is WAITING_FOR_DAMAGE_EXPERT (if locked, only the locking expert) or when awaiting factor validation.",
|
"Returns full claim details including captured images, required documents, damage selections, `evaluation.priceDrop` (included whenever saved, regardless of current status), `videoCapture` (from claim-video-capture via media.videoCaptureId), and `blameCase` (linked blameCases document with party video/voice URLs like expert-blame detail). `evaluation.damageExpertReply` / `damageExpertReplyFinal` are always returned once submitted. Completed claims include Fanavaran `claimNo` / `claimId` when available. Allowed when status is WAITING_FOR_DAMAGE_EXPERT (if locked, only the locking expert) or when awaiting factor validation.",
|
||||||
})
|
})
|
||||||
@ApiParam({ name: "claimRequestId" })
|
@ApiParam({ name: "claimRequestId" })
|
||||||
async getClaimDetailV2(
|
async getClaimDetailV2(
|
||||||
|
|||||||
Reference in New Issue
Block a user