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,78 @@
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 'design_request_model.g.dart';
@HiveType(typeId: HiveTypeIds.designRequestModel)
class DesignRequestModel extends HiveObject {
DesignRequestModel({required this.requestId, required this.userId, required this.projectName, required this.projectType, required this.area, required this.style, required this.budget, required this.currentSituation, required this.requirements, this.notes, this.attachments, required this.status, this.assignedDesigner, this.finalDesignLink, this.feedback, this.rating, this.estimatedCompletion, required this.createdAt, this.completedAt, this.updatedAt});
@HiveField(0) final String requestId;
@HiveField(1) final String userId;
@HiveField(2) final String projectName;
@HiveField(3) final ProjectType projectType;
@HiveField(4) final double area;
@HiveField(5) final String style;
@HiveField(6) final double budget;
@HiveField(7) final String currentSituation;
@HiveField(8) final String requirements;
@HiveField(9) final String? notes;
@HiveField(10) final String? attachments;
@HiveField(11) final DesignStatus status;
@HiveField(12) final String? assignedDesigner;
@HiveField(13) final String? finalDesignLink;
@HiveField(14) final String? feedback;
@HiveField(15) final int? rating;
@HiveField(16) final DateTime? estimatedCompletion;
@HiveField(17) final DateTime createdAt;
@HiveField(18) final DateTime? completedAt;
@HiveField(19) final DateTime? updatedAt;
factory DesignRequestModel.fromJson(Map<String, dynamic> json) => DesignRequestModel(
requestId: json['request_id'] as String,
userId: json['user_id'] as String,
projectName: json['project_name'] as String,
projectType: ProjectType.values.firstWhere((e) => e.name == json['project_type']),
area: (json['area'] as num).toDouble(),
style: json['style'] as String,
budget: (json['budget'] as num).toDouble(),
currentSituation: json['current_situation'] as String,
requirements: json['requirements'] as String,
notes: json['notes'] as String?,
attachments: json['attachments'] != null ? jsonEncode(json['attachments']) : null,
status: DesignStatus.values.firstWhere((e) => e.name == json['status']),
assignedDesigner: json['assigned_designer'] as String?,
finalDesignLink: json['final_design_link'] as String?,
feedback: json['feedback'] as String?,
rating: json['rating'] as int?,
estimatedCompletion: json['estimated_completion'] != null ? DateTime.parse(json['estimated_completion']?.toString() ?? '') : null,
createdAt: DateTime.parse(json['created_at']?.toString() ?? ''),
completedAt: json['completed_at'] != null ? DateTime.parse(json['completed_at']?.toString() ?? '') : null,
updatedAt: json['updated_at'] != null ? DateTime.parse(json['updated_at']?.toString() ?? '') : null,
);
Map<String, dynamic> toJson() => {
'request_id': requestId,
'user_id': userId,
'project_name': projectName,
'project_type': projectType.name,
'area': area,
'style': style,
'budget': budget,
'current_situation': currentSituation,
'requirements': requirements,
'notes': notes,
'attachments': attachments != null ? jsonDecode(attachments!) : null,
'status': status.name,
'assigned_designer': assignedDesigner,
'final_design_link': finalDesignLink,
'feedback': feedback,
'rating': rating,
'estimated_completion': estimatedCompletion?.toIso8601String(),
'created_at': createdAt.toIso8601String(),
'completed_at': completedAt?.toIso8601String(),
'updated_at': updatedAt?.toIso8601String(),
};
}

View File

