198 lines
6.9 KiB
Dart
198 lines
6.9 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import 'package:em2rp/models/event_model.dart';
|
|
import 'package:em2rp/models/equipment_model.dart';
|
|
import 'package:em2rp/models/container_model.dart';
|
|
import 'package:em2rp/services/api_service.dart';
|
|
import 'package:em2rp/services/data_service.dart';
|
|
|
|
/// Type de conflit
|
|
enum ConflictType {
|
|
equipmentUnavailable, // Équipement non quantifiable utilisé
|
|
insufficientQuantity, // Quantité insuffisante pour consommable/câble
|
|
containerFullyUsed, // Boîte complète utilisée
|
|
containerPartiallyUsed, // Certains équipements de la boîte utilisés
|
|
}
|
|
|
|
/// Informations sur un conflit de disponibilité
|
|
class AvailabilityConflict {
|
|
final String equipmentId;
|
|
final String equipmentName;
|
|
final EventModel conflictingEvent;
|
|
final int overlapDays;
|
|
final ConflictType type;
|
|
|
|
// Pour les quantités (consommables/câbles)
|
|
final int? totalQuantity;
|
|
final int? availableQuantity;
|
|
final int? requestedQuantity;
|
|
final int? reservedQuantity;
|
|
|
|
// Pour les boîtes
|
|
final String? containerId;
|
|
final String? containerName;
|
|
final List<String>? conflictingChildrenIds;
|
|
|
|
AvailabilityConflict({
|
|
required this.equipmentId,
|
|
required this.equipmentName,
|
|
required this.conflictingEvent,
|
|
required this.overlapDays,
|
|
this.type = ConflictType.equipmentUnavailable,
|
|
this.totalQuantity,
|
|
this.availableQuantity,
|
|
this.requestedQuantity,
|
|
this.reservedQuantity,
|
|
this.containerId,
|
|
this.containerName,
|
|
this.conflictingChildrenIds,
|
|
});
|
|
|
|
/// Message descriptif du conflit
|
|
String get conflictMessage {
|
|
switch (type) {
|
|
case ConflictType.equipmentUnavailable:
|
|
return 'Équipement déjà utilisé';
|
|
case ConflictType.insufficientQuantity:
|
|
return 'Stock insuffisant : $availableQuantity/$totalQuantity disponible (demandé: $requestedQuantity)';
|
|
case ConflictType.containerFullyUsed:
|
|
return 'Boîte complète déjà utilisée';
|
|
case ConflictType.containerPartiallyUsed:
|
|
final count = conflictingChildrenIds?.length ?? 0;
|
|
return '$count équipement(s) de la boîte déjà utilisé(s)';
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Service pour vérifier la disponibilité du matériel
|
|
class EventAvailabilityService {
|
|
final DataService _dataService = DataService(apiService);
|
|
|
|
/// Vérifie si un équipement est disponible pour une plage de dates via Cloud Function
|
|
Future<List<AvailabilityConflict>> checkEquipmentAvailability({
|
|
required String equipmentId,
|
|
required String equipmentName,
|
|
required DateTime startDate,
|
|
required DateTime endDate,
|
|
String? excludeEventId,
|
|
}) async {
|
|
final conflicts = <AvailabilityConflict>[];
|
|
|
|
try {
|
|
if (kDebugMode) debugPrint('[EventAvailabilityService] Checking availability for equipment $equipmentId ($equipmentName)');
|
|
|
|
final result = await _dataService.checkEquipmentAvailability(
|
|
equipmentId: equipmentId,
|
|
startDate: startDate,
|
|
endDate: endDate,
|
|
excludeEventId: excludeEventId,
|
|
);
|
|
|
|
final available = result['available'] as bool? ?? true;
|
|
if (!available) {
|
|
final conflictsData = result['conflicts'] as List<dynamic>? ?? [];
|
|
for (final conflictData in conflictsData) {
|
|
final conflict = conflictData as Map<String, dynamic>;
|
|
final eventId = conflict['eventId'] as String;
|
|
final eventData = conflict['eventData'] as Map<String, dynamic>?;
|
|
|
|
if (eventData != null && eventData.isNotEmpty) {
|
|
try {
|
|
final event = EventModel.fromMap(eventData, eventId);
|
|
conflicts.add(AvailabilityConflict(
|
|
equipmentId: equipmentId,
|
|
equipmentName: equipmentName,
|
|
conflictingEvent: event,
|
|
overlapDays: conflict['overlapDays'] as int? ?? 0,
|
|
));
|
|
} catch (e) {
|
|
if (kDebugMode) debugPrint('[EventAvailabilityService] Error creating EventModel: $e');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (kDebugMode) debugPrint('[EventAvailabilityService] Error checking availability: $e');
|
|
}
|
|
|
|
return conflicts;
|
|
}
|
|
|
|
/// Vérifie la disponibilité pour une liste d'équipements
|
|
Future<Map<String, List<AvailabilityConflict>>> checkMultipleEquipmentAvailability({
|
|
required List<String> equipmentIds,
|
|
required Map<String, String> equipmentNames,
|
|
required DateTime startDate,
|
|
required DateTime endDate,
|
|
String? excludeEventId,
|
|
}) async {
|
|
final allConflicts = <String, List<AvailabilityConflict>>{};
|
|
|
|
for (var equipmentId in equipmentIds) {
|
|
final conflicts = await checkEquipmentAvailability(
|
|
equipmentId: equipmentId,
|
|
equipmentName: equipmentNames[equipmentId] ?? equipmentId,
|
|
startDate: startDate,
|
|
endDate: endDate,
|
|
excludeEventId: excludeEventId,
|
|
);
|
|
|
|
if (conflicts.isNotEmpty) {
|
|
allConflicts[equipmentId] = conflicts;
|
|
}
|
|
}
|
|
|
|
return allConflicts;
|
|
}
|
|
|
|
/// Vérifie la disponibilité d'une boîte et de son contenu via le backend
|
|
Future<List<AvailabilityConflict>> checkContainerAvailability({
|
|
required ContainerModel container,
|
|
required List<EquipmentModel> containerEquipment,
|
|
required DateTime startDate,
|
|
required DateTime endDate,
|
|
String? excludeEventId,
|
|
}) async {
|
|
final conflicts = <AvailabilityConflict>[];
|
|
|
|
try {
|
|
final result = await _dataService.checkContainerAvailability(
|
|
containerId: container.id,
|
|
startDate: startDate,
|
|
endDate: endDate,
|
|
excludeEventId: excludeEventId,
|
|
);
|
|
|
|
final isAvailable = result['isAvailable'] as bool? ?? true;
|
|
if (!isAvailable) {
|
|
final conflictType = result['conflictType'] as String?;
|
|
|
|
if (conflictType == 'complete') {
|
|
final containerConflicts = result['containerConflicts'] as List<dynamic>? ?? [];
|
|
for (var conflictData in containerConflicts) {
|
|
final conflict = conflictData as Map<String, dynamic>;
|
|
final eventId = conflict['eventId'] as String;
|
|
final eventDoc = await _dataService.getEvents();
|
|
final eventData = (eventDoc['events'] as List<dynamic>).firstWhere((e) => e['id'] == eventId, orElse: () => null);
|
|
if (eventData != null) {
|
|
final event = EventModel.fromMap(eventData as Map<String, dynamic>, eventId);
|
|
conflicts.add(AvailabilityConflict(
|
|
equipmentId: container.id,
|
|
equipmentName: container.name,
|
|
conflictingEvent: event,
|
|
overlapDays: conflict['overlapDays'] as int? ?? 0,
|
|
type: ConflictType.containerFullyUsed,
|
|
containerId: container.id,
|
|
containerName: container.name,
|
|
));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (kDebugMode) debugPrint('[EventAvailabilityService] Error checking container availability: $e');
|
|
}
|
|
|
|
return conflicts;
|
|
}
|
|
}
|