import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; import { HydratedDocument, Schema as MongooseSchema, Types } from "mongoose"; import { ClaimRequiredDocumentType } from "src/Types&Enums/claim-request-management/required-document-type.enum"; import { ClaimStatus } from "src/Types&Enums/claim-request-management/claimStatus.enum"; import { ClaimCaseStatus } from "src/Types&Enums/claim-request-management/claim-case-status.enum"; import { HistoryEvent, HistoryEventSchema, } from "src/request-management/entities/schema/historyEvent.type"; import { ClaimDamageSelection, ClaimDamageSelectionSchema, } from "./claim-case.damage.schema"; import { ClaimMoney, ClaimMoneySchema, ClaimOwner, ClaimOwnerSchema, ClaimVehicleSnapshot, ClaimVehicleSnapshotSchema, } from "./claim-case.identity.schema"; import { ClaimMedia, ClaimMediaSchema } from "./claim-case.media.schema"; import { ClaimEvaluation, ClaimEvaluationSchema, } from "./claim-case.evaluation.schema"; import { ClaimCaseSnapshot, ClaimCaseSnapshotSchema, } from "./claim-case.snapshot.schema"; import { ClaimWorkflow, ClaimWorkflowSchema, } from "./claim-case.workflow.schema"; import { UserClaimRating } from "./claim-request-management.schema"; import { CaseInquiries, CaseInquiriesSchema, } from "src/common/schema/case-inquiries.schema"; @Schema({ _id: false }) export class RequiredDocumentRef { @Prop({ type: Types.ObjectId }) fileId?: Types.ObjectId; @Prop({ type: String }) filePath?: string; @Prop({ type: String }) fileName?: string; @Prop({ type: Boolean, default: true }) uploaded?: boolean; @Prop({ type: Date }) uploadedAt?: Date; } export const RequiredDocumentRefSchema = SchemaFactory.createForClass(RequiredDocumentRef); @Schema({ _id: false }) export class FanavaranSyncStage { @Prop({ type: String }) status?: "pending" | "success" | "failed" | "skipped"; @Prop({ type: Date }) lastTriedAt?: Date; @Prop({ type: String }) lastError?: string; @Prop({ type: Number }) claimId?: number; @Prop({ type: Number }) claimNo?: number; @Prop({ type: Number }) dmgCaseId?: number; @Prop({ type: Number }) expertiseId?: number; @Prop({ type: [MongooseSchema.Types.Mixed], default: [] }) files?: unknown[]; @Prop({ type: MongooseSchema.Types.Mixed }) response?: unknown; } export const FanavaranSyncStageSchema = SchemaFactory.createForClass(FanavaranSyncStage); @Schema({ _id: false }) export class FanavaranSyncState { @Prop({ type: FanavaranSyncStageSchema }) baseClaim?: FanavaranSyncStage; @Prop({ type: FanavaranSyncStageSchema }) damageCase?: FanavaranSyncStage; @Prop({ type: FanavaranSyncStageSchema }) attachments?: FanavaranSyncStage; @Prop({ type: FanavaranSyncStageSchema }) expertise?: FanavaranSyncStage; } export const FanavaranSyncStateSchema = SchemaFactory.createForClass(FanavaranSyncState); @Schema({ collection: "claimCases", timestamps: true, id: true, versionKey: false, }) export class ClaimCase { @Prop({ required: true, unique: true, index: true, trim: true }) requestNo: string; /** * Human-friendly shared id across blame+claim (e.g. A14235). * Generated once on blame creation and copied into claim. */ @Prop({ required: true, unique: true, index: true, trim: true }) publicId: string; /** * Overall case status (user flow + expert flow progression) */ @Prop({ required: true, type: String, enum: ClaimCaseStatus, default: ClaimCaseStatus.CREATED, }) status: ClaimCaseStatus; /** * Claim damage determination status (expert assessment) */ @Prop({ type: String, enum: ClaimStatus, default: ClaimStatus.PENDING }) claimStatus: ClaimStatus; /** * Set while the linked blame file is in WAITING_FOR_DOCUMENT_RESEND so the claim flow can block or message the user. */ @Prop({ default: false }) blameDocumentResendPending?: boolean; /** * Link to the blame case that originated this claim. * IMPORTANT: this is intentionally ONLY an id reference (no embedded blame file). */ @Prop({ type: Types.ObjectId, index: true }) blameRequestId?: Types.ObjectId; @Prop({ type: String, index: true }) blameRequestNo?: string; /** * Set when this claim was created by a field expert on behalf of the damaged * party (expert-initiated IN_PERSON flow). Used to scope the expert's panel * access to only their own initiated files. */ @Prop({ type: Types.ObjectId, index: true }) initiatedByFieldExpertId?: Types.ObjectId; /** * The damaged party's userId, resolved from the blame at claim-creation time. * Stored here so view/list access does not require an extra blame lookup. * For CAR_BODY this is the FIRST party; for THIRD_PARTY it is the non-guilty party. */ @Prop({ type: Types.ObjectId, index: true }) damagedPartyUserId?: Types.ObjectId; @Prop({ type: ClaimWorkflowSchema, default: () => ({}) }) workflow?: ClaimWorkflow; @Prop({ type: ClaimOwnerSchema, default: () => ({}) }) owner?: ClaimOwner; @Prop({ type: ClaimVehicleSnapshotSchema, default: () => ({}) }) vehicle?: ClaimVehicleSnapshot; @Prop({ type: ClaimMoneySchema }) money?: ClaimMoney; @Prop({ type: Number }) claimNo?: number; @Prop({ type: Number }) claimId?: number; @Prop({ type: Number }) dmgCaseId?: number; @Prop({ type: Number }) expertiseId?: number; @Prop({ type: FanavaranSyncStateSchema, default: () => ({}) }) fanavaranSync?: FanavaranSyncState; @Prop({ type: ClaimDamageSelectionSchema, default: () => ({}) }) damage?: ClaimDamageSelection; @Prop({ type: ClaimMediaSchema, default: () => ({}) }) media?: ClaimMedia; @Prop({ type: ClaimEvaluationSchema, default: () => ({}) }) evaluation?: ClaimEvaluation; @Prop({ type: CaseInquiriesSchema, default: () => ({}) }) inquiries?: CaseInquiries; /** * Optional “read-optimized” copy of fields from blame/request side. * Source of truth remains `blameRequestId`. */ @Prop({ type: ClaimCaseSnapshotSchema }) snapshot?: ClaimCaseSnapshot; /** * For quick “has user uploaded X?” checks. Values point to docs in the * `claim-required-documents` collection. */ @Prop({ type: Map, of: RequiredDocumentRefSchema, default: () => ({}), }) requiredDocuments?: Map; @Prop({ type: [HistoryEventSchema], default: [] }) history?: HistoryEvent[]; /** * User satisfaction rating (damaged party), after the case is completed. */ @Prop({ type: UserClaimRating, required: false }) userRating?: UserClaimRating; @Prop({ type: Types.ObjectId, index: true }) createdByRegistrarId?: Types.ObjectId; /** * Legacy fields kept optional to simplify progressive migration. * If you choose to migrate later, we can remove these. */ @Prop({ type: MongooseSchema.Types.Mixed }) legacy?: any; } export type ClaimCaseDocument = HydratedDocument; export const ClaimCaseSchema = SchemaFactory.createForClass(ClaimCase); ClaimCaseSchema.index({ status: 1, "workflow.locked": 1 });