push de 22102025
This commit is contained in:
parent
57efa196b9
commit
bb81798e03
@ -35,28 +35,28 @@ class _CaisseScreenState extends State<CaisseScreen> {
|
||||
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<CaisseScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
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),
|
||||
|
||||
Widget _buildPaymentMethodCard(PaymentMethod method) {
|
||||
final isSelected = selectedPaymentMethod?.id == method.id;
|
||||
// 🟢 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),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// 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<CaisseScreen> {
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selectedPaymentMethod = method;
|
||||
selectedPaymentMethod = method; // 🔹 setState global
|
||||
});
|
||||
},
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
@ -403,9 +493,7 @@ class _CaisseScreenState extends State<CaisseScreen> {
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(width: 16),
|
||||
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -431,24 +519,18 @@ class _CaisseScreenState extends State<CaisseScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
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<CaisseScreen> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Widget _buildPaymentButton() {
|
||||
final canPay = selectedPaymentMethod != null && !isProcessingPayment;
|
||||
|
||||
@ -592,22 +677,23 @@ class _CaisseScreenState extends State<CaisseScreen> {
|
||||
),
|
||||
)
|
||||
: 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),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,13 +421,28 @@ class _ValidateAddItemsPageState extends State<ValidateAddItemsPage> {
|
||||
}
|
||||
|
||||
// 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<dynamic> 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() {
|
||||
|
||||
@ -12,6 +12,7 @@ class _OrderHistoryPageState extends State<OrderHistoryPage>
|
||||
late AnimationController _animationController;
|
||||
List<AnimationController> _cardAnimationControllers = [];
|
||||
List<CommandeData> commandes = [];
|
||||
List<CommandeData> allCommandes = []; // contiendra toutes les commandes
|
||||
bool isLoading = true;
|
||||
String? error;
|
||||
DateTime? _startDate;
|
||||
@ -53,9 +54,8 @@ Future<void> _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<void> _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<void> _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<dynamic> data = [];
|
||||
|
||||
// Gestion selon le format de réponse
|
||||
// Gestion du format de réponse
|
||||
if (responseBody is Map<String, dynamic>) {
|
||||
final dataMap = responseBody['data'] as Map<String, dynamic>?;
|
||||
|
||||
@ -102,7 +100,6 @@ Future<void> _loadCommandes({int page = 1}) async {
|
||||
data = [commandesValue];
|
||||
}
|
||||
|
||||
// Pagination
|
||||
final pagination = dataMap['pagination'] as Map<String, dynamic>?;
|
||||
currentPage = pagination?['currentPage'] ?? page;
|
||||
totalPages = pagination?['totalPages'] ?? (data.length / itemsPerPage).ceil();
|
||||
@ -123,8 +120,7 @@ Future<void> _loadCommandes({int page = 1}) async {
|
||||
try {
|
||||
final item = data[i];
|
||||
if (item is Map<String, dynamic>) {
|
||||
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<void> _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<void> _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<void> _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),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user