update database

This commit is contained in:
Phuoc Nguyen
2025-10-24 11:31:48 +07:00
parent f95fa9d0a6
commit c4272f9a21
126 changed files with 23528 additions and 2234 deletions

View File

@@ -0,0 +1,314 @@
/// Domain Entity: User
///
/// Represents a user account in the Worker application.
/// Contains authentication, profile, and loyalty information.
library;
/// User role enum
enum UserRole {
/// Customer/worker user
customer,
/// Sales representative
sales,
/// System administrator
admin,
/// Accountant
accountant,
/// Designer
designer;
}
/// User status enum
enum UserStatus {
/// Account pending approval
pending,
/// Active account
active,
/// Suspended account
suspended,
/// Rejected account
rejected;
}
/// Loyalty tier enum
enum LoyaltyTier {
/// No tier
none,
/// Gold tier (entry level)
gold,
/// Platinum tier (mid level)
platinum,
/// Diamond tier (highest level)
diamond;
/// Get display name for tier
String get displayName {
switch (this) {
case LoyaltyTier.none:
return 'NONE';
case LoyaltyTier.gold:
return 'GOLD';
case LoyaltyTier.platinum:
return 'PLATINUM';
case LoyaltyTier.diamond:
return 'DIAMOND';
}
}
}
/// Company information
class CompanyInfo {
/// Company name
final String? name;
/// Tax identification number
final String? taxId;
/// Company address
final String? address;
/// Business type
final String? businessType;
/// Business license number
final String? licenseNumber;
const CompanyInfo({
this.name,
this.taxId,
this.address,
this.businessType,
this.licenseNumber,
});
/// Create from JSON map
factory CompanyInfo.fromJson(Map<String, dynamic> json) {
return CompanyInfo(
name: json['name'] as String?,
taxId: json['tax_id'] as String?,
address: json['address'] as String?,
businessType: json['business_type'] as String?,
licenseNumber: json['license_number'] as String?,
);
}
/// Convert to JSON map
Map<String, dynamic> toJson() {
return {
'name': name,
'tax_id': taxId,
'address': address,
'business_type': businessType,
'license_number': licenseNumber,
};
}
}
/// User Entity
///
/// Represents a complete user profile including:
/// - Authentication credentials
/// - Personal information
/// - Company details (if applicable)
/// - Loyalty program membership
/// - Referral information
class User {
/// Unique user identifier
final String userId;
/// Phone number (used for login)
final String phoneNumber;
/// Full name
final String fullName;
/// Email address
final String? email;
/// User role
final UserRole role;
/// Account status
final UserStatus status;
/// Current loyalty tier
final LoyaltyTier loyaltyTier;
/// Total loyalty points
final int totalPoints;
/// Company information (optional)
final CompanyInfo? companyInfo;
/// CCCD/ID card number
final String? cccd;
/// Attachment URLs (ID cards, licenses, etc.)
final List<String> attachments;
/// Address
final String? address;
/// Avatar URL
final String? avatarUrl;
/// Referral code (unique for this user)
final String? referralCode;
/// ID of user who referred this user
final String? referredBy;
/// ERPNext customer ID
final String? erpnextCustomerId;
/// Account creation timestamp
final DateTime createdAt;
/// Last update timestamp
final DateTime updatedAt;
/// Last login timestamp
final DateTime? lastLoginAt;
const User({
required this.userId,
required this.phoneNumber,
required this.fullName,
this.email,
required this.role,
required this.status,
required this.loyaltyTier,
required this.totalPoints,
this.companyInfo,
this.cccd,
required this.attachments,
this.address,
this.avatarUrl,
this.referralCode,
this.referredBy,
this.erpnextCustomerId,
required this.createdAt,
required this.updatedAt,
this.lastLoginAt,
});
/// Check if user is active
bool get isActive => status == UserStatus.active;
/// Check if user is pending approval
bool get isPending => status == UserStatus.pending;
/// Check if user has company info
bool get hasCompanyInfo => companyInfo != null && companyInfo!.name != null;
/// Check if user is an admin
bool get isAdmin => role == UserRole.admin;
/// Check if user is a customer
bool get isCustomer => role == UserRole.customer;
/// Get display name for user
String get displayName => fullName;
/// Copy with method for immutability
User copyWith({
String? userId,
String? phoneNumber,
String? fullName,
String? email,
UserRole? role,
UserStatus? status,
LoyaltyTier? loyaltyTier,
int? totalPoints,
CompanyInfo? companyInfo,
String? cccd,
List<String>? attachments,
String? address,
String? avatarUrl,
String? referralCode,
String? referredBy,
String? erpnextCustomerId,
DateTime? createdAt,
DateTime? updatedAt,
DateTime? lastLoginAt,
}) {
return User(
userId: userId ?? this.userId,
phoneNumber: phoneNumber ?? this.phoneNumber,
fullName: fullName ?? this.fullName,
email: email ?? this.email,
role: role ?? this.role,
status: status ?? this.status,
loyaltyTier: loyaltyTier ?? this.loyaltyTier,
totalPoints: totalPoints ?? this.totalPoints,
companyInfo: companyInfo ?? this.companyInfo,
cccd: cccd ?? this.cccd,
attachments: attachments ?? this.attachments,
address: address ?? this.address,
avatarUrl: avatarUrl ?? this.avatarUrl,
referralCode: referralCode ?? this.referralCode,
referredBy: referredBy ?? this.referredBy,
erpnextCustomerId: erpnextCustomerId ?? this.erpnextCustomerId,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
lastLoginAt: lastLoginAt ?? this.lastLoginAt,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is User &&
other.userId == userId &&
other.phoneNumber == phoneNumber &&
other.fullName == fullName &&
other.email == email &&
other.role == role &&
other.status == status &&
other.loyaltyTier == loyaltyTier &&
other.totalPoints == totalPoints &&
other.cccd == cccd &&
other.address == address &&
other.avatarUrl == avatarUrl &&
other.referralCode == referralCode &&
other.referredBy == referredBy &&
other.erpnextCustomerId == erpnextCustomerId;
}
@override
int get hashCode {
return Object.hash(
userId,
phoneNumber,
fullName,
email,
role,
status,
loyaltyTier,
totalPoints,
cccd,
address,
avatarUrl,
referralCode,
referredBy,
erpnextCustomerId,
);
}
@override
String toString() {
return 'User(userId: $userId, phoneNumber: $phoneNumber, fullName: $fullName, '
'role: $role, status: $status, loyaltyTier: $loyaltyTier, totalPoints: $totalPoints)';
}
}

View File

@@ -0,0 +1,142 @@
/// Domain Entity: User Session
///
/// Represents an active user session with device and authentication information.
library;
/// User Session Entity
///
/// Contains information about an active user session:
/// - Device details
/// - Authentication tokens
/// - Session timing
class UserSession {
/// Unique session identifier
final String sessionId;
/// User ID associated with this session
final String userId;
/// Unique device identifier
final String deviceId;
/// Device type (ios, android, web)
final String? deviceType;
/// Device name
final String? deviceName;
/// IP address
final String? ipAddress;
/// User agent string
final String? userAgent;
/// Refresh token for renewing access
final String? refreshToken;
/// Session expiration timestamp
final DateTime expiresAt;
/// Session creation timestamp
final DateTime createdAt;
/// Last activity timestamp
final DateTime? lastActivity;
const UserSession({
required this.sessionId,
required this.userId,
required this.deviceId,
this.deviceType,
this.deviceName,
this.ipAddress,
this.userAgent,
this.refreshToken,
required this.expiresAt,
required this.createdAt,
this.lastActivity,
});
/// Check if session is expired
bool get isExpired => DateTime.now().isAfter(expiresAt);
/// Check if session is expiring soon (within 1 hour)
bool get isExpiringSoon {
final hoursUntilExpiry = expiresAt.difference(DateTime.now()).inHours;
return hoursUntilExpiry > 0 && hoursUntilExpiry <= 1;
}
/// Check if session is active
bool get isActive => !isExpired;
/// Get device display name
String get deviceDisplayName => deviceName ?? deviceType ?? 'Unknown Device';
/// Get time since last activity
Duration? get timeSinceLastActivity {
if (lastActivity == null) return null;
return DateTime.now().difference(lastActivity!);
}
/// Copy with method for immutability
UserSession copyWith({
String? sessionId,
String? userId,
String? deviceId,
String? deviceType,
String? deviceName,
String? ipAddress,
String? userAgent,
String? refreshToken,
DateTime? expiresAt,
DateTime? createdAt,
DateTime? lastActivity,
}) {
return UserSession(
sessionId: sessionId ?? this.sessionId,
userId: userId ?? this.userId,
deviceId: deviceId ?? this.deviceId,
deviceType: deviceType ?? this.deviceType,
deviceName: deviceName ?? this.deviceName,
ipAddress: ipAddress ?? this.ipAddress,
userAgent: userAgent ?? this.userAgent,
refreshToken: refreshToken ?? this.refreshToken,
expiresAt: expiresAt ?? this.expiresAt,
createdAt: createdAt ?? this.createdAt,
lastActivity: lastActivity ?? this.lastActivity,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is UserSession &&
other.sessionId == sessionId &&
other.userId == userId &&
other.deviceId == deviceId &&
other.deviceType == deviceType &&
other.deviceName == deviceName &&
other.ipAddress == ipAddress &&
other.refreshToken == refreshToken;
}
@override
int get hashCode {
return Object.hash(
sessionId,
userId,
deviceId,
deviceType,
deviceName,
ipAddress,
refreshToken,
);
}
@override
String toString() {
return 'UserSession(sessionId: $sessionId, userId: $userId, deviceId: $deviceId, '
'deviceType: $deviceType, expiresAt: $expiresAt, isActive: $isActive)';
}
}