refactor: streamline API call handling in ExpenseDetailController and enhance error logging
This commit is contained in:
parent
31966f4bc5
commit
3427c5bd26
@ -11,9 +11,8 @@ class ExpenseDetailController extends GetxController {
|
||||
final Rx<EmployeeModel?> selectedReimbursedBy = Rx<EmployeeModel?>(null);
|
||||
final RxList<EmployeeModel> allEmployees = <EmployeeModel>[].obs;
|
||||
|
||||
bool _isInitialized = false;
|
||||
late String _expenseId;
|
||||
|
||||
bool _isInitialized = false;
|
||||
/// Call this once from the screen (NOT inside build) to initialize
|
||||
void init(String expenseId) {
|
||||
if (_isInitialized) return;
|
||||
@ -21,48 +20,61 @@ class ExpenseDetailController extends GetxController {
|
||||
_isInitialized = true;
|
||||
_expenseId = expenseId;
|
||||
|
||||
fetchExpenseDetails();
|
||||
fetchAllEmployees();
|
||||
// Use Future.wait to fetch details and employees concurrently
|
||||
Future.wait([
|
||||
fetchExpenseDetails(),
|
||||
fetchAllEmployees(),
|
||||
]);
|
||||
}
|
||||
|
||||
/// Fetch expense details by stored ID
|
||||
Future<void> fetchExpenseDetails() async {
|
||||
/// Generic method to handle API calls with loading and error states
|
||||
Future<T?> _apiCallWrapper<T>(
|
||||
Future<T?> Function() apiCall, String operationName) async {
|
||||
isLoading.value = true;
|
||||
errorMessage.value = '';
|
||||
errorMessage.value = ''; // Clear previous errors
|
||||
|
||||
try {
|
||||
logSafe("Fetching expense details for ID: $_expenseId");
|
||||
|
||||
final result =
|
||||
await ApiService.getExpenseDetailsApi(expenseId: _expenseId);
|
||||
if (result != null) {
|
||||
try {
|
||||
expense.value = ExpenseDetailModel.fromJson(result);
|
||||
logSafe("Expense details loaded successfully: ${expense.value?.id}");
|
||||
} catch (e) {
|
||||
errorMessage.value = 'Failed to parse expense details: $e';
|
||||
logSafe("Parse error in fetchExpenseDetails: $e",
|
||||
level: LogLevel.error);
|
||||
}
|
||||
} else {
|
||||
errorMessage.value = 'Failed to fetch expense details from server.';
|
||||
logSafe("fetchExpenseDetails failed: null response",
|
||||
level: LogLevel.error);
|
||||
}
|
||||
logSafe("Initiating $operationName...");
|
||||
final result = await apiCall();
|
||||
logSafe("$operationName completed successfully.");
|
||||
return result;
|
||||
} catch (e, stack) {
|
||||
errorMessage.value = 'An unexpected error occurred.';
|
||||
logSafe("Exception in fetchExpenseDetails: $e", level: LogLevel.error);
|
||||
errorMessage.value = 'An unexpected error occurred during $operationName.';
|
||||
logSafe("Exception in $operationName: $e", level: LogLevel.error);
|
||||
logSafe("StackTrace: $stack", level: LogLevel.debug);
|
||||
return null;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// In ExpenseDetailController
|
||||
/// Fetch expense details by stored ID
|
||||
Future<void> fetchExpenseDetails() async {
|
||||
final result = await _apiCallWrapper(
|
||||
() => ApiService.getExpenseDetailsApi(expenseId: _expenseId),
|
||||
"fetch expense details");
|
||||
|
||||
if (result != null) {
|
||||
try {
|
||||
expense.value = ExpenseDetailModel.fromJson(result);
|
||||
logSafe("Expense details loaded successfully: ${expense.value?.id}");
|
||||
} catch (e) {
|
||||
errorMessage.value = 'Failed to parse expense details: $e';
|
||||
logSafe("Parse error in fetchExpenseDetails: $e",
|
||||
level: LogLevel.error);
|
||||
}
|
||||
} else {
|
||||
errorMessage.value = 'Failed to fetch expense details from server.';
|
||||
logSafe("fetchExpenseDetails failed: null response",
|
||||
level: LogLevel.error);
|
||||
}
|
||||
}
|
||||
|
||||
// This method seems like a utility and might be better placed in a helper or utility class
|
||||
// if it's used across multiple controllers. Keeping it here for now as per original code.
|
||||
List<String> parsePermissionIds(dynamic permissionData) {
|
||||
if (permissionData == null) return [];
|
||||
if (permissionData is List) {
|
||||
// If it's already a List, return a list of Strings.
|
||||
return permissionData
|
||||
.map((e) => e.toString().trim())
|
||||
.where((e) => e.isNotEmpty)
|
||||
@ -81,26 +93,24 @@ class ExpenseDetailController extends GetxController {
|
||||
|
||||
/// Fetch all employees
|
||||
Future<void> fetchAllEmployees() async {
|
||||
isLoading.value = true;
|
||||
errorMessage.value = '';
|
||||
final response = await _apiCallWrapper(
|
||||
() => ApiService.getAllEmployees(), "fetch all employees");
|
||||
|
||||
try {
|
||||
final response = await ApiService.getAllEmployees();
|
||||
if (response != null && response.isNotEmpty) {
|
||||
if (response != null && response.isNotEmpty) {
|
||||
try {
|
||||
allEmployees.assignAll(response.map((e) => EmployeeModel.fromJson(e)));
|
||||
logSafe("All Employees fetched: ${allEmployees.length}",
|
||||
level: LogLevel.info);
|
||||
} else {
|
||||
allEmployees.clear();
|
||||
logSafe("No employees found.", level: LogLevel.warning);
|
||||
} catch (e) {
|
||||
errorMessage.value = 'Failed to parse employee data: $e';
|
||||
logSafe("Parse error in fetchAllEmployees: $e", level: LogLevel.error);
|
||||
}
|
||||
} catch (e) {
|
||||
} else {
|
||||
allEmployees.clear();
|
||||
logSafe("Error fetching employees", level: LogLevel.error, error: e);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
update();
|
||||
logSafe("No employees found.", level: LogLevel.warning);
|
||||
}
|
||||
// `update()` is typically not needed for RxList directly unless you have specific GetBuilder/Obx usage that requires it
|
||||
// If you are using Obx widgets, `allEmployees.assignAll` will automatically trigger a rebuild.
|
||||
}
|
||||
|
||||
/// Update expense with reimbursement info and status
|
||||
@ -111,68 +121,43 @@ class ExpenseDetailController extends GetxController {
|
||||
required String reimburseById,
|
||||
required String statusId,
|
||||
}) async {
|
||||
isLoading.value = true;
|
||||
errorMessage.value = '';
|
||||
|
||||
try {
|
||||
logSafe("Submitting reimbursement for expense: $_expenseId");
|
||||
|
||||
final success = await ApiService.updateExpenseStatusApi(
|
||||
final success = await _apiCallWrapper(
|
||||
() => ApiService.updateExpenseStatusApi(
|
||||
expenseId: _expenseId,
|
||||
statusId: statusId,
|
||||
comment: comment,
|
||||
reimburseTransactionId: reimburseTransactionId,
|
||||
reimburseDate: reimburseDate,
|
||||
reimbursedById: reimburseById,
|
||||
);
|
||||
),
|
||||
"submit reimbursement",
|
||||
);
|
||||
|
||||
if (success) {
|
||||
logSafe("Reimbursement submitted successfully.");
|
||||
await fetchExpenseDetails();
|
||||
return true;
|
||||
} else {
|
||||
errorMessage.value = "Failed to submit reimbursement.";
|
||||
return false;
|
||||
}
|
||||
} catch (e, stack) {
|
||||
errorMessage.value = 'An unexpected error occurred.';
|
||||
logSafe("Exception in updateExpenseStatusWithReimbursement: $e",
|
||||
level: LogLevel.error);
|
||||
logSafe("StackTrace: $stack", level: LogLevel.debug);
|
||||
if (success == true) { // Explicitly check for true as _apiCallWrapper returns T?
|
||||
await fetchExpenseDetails(); // Refresh details after successful update
|
||||
return true;
|
||||
} else {
|
||||
errorMessage.value = "Failed to submit reimbursement.";
|
||||
return false;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Update status for this specific expense
|
||||
Future<bool> updateExpenseStatus(String statusId) async {
|
||||
isLoading.value = true;
|
||||
errorMessage.value = '';
|
||||
|
||||
try {
|
||||
logSafe("Updating status for expense: $_expenseId -> $statusId");
|
||||
|
||||
final success = await ApiService.updateExpenseStatusApi(
|
||||
final success = await _apiCallWrapper(
|
||||
() => ApiService.updateExpenseStatusApi(
|
||||
expenseId: _expenseId,
|
||||
statusId: statusId,
|
||||
);
|
||||
),
|
||||
"update expense status",
|
||||
);
|
||||
|
||||
if (success) {
|
||||
logSafe("Expense status updated successfully.");
|
||||
await fetchExpenseDetails();
|
||||
return true;
|
||||
} else {
|
||||
errorMessage.value = "Failed to update expense status.";
|
||||
return false;
|
||||
}
|
||||
} catch (e, stack) {
|
||||
errorMessage.value = 'An unexpected error occurred.';
|
||||
logSafe("Exception in updateExpenseStatus: $e", level: LogLevel.error);
|
||||
logSafe("StackTrace: $stack", level: LogLevel.debug);
|
||||
if (success == true) { // Explicitly check for true as _apiCallWrapper returns T?
|
||||
await fetchExpenseDetails(); // Refresh details after successful update
|
||||
return true;
|
||||
} else {
|
||||
errorMessage.value = "Failed to update expense status.";
|
||||
return false;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user