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,47 @@
import 'dart:convert';
import 'package:hive_ce/hive.dart';
import 'package:worker/core/constants/storage_constants.dart';
part 'audit_log_model.g.dart';
@HiveType(typeId: HiveTypeIds.auditLogModel)
class AuditLogModel extends HiveObject {
AuditLogModel({required this.logId, required this.userId, required this.action, required this.entityType, required this.entityId, this.oldValue, this.newValue, this.ipAddress, this.userAgent, required this.timestamp});
@HiveField(0) final int logId;
@HiveField(1) final String userId;
@HiveField(2) final String action;
@HiveField(3) final String entityType;
@HiveField(4) final String entityId;
@HiveField(5) final String? oldValue;
@HiveField(6) final String? newValue;
@HiveField(7) final String? ipAddress;
@HiveField(8) final String? userAgent;
@HiveField(9) final DateTime timestamp;
factory AuditLogModel.fromJson(Map<String, dynamic> json) => AuditLogModel(
logId: json['log_id'] as int,
userId: json['user_id'] as String,
action: json['action'] as String,
entityType: json['entity_type'] as String,
entityId: json['entity_id'] as String,
oldValue: json['old_value'] != null ? jsonEncode(json['old_value']) : null,
newValue: json['new_value'] != null ? jsonEncode(json['new_value']) : null,
ipAddress: json['ip_address'] as String?,
userAgent: json['user_agent'] as String?,
timestamp: DateTime.parse(json['timestamp'] as String),
);
Map<String, dynamic> toJson() => {
'log_id': logId,
'user_id': userId,
'action': action,
'entity_type': entityType,
'entity_id': entityId,
'old_value': oldValue != null ? jsonDecode(oldValue!) : null,
'new_value': newValue != null ? jsonDecode(newValue!) : null,
'ip_address': ipAddress,
'user_agent': userAgent,
'timestamp': timestamp.toIso8601String(),
};
}

View File

