Files
unionflow-mobile-apps/lib/features/reporting/domain/entities/rapport_trimestriel.dart
dahoud 6ba71fb014 feat(sprint-13.C mobile 2026-04-25): feature reporting (rapports trimestriels Contrôleur Interne)
Mobile mirror du backend P2-NEW-3. DRY strict — Clean Architecture identique aux autres features (compliance, devise).

Domain
- StatutRapport enum (draft, signe, archive, inconnu) + extension StatutRapportX (code/libelle/severite/fromCode)
- RapportTrimestriel entity (Equatable) + helpers libellePeriode, scoreSeverite (>=80 success, >=60 warning, <60 danger)

Data
- RapportTrimestrielModel.fromJson (parsing tolérant null + dates ISO)
- ReportingRemoteDataSourceImpl (Dio) : lister/generer/signer/archiver/telechargerPdf
- ReportingRepositoryImpl @Injectable

Presentation
- ReportingBloc : Load/Generer/Signer/Archiver events, 4 states (Initial/Loading/Loaded/Error)
- RapportsTrimestrielsPage : Material 3 ListView avec cards (period, score coloré, tag statut, hash tronqué) + EmptyView + ErrorView

Tests (10/10 verts)
- StatutRapportX × 2 (fromCode parse/null/inconnu, libelle/severite/code)
- RapportTrimestriel × 5 (libellePeriode, estDraft/estSigne/estArchive, scoreSeverite × 3)
- RapportTrimestrielModel.fromJson × 3 (complet, fallbacks, date invalide)

Note : viewer PDF interne reporté à un sprint dédié (intégration pdfx + permission storage Android). Téléchargement bytes via API exposé dans datasource pour usage futur.
2026-04-25 15:28:17 +00:00

84 lines
2.4 KiB
Dart

import 'package:equatable/equatable.dart';
/// Statut d'un rapport trimestriel Contrôleur Interne.
enum StatutRapport { draft, signe, archive, inconnu }
extension StatutRapportX on StatutRapport {
String get code => switch (this) {
StatutRapport.draft => 'DRAFT',
StatutRapport.signe => 'SIGNE',
StatutRapport.archive => 'ARCHIVE',
StatutRapport.inconnu => '',
};
String get libelle => switch (this) {
StatutRapport.draft => 'Brouillon',
StatutRapport.signe => 'Signé',
StatutRapport.archive => 'Archivé',
StatutRapport.inconnu => 'Inconnu',
};
/// Couleur sémantique Material 3.
String get severite => switch (this) {
StatutRapport.draft => 'warning',
StatutRapport.signe => 'info',
StatutRapport.archive => 'success',
StatutRapport.inconnu => 'secondary',
};
static StatutRapport fromCode(String? code) {
return switch (code) {
'DRAFT' => StatutRapport.draft,
'SIGNE' => StatutRapport.signe,
'ARCHIVE' => StatutRapport.archive,
_ => StatutRapport.inconnu,
};
}
}
/// Rapport trimestriel Contrôleur Interne (miroir mobile du backend P2-NEW-3).
class RapportTrimestriel extends Equatable {
final String id;
final String organisationId;
final int annee;
final int trimestre;
final DateTime? dateGeneration;
final StatutRapport statut;
final int scoreConformite;
final String? signataireId;
final DateTime? dateSignature;
final String? hashSha256;
const RapportTrimestriel({
required this.id,
required this.organisationId,
required this.annee,
required this.trimestre,
required this.dateGeneration,
required this.statut,
required this.scoreConformite,
this.signataireId,
this.dateSignature,
this.hashSha256,
});
bool get estDraft => statut == StatutRapport.draft;
bool get estSigne => statut == StatutRapport.signe;
bool get estArchive => statut == StatutRapport.archive;
String get libellePeriode => 'T$trimestre / $annee';
/// Couleur sémantique du score (success >= 80, warning >= 60, danger < 60).
String get scoreSeverite {
if (scoreConformite >= 80) return 'success';
if (scoreConformite >= 60) return 'warning';
return 'danger';
}
@override
List<Object?> get props => [
id, organisationId, annee, trimestre, dateGeneration, statut,
scoreConformite, signataireId, dateSignature, hashSha256,
];
}