|
|
@ -60,6 +60,8 @@ class PlatformPrintService { |
|
|
'ville': 'Madagascar', |
|
|
'ville': 'Madagascar', |
|
|
'contact': '261348415301', |
|
|
'contact': '261348415301', |
|
|
'email': 'contact@careeragency.mg', |
|
|
'email': 'contact@careeragency.mg', |
|
|
|
|
|
'nif': '4002141594', |
|
|
|
|
|
'stat': '10715 33 2025 0 00414', |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
final factureNumber = |
|
|
final factureNumber = |
|
|
@ -69,223 +71,267 @@ class PlatformPrintService { |
|
|
pdf.addPage( |
|
|
pdf.addPage( |
|
|
pw.Page( |
|
|
pw.Page( |
|
|
pageFormat: ticket58mmFormat, |
|
|
pageFormat: ticket58mmFormat, |
|
|
|
|
|
margin: const pw.EdgeInsets.all(2), // 🔧 Marges minimales |
|
|
build: (pw.Context context) { |
|
|
build: (pw.Context context) { |
|
|
return pw.Column( |
|
|
return pw.Container( |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.center, |
|
|
width: double.infinity, // 🔧 Forcer la largeur complète |
|
|
children: [ |
|
|
child: pw.Column( |
|
|
// En-tête Restaurant (centré et compact) |
|
|
crossAxisAlignment: |
|
|
pw.Text( |
|
|
pw.CrossAxisAlignment.start, // 🔧 Alignement à gauche |
|
|
restaurantInfo['nom']!, |
|
|
children: [ |
|
|
style: pw.TextStyle( |
|
|
// En-tête Restaurant (centré et compact) |
|
|
fontSize: titleSize, |
|
|
pw.Container( |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
width: double.infinity, |
|
|
), |
|
|
child: pw.Text( |
|
|
textAlign: pw.TextAlign.center, |
|
|
restaurantInfo['nom']!, |
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 1), |
|
|
|
|
|
|
|
|
|
|
|
pw.Text( |
|
|
|
|
|
restaurantInfo['adresse']!, |
|
|
|
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.Text( |
|
|
|
|
|
restaurantInfo['ville']!, |
|
|
|
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.Text( |
|
|
|
|
|
'Tel: ${restaurantInfo['contact']!}', |
|
|
|
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 3), |
|
|
|
|
|
|
|
|
|
|
|
// Ligne de séparation |
|
|
|
|
|
pw.Container( |
|
|
|
|
|
width: double.infinity, |
|
|
|
|
|
height: 0.5, |
|
|
|
|
|
color: PdfColors.black, |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 2), |
|
|
|
|
|
|
|
|
|
|
|
// Informations ticket |
|
|
|
|
|
pw.Row( |
|
|
|
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
|
|
|
|
|
children: [ |
|
|
|
|
|
pw.Text( |
|
|
|
|
|
'Ticket: $factureNumber', |
|
|
|
|
|
style: pw.TextStyle( |
|
|
style: pw.TextStyle( |
|
|
fontSize: bodySize, |
|
|
fontSize: titleSize, |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
), |
|
|
), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
), |
|
|
), |
|
|
pw.Text( |
|
|
), |
|
|
'Via: ${commande.tablename ?? 'Table inconnue'}', |
|
|
|
|
|
style: pw.TextStyle(fontSize: bodySize), |
|
|
pw.SizedBox(height: 1), |
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 1), |
|
|
pw.Container( |
|
|
|
|
|
width: double.infinity, |
|
|
|
|
|
child: pw.Text( |
|
|
|
|
|
restaurantInfo['adresse']!, |
|
|
|
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
pw.Row( |
|
|
pw.Container( |
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
|
|
width: double.infinity, |
|
|
children: [ |
|
|
child: pw.Text( |
|
|
pw.Text( |
|
|
restaurantInfo['ville']!, |
|
|
_formatDate(dateTime), |
|
|
|
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
), |
|
|
), |
|
|
pw.Text( |
|
|
), |
|
|
_formatTime(dateTime), |
|
|
|
|
|
|
|
|
pw.Container( |
|
|
|
|
|
width: double.infinity, |
|
|
|
|
|
child: pw.Text( |
|
|
|
|
|
'Tel: ${restaurantInfo['contact']!}', |
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
), |
|
|
), |
|
|
], |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
pw.SizedBox(height: 3), |
|
|
pw.SizedBox(height: 2), |
|
|
|
|
|
|
|
|
// Ligne de séparation |
|
|
// Ligne de séparation |
|
|
pw.Container( |
|
|
pw.Container( |
|
|
width: double.infinity, |
|
|
width: double.infinity, |
|
|
height: 0.5, |
|
|
height: 0.5, |
|
|
color: PdfColors.black, |
|
|
color: PdfColors.black, |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
pw.SizedBox(height: 2), |
|
|
pw.SizedBox(height: 2), |
|
|
|
|
|
|
|
|
// Informations ticket |
|
|
// Articles (format très compact) |
|
|
pw.Container( |
|
|
...commande.items |
|
|
width: double.infinity, |
|
|
.map( |
|
|
child: pw.Row( |
|
|
(item) => pw.Container( |
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
|
|
margin: const pw.EdgeInsets.only(bottom: 1), |
|
|
children: [ |
|
|
child: pw.Column( |
|
|
pw.Text( |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
'Ticket: $factureNumber', |
|
|
children: [ |
|
|
style: pw.TextStyle( |
|
|
// Nom du plat |
|
|
fontSize: bodySize, |
|
|
pw.Text( |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
'${item.menuNom}', |
|
|
), |
|
|
style: pw.TextStyle(fontSize: bodySize), |
|
|
), |
|
|
maxLines: 2, |
|
|
], |
|
|
), |
|
|
), |
|
|
|
|
|
), |
|
|
// Quantité, prix unitaire et total sur une ligne |
|
|
|
|
|
pw.Row( |
|
|
pw.SizedBox(height: 1), |
|
|
mainAxisAlignment: |
|
|
|
|
|
pw.MainAxisAlignment.spaceBetween, |
|
|
pw.Container( |
|
|
children: [ |
|
|
width: double.infinity, |
|
|
pw.Text( |
|
|
child: pw.Row( |
|
|
'${item.quantite}x ${item.prixUnitaire.toStringAsFixed(2)}MGA', |
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
children: [ |
|
|
|
|
|
pw.Text( |
|
|
|
|
|
_formatDate(dateTime), |
|
|
|
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
|
|
|
), |
|
|
|
|
|
pw.Text( |
|
|
|
|
|
_formatTime(dateTime), |
|
|
|
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 2), |
|
|
|
|
|
|
|
|
|
|
|
// Ligne de séparation |
|
|
|
|
|
pw.Container( |
|
|
|
|
|
width: double.infinity, |
|
|
|
|
|
height: 0.5, |
|
|
|
|
|
color: PdfColors.black, |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 2), |
|
|
|
|
|
|
|
|
|
|
|
// Articles (format très compact) |
|
|
|
|
|
...commande.items |
|
|
|
|
|
.map( |
|
|
|
|
|
(item) => pw.Container( |
|
|
|
|
|
width: double.infinity, // 🔧 Largeur complète |
|
|
|
|
|
margin: const pw.EdgeInsets.only(bottom: 1), |
|
|
|
|
|
child: pw.Column( |
|
|
|
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
|
|
|
children: [ |
|
|
|
|
|
// Nom du plat |
|
|
|
|
|
pw.Container( |
|
|
|
|
|
width: double.infinity, |
|
|
|
|
|
child: pw.Text( |
|
|
|
|
|
'${item.menuNom}', |
|
|
|
|
|
style: pw.TextStyle(fontSize: bodySize), |
|
|
|
|
|
maxLines: 2, |
|
|
), |
|
|
), |
|
|
pw.Text( |
|
|
), |
|
|
'${(item.prixUnitaire * item.quantite).toStringAsFixed(2)}MGA', |
|
|
|
|
|
style: pw.TextStyle( |
|
|
// Quantité, prix unitaire et total sur une ligne |
|
|
fontSize: bodySize, |
|
|
pw.Container( |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
width: double.infinity, |
|
|
), |
|
|
child: pw.Row( |
|
|
|
|
|
mainAxisAlignment: |
|
|
|
|
|
pw.MainAxisAlignment.spaceBetween, |
|
|
|
|
|
children: [ |
|
|
|
|
|
pw.Text( |
|
|
|
|
|
'${item.quantite}x ${item.prixUnitaire.toStringAsFixed(2)}MGA', |
|
|
|
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
|
|
|
), |
|
|
|
|
|
pw.Text( |
|
|
|
|
|
'${(item.prixUnitaire * item.quantite).toStringAsFixed(2)}MGA', |
|
|
|
|
|
style: pw.TextStyle( |
|
|
|
|
|
fontSize: bodySize, |
|
|
|
|
|
fontWeight: pw.FontWeight.bold, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
], |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
) |
|
|
) |
|
|
.toList(), |
|
|
.toList(), |
|
|
|
|
|
|
|
|
pw.SizedBox(height: 2), |
|
|
pw.SizedBox(height: 2), |
|
|
|
|
|
|
|
|
// Ligne de séparation |
|
|
// Ligne de séparation |
|
|
pw.Container( |
|
|
pw.Container( |
|
|
width: double.infinity, |
|
|
width: double.infinity, |
|
|
height: 0.5, |
|
|
height: 0.5, |
|
|
color: PdfColors.black, |
|
|
color: PdfColors.black, |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
pw.SizedBox(height: 2), |
|
|
pw.SizedBox(height: 2), |
|
|
|
|
|
|
|
|
// Total |
|
|
// Total |
|
|
pw.Container( |
|
|
pw.Row( |
|
|
width: double.infinity, |
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
|
|
child: pw.Row( |
|
|
children: [ |
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
|
|
pw.Text( |
|
|
children: [ |
|
|
'TOTAL', |
|
|
pw.Text( |
|
|
style: pw.TextStyle( |
|
|
'TOTAL', |
|
|
fontSize: titleSize, |
|
|
style: pw.TextStyle( |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
fontSize: titleSize, |
|
|
), |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
pw.Text( |
|
|
|
|
|
'${commande.totalTtc.toStringAsFixed(2)}MGA', |
|
|
|
|
|
style: pw.TextStyle( |
|
|
|
|
|
fontSize: titleSize, |
|
|
|
|
|
fontWeight: pw.FontWeight.bold, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 3), |
|
|
|
|
|
|
|
|
|
|
|
// Mode de paiement |
|
|
|
|
|
pw.Container( |
|
|
|
|
|
width: double.infinity, |
|
|
|
|
|
child: pw.Text( |
|
|
|
|
|
'Paiement: ${paymentMethod.toLowerCase()}', |
|
|
|
|
|
style: pw.TextStyle(fontSize: bodySize), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
), |
|
|
), |
|
|
pw.Text( |
|
|
), |
|
|
'${commande.totalTtc.toStringAsFixed(2)}MGA', |
|
|
|
|
|
|
|
|
pw.SizedBox(height: 3), |
|
|
|
|
|
|
|
|
|
|
|
// Ligne de séparation |
|
|
|
|
|
pw.Container( |
|
|
|
|
|
width: double.infinity, |
|
|
|
|
|
height: 0.5, |
|
|
|
|
|
color: PdfColors.black, |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 2), |
|
|
|
|
|
|
|
|
|
|
|
// Message de remerciement |
|
|
|
|
|
pw.Container( |
|
|
|
|
|
width: double.infinity, |
|
|
|
|
|
child: pw.Text( |
|
|
|
|
|
'Merci de votre visite !', |
|
|
style: pw.TextStyle( |
|
|
style: pw.TextStyle( |
|
|
fontSize: titleSize, |
|
|
fontSize: bodySize, |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
fontStyle: pw.FontStyle.italic, |
|
|
), |
|
|
), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
), |
|
|
), |
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 3), |
|
|
|
|
|
|
|
|
|
|
|
// Mode de paiement |
|
|
|
|
|
pw.Text( |
|
|
|
|
|
'Paiement: ${_getPaymentMethodText(paymentMethod)}', |
|
|
|
|
|
style: pw.TextStyle(fontSize: bodySize), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 3), |
|
|
|
|
|
|
|
|
|
|
|
// Ligne de séparation |
|
|
|
|
|
pw.Container( |
|
|
|
|
|
width: double.infinity, |
|
|
|
|
|
height: 0.5, |
|
|
|
|
|
color: PdfColors.black, |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 2), |
|
|
|
|
|
|
|
|
|
|
|
// Message de remerciement |
|
|
|
|
|
pw.Text( |
|
|
|
|
|
'Merci de votre visite !', |
|
|
|
|
|
style: pw.TextStyle( |
|
|
|
|
|
fontSize: bodySize, |
|
|
|
|
|
fontStyle: pw.FontStyle.italic, |
|
|
|
|
|
), |
|
|
), |
|
|
textAlign: pw.TextAlign.center, |
|
|
|
|
|
), |
|
|
pw.Container( |
|
|
|
|
|
width: double.infinity, |
|
|
pw.Text( |
|
|
child: pw.Text( |
|
|
'A bientôt !', |
|
|
'A bientôt !', |
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
textAlign: pw.TextAlign.center, |
|
|
textAlign: pw.TextAlign.center, |
|
|
), |
|
|
), |
|
|
|
|
|
), |
|
|
pw.SizedBox(height: 3), |
|
|
|
|
|
|
|
|
pw.SizedBox(height: 3), |
|
|
// Code de suivi (optionnel) |
|
|
|
|
|
pw.Text( |
|
|
// Code de suivi (optionnel) |
|
|
'Code: ${factureNumber}', |
|
|
pw.Container( |
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
width: double.infinity, |
|
|
textAlign: pw.TextAlign.center, |
|
|
child: pw.Text( |
|
|
), |
|
|
'Code: ${factureNumber}', |
|
|
|
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
pw.SizedBox(height: 4), |
|
|
textAlign: pw.TextAlign.center, |
|
|
|
|
|
), |
|
|
// Ligne de découpe |
|
|
), |
|
|
pw.Text( |
|
|
|
|
|
'- - - - - - - - - - - - - - - -', |
|
|
pw.SizedBox(height: 4), |
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
// Ligne de découpe |
|
|
), |
|
|
pw.Container( |
|
|
|
|
|
width: double.infinity, |
|
|
pw.SizedBox(height: 2), |
|
|
child: pw.Text( |
|
|
], |
|
|
'- - - - - - - - - - - - - - - -', |
|
|
|
|
|
style: pw.TextStyle(fontSize: smallSize), |
|
|
|
|
|
textAlign: pw.TextAlign.center, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 2), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
), |
|
|
), |
|
|
|