1
0
forked from Yara724/api

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,510 @@
/**
* Swagger example bodies for CLAIM workflow step management
*/
export const createClaimWorkflowStepExamples = {
claimCreated: {
summary: 'Claim Created Step',
value: {
stepKey: 'CLAIM_CREATED',
type: 'CLAIM',
stepNumber: 1,
isActive: true,
stepName_fa: 'ایجاد درخواست خسارت',
stepName_en: 'Create Claim Request',
description_fa: 'ایجاد درخواست خسارت از پرونده تعیین تقصیر تکمیل شده - فقط طرف آسیب‌دیده می‌تواند درخواست دهد',
description_en: 'Create claim request from completed blame case - only damaged party can proceed',
category: 'CLAIM',
requiredPreviousSteps: [],
nextPossibleSteps: ['SELECT_OUTER_PARTS'],
allowedRoles: ['user'],
estimatedDuration: 1,
fields: [],
metadata: {
icon: 'file-plus',
color: '#8B5CF6',
requiresBlameCase: true,
blameStatusRequired: 'COMPLETED',
bothPartiesMustAccept: true,
userMustBeDamagedParty: true
}
}
},
selectOuterParts: {
summary: 'Select Outer Parts Step',
value: {
stepKey: 'SELECT_OUTER_PARTS',
type: 'CLAIM',
stepNumber: 2,
isActive: true,
stepName_fa: 'انتخاب قطعات خارجی آسیب‌دیده',
stepName_en: 'Select Damaged Outer Parts',
description_fa: 'انتخاب قطعات خارجی خودرو که در حادثه آسیب دیده‌اند (کاپوت، درب‌ها، سپر و...)',
description_en: 'Select vehicle outer parts damaged in the accident (hood, doors, bumpers, etc.)',
category: 'CLAIM',
requiredPreviousSteps: ['CLAIM_CREATED'],
nextPossibleSteps: ['SELECT_OTHER_PARTS'],
allowedRoles: ['user'],
estimatedDuration: 3,
fields: [
{
id: '67fa10c259e15f231a2d1001',
name_fa: 'قطعات خارجی',
name_en: 'outerParts',
label_fa: 'قطعات خارجی آسیب‌دیده',
label_en: 'Damaged Outer Parts',
placeholder_fa: 'قطعات خارجی آسیب‌دیده را انتخاب کنید',
placeholder_en: 'Select damaged outer parts',
value: [
{ label_fa: 'کاپوت', label_en: 'Hood', value: 'hood' },
{ label_fa: 'درب جلو راست', label_en: 'Front Right Door', value: 'front_right_door' },
{ label_fa: 'درب جلو چپ', label_en: 'Front Left Door', value: 'front_left_door' },
{ label_fa: 'درب عقب راست', label_en: 'Rear Right Door', value: 'rear_right_door' },
{ label_fa: 'درب عقب چپ', label_en: 'Rear Left Door', value: 'rear_left_door' },
{ label_fa: 'سپر جلو', label_en: 'Front Bumper', value: 'front_bumper' },
{ label_fa: 'سپر عقب', label_en: 'Rear Bumper', value: 'rear_bumper' },
{ label_fa: 'گلگیر جلو راست', label_en: 'Front Right Fender', value: 'front_right_fender' },
{ label_fa: 'گلگیر جلو چپ', label_en: 'Front Left Fender', value: 'front_left_fender' },
{ label_fa: 'گلگیر عقب راست', label_en: 'Rear Right Fender', value: 'rear_right_fender' },
{ label_fa: 'گلگیر عقب چپ', label_en: 'Rear Left Fender', value: 'rear_left_fender' },
{ label_fa: 'صندوق عقب', label_en: 'Trunk', value: 'trunk' },
{ label_fa: 'سقف', label_en: 'Roof', value: 'roof' }
],
dataType: 'multiselect',
required: true,
order: 1,
isActive: true,
validation: {
minItems: 1,
maxItems: 13
}
}
],
metadata: {
icon: 'car',
color: '#3B82F6',
requiresMultipleSelection: true
}
}
},
selectOtherParts: {
summary: 'Select Other Parts & Bank Info Step',
value: {
stepKey: 'SELECT_OTHER_PARTS',
type: 'CLAIM',
stepNumber: 3,
isActive: true,
stepName_fa: 'انتخاب سایر قطعات و اطلاعات بانکی',
stepName_en: 'Select Other Parts & Bank Information',
description_fa: 'انتخاب سایر قطعات آسیب‌دیده (غیر از بدنه)، شماره شبا و کد ملی بیمه‌گذار',
description_en: 'Select other damaged parts (non-body), Sheba number and insurer national code',
category: 'CLAIM',
requiredPreviousSteps: ['SELECT_OUTER_PARTS'],
nextPossibleSteps: ['UPLOAD_REQUIRED_DOCUMENTS'],
allowedRoles: ['user'],
estimatedDuration: 4,
fields: [
{
id: '67fa10c259e15f231a2d1002',
name_fa: 'سایر قطعات',
name_en: 'otherParts',
label_fa: 'سایر قطعات آسیب‌دیده',
label_en: 'Other Damaged Parts',
placeholder_fa: 'سایر قطعات آسیب‌دیده را انتخاب کنید',
placeholder_en: 'Select other damaged parts',
value: [
{ label_fa: 'موتور', label_en: 'Engine', value: 'engine' },
{ label_fa: 'سیستم تعلیق', label_en: 'Suspension', value: 'suspension' },
{ label_fa: 'سیستم ترمز', label_en: 'Brake System', value: 'brake_system' },
{ label_fa: 'سیستم برق', label_en: 'Electrical System', value: 'electrical' },
{ label_fa: 'رادیاتور', label_en: 'Radiator', value: 'radiator' },
{ label_fa: 'گیربکس', label_en: 'Transmission', value: 'transmission' },
{ label_fa: 'اگزوز', label_en: 'Exhaust', value: 'exhaust' },
{ label_fa: 'چراغ جلو', label_en: 'Headlight', value: 'headlight' },
{ label_fa: 'چراغ عقب', label_en: 'Taillight', value: 'taillight' },
{ label_fa: 'آینه', label_en: 'Mirror', value: 'mirror' },
{ label_fa: 'شیشه', label_en: 'Glass', value: 'glass' }
],
dataType: 'multiselect',
required: false,
order: 1,
isActive: true,
validation: {
minItems: 0,
maxItems: 11
}
},
{
id: '67fa10c259e15f231a2d1003',
name_fa: 'شماره شبا',
name_en: 'shebaNumber',
label_fa: 'شماره شبا',
label_en: 'Sheba Number',
placeholder_fa: 'شماره شبا (24 رقم بدون IR)',
placeholder_en: 'Sheba number (24 digits without IR)',
value: null,
dataType: 'string',
required: true,
order: 2,
isActive: true,
validation: {
pattern: '^[0-9]{24}$',
minLength: 24,
maxLength: 24
}
},
{
id: '67fa10c259e15f231a2d1004',
name_fa: 'کد ملی مالک',
name_en: 'nationalCodeOfOwner',
label_fa: 'کد ملی مالک',
label_en: 'National Code of Owner',
placeholder_fa: 'کد ملی 10 رقمی مالک',
placeholder_en: '10-digit national code of owner',
value: null,
dataType: 'string',
required: true,
order: 3,
isActive: true,
validation: {
pattern: '^[0-9]{10}$',
minLength: 10,
maxLength: 10
}
}
],
metadata: {
icon: 'list',
color: '#10B981',
requiresBankInfo: true
}
}
},
uploadRequiredDocuments: {
summary: 'Upload Required Documents Step',
value: {
stepKey: 'UPLOAD_REQUIRED_DOCUMENTS',
type: 'CLAIM',
stepNumber: 4,
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'],
allowedRoles: ['user'],
estimatedDuration: 5,
fields: [],
metadata: {
icon: 'upload',
color: '#F59E0B',
dynamicFields: true,
requiresAPI: '/claim-request-management/car-part-image-required/:claimRequestID',
note: 'لیست مدارک به صورت داینامیک از API دریافت می‌شود'
}
}
},
capturePartDamages: {
summary: 'Capture Part Damages Step',
value: {
stepKey: 'CAPTURE_PART_DAMAGES',
type: 'CLAIM',
stepNumber: 5,
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'],
allowedRoles: ['user'],
estimatedDuration: 10,
fields: [],
metadata: {
icon: 'camera',
color: '#EF4444',
dynamicFields: true,
requiresAPI: '/claim-request-management/capture-car-part-damage/:claimRequestID/:partId',
requiresCamera: true,
multipleRequests: true,
note: 'برای هر قطعه یک درخواست جداگانه ارسال می‌شود'
}
}
},
userSubmissionComplete: {
summary: 'User Submission Complete',
value: {
stepKey: 'USER_SUBMISSION_COMPLETE',
type: 'CLAIM',
stepNumber: 6,
isActive: true,
stepName_fa: 'تکمیل ثبت اطلاعات کاربر',
stepName_en: 'User Submission Complete',
description_fa: 'اطلاعات کاربر به طور کامل ثبت شد و در انتظار بررسی کارشناس خسارت',
description_en: 'User information completed, waiting for damage expert review',
category: 'CLAIM',
requiredPreviousSteps: ['CAPTURE_PART_DAMAGES'],
nextPossibleSteps: ['EXPERT_DAMAGE_ASSESSMENT'],
allowedRoles: ['user', 'damage_expert', 'admin'],
estimatedDuration: 0,
fields: [],
metadata: {
icon: 'check-circle',
color: '#10B981',
readOnly: true,
isSystemStep: true
}
}
},
expertDamageAssessment: {
summary: 'Expert Damage Assessment',
value: {
stepKey: 'EXPERT_DAMAGE_ASSESSMENT',
type: 'CLAIM',
stepNumber: 7,
isActive: true,
stepName_fa: 'ارزیابی خسارت توسط کارشناس',
stepName_en: 'Expert Damage Assessment',
description_fa: 'بررسی و ارزیابی خسارت توسط کارشناس خسارت',
description_en: 'Damage review and assessment by damage expert',
category: 'EXPERT',
requiredPreviousSteps: ['USER_SUBMISSION_COMPLETE'],
nextPossibleSteps: ['EXPERT_COST_EVALUATION'],
allowedRoles: ['damage_expert', 'admin'],
estimatedDuration: 30,
fields: [
{
id: '67fa10c259e15f231a2d1005',
name_fa: 'وضعیت ارزیابی',
name_en: 'assessmentStatus',
label_fa: 'وضعیت ارزیابی',
label_en: 'Assessment Status',
placeholder_fa: 'وضعیت ارزیابی را انتخاب کنید',
placeholder_en: 'Select assessment status',
value: [
{ label_fa: 'تایید شده', label_en: 'Approved', value: 'approved' },
{ label_fa: 'نیاز به بازنگری', label_en: 'Needs Revision', value: 'needs_revision' },
{ label_fa: 'رد شده', label_en: 'Rejected', value: 'rejected' }
],
dataType: 'select',
required: true,
order: 1,
isActive: true,
validation: {
enum: ['approved', 'needs_revision', 'rejected']
}
},
{
id: '67fa10c259e15f231a2d1006',
name_fa: 'توضیحات کارشناس',
name_en: 'expertComments',
label_fa: 'توضیحات کارشناس',
label_en: 'Expert Comments',
placeholder_fa: 'توضیحات خود را وارد کنید',
placeholder_en: 'Enter your comments',
value: null,
dataType: 'textarea',
required: true,
order: 2,
isActive: true,
validation: {
minLength: 10,
maxLength: 2000
}
}
],
metadata: {
icon: 'clipboard-check',
color: '#8B5CF6',
requiresExpertRole: true
}
}
},
expertCostEvaluation: {
summary: 'Expert Cost Evaluation',
value: {
stepKey: 'EXPERT_COST_EVALUATION',
type: 'CLAIM',
stepNumber: 8,
isActive: true,
stepName_fa: 'برآورد هزینه توسط کارشناس',
stepName_en: 'Expert Cost Evaluation',
description_fa: 'محاسبه و برآورد هزینه تعمیرات توسط کارشناس',
description_en: 'Repair cost calculation and estimation by expert',
category: 'EXPERT',
requiredPreviousSteps: ['EXPERT_DAMAGE_ASSESSMENT'],
nextPossibleSteps: ['INSURER_REVIEW'],
allowedRoles: ['damage_expert', 'admin'],
estimatedDuration: 20,
fields: [
{
id: '67fa10c259e15f231a2d1007',
name_fa: 'هزینه کل برآورد شده',
name_en: 'estimatedTotalCost',
label_fa: 'هزینه کل برآورد شده (ریال)',
label_en: 'Estimated Total Cost (Rials)',
placeholder_fa: 'مبلغ را وارد کنید',
placeholder_en: 'Enter amount',
value: null,
dataType: 'number',
required: true,
order: 1,
isActive: true,
validation: {
min: 0,
max: 999999999999
}
},
{
id: '67fa10c259e15f231a2d1008',
name_fa: 'جزئیات هزینه',
name_en: 'costBreakdown',
label_fa: 'جزئیات هزینه',
label_en: 'Cost Breakdown',
placeholder_fa: 'جزئیات هزینه را وارد کنید',
placeholder_en: 'Enter cost breakdown',
value: null,
dataType: 'textarea',
required: true,
order: 2,
isActive: true,
validation: {
minLength: 20,
maxLength: 5000
}
}
],
metadata: {
icon: 'dollar-sign',
color: '#F59E0B',
requiresExpertRole: true,
requiresCostCalculation: true
}
}
},
insurerReview: {
summary: 'Insurer Review',
value: {
stepKey: 'INSURER_REVIEW',
type: 'CLAIM',
stepNumber: 9,
isActive: true,
stepName_fa: 'بررسی بیمه‌گر',
stepName_en: 'Insurer Review',
description_fa: 'بررسی نهایی و تایید یا رد خسارت توسط بیمه‌گر',
description_en: 'Final review and approval/rejection by insurer',
category: 'INSURER',
requiredPreviousSteps: ['EXPERT_COST_EVALUATION'],
nextPossibleSteps: ['CLAIM_COMPLETED'],
allowedRoles: ['insurer', 'admin'],
estimatedDuration: 60,
fields: [
{
id: '67fa10c259e15f231a2d1009',
name_fa: 'تصمیم بیمه‌گر',
name_en: 'insurerDecision',
label_fa: 'تصمیم بیمه‌گر',
label_en: 'Insurer Decision',
placeholder_fa: 'تصمیم خود را انتخاب کنید',
placeholder_en: 'Select your decision',
value: [
{ label_fa: 'تایید', label_en: 'Approved', value: 'approved' },
{ label_fa: 'رد', label_en: 'Rejected', value: 'rejected' }
],
dataType: 'select',
required: true,
order: 1,
isActive: true,
validation: {
enum: ['approved', 'rejected']
}
},
{
id: '67fa10c259e15f231a2d100a',
name_fa: 'توضیحات بیمه‌گر',
name_en: 'insurerNotes',
label_fa: 'توضیحات بیمه‌گر',
label_en: 'Insurer Notes',
placeholder_fa: 'توضیحات خود را وارد کنید',
placeholder_en: 'Enter your notes',
value: null,
dataType: 'textarea',
required: true,
order: 2,
isActive: true,
validation: {
minLength: 10,
maxLength: 2000
}
}
],
metadata: {
icon: 'shield-check',
color: '#6366F1',
requiresInsurerRole: true,
isFinalStep: false
}
}
},
claimCompleted: {
summary: 'Claim Completed',
value: {
stepKey: 'CLAIM_COMPLETED',
type: 'CLAIM',
stepNumber: 10,
isActive: true,
stepName_fa: 'تکمیل خسارت',
stepName_en: 'Claim Completed',
description_fa: 'خسارت به طور کامل بررسی و نتیجه‌گیری شده است',
description_en: 'Claim has been fully reviewed and concluded',
category: 'FINAL',
requiredPreviousSteps: ['INSURER_REVIEW'],
nextPossibleSteps: [],
allowedRoles: ['user', 'damage_expert', 'insurer', 'admin'],
estimatedDuration: 0,
fields: [],
metadata: {
icon: 'check-circle',
color: '#10B981',
readOnly: true,
isSystemStep: true,
isFinalStep: true
}
}
}
};
export const updateClaimWorkflowStepExamples = {
example1: {
summary: 'Update claim step name',
value: {
stepName_fa: 'انتخاب قطعات خارجی - بروزرسانی شده',
stepName_en: 'Select Outer Parts - Updated',
category: 'CLAIM',
isActive: true
}
},
example2: {
summary: 'Update claim step metadata',
value: {
metadata: {
icon: 'car',
color: '#10B981',
requiresMultipleSelection: true,
priority: 'high'
}
}
}
};

