From 637cbb20d5de15401c2a12526b58007c26f5c951 Mon Sep 17 00:00:00 2001 From: SepehrYahyaee <7heycallmegray@gmail.com> Date: Wed, 29 Jul 2026 10:16:18 +0330 Subject: [PATCH] Fix v5 lock and re-submit mechanism --- src/expert-claim/expert-claim.service.ts | 69 +++++++++++++++--------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/src/expert-claim/expert-claim.service.ts b/src/expert-claim/expert-claim.service.ts index 6bd425a..c5f80d5 100644 --- a/src/expert-claim/expert-claim.service.ts +++ b/src/expert-claim/expert-claim.service.ts @@ -2671,32 +2671,39 @@ export class ExpertClaimService { if (!reviewerBlame) { throw new NotFoundException("Linked blame file not found."); } - const blameStatus = (reviewerBlame as any).status as string; - if (blameStatus === "WAITING_FOR_FILE_REVIEWER") { - // Phase 1: blame-assign path - return this.assignFileReviewerToV4Blame(claimRequestId, claim, actor); - } - // Phase 2: blame is past the initial assignment step. - // Only the reviewer who was assigned during Phase 1 may proceed. const assignedReviewerId = (reviewerBlame as any).assignedFileReviewerId ? String((reviewerBlame as any).assignedFileReviewerId) : null; - if (!assignedReviewerId) { - throw new BadRequestException({ - success: false, - status: "unavailable" satisfies ExpertFileAssignStatus, - message: "No reviewer has been assigned to this file yet.", - }); + const blameStatus = (reviewerBlame as any).status as string; + + if (blameStatus === "WAITING_FOR_FILE_REVIEWER") { + if (assignedReviewerId && assignedReviewerId === actor.sub) { + // Reviewer already assigned (e.g. after a FileMaker rejection that reset + // blame back to WAITING_FOR_FILE_REVIEWER) — skip Phase 1 and fall + // through to the damage-expert workflow lock below. + } else { + // Phase 1: first-time blame assignment + return this.assignFileReviewerToV4Blame(claimRequestId, claim, actor); + } + } else { + // Phase 2: blame is past the initial assignment step. + // Only the reviewer who was assigned during Phase 1 may proceed. + if (!assignedReviewerId) { + throw new BadRequestException({ + success: false, + status: "unavailable" satisfies ExpertFileAssignStatus, + message: "No reviewer has been assigned to this file yet.", + }); + } + if (assignedReviewerId !== actor.sub) { + throw new ConflictException({ + success: false, + status: "locked" satisfies ExpertFileAssignStatus, + message: "This file is assigned to another reviewer.", + }); + } } - if (assignedReviewerId !== actor.sub) { - throw new ConflictException({ - success: false, - status: "locked" satisfies ExpertFileAssignStatus, - message: "This file is assigned to another reviewer.", - }); - } - // Assigned reviewer — fall through to the damage-expert workflow lock below. - // (actor.role stays FILE_REVIEWER; assertExpertActorOnClaim checks clientKey scope) + // Fall through to the damage-expert workflow lock below. } await this.assertExpertActorOnClaim(claim, actor); @@ -2777,10 +2784,16 @@ export class ExpertClaimService { const now = new Date(); const lockSnapshot = await this.snapshotDamageExpert(actor.sub); const expiredAt = new Date(now.getTime() + EXPERT_WORKFLOW_LOCK_TTL_MS); - const actorType = isFieldExpertOwner ? "field_expert" : "damage_expert"; + const actorType = isFieldExpertOwner + ? "field_expert" + : (actor as any).role === RoleEnum.FILE_REVIEWER + ? "file_reviewer" + : "damage_expert"; const actorRoleLabel = isFieldExpertOwner ? ("field_expert" as const) - : ("damage_expert" as const); + : (actor as any).role === RoleEnum.FILE_REVIEWER + ? ("file_reviewer" as const) + : ("damage_expert" as const); const lockedByPayload = { actorId: expertOid, @@ -2834,7 +2847,13 @@ export class ExpertClaimService { }, }; - if (!claim.workflow?.assignedForReviewBy) { + // Update assignedForReviewBy whenever a FILE_REVIEWER re-locks after a + // FileMaker rejection — the stale payload (from a prior damage-expert cycle) + // must be replaced with the actual reviewer so submit checks pass. + if ( + !claim.workflow?.assignedForReviewBy || + (actor as any).role === RoleEnum.FILE_REVIEWER + ) { baseLockUpdate["workflow.assignedForReviewBy"] = lockedByPayload; }