import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; import { Schema as MongooseSchema, Types } from "mongoose"; import { ExpertProfileSnapshot, ExpertProfileSnapshotSchema, } from "src/request-management/entities/schema/expert-profile-snapshot.schema"; import { FactorStatus } from "src/Types&Enums/claim-request-management/factor-status.enum"; import { UserReplyEnum } from "src/Types&Enums/claim-request-management/userReply.enum"; @Schema({ _id: false }) export class ClaimPartPricing { @Prop({ type: Number }) partId: number; /** * Unified outer-part snapshot `{ id?, name, side, label_fa, catalogKey? }` (same as * `damage.selectedParts` / capture). Legacy: string or `{ part?, side? }` (expert UI). * Must be Mixed — objects cannot cast to String. */ @Prop({ type: MongooseSchema.Types.Mixed }) carPartDamage?: unknown; @Prop({ type: String }) typeOfDamage?: string; @Prop({ type: MongooseSchema.Types.Mixed }) price?: string | number; @Prop({ type: MongooseSchema.Types.Mixed }) salary?: string | number; @Prop({ type: MongooseSchema.Types.Mixed }) totalPayment?: string | number; /** V1/V2: string/number legacy, or `{ option, price?, branchId? }` after expert normalization. */ @Prop({ type: MongooseSchema.Types.Mixed }) daghi?: string | number | Record; @Prop({ type: Boolean, default: false }) factorNeeded?: boolean; @Prop({ type: Types.ObjectId }) factorLink?: Types.ObjectId; @Prop({ type: String, enum: FactorStatus, default: null }) factorStatus?: FactorStatus | null; @Prop({ type: String, default: null }) rejectionReason?: string | null; } export const ClaimPartPricingSchema = SchemaFactory.createForClass(ClaimPartPricing); @Schema({ _id: false }) export class ClaimExpertActor { @Prop({ type: String }) actorName?: string; /** * Kept as string to support existing queries like: * `"damageExpertReply.actorDetail.actorId": actor.sub` */ @Prop({ type: String }) actorId?: string; } export const ClaimExpertActorSchema = SchemaFactory.createForClass(ClaimExpertActor); @Schema({ _id: false }) export class ClaimUserComment { @Prop({ type: Boolean, default: null }) isAccept?: boolean | null; @Prop({ type: Types.ObjectId }) signDetailId?: Types.ObjectId; } export const ClaimUserCommentSchema = SchemaFactory.createForClass(ClaimUserComment); /** Owner acceptance + signature after expert pricing (post-expert insurer `INSURER_REVIEW` — `INSURER_REVIEW_AWAITING_OWNER_SIGN` / `INSURER_REVIEW_MIXED_FACTORS_PENDING` / legacy `WAITING_FOR_INSURER_APPROVAL`). */ @Schema({ _id: false }) export class ClaimOwnerInsurerApproval { @Prop({ type: Boolean, required: true }) agree: boolean; /** Branch the owner is signing for (must belong to their insurer; aligned with expert daghi options when present). */ @Prop({ type: Types.ObjectId }) branchId?: Types.ObjectId; @Prop({ type: Types.ObjectId }) signDetailId?: Types.ObjectId; @Prop({ type: Date, default: () => new Date() }) signedAt?: Date; } export const ClaimOwnerInsurerApprovalSchema = SchemaFactory.createForClass(ClaimOwnerInsurerApproval); /** Owner signed acceptance of priced lines only — required before uploading factors when reply is mixed priced + factorNeeded. */ @Schema({ _id: false }) export class ClaimOwnerPricedPartsApproval { @Prop({ type: Boolean, required: true }) agree: boolean; @Prop({ type: Types.ObjectId }) branchId?: Types.ObjectId; @Prop({ type: Types.ObjectId }) signDetailId?: Types.ObjectId; @Prop({ type: Date, default: () => new Date() }) signedAt?: Date; } export const ClaimOwnerPricedPartsApprovalSchema = SchemaFactory.createForClass(ClaimOwnerPricedPartsApproval); @Schema({ _id: false }) export class ClaimExpertReply { @Prop({ type: String }) description?: string; @Prop({ type: ClaimExpertActorSchema }) actorDetail?: ClaimExpertActor; @Prop({ type: [ClaimPartPricingSchema], default: [] }) parts?: ClaimPartPricing[]; @Prop({ type: Date, default: () => new Date() }) submittedAt?: Date; @Prop({ type: ClaimUserCommentSchema }) userComment?: ClaimUserComment; /** Damage expert profile at reply time (from `damage-expert` collection). */ @Prop({ type: ExpertProfileSnapshotSchema }) expertProfileSnapshot?: ExpertProfileSnapshot; } export const ClaimExpertReplySchema = SchemaFactory.createForClass(ClaimExpertReply); /** One line item the user disputes on an expert-priced part */ @Schema({ _id: false }) export class ClaimUserObjectionPart { @Prop({ type: Number, required: true }) partId: number; @Prop({ type: String }) reason?: string; @Prop({ type: String }) partPrice?: string; @Prop({ type: String }) partSalary?: string; @Prop({ type: String }) typeOfDamage?: string; @Prop({ type: String }) carPartDamage?: string; @Prop({ type: String }) side?: string; } export const ClaimUserObjectionPartSchema = SchemaFactory.createForClass(ClaimUserObjectionPart); @Schema({ _id: false }) export class ClaimUserObjectionNewPart { /** Catalog id when known; otherwise a generated string id for the new line. */ @Prop({ type: MongooseSchema.Types.Mixed }) partId?: number | string; @Prop({ type: String, required: true }) partName: string; @Prop({ type: String }) side?: string; } export const ClaimUserObjectionNewPartSchema = SchemaFactory.createForClass(ClaimUserObjectionNewPart); /** * Full user objection payload (matches v1 DTO: objectionParts + newParts). * Stored on {@link ClaimEvaluation.objection}. */ @Schema({ _id: false }) export class ClaimUserObjectionPayload { @Prop({ type: [ClaimUserObjectionPartSchema], default: [] }) objectionParts?: ClaimUserObjectionPart[]; @Prop({ type: [ClaimUserObjectionNewPartSchema], default: [] }) newParts?: ClaimUserObjectionNewPart[]; @Prop({ type: Date, default: () => new Date() }) submittedAt?: Date; } export const ClaimUserObjectionPayloadSchema = SchemaFactory.createForClass(ClaimUserObjectionPayload); @Schema({ _id: false }) export class ClaimResendRequest { @Prop({ type: String }) resendDescription?: string; @Prop({ type: [MongooseSchema.Types.Mixed], default: [] }) resendDocuments?: any[]; @Prop({ type: [MongooseSchema.Types.Mixed], default: [] }) resendCarParts?: any[]; /** Set when the owner has satisfied every requested document/part (or acknowledged description-only resend). */ @Prop({ type: Date }) fulfilledAt?: Date; /** Damage expert profile when resend was requested (`damage-expert` collection). */ @Prop({ type: ExpertProfileSnapshotSchema }) expertProfileSnapshot?: ExpertProfileSnapshot; @Prop({ type: Types.ObjectId }) requestedByExpertId?: Types.ObjectId; } export const ClaimResendRequestSchema = SchemaFactory.createForClass(ClaimResendRequest); @Schema({ _id: false }) export class ClaimUserResendPayload { @Prop({ type: [MongooseSchema.Types.Mixed], default: [] }) documents?: any[]; @Prop({ type: [MongooseSchema.Types.Mixed], default: [] }) carParts?: any[]; } export const ClaimUserResendPayloadSchema = SchemaFactory.createForClass(ClaimUserResendPayload); @Schema({ _id: false }) export class ClaimFileRating { @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; } export const ClaimFileRatingSchema = SchemaFactory.createForClass(ClaimFileRating); @Schema({ _id: false }) export class ClaimPriceDrop { @Prop({ type: Number }) total?: number; @Prop({ type: Number }) carPrice?: number; @Prop({ type: Number }) carModel?: number; @Prop({ type: [Number], default: [] }) carValue?: number[]; @Prop({ type: Number }) sumOfSeverity?: number; @Prop({ type: Number }) coefficientYear?: number; @Prop({ type: [MongooseSchema.Types.Mixed], default: [] }) partLines?: Array>; } export const ClaimPriceDropSchema = SchemaFactory.createForClass(ClaimPriceDrop); @Schema({ _id: false }) export class ClaimEvaluation { @Prop({ type: String, enum: UserReplyEnum, default: null }) effectedUserReply?: UserReplyEnum | null; @Prop({ type: ClaimExpertReplySchema }) damageExpertReply?: ClaimExpertReply | null; @Prop({ type: ClaimExpertReplySchema }) damageExpertReplyFinal?: ClaimExpertReply | null; @Prop({ type: ClaimResendRequestSchema }) damageExpertResend?: ClaimResendRequest | null; @Prop({ type: ClaimUserObjectionPayloadSchema }) objection?: ClaimUserObjectionPayload; @Prop({ type: ClaimUserResendPayloadSchema }) userResendDocuments?: ClaimUserResendPayload; @Prop({ type: ClaimFileRatingSchema }) rating?: ClaimFileRating; @Prop({ type: ClaimOwnerInsurerApprovalSchema }) ownerInsurerApproval?: ClaimOwnerInsurerApproval; @Prop({ type: ClaimOwnerPricedPartsApprovalSchema }) ownerPricedPartsApproval?: ClaimOwnerPricedPartsApproval; @Prop({ type: String }) visitLocation?: string; @Prop({ type: ClaimPriceDropSchema }) priceDrop?: ClaimPriceDrop; /** Damage expert profile at last factor validation (`damage-expert` collection). */ @Prop({ type: ExpertProfileSnapshotSchema }) factorValidationExpertProfileSnapshot?: ExpertProfileSnapshot; /** Damage expert profile when in-person visit was requested (`damage-expert` collection). */ @Prop({ type: ExpertProfileSnapshotSchema }) inPersonVisitExpertProfileSnapshot?: ExpertProfileSnapshot; } export const ClaimEvaluationSchema = SchemaFactory.createForClass(ClaimEvaluation);