/// Domain Entity: Invoice /// /// Represents an invoice from the API. /// Used for both list and detail views. library; import 'package:equatable/equatable.dart'; /// Seller/Company Information class SellerInfo extends Equatable { final String? phone; final String? email; final String? fax; final String? taxCode; final String? companyName; final String? addressLine1; final String? cityCode; final String? wardCode; final String? cityName; final String? wardName; const SellerInfo({ this.phone, this.email, this.fax, this.taxCode, this.companyName, this.addressLine1, this.cityCode, this.wardCode, this.cityName, this.wardName, }); /// Get formatted full address String get fullAddress { final parts = []; if (addressLine1 != null && addressLine1!.isNotEmpty) { parts.add(addressLine1!); } if (wardName != null && wardName!.isNotEmpty) { parts.add(wardName!); } if (cityName != null && cityName!.isNotEmpty) { parts.add(cityName!); } return parts.join(', '); } @override List get props => [ phone, email, fax, taxCode, companyName, addressLine1, cityCode, wardCode, cityName, wardName, ]; } /// Buyer/Customer Information class BuyerInfo extends Equatable { final String? name; final String? addressTitle; final String? addressLine1; final String? phone; final String? email; final String? fax; final String? taxCode; final String? cityCode; final String? wardCode; final String? cityName; final String? wardName; const BuyerInfo({ this.name, this.addressTitle, this.addressLine1, this.phone, this.email, this.fax, this.taxCode, this.cityCode, this.wardCode, this.cityName, this.wardName, }); /// Get formatted full address String get fullAddress { final parts = []; if (addressLine1 != null && addressLine1!.isNotEmpty) { parts.add(addressLine1!); } if (wardName != null && wardName!.isNotEmpty) { parts.add(wardName!); } if (cityName != null && cityName!.isNotEmpty) { parts.add(cityName!); } return parts.join(', '); } @override List get props => [ name, addressTitle, addressLine1, phone, email, fax, taxCode, cityCode, wardCode, cityName, wardName, ]; } /// Invoice Line Item class InvoiceItem extends Equatable { final String itemName; final String itemCode; final double qty; final double rate; final double amount; const InvoiceItem({ required this.itemName, required this.itemCode, required this.qty, required this.rate, required this.amount, }); @override List get props => [itemName, itemCode, qty, rate, amount]; } /// Invoice Entity /// /// Contains invoice information from API: /// - name: Invoice ID (e.g., "ACC-SINV-2025-00041") /// - postingDate: Invoice date /// - status: Status label (Vietnamese) /// - statusColor: Status color (Danger, Success, etc.) /// - orderId: Related order ID (nullable) /// - grandTotal: Total amount /// - customerName: Customer name (detail only) /// - sellerInfo: Seller company info (detail only) /// - buyerInfo: Buyer info (detail only) /// - items: Invoice line items (detail only) /// - total: Subtotal before discount (detail only) /// - discountAmount: Discount amount (detail only) class Invoice extends Equatable { /// Invoice ID (e.g., "ACC-SINV-2025-00041") final String name; /// Invoice posting date final DateTime postingDate; /// Status label (Vietnamese) final String status; /// Status color (Danger, Success, Warning, etc.) final String statusColor; /// Related order ID (nullable) final String? orderId; /// Grand total amount final double grandTotal; // Detail-only fields (nullable for list view) /// Customer name final String? customerName; /// Seller company information final SellerInfo? sellerInfo; /// Buyer information final BuyerInfo? buyerInfo; /// Invoice line items final List? items; /// Subtotal before discount final double? total; /// Discount amount final double? discountAmount; const Invoice({ required this.name, required this.postingDate, required this.status, required this.statusColor, this.orderId, required this.grandTotal, this.customerName, this.sellerInfo, this.buyerInfo, this.items, this.total, this.discountAmount, }); /// Check if this is a detail invoice (has all detail fields) bool get isDetail => sellerInfo != null && buyerInfo != null && items != null; /// Get formatted posting date String get formattedDate { return '${postingDate.day.toString().padLeft(2, '0')}/${postingDate.month.toString().padLeft(2, '0')}/${postingDate.year}'; } /// Copy with method for immutability Invoice copyWith({ String? name, DateTime? postingDate, String? status, String? statusColor, String? orderId, double? grandTotal, String? customerName, SellerInfo? sellerInfo, BuyerInfo? buyerInfo, List? items, double? total, double? discountAmount, }) { return Invoice( name: name ?? this.name, postingDate: postingDate ?? this.postingDate, status: status ?? this.status, statusColor: statusColor ?? this.statusColor, orderId: orderId ?? this.orderId, grandTotal: grandTotal ?? this.grandTotal, customerName: customerName ?? this.customerName, sellerInfo: sellerInfo ?? this.sellerInfo, buyerInfo: buyerInfo ?? this.buyerInfo, items: items ?? this.items, total: total ?? this.total, discountAmount: discountAmount ?? this.discountAmount, ); } @override List get props => [ name, postingDate, status, statusColor, orderId, grandTotal, customerName, sellerInfo, buyerInfo, items, total, discountAmount, ]; @override String toString() { return 'Invoice(name: $name, status: $status, grandTotal: $grandTotal)'; } }