erp-construccion/docs/04-modelado/domain-models/ASSETS-CONTEXT.md

652 lines
12 KiB
Markdown

# 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)
```typescript
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)
```typescript
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)
```typescript
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)
```typescript
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)
```typescript
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)
```typescript
interface WorkOrderTask {
id: UUID;
workOrderId: UUID;
taskNumber: number;
description: string;
isCompleted: boolean;
completedAt?: Timestamp;
completedBy?: UUID;
result?: string;
notes?: string;
sortOrder: number;
}
```
#### WorkOrderPart (Entity)
```typescript
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)
```typescript
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)
```typescript
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)
```typescript
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
```typescript
interface Location {
latitude: number;
longitude: number;
altitude?: number;
heading?: number;
speed?: number;
}
```
### Money
```typescript
interface Money {
amount: number;
currency: string;
}
```
### TCOResult
```typescript
interface TCOResult {
purchaseCost: Money;
depreciationCost: Money;
maintenanceCost: Money;
fuelCost: Money;
operatingHours: number;
costPerHour: Money;
totalTCO: Money;
}
```
### DepreciationSchedule
```typescript
interface DepreciationSchedule {
method: DepreciationMethod;
purchaseValue: Money;
salvageValue: Money;
usefulLifeYears: number;
currentYear: number;
annualDepreciation: Money;
accumulatedDepreciation: Money;
bookValue: Money;
}
```
---
## Domain Events
### Asset Lifecycle Events
```typescript
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
```typescript
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
```typescript
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
1. Un activo solo puede estar asignado a un proyecto a la vez
2. El status cambia automaticamente al crear orden de trabajo
3. La depreciacion no puede exceder el valor de compra menos salvage
4. Activos con status 'disposed' no pueden modificarse
### Maintenance Rules
1. El mantenimiento preventivo genera ordenes automaticamente
2. La tolerancia de frecuencia permite variacion sin alerta
3. Ordenes criticas requieren atencion en 24 horas
4. Las tareas obligatorias deben completarse para cerrar orden
### Usage Rules
1. Los registros de uso no pueden tener horas negativas
2. El odometro final debe ser >= inicial
3. Las horas de operacion acumulan en el activo
4. El consumo de combustible se usa para TCO
### Geofence Rules
1. Las geocercas requieren al menos 3 puntos de poligono
2. Los eventos se registran incluso si notificacion falla
3. Solo activos con GPS activo generan eventos
---
## Invariantes
1. `Asset.currentValue = purchaseValue - accumulatedDepreciation`
2. `Asset.accumulatedDepreciation <= purchaseValue - salvageValue`
3. `WorkOrder.actualTotalCost = actualLaborCost + actualPartsCost`
4. `AssetUsageLog.hoursUsed = hourMeterEnd - hourMeterStart`
5. `Asset.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
- [DDL-SPEC-assets.md](../database-design/schemas/DDL-SPEC-assets.md)
---
*Ultima actualizacion: 2025-12-05*