Files

147 lines
4.3 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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,
);
}
}