forked from Yara724/api
Fixed YARA-1217
This commit is contained in:
@@ -20,8 +20,6 @@ export enum ClaimRequiredDocumentType {
|
|||||||
GUILTY_CAR_CARD_FRONT = "guilty_car_card_front",
|
GUILTY_CAR_CARD_FRONT = "guilty_car_card_front",
|
||||||
GUILTY_CAR_CARD_BACK = "guilty_car_card_back",
|
GUILTY_CAR_CARD_BACK = "guilty_car_card_back",
|
||||||
GUILTY_METAL_PLATE = "guilty_metal_plate",
|
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 {
|
export enum CarAngle {
|
||||||
|
|||||||
@@ -460,7 +460,6 @@ export class ClaimRequestManagementService {
|
|||||||
isCarBody: boolean,
|
isCarBody: boolean,
|
||||||
assumeUploadedKey?: string,
|
assumeUploadedKey?: string,
|
||||||
skipMetalPlate?: boolean,
|
skipMetalPlate?: boolean,
|
||||||
requiresGuiltyCarPhoto?: boolean,
|
|
||||||
): boolean {
|
): boolean {
|
||||||
for (const k of this.v3PreCaptureDocumentKeys(isCarBody)) {
|
for (const k of this.v3PreCaptureDocumentKeys(isCarBody)) {
|
||||||
if (skipMetalPlate && OPTIONAL_CAPTURE_PHASE_DOC_KEYS_V4V5.includes(k as any)) continue;
|
if (skipMetalPlate && OPTIONAL_CAPTURE_PHASE_DOC_KEYS_V4V5.includes(k as any)) continue;
|
||||||
@@ -478,15 +477,6 @@ export class ClaimRequestManagementService {
|
|||||||
: this.isRequiredDocumentUploadedOnClaim(claimCase, g);
|
: this.isRequiredDocumentUploadedOnClaim(claimCase, g);
|
||||||
if (!ok) return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +485,6 @@ export class ClaimRequestManagementService {
|
|||||||
isCarBody: boolean,
|
isCarBody: boolean,
|
||||||
assumeUploadedKey?: string,
|
assumeUploadedKey?: string,
|
||||||
skipMetalPlate?: boolean,
|
skipMetalPlate?: boolean,
|
||||||
requiresGuiltyCarPhoto?: boolean,
|
|
||||||
): number {
|
): number {
|
||||||
let n = 0;
|
let n = 0;
|
||||||
for (const k of this.v3PreCaptureDocumentKeys(isCarBody)) {
|
for (const k of this.v3PreCaptureDocumentKeys(isCarBody)) {
|
||||||
@@ -514,15 +503,6 @@ export class ClaimRequestManagementService {
|
|||||||
: this.isRequiredDocumentUploadedOnClaim(claimCase, g);
|
: this.isRequiredDocumentUploadedOnClaim(claimCase, g);
|
||||||
if (!ok) n++;
|
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;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9093,7 +9073,7 @@ export class ClaimRequestManagementService {
|
|||||||
file: Express.Multer.File,
|
file: Express.Multer.File,
|
||||||
currentUserId: string,
|
currentUserId: string,
|
||||||
actor?: { sub: string; role?: string },
|
actor?: { sub: string; role?: string },
|
||||||
options?: { v3InPersonFlow?: boolean; skipMetalPlate?: boolean; requiresFileMakerApproval?: boolean; requiresGuiltyCarPhoto?: boolean },
|
options?: { v3InPersonFlow?: boolean; skipMetalPlate?: boolean; requiresFileMakerApproval?: boolean },
|
||||||
): Promise<UploadRequiredDocumentV2ResponseDto> {
|
): Promise<UploadRequiredDocumentV2ResponseDto> {
|
||||||
try {
|
try {
|
||||||
const claimCase = await this.claimCaseDbService.findById(claimRequestId);
|
const claimCase = await this.claimCaseDbService.findById(claimRequestId);
|
||||||
@@ -9326,7 +9306,6 @@ export class ClaimRequestManagementService {
|
|||||||
isCarBodyUpload,
|
isCarBodyUpload,
|
||||||
body.documentKey,
|
body.documentKey,
|
||||||
options?.skipMetalPlate,
|
options?.skipMetalPlate,
|
||||||
options?.requiresGuiltyCarPhoto,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
allDocumentsUploaded = options?.v3InPersonFlow
|
allDocumentsUploaded = options?.v3InPersonFlow
|
||||||
@@ -9342,7 +9321,6 @@ export class ClaimRequestManagementService {
|
|||||||
isCarBodyUpload,
|
isCarBodyUpload,
|
||||||
body.documentKey,
|
body.documentKey,
|
||||||
options?.skipMetalPlate,
|
options?.skipMetalPlate,
|
||||||
options?.requiresGuiltyCarPhoto,
|
|
||||||
)
|
)
|
||||||
: this.countRemainingV2OwnerDocuments(
|
: this.countRemainingV2OwnerDocuments(
|
||||||
claimCase,
|
claimCase,
|
||||||
@@ -9439,14 +9417,10 @@ export class ClaimRequestManagementService {
|
|||||||
: null;
|
: null;
|
||||||
const isCarBodyRecheck = blameForRecheck?.type === BlameRequestType.CAR_BODY;
|
const isCarBodyRecheck = blameForRecheck?.type === BlameRequestType.CAR_BODY;
|
||||||
const skipMetalPlateRecheck = !!(blameForRecheck as any)?.isMadeByFileMaker;
|
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 =
|
const allDoneNow =
|
||||||
afterWrite.status === ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS &&
|
afterWrite.status === ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS &&
|
||||||
afterWrite.workflow?.currentStep === ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS &&
|
afterWrite.workflow?.currentStep === ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS &&
|
||||||
this.allV3PreCaptureDocumentsComplete(afterWrite, isCarBodyRecheck, undefined, skipMetalPlateRecheck, requiresGuiltyCarPhotoRecheck);
|
this.allV3PreCaptureDocumentsComplete(afterWrite, isCarBodyRecheck, undefined, skipMetalPlateRecheck);
|
||||||
|
|
||||||
if (allDoneNow) {
|
if (allDoneNow) {
|
||||||
// Atomic conditional update: only succeeds when status is still
|
// 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 step = claimCase.workflow?.currentStep;
|
||||||
const capturePartDone = this.claimV3StepCompleted(
|
const capturePartDone = this.claimV3StepCompleted(
|
||||||
claimCase,
|
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(
|
return this.uploadRequiredDocumentV2(
|
||||||
claimRequestId,
|
claimRequestId,
|
||||||
body,
|
body,
|
||||||
file,
|
file,
|
||||||
currentUserId,
|
currentUserId,
|
||||||
actor,
|
actor,
|
||||||
{
|
{ v3InPersonFlow: true, skipMetalPlate, requiresFileMakerApproval: !!(claimCase as any).requiresFileMakerApproval },
|
||||||
v3InPersonFlow: true,
|
|
||||||
skipMetalPlate,
|
|
||||||
requiresFileMakerApproval: !!(claimCase as any).requiresFileMakerApproval,
|
|
||||||
requiresGuiltyCarPhoto,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11528,7 +11461,33 @@ export class ClaimRequestManagementService {
|
|||||||
"Select outer parts after accident fields and required documents.",
|
"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(
|
async selectOtherPartsV3(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
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 { Types } from "mongoose";
|
||||||
import { AddPlateDto } from "src/profile/dto/user/AddPlateDto";
|
import { AddPlateDto } from "src/profile/dto/user/AddPlateDto";
|
||||||
import { StepsEnum } from "src/Types&Enums/blame-request-management/steps.enum";
|
import { StepsEnum } from "src/Types&Enums/blame-request-management/steps.enum";
|
||||||
@@ -98,20 +98,24 @@ export class DescriptionV4Dto {
|
|||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
desc: string;
|
desc: string;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiPropertyOptional({
|
||||||
description: "Date of the accident (required for all V4 files)",
|
description:
|
||||||
|
"Date of the accident. Required for the first (guilty) party; " +
|
||||||
|
"optional for the second (damaged) party.",
|
||||||
example: "2025-12-08",
|
example: "2025-12-08",
|
||||||
})
|
})
|
||||||
@IsNotEmpty()
|
@IsOptional()
|
||||||
accidentDate: Date;
|
accidentDate?: Date;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiPropertyOptional({
|
||||||
description: "Time of the accident (required for all V4 files)",
|
description:
|
||||||
|
"Time of the accident. Required for the first (guilty) party; " +
|
||||||
|
"optional for the second (damaged) party.",
|
||||||
example: "14:30",
|
example: "14:30",
|
||||||
})
|
})
|
||||||
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
accidentTime?: string;
|
||||||
accidentTime: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -10280,37 +10280,35 @@ export class RequestManagementService {
|
|||||||
body: DescriptionV4Dto,
|
body: DescriptionV4Dto,
|
||||||
partyRole?: string,
|
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);
|
const req = await this.blameRequestDbService.findById(requestId);
|
||||||
if (!req) throw new NotFoundException("Request not found");
|
if (!req) throw new NotFoundException("Request not found");
|
||||||
await this.verifyExpertAccessForBlameV2(req, actor);
|
await this.verifyExpertAccessForBlameV2(req, actor);
|
||||||
const role = this.resolvePartyRoleV3(req, partyRole);
|
const role = this.resolvePartyRoleV3(req, partyRole);
|
||||||
this.assertBlameV3PartyDetailPhase(req, role);
|
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);
|
const idx = this.getPartyIndex(req, role);
|
||||||
if (idx === -1) throw new BadRequestException(`${role} party not found`);
|
if (idx === -1) throw new BadRequestException(`${role} party not found`);
|
||||||
|
|
||||||
const party = req.parties[idx];
|
const party = req.parties[idx];
|
||||||
if (!party.statement) party.statement = {} as any;
|
if (!party.statement) party.statement = {} as any;
|
||||||
party.statement.description = body.desc;
|
party.statement.description = body.desc;
|
||||||
party.statement.accidentDate = body.accidentDate as any;
|
if (body.accidentDate != null) party.statement.accidentDate = body.accidentDate as any;
|
||||||
party.statement.accidentTime = body.accidentTime;
|
if (body.accidentTime) party.statement.accidentTime = body.accidentTime;
|
||||||
|
|
||||||
if (!Array.isArray(req.history)) req.history = [];
|
if (!Array.isArray(req.history)) req.history = [];
|
||||||
req.history.push({
|
req.history.push({
|
||||||
|
|||||||
Reference in New Issue
Block a user