blame and claim refactored

This commit is contained in:
2026-02-24 12:19:25 +03:30
parent 0d8858f458
commit 35732dd70a
81 changed files with 11603 additions and 77 deletions

View File

@@ -0,0 +1,81 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
import { CarAngle } from 'src/Types&Enums/claim-request-management/required-document-type.enum';
/**
* V2 DTO for capturing car angle or damaged part
*/
export class CapturePartV2Dto {
@ApiProperty({
description: 'Type of capture: angle or part',
example: 'angle',
enum: ['angle', 'part'],
})
@IsNotEmpty({ message: 'Capture type is required' })
@IsEnum(['angle', 'part'], {
message: 'Capture type must be either "angle" or "part"',
})
captureType: 'angle' | 'part';
@ApiProperty({
description: 'Key of the angle or part being captured',
example: 'front',
})
@IsNotEmpty({ message: 'Capture key is required' })
@IsString({ message: 'Capture key must be a string' })
captureKey: string;
@ApiProperty({
type: 'string',
format: 'binary',
description: 'Image file (JPG, PNG)',
})
file: Express.Multer.File;
}
/**
* Response DTO for capture part V2
*/
export class CapturePartV2ResponseDto {
@ApiProperty({
description: 'Claim request ID',
example: '507f1f77bcf86cd799439011',
})
claimRequestId: string;
@ApiProperty({
description: 'Type of capture',
example: 'angle',
})
captureType: string;
@ApiProperty({
description: 'Key of what was captured',
example: 'front',
})
captureKey: string;
@ApiProperty({
description: 'File URL',
example: 'http://localhost:3000/files/captures/front-1234567890.jpg',
})
fileUrl: string;
@ApiProperty({
description: 'Whether all captures are now complete',
example: false,
})
allCapturesComplete: boolean;
@ApiProperty({
description: 'Current workflow step',
example: 'CAPTURE_PART_DAMAGES',
})
currentStep: string;
@ApiProperty({
description: 'Success message',
example: 'Angle captured successfully. 6 captures remaining.',
})
message: string;
}

View File

@@ -0,0 +1,163 @@
import { ApiProperty } from '@nestjs/swagger';
/**
* DTO for required document item
*/
export class RequiredDocumentItem {
@ApiProperty({
description: 'Document key/type',
example: 'car_green_card',
})
key: string;
@ApiProperty({
description: 'Display label in Farsi',
example: 'کارت سبز خودرو',
})
label_fa: string;
@ApiProperty({
description: 'Display label in English',
example: 'Car Green Card',
})
label_en: string;
@ApiProperty({
description: 'Whether this document has been uploaded',
example: false,
})
uploaded: boolean;
@ApiProperty({
description: 'Category of the document',
example: 'general',
enum: ['general', 'damaged_party', 'guilty_party'],
})
category: string;
}
/**
* DTO for car angle item
*/
export class CarAngleItem {
@ApiProperty({
description: 'Angle key',
example: 'front',
enum: ['front', 'back', 'left', 'right'],
})
key: string;
@ApiProperty({
description: 'Display label in Farsi',
example: 'جلو',
})
label_fa: string;
@ApiProperty({
description: 'Display label in English',
example: 'Front',
})
label_en: string;
@ApiProperty({
description: 'Whether this angle has been captured',
example: false,
})
captured: boolean;
}
/**
* DTO for damaged part item
*/
export class DamagedPartItem {
@ApiProperty({
description: 'Part key',
example: 'hood',
})
key: string;
@ApiProperty({
description: 'Display label in Farsi',
example: 'کاپوت',
})
label_fa: string;
@ApiProperty({
description: 'Display label in English',
example: 'Hood',
})
label_en: string;
@ApiProperty({
description: 'Whether this part has been captured',
example: false,
})
captured: boolean;
}
/**
* Response DTO for capture requirements V2
*/
export class GetCaptureRequirementsV2ResponseDto {
@ApiProperty({
description: 'Claim request ID',
example: '507f1f77bcf86cd799439011',
})
claimRequestId: string;
@ApiProperty({
description: 'Public ID',
example: 'A14235',
})
publicId: string;
@ApiProperty({
description: 'Current workflow step',
example: 'UPLOAD_REQUIRED_DOCUMENTS',
})
currentStep: string;
@ApiProperty({
description: 'List of required documents to upload',
type: [RequiredDocumentItem],
})
requiredDocuments: RequiredDocumentItem[];
@ApiProperty({
description: 'List of car angles to capture',
type: [CarAngleItem],
})
carAngles: CarAngleItem[];
@ApiProperty({
description: 'List of damaged parts to capture',
type: [DamagedPartItem],
})
damagedParts: DamagedPartItem[];
@ApiProperty({
description: 'Total number of items remaining',
example: 18,
})
totalRemaining: number;
@ApiProperty({
description: 'Summary of progress',
example: {
documentsUploaded: 2,
documentsTotal: 13,
anglesCapture: 0,
anglesTotal: 4,
partsCapture: 0,
partsTotal: 3,
},
})
progress: {
documentsUploaded: number;
documentsTotal: number;
anglesCaptured: number;
anglesTotal: number;
partsCaptured: number;
partsTotal: number;
};
}

