push 29072025_01
This commit is contained in:
parent
c5ef3ca0cb
commit
ab97716dd2
@ -45,6 +45,11 @@ class AppDatabase {
|
|||||||
await insertDefaultPointsDeVente();
|
await insertDefaultPointsDeVente();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String _formatDate(DateTime date) {
|
||||||
|
return DateFormat('yyyy-MM-dd HH:mm:ss').format(date);
|
||||||
|
}
|
||||||
|
|
||||||
Future<MySqlConnection> _initDB() async {
|
Future<MySqlConnection> _initDB() async {
|
||||||
try {
|
try {
|
||||||
final config = await DatabaseConfig.getSmartConfig();
|
final config = await DatabaseConfig.getSmartConfig();
|
||||||
@ -2395,30 +2400,55 @@ Future<double> getValeurTotaleStock() async {
|
|||||||
return erreurs;
|
return erreurs;
|
||||||
}
|
}
|
||||||
// --- MÉTHODES POUR LES VENTES PAR POINT DE VENTE ---
|
// --- MÉTHODES POUR LES VENTES PAR POINT DE VENTE ---
|
||||||
|
Future<List<Map<String, dynamic>>> getVentesParPointDeVente({
|
||||||
Future<List<Map<String, dynamic>>> getVentesParPointDeVente() async {
|
DateTime? dateDebut,
|
||||||
|
DateTime? dateFin,
|
||||||
|
bool? aujourdHuiSeulement = false,
|
||||||
|
}) async {
|
||||||
final db = await database;
|
final db = await database;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
String whereClause = 'WHERE c.statut != 5';
|
||||||
|
List<dynamic> whereArgs = [];
|
||||||
|
|
||||||
|
if (aujourdHuiSeulement == true) {
|
||||||
|
final today = DateTime.now();
|
||||||
|
final startOfDay = DateTime(today.year, today.month, today.day);
|
||||||
|
final endOfDay = DateTime(today.year, today.month, today.day, 23, 59, 59);
|
||||||
|
|
||||||
|
whereClause += ' AND c.dateCommande >= ? AND c.dateCommande <= ?';
|
||||||
|
whereArgs.addAll([
|
||||||
|
_formatDate(startOfDay),
|
||||||
|
_formatDate(endOfDay),
|
||||||
|
]);
|
||||||
|
} else if (dateDebut != null && dateFin != null) {
|
||||||
|
final adjustedEndDate = DateTime(dateFin.year, dateFin.month, dateFin.day, 23, 59, 59);
|
||||||
|
whereClause += ' AND c.dateCommande >= ? AND c.dateCommande <= ?';
|
||||||
|
whereArgs.addAll([
|
||||||
|
_formatDate(dateDebut),
|
||||||
|
_formatDate(adjustedEndDate),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
final result = await db.query('''
|
final result = await db.query('''
|
||||||
SELECT
|
SELECT
|
||||||
pv.id as point_vente_id,
|
pv.id AS point_vente_id,
|
||||||
pv.nom as point_vente_nom,
|
pv.nom AS point_vente_nom,
|
||||||
COUNT(DISTINCT c.id) as nombre_commandes,
|
COUNT(DISTINCT c.id) AS nombre_commandes,
|
||||||
COUNT(dc.id) as nombre_articles_vendus,
|
COUNT(dc.id) AS nombre_articles_vendus,
|
||||||
SUM(dc.quantite) as quantite_totale_vendue,
|
SUM(dc.quantite) AS quantite_totale_vendue,
|
||||||
SUM(c.montantTotal) as chiffre_affaires,
|
SUM(c.montantTotal) AS chiffre_affaires,
|
||||||
AVG(c.montantTotal) as panier_moyen,
|
AVG(c.montantTotal) AS panier_moyen,
|
||||||
MIN(c.dateCommande) as premiere_vente,
|
MIN(c.dateCommande) AS premiere_vente,
|
||||||
MAX(c.dateCommande) as derniere_vente
|
MAX(c.dateCommande) AS derniere_vente
|
||||||
FROM points_de_vente pv
|
FROM points_de_vente pv
|
||||||
LEFT JOIN products p ON pv.id = p.point_de_vente_id
|
LEFT JOIN users u ON u.point_de_vente_id = pv.id
|
||||||
LEFT JOIN details_commandes dc ON p.id = dc.produitId
|
LEFT JOIN commandes c ON c.commandeurId = u.id
|
||||||
LEFT JOIN commandes c ON dc.commandeId = c.id
|
LEFT JOIN details_commandes dc ON dc.commandeId = c.id
|
||||||
WHERE c.statut != 5 -- Exclure les commandes annulées
|
$whereClause
|
||||||
GROUP BY pv.id, pv.nom
|
GROUP BY pv.id, pv.nom
|
||||||
ORDER BY chiffre_affaires DESC
|
ORDER BY chiffre_affaires DESC;
|
||||||
''');
|
''', whereArgs);
|
||||||
|
|
||||||
return result.map((row) => row.fields).toList();
|
return result.map((row) => row.fields).toList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -2426,13 +2456,38 @@ Future<double> getValeurTotaleStock() async {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Map<String, dynamic>>> getTopProduitsParPointDeVente(
|
Future<List<Map<String, dynamic>>> getTopProduitsParPointDeVente(
|
||||||
int pointDeVenteId,
|
int pointDeVenteId, {
|
||||||
{int limit = 5}) async {
|
int limit = 5,
|
||||||
|
DateTime? dateDebut,
|
||||||
|
DateTime? dateFin,
|
||||||
|
bool? aujourdHuiSeulement = false,
|
||||||
|
}) async {
|
||||||
final db = await database;
|
final db = await database;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
String whereClause = 'WHERE p.point_de_vente_id = ? AND c.statut != 5';
|
||||||
|
List<dynamic> whereArgs = [pointDeVenteId];
|
||||||
|
|
||||||
|
if (aujourdHuiSeulement == true) {
|
||||||
|
final today = DateTime.now();
|
||||||
|
final startOfDay = DateTime(today.year, today.month, today.day);
|
||||||
|
final endOfDay = DateTime(today.year, today.month, today.day, 23, 59, 59);
|
||||||
|
|
||||||
|
whereClause += ' AND c.dateCommande >= ? AND c.dateCommande <= ?';
|
||||||
|
whereArgs.addAll([
|
||||||
|
_formatDate(startOfDay),
|
||||||
|
_formatDate(endOfDay),
|
||||||
|
]);
|
||||||
|
} else if (dateDebut != null && dateFin != null) {
|
||||||
|
final adjustedEndDate = DateTime(dateFin.year, dateFin.month, dateFin.day, 23, 59, 59);
|
||||||
|
whereClause += ' AND c.dateCommande >= ? AND c.dateCommande <= ?';
|
||||||
|
whereArgs.addAll([
|
||||||
|
_formatDate(dateDebut),
|
||||||
|
_formatDate(adjustedEndDate),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
final result = await db.query('''
|
final result = await db.query('''
|
||||||
SELECT
|
SELECT
|
||||||
p.id,
|
p.id,
|
||||||
@ -2445,11 +2500,11 @@ Future<double> getValeurTotaleStock() async {
|
|||||||
FROM products p
|
FROM products p
|
||||||
INNER JOIN details_commandes dc ON p.id = dc.produitId
|
INNER JOIN details_commandes dc ON p.id = dc.produitId
|
||||||
INNER JOIN commandes c ON dc.commandeId = c.id
|
INNER JOIN commandes c ON dc.commandeId = c.id
|
||||||
WHERE p.point_de_vente_id = ? AND c.statut != 5
|
$whereClause
|
||||||
GROUP BY p.id, p.name, p.price, p.category
|
GROUP BY p.id, p.name, p.price, p.category
|
||||||
ORDER BY quantite_vendue DESC
|
ORDER BY quantite_vendue DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
''', [pointDeVenteId, limit]);
|
''', [...whereArgs, limit]);
|
||||||
|
|
||||||
return result.map((row) => row.fields).toList();
|
return result.map((row) => row.fields).toList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -3270,3 +3325,6 @@ Future<List<Map<String, dynamic>>> getHistoriqueSortiesPersonnelles({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _formatDate {
|
||||||
|
}
|
||||||
|
|||||||
@ -1100,7 +1100,6 @@ Widget _buildMiniStatistics() {
|
|||||||
|
|
||||||
//widget vente
|
//widget vente
|
||||||
// 2. Ajoutez cette méthode dans la classe _DashboardPageState
|
// 2. Ajoutez cette méthode dans la classe _DashboardPageState
|
||||||
|
|
||||||
Widget _buildVentesParPointDeVenteCard() {
|
Widget _buildVentesParPointDeVenteCard() {
|
||||||
return Card(
|
return Card(
|
||||||
elevation: 4,
|
elevation: 4,
|
||||||
@ -1123,13 +1122,91 @@ Widget _buildVentesParPointDeVenteCard() {
|
|||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Spacer(),
|
||||||
|
// Boutons de filtre dans le header
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: _toggleTodayFilter,
|
||||||
|
icon: Icon(
|
||||||
|
_showOnlyToday ? Icons.today : Icons.calendar_today,
|
||||||
|
color: _showOnlyToday ? Colors.green : Colors.grey,
|
||||||
|
),
|
||||||
|
tooltip: _showOnlyToday ? 'Toutes les dates' : 'Aujourd\'hui seulement',
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => _selectDateRange(context),
|
||||||
|
icon: Icon(
|
||||||
|
Icons.date_range,
|
||||||
|
color: _dateRange != null ? Colors.orange : Colors.grey,
|
||||||
|
),
|
||||||
|
tooltip: 'Sélectionner une période',
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// Affichage de la période sélectionnée
|
||||||
|
if (_showOnlyToday || _dateRange != null)
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 8),
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: (_showOnlyToday ? Colors.green : Colors.orange).withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
border: Border.all(
|
||||||
|
color: (_showOnlyToday ? Colors.green : Colors.orange).withOpacity(0.3),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
_showOnlyToday ? Icons.today : Icons.date_range,
|
||||||
|
size: 16,
|
||||||
|
color: _showOnlyToday ? Colors.green : Colors.orange,
|
||||||
|
),
|
||||||
|
SizedBox(width: 4),
|
||||||
|
Text(
|
||||||
|
_showOnlyToday
|
||||||
|
? 'Aujourd\'hui'
|
||||||
|
: _dateRange != null
|
||||||
|
? '${DateFormat('dd/MM/yyyy').format(_dateRange!.start)} - ${DateFormat('dd/MM/yyyy').format(_dateRange!.end)}'
|
||||||
|
: 'Toutes les dates',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: _showOnlyToday ? Colors.green : Colors.orange,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 4),
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_showOnlyToday = false;
|
||||||
|
_dateRange = null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
Icons.close,
|
||||||
|
size: 16,
|
||||||
|
color: _showOnlyToday ? Colors.green : Colors.orange,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
SizedBox(height: 16),
|
SizedBox(height: 16),
|
||||||
Container(
|
Container(
|
||||||
height: 400,
|
height: 400,
|
||||||
child: FutureBuilder<List<Map<String, dynamic>>>(
|
child: FutureBuilder<List<Map<String, dynamic>>>(
|
||||||
future: _database.getVentesParPointDeVente(),
|
future: _database.getVentesParPointDeVente(
|
||||||
|
dateDebut: _dateRange?.start,
|
||||||
|
dateFin: _dateRange?.end,
|
||||||
|
aujourdHuiSeulement: _showOnlyToday,
|
||||||
|
),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
return Center(child: CircularProgressIndicator());
|
return Center(child: CircularProgressIndicator());
|
||||||
@ -1142,7 +1219,11 @@ Widget _buildVentesParPointDeVenteCard() {
|
|||||||
children: [
|
children: [
|
||||||
Icon(Icons.store_mall_directory_outlined, size: 64, color: Colors.grey),
|
Icon(Icons.store_mall_directory_outlined, size: 64, color: Colors.grey),
|
||||||
SizedBox(height: 16),
|
SizedBox(height: 16),
|
||||||
Text('Aucune donnée de vente par point de vente', style: TextStyle(color: Colors.grey)),
|
Text(
|
||||||
|
'Aucune donnée de vente${_showOnlyToday ? ' pour aujourd\'hui' : _dateRange != null ? ' pour cette période' : ''}',
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -1438,16 +1519,20 @@ String _formatCurrency(double value) {
|
|||||||
void _toggleTodayFilter() {
|
void _toggleTodayFilter() {
|
||||||
setState(() {
|
setState(() {
|
||||||
_showOnlyToday = !_showOnlyToday;
|
_showOnlyToday = !_showOnlyToday;
|
||||||
|
if (_showOnlyToday) {
|
||||||
|
_dateRange = null; // Reset date range when showing only today
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showPointVenteDetails(Map<String, dynamic> pointVenteData) async {
|
void _showPointVenteDetails(Map<String, dynamic> pointVenteData) async {
|
||||||
final isMobile = MediaQuery.of(context).size.width < 600;
|
final isMobile = MediaQuery.of(context).size.width < 600;
|
||||||
final pointVenteId = pointVenteData['point_vente_id'] as int;
|
final pointVenteId = pointVenteData['point_vente_id'] as int;
|
||||||
final pointVenteNom = pointVenteData['point_vente_nom'] as String;
|
final pointVenteNom = pointVenteData['point_vente_nom'] as String;
|
||||||
|
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder: (context) => StatefulBuilder(
|
||||||
|
builder: (context, setDialogState) => AlertDialog(
|
||||||
title: Text('Détails - $pointVenteNom'),
|
title: Text('Détails - $pointVenteNom'),
|
||||||
content: Container(
|
content: Container(
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
@ -1461,7 +1546,12 @@ void _showPointVenteDetails(Map<String, dynamic> pointVenteData) async {
|
|||||||
runSpacing: 8,
|
runSpacing: 8,
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: _toggleTodayFilter,
|
onPressed: () {
|
||||||
|
setDialogState(() {
|
||||||
|
_showOnlyToday = !_showOnlyToday;
|
||||||
|
if (_showOnlyToday) _dateRange = null;
|
||||||
|
});
|
||||||
|
},
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
_showOnlyToday ? Icons.today : Icons.calendar_today,
|
_showOnlyToday ? Icons.today : Icons.calendar_today,
|
||||||
size: 20,
|
size: 20,
|
||||||
@ -1485,7 +1575,25 @@ void _showPointVenteDetails(Map<String, dynamic> pointVenteData) async {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: () => _selectDateRange(context),
|
onPressed: () 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) {
|
||||||
|
setDialogState(() {
|
||||||
|
_dateRange = picked;
|
||||||
|
_showOnlyToday = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
icon: const Icon(Icons.date_range, size: 20),
|
icon: const Icon(Icons.date_range, size: 20),
|
||||||
label: Text(_dateRange != null
|
label: Text(_dateRange != null
|
||||||
? isMobile
|
? isMobile
|
||||||
@ -1507,30 +1615,53 @@ void _showPointVenteDetails(Map<String, dynamic> pointVenteData) async {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// Statistiques générales
|
|
||||||
_buildStatRow('Chiffre d\'affaires:', '${NumberFormat('#,##0.00', 'fr_FR').format((pointVenteData['chiffre_affaires'] as num?)?.toDouble() ?? 0.0)} MGA'),
|
SizedBox(height: 16),
|
||||||
_buildStatRow('Nombre de commandes:', '${pointVenteData['nombre_commandes'] ?? 0}'),
|
|
||||||
_buildStatRow('Articles vendus:', '${pointVenteData['nombre_articles_vendus'] ?? 0}'),
|
// Statistiques générales avec FutureBuilder pour refresh automatique
|
||||||
_buildStatRow('Quantité totale:', '${pointVenteData['quantite_totale_vendue'] ?? 0}'),
|
FutureBuilder<Map<String, dynamic>>(
|
||||||
_buildStatRow('Panier moyen:', '${NumberFormat('#,##0.00', 'fr_FR').format((pointVenteData['panier_moyen'] as num?)?.toDouble() ?? 0.0)} MGA'),
|
future: _getDetailedPointVenteStats(pointVenteId),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapshot.hasError || !snapshot.hasData) {
|
||||||
|
return Text('Erreur de chargement des statistiques');
|
||||||
|
}
|
||||||
|
|
||||||
|
final stats = snapshot.data!;
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
_buildStatRow('Chiffre d\'affaires:', '${NumberFormat('#,##0.00', 'fr_FR').format((stats['chiffre_affaires'] as num?)?.toDouble() ?? 0.0)} MGA'),
|
||||||
|
_buildStatRow('Nombre de commandes:', '${stats['nombre_commandes'] ?? 0}'),
|
||||||
|
_buildStatRow('Articles vendus:', '${stats['nombre_articles_vendus'] ?? 0}'),
|
||||||
|
_buildStatRow('Quantité totale:', '${stats['quantite_totale_vendue'] ?? 0}'),
|
||||||
|
_buildStatRow('Panier moyen:', '${NumberFormat('#,##0.00', 'fr_FR').format((stats['panier_moyen'] as num?)?.toDouble() ?? 0.0)} MGA'),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
SizedBox(height: 16),
|
SizedBox(height: 16),
|
||||||
Text('Top 5 des produits:', style: TextStyle(fontWeight: FontWeight.bold)),
|
Text('Top 5 des produits:', style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
|
|
||||||
|
// Top produits avec filtre
|
||||||
SizedBox(height: 16),
|
|
||||||
|
|
||||||
// ✅ Top produits
|
|
||||||
FutureBuilder<List<Map<String, dynamic>>>(
|
FutureBuilder<List<Map<String, dynamic>>>(
|
||||||
future: _database.getTopProduitsParPointDeVente(pointVenteId),
|
future: _database.getTopProduitsParPointDeVente(
|
||||||
|
pointVenteId,
|
||||||
|
dateDebut: _dateRange?.start,
|
||||||
|
dateFin: _dateRange?.end,
|
||||||
|
aujourdHuiSeulement: _showOnlyToday,
|
||||||
|
),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
return Center(child: CircularProgressIndicator());
|
return Center(child: CircularProgressIndicator());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snapshot.hasError || !snapshot.hasData || snapshot.data!.isEmpty) {
|
if (snapshot.hasError || !snapshot.hasData || snapshot.data!.isEmpty) {
|
||||||
return Text('Aucun produit vendu', style: TextStyle(color: Colors.grey));
|
return Text('Aucun produit vendu${_showOnlyToday ? ' aujourd\'hui' : _dateRange != null ? ' pour cette période' : ''}', style: TextStyle(color: Colors.grey));
|
||||||
}
|
}
|
||||||
|
|
||||||
final produits = snapshot.data!;
|
final produits = snapshot.data!;
|
||||||
@ -1562,15 +1693,47 @@ void _showPointVenteDetails(Map<String, dynamic> pointVenteData) async {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
|
if (_showOnlyToday || _dateRange != null)
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
setDialogState(() {
|
||||||
|
_showOnlyToday = false;
|
||||||
|
_dateRange = null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text('Réinitialiser'),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
child: Text('Fermer'),
|
child: Text('Fermer'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>> _getDetailedPointVenteStats(int pointVenteId) async {
|
||||||
|
final ventesData = await _database.getVentesParPointDeVente(
|
||||||
|
dateDebut: _dateRange?.start,
|
||||||
|
dateFin: _dateRange?.end,
|
||||||
|
aujourdHuiSeulement: _showOnlyToday,
|
||||||
|
);
|
||||||
|
|
||||||
|
final pointVenteStats = ventesData.firstWhere(
|
||||||
|
(data) => data['point_vente_id'] == pointVenteId,
|
||||||
|
orElse: () => {
|
||||||
|
'chiffre_affaires': 0.0,
|
||||||
|
'nombre_commandes': 0,
|
||||||
|
'nombre_articles_vendus': 0,
|
||||||
|
'quantite_totale_vendue': 0,
|
||||||
|
'panier_moyen': 0.0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return pointVenteStats;
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildStatRow(String label, String value) {
|
Widget _buildStatRow(String label, String value) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: 4),
|
padding: EdgeInsets.symmetric(vertical: 4),
|
||||||
|
|||||||
@ -11,7 +11,8 @@ class DatabaseConfig {
|
|||||||
static const String localDatabase = 'guycom';
|
static const String localDatabase = 'guycom';
|
||||||
|
|
||||||
// Production (public) MySQL settings
|
// Production (public) MySQL settings
|
||||||
static const String prodHost = '185.70.105.157';
|
// static const String prodHost = '185.70.105.157';
|
||||||
|
static const String prodHost = '102.17.52.31';
|
||||||
static const String prodUsername = 'guycom';
|
static const String prodUsername = 'guycom';
|
||||||
static const String prodPassword = '3iV59wjRdbuXAPR';
|
static const String prodPassword = '3iV59wjRdbuXAPR';
|
||||||
static const String prodDatabase = 'guycom';
|
static const String prodDatabase = 'guycom';
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user