Files
worker/lib/features/account/domain/entities/payment_reminder.dart
2025-10-24 11:31:48 +07:00

180 lines
4.2 KiB
Dart

/// Domain Entity: Payment Reminder
///
/// Represents a payment reminder for an unpaid invoice.
library;
/// Reminder type enum
enum ReminderType {
/// Initial reminder before due date
initial,
/// Reminder on due date
dueDate,
/// First reminder after due date
firstOverdue,
/// Second reminder after due date
secondOverdue,
/// Final warning
finalWarning;
/// Get display name for reminder type
String get displayName {
switch (this) {
case ReminderType.initial:
return 'Initial Reminder';
case ReminderType.dueDate:
return 'Due Date Reminder';
case ReminderType.firstOverdue:
return 'First Overdue';
case ReminderType.secondOverdue:
return 'Second Overdue';
case ReminderType.finalWarning:
return 'Final Warning';
}
}
}
/// Payment Reminder Entity
///
/// Contains information about a payment reminder:
/// - Invoice reference
/// - Reminder content
/// - Delivery status
/// - Scheduling
class PaymentReminder {
/// Unique reminder identifier
final String reminderId;
/// Invoice ID this reminder is for
final String invoiceId;
/// User ID receiving the reminder
final String userId;
/// Reminder type
final ReminderType reminderType;
/// Reminder subject
final String subject;
/// Reminder message
final String message;
/// Reminder has been read
final bool isRead;
/// Reminder has been sent
final bool isSent;
/// Scheduled send timestamp
final DateTime? scheduledAt;
/// Actual send timestamp
final DateTime? sentAt;
/// Read timestamp
final DateTime? readAt;
const PaymentReminder({
required this.reminderId,
required this.invoiceId,
required this.userId,
required this.reminderType,
required this.subject,
required this.message,
required this.isRead,
required this.isSent,
this.scheduledAt,
this.sentAt,
this.readAt,
});
/// Check if reminder is pending (scheduled but not sent)
bool get isPending => !isSent && scheduledAt != null;
/// Check if reminder is overdue to be sent
bool get isOverdueToSend {
if (isSent || scheduledAt == null) return false;
return DateTime.now().isAfter(scheduledAt!);
}
/// Check if reminder is unread
bool get isUnread => !isRead;
/// Get time until scheduled send
Duration? get timeUntilSend {
if (scheduledAt == null || isSent) return null;
final duration = scheduledAt!.difference(DateTime.now());
return duration.isNegative ? null : duration;
}
/// Get time since sent
Duration? get timeSinceSent {
if (sentAt == null) return null;
return DateTime.now().difference(sentAt!);
}
/// Copy with method for immutability
PaymentReminder copyWith({
String? reminderId,
String? invoiceId,
String? userId,
ReminderType? reminderType,
String? subject,
String? message,
bool? isRead,
bool? isSent,
DateTime? scheduledAt,
DateTime? sentAt,
DateTime? readAt,
}) {
return PaymentReminder(
reminderId: reminderId ?? this.reminderId,
invoiceId: invoiceId ?? this.invoiceId,
userId: userId ?? this.userId,
reminderType: reminderType ?? this.reminderType,
subject: subject ?? this.subject,
message: message ?? this.message,
isRead: isRead ?? this.isRead,
isSent: isSent ?? this.isSent,
scheduledAt: scheduledAt ?? this.scheduledAt,
sentAt: sentAt ?? this.sentAt,
readAt: readAt ?? this.readAt,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is PaymentReminder &&
other.reminderId == reminderId &&
other.invoiceId == invoiceId &&
other.userId == userId &&
other.reminderType == reminderType &&
other.isRead == isRead &&
other.isSent == isSent;
}
@override
int get hashCode {
return Object.hash(
reminderId,
invoiceId,
userId,
reminderType,
isRead,
isSent,
);
}
@override
String toString() {
return 'PaymentReminder(reminderId: $reminderId, invoiceId: $invoiceId, '
'reminderType: $reminderType, isSent: $isSent, isRead: $isRead)';
}
}