1
0
forked from Yara724/api

YARA-1117 and fixed completed status after in person visit has been called

This commit is contained in:
SepehrYahyaee
2026-07-14 11:51:52 +03:30
parent 4aa6e03afb
commit 168e52a475
6 changed files with 92 additions and 54 deletions

View File

@@ -364,7 +364,6 @@ export class FileReviewerBlameV4Controller {
@ApiBody({
schema: {
type: "object",
required: ["file"],
properties: { file: { type: "string", format: "binary" } },
},
})
@@ -385,17 +384,19 @@ export class FileReviewerBlameV4Controller {
@Post("upload-video/:requestId")
@ApiParam({ name: "requestId" })
@ApiOperation({
summary: "Blame accident video (FileReviewer final step)",
summary: "Blame accident video (FileReviewer final step — optional)",
description:
"Last step of the V4 flow. Requires claim walk-around video and completed capture. " +
"Sets blame status to WAITING_FOR_EXPERT.",
"File is optional — omit it to complete the blame without attaching a video.",
})
async uploadBlameVideo(
@Param("requestId") requestId: string,
@CurrentUser() fileReviewer: any,
@UploadedFile() file: Express.Multer.File,
) {
await this.mediaPolicyService.assertForBlame(file, requestId, "video");
if (file) {
await this.mediaPolicyService.assertForBlame(file, requestId, "video");
}
return this.requestManagementService.expertUploadBlameVideoV3(
fileReviewer,
requestId,

View File

@@ -365,7 +365,6 @@ export class FileReviewerBlameV5Controller {
@ApiBody({
schema: {
type: "object",
required: ["file"],
properties: { file: { type: "string", format: "binary" } },
},
})
@@ -386,17 +385,19 @@ export class FileReviewerBlameV5Controller {
@Post("upload-video/:requestId")
@ApiParam({ name: "requestId" })
@ApiOperation({
summary: "Blame accident video (FileReviewer final step — V5)",
summary: "Blame accident video (FileReviewer final step — V5, optional)",
description:
"Last step of the V5 FileReviewer flow. Requires claim walk-around video and completed capture. " +
"Sets blame status to WAITING_FOR_FINANCIAL_EXPERT (pending FinancialExpert approval).",
"File is optional — omit it to complete the blame without attaching a video.",
})
async uploadBlameVideo(
@Param("requestId") requestId: string,
@CurrentUser() fileReviewer: any,
@UploadedFile() file: Express.Multer.File,
) {
await this.mediaPolicyService.assertForBlame(file, requestId, "video");
if (file) {
await this.mediaPolicyService.assertForBlame(file, requestId, "video");
}
return this.requestManagementService.expertUploadBlameVideoV5(
fileReviewer,
requestId,

View File

@@ -9325,21 +9325,31 @@ export class RequestManagementService {
async expertUploadBlameVideoV3(
expert: any,
requestId: string,
file: Express.Multer.File,
file: Express.Multer.File | undefined,
): Promise<{
requestId: string;
publicId: string;
videoId: string;
videoId: string | undefined;
status: string;
message: string;
}> {
if (!file) throw new BadRequestException("Video file is required");
const req = await this.blameRequestDbService.findById(requestId);
if (!req) throw new NotFoundException("Request not found");
this.assertBlameV3ExpertInPerson(req);
await this.verifyExpertAccessForBlameV2(req, expert);
// Idempotent: if blame is already completed (car-capture auto-completed it
// for V4/V5, or a previous call already ran), return success immediately.
if ((req as any).status === CaseStatus.COMPLETED) {
return {
requestId: String(req._id),
publicId: req.publicId,
videoId: undefined,
status: (req as any).status,
message: "File already completed.",
};
}
if (!(req.expert?.decision as any)?.fields?.accidentWay) {
throw new BadRequestException(
"Submit accident fields before uploading the blame accident video.",
@@ -9381,19 +9391,23 @@ export class RequestManagementService {
const firstIdx = this.getPartyIndex(req, PartyRole.FIRST);
if (firstIdx === -1) throw new BadRequestException("First party not found");
const firstParty = req.parties[firstIdx];
if (firstParty?.evidence?.videoId) {
throw new ConflictException("Blame accident video already uploaded");
// Store video if provided; skip silently for V4/V5 where it is optional.
let videoId: string | undefined;
if (file) {
if (firstParty?.evidence?.videoId) {
throw new ConflictException("Blame accident video already uploaded");
}
const videoDocument = await this.blameVideoDbService.create({
fileName: file.filename,
path: file.path,
requestId: new Types.ObjectId(requestId),
} as any);
if (!firstParty.evidence) firstParty.evidence = {} as any;
firstParty.evidence.videoId = String((videoDocument as any)._id);
videoId = firstParty.evidence.videoId;
}
const videoDocument = await this.blameVideoDbService.create({
fileName: file.filename,
path: file.path,
requestId: new Types.ObjectId(requestId),
} as any);
if (!firstParty.evidence) firstParty.evidence = {} as any;
firstParty.evidence.videoId = String((videoDocument as any)._id);
this.pushWorkflowSteps(req, [
WorkflowStep.FIRST_VIDEO,
WorkflowStep.WAITING_FOR_GUILT_DECISION,
@@ -9410,7 +9424,7 @@ export class RequestManagementService {
actorName: `${expert.firstName || ""} ${expert.lastName || ""}`.trim(),
actorType: "field_expert",
},
metadata: { videoId: firstParty.evidence.videoId },
metadata: { videoId: videoId ?? null },
} as any);
if (typeof (req as any).markModified === "function") {
@@ -9449,10 +9463,11 @@ export class RequestManagementService {
return {
requestId: String(req._id),
publicId: req.publicId,
videoId: firstParty.evidence.videoId,
videoId,
status: req.status,
message:
"Blame accident video uploaded. File is now waiting for expert review.",
message: file
? "Blame accident video uploaded. File is now waiting for expert review."
: "File completed. Claim is now ready for damage expert review.",
};
}
@@ -9694,21 +9709,31 @@ export class RequestManagementService {
async expertUploadBlameVideoV5(
expert: any,
requestId: string,
file: Express.Multer.File,
file: Express.Multer.File | undefined,
): Promise<{
requestId: string;
publicId: string;
videoId: string;
videoId: string | undefined;
status: string;
message: string;
}> {
if (!file) throw new BadRequestException("Video file is required");
const req = await this.blameRequestDbService.findById(requestId);
if (!req) throw new NotFoundException("Request not found");
this.assertBlameV3ExpertInPerson(req);
await this.verifyExpertAccessForBlameV2(req, expert);
// Idempotent: blame already completed (car-capture auto-completed it for
// V4/V5, or a previous call already ran).
if ((req as any).status === CaseStatus.COMPLETED) {
return {
requestId: String(req._id),
publicId: req.publicId,
videoId: undefined,
status: (req as any).status,
message: "File already completed.",
};
}
if (!(req.expert?.decision as any)?.fields?.accidentWay) {
throw new BadRequestException(
"Submit accident fields before uploading the blame accident video.",
@@ -9750,19 +9775,23 @@ export class RequestManagementService {
const firstIdx = this.getPartyIndex(req, PartyRole.FIRST);
if (firstIdx === -1) throw new BadRequestException("First party not found");
const firstParty = req.parties[firstIdx];
if (firstParty?.evidence?.videoId) {
throw new ConflictException("Blame accident video already uploaded");
// Store video if provided; skip silently for V4/V5 where it is optional.
let videoId: string | undefined;
if (file) {
if (firstParty?.evidence?.videoId) {
throw new ConflictException("Blame accident video already uploaded");
}
const videoDocument = await this.blameVideoDbService.create({
fileName: file.filename,
path: file.path,
requestId: new Types.ObjectId(requestId),
} as any);
if (!firstParty.evidence) firstParty.evidence = {} as any;
firstParty.evidence.videoId = String((videoDocument as any)._id);
videoId = firstParty.evidence.videoId;
}
const videoDocument = await this.blameVideoDbService.create({
fileName: file.filename,
path: file.path,
requestId: new Types.ObjectId(requestId),
} as any);
if (!firstParty.evidence) firstParty.evidence = {} as any;
firstParty.evidence.videoId = String((videoDocument as any)._id);
this.pushWorkflowSteps(req, [
WorkflowStep.FIRST_VIDEO,
WorkflowStep.WAITING_FOR_GUILT_DECISION,
@@ -9779,7 +9808,7 @@ export class RequestManagementService {
actorName: `${expert.firstName || ""} ${expert.lastName || ""}`.trim(),
actorType: "file_reviewer",
},
metadata: { videoId: firstParty.evidence.videoId },
metadata: { videoId: videoId ?? null },
} as any);
if (typeof (req as any).markModified === "function") {
@@ -9825,11 +9854,11 @@ export class RequestManagementService {
return {
requestId: String(req._id),
publicId: req.publicId,
videoId: firstParty.evidence.videoId,
videoId,
status: req.status,
message:
"Blame accident video uploaded. File is now in expert review queue. " +
"After the full claim flow completes and the owner signs, the FileMaker must approve before fanavaran submission.",
message: file
? "Blame accident video uploaded. File is now in expert review queue. After the full claim flow completes and the owner signs, the FileMaker must approve before fanavaran submission."
: "File completed. Claim is now ready for damage expert review.",
};
}