import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:inventory_app/constants.dart'; import 'package:inventory_app/models/famille_produit.dart'; import 'package:inventory_app/models/depot.dart'; import 'package:inventory_app/models/inventory_line.dart'; import 'package:inventory_app/models/product.dart'; import 'package:inventory_app/models/tracking_number.dart'; import 'package:inventory_app/service/axelor_client.dart'; import 'package:inventory_app/views/login_view.dart'; enum InventoryLineState { newLine, existingLine } class HomeController extends GetxController { final outputController = TextEditingController(); final labelController = TextEditingController(); final qtyController = TextEditingController(text: "1"); final unitController = TextEditingController(); final serialNumberTxt = TextEditingController(); var product = Rxn(); var selectedOption = 'comptage1'.obs; var depotList = [].obs; var selectedDepot = Rxn(); var trackingNumbers = [].obs; var selectedTrackingNumber = Rxn(); var isLoading = false.obs; var imageUrl = ''.obs; var familleProduits = [].obs; var selectedFamilleProduit = Rxn(); var sousFamilleProduits = [].obs; var selectedSousFamilleProduit = Rxn(); var zoneCode = ''.obs; var selectedState = 'Moyen'.obs; late AxelorClient client; @override void onInit() { super.onInit(); _initClient(); } @override void onReady() { super.onReady(); _handleArgs(); } Future _initClient() async { isLoading(true); client = await AxelorClient.create(); depotList.value = (await client.fetchLocations()) ?? []; isLoading(false); } Future fetchLocations() async { isLoading(true); client = await AxelorClient.create(); depotList.value = (await client.fetchLocations()) ?? []; isLoading(false); } Future _loadProduct(String code) async { try { isLoading(true); Product? p = await client.fetchProductByCode(code); if (p == null) { Get.snackbar('Erreur', 'Produit introuvable', backgroundColor: Colors.red); return; } product.value = p; labelController.text = p.name ?? ''; unitController.text = p.unit?.name ?? ''; imageUrl.value = p.imageUrl ?? ''; trackingNumbers.value = await client.fetchTrackingNumberByProduct(p.id!) ?? []; Get.snackbar( 'Produit trouvé', 'Produit: ${p.name}', backgroundColor: Colors.green, duration: const Duration(seconds: 2), ); } catch (e) { Get.snackbar( 'Erreur', 'Impossible de charger le produit', backgroundColor: Colors.red, ); } finally { isLoading(false); } } Future _handleArgs() async { final args = Get.arguments; if (args is String) { outputController.text = args; await _loadProduct(args); } } void handleScannedCode(String code) async { outputController.text = code; trackingNumbers.clear(); selectedTrackingNumber.value = null; await _loadProduct(code); } void handleProductScan(String code) => handleScannedCode(code); void handleLocationScan(String name) async { var finalStr = ""; if (name.isNotEmpty) { finalStr = name.split(":")[0].trim(); } zoneCode.value = finalStr; final locationJson = await client.fetchStockLocationByName(name); if (locationJson == null) { Get.snackbar( 'Erreur', 'Zone introuvable (Veuillez rafraichir la page et ressayer)', backgroundColor: Colors.red, ); return; } final depot = Depot.fromJson(locationJson); selectedDepot.value = depot; Get.snackbar('Zone trouvée', 'Nom: ${depot.name}', backgroundColor: Colors.blue); } Future save() async { if (outputController.text.isEmpty || qtyController.text.isEmpty || product.value == null) { Get.snackbar('Erreur', 'Produit ou quantité invalide', backgroundColor: Colors.red); return; } final now = DateTime.now().toIso8601String(); final qty = double.tryParse(qtyController.text) ?? 1; final user = await client.fetchUserProfile(); final selected = selectedOption.value; double first = 0, second = 0, third = 0; String? firstDate, secondDate, thirdDate; Map? firstUser, secondUser, thirdUser; switch (selected) { case "comptage1": first = qty; firstDate = now; firstUser = user; break; case "comptage2": second = qty; secondDate = now; secondUser = user; break; case "comptage3": third = qty; thirdDate = now; thirdUser = user; break; } final line = InventoryLine( inventoryId: kInventoryId, productId: product.value!.id!, productName: product.value!.name ?? '', currentQty: qty, realQty: qty, unitId: product.value!.unit?.id ?? 2, description: selectedState.value, observation: serialNumberTxt.text, ticketId: "TICKET-${DateTime.now().millisecondsSinceEpoch}", rack: "A1", trackingNumberId: selectedTrackingNumber.value?.id, countingTypeSelect: 1, stockLocationId: selectedDepot.value?.id ?? 4, firstCounting: first, secondCounting: second, thirdCounting: third, firstCountingDate: firstDate, secondCountingDate: secondDate, thirdCountingDate: thirdDate, firstCountingByUser: firstUser, secondCountingByUser: secondUser, thirdCountingByUser: thirdUser, ); await client.saveInventoryLine(inventoryLine: line); _resetForm(); Get.snackbar('Succès', 'Ligne enregistrée avec succès', backgroundColor: Colors.green); } void _resetForm() { outputController.clear(); labelController.clear(); product.value = null; trackingNumbers.clear(); selectedTrackingNumber.value = null; serialNumberTxt.text = ""; } Future fetchImageBytes(int imageId) => client.fetchImageBytes(imageId); Future fetchFamilleProduits() async { try { isLoading(true); final list = await client.getFamilleProduit(); familleProduits.value = list ?? []; } catch (e) { familleProduits.clear(); } finally { isLoading(false); } } Future fetchSousFamilleProduits(int parentId) async { try { isLoading(true); final list = await client.getSousFamilleProduit(parentId); sousFamilleProduits.value = list ?? []; } catch (e) { sousFamilleProduits.clear(); } finally { isLoading(false); } } void onFamilleSelected(FamilleProduit? famille) async { selectedFamilleProduit.value = famille; selectedSousFamilleProduit.value = null; if (famille?.id != null) { await fetchSousFamilleProduits(famille!.id!); } else { sousFamilleProduits.clear(); } } void logout() async { if (await client.logout()) Get.off(LoginView()); } }