// models/commande_detail.dart class CommandeDetail { final int id; final int clientId; final int tableId; final int? reservationId; final String numeroCommande; final String statut; final double totalHt; final double totalTva; final double totalTtc; final String? modePaiement; final String? commentaires; final String serveur; final DateTime dateCommande; final DateTime? dateService; final DateTime createdAt; final DateTime updatedAt; final String tablename; final List items; CommandeDetail({ required this.id, required this.clientId, required this.tableId, this.reservationId, required this.numeroCommande, required this.statut, required this.totalHt, required this.totalTva, required this.totalTtc, this.modePaiement, this.commentaires, required this.serveur, required this.dateCommande, this.dateService, required this.createdAt, required this.updatedAt, required this.items, required this.tablename, }); factory CommandeDetail.fromJson(Map json) { // Gérer les cas où les données sont dans "data" ou directement dans json final data = json['data'] ?? json; return CommandeDetail( id: data['id'] ?? 0, clientId: data['client_id'] ?? 0, tableId: data['table_id'] ?? 0, reservationId: data['reservation_id'], numeroCommande: data['numero_commande'] ?? '', statut: data['statut'] ?? 'en_cours', totalHt: double.tryParse(data['total_ht']?.toString() ?? '0') ?? 0.0, totalTva: double.tryParse(data['total_tva']?.toString() ?? '0') ?? 0.0, totalTtc: double.tryParse(data['total_ttc']?.toString() ?? '0') ?? 0.0, modePaiement: data['mode_paiement'], commentaires: data['commentaires'], tablename: json['tablename'] ?? 'Inconnue', serveur: data['serveur'] ?? 'Serveur par défaut', dateCommande: data['date_commande'] != null ? DateTime.parse(data['date_commande']) : DateTime.now(), dateService: data['date_service'] != null ? DateTime.parse(data['date_service']) : null, createdAt: data['created_at'] != null ? DateTime.parse(data['created_at']) : DateTime.now(), updatedAt: data['updated_at'] != null ? DateTime.parse(data['updated_at']) : DateTime.now(), items: (data['items'] as List?) ?.map((item) => CommandeItem.fromJson(item)) .toList() ?? [], ); } Map toJson() { return { 'id': id, 'client_id': clientId, 'table_id': tableId, 'reservation_id': reservationId, 'numero_commande': numeroCommande, 'statut': statut, 'total_ht': totalHt.toString(), 'total_tva': totalTva.toString(), 'total_ttc': totalTtc.toString(), 'mode_paiement': modePaiement, 'commentaires': commentaires, 'serveur': serveur, 'date_commande': dateCommande.toIso8601String(), 'date_service': dateService?.toIso8601String(), 'created_at': createdAt.toIso8601String(), 'updated_at': updatedAt.toIso8601String(), 'items': items.map((item) => item.toJson()).toList(), }; } // Getters pour la compatibilité avec l'ancien code String get commandeId => id.toString(); int get tableNumber => tableId; double get total => totalTtc; // Méthodes utilitaires bool get isPaid => statut.toLowerCase() == 'payee'; bool get isInProgress => statut.toLowerCase() == 'en_cours'; bool get isReady => statut.toLowerCase() == 'pret'; bool get isCanceled => statut.toLowerCase() == 'annulee'; String get statutText { switch (statut.toLowerCase()) { case 'payee': return 'Payée'; case 'en_cours': return 'En cours'; case 'pret': return 'Prête'; case 'annulee': return 'Annulée'; case 'servie': return 'Servie'; default: return statut; } } String get statutColor { switch (statut.toLowerCase()) { case 'payee': return '#28A745'; // Vert case 'en_cours': return '#FFC107'; // Jaune case 'pret': return '#17A2B8'; // Bleu case 'annulee': return '#DC3545'; // Rouge case 'servie': return '#6F42C1'; // Violet default: return '#6C757D'; // Gris } } // Calculs double get totalItems => items.fold(0, (sum, item) => sum + item.totalItem); int get totalQuantity => items.fold(0, (sum, item) => sum + item.quantite); @override String toString() { return 'CommandeDetail{id: $id, numeroCommande: $numeroCommande, statut: $statut, totalTtc: $totalTtc}'; } } class CommandeItem { final int id; final int commandeId; final int menuId; final int quantite; final double prixUnitaire; final double totalItem; final String? commentaires; final String statut; final DateTime createdAt; final DateTime updatedAt; final String menuNom; final String? menuDescription; final double menuPrixActuel; CommandeItem({ required this.id, required this.commandeId, required this.menuId, required this.quantite, required this.prixUnitaire, required this.totalItem, this.commentaires, required this.statut, required this.createdAt, required this.updatedAt, required this.menuNom, this.menuDescription, required this.menuPrixActuel, }); factory CommandeItem.fromJson(Map json) { return CommandeItem( id: json['id'] ?? 0, commandeId: json['commande_id'] ?? 0, menuId: json['menu_id'] ?? 0, quantite: json['quantite'] ?? 1, prixUnitaire: double.tryParse(json['prix_unitaire']?.toString() ?? '0') ?? 0.0, totalItem: double.tryParse(json['total_item']?.toString() ?? '0') ?? 0.0, commentaires: json['commentaires'], statut: json['statut'] ?? 'commande', createdAt: json['created_at'] != null ? DateTime.parse(json['created_at']) : DateTime.now(), updatedAt: json['updated_at'] != null ? DateTime.parse(json['updated_at']) : DateTime.now(), menuNom: json['menu_nom'] ?? json['name'] ?? 'Article inconnu', menuDescription: json['menu_description'] ?? json['description'], menuPrixActuel: double.tryParse(json['menu_prix_actuel']?.toString() ?? '0') ?? 0.0, ); } Map toJson() { return { 'id': id, 'commande_id': commandeId, 'menu_id': menuId, 'quantite': quantite, 'prix_unitaire': prixUnitaire.toString(), 'total_item': totalItem.toString(), 'commentaires': commentaires, 'statut': statut, 'created_at': createdAt.toIso8601String(), 'updated_at': updatedAt.toIso8601String(), 'menu_nom': menuNom, 'menu_description': menuDescription, 'menu_prix_actuel': menuPrixActuel.toString(), }; } // Getters pour la compatibilité avec l'ancien code String get name => menuNom; int get quantity => quantite; double get price => prixUnitaire; // Méthodes utilitaires String get statutText { switch (statut.toLowerCase()) { case 'commande': return 'Commandé'; case 'preparation': return 'En préparation'; case 'pret': return 'Prêt'; case 'servi': return 'Servi'; default: return statut; } } String get displayText => '$quantite× $menuNom'; bool get hasComments => commentaires != null && commentaires!.isNotEmpty; @override String toString() { return 'CommandeItem{id: $id, menuNom: $menuNom, quantite: $quantite, totalItem: $totalItem}'; } } // Énumération pour les statuts de commande enum CommandeStatut { enCours('en_cours', 'En cours'), pret('pret', 'Prête'), servie('servie', 'Servie'), payee('payee', 'Payée'), annulee('annulee', 'Annulée'); const CommandeStatut(this.value, this.displayName); final String value; final String displayName; static CommandeStatut fromString(String status) { return CommandeStatut.values.firstWhere( (e) => e.value == status.toLowerCase(), orElse: () => CommandeStatut.enCours, ); } } // Énumération pour les statuts d'items enum ItemStatut { commande('commande', 'Commandé'), preparation('preparation', 'En préparation'), pret('pret', 'Prêt'), servi('servi', 'Servi'); const ItemStatut(this.value, this.displayName); final String value; final String displayName; static ItemStatut fromString(String status) { return ItemStatut.values.firstWhere( (e) => e.value == status.toLowerCase(), orElse: () => ItemStatut.commande, ); } } // Classe de réponse API pour wrapper les données class CommandeDetailResponse { final bool success; final CommandeDetail data; final String? message; CommandeDetailResponse({ required this.success, required this.data, this.message, }); factory CommandeDetailResponse.fromJson(Map json) { return CommandeDetailResponse( success: json['success'] ?? false, data: CommandeDetail.fromJson(json), message: json['message'], ); } }