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

233 lines
5.3 KiB
Dart

/// Domain Entity: Loyalty Point Entry
///
/// Represents a single loyalty points transaction.
library;
/// Entry type enum
enum EntryType {
/// Points earned
earn,
/// Points spent/redeemed
redeem,
/// Points adjusted by admin
adjustment,
/// Points expired
expiry;
}
/// Entry source enum
enum EntrySource {
/// Points from order purchase
order,
/// Points from referral
referral,
/// Points from gift redemption
redemption,
/// Points from project submission
project,
/// Points from points record
pointsRecord,
/// Manual adjustment by admin
manual,
/// Birthday bonus
birthday,
/// Welcome bonus
welcome,
/// Other source
other;
}
/// Complaint status enum
enum ComplaintStatus {
/// No complaint
none,
/// Complaint submitted
submitted,
/// Complaint under review
reviewing,
/// Complaint approved
approved,
/// Complaint rejected
rejected;
}
/// Loyalty Point Entry Entity
///
/// Contains information about a single points transaction:
/// - Points amount (positive for earn, negative for redeem)
/// - Transaction type and source
/// - Reference to related entity
/// - Complaint handling
class LoyaltyPointEntry {
/// Unique entry identifier
final String entryId;
/// User ID
final String userId;
/// Points amount (positive for earn, negative for redeem)
final int points;
/// Entry type
final EntryType entryType;
/// Source of the points
final EntrySource source;
/// Description of the transaction
final String? description;
/// Reference ID to related entity (order ID, gift ID, etc.)
final String? referenceId;
/// Reference type (order, gift, project, etc.)
final String? referenceType;
/// Complaint details (if any)
final Map<String, dynamic>? complaint;
/// Complaint status
final ComplaintStatus complaintStatus;
/// Balance after this transaction
final int balanceAfter;
/// Points expiry date
final DateTime? expiryDate;
/// Transaction timestamp
final DateTime timestamp;
/// ERPNext entry ID
final String? erpnextEntryId;
const LoyaltyPointEntry({
required this.entryId,
required this.userId,
required this.points,
required this.entryType,
required this.source,
this.description,
this.referenceId,
this.referenceType,
this.complaint,
required this.complaintStatus,
required this.balanceAfter,
this.expiryDate,
required this.timestamp,
this.erpnextEntryId,
});
/// Check if points are earned (positive)
bool get isEarn => points > 0 && entryType == EntryType.earn;
/// Check if points are spent (negative)
bool get isRedeem => points < 0 && entryType == EntryType.redeem;
/// Check if entry has complaint
bool get hasComplaint => complaintStatus != ComplaintStatus.none;
/// Check if complaint is pending
bool get isComplaintPending =>
complaintStatus == ComplaintStatus.submitted ||
complaintStatus == ComplaintStatus.reviewing;
/// Check if points are expired
bool get isExpired {
if (expiryDate == null) return false;
return DateTime.now().isAfter(expiryDate!);
}
/// Check if points are expiring soon (within 30 days)
bool get isExpiringSoon {
if (expiryDate == null) return false;
final daysUntilExpiry = expiryDate!.difference(DateTime.now()).inDays;
return daysUntilExpiry > 0 && daysUntilExpiry <= 30;
}
/// Get absolute points value
int get absolutePoints => points.abs();
/// Copy with method for immutability
LoyaltyPointEntry copyWith({
String? entryId,
String? userId,
int? points,
EntryType? entryType,
EntrySource? source,
String? description,
String? referenceId,
String? referenceType,
Map<String, dynamic>? complaint,
ComplaintStatus? complaintStatus,
int? balanceAfter,
DateTime? expiryDate,
DateTime? timestamp,
String? erpnextEntryId,
}) {
return LoyaltyPointEntry(
entryId: entryId ?? this.entryId,
userId: userId ?? this.userId,
points: points ?? this.points,
entryType: entryType ?? this.entryType,
source: source ?? this.source,
description: description ?? this.description,
referenceId: referenceId ?? this.referenceId,
referenceType: referenceType ?? this.referenceType,
complaint: complaint ?? this.complaint,
complaintStatus: complaintStatus ?? this.complaintStatus,
balanceAfter: balanceAfter ?? this.balanceAfter,
expiryDate: expiryDate ?? this.expiryDate,
timestamp: timestamp ?? this.timestamp,
erpnextEntryId: erpnextEntryId ?? this.erpnextEntryId,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is LoyaltyPointEntry &&
other.entryId == entryId &&
other.userId == userId &&
other.points == points &&
other.entryType == entryType &&
other.source == source &&
other.balanceAfter == balanceAfter;
}
@override
int get hashCode {
return Object.hash(
entryId,
userId,
points,
entryType,
source,
balanceAfter,
);
}
@override
String toString() {
return 'LoyaltyPointEntry(entryId: $entryId, userId: $userId, points: $points, '
'entryType: $entryType, source: $source, balanceAfter: $balanceAfter, '
'timestamp: $timestamp)';
}
}