Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document, Schema as MongooseSchema, Types } from 'mongoose'; @Schema({ timestamps: true, collection: 'field_service_territories' }) export class FieldServiceTerritory extends Document { @Prop({ required: true, index: true }) tenantId: string; @Prop({ required: true }) territoryName: string; // e.g. "South Mumbai", "Central Bangalore" @Prop({ type: [String], default: [] }) zipCodes: string[]; } export const FieldServiceTerritorySchema = SchemaFactory.createForClass(FieldServiceTerritory); @Schema({ timestamps: true, collection: 'technician_profiles' }) export class TechnicianProfile extends Document { @Prop({ required: true, index: true }) tenantId: string; @Prop({ required: true, unique: true }) employeeId: string; @Prop({ type: MongooseSchema.Types.ObjectId, ref: 'FieldServiceTerritory' }) territoryId?: MongooseSchema.Types.ObjectId; @Prop({ type: [String], default: [] }) skills: string[]; // e.g. ['HVAC', 'Fibre_Splicing'] @Prop({ default: null }) vanWarehouseId?: string; // Spare parts van storage location tracking @Prop({ default: 'active' }) status: string; // 'active' | 'on_leave' | 'suspended' } export const TechnicianProfileSchema = SchemaFactory.createForClass(TechnicianProfile); TechnicianProfileSchema.index({ tenantId: 1, employeeId: 1 }, { unique: true }); @Schema({ timestamps: true, collection: 'fsm_visits' }) export class FsmVisit extends Document { @Prop({ required: true, index: true }) tenantId: string; @Prop({ type: MongooseSchema.Types.ObjectId, ref: 'ServiceWorkOrder', required: true }) workOrderId: MongooseSchema.Types.ObjectId; @Prop({ required: true }) technicianId: string; // employeeId assigned @Prop({ required: true, default: () => new Date() }) scheduledStart: Date; @Prop({ default: null }) actualCheckIn?: Date; @Prop({ default: null }) actualCheckOut?: Date; // GPS Audit locations @Prop({ default: 0 }) checkInLatitude: number; @Prop({ default: 0 }) checkInLongitude: number; @Prop({ default: 0 }) checkOutLatitude: number; @Prop({ default: 0 }) checkOutLongitude: number; @Prop({ default: 'scheduled' }) status: string; // 'scheduled' | 'travelling' | 'checked_in' | 'checked_out' @Prop({ default: null }) otpConfirmedByCustomer?: string; // Customer OTP acknowledgment code } export const FsmVisitSchema = SchemaFactory.createForClass(FsmVisit); FsmVisitSchema.index({ tenantId: 1, workOrderId: 1 }); @Schema({ timestamps: true, collection: 'service_work_orders' }) export class ServiceWorkOrder extends Document { @Prop({ required: true, index: true }) tenantId: string; @Prop({ required: true, unique: true }) workOrderNumber: string; // e.g. "WO-FSM-000001" @Prop({ type: MongooseSchema.Types.ObjectId, ref: 'Ticket', required: true }) ticketId: MongooseSchema.Types.ObjectId; @Prop({ required: true }) workOrderType: string; // 'Installation' | 'Repair' | 'Preventive Maintenance' @Prop({ default: 'low' }) priority: string; // 'low' | 'medium' | 'high' @Prop({ default: 'draft' }) status: string; // 'draft' | 'assigned' | 'in_progress' | 'completed' | 'closed' @Prop({ default: null }) assignedTechnicianId?: string; // employeeId @Prop({ default: 0 }) estimatedCostMinor: number; @Prop({ default: 0 }) actualCostMinor: number; @Prop({ default: 0 }) partsCostMinor: number; @Prop({ default: 0 }) travelCostMinor: number; @Prop({ default: null }) completionNotes?: string; } export const ServiceWorkOrderSchema = SchemaFactory.createForClass(ServiceWorkOrder); ServiceWorkOrderSchema.index({ tenantId: 1, workOrderNumber: 1 }, { unique: true }); |