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
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|