You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

403 lines
14 KiB

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:youmazgestion/Models/client.dart';
import 'package:youmazgestion/Models/produit.dart';
import 'package:youmazgestion/Services/stock_managementDatabase.dart';
class HistoriquePage extends StatefulWidget {
const HistoriquePage({super.key});
@override
_HistoriquePageState createState() => _HistoriquePageState();
}
class _HistoriquePageState extends State<HistoriquePage> {
final AppDatabase _appDatabase = AppDatabase.instance;
List<Commande> _commandes = [];
bool _isLoading = true;
DateTimeRange? _dateRange;
final TextEditingController _searchController = TextEditingController();
@override
void initState() {
super.initState();
_loadCommandes();
}
Future<void> _loadCommandes() async {
setState(() {
_isLoading = true;
});
try {
final commandes = await _appDatabase.getCommandes();
setState(() {
_commandes = commandes;
_isLoading = false;
});
} catch (e) {
setState(() {
_isLoading = false;
});
Get.snackbar(
'Erreur',
'Impossible de charger les commandes: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
}
}
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;
});
_filterCommandes();
}
}
void _filterCommandes() {
final searchText = _searchController.text.toLowerCase();
setState(() {
_isLoading = true;
});
_appDatabase.getCommandes().then((commandes) {
List<Commande> filtered = commandes;
// Filtre par date
if (_dateRange != null) {
filtered = filtered.where((commande) {
final date = commande.dateCommande;
return date.isAfter(_dateRange!.start) &&
date.isBefore(_dateRange!.end.add(const Duration(days: 1)));
}).toList();
}
// Filtre par recherche
if (searchText.isNotEmpty) {
filtered = filtered.where((commande) {
return commande.clientNom!.toLowerCase().contains(searchText) ||
commande.clientPrenom!.toLowerCase().contains(searchText) ||
commande.id.toString().contains(searchText);
}).toList();
}
setState(() {
_commandes = filtered;
_isLoading = false;
});
});
}
void _showCommandeDetails(Commande commande) async {
final details = await _appDatabase.getDetailsCommande(commande.id!);
final client = await _appDatabase.getClientById(commande.clientId);
Get.bottomSheet(
Container(
padding: const EdgeInsets.all(16),
height: MediaQuery.of(context).size.height * 0.7,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Commande #${commande.id}',
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () => Get.back(),
),
],
),
const Divider(),
Text(
'Client: ${client?.nom} ${client?.prenom}',
style: const TextStyle(fontSize: 16),
),
Text(
'Date: ${commande.dateCommande}',
style: const TextStyle(fontSize: 16),
),
Text(
'Statut: ${_getStatutText(commande.statut)}',
style: TextStyle(
fontSize: 16,
color: _getStatutColor(commande.statut),
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
const Text(
'Articles:',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
Expanded(
child: ListView.builder(
itemCount: details.length,
itemBuilder: (context, index) {
final detail = details[index];
return ListTile(
leading: const Icon(Icons.shopping_bag),
title: Text(detail.produitNom ?? 'Produit inconnu'),
subtitle: Text(
'${detail.quantite} x ${detail.prixUnitaire.toStringAsFixed(2)} DA',
),
trailing: Text(
'${detail.sousTotal.toStringAsFixed(2)} DA',
style: const TextStyle(fontWeight: FontWeight.bold),
),
);
},
),
),
const Divider(),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Total:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
Text(
'${commande.montantTotal.toStringAsFixed(2)} DA',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
],
),
),
if (commande.statut == StatutCommande.enAttente ||
commande.statut == StatutCommande.enPreparation)
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue.shade800,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
),
onPressed: () => _updateStatutCommande(commande.id!),
child: const Text('Marquer comme livrée'),
),
],
),
),
);
}
String _getStatutText(StatutCommande statut) {
switch (statut) {
case StatutCommande.enAttente:
return 'En attente';
case StatutCommande.confirmee:
return 'Confirmée';
case StatutCommande.enPreparation:
return 'En préparation';
case StatutCommande.livree:
return 'Livrée';
case StatutCommande.annulee:
return 'Annulée';
default:
return 'Inconnu';
}
}
Color _getStatutColor(StatutCommande statut) {
switch (statut) {
case StatutCommande.enAttente:
return Colors.orange;
case StatutCommande.confirmee:
return Colors.blue;
case StatutCommande.enPreparation:
return Colors.purple;
case StatutCommande.livree:
return Colors.green;
case StatutCommande.annulee:
return Colors.red;
default:
return Colors.grey;
}
}
Future<void> _updateStatutCommande(int commandeId) async {
try {
await _appDatabase.updateStatutCommande(
commandeId, StatutCommande.livree);
Get.back(); // Ferme le bottom sheet
_loadCommandes();
Get.snackbar(
'Succès',
'Statut de la commande mis à jour',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.green,
colorText: Colors.white,
);
} catch (e) {
Get.snackbar(
'Erreur',
'Impossible de mettre à jour le statut: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Historique des Commandes'),
actions: [
IconButton(
icon: const Icon(Icons.refresh),
onPressed: _loadCommandes,
),
],
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(8),
child: Row(
children: [
Expanded(
child: TextField(
controller: _searchController,
decoration: InputDecoration(
labelText: 'Rechercher',
prefixIcon: const Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
_searchController.clear();
_filterCommandes();
},
),
),
onChanged: (value) => _filterCommandes(),
),
),
IconButton(
icon: const Icon(Icons.date_range),
onPressed: () => _selectDateRange(context),
),
],
),
),
if (_dateRange != null)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
DateFormat('dd/MM/yyyy').format(_dateRange!.start),
style: const TextStyle(fontWeight: FontWeight.bold),
),
const Text(' - '),
Text(
DateFormat('dd/MM/yyyy').format(_dateRange!.end),
style: const TextStyle(fontWeight: FontWeight.bold),
),
IconButton(
icon: const Icon(Icons.close, size: 18),
onPressed: () {
setState(() {
_dateRange = null;
});
_filterCommandes();
},
),
],
),
),
Expanded(
child: _isLoading
? const Center(child: CircularProgressIndicator())
: _commandes.isEmpty
? const Center(
child: Text('Aucune commande trouvée'),
)
: ListView.builder(
itemCount: _commandes.length,
itemBuilder: (context, index) {
final commande = _commandes[index];
return Card(
margin: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
child: ListTile(
leading: const Icon(Icons.shopping_cart),
title: Text(
'Commande #${commande.id} - ${commande.clientNom} ${commande.clientPrenom}'),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
commande.dateCommande as String
),
Text(
'${commande.montantTotal.toStringAsFixed(2)} DA',
style: const TextStyle(
fontWeight: FontWeight.bold),
),
],
),
trailing: Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: _getStatutColor(commande.statut)
.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: Text(
_getStatutText(commande.statut),
style: TextStyle(
color: _getStatutColor(commande.statut),
fontWeight: FontWeight.bold,
),
),
),
onTap: () => _showCommandeDetails(commande),
),
);
},
),
),
],
),
);
}
}