forked from Yara724/api
blame and claim refactored
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user