View File

@@ -0,0 +1,71 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
export class ClaimDetailsV2ResponseDto {
@ApiProperty({ description: 'Claim case ID' })
claimRequestId: string;
@ApiProperty({ description: 'Public ID' })
publicId: string;
@ApiProperty({ description: 'Request number' })
requestNo: string;
@ApiProperty({ description: 'Overall case status' })
status: string;
@ApiProperty({ description: 'Claim damage status' })
claimStatus: string;
@ApiProperty({ description: 'Current workflow step' })
currentStep: string;
@ApiPropertyOptional({ description: 'Next workflow step' })
nextStep?: string;
@ApiPropertyOptional({ description: 'Blame request ID' })
blameRequestId?: string;
@ApiPropertyOptional({ description: 'Blame request number' })
blameRequestNo?: string;
@ApiPropertyOptional({ description: 'Owner info' })
owner?: {
userId: string;
fullName?: string;
};
@ApiPropertyOptional({ description: 'Vehicle snapshot' })
vehicle?: {
carName?: string;
carModel?: string;
carType?: string;
plate?: any;
};
@ApiPropertyOptional({ description: 'Selected outer damaged parts' })
selectedParts?: string[];
@ApiPropertyOptional({ description: 'Selected other damaged parts' })
otherParts?: string[];
@ApiPropertyOptional({ description: 'Bank info (masked)' })
money?: {
sheba?: string;
nationalCodeOfOwner?: string;
};
@ApiPropertyOptional({ description: 'Required documents status' })
requiredDocuments?: Record<string, { uploaded: boolean; fileId?: string }>;
@ApiPropertyOptional({ description: 'Car angles captured' })
carAngles?: Record<string, { captured: boolean; url?: string }>;
@ApiPropertyOptional({ description: 'Damaged parts captured' })
damagedParts?: Record<string, { captured: boolean; url?: string }>;
@ApiProperty({ description: 'Created at' })
createdAt: string;
@ApiProperty({ description: 'Updated at' })
updatedAt: string;
}

View File

@@ -0,0 +1,26 @@
import { ApiProperty } from "@nestjs/swagger";
export class CreateClaimFromBlameResponseDto {
@ApiProperty({
example: "67fa10c259e15f231a2d1aae",
description: "Created claim request ID",
})
claimRequestId: string;
@ApiProperty({
example: "A14235",
description: "Shared public ID from blame case",
})
publicId: string;
@ApiProperty({
example: "SELECTING_OUTER_PARTS",
description: "Current status after creation",
})
status: string;
@ApiProperty({
example: "Claim request created successfully",
})
message: string;
}

View File

@@ -0,0 +1,35 @@
import { ApiProperty } from '@nestjs/swagger';
export class ClaimListItemV2Dto {
@ApiProperty({ description: 'Claim case ID', example: '507f1f77bcf86cd799439011' })
claimRequestId: string;
@ApiProperty({ description: 'Public ID shared across blame and claim', example: 'A14235' })
publicId: string;
@ApiProperty({ description: 'Claim request number', example: 'CL12345' })
requestNo: string;
@ApiProperty({ description: 'Overall case status', example: 'WAITING_FOR_DAMAGE_EXPERT' })
status: string;
@ApiProperty({ description: 'Claim damage determination status', example: 'PENDING' })
claimStatus: string;
@ApiProperty({ description: 'Current workflow step', example: 'USER_SUBMISSION_COMPLETE' })
currentStep: string;
@ApiProperty({ description: 'Creation date', example: '2026-02-22T10:00:00.000Z' })
createdAt: string;
@ApiProperty({ description: 'Blame request ID this claim originated from' })
blameRequestId?: string;
}
export class GetMyClaimsV2ResponseDto {
@ApiProperty({ description: 'List of user claims', type: [ClaimListItemV2Dto] })
list: ClaimListItemV2Dto[];
@ApiProperty({ description: 'Total count', example: 5 })
total: number;
}

