// 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 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, }); 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'], 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'], ); } }