feat: merge branche IA (beta) - Intégration assistant IA logisticien Gemini

This commit is contained in:
ElPoyo
2026-05-25 23:35:40 +02:00
15 changed files with 3394 additions and 163 deletions
+150
View File
@@ -553,6 +553,156 @@ class DataService {
}
}
/// Recherche des équipements pour l'assistant IA avec fallback paginé.
Future<List<Map<String, dynamic>>> searchEquipmentsForAssistant({
required String query,
int limit = 12,
}) async {
final normalizedQuery = query.trim();
if (normalizedQuery.isEmpty) {
return [];
}
try {
final quickResults = await quickSearch(
normalizedQuery,
limit: limit,
includeEquipments: true,
includeContainers: false,
);
final equipmentResults = quickResults
.where((item) =>
(item['type']?.toString().toLowerCase() ?? '') == 'equipment')
.map(_normalizeAssistantEquipment)
.toList();
if (equipmentResults.isNotEmpty) {
return equipmentResults;
}
final paginated = await getEquipmentsPaginated(
limit: limit,
searchQuery: normalizedQuery,
sortBy: 'id',
sortOrder: 'asc',
);
final equipments =
paginated['equipments'] as List<Map<String, dynamic>>? ?? [];
return equipments.map(_normalizeAssistantEquipment).toList();
} catch (e) {
DebugLog.error('[DataService] Error in searchEquipmentsForAssistant', e);
throw Exception('Erreur lors de la recherche de matériel: $e');
}
}
/// Vérifie la disponibilité d'un équipement dans un format normalisé pour l'IA.
Future<Map<String, dynamic>> checkEquipmentAvailabilityForAssistant({
required String equipmentId,
required DateTime startDate,
required DateTime endDate,
String? excludeEventId,
}) async {
try {
final result = await checkEquipmentAvailability(
equipmentId: equipmentId,
startDate: startDate,
endDate: endDate,
excludeEventId: excludeEventId,
);
final available = result['available'] as bool? ?? true;
final conflicts = (result['conflicts'] as List<dynamic>? ?? const [])
.whereType<Map<String, dynamic>>()
.map((conflict) {
final eventData =
conflict['eventData'] as Map<String, dynamic>? ?? const {};
final eventName =
(eventData['Name'] ?? conflict['eventName'] ?? '').toString();
return {
'eventId': conflict['eventId']?.toString() ?? '',
'eventName': eventName,
'overlapDays': conflict['overlapDays'] as int? ?? 0,
};
}).toList();
return {
'equipmentId': equipmentId,
'available': available,
'conflictCount': conflicts.length,
'conflicts': conflicts,
};
} catch (e) {
DebugLog.error(
'[DataService] Error in checkEquipmentAvailabilityForAssistant', e);
throw Exception('Erreur lors de la vérification de disponibilité: $e');
}
}
/// Retourne des événements passés, idéalement filtrés par type d'événement.
Future<List<Map<String, dynamic>>> getPastEventsForAssistant({
String? eventTypeId,
int limit = 10,
}) async {
try {
final now = DateTime.now();
final events = eventTypeId != null && eventTypeId.isNotEmpty
? await getEventsByEventType(eventTypeId)
: (await getEvents())['events'] as List<Map<String, dynamic>>? ?? [];
final pastEvents = events.where((event) {
final endDate = _parseEventDate(event['EndDateTime']);
return endDate != null && endDate.isBefore(now);
}).toList();
pastEvents.sort((a, b) {
final aDate = _parseEventDate(a['StartDateTime']) ??
DateTime.fromMillisecondsSinceEpoch(0);
final bDate = _parseEventDate(b['StartDateTime']) ??
DateTime.fromMillisecondsSinceEpoch(0);
return bDate.compareTo(aDate);
});
return pastEvents.take(limit).map((event) {
final assignedEquipment =
event['assignedEquipment'] as List<dynamic>? ?? const [];
return {
'id': event['id']?.toString() ?? '',
'name': (event['Name'] ?? '').toString(),
'startDate': event['StartDateTime']?.toString() ?? '',
'endDate': event['EndDateTime']?.toString() ?? '',
'assignedEquipment': assignedEquipment,
'assignedEquipmentCount': assignedEquipment.length,
};
}).toList();
} catch (e) {
DebugLog.error('[DataService] Error in getPastEventsForAssistant', e);
throw Exception(
'Erreur lors de la récupération des événements passés: $e');
}
}
Map<String, dynamic> _normalizeAssistantEquipment(Map<String, dynamic> item) {
return {
'id': (item['id'] ?? '').toString(),
'name': (item['name'] ?? item['id'] ?? '').toString(),
'category': (item['category'] ?? '').toString(),
'status': (item['status'] ?? '').toString(),
'brand': item['brand']?.toString(),
'model': item['model']?.toString(),
'availableQuantity': item['availableQuantity'],
'totalQuantity': item['totalQuantity'],
};
}
DateTime? _parseEventDate(dynamic rawValue) {
if (rawValue is String) {
return DateTime.tryParse(rawValue);
}
return null;
}
// ============================================================================
// USER - Current User
// ============================================================================