|
|
@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; |
|
|
import 'package:flutter/services.dart'; |
|
|
import 'package:flutter/services.dart'; |
|
|
import 'package:get/get.dart'; |
|
|
import 'package:get/get.dart'; |
|
|
import 'package:intl/intl.dart'; |
|
|
import 'package:intl/intl.dart'; |
|
|
|
|
|
import 'package:numbers_to_letters/numbers_to_letters.dart'; |
|
|
import 'package:pdf/pdf.dart'; |
|
|
import 'package:pdf/pdf.dart'; |
|
|
import 'package:pdf/widgets.dart' as pw; |
|
|
import 'package:pdf/widgets.dart' as pw; |
|
|
import 'package:path_provider/path_provider.dart'; |
|
|
import 'package:path_provider/path_provider.dart'; |
|
|
@ -118,10 +119,6 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> { |
|
|
message = 'Commande annulée avec succès'; |
|
|
message = 'Commande annulée avec succès'; |
|
|
backgroundColor = Colors.orange; |
|
|
backgroundColor = Colors.orange; |
|
|
break; |
|
|
break; |
|
|
case StatutCommande.livree: |
|
|
|
|
|
message = 'Commande marquée comme livrée'; |
|
|
|
|
|
backgroundColor = Colors.green; |
|
|
|
|
|
break; |
|
|
|
|
|
case StatutCommande.confirmee: |
|
|
case StatutCommande.confirmee: |
|
|
message = 'Commande confirmée'; |
|
|
message = 'Commande confirmée'; |
|
|
backgroundColor = Colors.blue; |
|
|
backgroundColor = Colors.blue; |
|
|
@ -230,39 +227,54 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> { |
|
|
}, |
|
|
}, |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
Future<pw.Widget> buildIconPhoneText() async { |
|
|
|
|
|
final font = pw.Font.ttf(await rootBundle.load('assets/fa-solid-900.ttf')); |
|
|
|
|
|
return pw.Text(String.fromCharCode(0xf095), style: pw.TextStyle(font: font)); |
|
|
|
|
|
} |
|
|
|
|
|
Future<pw.Widget> buildIconCheckedText() async { |
|
|
|
|
|
final font = pw.Font.ttf(await rootBundle.load('assets/fa-solid-900.ttf')); |
|
|
|
|
|
return pw.Text(String.fromCharCode(0xf14a), style: pw.TextStyle(font: font)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Future<pw.Widget> buildIconGlobeText() async { |
|
|
|
|
|
final font = pw.Font.ttf(await rootBundle.load('assets/fa-solid-900.ttf')); |
|
|
|
|
|
return pw.Text(String.fromCharCode(0xf0ac), style: pw.TextStyle(font: font)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _generateInvoice(Commande commande) async { |
|
|
Future<void> _generateInvoice(Commande commande) async { |
|
|
final details = await _database.getDetailsCommande(commande.id!); |
|
|
final details = await _database.getDetailsCommande(commande.id!); |
|
|
final client = await _database.getClientById(commande.clientId); |
|
|
final client = await _database.getClientById(commande.clientId); |
|
|
final commandeur = commande.commandeurId != null |
|
|
final pointDeVente = await _database.getPointDeVenteById(1); |
|
|
? await _database.getUserById(commande.commandeurId!) |
|
|
final iconPhone = await buildIconPhoneText(); |
|
|
: null; |
|
|
final iconChecked = await buildIconCheckedText(); |
|
|
final validateur = commande.validateurId != null |
|
|
final iconGlobe = await buildIconGlobeText(); |
|
|
? await _database.getUserById(commande.validateurId!) |
|
|
|
|
|
: null; |
|
|
// IMPORTANT: Récupérer tous les détails des produits AVANT de créer le PDF |
|
|
final pointDeVente = commandeur?.pointDeVenteId != null |
|
|
final List<Map<String, dynamic>> detailsAvecProduits = []; |
|
|
? await _database.getPointDeVenteById(commandeur!.pointDeVenteId!) |
|
|
for (final detail in details) { |
|
|
: null; |
|
|
final produit = await _database.getProductById(detail.produitId); |
|
|
|
|
|
detailsAvecProduits.add({ |
|
|
|
|
|
'detail': detail, |
|
|
|
|
|
'produit': produit, |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
final pdf = pw.Document(); |
|
|
final pdf = pw.Document(); |
|
|
final imageBytes = await loadImage(); |
|
|
final imageBytes = await loadImage(); |
|
|
final image = pw.MemoryImage(imageBytes); |
|
|
final image = pw.MemoryImage(imageBytes); |
|
|
|
|
|
final italicFont = pw.Font.ttf(await rootBundle.load('assets/fonts/Roboto-Italic.ttf')); |
|
|
final headerStyle = pw.TextStyle( |
|
|
|
|
|
fontSize: 18, |
|
|
// Styles de texte |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
final smallTextStyle = pw.TextStyle(fontSize: 9); |
|
|
color: PdfColors.blue900, |
|
|
final smallBoldTextStyle = pw.TextStyle(fontSize: 9, fontWeight: pw.FontWeight.bold); |
|
|
); |
|
|
final normalTextStyle = pw.TextStyle(fontSize: 10); |
|
|
|
|
|
final boldTextStyle = pw.TextStyle(fontSize: 10, fontWeight: pw.FontWeight.bold); |
|
|
final titleStyle = pw.TextStyle( |
|
|
final boldTexClienttStyle = pw.TextStyle(fontSize: 12, fontWeight: pw.FontWeight.bold); |
|
|
fontSize: 14, |
|
|
final frameTextStyle = pw.TextStyle(fontSize: 10); |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
final italicTextStyle = pw.TextStyle(fontSize: 9, fontWeight: pw.FontWeight.bold, font: italicFont); |
|
|
); |
|
|
final italicTextStyleLogo = pw.TextStyle(fontSize: 7, fontWeight: pw.FontWeight.bold, font: italicFont); |
|
|
|
|
|
|
|
|
final subtitleStyle = pw.TextStyle( |
|
|
|
|
|
fontSize: 12, |
|
|
|
|
|
color: PdfColors.grey600, |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
pdf.addPage( |
|
|
pdf.addPage( |
|
|
pw.Page( |
|
|
pw.Page( |
|
|
@ -271,208 +283,237 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> { |
|
|
return pw.Column( |
|
|
return pw.Column( |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
children: [ |
|
|
children: [ |
|
|
|
|
|
// Première ligne: Logo à gauche, informations à droite |
|
|
pw.Row( |
|
|
pw.Row( |
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
|
|
|
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
|
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
|
|
children: [ |
|
|
children: [ |
|
|
|
|
|
// Colonne de gauche avec logo et points de vente |
|
|
pw.Column( |
|
|
pw.Column( |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
children: [ |
|
|
children: [ |
|
|
|
|
|
// Logo |
|
|
pw.Container( |
|
|
pw.Container( |
|
|
width: 100, |
|
|
width: 150, |
|
|
height: 80, |
|
|
height: 150, |
|
|
decoration: pw.BoxDecoration( |
|
|
child: pw.Image(image), |
|
|
border: |
|
|
|
|
|
pw.Border.all(color: PdfColors.blue900, width: 2), |
|
|
|
|
|
borderRadius: pw.BorderRadius.circular(8), |
|
|
|
|
|
), |
|
|
|
|
|
child: pw.Center(child: pw.Image(image)), |
|
|
|
|
|
), |
|
|
|
|
|
pw.SizedBox(height: 10), |
|
|
|
|
|
pw.Text('guycom', style: headerStyle), |
|
|
|
|
|
if (pointDeVente != null) |
|
|
|
|
|
pw.Text('Point de vente: ${pointDeVente['designation']}', style: subtitleStyle), |
|
|
|
|
|
pw.Text('Tél: +213 123 456 789', style: subtitleStyle), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
), |
|
|
|
|
|
pw.Text(' NOTRE COMPETENCE, A VOTRE SERVICE', style: italicTextStyleLogo), |
|
|
|
|
|
pw.SizedBox(height: 12), |
|
|
|
|
|
// Liste des points de vente avec checkbox |
|
|
pw.Column( |
|
|
pw.Column( |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.end, |
|
|
|
|
|
children: [ |
|
|
|
|
|
pw.Container( |
|
|
|
|
|
padding: const pw.EdgeInsets.all(12), |
|
|
|
|
|
decoration: pw.BoxDecoration( |
|
|
|
|
|
color: PdfColors.blue50, |
|
|
|
|
|
borderRadius: pw.BorderRadius.circular(8), |
|
|
|
|
|
), |
|
|
|
|
|
child: pw.Column( |
|
|
|
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
children: [ |
|
|
children: [ |
|
|
pw.Text( |
|
|
pw.Row(children: [iconChecked, pw.SizedBox(width: 5), pw.Text('REMAX by GUYCOM Andravoangy', style: smallTextStyle)]), |
|
|
'FACTURE', |
|
|
pw.Row(children: [iconChecked, pw.SizedBox(width: 5), pw.Text('SUPREME CENTER Behoririka box 405', style: smallTextStyle)]), |
|
|
style: pw.TextStyle( |
|
|
pw.Row(children: [iconChecked, pw.SizedBox(width: 5), pw.Text('SUPREME CENTER Behoririka box 416', style: smallTextStyle)]), |
|
|
fontSize: 20, |
|
|
pw.Row(children: [iconChecked, pw.SizedBox(width: 5), pw.Text('SUPREME CENTER Behoririka box 119', style: smallTextStyle)]), |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
pw.Row(children: [iconChecked, pw.SizedBox(width: 5), pw.Text('TRIPOLITSA Analakely BOX 7', style: smallTextStyle)]), |
|
|
color: PdfColors.blue900, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
pw.SizedBox(height: 8), |
|
|
|
|
|
pw.Text('N°: ${commande.id}', style: titleStyle), |
|
|
|
|
|
pw.Text( |
|
|
|
|
|
'Date: ${DateFormat('dd/MM/yyyy').format(commande.dateCommande)}'), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
// Informations de contact |
|
|
|
|
|
pw.SizedBox(height: 10), |
|
|
|
|
|
pw.Row(children: [iconPhone, pw.SizedBox(width: 5), pw.Text('033 37 808 18', style: smallTextStyle)]), |
|
|
|
|
|
pw.Row(children: [iconGlobe, pw.SizedBox(width: 5), pw.Text('www.guycom.mg', style: smallTextStyle)]), |
|
|
|
|
|
pw.Text('Facebook: GuyCom', style: smallTextStyle), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
pw.SizedBox(height: 30), |
|
|
// Colonne de droite avec cadres de texte |
|
|
|
|
|
pw.Column( |
|
|
|
|
|
crossAxisAlignment: pw.CrossAxisAlignment.center, |
|
|
|
|
|
children: [ |
|
|
|
|
|
pw.Text('Date: ${DateFormat('dd/MM/yyyy').format(DateTime.now())}', style: boldTexClienttStyle), |
|
|
|
|
|
pw.SizedBox(height: 10), |
|
|
|
|
|
pw.Container(width: 200, height: 1, color: PdfColors.black), |
|
|
|
|
|
|
|
|
// Informations client |
|
|
// Deux petits cadres côte à côte |
|
|
|
|
|
pw.SizedBox(height: 10), |
|
|
|
|
|
pw.Row( |
|
|
|
|
|
children: [ |
|
|
pw.Container( |
|
|
pw.Container( |
|
|
width: double.infinity, |
|
|
width: 100, |
|
|
padding: const pw.EdgeInsets.all(12), |
|
|
height: 40, |
|
|
decoration: pw.BoxDecoration( |
|
|
padding: const pw.EdgeInsets.all(5), |
|
|
color: PdfColors.grey100, |
|
|
child: pw.Column( |
|
|
borderRadius: pw.BorderRadius.circular(8), |
|
|
children: [ |
|
|
|
|
|
pw.Text('Boutique:', style: frameTextStyle), |
|
|
|
|
|
pw.Text('${pointDeVente?['nom'] ?? 'S405A'}', style: boldTexClienttStyle), |
|
|
|
|
|
] |
|
|
|
|
|
) |
|
|
), |
|
|
), |
|
|
|
|
|
pw.SizedBox(width: 10), |
|
|
|
|
|
pw.Container( |
|
|
|
|
|
width: 100, |
|
|
|
|
|
height: 40, |
|
|
|
|
|
padding: const pw.EdgeInsets.all(5), |
|
|
child: pw.Column( |
|
|
child: pw.Column( |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
|
|
|
children: [ |
|
|
children: [ |
|
|
pw.Text('FACTURÉ À:', style: titleStyle), |
|
|
pw.Text('Bon de livraison N°:', style: frameTextStyle), |
|
|
pw.SizedBox(height: 5), |
|
|
pw.Text('${pointDeVente?['nom'] ?? 'S405A'}-P${commande.id}', style: boldTexClienttStyle), |
|
|
pw.Text(client?.nomComplet ?? 'Client inconnu', |
|
|
] |
|
|
style: pw.TextStyle(fontSize: 12)), |
|
|
) |
|
|
if (client?.telephone != null) |
|
|
|
|
|
pw.Text('Tél: ${client!.telephone}', |
|
|
|
|
|
style: pw.TextStyle( |
|
|
|
|
|
fontSize: 10, color: PdfColors.grey600)), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
// Grand cadre en dessous |
|
|
pw.SizedBox(height: 20), |
|
|
pw.SizedBox(height: 20), |
|
|
|
|
|
|
|
|
// Informations personnel |
|
|
|
|
|
if (commandeur != null || validateur != null) |
|
|
|
|
|
pw.Container( |
|
|
pw.Container( |
|
|
width: double.infinity, |
|
|
width: 300, |
|
|
padding: const pw.EdgeInsets.all(12), |
|
|
height: 100, |
|
|
decoration: pw.BoxDecoration( |
|
|
decoration: pw.BoxDecoration( |
|
|
color: PdfColors.grey100, |
|
|
border: pw.Border.all(color: PdfColors.black, width: 1), |
|
|
borderRadius: pw.BorderRadius.circular(8), |
|
|
|
|
|
), |
|
|
), |
|
|
|
|
|
padding: const pw.EdgeInsets.all(10), |
|
|
child: pw.Column( |
|
|
child: pw.Column( |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.center, |
|
|
children: [ |
|
|
children: [ |
|
|
pw.Text('PERSONNEL:', style: titleStyle), |
|
|
pw.Text('ID Client: ', style: frameTextStyle), |
|
|
pw.SizedBox(height: 5), |
|
|
pw.SizedBox(height: 5), |
|
|
if (commandeur != null) |
|
|
pw.Text('${pointDeVente?['nom'] ?? 'S405A'} - ${client?.id ?? 'Non spécifié'}', style: boldTexClienttStyle), |
|
|
pw.Text('Commandeur: ${commandeur.name} ', |
|
|
pw.SizedBox(height: 5), |
|
|
style: pw.TextStyle(fontSize: 12)), |
|
|
pw.Container(width: 200, height: 1, color: PdfColors.black), |
|
|
if (validateur != null) |
|
|
pw.Text(client?.nom ?? 'Non spécifié', style: boldTexClienttStyle), |
|
|
pw.Text('Validateur: ${validateur.name}', |
|
|
pw.SizedBox(height: 10), |
|
|
style: pw.TextStyle(fontSize: 12)), |
|
|
pw.Text(client?.telephone ?? 'Non spécifié', style: frameTextStyle), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
pw.SizedBox(height: 20), |
|
|
pw.SizedBox(height: 20), |
|
|
|
|
|
|
|
|
// Tableau des produits |
|
|
// Tableau des produits avec plus de colonnes |
|
|
pw.Text('DÉTAILS DE LA COMMANDE', style: titleStyle), |
|
|
|
|
|
pw.SizedBox(height: 10), |
|
|
|
|
|
|
|
|
|
|
|
pw.Table( |
|
|
pw.Table( |
|
|
border: |
|
|
border: pw.TableBorder.all(width: 0.5), |
|
|
pw.TableBorder.all(color: PdfColors.grey400, width: 0.5), |
|
|
columnWidths: { |
|
|
|
|
|
0: const pw.FlexColumnWidth(3), // Désignation |
|
|
|
|
|
1: const pw.FlexColumnWidth(1), // Qté |
|
|
|
|
|
2: const pw.FlexColumnWidth(2), // Prix unitaire |
|
|
|
|
|
3: const pw.FlexColumnWidth(2), // Montant |
|
|
|
|
|
}, |
|
|
children: [ |
|
|
children: [ |
|
|
|
|
|
// En-tête du tableau |
|
|
pw.TableRow( |
|
|
pw.TableRow( |
|
|
decoration: |
|
|
decoration: const pw.BoxDecoration(color: PdfColors.grey200), |
|
|
const pw.BoxDecoration(color: PdfColors.blue900), |
|
|
|
|
|
children: [ |
|
|
children: [ |
|
|
_buildTableCell('Produit', |
|
|
pw.Padding(padding: const pw.EdgeInsets.all(4), child: pw.Text('Désignations', style: boldTextStyle)), |
|
|
titleStyle.copyWith(color: PdfColors.white)), |
|
|
pw.Padding(padding: const pw.EdgeInsets.all(4), child: pw.Text('Qté', style: boldTextStyle, textAlign: pw.TextAlign.center)), |
|
|
_buildTableCell( |
|
|
pw.Padding(padding: const pw.EdgeInsets.all(4), child: pw.Text('Prix unitaire', style: boldTextStyle, textAlign: pw.TextAlign.right)), |
|
|
'Qté', titleStyle.copyWith(color: PdfColors.white)), |
|
|
pw.Padding(padding: const pw.EdgeInsets.all(4), child: pw.Text('Montant', style: boldTextStyle, textAlign: pw.TextAlign.right)), |
|
|
_buildTableCell('Prix unit.', |
|
|
|
|
|
titleStyle.copyWith(color: PdfColors.white)), |
|
|
|
|
|
_buildTableCell( |
|
|
|
|
|
'Total', titleStyle.copyWith(color: PdfColors.white)), |
|
|
|
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
...details.asMap().entries.map((entry) { |
|
|
|
|
|
final index = entry.key; |
|
|
// Lignes des produits avec détails complets |
|
|
final detail = entry.value; |
|
|
...detailsAvecProduits.map((item) { |
|
|
final isEven = index % 2 == 0; |
|
|
final detail = item['detail'] as DetailCommande; |
|
|
|
|
|
final produit = item['produit']; |
|
|
|
|
|
|
|
|
return pw.TableRow( |
|
|
return pw.TableRow( |
|
|
decoration: pw.BoxDecoration( |
|
|
|
|
|
color: isEven ? PdfColors.white : PdfColors.grey50, |
|
|
|
|
|
), |
|
|
|
|
|
children: [ |
|
|
children: [ |
|
|
_buildTableCell(detail.produitNom ?? 'Produit inconnu'), |
|
|
pw.Padding( |
|
|
_buildTableCell(detail.quantite.toString()), |
|
|
padding: const pw.EdgeInsets.all(4), |
|
|
_buildTableCell('${detail.prixUnitaire.toStringAsFixed(2)} MGA'), |
|
|
child: pw.Column( |
|
|
_buildTableCell('${detail.sousTotal.toStringAsFixed(2)} MGA'), |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
], |
|
|
children: [ |
|
|
); |
|
|
// Nom du produit |
|
|
}), |
|
|
pw.Text(detail.produitNom ?? 'Produit inconnu', |
|
|
], |
|
|
style: pw.TextStyle(fontSize: 10, fontWeight: pw.FontWeight.bold)), |
|
|
), |
|
|
pw.SizedBox(height: 2), |
|
|
|
|
|
|
|
|
pw.SizedBox(height: 20), |
|
|
|
|
|
|
|
|
|
|
|
// Total |
|
|
if (produit?.category != null && produit!.category.isNotEmpty && produit?.marque != null && produit!.marque.isNotEmpty) |
|
|
pw.Container( |
|
|
pw.Text('${produit.category} ${produit.marque}', style: smallTextStyle), |
|
|
alignment: pw.Alignment.centerRight, |
|
|
|
|
|
child: pw.Container( |
|
|
// IMEI |
|
|
padding: const pw.EdgeInsets.all(12), |
|
|
if (produit?.imei != null && produit!.imei!.isNotEmpty) |
|
|
decoration: pw.BoxDecoration( |
|
|
pw.Text('${produit.imei}', style: smallTextStyle), |
|
|
color: PdfColors.blue900, |
|
|
|
|
|
borderRadius: pw.BorderRadius.circular(8), |
|
|
|
|
|
|
|
|
// Référence |
|
|
|
|
|
if (produit?.reference != null && produit!.reference!.isNotEmpty && produit?.ram != null && produit!.ram!.isNotEmpty && produit?.memoireInterne != null && produit!.memoireInterne!.isNotEmpty) |
|
|
|
|
|
pw.Text('${produit.ram} | ${produit.memoireInterne} | ${produit.reference}', style: smallTextStyle), |
|
|
|
|
|
|
|
|
|
|
|
// // IMEI |
|
|
|
|
|
// if (produit?.imei != null && produit!.imei!.isNotEmpty) |
|
|
|
|
|
// pw.Text('IMEI: ${produit.imei}', style: smallTextStyle), |
|
|
|
|
|
|
|
|
|
|
|
// // RAM |
|
|
|
|
|
// if (produit?.ram != null && produit!.ram!.isNotEmpty) |
|
|
|
|
|
// pw.Text('RAM: ${produit.ram}', style: smallTextStyle), |
|
|
|
|
|
|
|
|
|
|
|
// // Stockage |
|
|
|
|
|
// if (produit?.memoireInterne != null && produit!.memoireInterne!.isNotEmpty) |
|
|
|
|
|
// pw.Text('Stockage: ${produit.memoireInterne}', style: smallTextStyle), |
|
|
|
|
|
|
|
|
|
|
|
// // Catégorie |
|
|
|
|
|
|
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
child: pw.Text( |
|
|
|
|
|
'TOTAL: ${commande.montantTotal.toStringAsFixed(2)} MGA', |
|
|
|
|
|
style: pw.TextStyle( |
|
|
|
|
|
fontSize: 16, |
|
|
|
|
|
fontWeight: pw.FontWeight.bold, |
|
|
|
|
|
color: PdfColors.white, |
|
|
|
|
|
), |
|
|
), |
|
|
|
|
|
pw.Padding( |
|
|
|
|
|
padding: const pw.EdgeInsets.all(4), |
|
|
|
|
|
child: pw.Text('${detail.quantite}', style: normalTextStyle, textAlign: pw.TextAlign.center), |
|
|
), |
|
|
), |
|
|
|
|
|
pw.Padding( |
|
|
|
|
|
padding: const pw.EdgeInsets.all(4), |
|
|
|
|
|
child: pw.Text('${detail.prixUnitaire.toStringAsFixed(0)}', style: normalTextStyle, textAlign: pw.TextAlign.right), |
|
|
), |
|
|
), |
|
|
|
|
|
pw.Padding( |
|
|
|
|
|
padding: const pw.EdgeInsets.all(4), |
|
|
|
|
|
child: pw.Text('${detail.sousTotal.toStringAsFixed(0)}', style: normalTextStyle, textAlign: pw.TextAlign.right), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
); |
|
|
|
|
|
}).toList(), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
pw.Spacer(), |
|
|
pw.SizedBox(height: 10), |
|
|
|
|
|
|
|
|
// Pied de page |
|
|
// Total |
|
|
pw.Container( |
|
|
pw.Row( |
|
|
width: double.infinity, |
|
|
mainAxisAlignment: pw.MainAxisAlignment.end, |
|
|
padding: const pw.EdgeInsets.all(12), |
|
|
|
|
|
decoration: pw.BoxDecoration( |
|
|
|
|
|
border: pw.Border( |
|
|
|
|
|
top: pw.BorderSide(color: PdfColors.grey400, width: 1), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
child: pw.Column( |
|
|
|
|
|
children: [ |
|
|
children: [ |
|
|
pw.Text( |
|
|
pw.Text('TOTAL', style: boldTextStyle), |
|
|
'Merci pour votre confiance!', |
|
|
pw.SizedBox(width: 20), |
|
|
style: pw.TextStyle( |
|
|
pw.Text('${commande.montantTotal.toStringAsFixed(0)}', style: boldTextStyle), |
|
|
fontSize: 14, |
|
|
], |
|
|
fontStyle: pw.FontStyle.italic, |
|
|
|
|
|
color: PdfColors.blue900, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
pw.SizedBox(height: 5), |
|
|
|
|
|
pw.Text( |
|
|
pw.SizedBox(height: 10), |
|
|
'Cette facture est générée automatiquement par le système Youmaz Gestion', |
|
|
|
|
|
style: |
|
|
// Montant en lettres |
|
|
pw.TextStyle(fontSize: 8, color: PdfColors.grey600), |
|
|
pw.Text('Arrêté à la somme de: ${_numberToWords(commande.montantTotal.toInt())} Ariary', style: italicTextStyle), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 30), |
|
|
|
|
|
|
|
|
|
|
|
// Signatures |
|
|
|
|
|
pw.Row( |
|
|
|
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
|
|
|
|
|
children: [ |
|
|
|
|
|
pw.Column( |
|
|
|
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
|
|
|
children: [ |
|
|
|
|
|
pw.Text('Signature du vendeur', style: smallTextStyle), |
|
|
|
|
|
pw.SizedBox(height: 20), |
|
|
|
|
|
pw.Container(width: 150, height: 1, color: PdfColors.black), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
|
|
|
pw.Column( |
|
|
|
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
|
|
|
children: [ |
|
|
|
|
|
pw.Text('Signature du client', style: smallTextStyle), |
|
|
|
|
|
pw.SizedBox(height: 20), |
|
|
|
|
|
pw.Container(width: 150, height: 1, color: PdfColors.black), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
); |
|
|
); |
|
|
@ -486,6 +527,30 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> { |
|
|
await OpenFile.open(file.path); |
|
|
await OpenFile.open(file.path); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pw.Widget _buildCheckboxPointDeVente(String text, bool checked) { |
|
|
|
|
|
return pw.Row( |
|
|
|
|
|
children: [ |
|
|
|
|
|
pw.Container( |
|
|
|
|
|
width: 10, |
|
|
|
|
|
height: 10, |
|
|
|
|
|
decoration: pw.BoxDecoration( |
|
|
|
|
|
border: pw.Border.all(width: 1), |
|
|
|
|
|
color: checked ? PdfColors.black : PdfColors.white, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
pw.SizedBox(width: 5), |
|
|
|
|
|
pw.Text(text, style: pw.TextStyle(fontSize: 9)), |
|
|
|
|
|
], |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
String _numberToWords(int number) { |
|
|
|
|
|
// Implémentez la conversion du nombre en lettres ici |
|
|
|
|
|
// Exemple simplifié: |
|
|
|
|
|
NumbersToLetters.toLetters('fr', number); |
|
|
|
|
|
return NumbersToLetters.toLetters('fr', number); |
|
|
|
|
|
} |
|
|
Future<void> _generateReceipt(Commande commande, PaymentMethod payment) async { |
|
|
Future<void> _generateReceipt(Commande commande, PaymentMethod payment) async { |
|
|
final details = await _database.getDetailsCommande(commande.id!); |
|
|
final details = await _database.getDetailsCommande(commande.id!); |
|
|
final client = await _database.getClientById(commande.clientId); |
|
|
final client = await _database.getClientById(commande.clientId); |
|
|
@ -499,6 +564,16 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> { |
|
|
? await _database.getPointDeVenteById(commandeur!.pointDeVenteId!) |
|
|
? await _database.getPointDeVenteById(commandeur!.pointDeVenteId!) |
|
|
: null; |
|
|
: null; |
|
|
|
|
|
|
|
|
|
|
|
// Récupérer les détails complets des produits |
|
|
|
|
|
final List<Map<String, dynamic>> detailsAvecProduits = []; |
|
|
|
|
|
for (final detail in details) { |
|
|
|
|
|
final produit = await _database.getProductById(detail.produitId); |
|
|
|
|
|
detailsAvecProduits.add({ |
|
|
|
|
|
'detail': detail, |
|
|
|
|
|
'produit': produit, |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
final pdf = pw.Document(); |
|
|
final pdf = pw.Document(); |
|
|
final imageBytes = await loadImage(); |
|
|
final imageBytes = await loadImage(); |
|
|
final image = pw.MemoryImage(imageBytes); |
|
|
final image = pw.MemoryImage(imageBytes); |
|
|
@ -511,22 +586,35 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> { |
|
|
return pw.Column( |
|
|
return pw.Column( |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.center, |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.center, |
|
|
children: [ |
|
|
children: [ |
|
|
// En-tête |
|
|
// En-tête avec logo |
|
|
pw.Center( |
|
|
pw.Center( |
|
|
child: pw.Container( |
|
|
child: pw.Container( |
|
|
width: 50, |
|
|
width: 40, |
|
|
height: 50, |
|
|
height: 40, |
|
|
child: pw.Image(image), |
|
|
child: pw.Image(image), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
pw.SizedBox(height: 4), |
|
|
pw.SizedBox(height: 4), |
|
|
|
|
|
|
|
|
|
|
|
// Informations de l'entreprise |
|
|
|
|
|
pw.Text('GUYCOM MADAGASCAR', |
|
|
|
|
|
style: pw.TextStyle( |
|
|
|
|
|
fontSize: 10, |
|
|
|
|
|
fontWeight: pw.FontWeight.bold, |
|
|
|
|
|
)), |
|
|
|
|
|
pw.Text('Tél: 033 37 808 18', style: const pw.TextStyle(fontSize: 7)), |
|
|
|
|
|
pw.Text('www.guycom.mg', style: const pw.TextStyle(fontSize: 7)), |
|
|
|
|
|
|
|
|
|
|
|
pw.SizedBox(height: 6), |
|
|
|
|
|
|
|
|
|
|
|
// Titre et numéro de ticket |
|
|
pw.Text('TICKET DE CAISSE', |
|
|
pw.Text('TICKET DE CAISSE', |
|
|
style: pw.TextStyle( |
|
|
style: pw.TextStyle( |
|
|
fontSize: 10, |
|
|
fontSize: 10, |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
fontWeight: pw.FontWeight.bold, |
|
|
), |
|
|
decoration: pw.TextDecoration.underline, |
|
|
), |
|
|
)), |
|
|
pw.Text('N°: ${commande.id}', |
|
|
pw.Text('N°: ${pointDeVente?['abreviation'] ?? 'PV'}-${commande.id}', |
|
|
style: const pw.TextStyle(fontSize: 8)), |
|
|
style: const pw.TextStyle(fontSize: 8)), |
|
|
pw.Text('Date: ${DateFormat('dd/MM/yyyy HH:mm').format(commande.dateCommande)}', |
|
|
pw.Text('Date: ${DateFormat('dd/MM/yyyy HH:mm').format(commande.dateCommande)}', |
|
|
style: const pw.TextStyle(fontSize: 8)), |
|
|
style: const pw.TextStyle(fontSize: 8)), |
|
|
@ -537,76 +625,118 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> { |
|
|
|
|
|
|
|
|
pw.Divider(thickness: 0.5), |
|
|
pw.Divider(thickness: 0.5), |
|
|
|
|
|
|
|
|
// Client |
|
|
// Informations client |
|
|
pw.Text('CLIENT: ${client?.nomComplet ?? 'Non spécifié'}', |
|
|
pw.Text('CLIENT: ${client?.nomComplet ?? 'Non spécifié'}', |
|
|
style: pw.TextStyle(fontSize: 8, fontWeight: pw.FontWeight.bold)), |
|
|
style: pw.TextStyle(fontSize: 8, fontWeight: pw.FontWeight.bold)), |
|
|
|
|
|
if (client?.telephone != null) |
|
|
|
|
|
pw.Text('Tél: ${client!.telephone}', style: const pw.TextStyle(fontSize: 7)), |
|
|
|
|
|
|
|
|
// Personnel |
|
|
// Personnel impliqué |
|
|
|
|
|
if (commandeur != null || validateur != null) |
|
|
|
|
|
pw.Column( |
|
|
|
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
|
|
|
children: [ |
|
|
|
|
|
pw.Divider(thickness: 0.5), |
|
|
if (commandeur != null) |
|
|
if (commandeur != null) |
|
|
pw.Text('Commandeur: ${commandeur.name} ', |
|
|
pw.Text('Vendeur: ${commandeur.name}', style: const pw.TextStyle(fontSize: 7)), |
|
|
style: const pw.TextStyle(fontSize: 7)), |
|
|
|
|
|
if (validateur != null) |
|
|
if (validateur != null) |
|
|
pw.Text('Validateur: ${validateur.name}', |
|
|
pw.Text('Validateur: ${validateur.name}', style: const pw.TextStyle(fontSize: 7)), |
|
|
style: const pw.TextStyle(fontSize: 7)), |
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
pw.Divider(thickness: 0.5), |
|
|
pw.Divider(thickness: 0.5), |
|
|
|
|
|
|
|
|
// Détails |
|
|
// Détails des produits |
|
|
pw.Table( |
|
|
pw.Table( |
|
|
columnWidths: { |
|
|
columnWidths: { |
|
|
0: const pw.FlexColumnWidth(3), |
|
|
0: const pw.FlexColumnWidth(3.5), |
|
|
1: const pw.FlexColumnWidth(1), |
|
|
1: const pw.FlexColumnWidth(1), |
|
|
2: const pw.FlexColumnWidth(2), |
|
|
2: const pw.FlexColumnWidth(1.5), |
|
|
}, |
|
|
}, |
|
|
children: [ |
|
|
children: [ |
|
|
|
|
|
// En-tête du tableau |
|
|
pw.TableRow( |
|
|
pw.TableRow( |
|
|
children: [ |
|
|
children: [ |
|
|
pw.Text('Produit', style: pw.TextStyle(fontSize: 7, fontWeight: pw.FontWeight.bold)), |
|
|
pw.Text('Désignation', style: pw.TextStyle(fontSize: 7, fontWeight: pw.FontWeight.bold)), |
|
|
pw.Text('Qté', style: pw.TextStyle(fontSize: 7, fontWeight: pw.FontWeight.bold)), |
|
|
pw.Text('Qté', style: pw.TextStyle(fontSize: 7, fontWeight: pw.FontWeight.bold)), |
|
|
pw.Text('Total', style: pw.TextStyle(fontSize: 7, fontWeight: pw.FontWeight.bold)), |
|
|
pw.Text('P.U', style: pw.TextStyle(fontSize: 7, fontWeight: pw.FontWeight.bold)), |
|
|
], |
|
|
], |
|
|
), |
|
|
decoration: const pw.BoxDecoration( |
|
|
...details.map((detail) => pw.TableRow( |
|
|
border: pw.Border(bottom: pw.BorderSide(width: 0.5)), |
|
|
|
|
|
|
|
|
|
|
|
),), |
|
|
|
|
|
|
|
|
|
|
|
// Lignes des produits |
|
|
|
|
|
...detailsAvecProduits.map( (item) { |
|
|
|
|
|
final detail = item['detail'] as DetailCommande; |
|
|
|
|
|
final produit = item['produit']; |
|
|
|
|
|
|
|
|
|
|
|
return pw.TableRow( |
|
|
|
|
|
decoration: const pw.BoxDecoration( |
|
|
|
|
|
border: pw.Border(bottom: pw.BorderSide(width: 0.2))), |
|
|
children: [ |
|
|
children: [ |
|
|
pw.Text(detail.produitNom ?? 'Produit', style: const pw.TextStyle(fontSize: 7)), |
|
|
pw.Column( |
|
|
pw.Text(detail.quantite.toString(), style: const pw.TextStyle(fontSize: 7)), |
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start, |
|
|
pw.Text('${detail.sousTotal.toStringAsFixed(2)} MGA', style: const pw.TextStyle(fontSize: 7)), |
|
|
children: [ |
|
|
|
|
|
pw.Text(detail.produitNom ?? 'Produit', |
|
|
|
|
|
style: const pw.TextStyle(fontSize: 7)), |
|
|
|
|
|
if (produit?.reference != null) |
|
|
|
|
|
pw.Text('Ref: ${produit!.reference}', |
|
|
|
|
|
style: const pw.TextStyle(fontSize: 6)), |
|
|
|
|
|
if (produit?.imei != null) |
|
|
|
|
|
pw.Text('IMEI: ${produit!.imei}', |
|
|
|
|
|
style: const pw.TextStyle(fontSize: 6)), |
|
|
], |
|
|
], |
|
|
)), |
|
|
), |
|
|
|
|
|
pw.Text(detail.quantite.toString(), |
|
|
|
|
|
style: const pw.TextStyle(fontSize: 7)), |
|
|
|
|
|
pw.Text('${detail.prixUnitaire.toStringAsFixed(0)}', |
|
|
|
|
|
style: const pw.TextStyle(fontSize: 7)), |
|
|
|
|
|
], |
|
|
|
|
|
); |
|
|
|
|
|
}), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
pw.Divider(thickness: 0.5), |
|
|
pw.Divider(thickness: 0.5), |
|
|
|
|
|
|
|
|
// Total |
|
|
// Total et paiement |
|
|
pw.Row( |
|
|
pw.Row( |
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
|
|
children: [ |
|
|
children: [ |
|
|
pw.Text('TOTAL:', style: pw.TextStyle(fontSize: 9, fontWeight: pw.FontWeight.bold)), |
|
|
pw.Text('TOTAL:', |
|
|
pw.Text('${commande.montantTotal.toStringAsFixed(2)} MGA', |
|
|
style: pw.TextStyle(fontSize: 9, fontWeight: pw.FontWeight.bold)), |
|
|
|
|
|
pw.Text('${commande.montantTotal.toStringAsFixed(0)} MGA', |
|
|
style: pw.TextStyle(fontSize: 9, fontWeight: pw.FontWeight.bold)), |
|
|
style: pw.TextStyle(fontSize: 9, fontWeight: pw.FontWeight.bold)), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
// Paiement |
|
|
pw.SizedBox(height: 6), |
|
|
pw.SizedBox(height: 8), |
|
|
|
|
|
pw.Text('MODE DE PAIEMENT:', style: const pw.TextStyle(fontSize: 8)), |
|
|
// Détails du paiement |
|
|
|
|
|
pw.Text('MODE DE PAIEMENT:', |
|
|
|
|
|
style: const pw.TextStyle(fontSize: 8)), |
|
|
pw.Text( |
|
|
pw.Text( |
|
|
payment.type == PaymentType.cash |
|
|
payment.type == PaymentType.cash |
|
|
? 'LIQUIDE (${payment.amountGiven.toStringAsFixed(2)} MGA)' |
|
|
? 'LIQUIDE (${payment.amountGiven.toStringAsFixed(0)} MGA)' |
|
|
: 'CARTE BANCAIRE', |
|
|
: 'CARTE BANCAIRE', |
|
|
style: pw.TextStyle(fontSize: 8, fontWeight: pw.FontWeight.bold), |
|
|
style: pw.TextStyle(fontSize: 8, fontWeight: pw.FontWeight.bold), |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
if (payment.type == PaymentType.cash && payment.amountGiven > commande.montantTotal) |
|
|
if (payment.type == PaymentType.cash && payment.amountGiven > commande.montantTotal) |
|
|
pw.Text('Monnaie rendue: ${(payment.amountGiven - commande.montantTotal).toStringAsFixed(2)} MGA', |
|
|
pw.Text('Monnaie rendue: ${(payment.amountGiven - commande.montantTotal).toStringAsFixed(0)} MGA', |
|
|
style: const pw.TextStyle(fontSize: 8)), |
|
|
style: const pw.TextStyle(fontSize: 8)), |
|
|
|
|
|
|
|
|
pw.SizedBox(height: 12), |
|
|
pw.SizedBox(height: 12), |
|
|
pw.Text('Merci pour votre achat !', |
|
|
|
|
|
|
|
|
// Mentions légales et remerciements |
|
|
|
|
|
pw.Text('Article non échangeable - Garantie selon conditions', |
|
|
|
|
|
style: const pw.TextStyle(fontSize: 6)), |
|
|
|
|
|
pw.Text('Ticket à conserver comme justificatif', |
|
|
|
|
|
style: const pw.TextStyle(fontSize: 6)), |
|
|
|
|
|
pw.SizedBox(height: 8), |
|
|
|
|
|
pw.Text('Merci pour votre confiance !', |
|
|
style: pw.TextStyle(fontSize: 8, fontStyle: pw.FontStyle.italic)), |
|
|
style: pw.TextStyle(fontSize: 8, fontStyle: pw.FontStyle.italic)), |
|
|
pw.Text('www.guycom.mg', |
|
|
|
|
|
style: const pw.TextStyle(fontSize: 7)), |
|
|
|
|
|
], |
|
|
], |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
@ -632,12 +762,12 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> { |
|
|
return Colors.orange.shade100; |
|
|
return Colors.orange.shade100; |
|
|
case StatutCommande.confirmee: |
|
|
case StatutCommande.confirmee: |
|
|
return Colors.blue.shade100; |
|
|
return Colors.blue.shade100; |
|
|
case StatutCommande.enPreparation: |
|
|
// case StatutCommande.enPreparation: |
|
|
return Colors.amber.shade100; |
|
|
// return Colors.amber.shade100; |
|
|
case StatutCommande.expediee: |
|
|
// case StatutCommande.expediee: |
|
|
return Colors.purple.shade100; |
|
|
// return Colors.purple.shade100; |
|
|
case StatutCommande.livree: |
|
|
// case StatutCommande.livree: |
|
|
return Colors.green.shade100; |
|
|
// return Colors.green.shade100; |
|
|
case StatutCommande.annulee: |
|
|
case StatutCommande.annulee: |
|
|
return Colors.red.shade100; |
|
|
return Colors.red.shade100; |
|
|
} |
|
|
} |
|
|
@ -649,12 +779,12 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> { |
|
|
return Icons.schedule; |
|
|
return Icons.schedule; |
|
|
case StatutCommande.confirmee: |
|
|
case StatutCommande.confirmee: |
|
|
return Icons.check_circle_outline; |
|
|
return Icons.check_circle_outline; |
|
|
case StatutCommande.enPreparation: |
|
|
// case StatutCommande.enPreparation: |
|
|
return Icons.settings; |
|
|
// return Icons.settings; |
|
|
case StatutCommande.expediee: |
|
|
// case StatutCommande.expediee: |
|
|
return Icons.local_shipping; |
|
|
// return Icons.local_shipping; |
|
|
case StatutCommande.livree: |
|
|
// case StatutCommande.livree: |
|
|
return Icons.check_circle; |
|
|
// return Icons.check_circle; |
|
|
case StatutCommande.annulee: |
|
|
case StatutCommande.annulee: |
|
|
return Icons.cancel; |
|
|
return Icons.cancel; |
|
|
} |
|
|
} |
|
|
@ -1209,12 +1339,12 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> { |
|
|
return 'En attente'; |
|
|
return 'En attente'; |
|
|
case StatutCommande.confirmee: |
|
|
case StatutCommande.confirmee: |
|
|
return 'Confirmée'; |
|
|
return 'Confirmée'; |
|
|
case StatutCommande.enPreparation: |
|
|
// case StatutCommande.enPreparation: |
|
|
return 'En préparation'; |
|
|
// return 'En préparation'; |
|
|
case StatutCommande.expediee: |
|
|
// case StatutCommande.expediee: |
|
|
return 'Expédiée'; |
|
|
// return 'Expédiée'; |
|
|
case StatutCommande.livree: |
|
|
// case StatutCommande.livree: |
|
|
return 'Livrée'; |
|
|
// return 'Livrée'; |
|
|
case StatutCommande.annulee: |
|
|
case StatutCommande.annulee: |
|
|
return 'Annulée'; |
|
|
return 'Annulée'; |
|
|
} |
|
|
} |
|
|
@ -1424,9 +1554,9 @@ class _CommandeActions extends StatelessWidget { |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case StatutCommande.confirmee: |
|
|
case StatutCommande.confirmee: |
|
|
case StatutCommande.enPreparation: |
|
|
// case StatutCommande.enPreparation: |
|
|
case StatutCommande.expediee: |
|
|
// case StatutCommande.expediee: |
|
|
case StatutCommande.livree: |
|
|
// case StatutCommande.livree: |
|
|
buttons.add( |
|
|
buttons.add( |
|
|
Container( |
|
|
Container( |
|
|
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), |
|
|
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), |
|
|
|