226 lines
6.8 KiB
Dart
226 lines
6.8 KiB
Dart
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
|
|
enum EventStatus {
|
|
confirmed,
|
|
canceled,
|
|
waitingForApproval,
|
|
}
|
|
|
|
String eventStatusToString(EventStatus status) {
|
|
switch (status) {
|
|
case EventStatus.confirmed:
|
|
return 'CONFIRMED';
|
|
case EventStatus.canceled:
|
|
return 'CANCELED';
|
|
case EventStatus.waitingForApproval:
|
|
default:
|
|
return 'WAITING_FOR_APPROVAL';
|
|
}
|
|
}
|
|
|
|
EventStatus eventStatusFromString(String? status) {
|
|
switch (status) {
|
|
case 'CONFIRMED':
|
|
return EventStatus.confirmed;
|
|
case 'CANCELED':
|
|
return EventStatus.canceled;
|
|
case 'WAITING_FOR_APPROVAL':
|
|
default:
|
|
return EventStatus.waitingForApproval;
|
|
}
|
|
}
|
|
|
|
class EventModel {
|
|
final String id;
|
|
final String name;
|
|
final String description;
|
|
final DateTime startDateTime;
|
|
final DateTime endDateTime;
|
|
final double basePrice;
|
|
final int installationTime;
|
|
final int disassemblyTime;
|
|
final String eventTypeId;
|
|
final DocumentReference? eventTypeRef;
|
|
final String customerId;
|
|
final String address;
|
|
final double latitude;
|
|
final double longitude;
|
|
final List<DocumentReference> workforce;
|
|
final List<Map<String, String>> documents;
|
|
final List<Map<String, dynamic>> options;
|
|
final EventStatus status;
|
|
|
|
EventModel({
|
|
required this.id,
|
|
required this.name,
|
|
required this.description,
|
|
required this.startDateTime,
|
|
required this.endDateTime,
|
|
required this.basePrice,
|
|
required this.installationTime,
|
|
required this.disassemblyTime,
|
|
required this.eventTypeId,
|
|
this.eventTypeRef,
|
|
required this.customerId,
|
|
required this.address,
|
|
required this.latitude,
|
|
required this.longitude,
|
|
required this.workforce,
|
|
required this.documents,
|
|
this.options = const [],
|
|
this.status = EventStatus.waitingForApproval,
|
|
});
|
|
|
|
factory EventModel.fromMap(Map<String, dynamic> map, String id) {
|
|
try {
|
|
// Gestion sécurisée des références workforce
|
|
final List<dynamic> workforceRefs = map['workforce'] ?? [];
|
|
final List<DocumentReference> safeWorkforce = [];
|
|
|
|
for (var ref in workforceRefs) {
|
|
if (ref is DocumentReference) {
|
|
safeWorkforce.add(ref);
|
|
} else {
|
|
print('Warning: Invalid workforce reference in event $id: $ref');
|
|
}
|
|
}
|
|
|
|
// Gestion sécurisée des timestamps
|
|
final Timestamp? startTimestamp = map['StartDateTime'] as Timestamp?;
|
|
final Timestamp? endTimestamp = map['EndDateTime'] as Timestamp?;
|
|
|
|
final DateTime startDate = startTimestamp?.toDate() ?? DateTime.now();
|
|
final DateTime endDate = endTimestamp?.toDate() ??
|
|
startDate.add(const Duration(hours: 1));
|
|
|
|
// Gestion sécurisée des documents
|
|
final docsRaw = map['documents'] ?? [];
|
|
final List<Map<String, String>> docs = [];
|
|
|
|
if (docsRaw is List) {
|
|
for (var e in docsRaw) {
|
|
try {
|
|
if (e is Map) {
|
|
docs.add(Map<String, String>.from(e));
|
|
} else if (e is String) {
|
|
final fileName = Uri.decodeComponent(
|
|
e.split('/').last.split('?').first,
|
|
);
|
|
docs.add({'name': fileName, 'url': e});
|
|
}
|
|
} catch (docError) {
|
|
print('Warning: Failed to parse document in event $id: $docError');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Gestion sécurisée des options
|
|
final optionsRaw = map['options'] ?? [];
|
|
final List<Map<String, dynamic>> options = [];
|
|
|
|
if (optionsRaw is List) {
|
|
for (var e in optionsRaw) {
|
|
try {
|
|
if (e is Map) {
|
|
options.add(Map<String, dynamic>.from(e));
|
|
}
|
|
} catch (optionError) {
|
|
print('Warning: Failed to parse option in event $id: $optionError');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Gestion sécurisée de l'EventType
|
|
String eventTypeId = '';
|
|
DocumentReference? eventTypeRef;
|
|
|
|
if (map['EventType'] is DocumentReference) {
|
|
eventTypeRef = map['EventType'] as DocumentReference;
|
|
eventTypeId = eventTypeRef.id;
|
|
} else if (map['EventType'] is String) {
|
|
eventTypeId = map['EventType'] as String;
|
|
}
|
|
|
|
// Gestion sécurisée du customer
|
|
String customerId = '';
|
|
if (map['customer'] is DocumentReference) {
|
|
customerId = (map['customer'] as DocumentReference).id;
|
|
} else if (map['customer'] is String) {
|
|
customerId = map['customer'] as String;
|
|
}
|
|
|
|
return EventModel(
|
|
id: id,
|
|
name: (map['Name'] ?? '').toString().trim(),
|
|
description: (map['Description'] ?? '').toString(),
|
|
startDateTime: startDate,
|
|
endDateTime: endDate,
|
|
basePrice: _parseDouble(map['BasePrice'] ?? map['Price'] ?? 0.0),
|
|
installationTime: _parseInt(map['InstallationTime'] ?? 0),
|
|
disassemblyTime: _parseInt(map['DisassemblyTime'] ?? 0),
|
|
eventTypeId: eventTypeId,
|
|
eventTypeRef: eventTypeRef,
|
|
customerId: customerId,
|
|
address: (map['Address'] ?? '').toString(),
|
|
latitude: _parseDouble(map['Latitude'] ?? 0.0),
|
|
longitude: _parseDouble(map['Longitude'] ?? 0.0),
|
|
workforce: safeWorkforce,
|
|
documents: docs,
|
|
options: options,
|
|
status: eventStatusFromString(map['status'] as String?),
|
|
);
|
|
} catch (e) {
|
|
print('Error parsing event $id: $e');
|
|
print('Event data: $map');
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
// Méthodes utilitaires pour le parsing sécurisé
|
|
static double _parseDouble(dynamic value) {
|
|
if (value is double) return value;
|
|
if (value is int) return value.toDouble();
|
|
if (value is String) {
|
|
final parsed = double.tryParse(value);
|
|
if (parsed != null) return parsed;
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
static int _parseInt(dynamic value) {
|
|
if (value is int) return value;
|
|
if (value is double) return value.toInt();
|
|
if (value is String) {
|
|
final parsed = int.tryParse(value);
|
|
if (parsed != null) return parsed;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Map<String, dynamic> toMap() {
|
|
return {
|
|
'Name': name,
|
|
'Description': description,
|
|
'StartDateTime': Timestamp.fromDate(startDateTime),
|
|
'EndDateTime': Timestamp.fromDate(endDateTime),
|
|
'BasePrice': basePrice,
|
|
'InstallationTime': installationTime,
|
|
'DisassemblyTime': disassemblyTime,
|
|
'EventType': eventTypeId.isNotEmpty
|
|
? FirebaseFirestore.instance.collection('eventTypes').doc(eventTypeId)
|
|
: null,
|
|
'customer': customerId.isNotEmpty
|
|
? FirebaseFirestore.instance.collection('customers').doc(customerId)
|
|
: null,
|
|
'Address': address,
|
|
'Position': GeoPoint(latitude, longitude),
|
|
'Latitude': latitude,
|
|
'Longitude': longitude,
|
|
'workforce': workforce,
|
|
'documents': documents,
|
|
'options': options,
|
|
'status': eventStatusToString(status),
|
|
};
|
|
}
|
|
}
|