333 lines
12 KiB
Dart
333 lines
12 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:appwrite/models.dart';
|
|
|
|
import 'auftrag_status.dart';
|
|
import 'dokument_typ.dart';
|
|
import 'zahlungs_status.dart';
|
|
|
|
/// Ein Datensatz = dokumentierter Vorgang (Fotos, Unterschrift, PDF).
|
|
///
|
|
/// `fotoUrls` und `unterschriftUrl` speichern Appwrite-**Datei-IDs** aus dem Bucket
|
|
/// (oder ältere http-URLs aus früheren Versionen).
|
|
///
|
|
/// In Appwrite liegen **alle** Felder (inkl. Fotos/Unterschrift/Kernfelder) in
|
|
/// **einem** String `extendedJson` als JSON mit `v: 2`, plus `userId` — wegen
|
|
/// des niedrigen Attribut-Limits in Appwrite 1.8.x. Ältere flache Dokumente
|
|
/// und `v: 1`-JSON werden weiter gelesen.
|
|
class Auftrag {
|
|
Auftrag({
|
|
required this.id,
|
|
required this.titel,
|
|
required this.beschreibung,
|
|
required this.kundenName,
|
|
required this.kundenAdresse,
|
|
required this.kundenEmail,
|
|
required this.rechnungsnummer,
|
|
required this.betragText,
|
|
required this.fotoUrls,
|
|
required this.unterschriftUrl,
|
|
required this.createdAt,
|
|
required this.status,
|
|
this.dokumentTyp = DokumentTyp.rechnung,
|
|
this.zahlungsStatus = ZahlungsStatus.offen,
|
|
this.faelligAm,
|
|
this.leistungsDatum,
|
|
this.kleinunternehmer = false,
|
|
this.reverseCharge = false,
|
|
this.skontoText = '',
|
|
this.ustIdKunde = '',
|
|
this.ibanVerkaeufer = '',
|
|
this.bicVerkaeufer = '',
|
|
this.kontoinhaberVerkaeufer = '',
|
|
});
|
|
|
|
final String id;
|
|
final String titel;
|
|
final String beschreibung;
|
|
final String kundenName;
|
|
final String kundenAdresse;
|
|
final String kundenEmail;
|
|
final String rechnungsnummer;
|
|
final String betragText;
|
|
final List<String> fotoUrls;
|
|
final String? unterschriftUrl;
|
|
final DateTime? createdAt;
|
|
final AuftragStatus status;
|
|
|
|
final DokumentTyp dokumentTyp;
|
|
final ZahlungsStatus zahlungsStatus;
|
|
final DateTime? faelligAm;
|
|
final DateTime? leistungsDatum;
|
|
final bool kleinunternehmer;
|
|
final bool reverseCharge;
|
|
final String skontoText;
|
|
final String ustIdKunde;
|
|
final String ibanVerkaeufer;
|
|
final String bicVerkaeufer;
|
|
final String kontoinhaberVerkaeufer;
|
|
|
|
bool get hasUnterschrift =>
|
|
unterschriftUrl != null && unterschriftUrl!.isNotEmpty;
|
|
|
|
static bool _parseBool(dynamic v) {
|
|
if (v == true) return true;
|
|
if (v == false) return false;
|
|
final s = v?.toString().trim().toLowerCase();
|
|
return s == '1' || s == 'true' || s == 'yes' || s == 'ja';
|
|
}
|
|
|
|
static List<String> _parseFotoListe(dynamic v) {
|
|
if (v == null) return [];
|
|
if (v is List) {
|
|
return v.map((e) => e.toString()).where((s) => s.isNotEmpty).toList();
|
|
}
|
|
final s = v.toString();
|
|
if (s.isEmpty) return [];
|
|
return s.split(',').map((e) => e.trim()).where((e) => e.isNotEmpty).toList();
|
|
}
|
|
|
|
static DateTime? _parseDate(dynamic v) {
|
|
if (v == null) return null;
|
|
final s = v.toString().trim();
|
|
if (s.isEmpty) return null;
|
|
return DateTime.tryParse(s);
|
|
}
|
|
|
|
static Map<String, dynamic>? _parseExtendedJson(String? raw) {
|
|
if (raw == null || raw.trim().isEmpty) return null;
|
|
try {
|
|
final o = jsonDecode(raw);
|
|
if (o is Map<String, dynamic>) return o;
|
|
if (o is Map) return Map<String, dynamic>.from(o);
|
|
} catch (_) {}
|
|
return null;
|
|
}
|
|
|
|
factory Auftrag.fromAppwriteDoc(Document doc) {
|
|
final d = doc.data;
|
|
final ext = _parseExtendedJson(d['extendedJson'] as String?);
|
|
|
|
if (ext != null && ext['v'] == 2) {
|
|
final betrag = ext['betragText'] as String? ?? '';
|
|
return Auftrag(
|
|
id: doc.$id,
|
|
titel: ext['titel'] as String? ?? '',
|
|
beschreibung: ext['beschreibung'] as String? ?? '',
|
|
kundenName: ext['kundenName'] as String? ?? '',
|
|
kundenAdresse: ext['kundenAdresse'] as String? ?? '',
|
|
kundenEmail: ext['kundenEmail'] as String? ?? '',
|
|
rechnungsnummer: ext['rechnungsnummer'] as String? ?? '',
|
|
betragText: betrag,
|
|
fotoUrls: _parseFotoListe(ext['fotoUrls']),
|
|
unterschriftUrl: ext['unterschriftUrl'] as String?,
|
|
createdAt: DateTime.tryParse(doc.$createdAt),
|
|
status: auftragStatusFromStorage(
|
|
ext['status'] as String?,
|
|
betragTextLegacy: betrag,
|
|
),
|
|
dokumentTyp: dokumentTypFromStorage(ext['dokumentTyp'] as String?),
|
|
zahlungsStatus:
|
|
zahlungsStatusFromStorage(ext['zahlungsStatus'] as String?),
|
|
faelligAm: _parseDate(ext['faelligAm']),
|
|
leistungsDatum: _parseDate(ext['leistungsDatum']),
|
|
kleinunternehmer: _parseBool(ext['kleinunternehmer']),
|
|
reverseCharge: _parseBool(ext['reverseCharge']),
|
|
skontoText: ext['skontoText'] as String? ?? '',
|
|
ustIdKunde: ext['ustIdKunde'] as String? ?? '',
|
|
ibanVerkaeufer: ext['ibanVerkaeufer'] as String? ?? '',
|
|
bicVerkaeufer: ext['bicVerkaeufer'] as String? ?? '',
|
|
kontoinhaberVerkaeufer:
|
|
ext['kontoinhaberVerkaeufer'] as String? ?? '',
|
|
);
|
|
}
|
|
|
|
final betrag = d['betragText'] as String? ?? '';
|
|
|
|
DokumentTyp dokumentTyp;
|
|
ZahlungsStatus zahlungsStatus;
|
|
DateTime? faelligAm;
|
|
DateTime? leistungsDatum;
|
|
bool kleinunternehmer;
|
|
bool reverseCharge;
|
|
String skontoText;
|
|
String ustIdKunde;
|
|
String ibanVerkaeufer;
|
|
String bicVerkaeufer;
|
|
String kontoinhaberVerkaeufer;
|
|
|
|
if (ext != null) {
|
|
dokumentTyp = dokumentTypFromStorage(ext['dokumentTyp'] as String?);
|
|
zahlungsStatus =
|
|
zahlungsStatusFromStorage(ext['zahlungsStatus'] as String?);
|
|
faelligAm = _parseDate(ext['faelligAm']);
|
|
leistungsDatum = _parseDate(ext['leistungsDatum']);
|
|
kleinunternehmer = _parseBool(ext['kleinunternehmer']);
|
|
reverseCharge = _parseBool(ext['reverseCharge']);
|
|
skontoText = ext['skontoText'] as String? ?? '';
|
|
ustIdKunde = ext['ustIdKunde'] as String? ?? '';
|
|
ibanVerkaeufer = ext['ibanVerkaeufer'] as String? ?? '';
|
|
bicVerkaeufer = ext['bicVerkaeufer'] as String? ?? '';
|
|
kontoinhaberVerkaeufer = ext['kontoinhaberVerkaeufer'] as String? ?? '';
|
|
} else {
|
|
dokumentTyp = dokumentTypFromStorage(d['dokumentTyp'] as String?);
|
|
zahlungsStatus =
|
|
zahlungsStatusFromStorage(d['zahlungsStatus'] as String?);
|
|
faelligAm = _parseDate(d['faelligAm']);
|
|
leistungsDatum = _parseDate(d['leistungsDatum']);
|
|
kleinunternehmer = _parseBool(d['kleinunternehmer']);
|
|
reverseCharge = _parseBool(d['reverseCharge']);
|
|
skontoText = d['skontoText'] as String? ?? '';
|
|
ustIdKunde = d['ustIdKunde'] as String? ?? '';
|
|
ibanVerkaeufer = d['ibanVerkaeufer'] as String? ?? '';
|
|
bicVerkaeufer = d['bicVerkaeufer'] as String? ?? '';
|
|
kontoinhaberVerkaeufer = d['kontoinhaberVerkaeufer'] as String? ?? '';
|
|
}
|
|
|
|
return Auftrag(
|
|
id: doc.$id,
|
|
titel: d['titel'] as String? ?? '',
|
|
beschreibung: d['beschreibung'] as String? ?? '',
|
|
kundenName: d['kundenName'] as String? ?? '',
|
|
kundenAdresse: d['kundenAdresse'] as String? ?? '',
|
|
kundenEmail: d['kundenEmail'] as String? ?? '',
|
|
rechnungsnummer: d['rechnungsnummer'] as String? ?? '',
|
|
betragText: betrag,
|
|
fotoUrls: _parseFotoListe(d['fotoUrls']),
|
|
unterschriftUrl: d['unterschriftUrl'] as String?,
|
|
createdAt: DateTime.tryParse(doc.$createdAt),
|
|
status: auftragStatusFromStorage(
|
|
d['status'] as String?,
|
|
betragTextLegacy: betrag,
|
|
),
|
|
dokumentTyp: dokumentTyp,
|
|
zahlungsStatus: zahlungsStatus,
|
|
faelligAm: faelligAm,
|
|
leistungsDatum: leistungsDatum,
|
|
kleinunternehmer: kleinunternehmer,
|
|
reverseCharge: reverseCharge,
|
|
skontoText: skontoText,
|
|
ustIdKunde: ustIdKunde,
|
|
ibanVerkaeufer: ibanVerkaeufer,
|
|
bicVerkaeufer: bicVerkaeufer,
|
|
kontoinhaberVerkaeufer: kontoinhaberVerkaeufer,
|
|
);
|
|
}
|
|
|
|
String _encodeAppwriteExtendedJson() {
|
|
return jsonEncode({
|
|
'v': 2,
|
|
'titel': titel,
|
|
'beschreibung': beschreibung,
|
|
'kundenName': kundenName,
|
|
'kundenAdresse': kundenAdresse,
|
|
'kundenEmail': kundenEmail,
|
|
'rechnungsnummer': rechnungsnummer,
|
|
'betragText': betragText,
|
|
'fotoUrls': fotoUrls,
|
|
'unterschriftUrl': unterschriftUrl,
|
|
'status': status.storageValue,
|
|
'dokumentTyp': dokumentTyp.storageValue,
|
|
'zahlungsStatus': zahlungsStatus.storageValue,
|
|
'faelligAm': faelligAm?.toIso8601String() ?? '',
|
|
'leistungsDatum': leistungsDatum?.toIso8601String() ?? '',
|
|
'kleinunternehmer': kleinunternehmer,
|
|
'reverseCharge': reverseCharge,
|
|
'skontoText': skontoText,
|
|
'ustIdKunde': ustIdKunde,
|
|
'ibanVerkaeufer': ibanVerkaeufer,
|
|
'bicVerkaeufer': bicVerkaeufer,
|
|
'kontoinhaberVerkaeufer': kontoinhaberVerkaeufer,
|
|
});
|
|
}
|
|
|
|
/// Payload für Appwrite `data` — nur [extendedJson]; [userId] setzt das Repo.
|
|
Map<String, dynamic> toMap() {
|
|
return {
|
|
'extendedJson': _encodeAppwriteExtendedJson(),
|
|
};
|
|
}
|
|
|
|
/// JSON-fähige Darstellung für Datenauskunft/Export (ohne Binärdateien).
|
|
Map<String, dynamic> toExportMap() {
|
|
return {
|
|
'id': id,
|
|
'titel': titel,
|
|
'beschreibung': beschreibung,
|
|
'kundenName': kundenName,
|
|
'kundenAdresse': kundenAdresse,
|
|
'kundenEmail': kundenEmail,
|
|
'rechnungsnummer': rechnungsnummer,
|
|
'betragText': betragText,
|
|
'status': status.storageValue,
|
|
'dokumentTyp': dokumentTyp.storageValue,
|
|
'zahlungsStatus': zahlungsStatus.storageValue,
|
|
'faelligAm': faelligAm?.toIso8601String(),
|
|
'leistungsDatum': leistungsDatum?.toIso8601String(),
|
|
'kleinunternehmer': kleinunternehmer,
|
|
'reverseCharge': reverseCharge,
|
|
'skontoText': skontoText,
|
|
'ustIdKunde': ustIdKunde,
|
|
'ibanVerkaeufer': ibanVerkaeufer,
|
|
'bicVerkaeufer': bicVerkaeufer,
|
|
'kontoinhaberVerkaeufer': kontoinhaberVerkaeufer,
|
|
'fotoDateiIds': fotoUrls,
|
|
'unterschriftDateiId': unterschriftUrl,
|
|
'createdAt': createdAt?.toIso8601String(),
|
|
};
|
|
}
|
|
|
|
Auftrag copyWith({
|
|
String? id,
|
|
String? titel,
|
|
String? beschreibung,
|
|
String? kundenName,
|
|
String? kundenAdresse,
|
|
String? kundenEmail,
|
|
String? rechnungsnummer,
|
|
String? betragText,
|
|
List<String>? fotoUrls,
|
|
String? unterschriftUrl,
|
|
DateTime? createdAt,
|
|
AuftragStatus? status,
|
|
DokumentTyp? dokumentTyp,
|
|
ZahlungsStatus? zahlungsStatus,
|
|
DateTime? faelligAm,
|
|
DateTime? leistungsDatum,
|
|
bool? kleinunternehmer,
|
|
bool? reverseCharge,
|
|
String? skontoText,
|
|
String? ustIdKunde,
|
|
String? ibanVerkaeufer,
|
|
String? bicVerkaeufer,
|
|
String? kontoinhaberVerkaeufer,
|
|
}) {
|
|
return Auftrag(
|
|
id: id ?? this.id,
|
|
titel: titel ?? this.titel,
|
|
beschreibung: beschreibung ?? this.beschreibung,
|
|
kundenName: kundenName ?? this.kundenName,
|
|
kundenAdresse: kundenAdresse ?? this.kundenAdresse,
|
|
kundenEmail: kundenEmail ?? this.kundenEmail,
|
|
rechnungsnummer: rechnungsnummer ?? this.rechnungsnummer,
|
|
betragText: betragText ?? this.betragText,
|
|
fotoUrls: fotoUrls ?? List.from(this.fotoUrls),
|
|
unterschriftUrl: unterschriftUrl ?? this.unterschriftUrl,
|
|
createdAt: createdAt ?? this.createdAt,
|
|
status: status ?? this.status,
|
|
dokumentTyp: dokumentTyp ?? this.dokumentTyp,
|
|
zahlungsStatus: zahlungsStatus ?? this.zahlungsStatus,
|
|
faelligAm: faelligAm ?? this.faelligAm,
|
|
leistungsDatum: leistungsDatum ?? this.leistungsDatum,
|
|
kleinunternehmer: kleinunternehmer ?? this.kleinunternehmer,
|
|
reverseCharge: reverseCharge ?? this.reverseCharge,
|
|
skontoText: skontoText ?? this.skontoText,
|
|
ustIdKunde: ustIdKunde ?? this.ustIdKunde,
|
|
ibanVerkaeufer: ibanVerkaeufer ?? this.ibanVerkaeufer,
|
|
bicVerkaeufer: bicVerkaeufer ?? this.bicVerkaeufer,
|
|
kontoinhaberVerkaeufer:
|
|
kontoinhaberVerkaeufer ?? this.kontoinhaberVerkaeufer,
|
|
);
|
|
}
|
|
}
|