From 210e96fcf19baa3838004b3b152aa81d6a50974d Mon Sep 17 00:00:00 2001 From: SepehrYahyaee <7heycallmegray@gmail.com> Date: Mon, 10 Aug 2026 10:34:20 +0330 Subject: [PATCH] Fixed YARA-1217 --- .../required-document-type.enum.ts | 2 - .../claim-request-management.service.ts | 101 ++++++------------ .../dto/create-request-management.dto.ts | 22 ++-- .../request-management.service.ts | 36 +++---- 4 files changed, 60 insertions(+), 101 deletions(-) diff --git a/src/Types&Enums/claim-request-management/required-document-type.enum.ts b/src/Types&Enums/claim-request-management/required-document-type.enum.ts index d046463..5f6312e 100644 --- a/src/Types&Enums/claim-request-management/required-document-type.enum.ts +++ b/src/Types&Enums/claim-request-management/required-document-type.enum.ts @@ -20,8 +20,6 @@ export enum ClaimRequiredDocumentType { GUILTY_CAR_CARD_FRONT = "guilty_car_card_front", GUILTY_CAR_CARD_BACK = "guilty_car_card_back", GUILTY_METAL_PLATE = "guilty_metal_plate", - /** V4 FileMaker flow only: one photo of the guilty party's car. */ - GUILTY_CAR_PHOTO = "guilty_car_photo", } export enum CarAngle { diff --git a/src/claim-request-management/claim-request-management.service.ts b/src/claim-request-management/claim-request-management.service.ts index 0a1f600..3ca7bca 100644 --- a/src/claim-request-management/claim-request-management.service.ts +++ b/src/claim-request-management/claim-request-management.service.ts @@ -460,7 +460,6 @@ export class ClaimRequestManagementService { isCarBody: boolean, assumeUploadedKey?: string, skipMetalPlate?: boolean, - requiresGuiltyCarPhoto?: boolean, ): boolean { for (const k of this.v3PreCaptureDocumentKeys(isCarBody)) { if (skipMetalPlate && OPTIONAL_CAPTURE_PHASE_DOC_KEYS_V4V5.includes(k as any)) continue; @@ -478,15 +477,6 @@ export class ClaimRequestManagementService { : this.isRequiredDocumentUploadedOnClaim(claimCase, g); if (!ok) return false; } - // V4 THIRD_PARTY only: require one photo of the guilty party's car. - if (requiresGuiltyCarPhoto && !isCarBody) { - const k = ClaimRequiredDocumentType.GUILTY_CAR_PHOTO; - const ok = - k === assumeUploadedKey - ? true - : this.isRequiredDocumentUploadedOnClaim(claimCase, k); - if (!ok) return false; - } return true; } @@ -495,7 +485,6 @@ export class ClaimRequestManagementService { isCarBody: boolean, assumeUploadedKey?: string, skipMetalPlate?: boolean, - requiresGuiltyCarPhoto?: boolean, ): number { let n = 0; for (const k of this.v3PreCaptureDocumentKeys(isCarBody)) { @@ -514,15 +503,6 @@ export class ClaimRequestManagementService { : this.isRequiredDocumentUploadedOnClaim(claimCase, g); if (!ok) n++; } - // V4 THIRD_PARTY only: one photo of the guilty party's car. - if (requiresGuiltyCarPhoto && !isCarBody) { - const k = ClaimRequiredDocumentType.GUILTY_CAR_PHOTO; - const ok = - k === assumeUploadedKey - ? true - : this.isRequiredDocumentUploadedOnClaim(claimCase, k); - if (!ok) n++; - } return n; } @@ -9093,7 +9073,7 @@ export class ClaimRequestManagementService { file: Express.Multer.File, currentUserId: string, actor?: { sub: string; role?: string }, - options?: { v3InPersonFlow?: boolean; skipMetalPlate?: boolean; requiresFileMakerApproval?: boolean; requiresGuiltyCarPhoto?: boolean }, + options?: { v3InPersonFlow?: boolean; skipMetalPlate?: boolean; requiresFileMakerApproval?: boolean }, ): Promise { try { const claimCase = await this.claimCaseDbService.findById(claimRequestId); @@ -9326,7 +9306,6 @@ export class ClaimRequestManagementService { isCarBodyUpload, body.documentKey, options?.skipMetalPlate, - options?.requiresGuiltyCarPhoto, ); allDocumentsUploaded = options?.v3InPersonFlow @@ -9342,7 +9321,6 @@ export class ClaimRequestManagementService { isCarBodyUpload, body.documentKey, options?.skipMetalPlate, - options?.requiresGuiltyCarPhoto, ) : this.countRemainingV2OwnerDocuments( claimCase, @@ -9439,14 +9417,10 @@ export class ClaimRequestManagementService { : null; const isCarBodyRecheck = blameForRecheck?.type === BlameRequestType.CAR_BODY; const skipMetalPlateRecheck = !!(blameForRecheck as any)?.isMadeByFileMaker; - // V4 = isMadeByFileMaker + requiresFileMakerApproval is false on the claim. - const requiresGuiltyCarPhotoRecheck = - !!(blameForRecheck as any)?.isMadeByFileMaker && - !(afterWrite as any).requiresFileMakerApproval; const allDoneNow = afterWrite.status === ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS && afterWrite.workflow?.currentStep === ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS && - this.allV3PreCaptureDocumentsComplete(afterWrite, isCarBodyRecheck, undefined, skipMetalPlateRecheck, requiresGuiltyCarPhotoRecheck); + this.allV3PreCaptureDocumentsComplete(afterWrite, isCarBodyRecheck, undefined, skipMetalPlateRecheck); if (allDoneNow) { // Atomic conditional update: only succeeds when status is still @@ -11279,37 +11253,6 @@ export class ClaimRequestManagementService { }; } - // V4 only (isMadeByFileMaker + NOT requiresFileMakerApproval) and THIRD_PARTY: - // inject one photo of the guilty party's car into the pre-capture document list. - const isV4 = - !!(blame as any)?.isMadeByFileMaker && - !(claimCase as any)?.requiresFileMakerApproval; - const isCarBodyBlame = blame?.type === BlameRequestType.CAR_BODY || (blame as any)?.type === "CAR_BODY"; - if (isV4 && !isCarBodyBlame) { - const guiltyCarPhotoKey = ClaimRequiredDocumentType.GUILTY_CAR_PHOTO; - const alreadyPresent = base.requiredDocuments.some( - (d) => d.key === guiltyCarPhotoKey, - ); - if (!alreadyPresent) { - const docData = (claimCase.requiredDocuments as any)?.get?.(guiltyCarPhotoKey) - ?? (claimCase.requiredDocuments as any)?.[guiltyCarPhotoKey]; - base = { - ...base, - requiredDocuments: [ - ...base.requiredDocuments, - { - key: guiltyCarPhotoKey, - label_fa: "عکس خودرو مقصر", - label_en: "Guilty Party Car Photo", - category: "guilty_party", - uploaded: !!docData?.uploaded, - preferUploadDuringCapture: false, - }, - ], - }; - } - } - const step = claimCase.workflow?.currentStep; const capturePartDone = this.claimV3StepCompleted( claimCase, @@ -11454,23 +11397,13 @@ export class ClaimRequestManagementService { } } - // V4 = isMadeByFileMaker + requiresFileMakerApproval is false. - const requiresGuiltyCarPhoto = - !!(blame as any).isMadeByFileMaker && - !(claimCase as any).requiresFileMakerApproval; - return this.uploadRequiredDocumentV2( claimRequestId, body, file, currentUserId, actor, - { - v3InPersonFlow: true, - skipMetalPlate, - requiresFileMakerApproval: !!(claimCase as any).requiresFileMakerApproval, - requiresGuiltyCarPhoto, - }, + { v3InPersonFlow: true, skipMetalPlate, requiresFileMakerApproval: !!(claimCase as any).requiresFileMakerApproval }, ); } @@ -11528,7 +11461,33 @@ export class ClaimRequestManagementService { "Select outer parts after accident fields and required documents.", ); - return this.selectOuterPartsV2(claimRequestId, body, currentUserId, actor); + const result = await this.selectOuterPartsV2(claimRequestId, body, currentUserId, actor); + + // V4 THIRD_PARTY only: append a synthetic "guilty damage area" entry to + // damage.selectedParts so the FileReviewer must capture one photo of the + // guilty party's damaged spot during the CAPTURE_PART_DAMAGES phase. + // selectOuterPartsV2 uses $set on damage.selectedParts, so we append here + // with a separate $push after the V2 write completes. + const isV4 = + !!(blame as any)?.isMadeByFileMaker && + !(refreshed as any)?.requiresFileMakerApproval; + const isCarBodyBlame = + blame?.type === BlameRequestType.CAR_BODY || + (blame as any)?.type === "CAR_BODY"; + if (isV4 && !isCarBodyBlame) { + await this.claimCaseDbService.findByIdAndUpdate(claimRequestId, { + $push: { + "damage.selectedParts": { + id: null, + name: "guilty_damage_area", + side: "", + label_fa: "تصویر نقطه آسیب‌دیده مقصر", + }, + }, + }); + } + + return result; } async selectOtherPartsV3( diff --git a/src/request-management/dto/create-request-management.dto.ts b/src/request-management/dto/create-request-management.dto.ts index 5b48b7a..ea37777 100644 --- a/src/request-management/dto/create-request-management.dto.ts +++ b/src/request-management/dto/create-request-management.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; -import { IsNotEmpty, IsString, MaxLength } from "class-validator"; +import { IsNotEmpty, IsOptional, IsString, MaxLength } from "class-validator"; import { Types } from "mongoose"; import { AddPlateDto } from "src/profile/dto/user/AddPlateDto"; import { StepsEnum } from "src/Types&Enums/blame-request-management/steps.enum"; @@ -98,20 +98,24 @@ export class DescriptionV4Dto { @IsNotEmpty() desc: string; - @ApiProperty({ - description: "Date of the accident (required for all V4 files)", + @ApiPropertyOptional({ + description: + "Date of the accident. Required for the first (guilty) party; " + + "optional for the second (damaged) party.", example: "2025-12-08", }) - @IsNotEmpty() - accidentDate: Date; + @IsOptional() + accidentDate?: Date; - @ApiProperty({ - description: "Time of the accident (required for all V4 files)", + @ApiPropertyOptional({ + description: + "Time of the accident. Required for the first (guilty) party; " + + "optional for the second (damaged) party.", example: "14:30", }) + @IsOptional() @IsString() - @IsNotEmpty() - accidentTime: string; + accidentTime?: string; } /** diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index 1caf80d..64bf3c8 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -10280,37 +10280,35 @@ export class RequestManagementService { body: DescriptionV4Dto, partyRole?: string, ) { - if ( - body.accidentDate == null || - body.accidentDate === ("" as any) - ) { - throw new BadRequestException( - "accidentDate is required for V4 files.", - ); - } - if ( - !body.accidentTime || - !String(body.accidentTime).trim() - ) { - throw new BadRequestException( - "accidentTime is required for V4 files.", - ); - } - const req = await this.blameRequestDbService.findById(requestId); if (!req) throw new NotFoundException("Request not found"); await this.verifyExpertAccessForBlameV2(req, actor); const role = this.resolvePartyRoleV3(req, partyRole); this.assertBlameV3PartyDetailPhase(req, role); + // accidentDate and accidentTime are only required for the first (guilty) + // party — the second (damaged) party can skip them. + if (role === PartyRole.FIRST) { + if (body.accidentDate == null || body.accidentDate === ("" as any)) { + throw new BadRequestException( + "accidentDate is required for the first party in V4 files.", + ); + } + if (!body.accidentTime || !String(body.accidentTime).trim()) { + throw new BadRequestException( + "accidentTime is required for the first party in V4 files.", + ); + } + } + const idx = this.getPartyIndex(req, role); if (idx === -1) throw new BadRequestException(`${role} party not found`); const party = req.parties[idx]; if (!party.statement) party.statement = {} as any; party.statement.description = body.desc; - party.statement.accidentDate = body.accidentDate as any; - party.statement.accidentTime = body.accidentTime; + if (body.accidentDate != null) party.statement.accidentDate = body.accidentDate as any; + if (body.accidentTime) party.statement.accidentTime = body.accidentTime; if (!Array.isArray(req.history)) req.history = []; req.history.push({