import 'package:cloud_firestore/cloud_firestore.dart'; enum EquipmentStatus { available, // Disponible inUse, // En prestation rented, // Loué lost, // Perdu outOfService, // HS maintenance, // En maintenance } String equipmentStatusToString(EquipmentStatus status) { switch (status) { case EquipmentStatus.available: return 'AVAILABLE'; case EquipmentStatus.inUse: return 'IN_USE'; case EquipmentStatus.rented: return 'RENTED'; case EquipmentStatus.lost: return 'LOST'; case EquipmentStatus.outOfService: return 'OUT_OF_SERVICE'; case EquipmentStatus.maintenance: return 'MAINTENANCE'; } } EquipmentStatus equipmentStatusFromString(String? status) { switch (status) { case 'AVAILABLE': return EquipmentStatus.available; case 'IN_USE': return EquipmentStatus.inUse; case 'RENTED': return EquipmentStatus.rented; case 'LOST': return EquipmentStatus.lost; case 'OUT_OF_SERVICE': return EquipmentStatus.outOfService; case 'MAINTENANCE': return EquipmentStatus.maintenance; default: return EquipmentStatus.available; } } enum EquipmentCategory { lighting, // Lumière sound, // Son video, // Vidéo effect, // Effets spéciaux structure, // Structure consumable, // Consommable cable, // Câble other // Autre } String equipmentCategoryToString(EquipmentCategory category) { switch (category) { case EquipmentCategory.lighting: return 'LIGHTING'; case EquipmentCategory.sound: return 'SOUND'; case EquipmentCategory.video: return 'VIDEO'; case EquipmentCategory.structure: return 'STRUCTURE'; case EquipmentCategory.consumable: return 'CONSUMABLE'; case EquipmentCategory.cable: return 'CABLE'; case EquipmentCategory.other: return 'OTHER'; case EquipmentCategory.effect: return 'EFFECT'; } } EquipmentCategory equipmentCategoryFromString(String? category) { switch (category) { case 'LIGHTING': return EquipmentCategory.lighting; case 'SOUND': return EquipmentCategory.sound; case 'VIDEO': return EquipmentCategory.video; case 'STRUCTURE': return EquipmentCategory.structure; case 'CONSUMABLE': return EquipmentCategory.consumable; case 'CABLE': return EquipmentCategory.cable; case 'EFFECT': return EquipmentCategory.effect; case 'OTHER': default: return EquipmentCategory.other; } } class EquipmentModel { final String id; // Identifiant unique (clé) final String name; // Nom de l'équipement final String? brand; // Marque (indexé) final String? model; // Modèle (indexé) final EquipmentCategory category; // Catégorie final EquipmentStatus status; // Statut actuel // Prix (visible uniquement avec manage_equipment) final double? purchasePrice; // Prix d'achat final double? rentalPrice; // Prix de location // Quantité (pour consommables/câbles) final int? totalQuantity; // Quantité totale final int? availableQuantity; // Quantité disponible final int? criticalThreshold; // Seuil critique pour alerte // Boîtes parentes (plusieurs possibles) final List parentBoxIds; // IDs des boîtes contenant cet équipement // Dates & maintenance final DateTime? purchaseDate; // Date d'achat final DateTime? lastMaintenanceDate; // Dernière maintenance final DateTime? nextMaintenanceDate; // Prochaine maintenance prévue // Maintenances (références) final List maintenanceIds; // IDs des opérations de maintenance // Image final String? imageUrl; // URL de l'image (Storage /materiel) // Métadonnées final String? notes; // Notes additionnelles final DateTime createdAt; // Date de création final DateTime updatedAt; // Date de mise à jour EquipmentModel({ required this.id, required this.name, this.brand, this.model, required this.category, this.status = EquipmentStatus.available, this.purchasePrice, this.rentalPrice, this.totalQuantity, this.availableQuantity, this.criticalThreshold, this.parentBoxIds = const [], this.purchaseDate, this.lastMaintenanceDate, this.nextMaintenanceDate, this.maintenanceIds = const [], this.imageUrl, this.notes, required this.createdAt, required this.updatedAt, }); factory EquipmentModel.fromMap(Map map, String id) { // Gestion des listes final List parentBoxIdsRaw = map['parentBoxIds'] ?? []; final List parentBoxIds = parentBoxIdsRaw.map((e) => e.toString()).toList(); final List maintenanceIdsRaw = map['maintenanceIds'] ?? []; final List maintenanceIds = maintenanceIdsRaw.map((e) => e.toString()).toList(); return EquipmentModel( id: id, name: map['name'] ?? '', brand: map['brand'], model: map['model'], category: equipmentCategoryFromString(map['category']), status: equipmentStatusFromString(map['status']), purchasePrice: map['purchasePrice']?.toDouble(), rentalPrice: map['rentalPrice']?.toDouble(), totalQuantity: map['totalQuantity']?.toInt(), availableQuantity: map['availableQuantity']?.toInt(), criticalThreshold: map['criticalThreshold']?.toInt(), parentBoxIds: parentBoxIds, purchaseDate: (map['purchaseDate'] as Timestamp?)?.toDate(), nextMaintenanceDate: (map['nextMaintenanceDate'] as Timestamp?)?.toDate(), maintenanceIds: maintenanceIds, imageUrl: map['imageUrl'], notes: map['notes'], createdAt: (map['createdAt'] as Timestamp?)?.toDate() ?? DateTime.now(), updatedAt: (map['updatedAt'] as Timestamp?)?.toDate() ?? DateTime.now(), ); } Map toMap() { return { 'name': name, 'brand': brand, 'model': model, 'category': equipmentCategoryToString(category), 'status': equipmentStatusToString(status), 'purchasePrice': purchasePrice, 'rentalPrice': rentalPrice, 'totalQuantity': totalQuantity, 'availableQuantity': availableQuantity, 'criticalThreshold': criticalThreshold, 'parentBoxIds': parentBoxIds, 'lastMaintenanceDate': lastMaintenanceDate != null ? Timestamp.fromDate(lastMaintenanceDate!) : null, 'purchaseDate': purchaseDate != null ? Timestamp.fromDate(purchaseDate!) : null, 'nextMaintenanceDate': nextMaintenanceDate != null ? Timestamp.fromDate(nextMaintenanceDate!) : null, 'maintenanceIds': maintenanceIds, 'imageUrl': imageUrl, 'notes': notes, 'createdAt': Timestamp.fromDate(createdAt), 'updatedAt': Timestamp.fromDate(updatedAt), }; } EquipmentModel copyWith({ String? id, String? brand, String? name, String? model, EquipmentCategory? category, EquipmentStatus? status, double? purchasePrice, double? rentalPrice, int? totalQuantity, int? availableQuantity, int? criticalThreshold, List? parentBoxIds, DateTime? purchaseDate, DateTime? lastMaintenanceDate, DateTime? nextMaintenanceDate, List? maintenanceIds, String? imageUrl, String? notes, DateTime? createdAt, DateTime? updatedAt, }) { return EquipmentModel( id: id ?? this.id, brand: brand ?? this.brand, name: name ?? this.name, model: model ?? this.model, category: category ?? this.category, status: status ?? this.status, purchasePrice: purchasePrice ?? this.purchasePrice, rentalPrice: rentalPrice ?? this.rentalPrice, totalQuantity: totalQuantity ?? this.totalQuantity, availableQuantity: availableQuantity ?? this.availableQuantity, criticalThreshold: criticalThreshold ?? this.criticalThreshold, parentBoxIds: parentBoxIds ?? this.parentBoxIds, lastMaintenanceDate: lastMaintenanceDate ?? this.lastMaintenanceDate, purchaseDate: purchaseDate ?? this.purchaseDate, nextMaintenanceDate: nextMaintenanceDate ?? this.nextMaintenanceDate, maintenanceIds: maintenanceIds ?? this.maintenanceIds, imageUrl: imageUrl ?? this.imageUrl, notes: notes ?? this.notes, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, ); } // Helper pour vérifier si c'est un consommable/câble avec quantité bool get hasQuantity => category == EquipmentCategory.consumable || category == EquipmentCategory.cable; // Helper pour vérifier si le stock est critique bool get isCriticalStock { if (!hasQuantity || criticalThreshold == null || availableQuantity == null) { return false; } return availableQuantity! <= criticalThreshold!; } // Helper pour vérifier si la maintenance est à venir bool get isMaintenanceDue { if (nextMaintenanceDate == null) return false; return nextMaintenanceDate!.isBefore(DateTime.now().add(const Duration(days: 7))); } }