Initial commit: unionflow-mobile-apps

Application Flutter complète (sans build artifacts).

Signed-off-by: lions dev Team
This commit is contained in:
dahoud
2026-03-15 16:30:08 +00:00
commit d094d6db9c
1790 changed files with 507435 additions and 0 deletions

View File

@@ -0,0 +1,229 @@
/// Datasource distant pour le workflow financier (API)
library finance_workflow_remote_datasource;
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:injectable/injectable.dart';
import '../../../../core/config/environment.dart';
import '../../../../core/error/exceptions.dart';
import '../models/transaction_approval_model.dart';
import '../models/budget_model.dart';
import '../../domain/entities/transaction_approval.dart';
import '../../domain/entities/budget.dart';
@lazySingleton
class FinanceWorkflowRemoteDatasource {
final http.Client client;
final FlutterSecureStorage secureStorage;
FinanceWorkflowRemoteDatasource({
required this.client,
required this.secureStorage,
});
/// Headers HTTP avec authentification
Future<Map<String, String>> _getHeaders() async {
final token = await secureStorage.read(key: 'access_token');
return {
'Content-Type': 'application/json',
'Accept': 'application/json',
if (token != null) 'Authorization': 'Bearer $token',
};
}
// === APPROBATIONS ===
Future<List<TransactionApprovalModel>> getPendingApprovals({
String? organizationId,
}) async {
final uri = Uri.parse('${AppConfig.apiBaseUrl}/api/finance/approvals/pending')
.replace(queryParameters: {
if (organizationId != null) 'organizationId': organizationId,
});
final response = await client.get(uri, headers: await _getHeaders());
if (response.statusCode == 200) {
final List<dynamic> jsonList = json.decode(response.body);
return jsonList
.map((json) => TransactionApprovalModel.fromJson(json))
.toList();
} else if (response.statusCode == 401) {
throw UnauthorizedException();
} else {
throw ServerException('Erreur lors de la récupération des approbations');
}
}
Future<TransactionApprovalModel> getApprovalById(String approvalId) async {
final uri = Uri.parse(
'${AppConfig.apiBaseUrl}/api/finance/approvals/$approvalId');
final response = await client.get(uri, headers: await _getHeaders());
if (response.statusCode == 200) {
return TransactionApprovalModel.fromJson(json.decode(response.body));
} else if (response.statusCode == 404) {
throw NotFoundException('Approbation non trouvée');
} else if (response.statusCode == 401) {
throw UnauthorizedException();
} else {
throw ServerException('Erreur lors de la récupération de l\'approbation');
}
}
Future<TransactionApprovalModel> approveTransaction({
required String approvalId,
String? comment,
}) async {
final uri =
Uri.parse('${AppConfig.apiBaseUrl}/api/finance/approvals/$approvalId/approve');
final body = json.encode({
if (comment != null) 'comment': comment,
});
final response = await client.post(
uri,
headers: await _getHeaders(),
body: body,
);
if (response.statusCode == 200) {
return TransactionApprovalModel.fromJson(json.decode(response.body));
} else if (response.statusCode == 401) {
throw UnauthorizedException();
} else if (response.statusCode == 403) {
throw ForbiddenException('Permission insuffisante pour approuver');
} else {
throw ServerException('Erreur lors de l\'approbation');
}
}
Future<TransactionApprovalModel> rejectTransaction({
required String approvalId,
required String reason,
}) async {
final uri =
Uri.parse('${AppConfig.apiBaseUrl}/api/finance/approvals/$approvalId/reject');
final body = json.encode({
'reason': reason,
});
final response = await client.post(
uri,
headers: await _getHeaders(),
body: body,
);
if (response.statusCode == 200) {
return TransactionApprovalModel.fromJson(json.decode(response.body));
} else if (response.statusCode == 401) {
throw UnauthorizedException();
} else if (response.statusCode == 403) {
throw ForbiddenException('Permission insuffisante pour rejeter');
} else {
throw ServerException('Erreur lors du rejet');
}
}
// === BUDGETS ===
Future<List<BudgetModel>> getBudgets({
String? organizationId,
String? status,
int? year,
}) async {
final uri = Uri.parse('${AppConfig.apiBaseUrl}/api/finance/budgets')
.replace(queryParameters: {
if (organizationId != null) 'organizationId': organizationId,
if (status != null) 'status': status,
if (year != null) 'year': year.toString(),
});
final response = await client.get(uri, headers: await _getHeaders());
if (response.statusCode == 200) {
final List<dynamic> jsonList = json.decode(response.body);
return jsonList.map((json) => BudgetModel.fromJson(json)).toList();
} else if (response.statusCode == 401) {
throw UnauthorizedException();
} else {
throw ServerException('Erreur lors de la récupération des budgets');
}
}
Future<BudgetModel> getBudgetById(String budgetId) async {
final uri =
Uri.parse('${AppConfig.apiBaseUrl}/api/finance/budgets/$budgetId');
final response = await client.get(uri, headers: await _getHeaders());
if (response.statusCode == 200) {
return BudgetModel.fromJson(json.decode(response.body));
} else if (response.statusCode == 404) {
throw NotFoundException('Budget non trouvé');
} else if (response.statusCode == 401) {
throw UnauthorizedException();
} else {
throw ServerException('Erreur lors de la récupération du budget');
}
}
Future<BudgetModel> createBudget({
required String name,
String? description,
required String organizationId,
required String period,
required int year,
int? month,
required List<Map<String, dynamic>> lines,
}) async {
final uri = Uri.parse('${AppConfig.apiBaseUrl}/api/finance/budgets');
final body = json.encode({
'name': name,
if (description != null) 'description': description,
'organizationId': organizationId,
'period': period,
'year': year,
if (month != null) 'month': month,
'lines': lines,
});
final response = await client.post(
uri,
headers: await _getHeaders(),
body: body,
);
if (response.statusCode == 201 || response.statusCode == 200) {
return BudgetModel.fromJson(json.decode(response.body));
} else if (response.statusCode == 401) {
throw UnauthorizedException();
} else if (response.statusCode == 403) {
throw ForbiddenException('Permission insuffisante pour créer un budget');
} else {
throw ServerException('Erreur lors de la création du budget');
}
}
Future<Map<String, dynamic>> getBudgetTracking({
required String budgetId,
}) async {
final uri = Uri.parse(
'${AppConfig.apiBaseUrl}/api/finance/budgets/$budgetId/tracking');
final response = await client.get(uri, headers: await _getHeaders());
if (response.statusCode == 200) {
return json.decode(response.body) as Map<String, dynamic>;
} else if (response.statusCode == 401) {
throw UnauthorizedException();
} else {
throw ServerException('Erreur lors de la récupération du suivi budgétaire');
}
}
}