marco.pms.mobileapp/lib/controller/finance/advance_payment_controller.dart

145 lines
3.8 KiB
Dart

import 'dart:async';
import 'package:get/get.dart';
import 'package:marco/model/finance/advance_payment_model.dart';
import 'package:marco/model/finance/get_employee_model.dart';
import 'package:marco/helpers/services/app_logger.dart';
import 'package:marco/helpers/services/api_service.dart';
class AdvancePaymentController extends GetxController {
/// Advance payments list
var payments = <AdvancePayment>[].obs;
var isLoading = false.obs;
/// Employees for dropdown search
var employees = <Employee>[].obs;
var allEmployees = <Employee>[]; // cache of last API response
var employeesLoading = false.obs;
var searchQuery = ''.obs;
var selectedEmployee = Rxn<Employee>();
/// Prevents unwanted API calls while programmatically updating search
var _suppressSearch = false.obs;
Timer? _debounceTimer;
@override
void onInit() {
super.onInit();
ever<String>(searchQuery, (q) {
if (_suppressSearch.value) return; // Skip while selecting employee
// 🔹 When user types new text, clear previous employee + payments instantly
if (selectedEmployee.value != null) {
selectedEmployee.value = null;
payments.clear();
}
// 🔹 Show fresh dropdown results for new query
_debounceTimer?.cancel();
_debounceTimer = Timer(const Duration(milliseconds: 400), () {
if (q.isNotEmpty) {
fetchEmployees(q); // repopulate dropdown
} else {
employees.clear(); // hide dropdown when search cleared
}
});
});
}
@override
void onClose() {
_debounceTimer?.cancel();
super.onClose();
}
/// Fetch employees by query
Future<void> fetchEmployees(String q) async {
if (q.isEmpty) {
employees.clear();
return;
}
if (employeesLoading.value) return;
try {
employeesLoading.value = true;
final list = await ApiService.getEmployees(query: q);
final parsed = Employee.listFromJson(list);
logSafe("✅ Employees fetched from API: ${parsed.map((e) => e.name).toList()}");
// Save full result and filter locally
allEmployees = parsed;
_filterEmployees(q);
} catch (e, s) {
logSafe("❌ fetchEmployees error: $e\n$s", level: LogLevel.error);
employees.clear();
} finally {
employeesLoading.value = false;
}
}
/// Local filter to update list based on search text
void _filterEmployees(String query) {
final q = query.toLowerCase();
employees
..clear()
..addAll(allEmployees.where((e) {
return e.name.toLowerCase().contains(q) ||
e.email.toLowerCase().contains(q);
}));
}
/// When user selects employee
void selectEmployee(Employee emp) {
_suppressSearch.value = true;
selectedEmployee.value = emp;
employees.clear(); // hide dropdown
searchQuery.value = emp.name;
fetchAdvancePayments(emp.id);
// Re-enable search after a short delay
Future.delayed(const Duration(milliseconds: 300), () {
_suppressSearch.value = false;
});
}
/// Fetch advance payments for the selected employee
Future<void> fetchAdvancePayments(String employeeId) async {
if (employeeId.isEmpty) {
payments.clear();
return;
}
try {
isLoading.value = true;
final list = await ApiService.getAdvancePayments(employeeId);
payments.assignAll(list);
} catch (e, s) {
logSafe("❌ fetchAdvancePayments error: $e\n$s", level: LogLevel.error);
payments.clear();
} finally {
isLoading.value = false;
}
}
/// Clear employee selection
void clearSelection() {
selectedEmployee.value = null;
payments.clear();
employees.clear();
searchQuery.value = '';
}
void resetSelectionOnNewSearch() {
if (selectedEmployee.value != null) {
selectedEmployee.value = null;
payments.clear();
}
}
}