View File

@@ -0,0 +1,254 @@
import { IsNotEmpty, IsString, IsNumber, IsBoolean, IsOptional, IsArray, IsEnum, ValidateNested, IsObject } from 'class-validator';
import { Type } from 'class-transformer';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { ClaimWorkflowStep } from 'src/Types&Enums/claim-request-management/claim-workflow-steps.enum';
import { WorkflowStep } from 'src/Types&Enums/blame-request-management/blameWorkflow-steps.enum';
import { Types } from 'mongoose';
// Combined enum for validation
const AllWorkflowSteps = { ...WorkflowStep, ...ClaimWorkflowStep };
export class ClaimStepFieldDto {
@ApiProperty({
description: 'Unique identifier for the field',
example: '67fa10c259e15f231a2d1001'
})
@IsNotEmpty()
id: Types.ObjectId;
@ApiProperty({
description: 'Field name in Farsi',
example: 'قطعات خارجی'
})
@IsNotEmpty()
@IsString()
name_fa: string;
@ApiProperty({
description: 'Field name in English',
example: 'outerParts'
})
@IsNotEmpty()
@IsString()
name_en: string;
@ApiPropertyOptional({
description: 'Field label in Farsi',
example: 'قطعات خارجی آسیب‌دیده'
})
@IsOptional()
@IsString()
label_fa?: string;
@ApiPropertyOptional({
description: 'Field label in English',
example: 'Damaged Outer Parts'
})
@IsOptional()
@IsString()
label_en?: string;
@ApiPropertyOptional({
description: 'Placeholder text in Farsi',
example: 'قطعات خارجی آسیب‌دیده را انتخاب کنید'
})
@IsOptional()
@IsString()
placeholder_fa?: string;
@ApiPropertyOptional({
description: 'Placeholder text in English',
example: 'Select damaged outer parts'
})
@IsOptional()
@IsString()
placeholder_en?: string;
@ApiPropertyOptional({
description: 'Possible values for select/multiselect fields (null for non-select fields)',
example: null,
nullable: true,
default: null
})
@IsOptional()
value?: Object[] | null;
@ApiProperty({
description: 'Data type of the field',
example: 'multiselect',
enum: ['string', 'number', 'boolean', 'date', 'select', 'multiselect', 'file', 'textarea', 'email', 'phone', 'object']
})
@IsNotEmpty()
@IsString()
dataType: string;
@ApiPropertyOptional({
description: 'Whether the field is required',
example: true,
default: false
})
@IsOptional()
@IsBoolean()
required?: boolean;
@ApiPropertyOptional({
description: 'Validation rules for the field',
example: { minItems: 1, maxItems: 13 }
})
@IsOptional()
@IsObject()
validation?: Object;
@ApiPropertyOptional({
description: 'Display order of the field in the form',
example: 1
})
@IsOptional()
@IsNumber()
order?: number;
@ApiPropertyOptional({
description: 'Whether the field is active',
example: true,
default: true
})
@IsOptional()
@IsBoolean()
isActive?: boolean;
}
export class CreateClaimWorkflowStepDto {
@ApiProperty({
description: 'Unique key identifying the claim workflow step',
example: 'CLAIM_CREATED',
enum: AllWorkflowSteps
})
@IsNotEmpty()
@IsEnum(AllWorkflowSteps)
stepKey: ClaimWorkflowStep | WorkflowStep;
@ApiProperty({
description: 'Workflow type: CLAIM for claim workflow',
example: 'CLAIM',
default: 'CLAIM'
})
@IsNotEmpty()
@IsString()
type: string;
@ApiProperty({
description: 'Order number of the step in the claim workflow',
example: 1
})
@IsNotEmpty()
@IsNumber()
stepNumber: number;
@ApiPropertyOptional({
description: 'Whether the step is active',
example: true,
default: true
})
@IsOptional()
@IsBoolean()
isActive?: boolean;
@ApiProperty({
description: 'Step name in Farsi',
example: 'ایجاد درخواست خسارت'
})
@IsNotEmpty()
@IsString()
stepName_fa: string;
@ApiProperty({
description: 'Step name in English',
example: 'Create Claim Request'
})
@IsNotEmpty()
@IsString()
stepName_en: string;
@ApiPropertyOptional({
description: 'Step description in Farsi',
example: 'ایجاد درخواست خسارت از پرونده تعیین تقصیر تکمیل شده'
})
@IsOptional()
@IsString()
description_fa?: string;
@ApiPropertyOptional({
description: 'Step description in English',
example: 'Create claim request from completed blame case'
})
@IsOptional()
@IsString()
description_en?: string;
@ApiPropertyOptional({
description: 'Category of the step',
example: 'CLAIM',
enum: ['CLAIM', 'EXPERT', 'INSURER', 'FINAL']
})
@IsOptional()
@IsString()
category?: string;
@ApiPropertyOptional({
description: 'Dynamic fields for this step',
type: [ClaimStepFieldDto],
example: []
})
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => ClaimStepFieldDto)
fields?: ClaimStepFieldDto[];
@ApiPropertyOptional({
description: 'Steps that must be completed before this step',
example: [],
enum: AllWorkflowSteps,
isArray: true
})
@IsOptional()
@IsArray()
@IsEnum(AllWorkflowSteps, { each: true })
requiredPreviousSteps?: (ClaimWorkflowStep | WorkflowStep)[];
@ApiPropertyOptional({
description: 'Possible next steps after completing this step',
example: ['SELECT_OUTER_PARTS'],
enum: AllWorkflowSteps,
isArray: true
})
@IsOptional()
@IsArray()
@IsEnum(AllWorkflowSteps, { each: true })
nextPossibleSteps?: (ClaimWorkflowStep | WorkflowStep)[];
@ApiPropertyOptional({
description: 'Additional metadata for the step',
example: { icon: 'file-plus', color: '#8B5CF6' }
})
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
@ApiPropertyOptional({
description: 'Estimated duration in minutes',
example: 1
})
@IsOptional()
@IsNumber()
estimatedDuration?: number;
@ApiPropertyOptional({
description: 'Roles allowed to access this step',
example: ['user', 'damage_expert', 'admin']
})
@IsOptional()
@IsArray()
@IsString({ each: true })
allowedRoles?: string[];
}

