Browse Source

commit de 18072025

28062025_02
andrymodeste 4 months ago
parent
commit
d043f6f20b
  1. 6
      lib/Models/Client.dart
  2. 34
      lib/Services/stock_managementDatabase.dart
  3. 132
      lib/Views/Dashboard.dart
  4. 6
      lib/Views/HandleProduct.dart
  5. 3
      lib/Views/bilanMois.dart
  6. 30
      lib/Views/commandManagement.dart
  7. 22
      lib/Views/historique.dart
  8. 5
      lib/Views/listCommandeHistory.dart
  9. 136
      lib/Views/newCommand.dart
  10. 3
      lib/Views/produitsCard.dart
  11. 22
      lib/Views/ticketPage.dart
  12. 2
      lib/config/DatabaseConfig.dart

6
lib/Models/Client.dart

@ -92,6 +92,8 @@ class Commande {
final String? clientNom;
final String? clientPrenom;
final String? clientEmail;
final int? pointDeVenteId;
final String? pointDeVenteDesign;
Commande({
this.id,
@ -106,6 +108,8 @@ class Commande {
this.clientNom,
this.clientPrenom,
this.clientEmail,
this.pointDeVenteId,
this.pointDeVenteDesign,
});
String get clientNomComplet {
@ -156,6 +160,8 @@ class Commande {
clientNom: map['clientNom'] as String?,
clientPrenom: map['clientPrenom'] as String?,
clientEmail: map['clientEmail'] as String?,
pointDeVenteId: map['pointDeVenteId'] as int?,
pointDeVenteDesign: map['pointDeVenteDesign'] as String?,
);
}
}

34
lib/Services/stock_managementDatabase.dart

@ -597,6 +597,31 @@ class AppDatabase {
}
}
Future<double> getValeurTotaleStock() async {
final db = await database;
try {
// Récupérer tous les produits
final List<Map<String, dynamic>> products = (await db.query('products')) as List<Map<String, dynamic>>;
double valeurTotale = 0.0;
for (final product in products) {
final stock = (product['stock'] as num?)?.toDouble();
final price = (product['price'] as num?)?.toDouble();
// Vérifier que stock et price ne sont pas null
if (stock != null && price != null) {
valeurTotale += (stock * price);
}
}
return valeurTotale;
} catch (e) {
print('Erreur lors du calcul de la valeur totale du stock: $e');
return 0.0;
}
}
// --- STATISTIQUES ---
Future<Map<String, dynamic>> getStatistiques() async {
@ -807,9 +832,16 @@ class AppDatabase {
Future<List<Commande>> getCommandes() async {
final db = await database;
final result = await db.query('''
SELECT c.*, cl.nom as clientNom, cl.prenom as clientPrenom, cl.email as clientEmail
SELECT c.*,
cl.nom AS clientNom,
cl.prenom AS clientPrenom,
cl.email AS clientEmail,
u.point_de_vente_id AS pointDeVenteId,
pv.nom AS pointDeVenteDesign
FROM commandes c
LEFT JOIN clients cl ON c.clientId = cl.id
LEFT JOIN users u ON c.commandeurId = u.id
LEFT JOIN points_de_vente pv ON u.point_de_vente_id = pv.id
ORDER BY c.dateCommande DESC
''');
return result.map((row) => Commande.fromMap(row.fields)).toList();

132
lib/Views/Dashboard.dart

@ -7,6 +7,7 @@ import 'package:youmazgestion/controller/userController.dart';
import 'package:youmazgestion/Models/users.dart';
import 'package:youmazgestion/Models/client.dart';
import 'package:youmazgestion/Models/produit.dart'; // Ajout de l'import manquant
import 'package:intl/intl.dart';
class DashboardPage extends StatefulWidget {
@override
@ -14,6 +15,8 @@ class DashboardPage extends StatefulWidget {
}
class _DashboardPageState extends State<DashboardPage> with SingleTickerProviderStateMixin {
DateTimeRange? _dateRange;
bool _showOnlyToday = false;
final AppDatabase _database = AppDatabase.instance;
final UserController _userController = Get.find<UserController>();
final GlobalKey _recentClientsKey = GlobalKey();
@ -60,8 +63,8 @@ void initState() {
super.dispose();
}
void _loadData() {
_statsFuture = _database.getStatistiques();
void _loadData() {
_statsFuture = _database.getStatistiques(); // Plus besoin de calcul supplémentaire
_recentOrdersFuture = _database.getCommandes().then((orders) => orders.take(5).toList());
_lowStockProductsFuture = _database.getProducts().then((products) {
return products.where((p) => (p.stock ?? 0) < 10).toList();
@ -69,7 +72,7 @@ void initState() {
_recentClientsFuture = _database.getClients().then((clients) => clients.take(5).toList());
_allOrdersFuture = _database.getCommandes();
_productsByCategoryFuture = _database.getProductCountByCategory();
}
}
Future<void> _showCategoryProductsDialog(String category) async {
final products = await _database.getProductsByCategory(category);
@ -90,7 +93,7 @@ Future<void> _showCategoryProductsDialog(String category) async {
: CircleAvatar(child: Icon(Icons.inventory)),
title: Text(product.name),
subtitle: Text('Stock: ${product.stock}'),
trailing: Text('${product.price.toStringAsFixed(2)} MGA'),
trailing: Text('${NumberFormat('#,##0', 'fr_FR').format(product.price)} MGA'),
);
},
),
@ -417,7 +420,7 @@ Future<void> _showCategoryProductsDialog(String category) async {
final month = salesData[groupIndex]['month'];
final total = salesData[groupIndex]['total'];
return BarTooltipItem(
'$month\n${total.toStringAsFixed(2)} MGA',
'$month\n${NumberFormat('#,##0', 'fr_FR').format(total)} MGA',
TextStyle(color: Colors.white),
);
},
@ -716,7 +719,7 @@ Future<void> _showCategoryProductsDialog(String category) async {
);
}
Widget _buildMiniStatistics() {
Widget _buildMiniStatistics() {
return FutureBuilder<Map<String, dynamic>>(
future: _statsFuture,
builder: (context, snapshot) {
@ -754,16 +757,22 @@ Future<void> _showCategoryProductsDialog(String category) async {
),
_buildMiniStatCard(
title: 'CA (MGA)',
value: '${(stats['chiffreAffaires'] ?? 0.0).toStringAsFixed(2)}',
value: NumberFormat('#,##0', 'fr_FR').format(stats['chiffreAffaires'] ?? 0.0),
icon: Icons.euro_symbol,
color: Colors.purple,
),
// NOUVELLE CARTE : Valeur totale du stock
_buildMiniStatCard(
title: 'Valeur Stock (MGA)',
value: NumberFormat('#,##0', 'fr_FR').format(stats['valeurTotaleStock'] ?? 0.0),
icon: Icons.inventory_2,
color: Colors.teal,
),
],
);
},
);
}
}
Widget _buildMiniStatCard({required String title, required String value, required IconData icon, required Color color}) {
@ -952,7 +961,7 @@ Future<void> _showCategoryProductsDialog(String category) async {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${order.montantTotal.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(order.montantTotal)} MGA',
style: TextStyle(fontSize: 12),
),
Text(
@ -1160,7 +1169,7 @@ Widget _buildVentesParPointDeVenteCard() {
final ca = pointVente['chiffre_affaires'] ?? 0.0;
final nbCommandes = pointVente['nombre_commandes'] ?? 0;
return BarTooltipItem(
'${pointVente['point_vente_nom']}\n${ca.toStringAsFixed(2)} MGA\n$nbCommandes commandes',
'${pointVente['point_vente_nom']}\n${NumberFormat('#,##0', 'fr_FR').format(ca)} MGA\n$nbCommandes commandes',
TextStyle(color: Colors.white, fontSize: 12),
);
},
@ -1333,7 +1342,9 @@ Widget _buildTableauVentesPointDeVente(List<Map<String, dynamic>> ventesData) {
Expanded(
flex: 2,
child: Text(
'${((data['chiffre_affaires'] as num?)?.toDouble() ?? 0.0).toStringAsFixed(2)}',
NumberFormat('#,##0.00', 'fr_FR').format(
(data['chiffre_affaires'] as num?)?.toDouble() ?? 0.0,
),
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
),
),
@ -1354,7 +1365,9 @@ Widget _buildTableauVentesPointDeVente(List<Map<String, dynamic>> ventesData) {
Expanded(
flex: 2,
child: Text(
'${((data['panier_moyen'] as num?)?.toDouble() ?? 0.0).toStringAsFixed(2)}',
NumberFormat('#,##0.00', 'fr_FR').format(
(data['panier_moyen'] as num?)?.toDouble() ?? 0.0,
),
style: TextStyle(fontSize: 12),
),
),
@ -1403,33 +1416,112 @@ String _formatCurrency(double value) {
}
}
Future<void> _selectDateRange(BuildContext context) async {
final DateTimeRange? picked = await showDateRangePicker(
context: context,
firstDate: DateTime(2020),
lastDate: DateTime.now().add(const Duration(days: 365)),
initialDateRange: _dateRange ??
DateTimeRange(
start: DateTime.now().subtract(const Duration(days: 30)),
end: DateTime.now(),
),
);
if (picked != null) {
setState(() {
_dateRange = picked;
});
}
}
void _toggleTodayFilter() {
setState(() {
_showOnlyToday = !_showOnlyToday;
});
}
void _showPointVenteDetails(Map<String, dynamic> pointVenteData) async {
final isMobile = MediaQuery.of(context).size.width < 600;
final pointVenteId = pointVenteData['point_vente_id'] as int;
final pointVenteNom = pointVenteData['point_vente_nom'] as String;
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Détails - $pointVenteNom'),
content: Container(
width: double.maxFinite,
height: 400,
height: 500,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton.icon(
onPressed: _toggleTodayFilter,
icon: Icon(
_showOnlyToday ? Icons.today : Icons.calendar_today,
size: 20,
),
label: Text(_showOnlyToday
? isMobile
? 'Toutes dates'
: 'Toutes les dates'
: isMobile
? 'Aujourd\'hui'
: 'Aujourd\'hui seulement'),
style: ElevatedButton.styleFrom(
backgroundColor: _showOnlyToday
? Colors.green.shade600
: Colors.blue.shade600,
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: isMobile ? 12 : 16,
vertical: 8,
),
),
),
ElevatedButton.icon(
onPressed: () => _selectDateRange(context),
icon: const Icon(Icons.date_range, size: 20),
label: Text(_dateRange != null
? isMobile
? 'Période'
: 'Période sélectionnée'
: isMobile
? 'Période'
: 'Choisir période'),
style: ElevatedButton.styleFrom(
backgroundColor: _dateRange != null
? Colors.orange.shade600
: Colors.grey.shade600,
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: isMobile ? 12 : 16,
vertical: 8,
),
),
),
],
),
// Statistiques générales
_buildStatRow('Chiffre d\'affaires:', '${((pointVenteData['chiffre_affaires'] as num?)?.toDouble() ?? 0.0).toStringAsFixed(2)} MGA'),
_buildStatRow('Chiffre d\'affaires:', '${NumberFormat('#,##0.00', 'fr_FR').format((pointVenteData['chiffre_affaires'] as num?)?.toDouble() ?? 0.0)} MGA'),
_buildStatRow('Nombre de commandes:', '${pointVenteData['nombre_commandes'] ?? 0}'),
_buildStatRow('Articles vendus:', '${pointVenteData['nombre_articles_vendus'] ?? 0}'),
_buildStatRow('Quantité totale:', '${pointVenteData['quantite_totale_vendue'] ?? 0}'),
_buildStatRow('Panier moyen:', '${((pointVenteData['panier_moyen'] as num?)?.toDouble() ?? 0.0).toStringAsFixed(2)} MGA'),
_buildStatRow('Panier moyen:', '${NumberFormat('#,##0.00', 'fr_FR').format((pointVenteData['panier_moyen'] as num?)?.toDouble() ?? 0.0)} MGA'),
SizedBox(height: 16),
Text('Top 5 des produits:', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 8),
// Top produits
SizedBox(height: 16),
// Top produits
FutureBuilder<List<Map<String, dynamic>>>(
future: _database.getTopProduitsParPointDeVente(pointVenteId),
builder: (context, snapshot) {
@ -1476,7 +1568,7 @@ void _showPointVenteDetails(Map<String, dynamic> pointVenteData) async {
),
],
),
);
);
}
Widget _buildStatRow(String label, String value) {
@ -1582,7 +1674,7 @@ Widget _buildStatRow(String label, String value) {
],
),
trailing: Text(
'${product.price.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(product.price)} MGA',
style: TextStyle(fontSize: 12),
),
),

6
lib/Views/HandleProduct.dart

@ -307,7 +307,7 @@ Future<void> _showDemandeTransfertDialog(Product product) async {
Expanded(
child: _buildInfoCard(
'Prix unitaire',
'${product.price.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(product.price)} MGA',
Icons.attach_money,
Colors.green,
),
@ -1823,7 +1823,7 @@ Future<void> _showDemandeTransfertDialog(Product product) async {
),
const SizedBox(height: 8),
Text('IMEI: ${product.imei}'),
Text('Prix: ${product.price.toStringAsFixed(2)} MGA'),
Text('Prix: ${NumberFormat('#,##0.00', 'fr_FR').format(product.price)} MGA'),
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.all(8),
@ -4476,7 +4476,7 @@ Future<void> _showDemandeTransfertDialog(Product product) async {
icon: Icons.info_outline,
color: Colors.blue,
children: [
_buildModernInfoRow('Prix', '${product.price} MGA',
_buildModernInfoRow('Prix', '${NumberFormat('#,##0.00', 'fr_FR').format(product.price)} MGA',
Icons.payments_outlined),
_buildModernInfoRow('Catégorie', product.category,
Icons.category_outlined),

3
lib/Views/bilanMois.dart

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:youmazgestion/Components/app_bar.dart';
import 'package:youmazgestion/controller/HistoryController.dart';
import 'package:intl/intl.dart';
import 'bilanDesJourne.dart';
@ -38,7 +39,7 @@ class _BilanMoisState extends State<BilanMois> {
children: [
_buildInfoCard(
title: 'Chiffre réalisé',
value: '${controller.totalSum.value.toStringAsFixed(2)} MGA',
value: '${NumberFormat('#,##0', 'fr_FR').format(controller.totalSum.value)} MGA',
color: Colors.green,
icon: Icons.monetization_on,
),

30
lib/Views/commandManagement.dart

@ -188,7 +188,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Montant total: ${montantFinal.toStringAsFixed(2)} MGA'),
Text('Montant total: ${NumberFormat('#,##0', 'fr_FR').format(montantFinal)} MGA'),
const SizedBox(height: 10),
TextField(
controller: amountController,
@ -207,7 +207,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
const SizedBox(height: 20),
if (amountGiven >= montantFinal)
Text(
'Monnaie à rendre: ${change.toStringAsFixed(2)} MGA',
'Monnaie à rendre: ${NumberFormat('#,##0', 'fr_FR').format(change)} MGA',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
@ -674,7 +674,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
),
] else
pw.Text(
'${detail.prixUnitaire.toStringAsFixed(0)}',
NumberFormat('#,##0', 'fr_FR').format(detail.prixUnitaire),
style: smallTextStyle
),
],
@ -690,7 +690,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
children: [
if (detail.estCadeau) ...[
pw.Text(
'${detail.sousTotal.toStringAsFixed(0)}',
NumberFormat('#,##0', 'fr_FR').format(detail.sousTotal),
style: pw.TextStyle(
fontSize: 8,
decoration: pw.TextDecoration.lineThrough,
@ -796,7 +796,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
children: [
pw.Text('TOTAL:', style: boldTextStyle),
pw.SizedBox(width: 10),
pw.Text('${commande.montantTotal.toStringAsFixed(0)} MGA', style: boldTextStyle),
pw.Text('${NumberFormat('#,##0', 'fr_FR').format(commande.montantTotal)} MGA', style: boldTextStyle),
],
),
],
@ -1552,7 +1552,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
if (totalRemises > 0 || totalCadeaux > 0) ...[
pw.SizedBox(height: 4),
pw.Text(
'Économies réalisées: ${(totalRemises + totalCadeaux).toStringAsFixed(0)} MGA',
'Économies réalisées: ${NumberFormat('#,##0', 'fr_FR').format(totalRemises + totalCadeaux)} MGA',
style: pw.TextStyle(
fontSize: 8,
color: PdfColors.green,
@ -1694,7 +1694,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
pw.Text('🎁 ', style: emojifont),
pw.Expanded(
child: pw.Text(
'Merci de votre confiance ! Nous espérons que nos cadeaux vous feront plaisir. ($nombreCadeaux article(s) offert(s) - Valeur: ${totalCadeaux.toStringAsFixed(0)} MGA)',
'Merci de votre confiance ! Nous espérons que nos cadeaux vous feront plaisir. ($nombreCadeaux article(s) offert(s) - Valeur: ${NumberFormat('#,##0', 'fr_FR').format(totalCadeaux)} MGA)',
style: pw.TextStyle(
fontSize: 9,
fontStyle: pw.FontStyle.italic,
@ -1893,7 +1893,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
String _getPaymentMethodLabel(PaymentMethod payment) {
switch (payment.type) {
case PaymentType.cash:
return 'LIQUIDE (${payment.amountGiven.toStringAsFixed(0)} MGA)';
return 'LIQUIDE (${NumberFormat('#,##0', 'fr_FR').format(payment.amountGiven)} MGA)';
case PaymentType.card:
return 'CARTE BANCAIRE';
case PaymentType.mvola:
@ -2149,7 +2149,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
children: [
pw.Text('SOUS-TOTAL:',
style: const pw.TextStyle(fontSize: 8)),
pw.Text('${sousTotal.toStringAsFixed(0)} MGA',
pw.Text('${NumberFormat('#,##0', 'fr_FR').format(sousTotal)} MGA',
style: const pw.TextStyle(fontSize: 8)),
],
),
@ -2160,7 +2160,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
pw.Text('REMISES:',
style: pw.TextStyle(
fontSize: 8, color: PdfColors.orange)),
pw.Text('-${totalRemises.toStringAsFixed(0)} MGA',
pw.Text('-${NumberFormat('#,##0', 'fr_FR').format(totalRemises)} MGA',
style: pw.TextStyle(
fontSize: 8, color: PdfColors.orange)),
],
@ -2173,7 +2173,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
pw.Text('CADEAUX ($nombreCadeaux):',
style: pw.TextStyle(
fontSize: 8, color: PdfColors.green700)),
pw.Text('-${totalCadeaux.toStringAsFixed(0)} MGA',
pw.Text('-${NumberFormat('#,##0', 'fr_FR').format(totalCadeaux)} MGA',
style: pw.TextStyle(
fontSize: 8, color: PdfColors.green700)),
],
@ -2189,7 +2189,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
pw.Text('TOTAL:',
style: pw.TextStyle(
fontSize: 9, fontWeight: pw.FontWeight.bold)),
pw.Text('${commande.montantTotal.toStringAsFixed(0)} MGA',
pw.Text('${NumberFormat('#,##0', 'fr_FR').format(commande.montantTotal)} MGA',
style: pw.TextStyle(
fontSize: 9, fontWeight: pw.FontWeight.bold)),
],
@ -2198,7 +2198,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
if (totalRemises > 0 || totalCadeaux > 0) ...[
pw.SizedBox(height: 4),
pw.Text(
'Économies: ${(totalRemises + totalCadeaux).toStringAsFixed(0)} MGA !',
'Économies: ${NumberFormat('#,##0', 'fr_FR').format(totalRemises + totalCadeaux)} MGA !',
style: pw.TextStyle(
fontSize: 7,
color: PdfColors.green,
@ -2222,7 +2222,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
if (payment.type == PaymentType.cash &&
payment.amountGiven > commande.montantTotal)
pw.Text(
'Monnaie rendue: ${(payment.amountGiven - commande.montantTotal).toStringAsFixed(0)} MGA',
'Monnaie rendue: ${NumberFormat('#,##0', 'fr_FR').format(payment.amountGiven - commande.montantTotal)} MGA',
style: const pw.TextStyle(fontSize: 8)),
pw.SizedBox(height: 8),
@ -2827,7 +2827,7 @@ class _GestionCommandesPageState extends State<GestionCommandesPage> {
),
const SizedBox(width: 4),
Text(
'${commande.montantTotal.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(commande.montantTotal)} MGA',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,

22
lib/Views/historique.dart

@ -54,7 +54,7 @@ class _HistoriquePageState extends State<HistoriquePage> {
Future<void> _loadPointsDeVenteWithDefault() async {
try {
print(_userController.userId);
print(_userController.pointDeVenteId);
final points = await _appDatabase.getPointsDeVente();
setState(() {
_pointsDeVente = points;
@ -88,7 +88,11 @@ class _HistoriquePageState extends State<HistoriquePage> {
});
try {
final commandes = await _appDatabase.getCommandes();
final allCommandes = await _appDatabase.getCommandes();
final pointDeVenteId = _userController.pointDeVenteId;
final commandes = pointDeVenteId == 0
? allCommandes
: allCommandes.where((cmd) => cmd.pointDeVenteId == pointDeVenteId).toList();
setState(() {
_commandes.clear();
@ -136,11 +140,13 @@ class _HistoriquePageState extends State<HistoriquePage> {
final searchText = _searchController.text.toLowerCase();
final clientQuery = _searchClientController.text.toLowerCase();
final commandeIdQuery = _searchCommandeIdController.text.toLowerCase();
final pointDeVenteId = _userController.pointDeVenteId;
setState(() {
_filteredCommandes.clear();
for (var commande in _commandes) {
if (pointDeVenteId != 0 && commande.pointDeVenteId != pointDeVenteId) continue;
bool matchesSearch = searchText.isEmpty ||
commande.clientNom!.toLowerCase().contains(searchText) ||
commande.clientPrenom!.toLowerCase().contains(searchText) ||
@ -590,7 +596,7 @@ class _HistoriquePageState extends State<HistoriquePage> {
),
),
Text(
'${commande.montantTotal.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(commande.montantTotal)} MGA',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
@ -641,10 +647,10 @@ class _HistoriquePageState extends State<HistoriquePage> {
const TextStyle(fontWeight: FontWeight.w500),
),
subtitle: Text(
'${detail.quantite} x ${detail.prixUnitaire.toStringAsFixed(2)} MGA',
'${detail.quantite} x ${NumberFormat('#,##0.00', 'fr_FR').format(detail.prixUnitaire)} MGA',
),
trailing: Text(
'${detail.sousTotal.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(detail.sousTotal)} MGA',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.blue.shade800,
@ -789,7 +795,7 @@ class _HistoriquePageState extends State<HistoriquePage> {
Widget _buildCommandeListItem(Commande commande) {
final isMobile = MediaQuery.of(context).size.width < 600;
// print(commande.commandeurId);
print(_userController.userId);
print(_userController.pointDeVenteId);
return Card(
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
@ -838,7 +844,7 @@ class _HistoriquePageState extends State<HistoriquePage> {
),
),
Text(
'PV: ${_selectedPointDeVente}',
'PV: ${commande.pointDeVenteDesign}',
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14,
@ -858,7 +864,7 @@ class _HistoriquePageState extends State<HistoriquePage> {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'${commande.montantTotal.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(commande.montantTotal)} MGA',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.green.shade700,

5
lib/Views/listCommandeHistory.dart

@ -5,6 +5,7 @@ import 'package:youmazgestion/Views/voirPlus.dart';
import 'package:youmazgestion/controller/HistoryController.dart';
import '../Models/Order.dart';
import 'package:youmazgestion/Views/detailHistory.dart';
import 'package:intl/intl.dart';
class HistoryDetailPage extends StatelessWidget {
final DateTime selectedDate;
@ -112,7 +113,7 @@ class HistoryDetailPage extends StatelessWidget {
),
),
Text(
'Total Somme: $totalSum MGA',
'Total Somme: ${NumberFormat('#,##0', 'fr_FR').format(totalSum)} MGA',
style: const TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
@ -197,7 +198,7 @@ class HistoryDetailPage extends StatelessWidget {
),
],
),
subtitle: Text('Total: ${order.totalPrice} MGA'),
subtitle: Text('Total: ${NumberFormat('#,##0', 'fr_FR').format(order.totalPrice)} MGA'),
trailing: Text('Date: ${order.dateTime}'),
leading: Text('vendeur: ${order.user}'),
onTap: () {

136
lib/Views/newCommand.dart

@ -10,6 +10,7 @@ import 'package:youmazgestion/Models/users.dart';
import 'package:youmazgestion/Models/produit.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import 'package:youmazgestion/controller/userController.dart';
import 'package:intl/intl.dart';
class NouvelleCommandePage extends StatefulWidget {
const NouvelleCommandePage({super.key});
@ -695,7 +696,7 @@ void _modifierQuantite(int productId, int nouvelleQuantite) {
const SizedBox(height: 12),
// Détails du produit en grille
_buildProductDetailRow('Prix', '${product.price.toStringAsFixed(2)} MGA'),
_buildProductDetailRow('Prix', '${NumberFormat('#,##0', 'fr_FR').format(product.price)} MGA'),
_buildProductDetailRow('Quantité ajoutée', '$newQuantity'),
if (product.imei != null && product.imei!.isNotEmpty)
@ -2348,10 +2349,18 @@ Widget _buildRoleBasedHeader() {
),
);
}
// 🎯 MODIFIÉ: Interface produit avec indication visuelle de la commandabilité
// 🎯 MODIFIÉ: Interface produit avec filtrage des produits en rupture ou non assignés
Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
// ===== FILTRAGE : Ne pas afficher les produits en rupture ou non assignés =====
final bool isOutOfStock = product.stock != null && product.stock! <= 0;
final bool hasNoPointDeVente = product.pointDeVenteId == null || product.pointDeVenteId == 0;
// Si le produit est en rupture de stock OU n'a pas de point de vente assigné, on ne l'affiche pas
if (isOutOfStock || hasNoPointDeVente) {
return const SizedBox.shrink(); // Widget vide qui ne prend pas d'espace
}
// ===== VARIABLES D'ÉTAT =====
final detailPanier = _panierDetails[product.id!];
final int currentQuantity = detailPanier?.quantite ?? 0;
final isCurrentUserPointDeVente = product.pointDeVenteId == _userController.pointDeVenteId;
@ -2385,9 +2394,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: isOutOfStock
? Border.all(color: Colors.red.shade200, width: 1.5)
: detailPanier?.estCadeau == true
border: detailPanier?.estCadeau == true
? Border.all(color: Colors.green.shade300, width: 2)
: detailPanier?.aRemise == true
? Border.all(color: Colors.orange.shade300, width: 2)
@ -2403,14 +2410,13 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
children: [
Row(
children: [
// ===== ICÔNE PRODUIT =====
Container(
width: isMobile ? 40 : 50,
height: isMobile ? 40 : 50,
decoration: BoxDecoration(
color: !isProduitCommandable
? Colors.grey.shade100
: isOutOfStock
? Colors.red.shade50
: detailPanier?.estCadeau == true
? Colors.green.shade50
: detailPanier?.aRemise == true
@ -2433,8 +2439,6 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
size: isMobile ? 20 : 24,
color: !isProduitCommandable
? Colors.grey.shade500
: isOutOfStock
? Colors.red
: detailPanier?.estCadeau == true
? Colors.green.shade700
: detailPanier?.aRemise == true
@ -2445,10 +2449,13 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
),
),
const SizedBox(width: 12),
// ===== INFORMATIONS PRODUIT =====
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Nom du produit avec badges de statut
Row(
children: [
Expanded(
@ -2459,13 +2466,12 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
fontSize: isMobile ? 14 : 16,
color: !isProduitCommandable
? Colors.grey.shade600
: isOutOfStock
? Colors.red.shade700
: null,
),
),
),
// Indicateurs de statut
// Badge "AUTRE PV" pour produits non commandables
if (!isProduitCommandable && !_isUserSuperAdmin())
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
@ -2489,6 +2495,8 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
],
),
),
// Badge "CADEAU"
if (detailPanier?.estCadeau == true)
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
@ -2505,6 +2513,8 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
),
),
),
// Badge "MON PV"
if (isCurrentUserPointDeVente && detailPanier?.estCadeau != true && isProduitCommandable)
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
@ -2529,6 +2539,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
Row(
children: [
if (detailPanier?.estCadeau == true) ...[
// Prix gratuit pour les cadeaux
Text(
'Gratuit',
style: TextStyle(
@ -2539,7 +2550,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
),
const SizedBox(width: 8),
Text(
'${product.price.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(product.price)} MGA',
style: TextStyle(
color: Colors.grey.shade500,
fontWeight: FontWeight.w600,
@ -2548,8 +2559,9 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
),
),
] else ...[
// Prix normal ou avec remise
Text(
'${product.price.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(product.price)} MGA',
style: TextStyle(
color: Colors.green.shade700,
fontWeight: FontWeight.w600,
@ -2559,10 +2571,11 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
: null,
),
),
// Prix après remise
if (detailPanier?.aRemise == true) ...[
const SizedBox(width: 8),
Text(
'${(detailPanier!.prixFinal / detailPanier.quantite).toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(detailPanier!.prixFinal / detailPanier.quantite)} MGA',
style: TextStyle(
color: Colors.orange.shade700,
fontWeight: FontWeight.bold,
@ -2574,7 +2587,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
],
),
// Affichage remise
// Description de la remise
if (detailPanier?.aRemise == true && !detailPanier!.estCadeau)
Text(
'Remise: ${detailPanier!.remiseDescription}',
@ -2585,20 +2598,17 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
),
),
// Stock
// ===== STOCK (Toujours > 0 grâce au filtrage) =====
if (product.stock != null)
Text(
'Stock: ${product.stock}${isOutOfStock ? ' (Rupture)' : ''}',
'Stock: ${product.stock}',
style: TextStyle(
fontSize: isMobile ? 10 : 12,
color: isOutOfStock
? Colors.red.shade600
: Colors.grey.shade600,
fontWeight: isOutOfStock ? FontWeight.w600 : FontWeight.normal,
color: Colors.grey.shade600,
),
),
// ===== AFFICHAGE IMEI ET RÉFÉRENCE =====
// ===== IMEI ET RÉFÉRENCE =====
if (product.imei != null && product.imei!.isNotEmpty)
Text(
'IMEI: ${product.imei}',
@ -2617,7 +2627,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
),
),
// Point de vente
// ===== POINT DE VENTE =====
const SizedBox(height: 4),
Row(
children: [
@ -2680,7 +2690,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
? Colors.green.shade700
: Colors.grey.shade600,
),
onPressed: isOutOfStock ? null : () => _basculerStatutCadeau(product.id!),
onPressed: () => _basculerStatutCadeau(product.id!),
tooltip: detailPanier?.estCadeau == true
? 'Retirer le statut cadeau'
: 'Marquer comme cadeau',
@ -2692,6 +2702,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
),
),
),
// Bouton remise (seulement pour les articles non-cadeaux)
if (!detailPanier!.estCadeau)
Container(
@ -2706,7 +2717,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
? Colors.orange.shade700
: Colors.grey.shade600,
),
onPressed: isOutOfStock ? null : () => _showRemiseDialog(product),
onPressed: () => _showRemiseDialog(product),
tooltip: detailPanier.aRemise
? 'Modifier la remise'
: 'Ajouter une remise',
@ -2718,6 +2729,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
),
),
),
// Bouton pour ajouter un cadeau à un autre produit
Container(
margin: const EdgeInsets.only(left: 4),
@ -2727,7 +2739,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
size: isMobile ? 16 : 18,
color: Colors.green.shade600,
),
onPressed: isOutOfStock ? null : () => _showCadeauDialog(product),
onPressed: () => _showCadeauDialog(product),
tooltip: 'Ajouter un cadeau',
style: IconButton.styleFrom(
backgroundColor: Colors.green.shade50,
@ -2740,13 +2752,11 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
const SizedBox(height: 8),
],
// Contrôles de quantité (seulement si commandable)
// ===== CONTRÔLES DE QUANTITÉ =====
if (isProduitCommandable)
Container(
decoration: BoxDecoration(
color: isOutOfStock
? Colors.grey.shade100
: detailPanier?.estCadeau == true
color: detailPanier?.estCadeau == true
? Colors.green.shade50
: isCurrentUserPointDeVente
? Colors.orange.shade50
@ -2756,14 +2766,16 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
// Bouton diminuer
IconButton(
icon: Icon(Icons.remove, size: isMobile ? 16 : 18),
onPressed: isOutOfStock ? null : () {
onPressed: () {
if (currentQuantity > 0) {
_modifierQuantite(product.id!, currentQuantity - 1);
}
},
),
// Quantité actuelle
Text(
currentQuantity.toString(),
style: TextStyle(
@ -2771,9 +2783,10 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
fontSize: isMobile ? 12 : 14,
),
),
// Bouton augmenter
IconButton(
icon: Icon(Icons.add, size: isMobile ? 16 : 18),
onPressed: isOutOfStock ? null : () {
onPressed: () {
if (product.stock == null || currentQuantity < product.stock!) {
if (currentQuantity == 0) {
_ajouterAuPanier(product, 1);
@ -2795,7 +2808,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
),
)
else
// Message informatif pour produits non-commandables
// ===== SECTION PRODUITS NON-COMMANDABLES =====
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
@ -2805,6 +2818,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
),
child: Column(
children: [
// Indicateur de consultation
Row(
mainAxisSize: MainAxisSize.min,
children: [
@ -2821,28 +2835,18 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
],
),
const SizedBox(height: 4),
// Bouton demande de transfert
ElevatedButton.icon(
icon: const Icon(Icons.swap_horiz, size: 14),
label:!isMobile ? const Text('Demander transfertt'):const SizedBox.shrink(),
label: !isMobile ? const Text('Demander transfert') : const SizedBox.shrink(),
style: ElevatedButton.styleFrom(
backgroundColor: (product.stock != null && product.stock! >= 1)
? Colors.blue.shade700
: Colors.grey.shade400,
backgroundColor: Colors.blue.shade700,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
),
onPressed: (product.stock != null && product.stock! >= 1)
? () => _showDemandeTransfertDialog(product)
: () {
Get.snackbar(
'Stock insuffisant',
'Impossible de demander un transfert : produit en rupture de stock',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.orange.shade600,
colorText: Colors.white,
);
},
),
onPressed: () => _showDemandeTransfertDialog(product),
),
],
),
),
@ -2989,7 +2993,7 @@ Future<void> _showDemandeTransfertDialog(Product product) async {
Expanded(
child: _buildInfoCard(
'Prix unitaire',
'${product.price.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(product.price)} MGA',
Icons.attach_money,
Colors.green,
),
@ -3513,7 +3517,7 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
),
const SizedBox(width: 8),
Text(
'(${detail.prixUnitaire.toStringAsFixed(2)} MGA)',
'(${NumberFormat('#,##0', 'fr_FR').format(detail.prixUnitaire)} MGA)',
style: TextStyle(
fontSize: 11,
color: Colors.grey.shade500,
@ -3530,19 +3534,19 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
),
const Text(''),
Text(
'${(detail.prixFinal / detail.quantite).toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(detail.prixFinal / detail.quantite)} MGA',
style: TextStyle(
color: Colors.orange.shade700,
fontWeight: FontWeight.bold,
),
),
] else
Text('${detail.prixUnitaire.toStringAsFixed(2)} MGA'),
Text('${NumberFormat('#,##0', 'fr_FR').format(detail.prixUnitaire)} MGA'),
],
),
if (detail.aRemise && !detail.estCadeau)
Text(
'Remise: ${detail.remiseDescription} (-${detail.montantRemise.toStringAsFixed(2)} MGA)',
'Remise: ${detail.remiseDescription} (-${NumberFormat('#,##0', 'fr_FR').format(detail.montantRemise)} MGA)',
style: TextStyle(
fontSize: 11,
color: Colors.orange.shade600,
@ -3595,7 +3599,7 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
],
),
Text(
'Valeur: ${detail.sousTotal.toStringAsFixed(2)} MGA',
'Valeur: ${NumberFormat('#,##0', 'fr_FR').format(detail.sousTotal)} MGA',
style: TextStyle(
fontSize: 10,
color: Colors.grey.shade500,
@ -3604,7 +3608,7 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
),
] else if (detail.aRemise && detail.sousTotal != detail.prixFinal) ...[
Text(
'${detail.sousTotal.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(detail.sousTotal)} MGA',
style: const TextStyle(
fontSize: 11,
decoration: TextDecoration.lineThrough,
@ -3612,7 +3616,7 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
),
),
Text(
'${detail.prixFinal.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(detail.prixFinal)} MGA',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.orange.shade700,
@ -3621,7 +3625,7 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
),
] else
Text(
'${detail.prixFinal.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(detail.prixFinal)} MGA',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.blue.shade800,
@ -3673,7 +3677,7 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
children: [
const Text('Sous-total:', style: TextStyle(fontSize: 14)),
Text(
'${sousTotal.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(sousTotal)} MGA',
style: const TextStyle(fontSize: 14),
),
],
@ -3694,7 +3698,7 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
),
),
Text(
'-${totalRemises.toStringAsFixed(2)} MGA',
'-${NumberFormat('#,##0', 'fr_FR').format(totalRemises)} MGA',
style: TextStyle(
fontSize: 14,
color: Colors.orange.shade700,
@ -3729,7 +3733,7 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
],
),
Text(
'-${totalCadeaux.toStringAsFixed(2)} MGA',
'-${NumberFormat('#,##0', 'fr_FR').format(totalCadeaux)} MGA',
style: TextStyle(
fontSize: 14,
color: Colors.green.shade700,
@ -3753,7 +3757,7 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
Text(
'${total.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(total)} MGA',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
@ -3791,7 +3795,7 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
),
const SizedBox(width: 4),
Text(
'Économies totales: ${(totalRemises + totalCadeaux).toStringAsFixed(2)} MGA',
'Économies totales: ${NumberFormat('#,##0', 'fr_FR').format(totalRemises + totalCadeaux)} MGA',
style: TextStyle(
color: Colors.green.shade700,
fontWeight: FontWeight.bold,
@ -3807,7 +3811,7 @@ Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Colo
if (totalRemises > 0 && totalCadeaux > 0) ...[
const SizedBox(height: 4),
Text(
'Remises: ${totalRemises.toStringAsFixed(2)} MGA • Cadeaux: ${totalCadeaux.toStringAsFixed(2)} MGA',
'Remises: ${NumberFormat('#,##0', 'fr_FR').format(totalRemises)} MGA • Cadeaux: ${NumberFormat('#,##0', 'fr_FR').format(totalCadeaux)} MGA',
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 11,

3
lib/Views/produitsCard.dart

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:youmazgestion/Models/produit.dart';
import 'package:intl/intl.dart';
class ProductCard extends StatefulWidget {
final Product product;
@ -221,7 +222,7 @@ class _ProductCardState extends State<ProductCard>
),
const SizedBox(height: 4),
Text(
'${widget.product.price.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0', 'fr_FR').format(widget.product.price)} MGA',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 13,

22
lib/Views/ticketPage.dart

@ -1,5 +1,5 @@
import 'dart:io';
import 'package:intl/intl.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@ -67,8 +67,8 @@ class TicketPage extends StatelessWidget {
return [
product.name,
quantity.toString(),
'${product.price.toStringAsFixed(2)} MGA',
'${productTotal.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(product.price)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(productTotal)} MGA',
];
}).toList(),
],
@ -82,7 +82,7 @@ class TicketPage extends StatelessWidget {
pw.Text('Total :',
style: pw.TextStyle(
fontSize: 18, fontWeight: pw.FontWeight.bold)),
pw.Text('${totalCartPrice.toStringAsFixed(2)} MGA',
pw.Text('${NumberFormat('#,##0.00', 'fr_FR').format(totalCartPrice)} MGA',
style: pw.TextStyle(
fontSize: 18, fontWeight: pw.FontWeight.bold)),
],
@ -95,7 +95,7 @@ class TicketPage extends StatelessWidget {
children: [
pw.Text('Somme remise :',
style: const pw.TextStyle(fontSize: 16)),
pw.Text('${amountPaid.toStringAsFixed(2)} MGA',
pw.Text('${NumberFormat('#,##0.00', 'fr_FR').format(amountPaid)} MGA',
style: const pw.TextStyle(fontSize: 16)),
],
),
@ -106,7 +106,7 @@ class TicketPage extends StatelessWidget {
pw.Text('Somme rendue :',
style: const pw.TextStyle(fontSize: 16)),
pw.Text(
'${(amountPaid - totalCartPrice).toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(amountPaid - totalCartPrice)} MGA',
style: const pw.TextStyle(fontSize: 16)),
],
),
@ -271,14 +271,14 @@ class TicketPage extends StatelessWidget {
TableCell(
child: Center(
child: Text(
'${product.price.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(product.price)} MGA',
),
),
),
TableCell(
child: Center(
child: Text(
'${productTotal.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(productTotal)} MGA',
),
),
),
@ -305,7 +305,7 @@ class TicketPage extends StatelessWidget {
),
),
Text(
'${totalOrderAmount.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(totalOrderAmount)} MGA',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
@ -330,7 +330,7 @@ class TicketPage extends StatelessWidget {
),
),
Text(
'${amountPaid.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(amountPaid)} MGA',
style: const TextStyle(
fontSize: 16,
),
@ -348,7 +348,7 @@ class TicketPage extends StatelessWidget {
),
),
Text(
'${change.toStringAsFixed(2)} MGA',
'${NumberFormat('#,##0.00', 'fr_FR').format(change)} MGA',
style: const TextStyle(
fontSize: 16,
),

2
lib/config/DatabaseConfig.dart

@ -5,7 +5,7 @@ import 'dart:async';
class DatabaseConfig {
// Local MySQL settings
static const String localHost = '192.168.88.73';
static const String localHost = '102.17.52.31';
static const String localUsername = 'guycom';
static const String? localPassword = '3iV59wjRdbuXAPR';
static const String localDatabase = 'guycom';

Loading…
Cancel
Save