/// Domain Entity: Price Document /// /// Pure business entity representing a price policy or price list document. /// This entity is framework-independent and contains only business logic. library; import 'package:equatable/equatable.dart'; /// Price policy document entity class PriceDocument extends Equatable { /// Document title final String title; /// URL to download the document final String fileUrl; /// Date the document was last updated final DateTime updatedAt; /// Category (policy or price list) final DocumentCategory category; /// Local file path after download (in-memory cache for current session) final String? filePath; /// Constructor const PriceDocument({ required this.title, required this.fileUrl, required this.updatedAt, required this.category, this.filePath, }); /// Get document type based on file extension DocumentType get documentType { final lowerUrl = fileUrl.toLowerCase(); if (lowerUrl.endsWith('.pdf')) { return DocumentType.pdf; } else if (lowerUrl.endsWith('.xlsx') || lowerUrl.endsWith('.xls') || lowerUrl.endsWith('.csv')) { return DocumentType.excel; } return DocumentType.excel; // Default to excel } /// Check if document is a PDF bool get isPdf => documentType == DocumentType.pdf; /// Check if document is an Excel file bool get isExcel => documentType == DocumentType.excel; /// Check if document is a policy document bool get isPolicy => category == DocumentCategory.policy; /// Check if document is a price list bool get isPriceList => category == DocumentCategory.priceList; /// Get formatted published date (dd/MM/yyyy) String get formattedDate { return '${updatedAt.day.toString().padLeft(2, '0')}/' '${updatedAt.month.toString().padLeft(2, '0')}/' '${updatedAt.year}'; } /// Get formatted date with time (dd/MM/yyyy HH:mm) String get formattedDateTime { return '$formattedDate ${updatedAt.hour.toString().padLeft(2, '0')}:' '${updatedAt.minute.toString().padLeft(2, '0')}'; } /// Get formatted date with prefix based on category String get formattedDateWithPrefix { final prefix = isPolicy ? 'Công bố' : 'Cập nhật'; return '$prefix: $formattedDate'; } /// Get icon name based on document type String get iconName => documentType == DocumentType.pdf ? 'PDF' : 'Excel'; /// Copy with method for immutability PriceDocument copyWith({ String? title, String? fileUrl, DateTime? updatedAt, DocumentCategory? category, String? filePath, }) { return PriceDocument( title: title ?? this.title, fileUrl: fileUrl ?? this.fileUrl, updatedAt: updatedAt ?? this.updatedAt, category: category ?? this.category, filePath: filePath ?? this.filePath, ); } /// Equatable props for equality comparison @override List get props => [title, fileUrl, updatedAt, category, filePath]; /// String representation @override String toString() { return 'PriceDocument(title: $title, fileUrl: $fileUrl, ' 'updatedAt: $updatedAt, category: $category, filePath: $filePath)'; } } /// Document type enum enum DocumentType { pdf, excel } /// Document category enum enum DocumentCategory { policy, // Chính sách giá (PRICING_RULE) priceList, // Bảng giá (PRICE_LIST) } // Extension for display extension DocumentTypeX on DocumentType { String get displayName { switch (this) { case DocumentType.pdf: return 'PDF'; case DocumentType.excel: return 'Excel'; } } } extension DocumentCategoryX on DocumentCategory { String get displayName { switch (this) { case DocumentCategory.policy: return 'Chính sách giá'; case DocumentCategory.priceList: return 'Bảng giá'; } } /// Get API parameter value for this category String get apiValue { switch (this) { case DocumentCategory.policy: return 'PRICING_RULE'; case DocumentCategory.priceList: return 'PRICE_LIST'; } } }