Browse Source

fixed

28062025_02
ASUS 5 months ago
parent
commit
6bc8373cad
  1. 2
      android/app/src/main/AndroidManifest.xml
  2. 18
      lib/Services/stock_managementDatabase.dart
  3. 6
      lib/Views/DemandeTransfert.dart
  4. 536
      lib/Views/HandleProduct.dart
  5. 3797
      lib/Views/commandManagement.dart
  6. 338
      lib/Views/newCommand.dart
  7. 6
      lib/config/DatabaseConfig.dart

2
android/app/src/main/AndroidManifest.xml

@ -2,7 +2,7 @@
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" /> <uses-permission android:name="android.permission.FLASHLIGHT" />
<application <application
android:label="my_app" android:label="GUYCOM"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity

18
lib/Services/stock_managementDatabase.dart

@ -2579,6 +2579,22 @@ Future<int> validerTransfert(int demandeId, int validateurId) async {
final sourceId = fields['point_de_vente_source_id'] as int; final sourceId = fields['point_de_vente_source_id'] as int;
final destinationId = fields['point_de_vente_destination_id'] as int; final destinationId = fields['point_de_vente_destination_id'] as int;
final getpointDeventeSource = await db.query(
'Select point_de_vente_source_id FROM demandes_transfert WHERE id=?',[demandeId]
);
final getpointDeventeDest = await db.query(
'Select point_de_vente_destination_id FROM demandes_transfert WHERE id=?',[demandeId]
);
final getpointDeventeSourceValue = getpointDeventeSource.first.fields['point_de_vente_source_id'];
final getpointDeventedestValue = getpointDeventeDest.first.fields['point_de_vente_destination_id'];
if(getpointDeventeSourceValue==getpointDeventedestValue){
await db.query('update products set point_de_vente_id=? where id = ?',[getpointDeventedestValue,produitId]);
}else{
// 2. Vérifier le stock source // 2. Vérifier le stock source
final stockSource = await db.query( final stockSource = await db.query(
'SELECT stock FROM products WHERE id = ? AND point_de_vente_id = ? FOR UPDATE', 'SELECT stock FROM products WHERE id = ? AND point_de_vente_id = ? FOR UPDATE',
@ -2646,7 +2662,7 @@ Future<int> validerTransfert(int demandeId, int validateurId) async {
null, // IMEI doit être unique donc on ne le copie pas null, // IMEI doit être unique donc on ne le copie pas
]); ]);
} }
}
// 5. Mettre à jour le statut de la demande // 5. Mettre à jour le statut de la demande
await db.query(''' await db.query('''
UPDATE demandes_transfert UPDATE demandes_transfert

6
lib/Views/DemandeTransfert.dart

@ -205,7 +205,7 @@ class _GestionTransfertsPageState extends State<GestionTransfertsPage> with Tick
), ),
Text('Référence: ${demande['produit_reference']}'), Text('Référence: ${demande['produit_reference']}'),
Text('Quantité: ${demande['quantite']}'), Text('Quantité: ${demande['quantite']}'),
Text('De: ${demande['point_vente_source']}'), Text(demande['point_vente_source'] == demande['point_vente_destination']?'De: Non specifier' : 'De: ${demande['point_vente_source']}'),
Text('Vers: ${demande['point_vente_destination']}'), Text('Vers: ${demande['point_vente_destination']}'),
Text( Text(
'Stock disponible: $stockDisponible', 'Stock disponible: $stockDisponible',
@ -602,7 +602,7 @@ class _GestionTransfertsPageState extends State<GestionTransfertsPage> with Tick
statutIcon = Icons.check_circle; statutIcon = Icons.check_circle;
statutText = 'Validée'; statutText = 'Validée';
break; break;
case 'rejetee': case 'refusee':
statutColor = Colors.red; statutColor = Colors.red;
statutIcon = Icons.cancel; statutIcon = Icons.cancel;
statutText = 'Rejetée'; statutText = 'Rejetée';
@ -695,7 +695,7 @@ class _GestionTransfertsPageState extends State<GestionTransfertsPage> with Tick
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: Text( child: Text(
'${demande['point_vente_source'] ?? 'N/A'}', demande['point_vente_source']==demande['point_vente_destination']?"Non specifier" : '${demande['point_vente_source'] ?? 'N/A'}',
style: const TextStyle(fontWeight: FontWeight.w500), style: const TextStyle(fontWeight: FontWeight.w500),
), ),
), ),

