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
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.timeZoneName
|
|
),
|
|
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),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|