You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

305 lines
8.6 KiB

// pages/facture_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../models/command_detail.dart';
import '../services/pdf_service.dart';
class FactureScreen extends StatefulWidget {
final CommandeDetail commande;
final String paymentMethod;
const FactureScreen({
Key? key,
required this.commande,
required this.paymentMethod,
}) : super(key: key);
@override
_FactureScreenState createState() => _FactureScreenState();
}
class _FactureScreenState extends State<FactureScreen> {
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 Column(
children: [
const Text(
'RESTAURANT',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
letterSpacing: 1.2,
),
),
const SizedBox(height: 12),
const Text(
'Adresse: 123 Rue de la Paix',
style: TextStyle(fontSize: 12, color: Colors.black87),
),
const Text(
'Contact: +33 1 23 45 67 89',
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(
'Table: ${widget.commande.tableId}',
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(
'${(item.prixUnitaire * item.quantite).toStringAsFixed(2)} MGA',
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(
'${widget.commande.totalTtc.toStringAsFixed(2)}',
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 {
try {
HapticFeedback.lightImpact();
final success = await PdfService.printFacture(
commande: widget.commande,
paymentMethod: widget.paymentMethod,
);
if (success) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Row(
children: [
Icon(Icons.check_circle, color: Colors.white),
SizedBox(width: 8),
Text('Facture envoyée à l\'impression'),
],
),
backgroundColor: const Color(0xFF28A745),
duration: const Duration(seconds: 2),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
margin: const EdgeInsets.all(16),
behavior: SnackBarBehavior.floating,
),
);
Future.delayed(const Duration(seconds: 2), () {
if (mounted) {
Navigator.of(context).popUntil((route) => route.isFirst);
}
});
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Erreur impression: $e'),
backgroundColor: Colors.red,
),
);
} finally {
if (mounted) {
Navigator.of(context).pop();
}
}
}
}