@@ -0,0 +1,68 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'audit_log_model.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class AuditLogModelAdapter extends TypeAdapter<AuditLogModel> {
@override
final typeId = 24;
@override
AuditLogModel read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return AuditLogModel(
logId: (fields[0] as num).toInt(),
userId: fields[1] as String,
action: fields[2] as String,
entityType: fields[3] as String,
entityId: fields[4] as String,
oldValue: fields[5] as String?,
newValue: fields[6] as String?,
ipAddress: fields[7] as String?,
userAgent: fields[8] as String?,
timestamp: fields[9] as DateTime,
);
}
@override
void write(BinaryWriter writer, AuditLogModel obj) {
writer
..writeByte(10)
..writeByte(0)
..write(obj.logId)
..writeByte(1)
..write(obj.userId)
..writeByte(2)
..write(obj.action)
..writeByte(3)
..write(obj.entityType)
..writeByte(4)
..write(obj.entityId)
..writeByte(5)
..write(obj.oldValue)
..writeByte(6)
..write(obj.newValue)
..writeByte(7)
..write(obj.ipAddress)
..writeByte(8)
..write(obj.userAgent)
..writeByte(9)
..write(obj.timestamp);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is AuditLogModelAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@@ -0,0 +1,50 @@
import 'package:hive_ce/hive.dart';
import 'package:worker/core/constants/storage_constants.dart';
import 'package:worker/core/database/models/enums.dart';
part 'payment_reminder_model.g.dart';
@HiveType(typeId: HiveTypeIds.paymentReminderModel)
class PaymentReminderModel extends HiveObject {
PaymentReminderModel({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});
@HiveField(0) final String reminderId;
@HiveField(1) final String invoiceId;
@HiveField(2) final String userId;
@HiveField(3) final ReminderType reminderType;
@HiveField(4) final String subject;
@HiveField(5) final String message;
@HiveField(6) final bool isRead;
@HiveField(7) final bool isSent;
@HiveField(8) final DateTime? scheduledAt;
@HiveField(9) final DateTime? sentAt;
@HiveField(10) final DateTime? readAt;
factory PaymentReminderModel.fromJson(Map<String, dynamic> json) => PaymentReminderModel(
reminderId: json['reminder_id'] as String,
invoiceId: json['invoice_id'] as String,
userId: json['user_id'] as String,
reminderType: ReminderType.values.firstWhere((e) => e.name == json['reminder_type']),
subject: json['subject'] as String,
message: json['message'] as String,
isRead: json['is_read'] as bool? ?? false,
isSent: json['is_sent'] as bool? ?? false,
scheduledAt: json['scheduled_at'] != null ? DateTime.parse(json['scheduled_at']?.toString() ?? '') : null,
sentAt: json['sent_at'] != null ? DateTime.parse(json['sent_at']?.toString() ?? '') : null,
readAt: json['read_at'] != null ? DateTime.parse(json['read_at']?.toString() ?? '') : null,
);
Map<String, dynamic> toJson() => {
'reminder_id': reminderId,
'invoice_id': invoiceId,
'user_id': userId,
'reminder_type': reminderType.name,
'subject': subject,
'message': message,
'is_read': isRead,
'is_sent': isSent,
'scheduled_at': scheduledAt?.toIso8601String(),
'sent_at': sentAt?.toIso8601String(),
'read_at': readAt?.toIso8601String(),
};
}

View File

@@ -0,0 +1,71 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'payment_reminder_model.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class PaymentReminderModelAdapter extends TypeAdapter<PaymentReminderModel> {
@override
final typeId = 23;
@override
PaymentReminderModel read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return PaymentReminderModel(
reminderId: fields[0] as String,
invoiceId: fields[1] as String,
userId: fields[2] as String,
reminderType: fields[3] as ReminderType,
subject: fields[4] as String,
message: fields[5] as String,
isRead: fields[6] as bool,
isSent: fields[7] as bool,
scheduledAt: fields[8] as DateTime?,
sentAt: fields[9] as DateTime?,
readAt: fields[10] as DateTime?,
);
}
@override
void write(BinaryWriter writer, PaymentReminderModel obj) {
writer
..writeByte(11)
..writeByte(0)
..write(obj.reminderId)
..writeByte(1)
..write(obj.invoiceId)
..writeByte(2)
..write(obj.userId)
..writeByte(3)
..write(obj.reminderType)
..writeByte(4)
..write(obj.subject)
..writeByte(5)
..write(obj.message)
..writeByte(6)
..write(obj.isRead)
..writeByte(7)
..write(obj.isSent)
..writeByte(8)
..write(obj.scheduledAt)
..writeByte(9)
..write(obj.sentAt)
..writeByte(10)
..write(obj.readAt);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is PaymentReminderModelAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@@ -0,0 +1,151 @@
/// Domain Entity: Audit Log
///
/// Represents an audit trail entry for system activities.
library;
/// Audit Log Entity
///
/// Contains information about a system action:
/// - User and action details
/// - Entity affected
/// - Change tracking
/// - Session information
class AuditLog {
/// Unique log identifier
final String logId;
/// User ID who performed the action
final String? userId;
/// Action performed (create, update, delete, login, etc.)
final String action;
/// Entity type affected (user, order, product, etc.)
final String? entityType;
/// Entity ID affected
final String? entityId;
/// Old value (before change)
final Map<String, dynamic>? oldValue;
/// New value (after change)
final Map<String, dynamic>? newValue;
/// IP address of the user
final String? ipAddress;
/// User agent string
final String? userAgent;
/// Timestamp of the action
final DateTime timestamp;
const AuditLog({
required this.logId,
this.userId,
required this.action,
this.entityType,
this.entityId,
this.oldValue,
this.newValue,
this.ipAddress,
this.userAgent,
required this.timestamp,
});
/// Check if log has old value
bool get hasOldValue => oldValue != null && oldValue!.isNotEmpty;
/// Check if log has new value
bool get hasNewValue => newValue != null && newValue!.isNotEmpty;
/// Check if action is create
bool get isCreate => action.toLowerCase() == 'create';
/// Check if action is update
bool get isUpdate => action.toLowerCase() == 'update';
/// Check if action is delete
bool get isDelete => action.toLowerCase() == 'delete';
/// Check if action is login
bool get isLogin => action.toLowerCase() == 'login';
/// Check if action is logout
bool get isLogout => action.toLowerCase() == 'logout';
/// Get changed fields
List<String> get changedFields {
if (!hasOldValue || !hasNewValue) return [];
final changed = <String>[];
for (final key in newValue!.keys) {
if (oldValue!.containsKey(key) && oldValue![key] != newValue![key]) {
changed.add(key);
}
}
return changed;
}
/// Get time since action
Duration get timeSinceAction {
return DateTime.now().difference(timestamp);
}
/// Copy with method for immutability
AuditLog copyWith({
String? logId,
String? userId,
String? action,
String? entityType,
String? entityId,
Map<String, dynamic>? oldValue,
Map<String, dynamic>? newValue,
String? ipAddress,
String? userAgent,
DateTime? timestamp,
}) {
return AuditLog(
logId: logId ?? this.logId,
userId: userId ?? this.userId,
action: action ?? this.action,
entityType: entityType ?? this.entityType,
entityId: entityId ?? this.entityId,
oldValue: oldValue ?? this.oldValue,
newValue: newValue ?? this.newValue,
ipAddress: ipAddress ?? this.ipAddress,
userAgent: userAgent ?? this.userAgent,
timestamp: timestamp ?? this.timestamp,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is AuditLog &&
other.logId == logId &&
other.userId == userId &&
other.action == action &&
other.entityType == entityType &&
other.entityId == entityId;
}
@override
int get hashCode {
return Object.hash(
logId,
userId,
action,
entityType,
entityId,
);
}
@override
String toString() {
return 'AuditLog(logId: $logId, userId: $userId, action: $action, '
'entityType: $entityType, entityId: $entityId, timestamp: $timestamp)';
}
}

View File

@@ -0,0 +1,179 @@
/// 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)';
}
}