View File

@@ -0,0 +1,126 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsArray, IsEnum, IsNotEmpty, IsOptional, IsString, Matches, Length, ArrayMaxSize } from 'class-validator';
/**
* Enum for valid other (non-body) car parts that can be damaged
*/
export enum OtherCarPart {
ENGINE = 'engine',
SUSPENSION = 'suspension',
BRAKE_SYSTEM = 'brake_system',
ELECTRICAL = 'electrical',
RADIATOR = 'radiator',
TRANSMISSION = 'transmission',
EXHAUST = 'exhaust',
HEADLIGHT = 'headlight',
TAILLIGHT = 'taillight',
MIRROR = 'mirror',
GLASS = 'glass',
}
/**
* V2 DTO for selecting other damaged parts and bank information
* Step 3 of claim workflow
*/
export class SelectOtherPartsV2Dto {
@ApiPropertyOptional({
description: 'Array of selected other damaged parts (non-body parts)',
example: ['engine', 'suspension', 'headlight'],
enum: OtherCarPart,
isArray: true,
maxItems: 11,
required: false,
})
@IsOptional()
@IsArray({ message: 'otherParts must be an array' })
@ArrayMaxSize(11, { message: 'Maximum 11 other parts can be selected' })
@IsEnum(OtherCarPart, {
each: true,
message: 'Invalid part name. Must be one of the valid other car parts',
})
otherParts?: OtherCarPart[];
@ApiProperty({
description: 'Sheba number (IBAN) for payment - 24 digits without IR prefix',
example: '123456789012345678901234',
pattern: '^[0-9]{24}$',
minLength: 24,
maxLength: 24,
})
@IsNotEmpty({ message: 'Sheba number is required' })
@IsString({ message: 'Sheba number must be a string' })
@Length(24, 24, { message: 'Sheba number must be exactly 24 digits' })
@Matches(/^[0-9]{24}$/, {
message: 'Sheba number must contain exactly 24 digits (without IR prefix)',
})
shebaNumber: string;
@ApiProperty({
description: 'National code of the owner - 10 digits',
example: '1234567890',
pattern: '^[0-9]{10}$',
minLength: 10,
maxLength: 10,
})
@IsNotEmpty({ message: 'National code of owner is required' })
@IsString({ message: 'National code must be a string' })
@Length(10, 10, { message: 'National code must be exactly 10 digits' })
@Matches(/^[0-9]{10}$/, {
message: 'National code must contain exactly 10 digits',
})
nationalCodeOfOwner: string;
}
/**
* Response DTO for select other parts V2
*/
export class SelectOtherPartsV2ResponseDto {
@ApiProperty({
description: 'Claim request ID',
example: '507f1f77bcf86cd799439011',
})
claimRequestId: string;
@ApiProperty({
description: 'Public ID shared across blame and claim',
example: 'A14235',
})
publicId: string;
@ApiProperty({
description: 'Array of selected other damaged parts',
example: ['engine', 'suspension'],
required: false,
})
otherParts?: string[];
@ApiProperty({
description: 'Sheba number (masked for security)',
example: 'IR12************1234',
})
shebaNumber: string;
@ApiProperty({
description: 'National code of owner (masked)',
example: '12******90',
})
nationalCodeOfOwner: string;
@ApiProperty({
description: 'Current workflow step',
example: 'UPLOAD_REQUIRED_DOCUMENTS',
})
currentStep: string;
@ApiProperty({
description: 'Next possible workflow step',
example: 'CAPTURE_PART_DAMAGES',
})
nextStep: string;
@ApiProperty({
description: 'Success message',
example: 'Other parts and bank information saved successfully. Please proceed to upload required documents.',
})
message: string;
}

View File

