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,300 @@
import 'dart:convert';
import 'package:hive_ce/hive.dart';
import 'package:worker/core/constants/storage_constants.dart';
import 'package:worker/core/database/models/enums.dart';
part 'user_model.g.dart';
/// User Model
///
/// Hive CE model for caching user data locally.
/// Maps to the 'users' table in the database.
///
/// Type ID: 0
@HiveType(typeId: HiveTypeIds.userModel)
class UserModel extends HiveObject {
UserModel({
required this.userId,
required this.phoneNumber,
this.passwordHash,
required this.fullName,
this.email,
required this.role,
required this.status,
required this.loyaltyTier,
required this.totalPoints,
this.companyInfo,
this.cccd,
this.attachments,
this.address,
this.avatarUrl,
this.referralCode,
this.referredBy,
this.erpnextCustomerId,
required this.createdAt,
this.updatedAt,
this.lastLoginAt,
});
/// User ID (Primary Key)
@HiveField(0)
final String userId;
/// Phone number (unique, used for login)
@HiveField(1)
final String phoneNumber;
/// Password hash (stored encrypted)
@HiveField(2)
final String? passwordHash;
/// Full name of the user
@HiveField(3)
final String fullName;
/// Email address
@HiveField(4)
final String? email;
/// User role (customer, distributor, admin, staff)
@HiveField(5)
final UserRole role;
/// Account status (active, inactive, suspended, pending)
@HiveField(6)
final UserStatus status;
/// Loyalty tier (bronze, silver, gold, platinum, diamond, titan)
@HiveField(7)
final LoyaltyTier loyaltyTier;
/// Total accumulated loyalty points
@HiveField(8)
final int totalPoints;
/// Company information (JSON encoded)
/// Contains: company_name, tax_id, business_type, etc.
@HiveField(9)
final String? companyInfo;
/// Citizen ID (CCCD/CMND)
@HiveField(10)
final String? cccd;
/// Attachments (JSON encoded list)
/// Contains: identity_card_images, business_license, etc.
@HiveField(11)
final String? attachments;
/// Address
@HiveField(12)
final String? address;
/// Avatar URL
@HiveField(13)
final String? avatarUrl;
/// Referral code for this user
@HiveField(14)
final String? referralCode;
/// ID of user who referred this user
@HiveField(15)
final String? referredBy;
/// ERPNext customer ID for integration
@HiveField(16)
final String? erpnextCustomerId;
/// Account creation timestamp
@HiveField(17)
final DateTime createdAt;
/// Last update timestamp
@HiveField(18)
final DateTime? updatedAt;
/// Last login timestamp
@HiveField(19)
final DateTime? lastLoginAt;
// =========================================================================
// JSON SERIALIZATION
// =========================================================================
/// Create UserModel from JSON
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
userId: json['user_id'] as String,
phoneNumber: json['phone_number'] as String,
passwordHash: json['password_hash'] as String?,
fullName: json['full_name'] as String,
email: json['email'] as String?,
role: UserRole.values.firstWhere(
(e) => e.name == (json['role'] as String),
orElse: () => UserRole.customer,
),
status: UserStatus.values.firstWhere(
(e) => e.name == (json['status'] as String),
orElse: () => UserStatus.pending,
),
loyaltyTier: LoyaltyTier.values.firstWhere(
(e) => e.name == (json['loyalty_tier'] as String),
orElse: () => LoyaltyTier.bronze,
),
totalPoints: json['total_points'] as int? ?? 0,
companyInfo: json['company_info'] != null
? jsonEncode(json['company_info'])
: null,
cccd: json['cccd'] as String?,
attachments: json['attachments'] != null
? jsonEncode(json['attachments'])
: null,
address: json['address'] as String?,
avatarUrl: json['avatar_url'] as String?,
referralCode: json['referral_code'] as String?,
referredBy: json['referred_by'] as String?,
erpnextCustomerId: json['erpnext_customer_id'] as String?,
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: json['updated_at'] != null
? DateTime.parse(json['updated_at'] as String)
: null,
lastLoginAt: json['last_login_at'] != null
? DateTime.parse(json['last_login_at'] as String)
: null,
);
}
/// Convert UserModel to JSON
Map<String, dynamic> toJson() {
return {
'user_id': userId,
'phone_number': phoneNumber,
'password_hash': passwordHash,
'full_name': fullName,
'email': email,
'role': role.name,
'status': status.name,
'loyalty_tier': loyaltyTier.name,
'total_points': totalPoints,
'company_info': companyInfo != null ? jsonDecode(companyInfo!) : null,
'cccd': cccd,
'attachments': attachments != null ? jsonDecode(attachments!) : null,
'address': address,
'avatar_url': avatarUrl,
'referral_code': referralCode,
'referred_by': referredBy,
'erpnext_customer_id': erpnextCustomerId,
'created_at': createdAt.toIso8601String(),
'updated_at': updatedAt?.toIso8601String(),
'last_login_at': lastLoginAt?.toIso8601String(),
};
}
// =========================================================================
// HELPER METHODS
// =========================================================================
/// Get company info as Map
Map<String, dynamic>? get companyInfoMap {
if (companyInfo == null) return null;
try {
return jsonDecode(companyInfo!) as Map<String, dynamic>;
} catch (e) {
return null;
}
}
/// Get attachments as List
List<dynamic>? get attachmentsList {
if (attachments == null) return null;
try {
return jsonDecode(attachments!) as List<dynamic>;
} catch (e) {
return null;
}
}
/// Check if user is active
bool get isActive => status == UserStatus.active;
/// Check if user is admin or staff
bool get isStaff => role == UserRole.admin || role == UserRole.staff;
/// Get user initials for avatar
String get initials {
final parts = fullName.trim().split(' ');
if (parts.length >= 2) {
return '${parts.first[0]}${parts.last[0]}'.toUpperCase();
}
return fullName.isNotEmpty ? fullName[0].toUpperCase() : '?';
}
// =========================================================================
// COPY WITH
// =========================================================================
/// Create a copy with updated fields
UserModel copyWith({
String? userId,
String? phoneNumber,
String? passwordHash,
String? fullName,
String? email,
UserRole? role,
UserStatus? status,
LoyaltyTier? loyaltyTier,
int? totalPoints,
String? companyInfo,
String? cccd,
String? attachments,
String? address,
String? avatarUrl,
String? referralCode,
String? referredBy,
String? erpnextCustomerId,
DateTime? createdAt,
DateTime? updatedAt,
DateTime? lastLoginAt,
}) {
return UserModel(
userId: userId ?? this.userId,
phoneNumber: phoneNumber ?? this.phoneNumber,
passwordHash: passwordHash ?? this.passwordHash,
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
String toString() {
return 'UserModel(userId: $userId, fullName: $fullName, role: $role, tier: $loyaltyTier, points: $totalPoints)';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is UserModel && other.userId == userId;
}
@override
int get hashCode => userId.hashCode;
}