// pages/facture_screen.dart import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../models/command_detail.dart'; import '../services/pdf_service.dart'; import 'package:intl/intl.dart'; class FactureScreen extends StatefulWidget { final CommandeDetail commande; final String paymentMethod; final String? tablename; const FactureScreen({ super.key, required this.commande, required this.paymentMethod, this.tablename, }); @override _FactureScreenState createState() => _FactureScreenState(); } class _FactureScreenState extends State { String get paymentMethodText { switch (widget.paymentMethod) { case 'mvola': return 'MVola'; case 'carte': return 'CB'; case 'especes': return 'Espèces'; default: return 'CB'; } } String get factureNumber { return 'F${DateTime.now().millisecondsSinceEpoch.toString().substring(7)}'; } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[100], appBar: AppBar( backgroundColor: Colors.white, elevation: 0, leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () => Navigator.of(context).pop(), ), title: const Text( 'Retour', style: TextStyle( color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500, ), ), actions: [ Container( margin: const EdgeInsets.only(right: 16, top: 8, bottom: 8), child: ElevatedButton.icon( onPressed: _printReceipt, icon: const Icon(Icons.print, size: 18), label: const Text('Imprimer'), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF28A745), foregroundColor: Colors.white, elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 8, ), ), ), ), ], ), body: Center( child: Container( width: 400, margin: const EdgeInsets.all(20), child: Card( elevation: 2, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), child: Padding( padding: const EdgeInsets.all(40), child: Column( mainAxisSize: MainAxisSize.min, children: [ _buildHeader(), const SizedBox(height: 30), _buildFactureInfo(), const SizedBox(height: 30), _buildItemsList(), const SizedBox(height: 20), _buildTotal(), const SizedBox(height: 30), _buildFooter(), ], ), ), ), ), ), ); } Widget _buildHeader() { return const Column( children: [ Text( 'RESTAURANT ITRIMOBE', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, letterSpacing: 1.2, ), ), SizedBox(height: 12), Text( 'Adresse: Moramanga, Madagascar', style: TextStyle(fontSize: 12, color: Colors.black87), ), Text( 'Contact: +261 34 12 34 56', style: TextStyle(fontSize: 12, color: Colors.black87), ), Text( 'NIF: 4002141594', style: TextStyle(fontSize: 12, color: Colors.black87), ), Text( 'STAT: 10715 33 2025 0 00414', style: TextStyle(fontSize: 12, color: Colors.black87), ), ], ); } Widget _buildFactureInfo() { final now = DateTime.now(); final dateStr = '${now.day.toString().padLeft(2, '0')}/${now.month.toString().padLeft(2, '0')}/${now.year}'; final timeStr = '${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}'; return Column( children: [ Text( 'Facture n° $factureNumber', style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600), ), const SizedBox(height: 4), Text( 'Date: $dateStr $timeStr', style: const TextStyle(fontSize: 12, color: Colors.black87), ), const SizedBox(height: 4), Text( 'Via: ${widget.commande?.tablename ?? widget.tablename}', style: const TextStyle(fontSize: 12, color: Colors.black87), ), const SizedBox(height: 4), Text( 'Paiement: $paymentMethodText', style: const TextStyle(fontSize: 12, color: Colors.black87), ), ], ); } Widget _buildItemsList() { return Column( children: [ const Padding( padding: EdgeInsets.only(bottom: 10), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Qté Désignation', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600), ), Text( 'Prix', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600), ), ], ), ), const Divider(height: 1, color: Colors.black26), const SizedBox(height: 10), ...widget.commande.items .map( (item) => Padding( padding: const EdgeInsets.only(bottom: 6), child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( '${item.quantite} ${item.menuNom}', style: const TextStyle( fontSize: 12, color: Colors.black87, ), ), ), Text( '${NumberFormat("#,##0.00", "fr_FR").format(item.prixUnitaire * item.quantite)} AR', style: const TextStyle( fontSize: 12, color: Colors.black87, ), ), ], ), ), ) .toList(), ], ); } Widget _buildTotal() { return Column( children: [ const Divider(height: 1, color: Colors.black26), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Total:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), Text( '${NumberFormat("#,##0.00", "fr_FR").format(widget.commande.totalTtc)} AR', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ], ), ], ); } Widget _buildFooter() { return const Text( 'Merci et à bientôt !', style: TextStyle( fontSize: 12, fontStyle: FontStyle.italic, color: Colors.black54, ), ); } void _printReceipt() async { bool isPrinting = false; setState(() => isPrinting = true); try { // Vérifier si l'impression est disponible final canPrint = await PlatformPrintService.canPrint(); if (!canPrint) { // Si pas d'imprimante, proposer seulement la sauvegarde _showSaveOnlyDialog(); return; } // Afficher les options d'impression final action = await showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Row( children: [ Icon(Icons.print, color: Theme.of(context).primaryColor), const SizedBox(width: 8), const Text('Options d\'impression'), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Plateforme: ${_getPlatformName()}', style: const TextStyle(fontSize: 12, color: Colors.grey), ), const SizedBox(height: 16), const Text('Que souhaitez-vous faire ?'), ], ), actions: [ TextButton.icon( onPressed: () => Navigator.of(context).pop('print'), icon: const Icon(Icons.print), label: const Text('Imprimer'), ), TextButton.icon( onPressed: () => Navigator.of(context).pop('save'), icon: const Icon(Icons.save), label: const Text('Sauvegarder PDF'), ), TextButton( onPressed: () => Navigator.of(context).pop('cancel'), child: const Text('Annuler'), ), ], ); }, ); if (action == null || action == 'cancel') return; HapticFeedback.lightImpact(); bool success = false; if (action == 'print') { success = await PlatformPrintService.printFacture( commande: widget.commande, paymentMethod: widget.paymentMethod, ); } else if (action == 'save') { success = await PlatformPrintService.saveFacturePdf( commande: widget.commande, paymentMethod: widget.paymentMethod, ); } if (success) { _showSuccessMessage( action == 'print' ? 'Facture envoyée à l\'imprimante ${_getPlatformName()}' : 'PDF sauvegardé avec succès', ); } else { _showErrorMessage( 'Erreur lors de ${action == 'print' ? 'l\'impression' : 'la sauvegarde'}', ); } } catch (e) { _showErrorMessage('Erreur: $e'); } finally { setState(() => isPrinting = false); } } void _showSaveOnlyDialog() async { final shouldSave = await showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Aucune imprimante'), content: const Text( 'Aucune imprimante détectée. Voulez-vous sauvegarder le PDF ?', ), actions: [ TextButton.icon( onPressed: () => Navigator.of(context).pop(true), icon: const Icon(Icons.save), label: const Text('Sauvegarder'), ), TextButton( onPressed: () => Navigator.of(context).pop(false), child: const Text('Annuler'), ), ], ); }, ); if (shouldSave == true) { final success = await PlatformPrintService.saveFacturePdf( commande: widget.commande, paymentMethod: widget.paymentMethod, ); if (success) { _showSuccessMessage('PDF sauvegardé avec succès'); } else { _showErrorMessage('Erreur lors de la sauvegarde'); } } } void _showSuccessMessage(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row( children: [ const Icon(Icons.check_circle, color: Colors.white), const SizedBox(width: 8), Expanded(child: Text(message)), ], ), backgroundColor: const Color(0xFF28A745), duration: const Duration(seconds: 3), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)), margin: const EdgeInsets.all(16), behavior: SnackBarBehavior.floating, ), ); Future.delayed(const Duration(seconds: 3), () { if (mounted) { Navigator.of(context).popUntil((route) => route.isFirst); } }); } void _showErrorMessage(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row( children: [ const Icon(Icons.error, color: Colors.white), const SizedBox(width: 8), Expanded(child: Text(message)), ], ), backgroundColor: Colors.red, duration: const Duration(seconds: 3), margin: const EdgeInsets.all(16), behavior: SnackBarBehavior.floating, ), ); } String _getPlatformName() { if (Platform.isAndroid) return 'Android'; if (Platform.isMacOS) return 'macOS'; if (Platform.isWindows) return 'Windows'; return 'cette plateforme'; } }