cashumit/lib/models/local_receipt.dart

194 lines
7.3 KiB
Dart

import 'receipt_item.dart';
import 'receipt_group.dart';
class LocalReceipt {
final String id;
final List<ReceiptGroup> groups;
final String? destinationAccountId;
final String? destinationAccountName;
final DateTime transactionDate;
final String?
transactionDescription; // Deskripsi transaksi untuk tampilan di daftar
// ID transaksi tunggal (format lama / fallback). Prefer [fireflyTransactionIds].
final String? fireflyTransactionId;
final List<String> fireflyTransactionIds; // ID per grup (format baru)
final String? fireflyTransactionUrl; // URL utama (format lama)
final List<String> fireflyTransactionUrls; // URL per grup (format baru)
final bool isSubmitted;
final String? submissionError;
final DateTime? submittedAt;
final DateTime createdAt;
final double paymentAmount;
final String?
tipSourceAccountId; // Akun sumber untuk transaksi tip (null = bukan tip)
final String? tipSourceAccountName;
LocalReceipt({
required this.id,
required this.groups,
this.destinationAccountId,
this.destinationAccountName,
required this.transactionDate,
this.transactionDescription,
this.fireflyTransactionId,
this.fireflyTransactionIds = const [],
this.fireflyTransactionUrl,
this.fireflyTransactionUrls = const [],
this.isSubmitted = false,
this.submissionError,
this.submittedAt,
required this.createdAt,
this.paymentAmount = 0.0,
this.tipSourceAccountId,
this.tipSourceAccountName,
});
double get total =>
groups.fold(0.0, (sum, group) => sum + group.total);
bool get hasTip => tipSourceAccountId != null && paymentAmount > total;
double get tipAmount => hasTip ? (paymentAmount - total) : 0.0;
/// Gabungan semua URL transaksi (untuk tampilan daftar link).
List<String> get allFireflyUrls {
final urls = <String>[...fireflyTransactionUrls];
if (fireflyTransactionUrl != null &&
fireflyTransactionUrl!.isNotEmpty &&
!urls.contains(fireflyTransactionUrl)) {
urls.insert(0, fireflyTransactionUrl!);
}
return urls;
}
Map<String, dynamic> toJson() {
return {
'id': id,
'groups': groups.map((group) => group.toJson()).toList(),
'destinationAccountId': destinationAccountId,
'destinationAccountName': destinationAccountName,
'transactionDate': transactionDate.toIso8601String(),
'transactionDescription': transactionDescription,
'fireflyTransactionId': fireflyTransactionId,
'fireflyTransactionIds': fireflyTransactionIds,
'fireflyTransactionUrl': fireflyTransactionUrl,
'fireflyTransactionUrls': fireflyTransactionUrls,
'isSubmitted': isSubmitted,
'submissionError': submissionError,
'submittedAt': submittedAt?.toIso8601String(),
'createdAt': createdAt.toIso8601String(),
'paymentAmount': paymentAmount,
'tipSourceAccountId': tipSourceAccountId,
'tipSourceAccountName': tipSourceAccountName,
};
}
factory LocalReceipt.fromJson(Map<String, dynamic> json) {
// Migrasi format lama: jika ada key "items" (list tunggal) tapi tidak ada "groups",
// bungkus menjadi satu grup dengan akun sumber lama.
List<ReceiptGroup> groups;
if (json.containsKey('groups') && json['groups'] is List) {
groups = (json['groups'] as List)
.map((g) => ReceiptGroup.fromJson(g as Map<String, dynamic>))
.toList();
} else {
// Format lama
final items = (json['items'] as List? ?? [])
.map((item) => ReceiptItem.fromJson(item as Map<String, dynamic>))
.toList();
groups = [
ReceiptGroup(
id: 'legacy_${json['id'] ?? DateTime.now().millisecondsSinceEpoch}',
items: items,
sourceAccountId: json['sourceAccountId'] as String?,
sourceAccountName: json['sourceAccountName'] as String?,
),
];
}
// fireflyTransactionIds (format baru) - fallback ke ID tunggal lama
final txIds = (json['fireflyTransactionIds'] as List?)
?.map((e) => e.toString())
.toList() ??
(json['fireflyTransactionId'] != null
? [json['fireflyTransactionId'].toString()]
: <String>[]);
// fireflyTransactionUrls (format baru) - fallback ke URL tunggal lama
final txUrls = (json['fireflyTransactionUrls'] as List?)
?.map((e) => e.toString())
.toList() ??
(json['fireflyTransactionUrl'] != null
? [json['fireflyTransactionUrl'].toString()]
: <String>[]);
return LocalReceipt(
id: json['id'],
groups: groups,
destinationAccountId: json['destinationAccountId'] as String?,
destinationAccountName: json['destinationAccountName'] as String?,
transactionDate: DateTime.parse(json['transactionDate']),
transactionDescription: json['transactionDescription'],
fireflyTransactionId: json['fireflyTransactionId'],
fireflyTransactionIds: txIds,
fireflyTransactionUrl: json['fireflyTransactionUrl'],
fireflyTransactionUrls: txUrls,
isSubmitted: json['isSubmitted'] ?? false,
submissionError: json['submissionError'],
submittedAt: json['submittedAt'] != null
? DateTime.parse(json['submittedAt'])
: null,
createdAt: DateTime.parse(json['createdAt']),
paymentAmount: json['paymentAmount']?.toDouble() ?? 0.0,
// Format lama pakai boolean isTip; tidak bisa dipulihkan menjadi akun sumber,
// jadi tipSourceAccountId tetap null (user dapat set ulang sebelum kirim).
tipSourceAccountId: json['tipSourceAccountId'] as String?,
tipSourceAccountName: json['tipSourceAccountName'] as String?,
);
}
LocalReceipt copyWith({
String? id,
List<ReceiptGroup>? groups,
String? destinationAccountId,
String? destinationAccountName,
DateTime? transactionDate,
String? transactionDescription,
String? fireflyTransactionId,
List<String>? fireflyTransactionIds,
String? fireflyTransactionUrl,
List<String>? fireflyTransactionUrls,
bool? isSubmitted,
String? submissionError,
DateTime? submittedAt,
DateTime? createdAt,
double? paymentAmount,
String? tipSourceAccountId,
String? tipSourceAccountName,
}) {
return LocalReceipt(
id: id ?? this.id,
groups: groups ?? this.groups,
destinationAccountId: destinationAccountId ?? this.destinationAccountId,
destinationAccountName:
destinationAccountName ?? this.destinationAccountName,
transactionDate: transactionDate ?? this.transactionDate,
transactionDescription:
transactionDescription ?? this.transactionDescription,
fireflyTransactionId: fireflyTransactionId ?? this.fireflyTransactionId,
fireflyTransactionIds:
fireflyTransactionIds ?? this.fireflyTransactionIds,
fireflyTransactionUrl: fireflyTransactionUrl ?? this.fireflyTransactionUrl,
fireflyTransactionUrls:
fireflyTransactionUrls ?? this.fireflyTransactionUrls,
isSubmitted: isSubmitted ?? this.isSubmitted,
submissionError: submissionError ?? this.submissionError,
submittedAt: submittedAt ?? this.submittedAt,
createdAt: createdAt ?? this.createdAt,
paymentAmount: paymentAmount ?? this.paymentAmount,
tipSourceAccountId: tipSourceAccountId ?? this.tipSourceAccountId,
tipSourceAccountName: tipSourceAccountName ?? this.tipSourceAccountName,
);
}
}