diff --git a/lib/pages/caisse_screen.dart b/lib/pages/caisse_screen.dart index c970e78..84ee4db 100644 --- a/lib/pages/caisse_screen.dart +++ b/lib/pages/caisse_screen.dart @@ -35,28 +35,28 @@ class _CaisseScreenState extends State { name: 'MVola', description: 'Paiement mobile MVola', icon: Icons.phone, - color: Color(0xFF4285F4), + color: Color(0xFF28A745), ), const PaymentMethod( id: 'orange_money', name: 'Orange Money', description: 'Paiement mobile Orange Money', icon: Icons.phone, - color: Color(0xFF4285F4), + color: Color(0xFFFF9500), ), const PaymentMethod( id: 'carte', name: 'Carte Bancaire', description: 'Paiement par carte', icon: Icons.credit_card, - color: Color(0xFF28A745), + color: Color(0xFF4285F4), ), const PaymentMethod( id: 'especes', name: 'Espèces', description: 'Paiement en liquide', icon: Icons.attach_money, - color: Color(0xFFFF9500), + color: Color(0xFFFFEB3B), ), ]; @@ -332,28 +332,118 @@ class _CaisseScreenState extends State { ); } - Widget _buildPaymentMethods() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Méthode de paiement', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.black87, + +Widget _buildPaymentSection() { + double montantDonne = 0.0; + double rendu = 0.0; + TextEditingController montantController = TextEditingController(); + + return StatefulBuilder( + builder: (context, setState) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 🔵 Colonne gauche : méthodes de paiement + Expanded( + flex: 1, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Méthode de paiement', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 16), + ...paymentMethods.map((method) { + final isSelected = selectedPaymentMethod?.id == method.id; + return _buildPaymentMethodCard(method, isSelected); // 🔹 plus besoin de StatefulBuilder + }).toList(), + ], ), ), - const SizedBox(height: 16), - ...paymentMethods.map((method) => _buildPaymentMethodCard(method)), - ], - ); - } + const SizedBox(width: 90), + + // 🟢 Colonne droite : saisie montant et rendu + Expanded( + flex: 1, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Montant à payer :', + style: const TextStyle( + fontWeight: FontWeight.bold, fontSize: 16), + ), + const SizedBox(height: 8), + Text( + '${NumberFormat("#,##0.00", "fr_FR").format(commande?.totalTtc ?? 0)} MGA', + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20, + color: Color(0xFF28A745)), + ), + const SizedBox(height: 24), + TextField( + controller: montantController, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + labelText: "Montant donné par le client", + border: OutlineInputBorder(), + ), + onChanged: (value) { + setState(() { + montantDonne = double.tryParse(value) ?? 0.0; + rendu = montantDonne - (commande?.totalTtc ?? 0.0); + }); + }, + ), + const SizedBox(height: 24), + Text( + 'Rendu :', + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + const SizedBox(height: 8), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, vertical: 12), + decoration: BoxDecoration( + color: rendu >= 0 ? Colors.green[50] : Colors.red[50], + borderRadius: BorderRadius.circular(12), + ), + child: Text( + '${rendu >= 0 ? NumberFormat("#,##0.00", "fr_FR").format(rendu) : "0"} MGA', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24, // rendu plus grand + color: rendu >= 0 ? Colors.green : Colors.red, + ), + ), + ), + if (rendu < 0) + const Padding( + padding: EdgeInsets.only(top: 8.0), + child: Text( + "Montant insuffisant", + style: TextStyle(color: Colors.red), + ), + ), + ], + ), + ), + ], + ); + }, + ); +} - Widget _buildPaymentMethodCard(PaymentMethod method) { - final isSelected = selectedPaymentMethod?.id == method.id; + +// Modification de _buildPaymentMethodCard pour accepter setState de la StatefulBuilder +Widget _buildPaymentMethodCard(PaymentMethod method, bool isSelected) { final amount = commande?.totalTtc ?? 0.0; return Container( @@ -363,7 +453,7 @@ class _CaisseScreenState extends State { child: InkWell( onTap: () { setState(() { - selectedPaymentMethod = method; + selectedPaymentMethod = method; // 🔹 setState global }); }, borderRadius: BorderRadius.circular(12), @@ -403,9 +493,7 @@ class _CaisseScreenState extends State { size: 24, ), ), - const SizedBox(width: 16), - Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -431,24 +519,18 @@ class _CaisseScreenState extends State { ], ), ), - - const SizedBox(width: 16), - Icon( isSelected ? Icons.check_circle : Icons.radio_button_unchecked, color: isSelected ? method.color : Colors.white, size: 22, ), - const SizedBox(width: 8), - Text( '${NumberFormat("#,##0.00", "fr_FR").format(amount)} MGA', style: TextStyle( - color: isSelected ? Colors.black87 : Colors.white, - fontSize: 16, - fontWeight: FontWeight.bold, - ), + color: isSelected ? Colors.black87 : Colors.white, + fontSize: 16, + fontWeight: FontWeight.bold), ), ], ), @@ -459,6 +541,9 @@ class _CaisseScreenState extends State { } + + + Widget _buildPaymentButton() { final canPay = selectedPaymentMethod != null && !isProcessingPayment; @@ -592,22 +677,23 @@ class _CaisseScreenState extends State { ), ) : SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildCommandeHeader(), + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildCommandeHeader(), - const SizedBox(height: 32), + const SizedBox(height: 32), - _buildPaymentMethods(), + _buildPaymentSection(), // <-- ici on met le widget avec 2 colonnes - _buildPaymentButton(), + _buildPaymentButton(), + + const SizedBox(height: 20), + ], + ), +), - const SizedBox(height: 20), - ], - ), - ), ); } } diff --git a/lib/pages/commande_item_validation.dart b/lib/pages/commande_item_validation.dart index bb0b3c6..9752200 100644 --- a/lib/pages/commande_item_validation.dart +++ b/lib/pages/commande_item_validation.dart @@ -421,13 +421,28 @@ class _ValidateAddItemsPageState extends State { } // Méthode pour naviguer avec succès - void _navigateBackWithSuccess() { - Navigator.of(context).pop({ - 'success': true, - 'shouldReload': true, - 'message': 'Articles ajoutés avec succès à la commande ${widget.numeroCommande}' - }); - } +void _navigateBackWithSuccess() { + // Fermer toutes les pages précédentes et rediriger vers OrdersManagementScreen + Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute( + builder: (context) => OrdersManagementScreen(), + ), + (Route route) => false, // Supprime toutes les pages précédentes + ); + + // Optionnel : petit délai pour laisser le temps à la navigation + Future.delayed(Duration(milliseconds: 300), () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Articles ajoutés avec succès à la commande ${widget.numeroCommande}', + ), + backgroundColor: Colors.green[700], + ), + ); + }); +} + // Ancien dialog de succès (sans impression) - garde comme fallback void _showSuccessDialog() { diff --git a/lib/pages/historique_commande.dart b/lib/pages/historique_commande.dart index cfd5c03..1bbad20 100644 --- a/lib/pages/historique_commande.dart +++ b/lib/pages/historique_commande.dart @@ -12,6 +12,7 @@ class _OrderHistoryPageState extends State late AnimationController _animationController; List _cardAnimationControllers = []; List commandes = []; + List allCommandes = []; // contiendra toutes les commandes bool isLoading = true; String? error; DateTime? _startDate; @@ -53,9 +54,8 @@ Future _loadCommandes({int page = 1}) async { 'limit': itemsPerPage.toString(), }; - // ✅ CORRECTION : Envoyer la date en format ISO avec fuseau horaire UTC + // Gestion des filtres de date if (_startDate != null) { - // Début de journée en UTC (00:00:00) final startUtc = DateTime.utc( _startDate!.year, _startDate!.month, @@ -65,9 +65,8 @@ Future _loadCommandes({int page = 1}) async { queryParams['date_start'] = startUtc.toIso8601String(); print('📅 Date début (UTC): ${startUtc.toIso8601String()}'); } - + if (_endDate != null) { - // Fin de journée en UTC (23:59:59) final endUtc = DateTime.utc( _endDate!.year, _endDate!.month, @@ -78,19 +77,18 @@ Future _loadCommandes({int page = 1}) async { print('📅 Date fin (UTC): ${endUtc.toIso8601String()}'); } - // Debug: Afficher l'URL complète + // URL complète final uri = Uri.parse('$baseUrl/api/commandes').replace(queryParameters: queryParams); print('🌐 URL appelée: $uri'); final response = await http.get(uri, headers: _headers); - print('📡 Status code: ${response.statusCode}'); if (response.statusCode == 200) { final dynamic responseBody = json.decode(response.body); List data = []; - // Gestion selon le format de réponse + // Gestion du format de réponse if (responseBody is Map) { final dataMap = responseBody['data'] as Map?; @@ -102,7 +100,6 @@ Future _loadCommandes({int page = 1}) async { data = [commandesValue]; } - // Pagination final pagination = dataMap['pagination'] as Map?; currentPage = pagination?['currentPage'] ?? page; totalPages = pagination?['totalPages'] ?? (data.length / itemsPerPage).ceil(); @@ -123,8 +120,7 @@ Future _loadCommandes({int page = 1}) async { try { final item = data[i]; if (item is Map) { - final commandeData = CommandeData.fromJson(item); - parsedCommandes.add(commandeData); + parsedCommandes.add(CommandeData.fromJson(item)); } else { print('Item $i invalide: ${item.runtimeType}'); } @@ -136,8 +132,10 @@ Future _loadCommandes({int page = 1}) async { print('✅ ${parsedCommandes.length} commandes chargées'); + // ⚡ Mise à jour du state avec toutes les commandes setState(() { - commandes = parsedCommandes; + allCommandes = parsedCommandes; // toutes les commandes + commandes = parsedCommandes; // commandes affichées (filtrage frontend possible) isLoading = false; }); @@ -160,7 +158,34 @@ Future _loadCommandes({int page = 1}) async { }); } } +void _filterByDate() { + if (_startDate == null && _endDate == null) { + setState(() { + commandes = allCommandes; + currentPage = 1; + totalItems = commandes.length; + totalPages = (totalItems / itemsPerPage).ceil(); + }); + return; + } + setState(() { + commandes = allCommandes.where((c) { + final date = c.datePaiement ?? c.dateCommande; + if (date == null) return false; + + final start = _startDate ?? DateTime(2000); + // Fin de journée pour inclure la date complète + final end = _endDate?.add(Duration(days: 1)).subtract(Duration(milliseconds: 1)) ?? DateTime(2100); + + return !date.isBefore(start) && !date.isAfter(end); + }).toList(); + + currentPage = 1; + totalItems = commandes.length; + totalPages = (totalItems / itemsPerPage).ceil(); + }); +} Future _selectDate(BuildContext context, bool isStart) async { final DateTime? picked = await showDatePicker( @@ -337,7 +362,7 @@ Widget _buildHeader() { ), SizedBox(width: 5), ElevatedButton( - onPressed: () => _loadCommandes(page: 1), + onPressed: () => _filterByDate(), child: Text('Filtrer'), style: ElevatedButton.styleFrom( backgroundColor: Colors.orange, @@ -364,23 +389,17 @@ Widget _buildHeader() { ), ), SizedBox(width: 5), - ElevatedButton( - onPressed: () { - final today = DateTime.now(); - setState(() { - _startDate = DateTime(today.year, today.month, today.day); - _endDate = DateTime(today.year, today.month, today.day, 23, 59, 59); - }); - _loadCommandes(page: 1); - }, - child: Text('Aujourd’hui'), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.blue, - foregroundColor: Colors.white, - padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), - textStyle: TextStyle(fontSize: 10), - ), - ), + ElevatedButton( + onPressed: () { + final today = DateTime.now(); + setState(() { + _startDate = DateTime(today.year, today.month, today.day); + _endDate = DateTime(today.year, today.month, today.day, 23, 59, 59); + _filterByDate(); // filtre local sur toutes les commandes déjà chargées + }); + }, + child: Text('Aujourd’hui'), + ), ], ), SizedBox(height: 4),