274 lines
9.0 KiB
Dart
274 lines
9.0 KiB
Dart
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
|
|
/// Type d'alerte
|
|
enum AlertType {
|
|
lowStock, // Stock faible
|
|
maintenanceDue, // Maintenance à venir
|
|
conflict, // Conflit disponibilité
|
|
lost, // Équipement perdu
|
|
eventCreated, // Événement créé
|
|
eventModified, // Événement modifié
|
|
eventCancelled, // Événement annulé
|
|
eventAssigned, // Assigné à un événement
|
|
maintenanceReminder, // Rappel maintenance périodique
|
|
equipmentMissing, // Équipement manquant à une étape
|
|
quantityMismatch, // Quantité incorrecte
|
|
damaged, // Équipement endommagé
|
|
workforceAdded, // Ajouté à la workforce d'un événement
|
|
}
|
|
|
|
/// Gravité de l'alerte
|
|
enum AlertSeverity {
|
|
info, // Information (bleu)
|
|
warning, // Avertissement (orange)
|
|
critical, // Critique (rouge)
|
|
}
|
|
|
|
String alertTypeToString(AlertType type) {
|
|
switch (type) {
|
|
case AlertType.lowStock:
|
|
return 'LOW_STOCK';
|
|
case AlertType.maintenanceDue:
|
|
return 'MAINTENANCE_DUE';
|
|
case AlertType.conflict:
|
|
return 'CONFLICT';
|
|
case AlertType.lost:
|
|
return 'LOST';
|
|
case AlertType.eventCreated:
|
|
return 'EVENT_CREATED';
|
|
case AlertType.eventModified:
|
|
return 'EVENT_MODIFIED';
|
|
case AlertType.eventCancelled:
|
|
return 'EVENT_CANCELLED';
|
|
case AlertType.eventAssigned:
|
|
return 'EVENT_ASSIGNED';
|
|
case AlertType.maintenanceReminder:
|
|
return 'MAINTENANCE_REMINDER';
|
|
case AlertType.equipmentMissing:
|
|
return 'EQUIPMENT_MISSING';
|
|
case AlertType.quantityMismatch:
|
|
return 'QUANTITY_MISMATCH';
|
|
case AlertType.damaged:
|
|
return 'DAMAGED';
|
|
case AlertType.workforceAdded:
|
|
return 'WORKFORCE_ADDED';
|
|
}
|
|
}
|
|
|
|
AlertType alertTypeFromString(String? type) {
|
|
switch (type) {
|
|
case 'LOW_STOCK':
|
|
return AlertType.lowStock;
|
|
case 'MAINTENANCE_DUE':
|
|
return AlertType.maintenanceDue;
|
|
case 'CONFLICT':
|
|
return AlertType.conflict;
|
|
case 'LOST':
|
|
return AlertType.lost;
|
|
case 'EVENT_CREATED':
|
|
return AlertType.eventCreated;
|
|
case 'EVENT_MODIFIED':
|
|
return AlertType.eventModified;
|
|
case 'EVENT_CANCELLED':
|
|
return AlertType.eventCancelled;
|
|
case 'EVENT_ASSIGNED':
|
|
return AlertType.eventAssigned;
|
|
case 'MAINTENANCE_REMINDER':
|
|
return AlertType.maintenanceReminder;
|
|
case 'EQUIPMENT_MISSING':
|
|
return AlertType.equipmentMissing;
|
|
case 'QUANTITY_MISMATCH':
|
|
return AlertType.quantityMismatch;
|
|
case 'DAMAGED':
|
|
return AlertType.damaged;
|
|
case 'WORKFORCE_ADDED':
|
|
return AlertType.workforceAdded;
|
|
default:
|
|
return AlertType.conflict;
|
|
}
|
|
}
|
|
|
|
String alertSeverityToString(AlertSeverity severity) {
|
|
switch (severity) {
|
|
case AlertSeverity.info:
|
|
return 'INFO';
|
|
case AlertSeverity.warning:
|
|
return 'WARNING';
|
|
case AlertSeverity.critical:
|
|
return 'CRITICAL';
|
|
}
|
|
}
|
|
|
|
AlertSeverity alertSeverityFromString(String? severity) {
|
|
switch (severity) {
|
|
case 'INFO':
|
|
return AlertSeverity.info;
|
|
case 'WARNING':
|
|
return AlertSeverity.warning;
|
|
case 'CRITICAL':
|
|
return AlertSeverity.critical;
|
|
default:
|
|
return AlertSeverity.info;
|
|
}
|
|
}
|
|
|
|
class AlertModel {
|
|
final String id; // ID généré automatiquement
|
|
final AlertType type; // Type d'alerte
|
|
final AlertSeverity severity; // Gravité de l'alerte
|
|
final String message; // Message de l'alerte
|
|
final List<String> assignedToUserIds; // Utilisateurs concernés
|
|
final String? eventId; // ID de l'événement concerné (optionnel)
|
|
final String? equipmentId; // ID de l'équipement concerné (optionnel)
|
|
final String? createdByUserId; // Qui a déclenché l'alerte
|
|
final DateTime createdAt; // Date de création
|
|
final DateTime? dueDate; // Date d'échéance (pour maintenance)
|
|
final String? actionUrl; // URL de redirection (deep link)
|
|
final bool isRead; // Statut lu/non lu
|
|
final bool isResolved; // Résolue ou non
|
|
final String? resolution; // Message de résolution
|
|
final DateTime? resolvedAt; // Date de résolution
|
|
final String? resolvedByUserId; // Qui a résolu
|
|
|
|
AlertModel({
|
|
required this.id,
|
|
required this.type,
|
|
this.severity = AlertSeverity.info,
|
|
required this.message,
|
|
this.assignedToUserIds = const [],
|
|
this.eventId,
|
|
this.equipmentId,
|
|
this.createdByUserId,
|
|
required this.createdAt,
|
|
this.dueDate,
|
|
this.actionUrl,
|
|
this.isRead = false,
|
|
this.isResolved = false,
|
|
this.resolution,
|
|
this.resolvedAt,
|
|
this.resolvedByUserId,
|
|
});
|
|
|
|
factory AlertModel.fromMap(Map<String, dynamic> map, String id) {
|
|
// Fonction helper pour convertir Timestamp ou String ISO en DateTime
|
|
DateTime parseDate(dynamic value) {
|
|
if (value == null) return DateTime.now();
|
|
if (value is Timestamp) return value.toDate();
|
|
if (value is String) return DateTime.tryParse(value) ?? DateTime.now();
|
|
return DateTime.now();
|
|
}
|
|
|
|
// Parser les assignedToUserIds (peut être List ou null)
|
|
List<String> parseUserIds(dynamic value) {
|
|
if (value == null) return [];
|
|
if (value is List) return value.map((e) => e.toString()).toList();
|
|
return [];
|
|
}
|
|
|
|
return AlertModel(
|
|
id: id,
|
|
type: alertTypeFromString(map['type']),
|
|
severity: alertSeverityFromString(map['severity']),
|
|
message: map['message'] ?? '',
|
|
assignedToUserIds: parseUserIds(map['assignedToUserIds'] ?? map['assignedTo']),
|
|
eventId: map['eventId'],
|
|
equipmentId: map['equipmentId'],
|
|
createdByUserId: map['createdByUserId'] ?? map['createdBy'],
|
|
createdAt: parseDate(map['createdAt']),
|
|
dueDate: map['dueDate'] != null ? parseDate(map['dueDate']) : null,
|
|
actionUrl: map['actionUrl'],
|
|
isRead: map['isRead'] ?? false,
|
|
isResolved: map['isResolved'] ?? false,
|
|
resolution: map['resolution'],
|
|
resolvedAt: map['resolvedAt'] != null ? parseDate(map['resolvedAt']) : null,
|
|
resolvedByUserId: map['resolvedByUserId'],
|
|
);
|
|
}
|
|
|
|
/// Factory depuis un document Firestore
|
|
factory AlertModel.fromFirestore(DocumentSnapshot doc) {
|
|
final data = doc.data() as Map<String, dynamic>?;
|
|
if (data == null) {
|
|
throw Exception('Document vide: ${doc.id}');
|
|
}
|
|
return AlertModel.fromMap(data, doc.id);
|
|
}
|
|
|
|
Map<String, dynamic> toMap() {
|
|
return {
|
|
'type': alertTypeToString(type),
|
|
'severity': alertSeverityToString(severity),
|
|
'message': message,
|
|
'assignedToUserIds': assignedToUserIds,
|
|
if (eventId != null) 'eventId': eventId,
|
|
if (equipmentId != null) 'equipmentId': equipmentId,
|
|
if (createdByUserId != null) 'createdByUserId': createdByUserId,
|
|
'createdAt': Timestamp.fromDate(createdAt),
|
|
if (dueDate != null) 'dueDate': Timestamp.fromDate(dueDate!),
|
|
if (actionUrl != null) 'actionUrl': actionUrl,
|
|
'isRead': isRead,
|
|
'isResolved': isResolved,
|
|
if (resolution != null) 'resolution': resolution,
|
|
if (resolvedAt != null) 'resolvedAt': Timestamp.fromDate(resolvedAt!),
|
|
if (resolvedByUserId != null) 'resolvedByUserId': resolvedByUserId,
|
|
};
|
|
}
|
|
|
|
AlertModel copyWith({
|
|
String? id,
|
|
AlertType? type,
|
|
AlertSeverity? severity,
|
|
String? message,
|
|
List<String>? assignedToUserIds,
|
|
String? eventId,
|
|
String? equipmentId,
|
|
String? createdByUserId,
|
|
DateTime? createdAt,
|
|
DateTime? dueDate,
|
|
String? actionUrl,
|
|
bool? isRead,
|
|
bool? isResolved,
|
|
String? resolution,
|
|
DateTime? resolvedAt,
|
|
String? resolvedByUserId,
|
|
}) {
|
|
return AlertModel(
|
|
id: id ?? this.id,
|
|
type: type ?? this.type,
|
|
severity: severity ?? this.severity,
|
|
message: message ?? this.message,
|
|
assignedToUserIds: assignedToUserIds ?? this.assignedToUserIds,
|
|
eventId: eventId ?? this.eventId,
|
|
equipmentId: equipmentId ?? this.equipmentId,
|
|
createdByUserId: createdByUserId ?? this.createdByUserId,
|
|
createdAt: createdAt ?? this.createdAt,
|
|
dueDate: dueDate ?? this.dueDate,
|
|
actionUrl: actionUrl ?? this.actionUrl,
|
|
isRead: isRead ?? this.isRead,
|
|
isResolved: isResolved ?? this.isResolved,
|
|
resolution: resolution ?? this.resolution,
|
|
resolvedAt: resolvedAt ?? this.resolvedAt,
|
|
resolvedByUserId: resolvedByUserId ?? this.resolvedByUserId,
|
|
);
|
|
}
|
|
|
|
/// Helper : Retourne true si l'alerte est pour un événement
|
|
bool get isEventAlert =>
|
|
type == AlertType.eventCreated ||
|
|
type == AlertType.eventModified ||
|
|
type == AlertType.eventCancelled ||
|
|
type == AlertType.eventAssigned;
|
|
|
|
/// Helper : Retourne true si l'alerte est pour la maintenance
|
|
bool get isMaintenanceAlert =>
|
|
type == AlertType.maintenanceDue ||
|
|
type == AlertType.maintenanceReminder;
|
|
|
|
/// Helper : Retourne true si l'alerte est pour un équipement
|
|
bool get isEquipmentAlert =>
|
|
type == AlertType.lost ||
|
|
type == AlertType.equipmentMissing ||
|
|
type == AlertType.lowStock;
|
|
}
|
|
|