Files
worker/lib/features/invoices/domain/entities/invoice.dart
Phuoc Nguyen 359c31a4d4 update invoice
2025-12-02 15:58:10 +07:00

273 lines
6.2 KiB
Dart

/// 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 = <String>[];
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<Object?> 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 = <String>[];
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<Object?> 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<Object?> 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<InvoiceItem>? 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<InvoiceItem>? 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<Object?> 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)';
}
}