View File

@@ -0,0 +1,271 @@
import { IsNotEmpty, IsString, IsNumber, IsBoolean, IsOptional, IsArray, IsEnum, ValidateNested, IsObject } from 'class-validator';
import { Type } from 'class-transformer';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { WorkflowStep } from 'src/Types&Enums/blame-request-management/blameWorkflow-steps.enum';
import { ClaimWorkflowStep } from 'src/Types&Enums/claim-request-management/claim-workflow-steps.enum';
import { Types } from 'mongoose';
// Combined enum for validation
const AllWorkflowSteps = { ...WorkflowStep, ...ClaimWorkflowStep };
export class StepFieldDto {
@ApiProperty({
description: 'Unique identifier for the field',
example: '507f1f77bcf86cd799439011'
})
@IsNotEmpty()
id: Types.ObjectId;
@ApiProperty({
description: 'Field name in Farsi',
example: 'فایل ویدیو'
})
@IsNotEmpty()
@IsString()
name_fa: string;
@ApiProperty({
description: 'Field name in English',
example: 'videoFile'
})
@IsNotEmpty()
@IsString()
name_en: string;
@ApiPropertyOptional({
description: 'Field label in Farsi',
example: 'فایل ویدیو'
})
@IsOptional()
@IsString()
label_fa?: string;
@ApiPropertyOptional({
description: 'Field label in English',
example: 'Video File'
})
@IsOptional()
@IsString()
label_en?: string;
@ApiPropertyOptional({
description: 'Placeholder text in Farsi',
example: 'فایل ویدیو خود را آپلود کنید'
})
@IsOptional()
@IsString()
placeholder_fa?: string;
@ApiPropertyOptional({
description: 'Placeholder text in English',
example: 'Upload your video file'
})
@IsOptional()
@IsString()
placeholder_en?: string;
@ApiPropertyOptional({
description: 'Possible values for select/multiselect fields (null for non-select fields)',
example: null,
nullable: true,
default: null
})
@IsOptional()
value?: Object[] | null;
@ApiProperty({
description: 'Data type of the field',
example: 'file',
enum: ['string', 'number', 'boolean', 'date', 'select', 'multiselect', 'file', 'textarea', 'email', 'phone']
})
@IsNotEmpty()
@IsString()
dataType: string;
@ApiPropertyOptional({
description: 'Whether the field is required',
example: true,
default: false
})
@IsOptional()
@IsBoolean()
required?: boolean;
@ApiPropertyOptional({
description: 'Validation rules for the field',
example: { maxSize: 52428800, allowedTypes: ['video/mp4', 'video/webm'] }
})
@IsOptional()
@IsObject()
validation?: Object;
@ApiPropertyOptional({
description: 'Display order of the field in the form',
example: 1
})
@IsOptional()
@IsNumber()
order?: number;
@ApiPropertyOptional({
description: 'Whether the field is active',
example: true,
default: true
})
@IsOptional()
@IsBoolean()
isActive?: boolean;
}
export class CreateWorkflowStepDto {
@ApiProperty({
description: 'Unique key identifying the workflow step (blame or claim)',
example: 'FIRST_VIDEO',
enum: AllWorkflowSteps
})
@IsNotEmpty()
@IsEnum(AllWorkflowSteps)
stepKey: WorkflowStep | ClaimWorkflowStep;
@ApiProperty({
description: 'Workflow type: THIRD_PARTY (blame) or CLAIM (claim workflow)',
example: 'THIRD_PARTY',
enum: ['THIRD_PARTY', 'CLAIM']
})
@IsNotEmpty()
@IsString()
type: string;
@ApiProperty({
description: 'Order number of the step within this workflow type',
example: 2
})
@IsNotEmpty()
@IsNumber()
stepNumber: number;
@ApiPropertyOptional({
description: 'Whether the step is active',
example: true,
default: true
})
@IsOptional()
@IsBoolean()
isActive?: boolean;
@ApiProperty({
description: 'Step name in Farsi',
example: 'ویدیو طرف اول'
})
@IsNotEmpty()
@IsString()
stepName_fa: string;
@ApiProperty({
description: 'Step name in English',
example: 'First Party Video'
})
@IsNotEmpty()
@IsString()
stepName_en: string;
@ApiPropertyOptional({
description: 'Step description in Farsi',
example: 'ضبط ویدیو توسط طرف اول'
})
@IsOptional()
@IsString()
description_fa?: string;
@ApiPropertyOptional({
description: 'Step description in English',
example: 'Video capture by first party'
})
@IsOptional()
@IsString()
description_en?: string;
@ApiPropertyOptional({
description: 'Category of the step within workflow (e.g., INITIAL, FIRST_PARTY, EXPERT)',
example: 'FIRST_PARTY',
enum: ['INITIAL', 'FIRST_PARTY', 'SECOND_PARTY', 'CLAIM', 'EXPERT', 'INSURER', 'FINAL']
})
@IsOptional()
@IsString()
category?: string;
@ApiPropertyOptional({
description: 'Dynamic fields for this step',
type: [StepFieldDto],
example: [
{
id: '507f1f77bcf86cd799439011',
name_fa: 'فایل ویدیو',
name_en: 'videoFile',
label_fa: 'فایل ویدیو',
label_en: 'Video File',
value: null,
dataType: 'file',
required: true,
order: 1,
isActive: true,
validation: {
maxSize: 52428800,
allowedTypes: ['video/mp4', 'video/webm']
}
}
]
})
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => StepFieldDto)
fields?: StepFieldDto[];
@ApiPropertyOptional({
description: 'Steps that must be completed before this step',
example: ['CREATED'],
enum: AllWorkflowSteps,
isArray: true
})
@IsOptional()
@IsArray()
@IsEnum(AllWorkflowSteps, { each: true })
requiredPreviousSteps?: (WorkflowStep | ClaimWorkflowStep)[];
@ApiPropertyOptional({
description: 'Possible next steps after completing this step',
example: ['FIRST_INITIAL_FORM'],
enum: AllWorkflowSteps,
isArray: true
})
@IsOptional()
@IsArray()
@IsEnum(AllWorkflowSteps, { each: true })
nextPossibleSteps?: (WorkflowStep | ClaimWorkflowStep)[];
@ApiPropertyOptional({
description: 'Additional metadata for the step',
example: { icon: 'video', color: '#3B82F6' }
})
@IsOptional()
@IsObject()
metadata?: Record<string, any>;
@ApiPropertyOptional({
description: 'Estimated duration in minutes',
example: 5
})
@IsOptional()
@IsNumber()
estimatedDuration?: number;
@ApiPropertyOptional({
description: 'Roles allowed to access this step',
example: ['user', 'expert', 'admin']
})
@IsOptional()
@IsArray()
@IsString({ each: true })
allowedRoles?: string[];
}

