perf: suppression du téléchargement massif d'événements côté client (appel de la CF checkContainerAvailability et lecture synchrone des quantités)
This commit is contained in:
@@ -141,7 +141,6 @@ class ContainerService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Vérifier la disponibilité d'un container et de son contenu pour un événement
|
|
||||||
Future<Map<String, dynamic>> checkContainerAvailability({
|
Future<Map<String, dynamic>> checkContainerAvailability({
|
||||||
required String containerId,
|
required String containerId,
|
||||||
required DateTime startDate,
|
required DateTime startDate,
|
||||||
@@ -149,43 +148,21 @@ class ContainerService {
|
|||||||
String? excludeEventId,
|
String? excludeEventId,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
final container = await getContainerById(containerId);
|
final result = await _dataService.checkContainerAvailability(
|
||||||
if (container == null) {
|
containerId: containerId,
|
||||||
return {'available': false, 'message': 'Container non trouvé'};
|
startDate: startDate,
|
||||||
}
|
endDate: endDate,
|
||||||
|
excludeEventId: excludeEventId,
|
||||||
// Vérifier le statut du container
|
);
|
||||||
if (container.status != EquipmentStatus.available) {
|
|
||||||
return {
|
return {
|
||||||
'available': false,
|
'available': result['isAvailable'] ?? false,
|
||||||
'message': 'Container ${container.name} n\'est pas disponible (statut: ${container.status})',
|
'message': result['isAvailable'] == true
|
||||||
|
? 'Container et tout son contenu disponibles'
|
||||||
|
: 'Container non disponible ou en conflit',
|
||||||
|
'conflictType': result['conflictType'],
|
||||||
|
'containerConflicts': result['containerConflicts'],
|
||||||
|
'equipmentConflicts': result['equipmentConflicts'],
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier la disponibilité de chaque équipement dans le container
|
|
||||||
List<String> unavailableEquipment = [];
|
|
||||||
|
|
||||||
if (container.equipmentIds.isNotEmpty) {
|
|
||||||
final equipmentsData = await _dataService.getEquipmentsByIds(container.equipmentIds);
|
|
||||||
|
|
||||||
for (var data in equipmentsData) {
|
|
||||||
final id = data['id'] as String;
|
|
||||||
final equipment = EquipmentModel.fromMap(data, id);
|
|
||||||
if (equipment.status != EquipmentStatus.available) {
|
|
||||||
unavailableEquipment.add('${equipment.name} (${equipment.status})');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unavailableEquipment.isNotEmpty) {
|
|
||||||
return {
|
|
||||||
'available': false,
|
|
||||||
'message': 'Certains équipements ne sont pas disponibles',
|
|
||||||
'unavailableItems': unavailableEquipment,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {'available': true, 'message': 'Container et tout son contenu disponibles'};
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error checking container availability: $e');
|
print('Error checking container availability: $e');
|
||||||
return {'available': false, 'message': 'Erreur: $e'};
|
return {'available': false, 'message': 'Erreur: $e'};
|
||||||
|
|||||||
@@ -779,6 +779,26 @@ class DataService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Vérifie la disponibilité d'un container
|
||||||
|
Future<Map<String, dynamic>> checkContainerAvailability({
|
||||||
|
required String containerId,
|
||||||
|
required DateTime startDate,
|
||||||
|
required DateTime endDate,
|
||||||
|
String? excludeEventId,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final result = await _apiService.call('checkContainerAvailability', {
|
||||||
|
'containerId': containerId,
|
||||||
|
'startDate': startDate.toIso8601String(),
|
||||||
|
'endDate': endDate.toIso8601String(),
|
||||||
|
if (excludeEventId != null) 'excludeEventId': excludeEventId,
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Erreur lors de la vérification de disponibilité du container: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Récupère tous les IDs d'équipements et conteneurs en conflit pour une période
|
/// Récupère tous les IDs d'équipements et conteneurs en conflit pour une période
|
||||||
/// Optimisé : une seule requête au lieu d'une par équipement
|
/// Optimisé : une seule requête au lieu d'une par équipement
|
||||||
Future<Map<String, dynamic>> getConflictingEquipmentIds({
|
Future<Map<String, dynamic>> getConflictingEquipmentIds({
|
||||||
|
|||||||
@@ -67,27 +67,19 @@ class AvailabilityConflict {
|
|||||||
class EventAvailabilityService {
|
class EventAvailabilityService {
|
||||||
final DataService _dataService = DataService(apiService);
|
final DataService _dataService = DataService(apiService);
|
||||||
|
|
||||||
/// Helper pour récupérer uniquement la liste d'événements
|
|
||||||
Future<List<Map<String, dynamic>>> _getEventsList() async {
|
|
||||||
final result = await _dataService.getEvents();
|
|
||||||
final events = result['events'] as List<dynamic>? ?? [];
|
|
||||||
return events.map((e) => e as Map<String, dynamic>).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Vérifie si un équipement est disponible pour une plage de dates via Cloud Function
|
/// Vérifie si un équipement est disponible pour une plage de dates via Cloud Function
|
||||||
Future<List<AvailabilityConflict>> checkEquipmentAvailability({
|
Future<List<AvailabilityConflict>> checkEquipmentAvailability({
|
||||||
required String equipmentId,
|
required String equipmentId,
|
||||||
required String equipmentName,
|
required String equipmentName,
|
||||||
required DateTime startDate,
|
required DateTime startDate,
|
||||||
required DateTime endDate,
|
required DateTime endDate,
|
||||||
String? excludeEventId, // Pour exclure l'événement en cours d'édition
|
String? excludeEventId,
|
||||||
}) async {
|
}) async {
|
||||||
final conflicts = <AvailabilityConflict>[];
|
final conflicts = <AvailabilityConflict>[];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Checking availability for equipment $equipmentId ($equipmentName)');
|
if (kDebugMode) debugPrint('[EventAvailabilityService] Checking availability for equipment $equipmentId ($equipmentName)');
|
||||||
|
|
||||||
// Utiliser la Cloud Function pour vérifier la disponibilité
|
|
||||||
final result = await _dataService.checkEquipmentAvailability(
|
final result = await _dataService.checkEquipmentAvailability(
|
||||||
equipmentId: equipmentId,
|
equipmentId: equipmentId,
|
||||||
startDate: startDate,
|
startDate: startDate,
|
||||||
@@ -95,20 +87,12 @@ class EventAvailabilityService {
|
|||||||
excludeEventId: excludeEventId,
|
excludeEventId: excludeEventId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Result for $equipmentId: $result');
|
|
||||||
|
|
||||||
final available = result['available'] as bool? ?? true;
|
final available = result['available'] as bool? ?? true;
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Equipment $equipmentId available: $available');
|
|
||||||
|
|
||||||
if (!available) {
|
if (!available) {
|
||||||
final conflictsData = result['conflicts'] as List<dynamic>? ?? [];
|
final conflictsData = result['conflicts'] as List<dynamic>? ?? [];
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Found ${conflictsData.length} conflicts for equipment $equipmentId');
|
|
||||||
|
|
||||||
for (final conflictData in conflictsData) {
|
for (final conflictData in conflictsData) {
|
||||||
final conflict = conflictData as Map<String, dynamic>;
|
final conflict = conflictData as Map<String, dynamic>;
|
||||||
final eventId = conflict['eventId'] as String;
|
final eventId = conflict['eventId'] as String;
|
||||||
|
|
||||||
// Le backend retourne déjà eventData
|
|
||||||
final eventData = conflict['eventData'] as Map<String, dynamic>?;
|
final eventData = conflict['eventData'] as Map<String, dynamic>?;
|
||||||
|
|
||||||
if (eventData != null && eventData.isNotEmpty) {
|
if (eventData != null && eventData.isNotEmpty) {
|
||||||
@@ -120,10 +104,8 @@ class EventAvailabilityService {
|
|||||||
conflictingEvent: event,
|
conflictingEvent: event,
|
||||||
overlapDays: conflict['overlapDays'] as int? ?? 0,
|
overlapDays: conflict['overlapDays'] as int? ?? 0,
|
||||||
));
|
));
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Added conflict with event ${event.name}');
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Error creating EventModel: $e');
|
if (kDebugMode) debugPrint('[EventAvailabilityService] Error creating EventModel: $e');
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] EventData: $eventData');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,7 +114,6 @@ class EventAvailabilityService {
|
|||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Error checking availability: $e');
|
if (kDebugMode) debugPrint('[EventAvailabilityService] Error checking availability: $e');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Returning ${conflicts.length} conflicts for equipment $equipmentId');
|
|
||||||
return conflicts;
|
return conflicts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,164 +141,10 @@ class EventAvailabilityService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return allConflicts;
|
return allConflicts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Vérifie si deux plages de dates se chevauchent
|
/// Vérifie la disponibilité d'une boîte et de son contenu via le backend
|
||||||
bool _datesOverlap(DateTime start1, DateTime end1, DateTime start2, DateTime end2) {
|
|
||||||
// Deux plages se chevauchent si elles ne sont PAS complètement séparées
|
|
||||||
// Elles sont séparées si : end1 < start2 OU end2 < start1
|
|
||||||
// Donc elles se chevauchent si : NOT (end1 < start2 OU end2 < start1)
|
|
||||||
// Équivalent à : end1 >= start2 ET end2 >= start1
|
|
||||||
return !end1.isBefore(start2) && !end2.isBefore(start1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calcule le nombre de jours de chevauchement
|
|
||||||
int _calculateOverlapDays(DateTime start1, DateTime end1, DateTime start2, DateTime end2) {
|
|
||||||
final overlapStart = start1.isAfter(start2) ? start1 : start2;
|
|
||||||
final overlapEnd = end1.isBefore(end2) ? end1 : end2;
|
|
||||||
|
|
||||||
return overlapEnd.difference(overlapStart).inDays + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Récupère la quantité disponible pour un consommable/câble
|
|
||||||
Future<int> getAvailableQuantity({
|
|
||||||
required EquipmentModel equipment,
|
|
||||||
required DateTime startDate,
|
|
||||||
required DateTime endDate,
|
|
||||||
String? excludeEventId,
|
|
||||||
}) async {
|
|
||||||
if (!equipment.hasQuantity) {
|
|
||||||
return 1; // Équipement non consommable
|
|
||||||
}
|
|
||||||
|
|
||||||
final totalQuantity = equipment.totalQuantity ?? 0;
|
|
||||||
int reservedQuantity = 0;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Récupérer tous les événements via Cloud Function
|
|
||||||
final eventsData = await _getEventsList();
|
|
||||||
|
|
||||||
for (var eventData in eventsData) {
|
|
||||||
final eventId = eventData['id'] as String;
|
|
||||||
if (excludeEventId != null && eventId == excludeEventId) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final event = EventModel.fromMap(eventData, eventId);
|
|
||||||
|
|
||||||
// Ignorer les événements annulés
|
|
||||||
if (event.status == EventStatus.canceled) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculer les dates réelles avec temps d'installation et démontage
|
|
||||||
final eventRealStartDate = event.startDateTime.subtract(
|
|
||||||
Duration(hours: event.installationTime),
|
|
||||||
);
|
|
||||||
final eventRealEndDate = event.endDateTime.add(
|
|
||||||
Duration(hours: event.disassemblyTime),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Vérifier le chevauchement des dates
|
|
||||||
if (_datesOverlap(startDate, endDate, eventRealStartDate, eventRealEndDate)) {
|
|
||||||
final assignedEquipment = event.assignedEquipment.firstWhere(
|
|
||||||
(eq) => eq.equipmentId == equipment.id,
|
|
||||||
orElse: () => EventEquipment(equipmentId: ''),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Si l'équipement est assigné, réserver la quantité
|
|
||||||
// (peu importe le statut de préparation/retour)
|
|
||||||
if (assignedEquipment.equipmentId.isNotEmpty) {
|
|
||||||
reservedQuantity += assignedEquipment.quantity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Error processing event $eventId for quantity: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Error getting available quantity: $e');
|
|
||||||
}
|
|
||||||
|
|
||||||
return totalQuantity - reservedQuantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Vérifie la disponibilité d'un équipement avec gestion des quantités
|
|
||||||
Future<List<AvailabilityConflict>> checkEquipmentAvailabilityWithQuantity({
|
|
||||||
required EquipmentModel equipment,
|
|
||||||
required int requestedQuantity,
|
|
||||||
required DateTime startDate,
|
|
||||||
required DateTime endDate,
|
|
||||||
String? excludeEventId,
|
|
||||||
}) async {
|
|
||||||
final conflicts = <AvailabilityConflict>[];
|
|
||||||
|
|
||||||
// Si équipement quantifiable (consommable/câble)
|
|
||||||
if (equipment.hasQuantity) {
|
|
||||||
final totalQuantity = equipment.totalQuantity ?? 0;
|
|
||||||
final availableQty = await getAvailableQuantity(
|
|
||||||
equipment: equipment,
|
|
||||||
startDate: startDate,
|
|
||||||
endDate: endDate,
|
|
||||||
excludeEventId: excludeEventId,
|
|
||||||
);
|
|
||||||
final reservedQty = totalQuantity - availableQty;
|
|
||||||
|
|
||||||
// ✅ Ne créer un conflit que si la quantité est VRAIMENT insuffisante
|
|
||||||
if (availableQty < requestedQuantity) {
|
|
||||||
// Trouver les événements qui réservent cette quantité
|
|
||||||
final eventsData = await _getEventsList();
|
|
||||||
|
|
||||||
for (var eventData in eventsData) {
|
|
||||||
final eventId = eventData['id'] as String;
|
|
||||||
if (excludeEventId != null && eventId == excludeEventId) continue;
|
|
||||||
|
|
||||||
try {
|
|
||||||
final event = EventModel.fromMap(eventData, eventId);
|
|
||||||
|
|
||||||
if (_datesOverlap(startDate, endDate, event.startDateTime, event.endDateTime)) {
|
|
||||||
final assignedEquipment = event.assignedEquipment.firstWhere(
|
|
||||||
(eq) => eq.equipmentId == equipment.id,
|
|
||||||
orElse: () => EventEquipment(equipmentId: ''),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (assignedEquipment.equipmentId.isNotEmpty && !assignedEquipment.isReturned) {
|
|
||||||
conflicts.add(AvailabilityConflict(
|
|
||||||
equipmentId: equipment.id,
|
|
||||||
equipmentName: equipment.name,
|
|
||||||
conflictingEvent: event,
|
|
||||||
overlapDays: _calculateOverlapDays(startDate, endDate, event.startDateTime, event.endDateTime),
|
|
||||||
type: ConflictType.insufficientQuantity,
|
|
||||||
totalQuantity: totalQuantity,
|
|
||||||
availableQuantity: availableQty,
|
|
||||||
requestedQuantity: requestedQuantity,
|
|
||||||
reservedQuantity: reservedQty,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Error processing event $eventId: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Équipement non quantifiable : vérification classique
|
|
||||||
return await checkEquipmentAvailability(
|
|
||||||
equipmentId: equipment.id,
|
|
||||||
equipmentName: equipment.name,
|
|
||||||
startDate: startDate,
|
|
||||||
endDate: endDate,
|
|
||||||
excludeEventId: excludeEventId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return conflicts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Vérifie la disponibilité d'une boîte et de son contenu
|
|
||||||
Future<List<AvailabilityConflict>> checkContainerAvailability({
|
Future<List<AvailabilityConflict>> checkContainerAvailability({
|
||||||
required ContainerModel container,
|
required ContainerModel container,
|
||||||
required List<EquipmentModel> containerEquipment,
|
required List<EquipmentModel> containerEquipment,
|
||||||
@@ -326,99 +153,45 @@ class EventAvailabilityService {
|
|||||||
String? excludeEventId,
|
String? excludeEventId,
|
||||||
}) async {
|
}) async {
|
||||||
final conflicts = <AvailabilityConflict>[];
|
final conflicts = <AvailabilityConflict>[];
|
||||||
final conflictingChildrenIds = <String>[];
|
|
||||||
|
|
||||||
// Vérifier d'abord si la boîte complète est utilisée
|
|
||||||
final eventsData = await _getEventsList();
|
|
||||||
bool isContainerFullyUsed = false;
|
|
||||||
EventModel? containerConflictingEvent;
|
|
||||||
|
|
||||||
for (var eventData in eventsData) {
|
|
||||||
final eventId = eventData['id'] as String;
|
|
||||||
if (excludeEventId != null && eventId == excludeEventId) continue;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final event = EventModel.fromMap(eventData, eventId);
|
final result = await _dataService.checkContainerAvailability(
|
||||||
|
|
||||||
// Ignorer les événements annulés
|
|
||||||
if (event.status == EventStatus.canceled) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculer les dates réelles avec temps d'installation et démontage
|
|
||||||
final eventRealStartDate = event.startDateTime.subtract(
|
|
||||||
Duration(hours: event.installationTime),
|
|
||||||
);
|
|
||||||
final eventRealEndDate = event.endDateTime.add(
|
|
||||||
Duration(hours: event.disassemblyTime),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Vérifier si cette boîte est assignée
|
|
||||||
if (event.assignedContainers.contains(container.id)) {
|
|
||||||
if (_datesOverlap(startDate, endDate, eventRealStartDate, eventRealEndDate)) {
|
|
||||||
isContainerFullyUsed = true;
|
|
||||||
containerConflictingEvent = event;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (kDebugMode) debugPrint('[EventAvailabilityService] Error processing event $eventId: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isContainerFullyUsed && containerConflictingEvent != null) {
|
|
||||||
// Boîte complète utilisée
|
|
||||||
conflicts.add(AvailabilityConflict(
|
|
||||||
equipmentId: container.id,
|
|
||||||
equipmentName: container.name,
|
|
||||||
conflictingEvent: containerConflictingEvent,
|
|
||||||
overlapDays: _calculateOverlapDays(
|
|
||||||
startDate,
|
|
||||||
endDate,
|
|
||||||
containerConflictingEvent.startDateTime,
|
|
||||||
containerConflictingEvent.endDateTime,
|
|
||||||
),
|
|
||||||
type: ConflictType.containerFullyUsed,
|
|
||||||
containerId: container.id,
|
containerId: container.id,
|
||||||
containerName: container.name,
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
// Vérifier chaque équipement enfant individuellement
|
|
||||||
for (var equipment in containerEquipment) {
|
|
||||||
final equipmentConflicts = await checkEquipmentAvailability(
|
|
||||||
equipmentId: equipment.id,
|
|
||||||
equipmentName: equipment.name,
|
|
||||||
startDate: startDate,
|
startDate: startDate,
|
||||||
endDate: endDate,
|
endDate: endDate,
|
||||||
excludeEventId: excludeEventId,
|
excludeEventId: excludeEventId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (equipmentConflicts.isNotEmpty) {
|
final isAvailable = result['isAvailable'] as bool? ?? true;
|
||||||
conflictingChildrenIds.add(equipment.id);
|
if (!isAvailable) {
|
||||||
conflicts.addAll(equipmentConflicts);
|
final conflictType = result['conflictType'] as String?;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Si au moins un enfant en conflit, ajouter un conflit pour la boîte
|
if (conflictType == 'complete') {
|
||||||
if (conflictingChildrenIds.isNotEmpty && conflicts.isNotEmpty) {
|
final containerConflicts = result['containerConflicts'] as List<dynamic>? ?? [];
|
||||||
conflicts.insert(
|
for (var conflictData in containerConflicts) {
|
||||||
0,
|
final conflict = conflictData as Map<String, dynamic>;
|
||||||
AvailabilityConflict(
|
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,
|
equipmentId: container.id,
|
||||||
equipmentName: container.name,
|
equipmentName: container.name,
|
||||||
conflictingEvent: conflicts.first.conflictingEvent,
|
conflictingEvent: event,
|
||||||
overlapDays: conflicts.first.overlapDays,
|
overlapDays: conflict['overlapDays'] as int? ?? 0,
|
||||||
type: ConflictType.containerPartiallyUsed,
|
type: ConflictType.containerFullyUsed,
|
||||||
containerId: container.id,
|
containerId: container.id,
|
||||||
containerName: container.name,
|
containerName: container.name,
|
||||||
conflictingChildrenIds: conflictingChildrenIds,
|
));
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (kDebugMode) debugPrint('[EventAvailabilityService] Error checking container availability: $e');
|
||||||
|
}
|
||||||
|
|
||||||
return conflicts;
|
return conflicts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:em2rp/models/equipment_model.dart';
|
import 'package:em2rp/models/equipment_model.dart';
|
||||||
import 'package:em2rp/models/container_model.dart';
|
import 'package:em2rp/models/container_model.dart';
|
||||||
import 'package:em2rp/models/event_model.dart';
|
import 'package:em2rp/models/event_model.dart';
|
||||||
import 'package:em2rp/services/event_availability_service.dart';
|
|
||||||
import 'package:em2rp/services/data_service.dart';
|
import 'package:em2rp/services/data_service.dart';
|
||||||
import 'package:em2rp/services/api_service.dart';
|
import 'package:em2rp/services/api_service.dart';
|
||||||
import 'package:em2rp/utils/colors.dart';
|
import 'package:em2rp/utils/colors.dart';
|
||||||
@@ -88,7 +87,6 @@ class EquipmentSelectionDialog extends StatefulWidget {
|
|||||||
class _EquipmentSelectionDialogState extends State<EquipmentSelectionDialog> {
|
class _EquipmentSelectionDialogState extends State<EquipmentSelectionDialog> {
|
||||||
final TextEditingController _searchController = TextEditingController();
|
final TextEditingController _searchController = TextEditingController();
|
||||||
final ScrollController _scrollController = ScrollController(); // Pr├®serve la position de scroll
|
final ScrollController _scrollController = ScrollController(); // Pr├®serve la position de scroll
|
||||||
final EventAvailabilityService _availabilityService = EventAvailabilityService();
|
|
||||||
final DataService _dataService = DataService(apiService);
|
final DataService _dataService = DataService(apiService);
|
||||||
|
|
||||||
EquipmentCategory? _selectedCategory;
|
EquipmentCategory? _selectedCategory;
|
||||||
@@ -279,7 +277,7 @@ class _EquipmentSelectionDialogState extends State<EquipmentSelectionDialog> {
|
|||||||
DebugLog.info('[EquipmentSelectionDialog] Loaded ${newEquipments.length} equipments, total: ${_paginatedEquipments.length}, hasMore: $_hasMoreEquipments');
|
DebugLog.info('[EquipmentSelectionDialog] Loaded ${newEquipments.length} equipments, total: ${_paginatedEquipments.length}, hasMore: $_hasMoreEquipments');
|
||||||
|
|
||||||
// Charger les quantites pour les consommables/cbles de cette page
|
// Charger les quantites pour les consommables/cbles de cette page
|
||||||
await _loadAvailableQuantities(newEquipments);
|
_loadAvailableQuantities(newEquipments);
|
||||||
|
|
||||||
// Vrifier si on doit charger d'autres lments (ex: tout a t filtr)
|
// Vrifier si on doit charger d'autres lments (ex: tout a t filtr)
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
@@ -442,7 +440,7 @@ class _EquipmentSelectionDialogState extends State<EquipmentSelectionDialog> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Charge les quantit├®s disponibles pour les consommables/c├óbles d'une liste d'├®quipements
|
/// Charge les quantit├®s disponibles pour les consommables/c├óbles d'une liste d'├®quipements
|
||||||
Future<void> _loadAvailableQuantities(List<EquipmentModel> equipments) async {
|
void _loadAvailableQuantities(List<EquipmentModel> equipments) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -453,12 +451,13 @@ class _EquipmentSelectionDialogState extends State<EquipmentSelectionDialog> {
|
|||||||
for (var eq in consumables) {
|
for (var eq in consumables) {
|
||||||
// Ne recharger que si on n'a pas d├®j├á la quantit├®
|
// Ne recharger que si on n'a pas d├®j├á la quantit├®
|
||||||
if (!_availableQuantities.containsKey(eq.id)) {
|
if (!_availableQuantities.containsKey(eq.id)) {
|
||||||
final available = await _availabilityService.getAvailableQuantity(
|
int available = eq.totalQuantity ?? 0;
|
||||||
equipment: eq,
|
if (_equipmentQuantities.containsKey(eq.id)) {
|
||||||
startDate: widget.startDate,
|
final qtyInfo = _equipmentQuantities[eq.id];
|
||||||
endDate: widget.endDate,
|
if (qtyInfo != null && qtyInfo['availableQuantity'] != null) {
|
||||||
excludeEventId: widget.excludeEventId,
|
available = (qtyInfo['availableQuantity'] as num).toInt();
|
||||||
);
|
}
|
||||||
|
}
|
||||||
_availableQuantities[eq.id] = available;
|
_availableQuantities[eq.id] = available;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user