@@ -0,0 +1,96 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsArray, IsEnum, IsNotEmpty, ArrayMinSize, ArrayUnique } from 'class-validator';
/**
* Enum for valid outer car parts that can be damaged
* Follows the naming convention from workflow step definition
*/
export enum OuterCarPart {
// Hood
HOOD = 'hood',
// Doors
FRONT_RIGHT_DOOR = 'front_right_door',
FRONT_LEFT_DOOR = 'front_left_door',
REAR_RIGHT_DOOR = 'rear_right_door',
REAR_LEFT_DOOR = 'rear_left_door',
// Bumpers
FRONT_BUMPER = 'front_bumper',
REAR_BUMPER = 'rear_bumper',
// Fenders
FRONT_RIGHT_FENDER = 'front_right_fender',
FRONT_LEFT_FENDER = 'front_left_fender',
REAR_RIGHT_FENDER = 'rear_right_fender',
REAR_LEFT_FENDER = 'rear_left_fender',
// Trunk & Roof
TRUNK = 'trunk',
ROOF = 'roof',
}
/**
* V2 DTO for selecting damaged outer car parts
* Much cleaner than the nested boolean structure
*/
export class SelectOuterPartsV2Dto {
@ApiProperty({
description: 'Array of selected damaged outer car parts',
example: ['hood', 'front_right_door', 'rear_bumper', 'roof'],
enum: OuterCarPart,
isArray: true,
minItems: 1,
maxItems: 13,
})
@IsNotEmpty({ message: 'Selected parts array cannot be empty' })
@IsArray({ message: 'selectedParts must be an array' })
@ArrayMinSize(1, { message: 'At least one damaged part must be selected' })
@ArrayUnique({ message: 'Duplicate parts are not allowed' })
@IsEnum(OuterCarPart, {
each: true,
message: 'Invalid part name. Must be one of the valid outer car parts',
})
selectedParts: OuterCarPart[];
}
/**
* Response DTO for select outer parts V2
*/
export class SelectOuterPartsV2ResponseDto {
@ApiProperty({
description: 'Claim request ID',
example: '507f1f77bcf86cd799439011',
})
claimRequestId: string;
@ApiProperty({
description: 'Public ID shared across blame and claim',
example: 'A14235',
})
publicId: string;
@ApiProperty({
description: 'Array of selected damaged parts',
example: ['hood', 'front_right_door', 'rear_bumper'],
})
selectedParts: string[];
@ApiProperty({
description: 'Current workflow step',
example: 'SELECT_OUTER_PARTS',
})
currentStep: string;
@ApiProperty({
description: 'Next possible workflow step',
example: 'SELECT_OTHER_PARTS',
})
nextStep: string;
@ApiProperty({
description: 'Success message',
example: 'Outer parts selected successfully. Please proceed to select other parts.',
})
message: string;
}

View File

@@ -0,0 +1,67 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
import { ClaimRequiredDocumentType } from 'src/Types&Enums/claim-request-management/required-document-type.enum';
/**
* V2 DTO for uploading required document
*/
export class UploadRequiredDocumentV2Dto {
@ApiProperty({
description: 'Document type/key',
example: 'car_green_card',
enum: ClaimRequiredDocumentType,
})
@IsNotEmpty({ message: 'Document key is required' })
@IsEnum(ClaimRequiredDocumentType, {
message: 'Invalid document type',
})
documentKey: ClaimRequiredDocumentType;
@ApiProperty({
type: 'string',
format: 'binary',
description: 'Image file (JPG, PNG, PDF)',
})
file: Express.Multer.File;
}
/**
* Response DTO for upload required document V2
*/
export class UploadRequiredDocumentV2ResponseDto {
@ApiProperty({
description: 'Claim request ID',
example: '507f1f77bcf86cd799439011',
})
claimRequestId: string;
@ApiProperty({
description: 'Document key that was uploaded',
example: 'car_green_card',
})
documentKey: string;
@ApiProperty({
description: 'File URL',
example: 'http://localhost:3000/files/documents/car-green-card-1234567890.jpg',
})
fileUrl: string;
@ApiProperty({
description: 'Whether all required documents are now uploaded',
example: false,
})
allDocumentsUploaded: boolean;
@ApiProperty({
description: 'Current workflow step',
example: 'UPLOAD_REQUIRED_DOCUMENTS',
})
currentStep: string;
@ApiProperty({
description: 'Success message',
example: 'Document uploaded successfully. 12 documents remaining.',
})
message: string;
}