1
0
forked from Yara724/api
Files
yara724-api/src/claim-request-management/entites/schema/claim-case.evaluation.schema.ts
SepehrYahyaee e1954cdb37 YARA-885
2026-05-18 11:00:53 +03:30

321 lines
9.3 KiB
TypeScript

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: String })
partId: string;
/**
* 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<string, unknown>;
@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: String, required: true })
partId: string;
@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 {
@Prop({ type: String })
partId?: 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;
}
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);