233 lines
5.3 KiB
Dart
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)';
|
|
}
|
|
}
|