12 KiB
12 KiB
DOMAIN MODEL: Assets Context
Version: 1.0.0 Fecha: 2025-12-05 Modulos: MAE-015
Descripcion
El contexto de Assets gestiona el ciclo de vida completo de activos de construccion: maquinaria pesada, vehiculos, equipos y herramientas. Incluye control de ubicacion, asignaciones a proyectos, mantenimiento preventivo/correctivo y calculo de TCO.
Agregados
1. Asset Aggregate
Asset (Aggregate Root)
|
+-- AssetAssignment (Entity)
| +-- Period (Value Object)
|
+-- AssetUsageLog (Entity)
|
+-- GPSTracking (Entity)
|
+-- DepreciationSchedule (Value Object)
Asset (Root)
interface Asset {
id: UUID;
tenantId: UUID;
assetCode: string;
name: string;
description?: string;
// Classification
assetType: AssetType;
categoryId?: UUID;
subcategory?: string;
// Specifications
brand?: string;
model?: string;
serialNumber?: string;
year?: number;
capacity?: string;
specifications?: Record<string, any>;
// Current location
currentLocation?: string;
currentProjectId?: UUID;
assignedTo?: UUID;
// GPS/IoT
gpsDeviceId?: string;
lastGPSLocation?: Location;
lastGPSUpdate?: Timestamp;
// Financial
purchaseDate?: Date;
purchaseValue: Money;
currentValue: Money;
depreciationMethod?: DepreciationMethod;
usefulLifeYears?: number;
salvageValue: Money;
accumulatedDepreciation: Money;
// Operational
operatingHours: number;
odometerReading?: number;
fuelType?: string;
hourlyCost: Money;
status: AssetStatus;
imageUrl?: string;
documentsUrls?: string[];
assignments: AssetAssignment[];
usageLogs: AssetUsageLog[];
maintenancePlans: MaintenancePlan[];
}
enum AssetType {
HEAVY_EQUIPMENT = 'heavy_equipment',
VEHICLE = 'vehicle',
TOOL = 'tool',
EQUIPMENT = 'equipment',
COMPUTER = 'computer',
FURNITURE = 'furniture',
OTHER = 'other'
}
enum AssetStatus {
AVAILABLE = 'available',
IN_USE = 'in_use',
MAINTENANCE = 'maintenance',
REPAIR = 'repair',
OUT_OF_SERVICE = 'out_of_service',
DISPOSED = 'disposed'
}
enum DepreciationMethod {
STRAIGHT_LINE = 'straight_line',
DECLINING_BALANCE = 'declining_balance',
UNITS_OF_PRODUCTION = 'units_of_production'
}
AssetAssignment (Entity)
interface AssetAssignment {
id: UUID;
assetId: UUID;
projectId?: UUID;
assignedTo?: UUID;
department?: string;
startDate: Date;
endDate?: Date;
plannedEndDate?: Date;
location?: string;
locationCoordinates?: Location;
status: AssignmentStatus;
// Usage tracking
initialHours?: number;
finalHours?: number;
initialOdometer?: number;
finalOdometer?: number;
notes?: string;
}
enum AssignmentStatus {
ACTIVE = 'active',
COMPLETED = 'completed',
CANCELLED = 'cancelled'
}
AssetUsageLog (Entity)
interface AssetUsageLog {
id: UUID;
assetId: UUID;
assignmentId?: UUID;
logDate: Date;
startTime?: Time;
endTime?: Time;
hoursUsed?: number;
distanceTraveled?: number;
fuelConsumed?: number;
projectId?: UUID;
activityDescription?: string;
operatorId?: UUID;
operatorName?: string;
// Readings
odometerStart?: number;
odometerEnd?: number;
hourMeterStart?: number;
hourMeterEnd?: number;
notes?: string;
}
2. Maintenance Aggregate
MaintenancePlan (Aggregate Root)
|
+-- MaintenanceSchedule (Value Object)
|
+-- NextDueCalculation (Value Object)
WorkOrder (Aggregate Root)
|
+-- WorkOrderTask (Entity)
+-- WorkOrderPart (Entity)
+-- WorkOrderLabor (Entity)
MaintenancePlan (Root)
interface MaintenancePlan {
id: UUID;
tenantId: UUID;
assetId: UUID;
planName: string;
description?: string;
maintenanceType: MaintenanceType;
// Frequency
frequencyType: FrequencyType;
frequencyValue: number;
toleranceValue: number;
// Last and next
lastPerformedAt?: Timestamp;
lastPerformedHours?: number;
lastPerformedDistance?: number;
nextDueAt?: Timestamp;
nextDueHours?: number;
nextDueDistance?: number;
// Tasks
tasksChecklist?: TaskChecklistItem[];
estimatedDurationHours?: number;
estimatedCost: Money;
isActive: boolean;
}
enum MaintenanceType {
PREVENTIVE = 'preventive',
CORRECTIVE = 'corrective',
PREDICTIVE = 'predictive',
INSPECTION = 'inspection',
CALIBRATION = 'calibration'
}
enum FrequencyType {
HOURS = 'hours',
DAYS = 'days',
DISTANCE = 'distance',
CALENDAR = 'calendar'
}
interface TaskChecklistItem {
id: string;
description: string;
isMandatory: boolean;
estimatedMinutes?: number;
}
WorkOrder (Root)
interface WorkOrder {
id: UUID;
tenantId: UUID;
assetId: UUID;
woNumber: string;
maintenanceType: MaintenanceType;
priority: MaintenancePriority;
title: string;
description?: string;
problemReported?: string;
// Origin
maintenancePlanId?: UUID;
reportedBy?: UUID;
reportedAt: Timestamp;
// Assignment
assignedTo?: UUID;
assignedTeam?: string;
// Schedule
scheduledDate?: Date;
scheduledStartTime?: Time;
estimatedDurationHours?: number;
actualStartAt?: Timestamp;
actualEndAt?: Timestamp;
// Location
workLocation?: string;
projectId?: UUID;
// Costs
estimatedCost: Money;
actualLaborCost: Money;
actualPartsCost: Money;
actualTotalCost: Money;
status: WorkOrderStatus;
// Result
workPerformed?: string;
rootCause?: string;
recommendations?: string;
// Readings at time of work
hoursAtWork?: number;
odometerAtWork?: number;
tasks: WorkOrderTask[];
parts: WorkOrderPart[];
labor: WorkOrderLabor[];
}
enum MaintenancePriority {
LOW = 'low',
MEDIUM = 'medium',
HIGH = 'high',
CRITICAL = 'critical'
}
enum WorkOrderStatus {
DRAFT = 'draft',
SCHEDULED = 'scheduled',
IN_PROGRESS = 'in_progress',
ON_HOLD = 'on_hold',
COMPLETED = 'completed',
CANCELLED = 'cancelled'
}
WorkOrderTask (Entity)
interface WorkOrderTask {
id: UUID;
workOrderId: UUID;
taskNumber: number;
description: string;
isCompleted: boolean;
completedAt?: Timestamp;
completedBy?: UUID;
result?: string;
notes?: string;
sortOrder: number;
}
WorkOrderPart (Entity)
interface WorkOrderPart {
id: UUID;
workOrderId: UUID;
productId?: UUID;
productCode?: string;
productName: string;
quantity: number;
unitCode?: string;
unitCost: Money;
totalCost: Money;
warehouseId?: UUID;
purchaseOrderId?: UUID;
}
WorkOrderLabor (Entity)
interface WorkOrderLabor {
id: UUID;
workOrderId: UUID;
technicianId?: UUID;
technicianName: string;
workDate: Date;
hoursWorked: number;
overtimeHours: number;
hourlyRate: Money;
overtimeRate: Money;
totalCost: Money;
workDescription?: string;
}
3. Geofence Aggregate
Geofence (Aggregate Root)
|
+-- GeofenceEvent (Entity)
|
+-- AlertRecipient (Value Object)
Geofence (Root)
interface Geofence {
id: UUID;
tenantId: UUID;
name: string;
description?: string;
boundary: Polygon;
centerPoint?: Location;
radiusMeters?: number;
projectId?: UUID;
alertOnEntry: boolean;
alertOnExit: boolean;
alertRecipients?: UUID[];
isActive: boolean;
}
GeofenceEvent (Entity)
interface GeofenceEvent {
id: UUID;
assetId: UUID;
geofenceId: UUID;
eventType: GeofenceEventType;
eventTime: Timestamp;
location?: Location;
notificationSent: boolean;
notificationSentAt?: Timestamp;
}
enum GeofenceEventType {
ENTRY = 'entry',
EXIT = 'exit'
}
Value Objects
Location
interface Location {
latitude: number;
longitude: number;
altitude?: number;
heading?: number;
speed?: number;
}
Money
interface Money {
amount: number;
currency: string;
}
TCOResult
interface TCOResult {
purchaseCost: Money;
depreciationCost: Money;
maintenanceCost: Money;
fuelCost: Money;
operatingHours: number;
costPerHour: Money;
totalTCO: Money;
}
DepreciationSchedule
interface DepreciationSchedule {
method: DepreciationMethod;
purchaseValue: Money;
salvageValue: Money;
usefulLifeYears: number;
currentYear: number;
annualDepreciation: Money;
accumulatedDepreciation: Money;
bookValue: Money;
}
Domain Events
Asset Lifecycle Events
interface AssetCreated {
assetId: UUID;
assetCode: string;
assetType: AssetType;
purchaseValue: Money;
timestamp: Timestamp;
}
interface AssetStatusChanged {
assetId: UUID;
previousStatus: AssetStatus;
newStatus: AssetStatus;
reason?: string;
timestamp: Timestamp;
}
interface AssetAssigned {
assetId: UUID;
assignmentId: UUID;
projectId?: UUID;
assignedTo?: UUID;
startDate: Date;
timestamp: Timestamp;
}
interface AssetDisposed {
assetId: UUID;
disposalReason: string;
disposalValue: Money;
timestamp: Timestamp;
}
Maintenance Events
interface MaintenanceDue {
assetId: UUID;
maintenancePlanId: UUID;
dueAt: Timestamp;
dueHours?: number;
maintenanceType: MaintenanceType;
timestamp: Timestamp;
}
interface WorkOrderCreated {
workOrderId: UUID;
assetId: UUID;
woNumber: string;
maintenanceType: MaintenanceType;
priority: MaintenancePriority;
timestamp: Timestamp;
}
interface WorkOrderCompleted {
workOrderId: UUID;
assetId: UUID;
actualCost: Money;
laborHours: number;
timestamp: Timestamp;
}
GPS/Geofence Events
interface LocationUpdated {
assetId: UUID;
location: Location;
speed?: number;
timestamp: Timestamp;
}
interface GeofenceViolation {
assetId: UUID;
geofenceId: UUID;
eventType: GeofenceEventType;
location: Location;
timestamp: Timestamp;
}
Business Rules
Asset Rules
- Un activo solo puede estar asignado a un proyecto a la vez
- El status cambia automaticamente al crear orden de trabajo
- La depreciacion no puede exceder el valor de compra menos salvage
- Activos con status 'disposed' no pueden modificarse
Maintenance Rules
- El mantenimiento preventivo genera ordenes automaticamente
- La tolerancia de frecuencia permite variacion sin alerta
- Ordenes criticas requieren atencion en 24 horas
- Las tareas obligatorias deben completarse para cerrar orden
Usage Rules
- Los registros de uso no pueden tener horas negativas
- El odometro final debe ser >= inicial
- Las horas de operacion acumulan en el activo
- El consumo de combustible se usa para TCO
Geofence Rules
- Las geocercas requieren al menos 3 puntos de poligono
- Los eventos se registran incluso si notificacion falla
- Solo activos con GPS activo generan eventos
Invariantes
Asset.currentValue = purchaseValue - accumulatedDepreciationAsset.accumulatedDepreciation <= purchaseValue - salvageValueWorkOrder.actualTotalCost = actualLaborCost + actualPartsCostAssetUsageLog.hoursUsed = hourMeterEnd - hourMeterStartAsset.operatingHours += SUM(usageLogs.hoursUsed)
Integraciones
Con Project Context
- Activos asignados a proyectos
- Costos de maquinaria en presupuestos
- Ubicacion en obra
Con Finance Context
- Depreciacion genera polizas
- Costos de mantenimiento como gastos
- TCO para analisis financiero
Con Inventory Context
- Repuestos desde almacen
- Consumibles para mantenimiento
Con GPS/IoT (Externo)
- Tracking en tiempo real
- Telemetria de activos
- Alertas de geocerca
Referencias
Ultima actualizacion: 2025-12-05