forked from Yara724/api
fixed many bugs and step issues
This commit is contained in:
@@ -7,12 +7,12 @@ export enum ClaimWorkflowStep {
|
||||
SELECT_OUTER_PARTS = "SELECT_OUTER_PARTS",
|
||||
SELECT_OTHER_PARTS = "SELECT_OTHER_PARTS",
|
||||
|
||||
// User: Documentation phase
|
||||
UPLOAD_REQUIRED_DOCUMENTS = "UPLOAD_REQUIRED_DOCUMENTS",
|
||||
|
||||
// User: Damage capture phase (per part)
|
||||
// User: Damage capture phase (angles + per-part photos) — before document upload in v2
|
||||
CAPTURE_PART_DAMAGES = "CAPTURE_PART_DAMAGES",
|
||||
|
||||
// User: Documentation phase — after captures in v2
|
||||
UPLOAD_REQUIRED_DOCUMENTS = "UPLOAD_REQUIRED_DOCUMENTS",
|
||||
|
||||
// User submission complete
|
||||
USER_SUBMISSION_COMPLETE = "USER_SUBMISSION_COMPLETE",
|
||||
|
||||
|
||||
@@ -669,7 +669,7 @@ export class ClaimRequestManagementService {
|
||||
"damage.selectedParts": selectedParts,
|
||||
status: ClaimCaseStatus.SELECTING_OTHER_PARTS,
|
||||
"workflow.currentStep": ClaimWorkflowStep.SELECT_OTHER_PARTS,
|
||||
"workflow.nextStep": ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||
"workflow.nextStep": ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
|
||||
$push: {
|
||||
"workflow.completedSteps": ClaimWorkflowStep.SELECT_OUTER_PARTS,
|
||||
history: {
|
||||
@@ -759,9 +759,9 @@ export class ClaimRequestManagementService {
|
||||
otherPartsArr.length > 0 ? otherPartsArr : [],
|
||||
}
|
||||
: {}),
|
||||
status: ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS,
|
||||
"workflow.currentStep": ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||
"workflow.nextStep": ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
|
||||
status: ClaimCaseStatus.CAPTURING_PART_DAMAGES,
|
||||
"workflow.currentStep": ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
|
||||
"workflow.nextStep": ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||
$push: {
|
||||
"workflow.completedSteps": ClaimWorkflowStep.SELECT_OTHER_PARTS,
|
||||
history: {
|
||||
@@ -3184,6 +3184,13 @@ export class ClaimRequestManagementService {
|
||||
owner: {
|
||||
userId: new Types.ObjectId(currentUserId),
|
||||
userRole: currentUserParty.role as any,
|
||||
...(currentUserParty.person?.clientId
|
||||
? {
|
||||
clientId: new Types.ObjectId(
|
||||
currentUserParty.person.clientId as any,
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
history: [
|
||||
{
|
||||
@@ -3305,6 +3312,11 @@ export class ClaimRequestManagementService {
|
||||
owner: {
|
||||
userId: new Types.ObjectId(damagedUserId),
|
||||
userRole: damagedParty?.role as any,
|
||||
...(damagedParty?.person?.clientId
|
||||
? {
|
||||
clientId: new Types.ObjectId(damagedParty.person.clientId as any),
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
history: [
|
||||
{
|
||||
@@ -3440,6 +3452,11 @@ export class ClaimRequestManagementService {
|
||||
owner: {
|
||||
userId: new Types.ObjectId(damagedUserId),
|
||||
userRole: damagedParty?.role as any,
|
||||
...(damagedParty?.person?.clientId
|
||||
? {
|
||||
clientId: new Types.ObjectId(damagedParty.person.clientId as any),
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
createdByRegistrarId: new Types.ObjectId(registrar.sub),
|
||||
history: [
|
||||
@@ -3550,7 +3567,7 @@ export class ClaimRequestManagementService {
|
||||
'damage.selectedParts': selectedParts,
|
||||
'status': ClaimCaseStatus.SELECTING_OTHER_PARTS,
|
||||
'workflow.currentStep': ClaimWorkflowStep.SELECT_OTHER_PARTS,
|
||||
'workflow.nextStep': ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||
'workflow.nextStep': ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
|
||||
$push: {
|
||||
'workflow.completedSteps': ClaimWorkflowStep.SELECT_OUTER_PARTS,
|
||||
history: {
|
||||
@@ -3586,7 +3603,7 @@ export class ClaimRequestManagementService {
|
||||
publicId: updatedClaim.publicId,
|
||||
selectedParts: selectedParts,
|
||||
currentStep: ClaimWorkflowStep.SELECT_OTHER_PARTS,
|
||||
nextStep: ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||
nextStep: ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
|
||||
message: 'Outer parts selected successfully. Please proceed to select other parts and provide bank information.',
|
||||
};
|
||||
} catch (error) {
|
||||
@@ -3704,9 +3721,9 @@ export class ClaimRequestManagementService {
|
||||
'damage.otherParts': otherParts.length > 0 ? otherParts : undefined,
|
||||
'money.sheba': shebaNumber,
|
||||
'money.nationalCodeOfInsurer': nationalCode,
|
||||
'status': ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS,
|
||||
'status': ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS ,
|
||||
'workflow.currentStep': ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||
'workflow.nextStep': ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
|
||||
'workflow.nextStep': ClaimWorkflowStep.USER_SUBMISSION_COMPLETE,
|
||||
$push: {
|
||||
'workflow.completedSteps': ClaimWorkflowStep.SELECT_OTHER_PARTS,
|
||||
history: {
|
||||
@@ -3785,9 +3802,10 @@ export class ClaimRequestManagementService {
|
||||
otherParts: otherParts,
|
||||
shebaNumber: maskedSheba,
|
||||
nationalCodeOfOwner: maskedNationalCode,
|
||||
currentStep: ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||
nextStep: ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
|
||||
message: 'Other parts and bank information saved successfully. Please proceed to upload required documents.',
|
||||
currentStep: ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
|
||||
nextStep: ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||
message:
|
||||
'Other parts and bank information saved successfully. Please capture car angles and damaged parts, then upload required documents.',
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof HttpException) throw error;
|
||||
@@ -3854,7 +3872,6 @@ export class ClaimRequestManagementService {
|
||||
: null;
|
||||
const isCarBody = blameRequest?.type === BlameRequestType.CAR_BODY;
|
||||
const requiredDocsDefinition = [
|
||||
{ key: 'car_green_card', label_fa: 'کارت سبز خودرو', label_en: 'Car Green Card', category: 'general' },
|
||||
{ key: 'damaged_driving_license_front', label_fa: 'گواهینامه طرف آسیبدیده - جلو', label_en: 'Damaged Party License - Front', category: 'damaged_party' },
|
||||
{ key: 'damaged_driving_license_back', label_fa: 'گواهینامه طرف آسیبدیده - پشت', label_en: 'Damaged Party License - Back', category: 'damaged_party' },
|
||||
{ key: 'damaged_chassis_number', label_fa: 'شماره شاسی', label_en: 'Chassis Number', category: 'damaged_party' },
|
||||
@@ -4036,11 +4053,14 @@ export class ClaimRequestManagementService {
|
||||
const uploadedCount = (currentDocs instanceof Map ? currentDocs.size : Object.keys(currentDocs).length) + 1;
|
||||
const allDocumentsUploaded = uploadedCount >= totalDocsRequired;
|
||||
|
||||
// If all documents uploaded, move to next step
|
||||
// If all documents uploaded, user flow complete (captures were done earlier in v2)
|
||||
if (allDocumentsUploaded) {
|
||||
updateData['status'] = ClaimCaseStatus.CAPTURING_PART_DAMAGES;
|
||||
updateData['workflow.currentStep'] = ClaimWorkflowStep.CAPTURE_PART_DAMAGES;
|
||||
updateData['workflow.nextStep'] = ClaimWorkflowStep.USER_SUBMISSION_COMPLETE;
|
||||
updateData['status'] = ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT;
|
||||
updateData['claimStatus'] = ClaimStatus.PENDING;
|
||||
updateData['workflow.currentStep'] =
|
||||
ClaimWorkflowStep.USER_SUBMISSION_COMPLETE;
|
||||
updateData['workflow.nextStep'] =
|
||||
ClaimWorkflowStep.EXPERT_DAMAGE_ASSESSMENT;
|
||||
updateData.$push.history = [
|
||||
updateData.$push.history,
|
||||
{
|
||||
@@ -4056,15 +4076,30 @@ export class ClaimRequestManagementService {
|
||||
description: 'All required documents uploaded',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'STEP_COMPLETED',
|
||||
actor: {
|
||||
actorId: new Types.ObjectId(currentUserId),
|
||||
actorName: claimCase.owner?.fullName || 'User',
|
||||
actorType: 'user',
|
||||
},
|
||||
timestamp: new Date(),
|
||||
metadata: {
|
||||
stepKey: ClaimWorkflowStep.USER_SUBMISSION_COMPLETE,
|
||||
description:
|
||||
'User submission complete. Claim ready for damage expert review.',
|
||||
},
|
||||
},
|
||||
];
|
||||
updateData.$push['workflow.completedSteps'] = ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS;
|
||||
updateData.$push['workflow.completedSteps'] =
|
||||
ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS;
|
||||
}
|
||||
|
||||
await this.claimCaseDbService.findByIdAndUpdate(claimRequestId, updateData);
|
||||
|
||||
const remaining = totalDocsRequired - uploadedCount;
|
||||
const message = allDocumentsUploaded
|
||||
? 'All documents uploaded successfully. Please proceed to capture car angles and damaged parts.'
|
||||
? 'All documents uploaded successfully. Your claim is now ready for damage expert review.'
|
||||
: `Document uploaded successfully. ${remaining} documents remaining.`;
|
||||
|
||||
return {
|
||||
@@ -4072,7 +4107,9 @@ export class ClaimRequestManagementService {
|
||||
documentKey: body.documentKey,
|
||||
fileUrl,
|
||||
allDocumentsUploaded,
|
||||
currentStep: allDocumentsUploaded ? ClaimWorkflowStep.CAPTURE_PART_DAMAGES : ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||
currentStep: allDocumentsUploaded
|
||||
? ClaimWorkflowStep.USER_SUBMISSION_COMPLETE
|
||||
: ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||
message,
|
||||
};
|
||||
} catch (error) {
|
||||
@@ -4169,10 +4206,9 @@ export class ClaimRequestManagementService {
|
||||
|
||||
if (allCapturesComplete) {
|
||||
await this.claimCaseDbService.findByIdAndUpdate(claimRequestId, {
|
||||
status: ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT,
|
||||
claimStatus: ClaimStatus.PENDING,
|
||||
'workflow.currentStep': ClaimWorkflowStep.USER_SUBMISSION_COMPLETE,
|
||||
'workflow.nextStep': ClaimWorkflowStep.EXPERT_DAMAGE_ASSESSMENT,
|
||||
status: ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS,
|
||||
'workflow.currentStep': ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS,
|
||||
'workflow.nextStep': ClaimWorkflowStep.USER_SUBMISSION_COMPLETE,
|
||||
$push: {
|
||||
'workflow.completedSteps': ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
|
||||
history: {
|
||||
@@ -4184,8 +4220,9 @@ export class ClaimRequestManagementService {
|
||||
},
|
||||
timestamp: new Date(),
|
||||
metadata: {
|
||||
stepKey: ClaimWorkflowStep.USER_SUBMISSION_COMPLETE,
|
||||
description: 'User submission complete. Claim ready for damage expert review.',
|
||||
stepKey: ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
|
||||
description:
|
||||
'All car angles and damaged parts captured. Please upload required documents.',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4194,7 +4231,7 @@ export class ClaimRequestManagementService {
|
||||
|
||||
const remaining = (4 - anglesCaptured) + (selectedParts.length - partsCaptured);
|
||||
const message = allCapturesComplete
|
||||
? 'All captures complete. Your claim is now ready for damage expert review.'
|
||||
? 'All captures complete. Please proceed to upload required documents.'
|
||||
: `${body.captureType === 'angle' ? 'Angle' : 'Part'} captured successfully. ${remaining} captures remaining.`;
|
||||
|
||||
return {
|
||||
@@ -4204,7 +4241,7 @@ export class ClaimRequestManagementService {
|
||||
fileUrl,
|
||||
allCapturesComplete,
|
||||
currentStep: allCapturesComplete
|
||||
? ClaimWorkflowStep.USER_SUBMISSION_COMPLETE
|
||||
? ClaimWorkflowStep.UPLOAD_REQUIRED_DOCUMENTS
|
||||
: ClaimWorkflowStep.CAPTURE_PART_DAMAGES,
|
||||
message,
|
||||
};
|
||||
|
||||
@@ -270,8 +270,8 @@ Optional: upload car green card file in the same step.
|
||||
- headlight, taillight, mirror, glass
|
||||
|
||||
**After Success:**
|
||||
- Workflow moves to: UPLOAD_REQUIRED_DOCUMENTS (Step 4)
|
||||
- User can proceed to upload required documents
|
||||
- Workflow moves to: CAPTURE_PART_DAMAGES (Step 4)
|
||||
- User captures car angles and damaged-part photos, then uploads required documents (Step 5)
|
||||
`,
|
||||
})
|
||||
@ApiParam({
|
||||
@@ -371,6 +371,8 @@ Optional: upload car green card file in the same step.
|
||||
- Damaged parts (based on selected outer parts)
|
||||
|
||||
Returns status of each item (uploaded/captured or not).
|
||||
|
||||
**V2 order:** Complete angles and part photos first, then required documents.
|
||||
`,
|
||||
})
|
||||
@ApiParam({
|
||||
@@ -433,9 +435,9 @@ Returns status of each item (uploaded/captured or not).
|
||||
)
|
||||
@ApiConsumes("multipart/form-data")
|
||||
@ApiOperation({
|
||||
summary: "Upload Required Document (V2 - Step 4)",
|
||||
summary: "Upload Required Document (V2 - Step 5)",
|
||||
description: `
|
||||
**Workflow Step:** UPLOAD_REQUIRED_DOCUMENTS (Step 4 of Claim)
|
||||
**Workflow Step:** UPLOAD_REQUIRED_DOCUMENTS (Step 5 of Claim)
|
||||
|
||||
**Upload one of the required documents** (13 for THIRD_PARTY; CAR_BODY may require fewer — see capture-requirements):
|
||||
- car_green_card
|
||||
@@ -444,7 +446,7 @@ Returns status of each item (uploaded/captured or not).
|
||||
- damaged_car_card_front/back, damaged_metal_plate
|
||||
- guilty_driving_license_front/back, guilty_car_card_front/back, guilty_metal_plate (THIRD_PARTY)
|
||||
|
||||
**When all required documents are uploaded:** Workflow moves to CAPTURE_PART_DAMAGES (Step 5).
|
||||
**When all required documents are uploaded:** Workflow moves to USER_SUBMISSION_COMPLETE and the claim is ready for damage expert review.
|
||||
|
||||
**Field expert IN_PERSON:** Same endpoint; use with claim created from expert-initiated IN_PERSON blame to upload documents on behalf of the damaged party.
|
||||
`,
|
||||
@@ -462,7 +464,6 @@ Returns status of each item (uploaded/captured or not).
|
||||
documentKey: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"car_green_card",
|
||||
"damaged_driving_license_front",
|
||||
"damaged_driving_license_back",
|
||||
"damaged_chassis_number",
|
||||
@@ -476,7 +477,7 @@ Returns status of each item (uploaded/captured or not).
|
||||
"guilty_car_card_back",
|
||||
"guilty_metal_plate",
|
||||
],
|
||||
example: "car_green_card",
|
||||
example: "damaged_driving_license_front",
|
||||
},
|
||||
file: {
|
||||
type: "string",
|
||||
@@ -542,15 +543,15 @@ Returns status of each item (uploaded/captured or not).
|
||||
)
|
||||
@ApiConsumes("multipart/form-data")
|
||||
@ApiOperation({
|
||||
summary: "Capture Car Angle or Damaged Part (V2 - Step 5)",
|
||||
summary: "Capture Car Angle or Damaged Part (V2 - Step 4)",
|
||||
description: `
|
||||
**Workflow Step:** CAPTURE_PART_DAMAGES (Step 5 of Claim)
|
||||
**Workflow Step:** CAPTURE_PART_DAMAGES (Step 4 of Claim)
|
||||
|
||||
**Capture types:**
|
||||
1. **angle**: Car angles (front, back, left, right) - 4 required
|
||||
2. **part**: Damaged parts based on selectedParts from Step 2
|
||||
|
||||
**All captures must be completed before user can submit claim.**
|
||||
**When all captures are complete:** Workflow moves to UPLOAD_REQUIRED_DOCUMENTS (Step 5).
|
||||
|
||||
**Field expert IN_PERSON:** Same endpoint; use with claim created from expert-initiated IN_PERSON blame to capture photos on behalf of the damaged party.
|
||||
`,
|
||||
|
||||
@@ -117,19 +117,20 @@ export class SelectOtherPartsV2ResponseDto {
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Current workflow step',
|
||||
example: 'UPLOAD_REQUIRED_DOCUMENTS',
|
||||
example: 'CAPTURE_PART_DAMAGES',
|
||||
})
|
||||
currentStep: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Next possible workflow step',
|
||||
example: 'CAPTURE_PART_DAMAGES',
|
||||
example: 'UPLOAD_REQUIRED_DOCUMENTS',
|
||||
})
|
||||
nextStep: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Success message',
|
||||
example: 'Other parts and bank information saved successfully. Please proceed to upload required documents.',
|
||||
example:
|
||||
'Other parts and bank information saved successfully. Please capture car angles and damaged parts, then upload required documents.',
|
||||
})
|
||||
message: string;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,9 @@ export class ClaimOwner {
|
||||
|
||||
@Prop({ type: String })
|
||||
fullName?: string;
|
||||
|
||||
@Prop({ type: Types.ObjectId })
|
||||
clientId: Types.ObjectId;
|
||||
}
|
||||
export const ClaimOwnerSchema = SchemaFactory.createForClass(ClaimOwner);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { BlameRequestType } from 'src/Types&Enums/blame-request-management/blameRequestType.enum';
|
||||
|
||||
export class ClaimDetailV2ResponseDto {
|
||||
@ApiProperty()
|
||||
@@ -43,6 +44,19 @@ export class ClaimDetailV2ResponseDto {
|
||||
plate?: any;
|
||||
};
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Blame file type from linked blame case',
|
||||
enum: BlameRequestType,
|
||||
})
|
||||
blameRequestType?: BlameRequestType;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description:
|
||||
'CAR_BODY only: first-step flags — another car (`car`) and/or object (`object`)',
|
||||
example: { car: true, object: false },
|
||||
})
|
||||
carBodyFirstForm?: { car?: boolean; object?: boolean };
|
||||
|
||||
@ApiPropertyOptional({ description: 'Blame request ID', example: '507f...' })
|
||||
blameRequestId?: string;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { BlameRequestType } from 'src/Types&Enums/blame-request-management/blameRequestType.enum';
|
||||
|
||||
export class ClaimListItemV2Dto {
|
||||
@ApiProperty({ description: 'Claim case ID' })
|
||||
@@ -29,6 +30,20 @@ export class ClaimListItemV2Dto {
|
||||
carType?: string;
|
||||
};
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Blame file type from linked blame case',
|
||||
enum: BlameRequestType,
|
||||
example: BlameRequestType.THIRD_PARTY,
|
||||
})
|
||||
blameRequestType?: BlameRequestType;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description:
|
||||
'CAR_BODY only: first-step flags — accident involved another car (`car`) and/or fixed object (`object`)',
|
||||
example: { car: true, object: false },
|
||||
})
|
||||
carBodyFirstForm?: { car?: boolean; object?: boolean };
|
||||
|
||||
@ApiProperty({ description: 'Submission date', example: '2026-02-22T10:00:00.000Z' })
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ import {
|
||||
requireActorClientKey,
|
||||
} from "src/helpers/tenant-scope";
|
||||
import { ClaimWorkflowStep } from "src/Types&Enums/claim-request-management/claim-workflow-steps.enum";
|
||||
import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum";
|
||||
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
||||
import { GetClaimListV2ResponseDto, ClaimListItemV2Dto } from "./dto/claim-list-v2.dto";
|
||||
import { ClaimDetailV2ResponseDto } from "./dto/claim-detail-v2.dto";
|
||||
import { ClaimSubmitReplyDto, ClaimSubmitResendDto } from "./dto/reply.dto";
|
||||
@@ -47,6 +49,7 @@ import { ClaimRequiredDocumentDbService } from "src/claim-request-management/ent
|
||||
import { FactorStatus } from "src/Types&Enums/claim-request-management/factor-status.enum";
|
||||
import { DaghiOption } from "src/Types&Enums/claim-request-management/daghi-option.enum";
|
||||
import { BranchDbService } from "src/client/entities/db-service/branch.db.service";
|
||||
import { BlameRequestDbService } from "src/request-management/entities/db-service/blame-request.db.service";
|
||||
|
||||
@Injectable()
|
||||
export class ExpertClaimService {
|
||||
@@ -165,8 +168,120 @@ export class ExpertClaimService {
|
||||
private readonly claimFactorsImageDbService: ClaimFactorsImageDbService,
|
||||
private readonly claimRequiredDocumentDbService: ClaimRequiredDocumentDbService,
|
||||
private readonly branchDbService: BranchDbService,
|
||||
private readonly blameRequestDbService: BlameRequestDbService,
|
||||
) {}
|
||||
|
||||
/** Map blame party `Vehicle` (name/model/type) to expert panel shape. */
|
||||
private expertVehicleFromPartyVehicle(v: any): {
|
||||
carName?: string;
|
||||
carModel?: string;
|
||||
carType?: string;
|
||||
plate?: { plateId?: string };
|
||||
} | undefined {
|
||||
if (!v || typeof v !== "object") return undefined;
|
||||
const carName = v.name ?? v.carName;
|
||||
const carModel = v.model ?? v.carModel;
|
||||
const carType = v.type ?? v.carType;
|
||||
const plateId = v.plateId;
|
||||
const plate =
|
||||
plateId != null && String(plateId).length > 0
|
||||
? { plateId: String(plateId) }
|
||||
: undefined;
|
||||
if (!carName && !carModel && !carType && !plate) return undefined;
|
||||
return { carName, carModel, carType, ...(plate ? { plate } : {}) };
|
||||
}
|
||||
|
||||
/** Damaged party vehicle on blame (matches claim owner, or non-guilty party for THIRD_PARTY). */
|
||||
private damagedPartyVehicleFromBlame(
|
||||
blame: any,
|
||||
claim: any,
|
||||
):
|
||||
| {
|
||||
carName?: string;
|
||||
carModel?: string;
|
||||
carType?: string;
|
||||
plate?: { plateId?: string };
|
||||
}
|
||||
| undefined {
|
||||
const parties = blame?.parties;
|
||||
if (!Array.isArray(parties) || parties.length === 0) return undefined;
|
||||
|
||||
const ownerId = claim?.owner?.userId ? String(claim.owner.userId) : "";
|
||||
let party = ownerId
|
||||
? parties.find(
|
||||
(p: any) =>
|
||||
p?.person?.userId && String(p.person.userId) === ownerId,
|
||||
)
|
||||
: undefined;
|
||||
|
||||
if (!party && blame?.expert?.decision?.guiltyPartyId) {
|
||||
const guilty = String(blame.expert.decision.guiltyPartyId);
|
||||
party = parties.find(
|
||||
(p: any) =>
|
||||
p?.person?.userId && String(p.person.userId) !== guilty,
|
||||
);
|
||||
}
|
||||
|
||||
if (!party && parties.length === 1) party = parties[0];
|
||||
|
||||
return this.expertVehicleFromPartyVehicle(party?.vehicle);
|
||||
}
|
||||
|
||||
private vehicleForExpertFromClaimAndBlameMap(
|
||||
claim: any,
|
||||
blameById: Map<string, any>,
|
||||
):
|
||||
| { carName?: string; carModel?: string; carType?: string; plate?: { plateId?: string } }
|
||||
| undefined {
|
||||
const cv = claim?.vehicle;
|
||||
if (
|
||||
cv &&
|
||||
(cv.carName || cv.carModel || cv.carType || (cv as any).plate)
|
||||
) {
|
||||
return {
|
||||
carName: cv.carName,
|
||||
carModel: cv.carModel,
|
||||
carType: cv.carType,
|
||||
...((cv as any).plate ? { plate: (cv as any).plate } : {}),
|
||||
};
|
||||
}
|
||||
const bid = claim?.blameRequestId?.toString();
|
||||
if (!bid) return undefined;
|
||||
const blame = blameById.get(bid);
|
||||
if (!blame) return undefined;
|
||||
return this.damagedPartyVehicleFromBlame(blame, claim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blame file kind for damage-expert UI: THIRD_PARTY vs CAR_BODY, and CAR_BODY first-step flags.
|
||||
*/
|
||||
private blameFileContextForExpert(blame: any): {
|
||||
blameRequestType?: BlameRequestType;
|
||||
carBodyFirstForm?: { car?: boolean; object?: boolean };
|
||||
} {
|
||||
if (!blame?.type) return {};
|
||||
const blameRequestType = blame.type as BlameRequestType;
|
||||
const out: {
|
||||
blameRequestType?: BlameRequestType;
|
||||
carBodyFirstForm?: { car?: boolean; object?: boolean };
|
||||
} = { blameRequestType };
|
||||
if (blameRequestType !== BlameRequestType.CAR_BODY) return out;
|
||||
|
||||
const parties = blame.parties;
|
||||
if (!Array.isArray(parties) || parties.length === 0) return out;
|
||||
|
||||
const first =
|
||||
parties.find((p: any) => p?.role === PartyRole.FIRST) ?? parties[0];
|
||||
const cbf = first?.carBodyFirstForm;
|
||||
if (cbf && typeof cbf === "object") {
|
||||
out.carBodyFirstForm = {
|
||||
...(typeof cbf.car === "boolean" ? { car: cbf.car } : {}),
|
||||
...(typeof cbf.object === "boolean" ? { object: cbf.object } : {}),
|
||||
};
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private isVisibleToClientType(client: any, actor: any): boolean {
|
||||
if (actor.userType === UserType.GENUINE) {
|
||||
return true;
|
||||
@@ -1858,13 +1973,39 @@ export class ExpertClaimService {
|
||||
],
|
||||
});
|
||||
|
||||
const list = (claims as any[])
|
||||
.filter((c) => claimCaseTouchesClient(c, clientKey))
|
||||
.map((c) => ({
|
||||
const filtered = (claims as any[]).filter((c) =>
|
||||
claimCaseTouchesClient(c, clientKey),
|
||||
);
|
||||
|
||||
const blameIds = [
|
||||
...new Set(
|
||||
filtered
|
||||
.map((c) => c.blameRequestId?.toString())
|
||||
.filter((id): id is string => !!id),
|
||||
),
|
||||
];
|
||||
const blames =
|
||||
blameIds.length > 0
|
||||
? ((await this.blameRequestDbService.find(
|
||||
{ _id: { $in: blameIds.map((id) => new Types.ObjectId(id)) } },
|
||||
{ lean: true, select: "type parties expert.decision" },
|
||||
)) as any[])
|
||||
: [];
|
||||
const blameById = new Map<string, any>(
|
||||
blames.map((b) => [String(b._id), b]),
|
||||
);
|
||||
|
||||
const list = filtered.map((c) => {
|
||||
const v = this.vehicleForExpertFromClaimAndBlameMap(c, blameById);
|
||||
const blame = c.blameRequestId
|
||||
? blameById.get(c.blameRequestId.toString())
|
||||
: undefined;
|
||||
const fileCtx = blame ? this.blameFileContextForExpert(blame) : {};
|
||||
return {
|
||||
claimRequestId: c._id.toString(),
|
||||
publicId: c.publicId,
|
||||
status: c.status,
|
||||
currentStep: c.workflow?.currentStep || '',
|
||||
currentStep: c.workflow?.currentStep || "",
|
||||
locked: c.workflow?.locked || false,
|
||||
lockedBy: c.workflow?.lockedBy
|
||||
? {
|
||||
@@ -1872,15 +2013,17 @@ export class ExpertClaimService {
|
||||
actorName: c.workflow.lockedBy.actorName,
|
||||
}
|
||||
: undefined,
|
||||
vehicle: c.vehicle
|
||||
vehicle: v
|
||||
? {
|
||||
carName: c.vehicle.carName,
|
||||
carModel: c.vehicle.carModel,
|
||||
carType: c.vehicle.carType,
|
||||
carName: v.carName,
|
||||
carModel: v.carModel,
|
||||
carType: v.carType,
|
||||
}
|
||||
: undefined,
|
||||
...fileCtx,
|
||||
createdAt: c.createdAt,
|
||||
})) as ClaimListItemV2Dto[];
|
||||
};
|
||||
}) as ClaimListItemV2Dto[];
|
||||
|
||||
return { list, total: list.length };
|
||||
}
|
||||
@@ -1967,6 +2110,32 @@ export class ExpertClaimService {
|
||||
};
|
||||
}
|
||||
|
||||
let vehiclePayload = claim.vehicle as any;
|
||||
const hasClaimVehicle =
|
||||
vehiclePayload &&
|
||||
(vehiclePayload.carName ||
|
||||
vehiclePayload.carModel ||
|
||||
vehiclePayload.carType ||
|
||||
vehiclePayload.plate);
|
||||
|
||||
let blameLean: any = null;
|
||||
if (claim.blameRequestId) {
|
||||
const rows = (await this.blameRequestDbService.find(
|
||||
{ _id: new Types.ObjectId(claim.blameRequestId.toString()) },
|
||||
{ lean: true, select: "type parties expert.decision" },
|
||||
)) as any[];
|
||||
blameLean = rows[0] ?? null;
|
||||
}
|
||||
|
||||
if (!hasClaimVehicle && blameLean) {
|
||||
const fromBlame = this.damagedPartyVehicleFromBlame(blameLean, claim);
|
||||
if (fromBlame) vehiclePayload = fromBlame;
|
||||
}
|
||||
|
||||
const blameFileContext = blameLean
|
||||
? this.blameFileContextForExpert(blameLean)
|
||||
: {};
|
||||
|
||||
return {
|
||||
claimRequestId: claim._id.toString(),
|
||||
publicId: claim.publicId,
|
||||
@@ -1988,7 +2157,8 @@ export class ExpertClaimService {
|
||||
fullName: claim.owner.fullName,
|
||||
}
|
||||
: undefined,
|
||||
vehicle: claim.vehicle,
|
||||
vehicle: vehiclePayload,
|
||||
...blameFileContext,
|
||||
blameRequestId: claim.blameRequestId?.toString(),
|
||||
blameRequestNo: claim.blameRequestNo,
|
||||
selectedParts: claim.damage?.selectedParts,
|
||||
|
||||
@@ -19,7 +19,12 @@ export function blameCaseTouchesClient(doc: any, clientKey: string): boolean {
|
||||
}
|
||||
|
||||
export function claimCaseTouchesClient(doc: any, clientKey: string): boolean {
|
||||
return String(doc?.owner?.userClientKey ?? "") === String(clientKey);
|
||||
const id = String(clientKey);
|
||||
const owner = doc?.owner as
|
||||
| { clientId?: unknown; userClientKey?: unknown }
|
||||
| undefined;
|
||||
const tenantId = owner?.clientId ?? owner?.userClientKey;
|
||||
return String(tenantId ?? "") === id;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
19
src/request-management/dto/claim-creation-hint.dto.ts
Normal file
19
src/request-management/dto/claim-creation-hint.dto.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
|
||||
/**
|
||||
* Computed on GET blame v2 for the current viewer — no DB field on BlameRequest.
|
||||
*/
|
||||
export class ClaimCreationHintDto {
|
||||
@ApiProperty({
|
||||
description:
|
||||
"True if a v2 claim case already exists for this blame (by blameRequestId).",
|
||||
})
|
||||
hasClaim: boolean;
|
||||
|
||||
@ApiProperty({
|
||||
description:
|
||||
"True when this viewer is the damaged party, blame is COMPLETED, no claim exists yet, " +
|
||||
"and for THIRD_PARTY all parties have signed and accepted the expert decision.",
|
||||
})
|
||||
shouldGuideToCreateClaim: boolean;
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import { RequestManagementModel } from "./entities/schema/request-management.sch
|
||||
import { BlameDocumentType } from "./entities/schema/blame-document.schema";
|
||||
import { SandHubDbService } from "src/sand-hub/entity/db-service/sand-hub.db.service";
|
||||
import { ClaimRequestManagementDbService } from "src/claim-request-management/entites/db-service/claim-request-management.db.service";
|
||||
import { ClaimCaseDbService } from "src/claim-request-management/entites/db-service/claim-case.db.service";
|
||||
import {
|
||||
CreationMethod,
|
||||
FilledBy,
|
||||
@@ -300,6 +301,7 @@ export class RequestManagementService {
|
||||
private readonly expertDbService: ExpertDbService,
|
||||
private readonly autoCloseRequestService: AutoCloseRequestService,
|
||||
private readonly claimRequestManagementDbService: ClaimRequestManagementDbService,
|
||||
private readonly claimCaseDbService: ClaimCaseDbService,
|
||||
private readonly publicIdService: PublicIdService,
|
||||
private readonly workflowStepDbService: WorkflowStepDbService,
|
||||
private readonly hashService: HashService,
|
||||
@@ -3916,6 +3918,81 @@ export class RequestManagementService {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* V2: Hint for UX — damaged user should open create-claim when blame is done and no claim exists.
|
||||
* Mirrors eligibility rules in createClaimFromBlameV2 (without throwing).
|
||||
*/
|
||||
private async computeClaimCreationHintForViewer(
|
||||
blame: any,
|
||||
user: any,
|
||||
): Promise<{ hasClaim: boolean; shouldGuideToCreateClaim: boolean }> {
|
||||
const none = { hasClaim: false, shouldGuideToCreateClaim: false };
|
||||
if (!user?.sub || !Types.ObjectId.isValid(String(user.sub))) {
|
||||
return none;
|
||||
}
|
||||
const currentUserId = String(user.sub);
|
||||
|
||||
const existingClaim = await this.claimCaseDbService.findOne({
|
||||
blameRequestId: blame._id,
|
||||
});
|
||||
const hasClaim = !!existingClaim;
|
||||
if (hasClaim) {
|
||||
return { hasClaim: true, shouldGuideToCreateClaim: false };
|
||||
}
|
||||
|
||||
if (blame.status !== CaseStatus.COMPLETED) {
|
||||
return { hasClaim: false, shouldGuideToCreateClaim: false };
|
||||
}
|
||||
|
||||
const parties = blame.parties || [];
|
||||
|
||||
if (blame.type === BlameRequestType.CAR_BODY) {
|
||||
const first = parties.find(
|
||||
(p: any) => p?.role === PartyRole.FIRST || p?.role === "FIRST",
|
||||
);
|
||||
const damagedId = first?.person?.userId
|
||||
? String(first.person.userId)
|
||||
: null;
|
||||
if (!damagedId || damagedId !== currentUserId) {
|
||||
return { hasClaim: false, shouldGuideToCreateClaim: false };
|
||||
}
|
||||
return { hasClaim: false, shouldGuideToCreateClaim: true };
|
||||
}
|
||||
|
||||
if (blame.type === BlameRequestType.THIRD_PARTY) {
|
||||
const guiltyRaw = blame.expert?.decision?.guiltyPartyId;
|
||||
if (!guiltyRaw) {
|
||||
return { hasClaim: false, shouldGuideToCreateClaim: false };
|
||||
}
|
||||
const guiltyId = String(guiltyRaw);
|
||||
if (currentUserId === guiltyId) {
|
||||
return { hasClaim: false, shouldGuideToCreateClaim: false };
|
||||
}
|
||||
const userParty = parties.find(
|
||||
(p: any) =>
|
||||
p?.person?.userId && String(p.person.userId) === currentUserId,
|
||||
);
|
||||
if (!userParty) {
|
||||
return { hasClaim: false, shouldGuideToCreateClaim: false };
|
||||
}
|
||||
if (parties.length < 2) {
|
||||
return { hasClaim: false, shouldGuideToCreateClaim: false };
|
||||
}
|
||||
const allSigned = parties.every(
|
||||
(p: any) => p.confirmation !== undefined && p.confirmation !== null,
|
||||
);
|
||||
const allAccepted = parties.every(
|
||||
(p: any) => p.confirmation?.accepted === true,
|
||||
);
|
||||
if (!allSigned || !allAccepted) {
|
||||
return { hasClaim: false, shouldGuideToCreateClaim: false };
|
||||
}
|
||||
return { hasClaim: false, shouldGuideToCreateClaim: true };
|
||||
}
|
||||
|
||||
return none;
|
||||
}
|
||||
|
||||
/**
|
||||
* V2: Get one blame request by id. Access allowed if current user is a party (by userId or phone)
|
||||
* or the initiating field expert. For expert-initiated LINK, party access by phone is sufficient.
|
||||
@@ -3958,7 +4035,13 @@ export class RequestManagementService {
|
||||
await (req as any).save();
|
||||
}
|
||||
}
|
||||
return req;
|
||||
|
||||
const claimCreation = await this.computeClaimCreationHintForViewer(req, user);
|
||||
const plain =
|
||||
typeof (req as any).toObject === "function"
|
||||
? (req as any).toObject({ versionKey: false })
|
||||
: { ...(req as any) };
|
||||
return { ...plain, claimCreation };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
ApiBearerAuth,
|
||||
ApiBody,
|
||||
ApiConsumes,
|
||||
ApiOperation,
|
||||
ApiParam,
|
||||
ApiTags,
|
||||
} from "@nestjs/swagger";
|
||||
@@ -77,6 +78,11 @@ export class RequestManagementV2Controller {
|
||||
* Get one blame request by id. Allowed for the request owner (party) or the initiating field expert.
|
||||
*/
|
||||
@Get(":requestId")
|
||||
@ApiOperation({
|
||||
summary: "Get one blame request (v2)",
|
||||
description:
|
||||
"Response is the blame document plus **claimCreation** ({ hasClaim, shouldGuideToCreateClaim }) — computed for the current user so the app can route the damaged party to create-claim when the blame is COMPLETED and no v2 claim exists yet.",
|
||||
})
|
||||
@ApiParam({ name: "requestId", description: "Blame request ID" })
|
||||
@Roles(RoleEnum.USER, RoleEnum.FIELD_EXPERT)
|
||||
async getBlameRequestV2(
|
||||
|
||||
@@ -102,7 +102,7 @@ export const createClaimWorkflowStepExamples = {
|
||||
description_en: 'Select other damaged parts (non-body), Sheba number and insurer national code',
|
||||
category: 'CLAIM',
|
||||
requiredPreviousSteps: ['SELECT_OUTER_PARTS'],
|
||||
nextPossibleSteps: ['UPLOAD_REQUIRED_DOCUMENTS'],
|
||||
nextPossibleSteps: ['CAPTURE_PART_DAMAGES'],
|
||||
allowedRoles: ['user'],
|
||||
estimatedDuration: 4,
|
||||
fields: [
|
||||
@@ -188,15 +188,15 @@ export const createClaimWorkflowStepExamples = {
|
||||
value: {
|
||||
stepKey: 'UPLOAD_REQUIRED_DOCUMENTS',
|
||||
type: 'CLAIM',
|
||||
stepNumber: 4,
|
||||
stepNumber: 5,
|
||||
isActive: true,
|
||||
stepName_fa: 'آپلود مدارک مورد نیاز',
|
||||
stepName_en: 'Upload Required Documents',
|
||||
description_fa: 'آپلود مدارک مورد نیاز برای بررسی خسارت (لیست داینامیک بر اساس قطعات انتخاب شده)',
|
||||
description_en: 'Upload required documents for claim review (dynamic list based on selected parts)',
|
||||
category: 'CLAIM',
|
||||
requiredPreviousSteps: ['SELECT_OTHER_PARTS'],
|
||||
nextPossibleSteps: ['CAPTURE_PART_DAMAGES'],
|
||||
requiredPreviousSteps: ['CAPTURE_PART_DAMAGES'],
|
||||
nextPossibleSteps: ['USER_SUBMISSION_COMPLETE'],
|
||||
allowedRoles: ['user'],
|
||||
estimatedDuration: 5,
|
||||
fields: [],
|
||||
@@ -215,15 +215,15 @@ export const createClaimWorkflowStepExamples = {
|
||||
value: {
|
||||
stepKey: 'CAPTURE_PART_DAMAGES',
|
||||
type: 'CLAIM',
|
||||
stepNumber: 5,
|
||||
stepNumber: 4,
|
||||
isActive: true,
|
||||
stepName_fa: 'ثبت تصاویر آسیبهای قطعات',
|
||||
stepName_en: 'Capture Part Damages',
|
||||
description_fa: 'ثبت تصاویر آسیب برای هر قطعه (یک درخواست به ازای هر قطعه)',
|
||||
description_en: 'Capture damage images for each part (one request per part)',
|
||||
category: 'CLAIM',
|
||||
requiredPreviousSteps: ['UPLOAD_REQUIRED_DOCUMENTS'],
|
||||
nextPossibleSteps: ['USER_SUBMISSION_COMPLETE'],
|
||||
requiredPreviousSteps: ['SELECT_OTHER_PARTS'],
|
||||
nextPossibleSteps: ['UPLOAD_REQUIRED_DOCUMENTS'],
|
||||
allowedRoles: ['user'],
|
||||
estimatedDuration: 10,
|
||||
fields: [],
|
||||
@@ -251,7 +251,7 @@ export const createClaimWorkflowStepExamples = {
|
||||
description_fa: 'اطلاعات کاربر به طور کامل ثبت شد و در انتظار بررسی کارشناس خسارت',
|
||||
description_en: 'User information completed, waiting for damage expert review',
|
||||
category: 'CLAIM',
|
||||
requiredPreviousSteps: ['CAPTURE_PART_DAMAGES'],
|
||||
requiredPreviousSteps: ['UPLOAD_REQUIRED_DOCUMENTS'],
|
||||
nextPossibleSteps: ['EXPERT_DAMAGE_ASSESSMENT'],
|
||||
allowedRoles: ['user', 'damage_expert', 'admin'],
|
||||
estimatedDuration: 0,
|
||||
|
||||
@@ -1158,7 +1158,7 @@ export const claimWorkflowStepExamples = {
|
||||
"description_en": "Select other damaged parts (non-body), Sheba number and insurer national code",
|
||||
"category": "CLAIM",
|
||||
"requiredPreviousSteps": ["SELECT_OUTER_PARTS"],
|
||||
"nextPossibleSteps": ["UPLOAD_REQUIRED_DOCUMENTS"],
|
||||
"nextPossibleSteps": ["CAPTURE_PART_DAMAGES"],
|
||||
"allowedRoles": ["user"],
|
||||
"estimatedDuration": 4,
|
||||
"fields": [
|
||||
@@ -1240,19 +1240,19 @@ export const claimWorkflowStepExamples = {
|
||||
},
|
||||
|
||||
uploadRequiredDocuments: {
|
||||
summary: 'Claim Step 4: UPLOAD_REQUIRED_DOCUMENTS',
|
||||
summary: 'Claim Step 5: UPLOAD_REQUIRED_DOCUMENTS',
|
||||
value: {
|
||||
"stepKey": "UPLOAD_REQUIRED_DOCUMENTS",
|
||||
"type": "CLAIM",
|
||||
"stepNumber": 4,
|
||||
"stepNumber": 5,
|
||||
"isActive": true,
|
||||
"stepName_fa": "آپلود مدارک مورد نیاز",
|
||||
"stepName_en": "Upload Required Documents",
|
||||
"description_fa": "آپلود مدارک مورد نیاز برای بررسی خسارت (لیست داینامیک بر اساس قطعات انتخاب شده)",
|
||||
"description_en": "Upload required documents for claim review (dynamic list based on selected parts)",
|
||||
"category": "CLAIM",
|
||||
"requiredPreviousSteps": ["SELECT_OTHER_PARTS"],
|
||||
"nextPossibleSteps": ["CAPTURE_PART_DAMAGES"],
|
||||
"requiredPreviousSteps": ["CAPTURE_PART_DAMAGES"],
|
||||
"nextPossibleSteps": ["USER_SUBMISSION_COMPLETE"],
|
||||
"allowedRoles": ["user"],
|
||||
"estimatedDuration": 5,
|
||||
"fields": [],
|
||||
@@ -1266,19 +1266,19 @@ export const claimWorkflowStepExamples = {
|
||||
},
|
||||
|
||||
capturePartDamages: {
|
||||
summary: 'Claim Step 5: CAPTURE_PART_DAMAGES',
|
||||
summary: 'Claim Step 4: CAPTURE_PART_DAMAGES',
|
||||
value: {
|
||||
"stepKey": "CAPTURE_PART_DAMAGES",
|
||||
"type": "CLAIM",
|
||||
"stepNumber": 5,
|
||||
"stepNumber": 4,
|
||||
"isActive": true,
|
||||
"stepName_fa": "ثبت تصاویر آسیبهای قطعات",
|
||||
"stepName_en": "Capture Part Damages",
|
||||
"description_fa": "ثبت تصاویر آسیب برای هر قطعه (یک درخواست به ازای هر قطعه)",
|
||||
"description_en": "Capture damage images for each part (one request per part)",
|
||||
"category": "CLAIM",
|
||||
"requiredPreviousSteps": ["UPLOAD_REQUIRED_DOCUMENTS"],
|
||||
"nextPossibleSteps": ["USER_SUBMISSION_COMPLETE"],
|
||||
"requiredPreviousSteps": ["SELECT_OTHER_PARTS"],
|
||||
"nextPossibleSteps": ["UPLOAD_REQUIRED_DOCUMENTS"],
|
||||
"allowedRoles": ["user"],
|
||||
"estimatedDuration": 10,
|
||||
"fields": [],
|
||||
@@ -1305,7 +1305,7 @@ export const claimWorkflowStepExamples = {
|
||||
"description_fa": "اطلاعات کاربر به طور کامل ثبت شد و در انتظار بررسی کارشناس خسارت",
|
||||
"description_en": "User information completed, waiting for damage expert review",
|
||||
"category": "CLAIM",
|
||||
"requiredPreviousSteps": ["CAPTURE_PART_DAMAGES"],
|
||||
"requiredPreviousSteps": ["UPLOAD_REQUIRED_DOCUMENTS"],
|
||||
"nextPossibleSteps": ["EXPERT_DAMAGE_ASSESSMENT"],
|
||||
"allowedRoles": ["user", "damage_expert", "admin"],
|
||||
"estimatedDuration": 0,
|
||||
|
||||
Reference in New Issue
Block a user