Files
yara724api/src/request-management/entities/schema/request-management.schema.ts

478 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import { Types } from "mongoose";
import {
ResendFirstPartyDto,
ResendSecondPartyDto,
} from "src/expert-blame/dto/reply.dto";
import { AddPlateDto } from "src/profile/dto/user/AddPlateDto";
import { ReqBlameStatus } from "src/Types&Enums/blame-request-management/status.enum";
import { StepsEnum } from "src/Types&Enums/blame-request-management/steps.enum";
export class InitialForm {
@Prop({ required: false, default: false })
expertOpinion?: boolean;
@Prop({ required: false, default: false })
imDamaged?: boolean;
@Prop({ required: false, default: false })
imGuilty?: boolean;
}
export class FirstPartyFile {
@Prop()
descriptions?: string[];
@Prop()
voices?: string[];
@Prop()
firstPartyVideoId?: string;
// CAR_BODY specific accident details
@Prop({ type: Date })
accidentDate?: Date;
@Prop()
accidentTime?: string;
@Prop()
weatherCondition?: string;
@Prop()
roadCondition?: string;
@Prop()
lightCondition?: string;
}
export class CarDetail {
carName?: string;
carModel?: string;
carType?: string;
isNewCar?: boolean;
insurerBirthday?: string;
driverBirthday?: string | null;
}
export class InsuranceDetail {
insuranceId?: string;
insuranceCompany?: string;
financialCommitmentCeiling?: string;
startDate?: string;
endDate?: string;
}
// CAR_BODY specific insurance details for the damaged party
export class CarBodyInsuranceDetail {
@Prop()
policyNumber?: string;
@Prop()
startDate?: string;
@Prop()
endDate?: string;
@Prop()
insurerCompany?: string;
@Prop({ type: [String] })
coverages?: string[];
}
export class SecondPartyFile {
@Prop()
descriptions?: string[];
@Prop()
voices?: string[];
@Prop()
secondPartyVideoId?: string;
}
export class FirstPartyClient {
clientName?: string;
clientId?: Types.ObjectId;
}
export class SecondPartyClient {
clientName?: string;
clientId?: Types.ObjectId;
}
export class FirstPartyDetail {
@Prop({ type: String })
firstPartyId?: Types.ObjectId;
@Prop({ type: String })
firstPartyPhoneNumber?: string;
@Prop({ type: String })
firstPartyClientId?: string;
@Prop({
type: AddPlateDto,
description: "first add plate and send plate id to this field",
})
firstPartyPlate?: AddPlateDto;
@Prop({ type: CarDetail })
firstPartyCarDetail?: CarDetail;
@Prop({ type: InsuranceDetail })
firstPartyInsuranceDetail?: InsuranceDetail;
// Only used for CAR_BODY type requests car body insurance info
@Prop({ type: CarBodyInsuranceDetail })
firstPartyCarBodyInsuranceDetail?: CarBodyInsuranceDetail;
@Prop({ type: FirstPartyFile })
firstPartyClient?: FirstPartyClient;
@Prop({ type: FirstPartyFile })
firstPartyFile?: FirstPartyFile;
@Prop({ type: FirstPartyFile })
firstPartyInitialForm?: InitialForm;
@Prop({ type: Boolean })
firstPartyCertificate: boolean | null;
}
export class SecondPartyDetail {
@Prop({ type: String })
secondPartyId?: Types.ObjectId;
@Prop({ type: String })
secondPartyPhoneNumber?: string;
@Prop({ type: SecondPartyClient })
secondPartyClient?: SecondPartyClient;
@Prop({
type: AddPlateDto,
description: "secondParty add plate and send plate id to this field",
})
secondPartyPlate?: AddPlateDto;
@Prop()
secondPartyCarDetail?: CarDetail;
@Prop({ type: InsuranceDetail })
secondPartyInsuranceDetail?: InsuranceDetail;
@Prop()
secondPartyPlateId?: string;
@Prop({ type: InitialForm })
secondPartyInitialForm: InitialForm;
@Prop({ type: SecondPartyFile })
secondPartyFiles?: SecondPartyFile;
}
export class LocationDto {
@Prop({ type: Number, required: true })
lat: number;
@Prop({ type: Number, required: true })
lon: number;
}
export class AccidentWayIF {
@Prop({ required: true })
id: string;
@Prop({ required: true })
label: string;
}
export class AccidentReasonIF {
@Prop({ required: true })
id: string;
@Prop({ required: true })
label: string;
@Prop({ required: true })
fanavaran: number;
}
export class FieldsInterface {
@Prop({ required: true, type: AccidentWayIF })
accidentWay: AccidentWayIF;
@Prop({ required: true, type: AccidentReasonIF })
accidentReason: AccidentReasonIF;
@Prop({ required: true, type: AccidentWayIF })
accidentType: AccidentWayIF;
}
export class SignDetail {
@Prop()
fileId: string;
@Prop()
fileName: string;
@Prop()
fileUrl: string;
}
export class PartiesComment {
@Prop({ required: true, type: Boolean })
isAccept?: boolean;
@Prop({ required: true })
signDetail?: SignDetail;
}
export class SubmitReply {
@Prop({ required: true })
description: string;
@Prop({ required: true, type: String })
guiltyUserId: Types.ObjectId;
@Prop({ required: true })
fields: FieldsInterface;
@Prop({ required: true, default: () => new Date() })
submitTime: Date;
@Prop({ type: PartiesComment })
firstPartyComment?: PartiesComment;
@Prop({ type: PartiesComment })
secondPartyComment?: PartiesComment;
@Prop()
systemResponse: string;
}
export class ExpertResendParties {
userId?: Types.ObjectId;
description?: string;
}
export class ExpertResendReply {
// TODO change DTOs to dynamic Exmple SubmitReply Parties comment
@Prop()
firstParty?: ResendFirstPartyDto;
@Prop()
secondParty?: ResendSecondPartyDto;
}
export class ActorLockDetails {
@Prop({ type: String })
fullName?: string;
@Prop({ type: Types.ObjectId })
actorId?: Types.ObjectId;
}
export enum CreationMethod {
NORMAL = "NORMAL",
LINK = "LINK",
IN_PERSON = "IN_PERSON",
}
export enum FilledBy {
CUSTOMER = "customer",
EXPERT = "expert",
}
export class ExpertLinkInfo {
@Prop({ type: String, required: true })
token: string;
@Prop({ type: Date, required: true })
expiresAt: Date;
@Prop({ type: Boolean, default: false })
isUsed: boolean;
@Prop({ type: Boolean, default: false })
isExpired: boolean;
@Prop({ type: Date })
generatedAt: Date;
@Prop({ type: String })
sentTo?: string; // Phone number or email
@Prop({ type: Number, default: 0 })
openCount: number;
@Prop({ type: Date })
lastOpenedAt?: Date;
@Prop({ type: Date })
usedAt?: Date;
}
export class FileHistoryEvent {
@Prop({ type: String, required: true })
eventType: string; // "LINK_SENT", "LINK_OPENED", "FILLED_BY_CUSTOMER", "FILLED_BY_EXPERT", "ASSIGNED_TO_EXPERT", "EVALUATION_STARTED", "EVALUATION_COMPLETED", "USER_ACCEPTED", "USER_REJECTED", "SENT_TO_FANAVARAN", "CODE_RECEIVED"
@Prop({ type: Types.ObjectId })
actorId?: Types.ObjectId;
@Prop({ type: String })
actorName?: string;
@Prop({ type: String })
actorType?: string; // "expert", "damage_expert", "customer"
@Prop({ type: Date, default: () => new Date() })
timestamp: Date;
@Prop({ type: Object })
metadata?: any; // Additional event-specific data
}
@Schema({ _id: false })
export class FileRating {
@Prop({ type: Number, min: 0, max: 5 })
collisionMethodAccuracy: number;
@Prop({ type: Number, min: 0, max: 5 })
evaluationTimeliness: number;
@Prop({ type: Number, min: 0, max: 5 })
accidentCauseAccuracy: number;
@Prop({ type: Number, min: 0, max: 5 })
guiltyVehicleIdentification: number;
@Prop({ type: Number, min: 0, max: 5 })
botRating: number;
}
// TODO clean all sub Object to other files
export type RequestManagementDocs = RequestManagementModel & Document;
@Schema({
collection: "requests-management",
versionKey: false,
timestamps: true,
autoIndex: true,
_id: true,
})
export class RequestManagementModel {
@Prop({ type: String, required: false })
type: string;
@Prop({ type: String, required: true, index: { unique: true } })
requestNumber: string;
/**
* Human-friendly shared id across blame+claim (e.g. A14235).
* Generated once at creation time and reused by claim.
*
* NOTE: `sparse` keeps existing documents without this field valid.
*/
@Prop({ type: String, unique: true, index: true, sparse: true, trim: true })
publicId?: string;
@Prop()
blameStatus: ReqBlameStatus | StepsEnum;
@Prop()
steps?: StepsEnum[];
@Prop()
userComment?: string;
@Prop()
currentStep: StepsEnum;
@Prop()
nextStep?: StepsEnum;
@Prop({ description: "first step" })
initialForm?: InitialForm;
@Prop({ required: false })
firstPartyDetails?: FirstPartyDetail;
@Prop({ required: false, type: Types.ObjectId })
sanHubId?: Types.ObjectId;
@Prop({ required: false })
secondPartyDetails?: SecondPartyDetail;
@Prop({ required: false, description: "third step call" })
firstPartyLocation?: LocationDto;
@Prop({ required: false })
secondPartyLocation?: LocationDto;
@Prop({ type: Date, default: Date.now })
createdAt?: Date | string;
@Prop({ type: Date, default: Date.now })
updatedAt?: Date;
@Prop()
lockFile?: boolean;
@Prop({ type: Date })
lockTime?: Date | string | number;
@Prop({ type: Date })
unlockTime?: Date | number;
@Prop()
actorLocked?: ActorLockDetails;
@Prop()
actorsChecker?: [];
@Prop({ required: false })
expertSubmitReply?: SubmitReply | null;
@Prop()
expertResendReply?: ExpertResendReply;
@Prop()
expertSubmitReplyFinal?: ExpertResendReply;
@Prop({ type: FileRating, required: false })
rating?: FileRating;
@Prop({ type: Date, required: false })
autoCloseTriggerTime?: Date;
@Prop({ type: Boolean, default: false })
isHandledStatsUpdated?: boolean;
// Expert-initiated file tracking
@Prop({ type: Boolean, default: false })
expertInitiated?: boolean;
@Prop({ type: Types.ObjectId })
initiatedBy?: Types.ObjectId; // Expert who started the process
@Prop({ type: String, enum: FilledBy })
filledBy?: FilledBy; // Who filled the information
@Prop({ type: String, enum: CreationMethod, default: CreationMethod.NORMAL })
creationMethod?: CreationMethod; // How the file was created
@Prop({ type: ExpertLinkInfo })
expertLink?: ExpertLinkInfo; // Link information if created via link
@Prop({ type: [FileHistoryEvent], default: [] })
history?: FileHistoryEvent[]; // Timeline of events
@Prop({ type: Types.ObjectId })
assignedExpertId?: Types.ObjectId; // Expert assigned for evaluation (should be same as initiatedBy for expert-initiated files)
}
export const RequestManagementSchema = SchemaFactory.createForClass(
RequestManagementModel,
);