351 lines
11 KiB
Dart
351 lines
11 KiB
Dart
import 'package:em2rp/services/api_service.dart';
|
|
import 'package:em2rp/utils/debug_log.dart';
|
|
|
|
/// Repository pour gérer toutes les opérations sur les équipements.
|
|
class EquipmentRepository {
|
|
final ApiService _apiService;
|
|
|
|
EquipmentRepository(this._apiService);
|
|
|
|
/// Récupère tous les équipements (avec masquage des prix selon permissions)
|
|
Future<List<Map<String, dynamic>>> getEquipments() async {
|
|
try {
|
|
print('[EquipmentRepository] Calling getEquipments API...');
|
|
final result = await _apiService.call('getEquipments', {});
|
|
print('[EquipmentRepository] API call successful, parsing result...');
|
|
final equipments = result['equipments'] as List<dynamic>?;
|
|
if (equipments == null) {
|
|
print('[EquipmentRepository] No equipments in result');
|
|
return [];
|
|
}
|
|
print('[EquipmentRepository] Found ${equipments.length} equipments');
|
|
return equipments.map((e) => e as Map<String, dynamic>).toList();
|
|
} catch (e) {
|
|
print('[EquipmentRepository] Error getting equipments: $e');
|
|
throw Exception('Erreur lors de la récupération des équipements: $e');
|
|
}
|
|
}
|
|
|
|
/// Récupère plusieurs équipements par leurs IDs
|
|
Future<List<Map<String, dynamic>>> getEquipmentsByIds(
|
|
List<String> equipmentIds) async {
|
|
try {
|
|
if (equipmentIds.isEmpty) return [];
|
|
|
|
print(
|
|
'[EquipmentRepository] Getting equipments by IDs: ${equipmentIds.length} items');
|
|
final result = await _apiService.call('getEquipmentsByIds', {
|
|
'equipmentIds': equipmentIds,
|
|
});
|
|
final equipments = result['equipments'] as List<dynamic>?;
|
|
if (equipments == null) {
|
|
print('[EquipmentRepository] No equipments in result');
|
|
return [];
|
|
}
|
|
print('[EquipmentRepository] Found ${equipments.length} equipments by IDs');
|
|
return equipments.map((e) => e as Map<String, dynamic>).toList();
|
|
} catch (e) {
|
|
print('[EquipmentRepository] Error getting equipments by IDs: $e');
|
|
throw Exception('Erreur lors de la récupération des équipements: $e');
|
|
}
|
|
}
|
|
|
|
/// Récupère les équipements avec pagination et filtrage
|
|
Future<Map<String, dynamic>> getEquipmentsPaginated({
|
|
int limit = 20,
|
|
String? startAfter,
|
|
String? category,
|
|
String? status,
|
|
String? searchQuery,
|
|
String sortBy = 'id',
|
|
String sortOrder = 'asc',
|
|
}) async {
|
|
try {
|
|
final params = <String, dynamic>{
|
|
'limit': limit,
|
|
'sortBy': sortBy,
|
|
'sortOrder': sortOrder,
|
|
};
|
|
|
|
if (startAfter != null) params['startAfter'] = startAfter;
|
|
if (category != null) params['category'] = category;
|
|
if (status != null) params['status'] = status;
|
|
if (searchQuery != null && searchQuery.isNotEmpty) {
|
|
params['searchQuery'] = searchQuery;
|
|
}
|
|
|
|
final result =
|
|
await (_apiService as FirebaseFunctionsApiService).callPaginated(
|
|
'getEquipmentsPaginated',
|
|
params,
|
|
);
|
|
|
|
return {
|
|
'equipments': (result['equipments'] as List<dynamic>?)
|
|
?.map((e) => e as Map<String, dynamic>)
|
|
.toList() ??
|
|
[],
|
|
'hasMore': result['hasMore'] as bool? ?? false,
|
|
'lastVisible': result['lastVisible'] as String?,
|
|
'total': result['total'] as int? ?? 0,
|
|
};
|
|
} catch (e) {
|
|
DebugLog.error('[EquipmentRepository] Error in getEquipmentsPaginated', e);
|
|
throw Exception(
|
|
'Erreur lors de la récupération paginée des équipements: $e');
|
|
}
|
|
}
|
|
|
|
/// Crée un équipement
|
|
Future<void> createEquipment(
|
|
String equipmentId, Map<String, dynamic> data) async {
|
|
try {
|
|
final equipmentData = Map<String, dynamic>.from(data);
|
|
equipmentData['id'] = equipmentId;
|
|
|
|
await _apiService.call('createEquipment', equipmentData);
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la création de l\'équipement: $e');
|
|
}
|
|
}
|
|
|
|
/// Met à jour un équipement
|
|
Future<void> updateEquipment(
|
|
String equipmentId, Map<String, dynamic> data) async {
|
|
try {
|
|
await _apiService.call('updateEquipment', {
|
|
'equipmentId': equipmentId,
|
|
'data': data,
|
|
});
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la mise à jour de l\'équipement: $e');
|
|
}
|
|
}
|
|
|
|
/// Supprime un équipement
|
|
Future<void> deleteEquipment(String equipmentId,
|
|
{bool forceDelete = false}) async {
|
|
try {
|
|
await _apiService.call('deleteEquipment', {
|
|
'equipmentId': equipmentId,
|
|
'forceDelete': forceDelete,
|
|
});
|
|
} on ApiException {
|
|
rethrow;
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la suppression de l\'équipement: $e');
|
|
}
|
|
}
|
|
|
|
/// Met à jour uniquement le statut d'un équipement
|
|
Future<void> updateEquipmentStatusOnly({
|
|
required String equipmentId,
|
|
String? status,
|
|
int? availableQuantity,
|
|
}) async {
|
|
try {
|
|
final data = <String, dynamic>{'equipmentId': equipmentId};
|
|
|
|
if (status != null) data['status'] = status;
|
|
if (availableQuantity != null) {
|
|
data['availableQuantity'] = availableQuantity;
|
|
}
|
|
|
|
await _apiService.call('updateEquipmentStatusOnly', data);
|
|
} catch (e) {
|
|
throw Exception(
|
|
'Erreur lors de la mise à jour du statut de l\'équipement: $e');
|
|
}
|
|
}
|
|
|
|
/// Recherche rapide (autocomplétion)
|
|
Future<List<Map<String, dynamic>>> quickSearch(
|
|
String query, {
|
|
int limit = 10,
|
|
bool includeEquipments = true,
|
|
bool includeContainers = true,
|
|
}) async {
|
|
try {
|
|
return await (_apiService as FirebaseFunctionsApiService).quickSearch(
|
|
query,
|
|
limit: limit,
|
|
includeEquipments: includeEquipments,
|
|
includeContainers: includeContainers,
|
|
);
|
|
} catch (e) {
|
|
DebugLog.error('[EquipmentRepository] Error in quickSearch', e);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/// 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('[EquipmentRepository] 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(
|
|
'[EquipmentRepository] Error in checkEquipmentAvailabilityForAssistant', e);
|
|
throw Exception('Erreur lors de la vérification de disponibilité: $e');
|
|
}
|
|
}
|
|
|
|
/// Vérifie la disponibilité d'un équipement
|
|
Future<Map<String, dynamic>> checkEquipmentAvailability({
|
|
required String equipmentId,
|
|
required DateTime startDate,
|
|
required DateTime endDate,
|
|
String? excludeEventId,
|
|
}) async {
|
|
try {
|
|
final result = await _apiService.call('checkEquipmentAvailability', {
|
|
'equipmentId': equipmentId,
|
|
'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é: $e');
|
|
}
|
|
}
|
|
|
|
/// 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
|
|
Future<Map<String, dynamic>> getConflictingEquipmentIds({
|
|
required DateTime startDate,
|
|
required DateTime endDate,
|
|
String? excludeEventId,
|
|
int installationTime = 0,
|
|
int disassemblyTime = 0,
|
|
}) async {
|
|
try {
|
|
final result = await _apiService.call('getConflictingEquipmentIds', {
|
|
'startDate': startDate.toIso8601String(),
|
|
'endDate': endDate.toIso8601String(),
|
|
if (excludeEventId != null) 'excludeEventId': excludeEventId,
|
|
'installationTime': installationTime,
|
|
'disassemblyTime': disassemblyTime,
|
|
});
|
|
return result;
|
|
} catch (e) {
|
|
throw Exception(
|
|
'Erreur lors de la récupération des équipements en conflit: $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'],
|
|
};
|
|
}
|
|
|
|
/// Récupère toutes les maintenances
|
|
Future<List<Map<String, dynamic>>> getMaintenances(
|
|
{String? equipmentId}) async {
|
|
try {
|
|
final data = <String, dynamic>{};
|
|
if (equipmentId != null) data['equipmentId'] = equipmentId;
|
|
|
|
final result = await _apiService.call('getMaintenances', data);
|
|
final maintenances = result['maintenances'] as List<dynamic>?;
|
|
if (maintenances == null) return [];
|
|
return maintenances.map((e) => e as Map<String, dynamic>).toList();
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la récupération des maintenances: $e');
|
|
}
|
|
}
|
|
|
|
/// Supprime une maintenance
|
|
Future<void> deleteMaintenance(String maintenanceId) async {
|
|
try {
|
|
await _apiService
|
|
.call('deleteMaintenance', {'maintenanceId': maintenanceId});
|
|
} catch (e) {
|
|
throw Exception('Erreur lors de la suppression de la maintenance: $e');
|
|
}
|
|
}
|
|
}
|