Browse Source

client

28062025_02
Stephane 4 months ago
parent
commit
13296529c3
  1. 14
      lib/Services/stock_managementDatabase.dart
  2. 138
      lib/Views/historique.dart
  3. 2
      lib/config/DatabaseConfig.dart

14
lib/Services/stock_managementDatabase.dart

@ -806,24 +806,12 @@ 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,
u.nom as commandeurNom,
u.prenom as commandeurPrenom,
pdv.nom as pointDeVenteNom,
pdv.id as pointDeVenteId
SELECT c.*, cl.nom as clientNom, cl.prenom as clientPrenom, cl.email as clientEmail
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 pdv ON u.point_de_vente_id = pdv.id
ORDER BY c.dateCommande DESC
''');
return result.map((row) => Commande.fromMap(row.fields)).toList();
}

138
lib/Views/historique.dart

@ -1,19 +1,20 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:youmazgestion/Components/app_bar.dart';
import 'package:youmazgestion/Components/appDrawer.dart';
import 'package:youmazgestion/Models/client.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import 'package:youmazgestion/controller/userController.dart';
class HistoriquePage extends StatefulWidget {
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:youmazgestion/Components/app_bar.dart';
import 'package:youmazgestion/Components/appDrawer.dart';
import 'package:youmazgestion/Models/client.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
import 'package:youmazgestion/controller/userController.dart';
class HistoriquePage extends StatefulWidget {
const HistoriquePage({super.key});
@override
_HistoriquePageState createState() => _HistoriquePageState();
}
}
class _HistoriquePageState extends State<HistoriquePage> {
class _HistoriquePageState extends State<HistoriquePage> {
final AppDatabase _appDatabase = AppDatabase.instance;
// Listes pour les commandes
@ -30,7 +31,8 @@
// Contrôleurs pour les filtres
final TextEditingController _searchController = TextEditingController();
final TextEditingController _searchClientController = TextEditingController();
final TextEditingController _searchCommandeIdController = TextEditingController();
final TextEditingController _searchCommandeIdController =
TextEditingController();
// Variables de filtre
StatutCommande? _selectedStatut;
@ -50,8 +52,7 @@
_searchCommandeIdController.addListener(_filterCommandes);
}
Future<void> _loadPointsDeVenteWithDefault() async {
Future<void> _loadPointsDeVenteWithDefault() async {
try {
print(_userController.userId);
final points = await _appDatabase.getPointsDeVente();
@ -79,7 +80,7 @@ Future<void> _loadPointsDeVenteWithDefault() async {
Get.snackbar('Erreur', 'Impossible de charger les points de vente: $e');
print('❌ Erreur chargement points de vente: $e');
}
}
}
Future<void> _loadCommandes() async {
setState(() {
@ -115,7 +116,8 @@ Future<void> _loadPointsDeVenteWithDefault() async {
context: context,
firstDate: DateTime(2020),
lastDate: DateTime.now().add(const Duration(days: 365)),
initialDateRange: _dateRange ?? DateTimeRange(
initialDateRange: _dateRange ??
DateTimeRange(
start: DateTime.now().subtract(const Duration(days: 30)),
end: DateTime.now(),
),
@ -151,8 +153,8 @@ Future<void> _loadPointsDeVenteWithDefault() async {
bool matchesCommandeId = commandeIdQuery.isEmpty ||
commande.id.toString().contains(commandeIdQuery);
bool matchesStatut = _selectedStatut == null ||
commande.statut == _selectedStatut;
bool matchesStatut =
_selectedStatut == null || commande.statut == _selectedStatut;
bool matchesDate = true;
if (_dateRange != null) {
@ -161,8 +163,7 @@ Future<void> _loadPointsDeVenteWithDefault() async {
date.isBefore(_dateRange!.end.add(const Duration(days: 1)));
}
bool matchesToday = !_showOnlyToday ||
_isToday(commande.dateCommande);
bool matchesToday = !_showOnlyToday || _isToday(commande.dateCommande);
bool matchesAmount = true;
if (_minAmount != null && commande.montantTotal < _minAmount!) {
@ -172,8 +173,13 @@ Future<void> _loadPointsDeVenteWithDefault() async {
matchesAmount = false;
}
if (matchesSearch && matchesClient && matchesCommandeId &&
matchesStatut && matchesDate && matchesToday && matchesAmount) {
if (matchesSearch &&
matchesClient &&
matchesCommandeId &&
matchesStatut &&
matchesDate &&
matchesToday &&
matchesAmount) {
_filteredCommandes.add(commande);
}
}
@ -241,7 +247,8 @@ Future<void> _loadPointsDeVenteWithDefault() async {
TextButton.icon(
onPressed: _clearFilters,
icon: const Icon(Icons.clear, size: 18),
label: isMobile ? const SizedBox() : const Text('Réinitialiser'),
label:
isMobile ? const SizedBox() : const Text('Réinitialiser'),
style: TextButton.styleFrom(
foregroundColor: Colors.grey.shade600,
),
@ -281,7 +288,8 @@ Future<void> _loadPointsDeVenteWithDefault() async {
filled: true,
fillColor: Colors.grey.shade50,
),
),),
),
),
const SizedBox(width: 12),
Expanded(
child: TextField(
@ -376,34 +384,38 @@ Future<void> _loadPointsDeVenteWithDefault() async {
size: 20,
),
label: Text(_showOnlyToday
? isMobile ? 'Toutes dates' : 'Toutes les dates'
: isMobile ? 'Aujourd\'hui' : 'Aujourd\'hui seulement'),
? 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
),
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'),
? 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
),
horizontal: isMobile ? 12 : 16, vertical: 8),
),
),
],
@ -422,8 +434,7 @@ Future<void> _loadPointsDeVenteWithDefault() async {
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.date_range,
size: 16,
color: Colors.orange.shade700),
size: 16, color: Colors.orange.shade700),
const SizedBox(width: 4),
Text(
'${DateFormat('dd/MM/yyyy').format(_dateRange!.start)} - ${DateFormat('dd/MM/yyyy').format(_dateRange!.end)}',
@ -442,8 +453,7 @@ Future<void> _loadPointsDeVenteWithDefault() async {
_filterCommandes();
},
child: Icon(Icons.close,
size: 16,
color: Colors.orange.shade700),
size: 16, color: Colors.orange.shade700),
),
],
),
@ -454,10 +464,7 @@ Future<void> _loadPointsDeVenteWithDefault() async {
// Compteur de résultats
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(20),
@ -484,7 +491,8 @@ Future<void> _loadPointsDeVenteWithDefault() async {
Get.bottomSheet(
Container(
padding: const EdgeInsets.all(16),
height: MediaQuery.of(context).size.height * 0.85, // Plus grand sur mobile
height:
MediaQuery.of(context).size.height * 0.85, // Plus grand sur mobile
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
@ -503,7 +511,8 @@ Future<void> _loadPointsDeVenteWithDefault() async {
color: Colors.blue.shade100,
borderRadius: BorderRadius.circular(8),
),
child: Icon(Icons.receipt_long, color: Colors.blue.shade700),
child:
Icon(Icons.receipt_long, color: Colors.blue.shade700),
),
const SizedBox(width: 12),
Text(
@ -533,18 +542,28 @@ Future<void> _loadPointsDeVenteWithDefault() async {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDetailRow('Client', '${client?.nom} ${client?.prenom}', Icons.person),
_buildDetailRow('Date', DateFormat('dd/MM/yyyy à HH:mm').format(commande.dateCommande), Icons.calendar_today),
_buildDetailRow('Client', '${_selectedPointDeVente} ', Icons.person),
_buildDetailRow('Client', '${client?.nom} ${client?.prenom}',
Icons.person),
_buildDetailRow(
'Date',
DateFormat('dd/MM/yyyy à HH:mm')
.format(commande.dateCommande),
Icons.calendar_today),
_buildDetailRow(
'PV', '${_selectedPointDeVente} ', Icons.person),
Row(
children: [
Icon(Icons.assignment, size: 16, color: Colors.grey.shade600),
Icon(Icons.assignment,
size: 16, color: Colors.grey.shade600),
const SizedBox(width: 8),
const Text('Statut: ', style: TextStyle(fontWeight: FontWeight.w500)),
const Text('Statut: ',
style: TextStyle(fontWeight: FontWeight.w500)),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: _getStatutColor(commande.statut).withOpacity(0.2),
color:
_getStatutColor(commande.statut).withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: Text(
@ -618,7 +637,8 @@ Future<void> _loadPointsDeVenteWithDefault() async {
),
title: Text(
detail.produitNom ?? 'Produit inconnu',
style: const TextStyle(fontWeight: FontWeight.w500),
style:
const TextStyle(fontWeight: FontWeight.w500),
),
subtitle: Text(
'${detail.quantite} x ${detail.prixUnitaire.toStringAsFixed(2)} MGA',
@ -643,7 +663,8 @@ Future<void> _loadPointsDeVenteWithDefault() async {
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue.shade800,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14), // Plus compact
padding: const EdgeInsets.symmetric(
vertical: 14), // Plus compact
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
@ -817,7 +838,7 @@ Future<void> _loadPointsDeVenteWithDefault() async {
),
),
Text(
'${_selectedPointDeVente}',
'PV: ${_selectedPointDeVente}',
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14,
@ -846,7 +867,8 @@ Future<void> _loadPointsDeVenteWithDefault() async {
),
const SizedBox(height: 4),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: _getStatutColor(commande.statut).withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
@ -892,7 +914,8 @@ Future<void> _loadPointsDeVenteWithDefault() async {
// Sur mobile, on ajoute un bouton pour afficher les filtres dans un modal
if (isMobile) ...[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
padding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: ElevatedButton.icon(
icon: const Icon(Icons.filter_alt),
label: const Text('Filtres'),
@ -921,7 +944,8 @@ Future<void> _loadPointsDeVenteWithDefault() async {
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(20),

2
lib/config/DatabaseConfig.dart

@ -11,7 +11,7 @@ class DatabaseConfig {
static const String localDatabase = 'guycom';
// Production (public) MySQL settings
static const String prodHost = '185.70.105.157';
static const String prodHost = '102.17.52.31';
static const String prodUsername = 'guycom';
static const String prodPassword = '3iV59wjRdbuXAPR';
static const String prodDatabase = 'guycom';

Loading…
Cancel
Save