// Remplacez complètement votre fichier CommandeDetails par celui-ci : import 'package:flutter/material.dart'; import 'package:youmazgestion/Models/client.dart'; import 'package:youmazgestion/Services/stock_managementDatabase.dart'; import 'package:intl/intl.dart'; class CommandeDetails extends StatelessWidget { final Commande commande; const CommandeDetails({required this.commande}); Widget _buildTableHeader(String text, {bool isAmount = false}) { return Padding( padding: const EdgeInsets.all(8.0), child: Text( text, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 14, ), textAlign: isAmount ? TextAlign.right : TextAlign.center, ), ); } Widget _buildTableCell(String text, {bool isAmount = false, Color? textColor}) { return Padding( padding: const EdgeInsets.all(8.0), child: Text( text, style: TextStyle( fontSize: 13, color: textColor, ), textAlign: isAmount ? TextAlign.right : TextAlign.center, ), ); } Widget _buildPriceColumn(DetailCommande detail) { if (detail.aRemise) { return Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( '${detail.prixUnitaire.toStringAsFixed(2)}', style: const TextStyle( fontSize: 11, decoration: TextDecoration.lineThrough, color: Colors.grey, ), ), const SizedBox(height: 2), Text( '${NumberFormat('#,##0', 'fr_FR').format(detail.prixFinal / detail.quantite)} MGA', style: TextStyle( fontSize: 13, fontWeight: FontWeight.bold, color: Colors.orange.shade700, ), ), ], ), ); } else { return _buildTableCell('${NumberFormat('#,##0', 'fr_FR').format(detail.prixUnitaire)} MGA', isAmount: true); } } Widget _buildRemiseColumn(DetailCommande detail) { return Padding( padding: const EdgeInsets.all(8.0), child: detail.aRemise ? Column( children: [ Text( detail.remiseDescription, style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: Colors.orange.shade700, ), textAlign: TextAlign.center, ), Text( '-${NumberFormat('#,##0', 'fr_FR').format(detail.montantRemise)} MGA', style: TextStyle( fontSize: 10, color: Colors.teal.shade700, ), textAlign: TextAlign.center, ), ], ) : const Text( '-', style: TextStyle(fontSize: 13, color: Colors.grey), textAlign: TextAlign.center, ), ); } Widget _buildTotalColumn(DetailCommande detail) { if (detail.aRemise && detail.sousTotal != detail.prixFinal) { return Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( '${detail.sousTotal.toStringAsFixed(2)}', style: const TextStyle( fontSize: 11, decoration: TextDecoration.lineThrough, color: Colors.grey, ), ), const SizedBox(height: 2), Text( '${NumberFormat('#,##0', 'fr_FR').format(detail.prixFinal)} MGA', style: const TextStyle( fontSize: 13, fontWeight: FontWeight.bold, ), ), ], ), ); } else { return _buildTableCell('${NumberFormat('#,##0', 'fr_FR').format(detail.prixFinal)} MGA', isAmount: true); } } @override Widget build(BuildContext context) { return FutureBuilder>( future: AppDatabase.instance.getDetailsCommande(commande.id!), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Text('Aucun détail disponible'); } final details = snapshot.data!; // Calculer les totaux double sousTotal = 0; double totalRemises = 0; double totalFinal = 0; bool hasRemises = false; for (final detail in details) { sousTotal += detail.sousTotal; totalRemises += detail.montantRemise; totalFinal += detail.prixFinal; if (detail.aRemise) hasRemises = true; } return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: hasRemises ? Colors.orange.shade50 : Colors.blue.shade50, borderRadius: BorderRadius.circular(8), border: hasRemises ? Border.all(color: Colors.orange.shade200) : null, ), child: Row( children: [ Icon( hasRemises ? Icons.discount : Icons.receipt_long, color: hasRemises ? Colors.orange.shade700 : Colors.blue.shade700, ), const SizedBox(width: 8), Text( hasRemises ? 'Détails de la commande (avec remises)' : 'Détails de la commande', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16, color: hasRemises ? Colors.orange.shade800 : Colors.black87, ), ), if (hasRemises) ...[ const Spacer(), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.orange.shade100, borderRadius: BorderRadius.circular(12), ), child: Text( 'Économies: ${NumberFormat('#,##0', 'fr_FR').format(totalRemises)} MGA', style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: Colors.orange.shade700, ), ), ), ], ], ), ), const SizedBox(height: 12), Container( decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade300), borderRadius: BorderRadius.circular(8), ), child: Table( children: [ TableRow( decoration: BoxDecoration( color: Colors.grey.shade100, ), children: [ _buildTableHeader('Produit'), _buildTableHeader('Qté'), _buildTableHeader('Prix unit.', isAmount: true), if (hasRemises) _buildTableHeader('Remise'), _buildTableHeader('Total', isAmount: true), ], ), ...details.map((detail) => TableRow( decoration: detail.aRemise ? BoxDecoration( color: const Color.fromARGB(255, 243, 191, 114), border: Border( left: BorderSide( color: Colors.orange.shade300, width: 3, ), ), ) : null, children: [ Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( detail.produitNom ?? 'Produit inconnu', style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w500, ), ), if (detail.aRemise) ...[ const SizedBox(height: 2), Row( children: [ Icon( Icons.local_offer, size: 12, color: Colors.teal.shade700, ), const SizedBox(width: 4), Text( 'Avec remise', style: TextStyle( fontSize: 10, color: Colors.teal.shade700, fontStyle: FontStyle.italic, ), ), ], ), ], ], ), ), _buildTableCell('${detail.quantite}'), _buildPriceColumn(detail), if (hasRemises) _buildRemiseColumn(detail), _buildTotalColumn(detail), ], )), ], ), ), const SizedBox(height: 12), // Section des totaux Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.green.shade50, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.green.shade200), ), child: Column( children: [ // Sous-total si il y a des remises if (hasRemises) ...[ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Sous-total:', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, ), ), Text( '${NumberFormat('#,##0', 'fr_FR').format(sousTotal)} MGA', style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w500, ), ), ], ), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Icon( Icons.discount, size: 16, color: Colors.orange.shade700, ), const SizedBox(width: 4), Text( 'Remises totales:', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Colors.orange.shade700, ), ), ], ), Text( '-${NumberFormat('#,##0', 'fr_FR').format(totalRemises)} MGA', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Colors.orange.shade700, ), ), ], ), const Divider(height: 16), ], // Total final Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Total de la commande:', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), Text( '${NumberFormat('#,##0', 'fr_FR').format(commande.montantTotal)} MGA', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 18, color: Colors.green.shade700, ), ), ], ), ], ), ), ], ); }, ); } }