View File

@@ -0,0 +1,8 @@
import { PartialType } from '@nestjs/swagger';
import { CreateWorkflowStepDto } from './create-workflow-step.dto';
/**
* Update DTO inherits all fields from Create DTO but makes them all optional
* Supports both blame and claim workflow steps
*/
export class UpdateWorkflowStepDto extends PartialType(CreateWorkflowStepDto) {}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,156 @@
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { WorkflowStepModel, WorkflowStepsDB } from '../schema/workflow-step.schema';
import { CreateWorkflowStepDto } from '../../dto/create-workflow-step.dto';
import { UpdateWorkflowStepDto } from '../../dto/update-workflow-step.dto';
import { WorkflowStep } from 'src/Types&Enums/blame-request-management/blameWorkflow-steps.enum';
import { ClaimWorkflowStep } from 'src/Types&Enums/claim-request-management/claim-workflow-steps.enum';
// Type alias for combined workflow steps
type AnyWorkflowStep = WorkflowStep | ClaimWorkflowStep;
@Injectable()
export class WorkflowStepDbService {
constructor(
@InjectModel(WorkflowStepsDB)
private readonly workflowStepModel: Model<WorkflowStepModel>,
) {}
/**
* Create a new workflow step
*/
async create(createDto: CreateWorkflowStepDto): Promise<WorkflowStepModel> {
const created = new this.workflowStepModel(createDto);
return await created.save();
}
/**
* Find all active workflow steps
*/
async findAll(): Promise<WorkflowStepModel[]> {
return await this.workflowStepModel
.find({ isActive: true })
.sort({ stepNumber: 1 })
.exec();
}
/**
* Find all workflow steps including inactive ones
*/
async findAllIncludingInactive(): Promise<WorkflowStepModel[]> {
return await this.workflowStepModel
.find()
.sort({ stepNumber: 1 })
.exec();
}
/**
* Find a workflow step by ID
*/
async findById(id: string): Promise<WorkflowStepModel | null> {
return await this.workflowStepModel.findById(id).exec();
}
/**
* Find a workflow step by step key (supports both blame and claim)
*/
async findByStepKey(stepKey: AnyWorkflowStep): Promise<WorkflowStepModel | null> {
return await this.workflowStepModel.findOne({ stepKey }).exec();
}
/**
* Find a workflow step by step number
*/
async findByStepNumber(stepNumber: number): Promise<WorkflowStepModel | null> {
return await this.workflowStepModel.findOne({ stepNumber }).exec();
}
/**
* Find steps by category
*/
async findByCategory(category: string): Promise<WorkflowStepModel[]> {
return await this.workflowStepModel
.find({ category, isActive: true })
.sort({ stepNumber: 1 })
.exec();
}
/**
* Update a workflow step by ID
*/
async update(id: string, updateDto: UpdateWorkflowStepDto): Promise<WorkflowStepModel | null> {
return await this.workflowStepModel
.findByIdAndUpdate(id, updateDto, { new: true })
.exec();
}
/**
* Update a workflow step by step key (supports both blame and claim)
*/
async updateByStepKey(
stepKey: AnyWorkflowStep,
updateDto: UpdateWorkflowStepDto,
): Promise<WorkflowStepModel | null> {
return await this.workflowStepModel
.findOneAndUpdate({ stepKey }, updateDto, { new: true })
.exec();
}
/**
* Soft delete (deactivate) a workflow step
*/
async remove(id: string): Promise<WorkflowStepModel | null> {
return await this.workflowStepModel
.findByIdAndUpdate(id, { isActive: false }, { new: true })
.exec();
}
/**
* Upsert a workflow step by step key (supports both blame and claim)
*/
async upsertByStepKey(
stepKey: AnyWorkflowStep,
data: CreateWorkflowStepDto | UpdateWorkflowStepDto,
): Promise<WorkflowStepModel> {
return await this.workflowStepModel
.findOneAndUpdate({ stepKey }, data, { upsert: true, new: true })
.exec();
}
/**
* Bulk upsert workflow steps
*/
async bulkUpsert(steps: CreateWorkflowStepDto[]): Promise<any> {
const bulkOps = steps.map((step) => ({
updateOne: {
filter: { stepKey: step.stepKey },
update: { $set: step as any },
upsert: true,
},
}));
return await this.workflowStepModel.bulkWrite(bulkOps as any);
}
/**
* Get the next step number
*/
async getNextStepNumber(): Promise<number> {
const maxStep = await this.workflowStepModel
.findOne()
.sort({ stepNumber: -1 })
.select('stepNumber')
.exec();
return maxStep ? maxStep.stepNumber + 1 : 1;
}
/**
* Check if a step exists (supports both blame and claim)
*/
async exists(stepKey: AnyWorkflowStep): Promise<boolean> {
const count = await this.workflowStepModel.countDocuments({ stepKey }).exec();
return count > 0;
}
}

