ajout panier
This commit is contained in:
parent
fe6b2beed6
commit
a23321274a
@ -6,7 +6,8 @@ class ValidateAddItemsPage extends StatefulWidget {
|
||||
final int commandeId;
|
||||
final String numeroCommande;
|
||||
final List<dynamic> newItems; // Nouveaux articles à ajouter
|
||||
final Map<String, dynamic>? commandeDetails; // Détails de la commande existante
|
||||
final Map<String, dynamic>?
|
||||
commandeDetails; // Détails de la commande existante
|
||||
|
||||
const ValidateAddItemsPage({
|
||||
Key? key,
|
||||
@ -88,14 +89,17 @@ class _ValidateAddItemsPageState extends State<ValidateAddItemsPage> {
|
||||
|
||||
// Calculer le total des articles existants
|
||||
double _calculateExistingItemsTotal() {
|
||||
if (widget.commandeDetails == null || widget.commandeDetails!['items'] == null) {
|
||||
if (widget.commandeDetails == null ||
|
||||
widget.commandeDetails!['items'] == null) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double total = 0.0;
|
||||
for (var item in widget.commandeDetails!['items']) {
|
||||
// Correction: utiliser 'menu_prix_actuel' au lieu de 'menu_prix'
|
||||
double prix = _parsePrice(item['menu_prix_actuel'] ?? item['prix_unitaire']);
|
||||
double prix = _parsePrice(
|
||||
item['menu_prix_actuel'] ?? item['prix_unitaire'],
|
||||
);
|
||||
int quantite = item['quantite'] ?? 1;
|
||||
total += prix * quantite;
|
||||
}
|
||||
@ -112,10 +116,14 @@ class _ValidateAddItemsPageState extends State<ValidateAddItemsPage> {
|
||||
}
|
||||
|
||||
int _getTotalExistingArticles() {
|
||||
if (widget.commandeDetails == null || widget.commandeDetails!['items'] == null) {
|
||||
if (widget.commandeDetails == null ||
|
||||
widget.commandeDetails!['items'] == null) {
|
||||
return 0;
|
||||
}
|
||||
return widget.commandeDetails!['items'].fold(0, (sum, item) => sum + (item['quantite'] ?? 1));
|
||||
return widget.commandeDetails!['items'].fold(
|
||||
0,
|
||||
(sum, item) => sum + (item['quantite'] ?? 1),
|
||||
);
|
||||
}
|
||||
|
||||
void _showConfirmationDialog() {
|
||||
@ -132,7 +140,9 @@ class _ValidateAddItemsPageState extends State<ValidateAddItemsPage> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Êtes-vous sûr de vouloir ajouter ces articles à la commande ?'),
|
||||
Text(
|
||||
'Êtes-vous sûr de vouloir ajouter ces articles à la commande ?',
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
'Récapitulatif:',
|
||||
@ -140,7 +150,9 @@ class _ValidateAddItemsPageState extends State<ValidateAddItemsPage> {
|
||||
),
|
||||
Text('• Commande: ${widget.numeroCommande}'),
|
||||
Text('• Nouveaux articles: ${_getTotalNewArticles()}'),
|
||||
Text('• Nouveau total: ${_calculateGrandTotal().toStringAsFixed(2)} MGA'),
|
||||
Text(
|
||||
'• Nouveau total: ${_calculateGrandTotal().toStringAsFixed(2)} MGA',
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
@ -149,26 +161,30 @@ class _ValidateAddItemsPageState extends State<ValidateAddItemsPage> {
|
||||
child: Text('Annuler', style: TextStyle(color: Colors.grey[600])),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: _isValidating
|
||||
? null
|
||||
: () {
|
||||
Navigator.of(context).pop();
|
||||
_validateAddItems();
|
||||
},
|
||||
onPressed:
|
||||
_isValidating
|
||||
? null
|
||||
: () {
|
||||
Navigator.of(context).pop();
|
||||
_validateAddItems();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green[700],
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: _isValidating
|
||||
? SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||||
),
|
||||
)
|
||||
: Text('Confirmer'),
|
||||
child:
|
||||
_isValidating
|
||||
? SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Colors.white,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Text('Confirmer'),
|
||||
),
|
||||
],
|
||||
);
|
||||
@ -193,36 +209,36 @@ class _ValidateAddItemsPageState extends State<ValidateAddItemsPage> {
|
||||
|
||||
try {
|
||||
// Préparer les données des nouveaux articles
|
||||
// 1. Construire la liste des items sans commande_id à l’intérieur
|
||||
List<Map<String, dynamic>> items = _newCartItems.map((cartItem) {
|
||||
return {
|
||||
'menu_id': cartItem.id,
|
||||
'quantite': cartItem.quantity,
|
||||
'commentaires': cartItem.notes.isNotEmpty ? cartItem.notes : null,
|
||||
};
|
||||
}).toList();
|
||||
// 1. Construire la liste des items sans commande_id à l’intérieur
|
||||
List<Map<String, dynamic>> items =
|
||||
_newCartItems.map((cartItem) {
|
||||
return {
|
||||
'menu_id': cartItem.id,
|
||||
'quantite': cartItem.quantity,
|
||||
'commentaires': cartItem.notes.isNotEmpty ? cartItem.notes : null,
|
||||
};
|
||||
}).toList();
|
||||
|
||||
// 2. Construire le body correctement avec commande_id à la racine
|
||||
final body = {
|
||||
'commande_id': widget.commandeId,
|
||||
'items': items,
|
||||
};
|
||||
// 2. Construire le body correctement avec commande_id à la racine
|
||||
final body = {'commande_id': widget.commandeId, 'items': items};
|
||||
|
||||
print("📦 Données envoyées : ${json.encode(body)}");
|
||||
print("📦 Données envoyées : ${json.encode(body)}");
|
||||
|
||||
// 3. Envoi vers l'API
|
||||
final response = await http.post(
|
||||
Uri.parse('https://restaurant.careeracademy.mg/api/commande-items/add-multiple'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: json.encode(body),
|
||||
);
|
||||
// 3. Envoi vers l'API
|
||||
final response = await http.post(
|
||||
Uri.parse(
|
||||
'https://restaurant.careeracademy.mg/api/commande-items/add-multiple',
|
||||
),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: json.encode(body),
|
||||
);
|
||||
|
||||
// 4. Afficher la réponse backend
|
||||
final responseData = jsonDecode(response.body);
|
||||
print('✅ Réponse backend : $responseData');
|
||||
// 4. Afficher la réponse backend
|
||||
final responseData = jsonDecode(response.body);
|
||||
print('✅ Réponse backend : $responseData');
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final responseData = json.decode(response.body);
|
||||
@ -349,60 +365,59 @@ print('✅ Réponse backend : $responseData');
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
|
||||
|
||||
// Résumé des articles existants
|
||||
if (widget.commandeDetails != null && widget.commandeDetails!['items'] != null) ...[
|
||||
Text(
|
||||
'Articles déjà commandés:',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
...widget.commandeDetails!['items'].map<Widget>((item) {
|
||||
final nom = item['menu_nom'] ?? 'Inconnu';
|
||||
final quantite = item['quantite'] ?? 1;
|
||||
// Correction: utiliser 'menu_prix_actuel' au lieu de 'menu_prix'
|
||||
final prix = _parsePrice(item['menu_prix_actuel'] ?? item['prix_unitaire']);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'$nom x$quantite',
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${(prix * quantite).toStringAsFixed(2)} MGA',
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Sous-total existant:',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
),
|
||||
Text(
|
||||
'${_calculateExistingItemsTotal().toStringAsFixed(2)} MGA',
|
||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(height: 20),
|
||||
],
|
||||
|
||||
// if (widget.commandeDetails != null && widget.commandeDetails!['items'] != null) ...[
|
||||
// Text(
|
||||
// 'Articles déjà commandés:',
|
||||
// style: TextStyle(
|
||||
// fontSize: 16,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// color: Colors.grey[700],
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(height: 8),
|
||||
// ...widget.commandeDetails!['items'].map<Widget>((item) {
|
||||
// final nom = item['menu_nom'] ?? 'Inconnu';
|
||||
// final quantite = item['quantite'] ?? 1;
|
||||
// // Correction: utiliser 'menu_prix_actuel' au lieu de 'menu_prix'
|
||||
// final prix = _parsePrice(item['menu_prix_actuel'] ?? item['prix_unitaire']);
|
||||
|
||||
// return Padding(
|
||||
// padding: const EdgeInsets.symmetric(vertical: 2),
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Expanded(
|
||||
// child: Text(
|
||||
// '$nom x$quantite',
|
||||
// style: TextStyle(fontSize: 14, color: Colors.grey[600]),
|
||||
// ),
|
||||
// ),
|
||||
// Text(
|
||||
// '${(prix * quantite).toStringAsFixed(2)} MGA',
|
||||
// style: TextStyle(fontSize: 14, color: Colors.grey[600]),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }).toList(),
|
||||
// SizedBox(height: 8),
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Text(
|
||||
// 'Sous-total existant:',
|
||||
// style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
// ),
|
||||
// Text(
|
||||
// '${_calculateExistingItemsTotal().toStringAsFixed(2)} MGA',
|
||||
// style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// Divider(height: 20),
|
||||
// ],
|
||||
Text(
|
||||
'Nouveaux articles à ajouter: ${_getTotalNewArticles()}',
|
||||
style: TextStyle(
|
||||
@ -417,152 +432,168 @@ print('✅ Réponse backend : $responseData');
|
||||
|
||||
// Liste des nouveaux articles
|
||||
Expanded(
|
||||
child: _newCartItems.isEmpty
|
||||
? Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.shopping_cart_outlined,
|
||||
size: 80,
|
||||
color: Colors.grey[400],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
'Aucun nouvel article sélectionné',
|
||||
style: TextStyle(fontSize: 18, color: Colors.grey[600]),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: ListView.separated(
|
||||
padding: EdgeInsets.all(16),
|
||||
itemCount: _newCartItems.length,
|
||||
separatorBuilder: (context, index) => SizedBox(height: 12),
|
||||
itemBuilder: (context, index) {
|
||||
final item = _newCartItems[index];
|
||||
return Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: Colors.green[200]!, width: 1),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 2),
|
||||
child:
|
||||
_newCartItems.isEmpty
|
||||
? Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.shopping_cart_outlined,
|
||||
size: 80,
|
||||
color: Colors.grey[400],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
'Aucun nouvel article sélectionné',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.add_circle, color: Colors.green[600], size: 20),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.nom,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: ListView.separated(
|
||||
padding: EdgeInsets.all(16),
|
||||
itemCount: _newCartItems.length,
|
||||
separatorBuilder:
|
||||
(context, index) => SizedBox(height: 12),
|
||||
itemBuilder: (context, index) {
|
||||
final item = _newCartItems[index];
|
||||
return Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: Colors.green[200]!,
|
||||
width: 1,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.add_circle,
|
||||
color: Colors.green[600],
|
||||
size: 20,
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.nom,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => _removeItem(index),
|
||||
icon: Icon(
|
||||
Icons.delete_outline,
|
||||
color: Colors.red,
|
||||
),
|
||||
constraints: BoxConstraints(),
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'${item.prix.toStringAsFixed(2)} MGA l\'unité',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
if (item.notes.isNotEmpty) ...[
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
'Notes: ${item.notes}',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey[600],
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
],
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// Contrôles de quantité
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed:
|
||||
() => _updateQuantity(
|
||||
index,
|
||||
item.quantity - 1,
|
||||
),
|
||||
icon: Icon(Icons.remove),
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: Colors.grey[200],
|
||||
minimumSize: Size(40, 40),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
Text(
|
||||
item.quantity.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
IconButton(
|
||||
onPressed:
|
||||
() => _updateQuantity(
|
||||
index,
|
||||
item.quantity + 1,
|
||||
),
|
||||
icon: Icon(Icons.add),
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: Colors.grey[200],
|
||||
minimumSize: Size(40, 40),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => _removeItem(index),
|
||||
icon: Icon(
|
||||
Icons.delete_outline,
|
||||
color: Colors.red,
|
||||
// Prix total de l'article
|
||||
Text(
|
||||
'${(item.prix * item.quantity).toStringAsFixed(2)} MGA',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.green[700],
|
||||
),
|
||||
),
|
||||
constraints: BoxConstraints(),
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'${item.prix.toStringAsFixed(2)} MGA l\'unité',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
if (item.notes.isNotEmpty) ...[
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
'Notes: ${item.notes}',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey[600],
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// Contrôles de quantité
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => _updateQuantity(
|
||||
index,
|
||||
item.quantity - 1,
|
||||
),
|
||||
icon: Icon(Icons.remove),
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: Colors.grey[200],
|
||||
minimumSize: Size(40, 40),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
Text(
|
||||
item.quantity.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
IconButton(
|
||||
onPressed: () => _updateQuantity(
|
||||
index,
|
||||
item.quantity + 1,
|
||||
),
|
||||
icon: Icon(Icons.add),
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: Colors.grey[200],
|
||||
minimumSize: Size(40, 40),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Prix total de l'article
|
||||
Text(
|
||||
'${(item.prix * item.quantity).toStringAsFixed(2)} MGA',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.green[700],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
// Récapitulatif final
|
||||
@ -577,10 +608,7 @@ print('✅ Réponse backend : $responseData');
|
||||
children: [
|
||||
Text(
|
||||
'Récapitulatif final',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
@ -596,7 +624,10 @@ print('✅ Réponse backend : $responseData');
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Sous-total existant:', style: TextStyle(fontSize: 16)),
|
||||
Text(
|
||||
'Sous-total existant:',
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
'${_calculateExistingItemsTotal().toStringAsFixed(2)} MGA',
|
||||
style: TextStyle(fontSize: 16),
|
||||
@ -607,7 +638,10 @@ print('✅ Réponse backend : $responseData');
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Nouveaux articles:', style: TextStyle(fontSize: 16, color: Colors.green[700])),
|
||||
Text(
|
||||
'Nouveaux articles:',
|
||||
style: TextStyle(fontSize: 16, color: Colors.green[700]),
|
||||
),
|
||||
Text(
|
||||
_getTotalNewArticles().toString(),
|
||||
style: TextStyle(fontSize: 16, color: Colors.green[700]),
|
||||
@ -617,7 +651,10 @@ print('✅ Réponse backend : $responseData');
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Sous-total nouveaux:', style: TextStyle(fontSize: 16, color: Colors.green[700])),
|
||||
Text(
|
||||
'Sous-total nouveaux:',
|
||||
style: TextStyle(fontSize: 16, color: Colors.green[700]),
|
||||
),
|
||||
Text(
|
||||
'${_calculateNewItemsTotal().toStringAsFixed(2)} MGA',
|
||||
style: TextStyle(fontSize: 16, color: Colors.green[700]),
|
||||
@ -651,9 +688,10 @@ print('✅ Réponse backend : $responseData');
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: _newCartItems.isNotEmpty && !_isValidating
|
||||
? _showConfirmationDialog
|
||||
: null,
|
||||
onPressed:
|
||||
_newCartItems.isNotEmpty && !_isValidating
|
||||
? _showConfirmationDialog
|
||||
: null,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green[700],
|
||||
foregroundColor: Colors.white,
|
||||
@ -672,7 +710,9 @@ print('✅ Réponse backend : $responseData');
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
@ -687,7 +727,7 @@ print('✅ Réponse backend : $responseData');
|
||||
Icon(Icons.add_shopping_cart, size: 20),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
_newCartItems.isEmpty
|
||||
_newCartItems.isEmpty
|
||||
? 'Aucun article à ajouter'
|
||||
: 'Ajouter à la commande (${_getTotalNewArticles()})',
|
||||
style: TextStyle(
|
||||
@ -724,4 +764,4 @@ class CartItemModel {
|
||||
required this.quantity,
|
||||
required this.notes,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,8 +140,6 @@ class _OrdersManagementScreenState extends State<OrdersManagementScreen> {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Future<void> updateOrderStatus(
|
||||
Order order,
|
||||
String newStatus, {
|
||||
@ -289,9 +287,6 @@ class _OrdersManagementScreenState extends State<OrdersManagementScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
List<Order> get activeOrders {
|
||||
return orders
|
||||
.where(
|
||||
@ -347,7 +342,6 @@ class _OrdersManagementScreenState extends State<OrdersManagementScreen> {
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
);
|
||||
},
|
||||
@ -356,22 +350,23 @@ class _OrdersManagementScreenState extends State<OrdersManagementScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> updateTableStatus(int tableId, String newStatus) async {
|
||||
const String apiUrl = 'https://restaurant.careeracademy.mg/api/tables'; // ← adapte l’URL si besoin
|
||||
Future<void> updateTableStatus(int tableId, String newStatus) async {
|
||||
const String apiUrl =
|
||||
'https://restaurant.careeracademy.mg/api/tables'; // ← adapte l’URL si besoin
|
||||
|
||||
final response = await http.put(
|
||||
Uri.parse('$apiUrl/$tableId'),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode({'status': newStatus}),
|
||||
);
|
||||
final response = await http.put(
|
||||
Uri.parse('$apiUrl/$tableId'),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode({'status': newStatus}),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
print('Erreur lors de la mise à jour du statut de la table');
|
||||
throw Exception('Erreur: ${response.body}');
|
||||
} else {
|
||||
print('✅ Table $tableId mise à jour en $newStatus');
|
||||
if (response.statusCode != 200) {
|
||||
print('Erreur lors de la mise à jour du statut de la table');
|
||||
throw Exception('Erreur: ${response.body}');
|
||||
} else {
|
||||
print('✅ Table $tableId mise à jour en $newStatus');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -602,44 +597,37 @@ class OrderCard extends StatelessWidget {
|
||||
// Header row
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _getStatusColor(order.statut),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
_getStatusText(order.statut),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: onViewDetails,
|
||||
child: Text(
|
||||
'Table ${order.tableId}',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
if (order.statut == 'en_attente')
|
||||
IconButton(
|
||||
icon: const Icon(Icons.add_circle_outline, size: 20, color: Colors.blue),
|
||||
tooltip: 'Ajouter un article',
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => AddItemsToOrderPage(
|
||||
commandeId: order.id,
|
||||
numeroCommande: order.numero ?? 'Commande #${order.id}',
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _getStatusColor(order.statut),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
_getStatusText(order.statut),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
@ -731,7 +719,8 @@ class OrderCard extends StatelessWidget {
|
||||
order.statut == 'en_preparation')
|
||||
Row(
|
||||
children: [
|
||||
if (order.statut == 'en_attente')
|
||||
if (order.statut == 'en_attente' ||
|
||||
order.statut == 'en_preparation')
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed:
|
||||
@ -741,22 +730,28 @@ class OrderCard extends StatelessWidget {
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => AddItemsToOrderPage(
|
||||
commandId: order.id,
|
||||
commandeId: order.id,
|
||||
numeroCommande: order.numeroCommande,
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.orange,
|
||||
backgroundColor: const Color.fromARGB(
|
||||
255,
|
||||
0,
|
||||
76,
|
||||
255,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'Préparer',
|
||||
style: TextStyle(color: Colors.white, fontSize: 12),
|
||||
child: const Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -860,8 +855,6 @@ class OrderCard extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Updated Order model to include items
|
||||
class Order {
|
||||
final int id;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user