feat: ajout de la gestion de la préparation d'un événement avec page permettant de le gérer

This commit is contained in:
ElPoyo
2026-01-06 10:53:23 +01:00
parent fa1d6a4295
commit 25d395b41a
18 changed files with 2121 additions and 500 deletions

View File

@@ -24,8 +24,22 @@ class _EquipmentConflictDialogState extends State<EquipmentConflictDialog> {
.where((entry) => !_removedEquipmentIds.contains(entry.key))
.fold(0, (sum, entry) => sum + entry.value.length);
/// Retourne l'icône appropriée selon le type de conflit
IconData _getIconForConflict(AvailabilityConflict conflict) {
switch (conflict.type) {
case ConflictType.containerFullyUsed:
case ConflictType.containerPartiallyUsed:
return Icons.inventory_2;
case ConflictType.insufficientQuantity:
return Icons.production_quantity_limits;
case ConflictType.equipmentUnavailable:
return Icons.block;
}
}
@override
Widget build(BuildContext context) {
final dateFormat = DateFormat('dd/MM/yyyy');
return Dialog(
@@ -117,19 +131,37 @@ class _EquipmentConflictDialogState extends State<EquipmentConflictDialog> {
Row(
children: [
Icon(
Icons.inventory_2,
_getIconForConflict(firstConflict),
color: isRemoved ? Colors.grey : AppColors.rouge,
size: 20,
),
const SizedBox(width: 8),
Expanded(
child: Text(
firstConflict.equipmentName,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
decoration: isRemoved ? TextDecoration.lineThrough : null,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
firstConflict.equipmentName,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
decoration: isRemoved ? TextDecoration.lineThrough : null,
),
),
// Message de conflit spécifique
if (firstConflict.conflictMessage.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
firstConflict.conflictMessage,
style: TextStyle(
fontSize: 13,
color: Colors.orange.shade700,
fontWeight: FontWeight.w500,
),
),
),
],
),
),
if (isRemoved)

View File

@@ -213,28 +213,54 @@ class _EquipmentSelectionDialogState extends State<EquipmentSelectionDialog> {
setState(() => _isLoadingConflicts = true);
try {
print('[EquipmentSelectionDialog] Loading equipment conflicts...');
final equipmentProvider = context.read<EquipmentProvider>();
final equipment = await equipmentProvider.equipmentStream.first;
print('[EquipmentSelectionDialog] Checking conflicts for ${equipment.length} equipments');
for (var eq in equipment) {
final conflicts = await _availabilityService.checkEquipmentAvailability(
equipmentId: eq.id,
equipmentName: eq.id,
startDate: widget.startDate,
endDate: widget.endDate,
excludeEventId: widget.excludeEventId,
);
// Pour les consommables/câbles, vérifier avec gestion de quantité
if (eq.hasQuantity) {
// Récupérer la quantité disponible
final availableQty = await _availabilityService.getAvailableQuantity(
equipment: eq,
startDate: widget.startDate,
endDate: widget.endDate,
excludeEventId: widget.excludeEventId,
);
if (conflicts.isNotEmpty) {
print('[EquipmentSelectionDialog] Found ${conflicts.length} conflict(s) for ${eq.id}');
_equipmentConflicts[eq.id] = conflicts;
// Vérifier si un item de cet équipement est déjà sélectionné
final selectedItem = _selectedItems[eq.id];
final requestedQty = selectedItem?.quantity ?? 1;
// ✅ Ne créer un conflit QUE si la quantité demandée dépasse la quantité disponible
if (requestedQty > availableQty) {
final conflicts = await _availabilityService.checkEquipmentAvailabilityWithQuantity(
equipment: eq,
requestedQuantity: requestedQty,
startDate: widget.startDate,
endDate: widget.endDate,
excludeEventId: widget.excludeEventId,
);
if (conflicts.isNotEmpty) {
_equipmentConflicts[eq.id] = conflicts;
}
}
// Sinon, pas de conflit à afficher dans la liste
} else {
// Pour les équipements non quantifiables, vérification classique
final conflicts = await _availabilityService.checkEquipmentAvailability(
equipmentId: eq.id,
equipmentName: eq.id,
startDate: widget.startDate,
endDate: widget.endDate,
excludeEventId: widget.excludeEventId,
);
if (conflicts.isNotEmpty) {
_equipmentConflicts[eq.id] = conflicts;
}
}
}
print('[EquipmentSelectionDialog] Total equipments with conflicts: ${_equipmentConflicts.length}');
} catch (e) {
print('[EquipmentSelectionDialog] Error loading conflicts: $e');
} finally {
@@ -247,32 +273,76 @@ class _EquipmentSelectionDialogState extends State<EquipmentSelectionDialog> {
try {
print('[EquipmentSelectionDialog] Loading container conflicts...');
final containerProvider = context.read<ContainerProvider>();
final equipmentProvider = context.read<EquipmentProvider>();
final containers = await containerProvider.containersStream.first;
final allEquipment = await equipmentProvider.equipmentStream.first;
print('[EquipmentSelectionDialog] Checking conflicts for ${containers.length} containers');
for (var container in containers) {
final conflictingChildren = <String>[];
// Vérifier d'abord si la boîte complète est utilisée ailleurs
final containerEquipment = allEquipment
.where((eq) => container.equipmentIds.contains(eq.id))
.toList();
// Vérifier chaque équipement enfant
for (var equipmentId in container.equipmentIds) {
if (_equipmentConflicts.containsKey(equipmentId)) {
conflictingChildren.add(equipmentId);
}
}
final containerConflicts = await _availabilityService.checkContainerAvailability(
container: container,
containerEquipment: containerEquipment,
startDate: widget.startDate,
endDate: widget.endDate,
excludeEventId: widget.excludeEventId,
);
if (conflictingChildren.isNotEmpty) {
final status = conflictingChildren.length == container.equipmentIds.length
? ContainerConflictStatus.complete
: ContainerConflictStatus.partial;
_containerConflicts[container.id] = ContainerConflictInfo(
status: status,
conflictingEquipmentIds: conflictingChildren,
totalChildren: container.equipmentIds.length,
if (containerConflicts.isNotEmpty) {
// Déterminer le statut en fonction du type de conflit
final hasFullConflict = containerConflicts.any(
(c) => c.type == ConflictType.containerFullyUsed,
);
print('[EquipmentSelectionDialog] Container ${container.id}: ${status.name} conflict (${conflictingChildren.length}/${container.equipmentIds.length} children)');
final conflictingChildren = containerConflicts
.where((c) => c.type != ConflictType.containerFullyUsed &&
c.type != ConflictType.containerPartiallyUsed)
.map((c) => c.equipmentId)
.toList();
final status = hasFullConflict
? ContainerConflictStatus.complete
: (conflictingChildren.isNotEmpty
? ContainerConflictStatus.partial
: ContainerConflictStatus.none);
if (status != ContainerConflictStatus.none) {
_containerConflicts[container.id] = ContainerConflictInfo(
status: status,
conflictingEquipmentIds: conflictingChildren,
totalChildren: container.equipmentIds.length,
);
print('[EquipmentSelectionDialog] Container ${container.id}: ${status.name} conflict');
}
} else {
// Vérifier chaque équipement enfant individuellement
final conflictingChildren = <String>[];
for (var equipmentId in container.equipmentIds) {
if (_equipmentConflicts.containsKey(equipmentId)) {
conflictingChildren.add(equipmentId);
}
}
if (conflictingChildren.isNotEmpty) {
final status = conflictingChildren.length == container.equipmentIds.length
? ContainerConflictStatus.complete
: ContainerConflictStatus.partial;
_containerConflicts[container.id] = ContainerConflictInfo(
status: status,
conflictingEquipmentIds: conflictingChildren,
totalChildren: container.equipmentIds.length,
);
print('[EquipmentSelectionDialog] Container ${container.id}: ${status.name} conflict (${conflictingChildren.length}/${container.equipmentIds.length} children)');
}
}
}