View File

@@ -0,0 +1,119 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Types } from 'mongoose';
import { WorkflowStep } from 'src/Types&Enums/blame-request-management/blameWorkflow-steps.enum';
import { ClaimWorkflowStep } from 'src/Types&Enums/claim-request-management/claim-workflow-steps.enum';
// Combined enum values for both blame and claim workflows
const allWorkflowSteps = [...Object.values(WorkflowStep), ...Object.values(ClaimWorkflowStep)];
export const WorkflowStepsDB = 'WorkflowSteps';
export type FieldValueType = Object | string | number | boolean | null;
/**
* Field definition for dynamic form generation
* Each step can have multiple fields that represent form inputs
*/
@Schema({ _id: false })
export class StepField {
@Prop({ required: true, type: Types.ObjectId })
id: Types.ObjectId;
@Prop({ required: true, type: String })
name_fa: string;
@Prop({ required: true, type: String })
name_en: string;
@Prop({ type: String })
label_fa?: string;
@Prop({ type: String })
label_en?: string;
@Prop({ type: String })
placeholder_fa?: string;
@Prop({ type: String })
placeholder_en?: string;
@Prop({ type: [Object], default: null })
value: Object[] | null;
@Prop({ required: true, type: String })
dataType: string; // e.g., 'string', 'number', 'boolean', 'date', 'select', 'multiselect', 'file', etc.
@Prop({ type: Boolean, default: false })
required?: boolean;
@Prop({ type: Object })
validation?: Object; // Validation rules (min, max, pattern, etc.)
@Prop({ type: Number })
order?: number; // Field order in the form
@Prop({ type: Boolean, default: true })
isActive?: boolean;
}
export const StepFieldSchema = SchemaFactory.createForClass(StepField);
/**
* Workflow Step Model
* Defines the configuration for each step in the workflow
*/
@Schema({ versionKey: false, collection: 'workflowSteps', timestamps: true })
export class WorkflowStepModel {
@Prop({ required: true, type: String, enum: allWorkflowSteps, unique: true })
stepKey: WorkflowStep | ClaimWorkflowStep;
@Prop({ required: true, type: String })
type: string; // 'THIRD_PARTY' (blame workflow) or 'CLAIM' (claim workflow)
@Prop({ required: true, type: Number })
stepNumber: number;
@Prop({ type: Boolean, default: true })
isActive: boolean;
@Prop({ required: true, type: String })
stepName_fa: string;
@Prop({ required: true, type: String })
stepName_en: string;
@Prop({ type: String })
description_fa?: string;
@Prop({ type: String })
description_en?: string;
@Prop({ type: String })
category?: string; // e.g., 'INITIAL', 'FIRST_PARTY', 'SECOND_PARTY', 'EXPERT', 'INSURER'
@Prop({ type: [StepFieldSchema], default: [] })
fields?: StepField[];
@Prop({ type: [String], enum: allWorkflowSteps, default: [] })
requiredPreviousSteps?: (WorkflowStep | ClaimWorkflowStep)[]; // Steps that must be completed before this step
@Prop({ type: [String], enum: allWorkflowSteps, default: [] })
nextPossibleSteps?: (WorkflowStep | ClaimWorkflowStep)[]; // Possible next steps after completing this step
@Prop({ type: Object })
metadata?: Record<string, any>; // Additional metadata for the step
@Prop({ type: Number })
estimatedDuration?: number; // Estimated duration in minutes
@Prop({ type: [String], default: [] })
allowedRoles?: string[]; // Roles allowed to access this step
}
export const WorkflowStepSchema = SchemaFactory.createForClass(WorkflowStepModel);
// Create indexes for better query performance
WorkflowStepSchema.index({ stepKey: 1 }); // Unique via @Prop
WorkflowStepSchema.index({ type: 1, isActive: 1 }); // Query by workflow type
WorkflowStepSchema.index({ type: 1, stepNumber: 1 }, { unique: true }); // Unique stepNumber within workflow type
WorkflowStepSchema.index({ type: 1, category: 1, stepNumber: 1 }); // Sorting within workflow and category