@@ -0,0 +1,98 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'design_request_model.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class DesignRequestModelAdapter extends TypeAdapter<DesignRequestModel> {
@override
final typeId = 15;
@override
DesignRequestModel read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return DesignRequestModel(
requestId: fields[0] as String,
userId: fields[1] as String,
projectName: fields[2] as String,
projectType: fields[3] as ProjectType,
area: (fields[4] as num).toDouble(),
style: fields[5] as String,
budget: (fields[6] as num).toDouble(),
currentSituation: fields[7] as String,
requirements: fields[8] as String,
notes: fields[9] as String?,
attachments: fields[10] as String?,
status: fields[11] as DesignStatus,
assignedDesigner: fields[12] as String?,
finalDesignLink: fields[13] as String?,
feedback: fields[14] as String?,
rating: (fields[15] as num?)?.toInt(),
estimatedCompletion: fields[16] as DateTime?,
createdAt: fields[17] as DateTime,
completedAt: fields[18] as DateTime?,
updatedAt: fields[19] as DateTime?,
);
}
@override
void write(BinaryWriter writer, DesignRequestModel obj) {
writer
..writeByte(20)
..writeByte(0)
..write(obj.requestId)
..writeByte(1)
..write(obj.userId)
..writeByte(2)
..write(obj.projectName)
..writeByte(3)
..write(obj.projectType)
..writeByte(4)
..write(obj.area)
..writeByte(5)
..write(obj.style)
..writeByte(6)
..write(obj.budget)
..writeByte(7)
..write(obj.currentSituation)
..writeByte(8)
..write(obj.requirements)
..writeByte(9)
..write(obj.notes)
..writeByte(10)
..write(obj.attachments)
..writeByte(11)
..write(obj.status)
..writeByte(12)
..write(obj.assignedDesigner)
..writeByte(13)
..write(obj.finalDesignLink)
..writeByte(14)
..write(obj.feedback)
..writeByte(15)
..write(obj.rating)
..writeByte(16)
..write(obj.estimatedCompletion)
..writeByte(17)
..write(obj.createdAt)
..writeByte(18)
..write(obj.completedAt)
..writeByte(19)
..write(obj.updatedAt);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is DesignRequestModelAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@@ -0,0 +1,86 @@
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 'project_submission_model.g.dart';
@HiveType(typeId: HiveTypeIds.projectSubmissionModel)
class ProjectSubmissionModel extends HiveObject {
ProjectSubmissionModel({required this.submissionId, required this.userId, required this.projectName, required this.projectAddress, required this.projectValue, required this.projectType, this.beforePhotos, this.afterPhotos, this.invoices, required this.status, this.reviewNotes, this.rejectionReason, this.pointsEarned, required this.submittedAt, this.reviewedAt, this.reviewedBy});
@HiveField(0) final String submissionId;
@HiveField(1) final String userId;
@HiveField(2) final String projectName;
@HiveField(3) final String projectAddress;
@HiveField(4) final double projectValue;
@HiveField(5) final ProjectType projectType;
@HiveField(6) final String? beforePhotos;
@HiveField(7) final String? afterPhotos;
@HiveField(8) final String? invoices;
@HiveField(9) final SubmissionStatus status;
@HiveField(10) final String? reviewNotes;
@HiveField(11) final String? rejectionReason;
@HiveField(12) final int? pointsEarned;
@HiveField(13) final DateTime submittedAt;
@HiveField(14) final DateTime? reviewedAt;
@HiveField(15) final String? reviewedBy;
factory ProjectSubmissionModel.fromJson(Map<String, dynamic> json) => ProjectSubmissionModel(
submissionId: json['submission_id'] as String,
userId: json['user_id'] as String,
projectName: json['project_name'] as String,
projectAddress: json['project_address'] as String,
projectValue: (json['project_value'] as num).toDouble(),
projectType: ProjectType.values.firstWhere((e) => e.name == json['project_type']),
beforePhotos: json['before_photos'] != null ? jsonEncode(json['before_photos']) : null,
afterPhotos: json['after_photos'] != null ? jsonEncode(json['after_photos']) : null,
invoices: json['invoices'] != null ? jsonEncode(json['invoices']) : null,
status: SubmissionStatus.values.firstWhere((e) => e.name == json['status']),
reviewNotes: json['review_notes'] as String?,
rejectionReason: json['rejection_reason'] as String?,
pointsEarned: json['points_earned'] as int?,
submittedAt: DateTime.parse(json['submitted_at']?.toString() ?? ''),
reviewedAt: json['reviewed_at'] != null ? DateTime.parse(json['reviewed_at']?.toString() ?? '') : null,
reviewedBy: json['reviewed_by'] as String?,
);
Map<String, dynamic> toJson() => {
'submission_id': submissionId,
'user_id': userId,
'project_name': projectName,
'project_address': projectAddress,
'project_value': projectValue,
'project_type': projectType.name,
'before_photos': beforePhotos != null ? jsonDecode(beforePhotos!) : null,
'after_photos': afterPhotos != null ? jsonDecode(afterPhotos!) : null,
'invoices': invoices != null ? jsonDecode(invoices!) : null,
'status': status.name,
'review_notes': reviewNotes,
'rejection_reason': rejectionReason,
'points_earned': pointsEarned,
'submitted_at': submittedAt.toIso8601String(),
'reviewed_at': reviewedAt?.toIso8601String(),
'reviewed_by': reviewedBy,
};
List<String>? get beforePhotosList {
if (beforePhotos == null) return null;
try {
final decoded = jsonDecode(beforePhotos!) as List;
return decoded.map((e) => e.toString()).toList();
} catch (e) {
return null;
}
}
List<String>? get afterPhotosList {
if (afterPhotos == null) return null;
try {
final decoded = jsonDecode(afterPhotos!) as List;
return decoded.map((e) => e.toString()).toList();
} catch (e) {
return null;
}
}
}

View File

@@ -0,0 +1,87 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'project_submission_model.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class ProjectSubmissionModelAdapter
extends TypeAdapter<ProjectSubmissionModel> {
@override
final typeId = 14;
@override
ProjectSubmissionModel read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return ProjectSubmissionModel(
submissionId: fields[0] as String,
userId: fields[1] as String,
projectName: fields[2] as String,
projectAddress: fields[3] as String,
projectValue: (fields[4] as num).toDouble(),
projectType: fields[5] as ProjectType,
beforePhotos: fields[6] as String?,
afterPhotos: fields[7] as String?,
invoices: fields[8] as String?,
status: fields[9] as SubmissionStatus,
reviewNotes: fields[10] as String?,
rejectionReason: fields[11] as String?,
pointsEarned: (fields[12] as num?)?.toInt(),
submittedAt: fields[13] as DateTime,
reviewedAt: fields[14] as DateTime?,
reviewedBy: fields[15] as String?,
);
}
@override
void write(BinaryWriter writer, ProjectSubmissionModel obj) {
writer
..writeByte(16)
..writeByte(0)
..write(obj.submissionId)
..writeByte(1)
..write(obj.userId)
..writeByte(2)
..write(obj.projectName)
..writeByte(3)
..write(obj.projectAddress)
..writeByte(4)
..write(obj.projectValue)
..writeByte(5)
..write(obj.projectType)
..writeByte(6)
..write(obj.beforePhotos)
..writeByte(7)
..write(obj.afterPhotos)
..writeByte(8)
..write(obj.invoices)
..writeByte(9)
..write(obj.status)
..writeByte(10)
..write(obj.reviewNotes)
..writeByte(11)
..write(obj.rejectionReason)
..writeByte(12)
..write(obj.pointsEarned)
..writeByte(13)
..write(obj.submittedAt)
..writeByte(14)
..write(obj.reviewedAt)
..writeByte(15)
..write(obj.reviewedBy);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ProjectSubmissionModelAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@@ -0,0 +1,249 @@
/// Domain Entity: Design Request
///
/// Represents a request for design consultation service.
library;
import 'project_submission.dart';
/// Design status enum
enum DesignStatus {
/// Request submitted, pending assignment
pending,
/// Assigned to designer
assigned,
/// Design in progress
inProgress,
/// Design completed
completed,
/// Request cancelled
cancelled;
/// Get display name for status
String get displayName {
switch (this) {
case DesignStatus.pending:
return 'Pending';
case DesignStatus.assigned:
return 'Assigned';
case DesignStatus.inProgress:
return 'In Progress';
case DesignStatus.completed:
return 'Completed';
case DesignStatus.cancelled:
return 'Cancelled';
}
}
}
/// Design Request Entity
///
/// Contains information about a design consultation request:
/// - Project requirements
/// - Design preferences
/// - Budget constraints
/// - Assignment and tracking
class DesignRequest {
/// Unique request identifier
final String requestId;
/// User ID who requested
final String userId;
/// Project name
final String projectName;
/// Project type
final ProjectType projectType;
/// Project area (square meters)
final double area;
/// Design style preference
final String? style;
/// Budget for design/construction
final double? budget;
/// Current situation description
final String? currentSituation;
/// Requirements and wishes
final String? requirements;
/// Additional notes
final String? notes;
/// Attachment URLs (photos, references)
final List<String> attachments;
/// Request status
final DesignStatus status;
/// Assigned designer name
final String? assignedDesigner;
/// Final design link/URL
final String? finalDesignLink;
/// User feedback
final String? feedback;
/// User rating (1-5)
final int? rating;
/// Estimated completion date
final DateTime? estimatedCompletion;
/// Request creation timestamp
final DateTime createdAt;
/// Completion timestamp
final DateTime? completedAt;
/// Last update timestamp
final DateTime updatedAt;
const DesignRequest({
required this.requestId,
required this.userId,
required this.projectName,
required this.projectType,
required this.area,
this.style,
this.budget,
this.currentSituation,
this.requirements,
this.notes,
required this.attachments,
required this.status,
this.assignedDesigner,
this.finalDesignLink,
this.feedback,
this.rating,
this.estimatedCompletion,
required this.createdAt,
this.completedAt,
required this.updatedAt,
});
/// Check if request is pending
bool get isPending => status == DesignStatus.pending;
/// Check if request is assigned
bool get isAssigned =>
status == DesignStatus.assigned || status == DesignStatus.inProgress;
/// Check if request is in progress
bool get isInProgress => status == DesignStatus.inProgress;
/// Check if request is completed
bool get isCompleted => status == DesignStatus.completed;
/// Check if request is cancelled
bool get isCancelled => status == DesignStatus.cancelled;
/// Check if request has attachments
bool get hasAttachments => attachments.isNotEmpty;
/// Check if design is ready
bool get hasDesign =>
finalDesignLink != null && finalDesignLink!.isNotEmpty;
/// Check if user has provided feedback
bool get hasFeedback => feedback != null || rating != null;
/// Get completion duration
Duration? get completionDuration {
if (completedAt == null) return null;
return completedAt!.difference(createdAt);
}
/// Check if overdue
bool get isOverdue {
if (estimatedCompletion == null || isCompleted || isCancelled) {
return false;
}
return DateTime.now().isAfter(estimatedCompletion!);
}
/// Copy with method for immutability
DesignRequest copyWith({
String? requestId,
String? userId,
String? projectName,
ProjectType? projectType,
double? area,
String? style,
double? budget,
String? currentSituation,
String? requirements,
String? notes,
List<String>? attachments,
DesignStatus? status,
String? assignedDesigner,
String? finalDesignLink,
String? feedback,
int? rating,
DateTime? estimatedCompletion,
DateTime? createdAt,
DateTime? completedAt,
DateTime? updatedAt,
}) {
return DesignRequest(
requestId: requestId ?? this.requestId,
userId: userId ?? this.userId,
projectName: projectName ?? this.projectName,
projectType: projectType ?? this.projectType,
area: area ?? this.area,
style: style ?? this.style,
budget: budget ?? this.budget,
currentSituation: currentSituation ?? this.currentSituation,
requirements: requirements ?? this.requirements,
notes: notes ?? this.notes,
attachments: attachments ?? this.attachments,
status: status ?? this.status,
assignedDesigner: assignedDesigner ?? this.assignedDesigner,
finalDesignLink: finalDesignLink ?? this.finalDesignLink,
feedback: feedback ?? this.feedback,
rating: rating ?? this.rating,
estimatedCompletion: estimatedCompletion ?? this.estimatedCompletion,
createdAt: createdAt ?? this.createdAt,
completedAt: completedAt ?? this.completedAt,
updatedAt: updatedAt ?? this.updatedAt,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is DesignRequest &&
other.requestId == requestId &&
other.userId == userId &&
other.projectName == projectName &&
other.area == area &&
other.status == status;
}
@override
int get hashCode {
return Object.hash(
requestId,
userId,
projectName,
area,
status,
);
}
@override
String toString() {
return 'DesignRequest(requestId: $requestId, projectName: $projectName, '
'projectType: $projectType, area: $area, status: $status, '
'assignedDesigner: $assignedDesigner)';
}
}

View File

@@ -0,0 +1,247 @@
/// Domain Entity: Project Submission
///
/// Represents a completed project submitted for loyalty points.
library;
/// Project type enum
enum ProjectType {
/// Residential project
residential,
/// Commercial project
commercial,
/// Industrial project
industrial,
/// Public infrastructure
infrastructure,
/// Other type
other;
/// Get display name for project type
String get displayName {
switch (this) {
case ProjectType.residential:
return 'Residential';
case ProjectType.commercial:
return 'Commercial';
case ProjectType.industrial:
return 'Industrial';
case ProjectType.infrastructure:
return 'Infrastructure';
case ProjectType.other:
return 'Other';
}
}
}
/// Submission status enum
enum SubmissionStatus {
/// Submitted, pending review
pending,
/// Under review
reviewing,
/// Approved, points awarded
approved,
/// Rejected
rejected;
/// Get display name for status
String get displayName {
switch (this) {
case SubmissionStatus.pending:
return 'Pending';
case SubmissionStatus.reviewing:
return 'Reviewing';
case SubmissionStatus.approved:
return 'Approved';
case SubmissionStatus.rejected:
return 'Rejected';
}
}
}
/// Project Submission Entity
///
/// Contains information about a completed project:
/// - Project details
/// - Before/after photos
/// - Invoice documentation
/// - Review status
/// - Points earned
class ProjectSubmission {
/// Unique submission identifier
final String submissionId;
/// User ID who submitted
final String userId;
/// Project name
final String projectName;
/// Project address/location
final String? projectAddress;
/// Project value/cost
final double projectValue;
/// Project type
final ProjectType projectType;
/// Before photos URLs
final List<String> beforePhotos;
/// After photos URLs
final List<String> afterPhotos;
/// Invoice/receipt URLs
final List<String> invoices;
/// Submission status
final SubmissionStatus status;
/// Review notes from admin
final String? reviewNotes;
/// Rejection reason (if rejected)
final String? rejectionReason;
/// Points earned (if approved)
final int? pointsEarned;
/// Submission timestamp
final DateTime submittedAt;
/// Review timestamp
final DateTime? reviewedAt;
/// ID of admin who reviewed
final String? reviewedBy;
const ProjectSubmission({
required this.submissionId,
required this.userId,
required this.projectName,
this.projectAddress,
required this.projectValue,
required this.projectType,
required this.beforePhotos,
required this.afterPhotos,
required this.invoices,
required this.status,
this.reviewNotes,
this.rejectionReason,
this.pointsEarned,
required this.submittedAt,
this.reviewedAt,
this.reviewedBy,
});
/// Check if submission is pending
bool get isPending => status == SubmissionStatus.pending;
/// Check if submission is under review
bool get isReviewing => status == SubmissionStatus.reviewing;
/// Check if submission is approved
bool get isApproved => status == SubmissionStatus.approved;
/// Check if submission is rejected
bool get isRejected => status == SubmissionStatus.rejected;
/// Check if submission has been reviewed
bool get isReviewed =>
status == SubmissionStatus.approved || status == SubmissionStatus.rejected;
/// Check if submission has before photos
bool get hasBeforePhotos => beforePhotos.isNotEmpty;
/// Check if submission has after photos
bool get hasAfterPhotos => afterPhotos.isNotEmpty;
/// Check if submission has invoices
bool get hasInvoices => invoices.isNotEmpty;
/// Get total number of photos
int get totalPhotos => beforePhotos.length + afterPhotos.length;
/// Get review duration
Duration? get reviewDuration {
if (reviewedAt == null) return null;
return reviewedAt!.difference(submittedAt);
}
/// Copy with method for immutability
ProjectSubmission copyWith({
String? submissionId,
String? userId,
String? projectName,
String? projectAddress,
double? projectValue,
ProjectType? projectType,
List<String>? beforePhotos,
List<String>? afterPhotos,
List<String>? invoices,
SubmissionStatus? status,
String? reviewNotes,
String? rejectionReason,
int? pointsEarned,
DateTime? submittedAt,
DateTime? reviewedAt,
String? reviewedBy,
}) {
return ProjectSubmission(
submissionId: submissionId ?? this.submissionId,
userId: userId ?? this.userId,
projectName: projectName ?? this.projectName,
projectAddress: projectAddress ?? this.projectAddress,
projectValue: projectValue ?? this.projectValue,
projectType: projectType ?? this.projectType,
beforePhotos: beforePhotos ?? this.beforePhotos,
afterPhotos: afterPhotos ?? this.afterPhotos,
invoices: invoices ?? this.invoices,
status: status ?? this.status,
reviewNotes: reviewNotes ?? this.reviewNotes,
rejectionReason: rejectionReason ?? this.rejectionReason,
pointsEarned: pointsEarned ?? this.pointsEarned,
submittedAt: submittedAt ?? this.submittedAt,
reviewedAt: reviewedAt ?? this.reviewedAt,
reviewedBy: reviewedBy ?? this.reviewedBy,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is ProjectSubmission &&
other.submissionId == submissionId &&
other.userId == userId &&
other.projectName == projectName &&
other.projectValue == projectValue &&
other.status == status;
}
@override
int get hashCode {
return Object.hash(
submissionId,
userId,
projectName,
projectValue,
status,
);
}
@override
String toString() {
return 'ProjectSubmission(submissionId: $submissionId, projectName: $projectName, '
'projectValue: $projectValue, projectType: $projectType, status: $status, '
'pointsEarned: $pointsEarned)';
}
}