147 lines
4.3 KiB
Dart
147 lines
4.3 KiB
Dart
// lib/features/igel/data/export_service.dart
|
||
import 'dart:convert';
|
||
import 'dart:typed_data';
|
||
|
||
import 'package:file_saver/file_saver.dart';
|
||
import 'package:intl/intl.dart';
|
||
|
||
import '../../igel/data/igel_repository.dart';
|
||
import '../../messwerte/data/messwerte_repository.dart';
|
||
import '../../messwerte/domain/messwert.dart';
|
||
|
||
class IgelExportService {
|
||
final IgelRepository igelRepo;
|
||
final MesswerteRepository messRepo;
|
||
|
||
IgelExportService({
|
||
required this.igelRepo,
|
||
required this.messRepo,
|
||
});
|
||
|
||
String _fmtDate(DateTime? d) =>
|
||
d == null ? '' : DateFormat('yyyy-MM-dd').format(d);
|
||
|
||
String _fmtDateTime(DateTime? d) =>
|
||
d == null ? '' : DateFormat('yyyy-MM-dd HH:mm').format(d);
|
||
|
||
String _csvEscape(String? v, {String delimiter = ';'}) {
|
||
final s = v ?? '';
|
||
final needsQuote =
|
||
s.contains(delimiter) || s.contains('\n') || s.contains('"');
|
||
final escaped = s.replaceAll('"', '""');
|
||
return needsQuote ? '"$escaped"' : escaped;
|
||
}
|
||
|
||
/// Erzeugt eine *denormalisierte* CSV:
|
||
/// Jede Zeile = 1 Messwert + zugehörige Igel-Stammdaten.
|
||
/// Hat ein Igel *keine* Messwerte, gibt es *trotzdem eine Zeile* mit leeren Messwert-Spalten.
|
||
Future<void> exportDenormalizedCsv() async {
|
||
// Immer frisch laden
|
||
final igelList = await igelRepo.list();
|
||
|
||
const sep = ';';
|
||
final sb = StringBuffer();
|
||
|
||
// Kopfzeile – nur Felder, die deine Models wirklich haben
|
||
sb.writeln([
|
||
// Igel
|
||
'igel_id',
|
||
'igel_name',
|
||
'igel_gender',
|
||
'igel_feature',
|
||
'igel_note',
|
||
'igel_rescued_at',
|
||
'igel_location',
|
||
'igel_marking',
|
||
'igel_finder',
|
||
'igel_phone',
|
||
'igel_email',
|
||
'igel_admission_reason',
|
||
'igel_animal_condition',
|
||
'igel_released_at',
|
||
'igel_release_location',
|
||
// Messwert
|
||
'messwert_id',
|
||
'messwert_datum',
|
||
'messwert_gewicht',
|
||
'messwert_behandlung',
|
||
'messwert_bemerkung',
|
||
].join(sep));
|
||
|
||
for (final ig in igelList) {
|
||
List<Messwert> mw = [];
|
||
try {
|
||
mw = await messRepo.list(ig.id);
|
||
} catch (_) {
|
||
mw = [];
|
||
}
|
||
|
||
if (mw.isEmpty) {
|
||
// Igel ohne Messwerte → eine Zeile mit leeren Messwert-Spalten
|
||
sb.writeln([
|
||
ig.id,
|
||
_csvEscape(ig.name, delimiter: sep),
|
||
_csvEscape(ig.gender, delimiter: sep),
|
||
_csvEscape(ig.feature, delimiter: sep),
|
||
_csvEscape(ig.note, delimiter: sep),
|
||
_fmtDate(ig.rescuedAt),
|
||
_csvEscape(ig.location, delimiter: sep),
|
||
_csvEscape(ig.marking, delimiter: sep),
|
||
_csvEscape(ig.finder, delimiter: sep),
|
||
_csvEscape(ig.phone, delimiter: sep),
|
||
_csvEscape(ig.email, delimiter: sep),
|
||
_csvEscape(ig.admissionReason, delimiter: sep),
|
||
_csvEscape(ig.animalCondition, delimiter: sep),
|
||
_fmtDate(ig.releasedAt),
|
||
_csvEscape(ig.releaseLocation, delimiter: sep),
|
||
|
||
// Messwert-Spalten leer
|
||
'',
|
||
'',
|
||
'',
|
||
'',
|
||
'',
|
||
].join(sep));
|
||
continue;
|
||
}
|
||
|
||
for (final m in mw) {
|
||
sb.writeln([
|
||
ig.id,
|
||
_csvEscape(ig.name, delimiter: sep),
|
||
_csvEscape(ig.gender, delimiter: sep),
|
||
_csvEscape(ig.feature, delimiter: sep),
|
||
_csvEscape(ig.note, delimiter: sep),
|
||
_fmtDate(ig.rescuedAt),
|
||
_csvEscape(ig.location, delimiter: sep),
|
||
_csvEscape(ig.marking, delimiter: sep),
|
||
_csvEscape(ig.finder, delimiter: sep),
|
||
_csvEscape(ig.phone, delimiter: sep),
|
||
_csvEscape(ig.email, delimiter: sep),
|
||
_csvEscape(ig.admissionReason, delimiter: sep),
|
||
_csvEscape(ig.animalCondition, delimiter: sep),
|
||
_fmtDate(ig.releasedAt),
|
||
_csvEscape(ig.releaseLocation, delimiter: sep),
|
||
m.id,
|
||
_fmtDateTime(m.datum),
|
||
m.gewicht,
|
||
_csvEscape(m.behandlung, delimiter: sep),
|
||
_csvEscape(m.bemerkung, delimiter: sep),
|
||
].join(sep));
|
||
}
|
||
}
|
||
|
||
final bytes =
|
||
Uint8List.fromList(const Utf8Encoder().convert(sb.toString()));
|
||
final filename =
|
||
'igel_export_denorm_${DateFormat('yyyyMMdd_HHmmss').format(DateTime.now())}';
|
||
|
||
await FileSaver.instance.saveFile(
|
||
name: filename,
|
||
bytes: bytes,
|
||
ext: 'csv',
|
||
mimeType: MimeType.csv,
|
||
);
|
||
}
|
||
}
|