View File

@@ -0,0 +1,8 @@
export * from './workflow-step-management.module';
export * from './workflow-step-management.service';
export * from './workflow-step-management.controller';
export * from './dto/create-workflow-step.dto';
export * from './dto/update-workflow-step.dto';
export * from './dto/workflow-step.examples';
export * from './entities/schema/workflow-step.schema';
export * from './entities/db-service/workflow-step.db.service';

View File

@@ -0,0 +1,353 @@
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
Query,
HttpCode,
HttpStatus,
} from '@nestjs/common';
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiBody,
ApiParam,
ApiQuery,
ApiBearerAuth
} from '@nestjs/swagger';
import { WorkflowStepManagementService } from './workflow-step-management.service';
import { CreateWorkflowStepDto } from './dto/create-workflow-step.dto';
import { UpdateWorkflowStepDto } from './dto/update-workflow-step.dto';
import { WorkflowStep } from 'src/Types&Enums/blame-request-management/blameWorkflow-steps.enum';
import { ClaimWorkflowStep } from 'src/Types&Enums/claim-request-management/claim-workflow-steps.enum';
import {
createWorkflowStepExamples,
updateWorkflowStepExamples,
bulkUpsertWorkflowStepExamples,
validateAccessExamples,
claimWorkflowStepExamples,
} from './dto/workflow-step.examples';
@ApiTags('Workflow Step Management')
@Controller('workflow-step-management')
export class WorkflowStepManagementController {
constructor(
private readonly workflowStepManagementService: WorkflowStepManagementService,
) {}
/**
* Create a new workflow step configuration
*/
@Post()
@HttpCode(HttpStatus.CREATED)
@ApiOperation({
summary: 'Create a new workflow step',
description: 'Creates a new workflow step configuration with fields and validation rules'
})
@ApiBody({
type: CreateWorkflowStepDto,
examples: {
...createWorkflowStepExamples,
...claimWorkflowStepExamples
}
})
@ApiResponse({ status: 201, description: 'Workflow step created successfully' })
@ApiResponse({ status: 400, description: 'Bad request - Invalid input data' })
@ApiResponse({ status: 409, description: 'Conflict - Step already exists' })
async create(@Body() createDto: CreateWorkflowStepDto) {
return await this.workflowStepManagementService.create(createDto);
}
/**
* Get all active workflow steps
*/
@Get()
@ApiOperation({
summary: 'Get all workflow steps',
description: 'Retrieves all workflow steps, optionally including inactive ones'
})
@ApiQuery({
name: 'includeInactive',
required: false,
type: String,
description: 'Set to "true" to include inactive steps',
example: 'false'
})
@ApiResponse({ status: 200, description: 'List of workflow steps retrieved successfully' })
async findAll(@Query('includeInactive') includeInactive?: string) {
if (includeInactive === 'true') {
return await this.workflowStepManagementService.findAllIncludingInactive();
}
return await this.workflowStepManagementService.findAll();
}
/**
* Update a workflow step by ID
*/
@Patch(':id')
@ApiOperation({
summary: 'Update workflow step by ID',
description: 'Updates a workflow step using its database ID'
})
@ApiParam({ name: 'id', description: 'Workflow step ID', example: '507f1f77bcf86cd799439011' })
@ApiBody({
type: UpdateWorkflowStepDto,
examples: updateWorkflowStepExamples
})
@ApiResponse({ status: 200, description: 'Workflow step updated successfully' })
@ApiResponse({ status: 404, description: 'Workflow step not found' })
async update(@Param('id') id: string, @Body() updateDto: UpdateWorkflowStepDto) {
return await this.workflowStepManagementService.update(id, updateDto);
}
/**
* Update a workflow step by key
*/
@Patch('step/:stepKey')
@ApiOperation({
summary: 'Update workflow step by key',
description: 'Updates a workflow step using its step key from the enum'
})
@ApiParam({
name: 'stepKey',
description: 'Workflow step key (blame or claim)',
example: 'FIRST_VIDEO'
})
@ApiBody({
type: UpdateWorkflowStepDto,
examples: updateWorkflowStepExamples
})
@ApiResponse({ status: 200, description: 'Workflow step updated successfully' })
@ApiResponse({ status: 404, description: 'Workflow step not found' })
async updateByStepKey(
@Param('stepKey') stepKey: WorkflowStep | ClaimWorkflowStep,
@Body() updateDto: UpdateWorkflowStepDto,
) {
return await this.workflowStepManagementService.updateByStepKey(stepKey as any, updateDto);
}
/**
* Initialize default workflow steps
*/
@Post('initialize')
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: 'Initialize default workflow steps',
description: 'Creates default workflow step configurations for the system'
})
@ApiResponse({ status: 200, description: 'Default steps initialized successfully' })
async initialize() {
return await this.workflowStepManagementService.initializeDefaultSteps();
}
/**
* Get a specific step by stepKey or stepNumber (intelligent lookup)
*/
@Get('find/:identifier')
@ApiOperation({
summary: 'Get workflow step by stepKey or stepNumber',
description: 'Retrieves a workflow step by either its stepKey (enum) or stepNumber. Automatically detects which one is provided.'
})
@ApiParam({
name: 'identifier',
description: 'Step key (e.g., "FIRST_VIDEO") or step number (e.g., 3)',
example: 'FIRST_VIDEO',
examples: {
byStepKey: {
summary: 'By Step Key',
value: 'FIRST_VIDEO'
},
byStepNumber: {
summary: 'By Step Number',
value: 3
}
}
})
@ApiResponse({ status: 200, description: 'Workflow step retrieved successfully' })
@ApiResponse({ status: 404, description: 'Workflow step not found' })
async findByStepKeyOrNumber(@Param('identifier') identifier: string) {
return await this.workflowStepManagementService.findByStepKeyOrNumber(identifier);
}
/**
* Get a specific step by ID
*/
@Get(':id')
@ApiOperation({
summary: 'Get workflow step by ID',
description: 'Retrieves a specific workflow step by its database ID'
})
@ApiParam({ name: 'id', description: 'Workflow step ID', example: '507f1f77bcf86cd799439011' })
@ApiResponse({ status: 200, description: 'Workflow step retrieved successfully' })
@ApiResponse({ status: 404, description: 'Workflow step not found' })
async findById(@Param('id') id: string) {
return await this.workflowStepManagementService.findById(id);
}
/**
* Soft delete a step
*/
@Delete(':id')
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: 'Delete workflow step',
description: 'Soft deletes a workflow step by setting isActive to false'
})
@ApiParam({ name: 'id', description: 'Workflow step ID', example: '507f1f77bcf86cd799439011' })
@ApiResponse({ status: 200, description: 'Workflow step deleted successfully' })
@ApiResponse({ status: 404, description: 'Workflow step not found' })
async remove(@Param('id') id: string) {
return await this.workflowStepManagementService.remove(id);
}
// ============================================================
// DEPRECATED ENDPOINTS - Will be removed in future versions
// ============================================================
/**
* @deprecated Use individual create endpoint instead
* Bulk upsert steps (for initial setup or migrations)
*/
@Post('bulk-upsert')
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: '[DEPRECATED] Bulk upsert workflow steps',
description: 'This endpoint is deprecated and will be removed in a future version. Use the individual create endpoint instead.',
deprecated: true
})
@ApiBody({
type: [CreateWorkflowStepDto],
examples: bulkUpsertWorkflowStepExamples
})
@ApiResponse({ status: 200, description: 'Steps upserted successfully' })
async bulkUpsert(@Body() steps: CreateWorkflowStepDto[]) {
return await this.workflowStepManagementService.bulkUpsert(steps);
}
/**
* @deprecated This endpoint is no longer needed
* Validate step access
*/
@Post('validate-access')
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: '[DEPRECATED] Validate step access',
description: 'This endpoint is deprecated and will be removed in a future version.',
deprecated: true
})
@ApiBody({
schema: {
type: 'object',
properties: {
stepKey: {
type: 'string',
description: 'Workflow step key (blame or claim)',
example: 'FIRST_VIDEO'
},
completedSteps: {
type: 'array',
items: {
type: 'string'
},
example: ['CREATED']
}
}
},
examples: validateAccessExamples
})
@ApiResponse({ status: 200, description: 'Validation result returned' })
async validateAccess(
@Body() body: { stepKey: WorkflowStep | ClaimWorkflowStep; completedSteps: (WorkflowStep | ClaimWorkflowStep)[] },
) {
return await this.workflowStepManagementService.validateStepAccess(
body.stepKey as any,
body.completedSteps as any,
);
}
/**
* @deprecated This endpoint is no longer needed
* Get steps by category
*/
@Get('category/:category')
@ApiOperation({
summary: '[DEPRECATED] Get steps by category',
description: 'This endpoint is deprecated and will be removed in a future version.',
deprecated: true
})
@ApiParam({
name: 'category',
description: 'Step category',
example: 'FIRST_PARTY',
enum: ['INITIAL', 'FIRST_PARTY', 'SECOND_PARTY', 'RESOLUTION']
})
@ApiResponse({ status: 200, description: 'Steps retrieved successfully' })
async findByCategory(@Param('category') category: string) {
return await this.workflowStepManagementService.findByCategory(category);
}
/**
* @deprecated This endpoint is no longer needed
* Get next possible steps from current step
*/
@Get('next-steps/:stepKey')
@ApiOperation({
summary: '[DEPRECATED] Get next possible steps',
description: 'This endpoint is deprecated and will be removed in a future version.',
deprecated: true
})
@ApiParam({
name: 'stepKey',
description: 'Current workflow step key (blame or claim)',
example: 'FIRST_VIDEO'
})
@ApiResponse({ status: 200, description: 'Next steps retrieved successfully' })
async getNextSteps(@Param('stepKey') stepKey: WorkflowStep | ClaimWorkflowStep) {
return await this.workflowStepManagementService.getNextSteps(stepKey as any);
}
/**
* @deprecated This endpoint is no longer needed
* Get step fields (for form generation)
*/
@Get('fields/:stepKey')
@ApiOperation({
summary: '[DEPRECATED] Get step fields',
description: 'This endpoint is deprecated and will be removed in a future version.',
deprecated: true
})
@ApiParam({
name: 'stepKey',
description: 'Workflow step key (blame or claim)',
example: 'FIRST_VIDEO'
})
@ApiResponse({ status: 200, description: 'Step fields retrieved successfully' })
async getStepFields(@Param('stepKey') stepKey: WorkflowStep | ClaimWorkflowStep) {
return await this.workflowStepManagementService.getStepFields(stepKey as any);
}
/**
* @deprecated Use findById instead
* Get a specific step by key
*/
@Get('step/:stepKey')
@ApiOperation({
summary: '[DEPRECATED] Get workflow step by key',
description: 'This endpoint is deprecated and will be removed in a future version. Use GET /:id instead.',
deprecated: true
})
@ApiParam({
name: 'stepKey',
description: 'Workflow step key (blame or claim)',
example: 'FIRST_VIDEO'
})
@ApiResponse({ status: 200, description: 'Workflow step retrieved successfully' })
@ApiResponse({ status: 404, description: 'Workflow step not found' })
async findByStepKey(@Param('stepKey') stepKey: WorkflowStep | ClaimWorkflowStep) {
return await this.workflowStepManagementService.findByStepKey(stepKey as any);
}
}

View File

@@ -0,0 +1,21 @@
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { WorkflowStepManagementService } from './workflow-step-management.service';
import { WorkflowStepManagementController } from './workflow-step-management.controller';
import { WorkflowStepDbService } from './entities/db-service/workflow-step.db.service';
import {
WorkflowStepsDB,
WorkflowStepSchema,
} from './entities/schema/workflow-step.schema';
@Module({
imports: [
MongooseModule.forFeature([
{ name: WorkflowStepsDB, schema: WorkflowStepSchema },
]),
],
controllers: [WorkflowStepManagementController],
providers: [WorkflowStepManagementService, WorkflowStepDbService],
exports: [WorkflowStepManagementService, WorkflowStepDbService],
})
export class WorkflowStepManagementModule {}

File diff suppressed because it is too large Load Diff