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.
 
 
 
 
 
 

266 lines
8.4 KiB

// services/pdf_service.dart
import 'dart:io';
import 'dart:typed_data';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
import '../models/command_detail.dart';
class PdfService {
static Future<Uint8List> generateFacturePdf({
required CommandeDetail commande,
required String paymentMethod,
}) async {
final pdf = pw.Document();
// Informations du restaurant
final restaurantInfo = {
'nom': 'RESTAURANT',
'adresse': 'Moramanga, Antananarivo',
'contact': '+261 34 12 34 56',
};
// Générer numéro de facture
final factureNumber =
'F${DateTime.now().millisecondsSinceEpoch.toString().substring(7)}';
final dateTime = DateTime.now();
pdf.addPage(
pw.Page(
pageFormat: PdfPageFormat.a4,
margin: const pw.EdgeInsets.all(32),
build: (pw.Context context) {
return pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
// En-tête Restaurant
pw.Center(
child: pw.Column(
children: [
pw.Text(
restaurantInfo['nom']!,
style: pw.TextStyle(
fontSize: 24,
fontWeight: pw.FontWeight.bold,
),
),
pw.SizedBox(height: 8),
pw.Text(
'Adresse: ${restaurantInfo['adresse']}',
style: const pw.TextStyle(fontSize: 12),
),
pw.Text(
'Contact: ${restaurantInfo['contact']}',
style: const pw.TextStyle(fontSize: 12),
),
],
),
),
pw.SizedBox(height: 30),
// Informations facture
pw.Center(
child: pw.Column(
children: [
pw.Text(
'Facture n° $factureNumber',
style: pw.TextStyle(
fontSize: 14,
fontWeight: pw.FontWeight.bold,
),
),
pw.SizedBox(height: 4),
pw.Text(
'Date: ${_formatDateTime(dateTime)}',
style: const pw.TextStyle(fontSize: 12),
),
pw.SizedBox(height: 4),
pw.Text(
'Table: ${commande.numeroCommande}',
style: const pw.TextStyle(fontSize: 12),
),
pw.SizedBox(height: 4),
pw.Text(
'Paiement: ${_getPaymentMethodText(paymentMethod)}',
style: const pw.TextStyle(fontSize: 12),
),
],
),
),
pw.SizedBox(height: 30),
// Tableau des articles
pw.Table(
border: pw.TableBorder.all(color: PdfColors.grey300),
columnWidths: {
0: const pw.FlexColumnWidth(3),
1: const pw.FlexColumnWidth(1),
2: const pw.FlexColumnWidth(1),
},
children: [
// En-tête du tableau
pw.TableRow(
decoration: const pw.BoxDecoration(
color: PdfColors.grey100,
),
children: [
pw.Padding(
padding: const pw.EdgeInsets.all(8),
child: pw.Text(
'Qté Désignation',
style: pw.TextStyle(fontWeight: pw.FontWeight.bold),
),
),
pw.Padding(
padding: const pw.EdgeInsets.all(8),
child: pw.Text(
'Prix',
style: pw.TextStyle(fontWeight: pw.FontWeight.bold),
textAlign: pw.TextAlign.right,
),
),
],
),
// Lignes des articles
...commande.items
.map(
(item) => pw.TableRow(
children: [
pw.Padding(
padding: const pw.EdgeInsets.all(8),
child: pw.Text(
'${item.quantite} TESTNOMCOMMANDE',
),
),
pw.Padding(
padding: const pw.EdgeInsets.all(8),
child: pw.Text(
'${item.prixUnitaire.toStringAsFixed(2)}',
textAlign: pw.TextAlign.right,
),
),
],
),
)
.toList(),
],
),
pw.SizedBox(height: 20),
// Total
pw.Container(
alignment: pw.Alignment.centerRight,
child: pw.Container(
padding: const pw.EdgeInsets.all(12),
decoration: pw.BoxDecoration(
border: pw.Border.all(color: PdfColors.grey400),
color: PdfColors.grey50,
),
child: pw.Text(
'Total: ${commande.totalTtc.toStringAsFixed(2)}',
style: pw.TextStyle(
fontSize: 16,
fontWeight: pw.FontWeight.bold,
),
),
),
),
pw.Spacer(),
// Message de remerciement
pw.Center(
child: pw.Text(
'Merci et à bientôt !',
style: pw.TextStyle(
fontSize: 12,
fontStyle: pw.FontStyle.italic,
),
),
),
],
);
},
),
);
return pdf.save();
}
static String _formatDateTime(DateTime dateTime) {
return '${dateTime.day.toString().padLeft(2, '0')}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.year} ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
}
static String _getPaymentMethodText(String method) {
switch (method) {
case 'mvola':
return 'MVola';
case 'carte':
return 'CB';
case 'especes':
return 'Espèces';
default:
return 'CB';
}
}
// Imprimer directement
static Future<bool> printFacture({
required CommandeDetail commande,
required String paymentMethod,
}) async {
try {
final pdfData = await generateFacturePdf(
commande: commande,
paymentMethod: paymentMethod,
);
await Printing.layoutPdf(
onLayout: (PdfPageFormat format) async => pdfData,
name:
'Facture_${commande.numeroCommande}_${DateTime.now().millisecondsSinceEpoch}',
);
return true;
} catch (e) {
print('Erreur impression: $e');
return false;
}
}
// Sauvegarder et partager le PDF
static Future<bool> saveAndShareFacture({
required CommandeDetail commande,
required String paymentMethod,
}) async {
try {
final pdfData = await generateFacturePdf(
commande: commande,
paymentMethod: paymentMethod,
);
final directory = await getApplicationDocumentsDirectory();
final fileName =
'Facture_${commande.numeroCommande}_${DateTime.now().millisecondsSinceEpoch}.pdf';
final file = File('${directory.path}/$fileName');
await file.writeAsBytes(pdfData);
await Share.shareXFiles(
[XFile(file.path)],
subject: 'Facture ${commande.numeroCommande}',
text: 'Facture de votre commande au restaurant',
);
return true;
} catch (e) {
print('Erreur sauvegarde/partage: $e');
return false;
}
}
}