forked from Yara724/api
Merge pull request 'Fixed Bugs: 1) V4 incorrect advancement to file maker approval state, 2) V4 race condition for finishing file maker steps' (#210) from s.yahyaee/yara724-api:main into main
Reviewed-on: Yara724/api#210
This commit is contained in:
@@ -8643,31 +8643,10 @@ export class ClaimRequestManagementService {
|
|||||||
|
|
||||||
if (allDocumentsUploaded) {
|
if (allDocumentsUploaded) {
|
||||||
if (options?.v3InPersonFlow) {
|
if (options?.v3InPersonFlow) {
|
||||||
// V4 split flow: mark the claim as waiting for the FileReviewer.
|
// V4/V5 split flow: the status transition to WAITING_FOR_FILE_REVIEWER is
|
||||||
// The FileReviewer calls accident-fields then select-outer-parts, at
|
// deferred to a post-write re-check (see below) to eliminate the race
|
||||||
// which point advanceV3ClaimToOuterPartsIfReady() moves the claim to
|
// condition where two concurrent uploads each see a stale snapshot and
|
||||||
// SELECTING_OUTER_PARTS / SELECT_OUTER_PARTS.
|
// neither fires the transition. We skip adding it to $set here.
|
||||||
$set["status"] = ClaimCaseStatus.WAITING_FOR_FILE_REVIEWER;
|
|
||||||
$set["workflow.nextStep"] = ClaimWorkflowStep.SELECT_OUTER_PARTS;
|
|
||||||
|
|
||||||
completedStepsEntries.push(
|
|
||||||
ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
|
||||||
);
|
|
||||||
historyEntries.push({
|
|
||||||
type: "STEP_COMPLETED",
|
|
||||||
actor: {
|
|
||||||
actorId: new Types.ObjectId(currentUserId),
|
|
||||||
actorName: claimCase.owner?.fullName || "User",
|
|
||||||
actorType: "user",
|
|
||||||
},
|
|
||||||
timestamp: new Date(),
|
|
||||||
metadata: {
|
|
||||||
stepKey: ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
|
||||||
description:
|
|
||||||
"FileMaker documents complete. File sealed — awaiting FileReviewer.",
|
|
||||||
v3InPersonFlow: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
$set["status"] = ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT;
|
$set["status"] = ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT;
|
||||||
$set["claimStatus"] = ClaimStatus.PENDING;
|
$set["claimStatus"] = ClaimStatus.PENDING;
|
||||||
@@ -8734,6 +8713,77 @@ export class ClaimRequestManagementService {
|
|||||||
updatePayload,
|
updatePayload,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ─── V4/V5 in-person flow: post-write race-safe status transition ──────
|
||||||
|
// After the write we re-read the actual DB state. If all pre-capture
|
||||||
|
// documents are now present but the status has not yet advanced (i.e. a
|
||||||
|
// concurrent request uploaded the last doc a split-second before us and
|
||||||
|
// the stale snapshot we read earlier missed it — or vice-versa), we apply
|
||||||
|
// WAITING_FOR_FILE_REVIEWER atomically using findOneAndUpdate with a status
|
||||||
|
// condition, so exactly one writer wins regardless of concurrency.
|
||||||
|
if (options?.v3InPersonFlow && !isResendUpload && !isCapturePhaseDocUpload) {
|
||||||
|
const afterWrite = await this.claimCaseDbService.findById(claimRequestId);
|
||||||
|
if (afterWrite) {
|
||||||
|
const blameForRecheck = afterWrite.blameRequestId
|
||||||
|
? await this.blameRequestDbService.findById(
|
||||||
|
afterWrite.blameRequestId.toString(),
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
const isCarBodyRecheck = blameForRecheck?.type === BlameRequestType.CAR_BODY;
|
||||||
|
const allDoneNow =
|
||||||
|
afterWrite.status === ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS &&
|
||||||
|
afterWrite.workflow?.currentStep === ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS &&
|
||||||
|
this.allV3PreCaptureDocumentsComplete(afterWrite, isCarBodyRecheck);
|
||||||
|
|
||||||
|
if (allDoneNow) {
|
||||||
|
// Atomic conditional update: only succeeds when status is still
|
||||||
|
// UPLOADING_REQUIRED_DOCUMENTS, preventing double-application.
|
||||||
|
const advanced = await this.claimCaseDbService.findOneAndUpdate(
|
||||||
|
{
|
||||||
|
_id: afterWrite._id,
|
||||||
|
status: ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
status: ClaimCaseStatus.WAITING_FOR_FILE_REVIEWER,
|
||||||
|
"workflow.nextStep": ClaimWorkflowStep.SELECT_OUTER_PARTS,
|
||||||
|
},
|
||||||
|
$push: {
|
||||||
|
"workflow.completedSteps": ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||||
|
history: {
|
||||||
|
type: "STEP_COMPLETED",
|
||||||
|
actor: {
|
||||||
|
actorId: new Types.ObjectId(currentUserId),
|
||||||
|
actorName: afterWrite.owner?.fullName || "User",
|
||||||
|
actorType: "user",
|
||||||
|
},
|
||||||
|
timestamp: new Date(),
|
||||||
|
metadata: {
|
||||||
|
stepKey: ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||||
|
description:
|
||||||
|
"FileMaker documents complete. File sealed — awaiting FileReviewer.",
|
||||||
|
v3InPersonFlow: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (advanced) {
|
||||||
|
// This request won the race — reflect the final state in the response.
|
||||||
|
allDocumentsUploaded = true;
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
afterWrite.status === ClaimCaseStatus.WAITING_FOR_FILE_REVIEWER ||
|
||||||
|
(afterWrite.workflow?.completedSteps ?? []).includes(
|
||||||
|
ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// Another concurrent request already advanced the status — treat
|
||||||
|
// this upload as the completing upload for response purposes.
|
||||||
|
allDocumentsUploaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Auto-submit Fanavaran attachments when all documents are uploaded
|
// Auto-submit Fanavaran attachments when all documents are uploaded
|
||||||
if (allDocumentsUploaded && !isResendUpload && !options?.v3InPersonFlow) {
|
if (allDocumentsUploaded && !isResendUpload && !options?.v3InPersonFlow) {
|
||||||
this.submitFanavaranAttachmentsV2(claimRequestId, resolveFanavaranClientKey()).catch(
|
this.submitFanavaranAttachmentsV2(claimRequestId, resolveFanavaranClientKey()).catch(
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ export class FileMakerBlameV4Controller {
|
|||||||
) {
|
) {
|
||||||
return this.requestManagementService.createExpertInitiatedBlameV2(
|
return this.requestManagementService.createExpertInitiatedBlameV2(
|
||||||
fileMaker,
|
fileMaker,
|
||||||
{ ...dto, creationMethod: CreationMethod.IN_PERSON },
|
// requiresFileMakerApproval is V5-only; explicitly exclude it from V4 so
|
||||||
|
// a client that accidentally sends the field cannot poison the blame record.
|
||||||
|
{ ...dto, creationMethod: CreationMethod.IN_PERSON, requiresFileMakerApproval: false },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user