536
lib/Views/HandleProduct.dart

@ -26,6 +26,7 @@ class ProductManagementPage extends StatefulWidget {
class _ProductManagementPageState extends State<ProductManagementPage> { class _ProductManagementPageState extends State<ProductManagementPage> {
final AppDatabase _productDatabase = AppDatabase.instance; final AppDatabase _productDatabase = AppDatabase.instance;
final AppDatabase _appDatabase = AppDatabase.instance;
final UserController _userController = Get.find<UserController>(); final UserController _userController = Get.find<UserController>();
List<Product> _products = []; List<Product> _products = [];
@ -99,6 +100,494 @@ bool _isUserSuperAdmin() {
bool autoGenerateReference = true; bool autoGenerateReference = true;
bool showAddNewPoint = false; bool showAddNewPoint = false;
// 🎨 Widget pour les cartes d'information
Widget _buildInfoCard(String label, String value, IconData icon, Color color) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: color.withOpacity(0.3)),
),
child: Column(
children: [
Icon(icon, color: color, size: 20),
const SizedBox(height: 4),
Text(
label,
style: TextStyle(
fontSize: 10,
color: Colors.grey.shade600,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
),
Text(
value,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: color,
),
textAlign: TextAlign.center,
),
],
),
);
}
// 🎨 Widget pour les étapes de transfert
Widget _buildTransferStep(String label, String pointDeVente, IconData icon, Color color) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: color.withOpacity(0.3)),
),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(6),
),
child: Icon(icon, color: color, size: 16),
),
const SizedBox(height: 6),
Text(
label,
style: TextStyle(
fontSize: 10,
color: Colors.grey.shade600,
fontWeight: FontWeight.bold,
),
),
Text(
pointDeVente,
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w600,
color: color,
),
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
);
}
// 🎨 INTERFACE AMÉLIORÉE: Dialog moderne pour demande de transfert
Future<void> _showDemandeTransfertDialog(Product product) async {
final quantiteController = TextEditingController(text: '1');
final notesController = TextEditingController();
final _formKey = GlobalKey<FormState>();
// Récupérer les infos du point de vente source
final pointDeVenteSource = await _appDatabase.getPointDeVenteNomById(product.pointDeVenteId ?? 0);
final pointDeVenteDestination = await _appDatabase.getPointDeVenteNomById(_userController.pointDeVenteId);
await showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
contentPadding: EdgeInsets.zero,
content: Container(
width: 400,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// En-tête avec design moderne
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue.shade600, Colors.blue.shade700],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
child: Column(
children: [
Icon(
Icons.swap_horizontal_circle,
size: 48,
color: Colors.white,
),
const SizedBox(height: 8),
Text(
'Demande de transfert',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
'Transférer un produit entre points de vente',
style: TextStyle(
fontSize: 14,
color: Colors.white.withOpacity(0.9),
),
),
],
),
),
// Contenu principal
Padding(
padding: const EdgeInsets.all(20),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Informations du produit
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey.shade200),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue.shade100,
borderRadius: BorderRadius.circular(8),
),
child: Icon(
Icons.inventory_2,
color: Colors.blue.shade700,
size: 20,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Produit à transférer',
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade600,
fontWeight: FontWeight.w500,
),
),
Text(
product.name,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: _buildInfoCard(
'Prix unitaire',
'${product.price.toStringAsFixed(2)} MGA',
Icons.attach_money,
Colors.green,
),
),
const SizedBox(width: 8),
Expanded(
child: _buildInfoCard(
'Stock disponible',
'${product.stock ?? 0}',
Icons.inventory,
product.stock != null && product.stock! > 0
? Colors.green
: Colors.red,
),
),
],
),
if (product.reference != null && product.reference!.isNotEmpty) ...[
const SizedBox(height: 8),
Text(
'Référence: ${product.reference}',
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade600,
fontFamily: 'monospace',
),
),
],
],
),
),
const SizedBox(height: 20),
// Informations de transfert
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.orange.shade50,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.orange.shade200),
),
child: Column(
children: [
Row(
children: [
Icon(Icons.arrow_forward, color: Colors.orange.shade700),
const SizedBox(width: 8),
Text(
'Informations de transfert',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.orange.shade700,
),
),
],
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: _buildTransferStep(
'DE',
pointDeVenteSource ?? 'Chargement...',
Icons.store_outlined,
Colors.red.shade600,
),
),
Container(
margin: const EdgeInsets.symmetric(horizontal: 8),
child: Icon(
Icons.arrow_forward,
color: Colors.orange.shade700,
size: 24,
),
),
Expanded(
child: _buildTransferStep(
'VERS',
pointDeVenteDestination ?? 'Chargement...',
Icons.store,
Colors.green.shade600,
),
),
],
),
],
),
),
const SizedBox(height: 20),
// Champ quantité avec design amélioré
Text(
'Quantité à transférer',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.grey.shade700,
),
),
const SizedBox(height: 8),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey.shade300),
),
child: Row(
children: [
IconButton(
onPressed: () {
int currentQty = int.tryParse(quantiteController.text) ?? 1;
if (currentQty > 1) {
quantiteController.text = (currentQty - 1).toString();
}
},
icon: Icon(Icons.remove, color: Colors.grey.shade600),
),
Expanded(
child: TextFormField(
controller: quantiteController,
decoration: const InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 16),
hintText: 'Quantité',
),
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez entrer une quantité';
}
final qty = int.tryParse(value) ?? 0;
if (qty <= 0) {
return 'Quantité invalide';
}
if (product.stock != null && qty > product.stock!) {
return 'Quantité supérieure au stock disponible';
}
return null;
},
),
),
IconButton(
onPressed: () {
int currentQty = int.tryParse(quantiteController.text) ?? 1;
int maxStock = product.stock ?? 999;
if (currentQty < maxStock) {
quantiteController.text = (currentQty + 1).toString();
}
},
icon: Icon(Icons.add, color: Colors.grey.shade600),
),
],
),
),
// Boutons d'action avec design moderne
Row(
children: [
Expanded(
child: TextButton(
onPressed: () => Navigator.pop(context),
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: BorderSide(color: Colors.grey.shade300),
),
),
child: Text(
'Annuler',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.grey.shade700,
),
),
),
),
const SizedBox(width: 12),
Expanded(
flex: 2,
child: ElevatedButton.icon(
onPressed: () async {
if (!_formKey.currentState!.validate()) return;
final qty = int.tryParse(quantiteController.text) ?? 0;
if (qty <= 0) {
Get.snackbar(
'Erreur',
'Quantité invalide',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
return;
}
try {
setState(() => _isLoading = true);
Navigator.pop(context);
await _appDatabase.createDemandeTransfert(
produitId: product.id!,
pointDeVenteSourceId: product.pointDeVenteId!,
pointDeVenteDestinationId: _userController.pointDeVenteId,
demandeurId: _userController.userId,
quantite: qty,
notes: notesController.text.isNotEmpty
? notesController.text
: 'Demande de transfert depuis l\'application mobile',
);
Get.snackbar(
'Demande envoyée ✅',
'Votre demande de transfert de $qty unité(s) a été enregistrée et sera traitée prochainement.',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.green,
colorText: Colors.white,
duration: const Duration(seconds: 4),
icon: const Icon(Icons.check_circle, color: Colors.white),
);
} catch (e) {
Get.snackbar(
'Erreur',
'Impossible d\'envoyer la demande: ${e.toString()}',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
duration: const Duration(seconds: 4),
);
} finally {
setState(() => _isLoading = false);
}
},
icon: const Icon(Icons.send, color: Colors.white),
label: const Text(
'Envoyer la demande',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue.shade600,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 2,
),
),
),
],
),
],
),
),
),
],
),
),
),
),
);
}
// Fonction pour mettre à jour le QR preview // Fonction pour mettre à jour le QR preview
void updateQrPreview() { void updateQrPreview() {
if (nameController.text.isNotEmpty) { if (nameController.text.isNotEmpty) {
@ -1253,25 +1742,32 @@ bool _isUserSuperAdmin() {
} }
// Assigner le point de vente de l'utilisateur au produit // Assigner le point de vente de l'utilisateur au produit
final updatedProduct = Product( // final updatedProduct = Product(
id: foundProduct.id, // id: foundProduct.id,
name: foundProduct.name, // name: foundProduct.name,
price: foundProduct.price, // price: foundProduct.price,
image: foundProduct.image, // image: foundProduct.image,
category: foundProduct.category, // category: foundProduct.category,
description: foundProduct.description, // description: foundProduct.description,
stock: foundProduct.stock, // stock: foundProduct.stock,
qrCode: foundProduct.qrCode, // qrCode: foundProduct.qrCode,
reference: foundProduct.reference, // reference: foundProduct.reference,
marque: foundProduct.marque, // marque: foundProduct.marque,
ram: foundProduct.ram, // ram: foundProduct.ram,
memoireInterne: foundProduct.memoireInterne, // memoireInterne: foundProduct.memoireInterne,
imei: foundProduct.imei, // imei: foundProduct.imei,
pointDeVenteId: // pointDeVenteId:
_userController.pointDeVenteId, // Nouveau point de vente // _userController.pointDeVenteId, // Nouveau point de vente
); // );
await _appDatabase.createDemandeTransfert(
await _productDatabase.updateProduct(updatedProduct); produitId: foundProduct.id!,
pointDeVenteSourceId: _userController.pointDeVenteId,
pointDeVenteDestinationId: _userController.pointDeVenteId,
demandeurId: _userController.userId,
quantite: foundProduct.stock,
notes: 'produit non assigner',
);
// await _productDatabase.updateProduct(updatedProduct);
// Recharger les produits pour refléter les changements // Recharger les produits pour refléter les changements
_loadProducts(); _loadProducts();
@ -1311,7 +1807,7 @@ bool _isUserSuperAdmin() {
child: Icon(Icons.check_circle, color: Colors.green.shade700), child: Icon(Icons.check_circle, color: Colors.green.shade700),
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
const Expanded(child: Text('Attribution réussie !')), const Expanded(child: Text( 'demande attribution réussie en attente de validation!')),
], ],
), ),
content: Column( content: Column(

3797
lib/Views/commandManagement.dart

File diff suppressed because it is too large

338
lib/Views/newCommand.dart

@ -608,99 +608,291 @@ void _modifierQuantite(int productId, int nouvelleQuantite) {
} }
void _showProductFoundAndAddedDialog(Product product, int newQuantity) { void _showProductFoundAndAddedDialog(Product product, int newQuantity) {
Get.dialog( final isProduitCommandable = _isProduitCommandable(product);
AlertDialog( final canRequestTransfer = product.stock != null && product.stock! >= 1;
title: Row(
Get.dialog(
Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Container(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [ children: [
// Header avec icône de succès
Container( Container(
padding: const EdgeInsets.all(8), width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.green.shade100, color: Colors.green.shade50,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.green.shade200),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.green.shade100,
shape: BoxShape.circle,
),
child: Icon(
Icons.check_circle,
color: Colors.green.shade700,
size: 24,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Produit identifié !',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
Text(
'Ajouté au panier avec succès',
style: TextStyle(
fontSize: 12,
color: Colors.green.shade700,
fontWeight: FontWeight.w500,
),
),
],
),
),
],
), ),
child: Icon(Icons.check_circle, color: Colors.green.shade700),
), ),
const SizedBox(width: 12),
const Expanded(child: Text('Produit identifié et ajouté !')), const SizedBox(height: 20),
],
), // Informations du produit
content: Column( Container(
mainAxisSize: MainAxisSize.min, width: double.infinity,
crossAxisAlignment: CrossAxisAlignment.start, padding: const EdgeInsets.all(16),
children: [ decoration: BoxDecoration(
Text( color: Colors.grey.shade50,
product.name, borderRadius: BorderRadius.circular(12),
style: const TextStyle( border: Border.all(color: Colors.grey.shade200),
fontSize: 16, ),
fontWeight: FontWeight.bold, child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
product.name,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 12),
// Détails du produit en grille
_buildProductDetailRow('Prix', '${product.price.toStringAsFixed(2)} MGA'),
_buildProductDetailRow('Quantité ajoutée', '$newQuantity'),
if (product.imei != null && product.imei!.isNotEmpty)
_buildProductDetailRow('IMEI', product.imei!),
if (product.reference != null && product.reference!.isNotEmpty)
_buildProductDetailRow('Référence', product.reference!),
if (product.stock != null)
_buildProductDetailRow('Stock restant', '${product.stock! - newQuantity}'),
],
), ),
), ),
const SizedBox(height: 8),
if (product.imei != null && product.imei!.isNotEmpty) const SizedBox(height: 20),
Text('IMEI: ${product.imei}'),
if (product.reference != null && product.reference!.isNotEmpty) // Badge identification automatique
Text('Référence: ${product.reference}'),
Text('Prix: ${product.price.toStringAsFixed(2)} MGA'),
Text('Quantité dans le panier: $newQuantity'),
if (product.stock != null)
Text('Stock restant: ${product.stock! - newQuantity}'),
const SizedBox(height: 12),
Container( Container(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.green.shade50, color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.blue.shade200),
), ),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon(Icons.auto_awesome, Icon(Icons.auto_awesome,
color: Colors.green.shade700, size: 16), color: Colors.blue.shade700, size: 16),
const SizedBox(width: 8), const SizedBox(width: 6),
const Expanded( Text(
child: Text( 'Identifié automatiquement',
'Produit identifié automatiquement', style: TextStyle(
style: TextStyle( fontSize: 12,
fontSize: 12, fontWeight: FontWeight.w600,
fontWeight: FontWeight.w500, color: Colors.blue.shade700,
),
), ),
), ),
], ],
), ),
), ),
const SizedBox(height: 24),
// Boutons d'action redessinés
Column(
children: [
// Bouton principal selon les permissions
SizedBox(
width: double.infinity,
height: 48,
child: (!isProduitCommandable && !_isUserSuperAdmin())
? ElevatedButton.icon(
onPressed: canRequestTransfer
? () {
Get.back();
_showDemandeTransfertDialog(product);
}
: () {
Get.snackbar(
'Stock insuffisant',
'Impossible de demander un transfert : produit en rupture de stock',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.orange.shade600,
colorText: Colors.white,
margin: const EdgeInsets.all(16),
);
},
icon: const Icon(Icons.swap_horiz, size: 20),
label: const Text(
'Demander un transfert',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
),
style: ElevatedButton.styleFrom(
backgroundColor: canRequestTransfer
? Colors.orange.shade600
: Colors.grey.shade400,
foregroundColor: Colors.white,
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
)
: ElevatedButton.icon(
onPressed: () {
_ajouterAuPanier(product, 1);
Get.back();
_showCartBottomSheet();
},
icon: const Icon(Icons.shopping_cart, size: 20),
label: const Text(
'Voir le panier',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green.shade600,
foregroundColor: Colors.white,
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
),
const SizedBox(height: 12),
// Boutons secondaires
Row(
children: [
// Continuer
Expanded(
child: SizedBox(
height: 44,
child: OutlinedButton.icon(
onPressed: () => Get.back(),
icon: const Icon(Icons.close, size: 18),
label: const Text('Continuer'),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.grey.shade700,
side: BorderSide(color: Colors.grey.shade300),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
),
),
const SizedBox(width: 12),
// Scanner encore
Expanded(
child: SizedBox(
height: 44,
child: ElevatedButton.icon(
onPressed: () {
Get.back();
_startAutomaticScanning();
},
icon: const Icon(Icons.qr_code_scanner, size: 18),
label: const Text('Scanner'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue.shade600,
foregroundColor: Colors.white,
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
),
),
],
),
],
),
], ],
), ),
actions: [ ),
TextButton( ),
onPressed: () => Get.back(), );
child: const Text('Continuer'), }
),
ElevatedButton( // Widget helper pour les détails du produit
onPressed: () { Widget _buildProductDetailRow(String label, String value) {
Get.back(); return Padding(
_showCartBottomSheet(); padding: const EdgeInsets.only(bottom: 8),
}, child: Row(
style: ElevatedButton.styleFrom( crossAxisAlignment: CrossAxisAlignment.start,
backgroundColor: Colors.green.shade700, children: [
foregroundColor: Colors.white, SizedBox(
width: 100,
child: Text(
'$label:',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.grey.shade600,
), ),
child: const Text('Voir le panier'),
), ),
ElevatedButton( ),
onPressed: () { Expanded(
Get.back(); child: Text(
_startAutomaticScanning(); // Scanner un autre produit value,
}, style: const TextStyle(
style: ElevatedButton.styleFrom( fontSize: 14,
backgroundColor: Colors.blue.shade700, fontWeight: FontWeight.w600,
foregroundColor: Colors.white, color: Colors.black87,
), ),
child: const Text('Scanner encore'),
), ),
], ),
), ],
); ),
} );
}
void _showProductNotFoundDialog(String scannedData) { void _showProductNotFoundDialog(String scannedData) {
Get.dialog( Get.dialog(
@ -1899,9 +2091,9 @@ Widget _buildUserPointDeVenteInfo() {
// 6. Ajoutez cette méthode pour filtrer les produits par point de vente // 6. Ajoutez cette méthode pour filtrer les produits par point de vente
// 🎯 MODIFIÉ: Dropdown avec gestion améliorée // 🎯 MODIFIÉ: Dropdown avec gestion améliorée
Widget _buildPointDeVenteFilter() { Widget _buildPointDeVenteFilter() {
if (!_isUserSuperAdmin()) { // if (!_isUserSuperAdmin()) {
return const SizedBox.shrink(); // Cacher pour les non-admins // return const SizedBox.shrink(); // Cacher pour les non-admins
} // }
return Card( return Card(
elevation: 2, elevation: 2,
@ -2630,7 +2822,7 @@ Widget _buildProductListItem(Product product, int quantity, bool isMobile) {
const SizedBox(height: 4), const SizedBox(height: 4),
ElevatedButton.icon( ElevatedButton.icon(
icon: const Icon(Icons.swap_horiz, size: 14), icon: const Icon(Icons.swap_horiz, size: 14),
label: const Text('Demander transfert'), label:!isMobile ? const Text('Demander transfertt'):const SizedBox.shrink(),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: (product.stock != null && product.stock! >= 1) backgroundColor: (product.stock != null && product.stock! >= 1)
? Colors.blue.shade700 ? Colors.blue.shade700

6
lib/config/DatabaseConfig.dart

@ -1,6 +1,8 @@
// Config/database_config.dart - Version améliorée // Config/database_config.dart - Version améliorée
class DatabaseConfig { class DatabaseConfig {
static const String host = 'localhost'; // static const String host = '10.0.2.2';
//static const String host = '172.20.10.5';
static const String host = 'localhost';
static const int port = 3306; static const int port = 3306;
static const String username = 'root'; static const String username = 'root';
static const String? password = null; static const String? password = null;
@ -17,7 +19,7 @@ class DatabaseConfig {
static const int maxConnections = 10; static const int maxConnections = 10;
static const int minConnections = 2; static const int minConnections = 2;
static bool get isDevelopment => true; static bool get isDevelopment => false;
static Map<String, dynamic> getConfig() { static Map<String, dynamic> getConfig() {
if (isDevelopment) { if (isDevelopment) {

Loading…
Cancel
Save