Files
Handwerks_app/models/auftrag.dart
JUSN 9ddce354c0 Feature
ein paar feature aber datenbank macht probleme wenn man aufträge speichern möchge
2026-04-05 12:47:57 +02:00

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,
);
}
}