list orders

This commit is contained in:
Phuoc Nguyen
2025-11-24 16:25:54 +07:00
parent 354df3ad01
commit 75d6507719
24 changed files with 1004 additions and 982 deletions

View File

@@ -1,321 +1,97 @@
/// Domain Entity: Order
///
/// Represents a customer order.
/// Represents a customer order (simplified to match API structure).
library;
/// Order status enum
enum OrderStatus {
/// Order has been created but not confirmed
draft,
/// Order has been confirmed
confirmed,
/// Order is being processed
processing,
/// Order is ready for shipping
ready,
/// Order has been shipped
shipped,
/// Order has been delivered
delivered,
/// Order has been completed
completed,
/// Order has been cancelled
cancelled,
/// Order has been returned
returned;
/// Get display name for status
String get displayName {
switch (this) {
case OrderStatus.draft:
return 'Draft';
case OrderStatus.confirmed:
return 'Confirmed';
case OrderStatus.processing:
return 'Processing';
case OrderStatus.ready:
return 'Ready';
case OrderStatus.shipped:
return 'Shipped';
case OrderStatus.delivered:
return 'Delivered';
case OrderStatus.completed:
return 'Completed';
case OrderStatus.cancelled:
return 'Cancelled';
case OrderStatus.returned:
return 'Returned';
}
}
}
/// Address information
class Address {
/// Recipient name
final String? name;
/// Phone number
final String? phone;
/// Street address
final String? street;
/// Ward/commune
final String? ward;
/// District
final String? district;
/// City/province
final String? city;
/// Postal code
final String? postalCode;
const Address({
this.name,
this.phone,
this.street,
this.ward,
this.district,
this.city,
this.postalCode,
});
/// Get full address string
String get fullAddress {
final parts = [
street,
ward,
district,
city,
postalCode,
].where((part) => part != null && part.isNotEmpty).toList();
return parts.join(', ');
}
/// Create from JSON map
factory Address.fromJson(Map<String, dynamic> json) {
return Address(
name: json['name'] as String?,
phone: json['phone'] as String?,
street: json['street'] as String?,
ward: json['ward'] as String?,
district: json['district'] as String?,
city: json['city'] as String?,
postalCode: json['postal_code'] as String?,
);
}
/// Convert to JSON map
Map<String, dynamic> toJson() {
return {
'name': name,
'phone': phone,
'street': street,
'ward': ward,
'district': district,
'city': city,
'postal_code': postalCode,
};
}
}
import 'package:equatable/equatable.dart';
/// Order Entity
///
/// Contains complete order information:
/// - Order identification
/// - Customer details
/// - Pricing and discounts
/// - Shipping information
/// - Status tracking
class Order {
/// Unique order identifier
final String orderId;
/// Pure domain entity matching API response structure
class Order extends Equatable {
/// Order ID/Number
final String name;
/// Human-readable order number
final String orderNumber;
/// Transaction date (ISO format string)
final String transactionDate;
/// User ID who placed the order
final String userId;
/// Expected delivery date (ISO format string)
final String deliveryDate;
/// Current order status
final OrderStatus status;
/// Delivery address
final String address;
/// Total order amount before discounts
final double totalAmount;
/// Grand total amount
final double grandTotal;
/// Discount amount applied
final double discountAmount;
/// Status label (Vietnamese)
final String status;
/// Tax amount
final double taxAmount;
/// Shipping fee
final double shippingFee;
/// Final amount to pay
final double finalAmount;
/// Shipping address
final Address? shippingAddress;
/// Billing address
final Address? billingAddress;
/// Expected delivery date
final DateTime? expectedDeliveryDate;
/// Actual delivery date
final DateTime? actualDeliveryDate;
/// Order notes
final String? notes;
/// Cancellation reason
final String? cancellationReason;
/// ERPNext sales order reference
final String? erpnextSalesOrder;
/// Order creation timestamp
final DateTime createdAt;
/// Last update timestamp
final DateTime updatedAt;
/// Status color (Warning, Success, Danger, Info, Secondary)
final String statusColor;
const Order({
required this.orderId,
required this.orderNumber,
required this.userId,
required this.name,
required this.transactionDate,
required this.deliveryDate,
required this.address,
required this.grandTotal,
required this.status,
required this.totalAmount,
required this.discountAmount,
required this.taxAmount,
required this.shippingFee,
required this.finalAmount,
this.shippingAddress,
this.billingAddress,
this.expectedDeliveryDate,
this.actualDeliveryDate,
this.notes,
this.cancellationReason,
this.erpnextSalesOrder,
required this.createdAt,
required this.updatedAt,
required this.statusColor,
});
/// Check if order is active (not cancelled or completed)
bool get isActive =>
status != OrderStatus.cancelled &&
status != OrderStatus.completed &&
status != OrderStatus.returned;
/// Get parsed transaction date
DateTime? get transactionDateTime {
try {
return DateTime.parse(transactionDate);
} catch (e) {
return null;
}
}
/// Check if order can be cancelled
bool get canBeCancelled =>
status == OrderStatus.draft ||
status == OrderStatus.confirmed ||
status == OrderStatus.processing;
/// Check if order is delivered
bool get isDelivered =>
status == OrderStatus.delivered || status == OrderStatus.completed;
/// Check if order is cancelled
bool get isCancelled => status == OrderStatus.cancelled;
/// Get discount percentage
double get discountPercentage {
if (totalAmount == 0) return 0;
return (discountAmount / totalAmount) * 100;
/// Get parsed delivery date
DateTime? get deliveryDateTime {
try {
return DateTime.parse(deliveryDate);
} catch (e) {
return null;
}
}
/// Copy with method for immutability
Order copyWith({
String? orderId,
String? orderNumber,
String? userId,
OrderStatus? status,
double? totalAmount,
double? discountAmount,
double? taxAmount,
double? shippingFee,
double? finalAmount,
Address? shippingAddress,
Address? billingAddress,
DateTime? expectedDeliveryDate,
DateTime? actualDeliveryDate,
String? notes,
String? cancellationReason,
String? erpnextSalesOrder,
DateTime? createdAt,
DateTime? updatedAt,
String? name,
String? transactionDate,
String? deliveryDate,
String? address,
double? grandTotal,
String? status,
String? statusColor,
}) {
return Order(
orderId: orderId ?? this.orderId,
orderNumber: orderNumber ?? this.orderNumber,
userId: userId ?? this.userId,
name: name ?? this.name,
transactionDate: transactionDate ?? this.transactionDate,
deliveryDate: deliveryDate ?? this.deliveryDate,
address: address ?? this.address,
grandTotal: grandTotal ?? this.grandTotal,
status: status ?? this.status,
totalAmount: totalAmount ?? this.totalAmount,
discountAmount: discountAmount ?? this.discountAmount,
taxAmount: taxAmount ?? this.taxAmount,
shippingFee: shippingFee ?? this.shippingFee,
finalAmount: finalAmount ?? this.finalAmount,
shippingAddress: shippingAddress ?? this.shippingAddress,
billingAddress: billingAddress ?? this.billingAddress,
expectedDeliveryDate: expectedDeliveryDate ?? this.expectedDeliveryDate,
actualDeliveryDate: actualDeliveryDate ?? this.actualDeliveryDate,
notes: notes ?? this.notes,
cancellationReason: cancellationReason ?? this.cancellationReason,
erpnextSalesOrder: erpnextSalesOrder ?? this.erpnextSalesOrder,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
statusColor: statusColor ?? this.statusColor,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Order &&
other.orderId == orderId &&
other.orderNumber == orderNumber &&
other.userId == userId &&
other.status == status &&
other.totalAmount == totalAmount &&
other.discountAmount == discountAmount &&
other.taxAmount == taxAmount &&
other.shippingFee == shippingFee &&
other.finalAmount == finalAmount;
}
@override
int get hashCode {
return Object.hash(
orderId,
orderNumber,
userId,
status,
totalAmount,
discountAmount,
taxAmount,
shippingFee,
finalAmount,
);
}
List<Object?> get props => [
name,
transactionDate,
deliveryDate,
address,
grandTotal,
status,
statusColor,
];
@override
String toString() {
return 'Order(orderId: $orderId, orderNumber: $orderNumber, status: $status, '
'finalAmount: $finalAmount, createdAt: $createdAt)';
return 'Order(name: $name, status: $status, grandTotal: $grandTotal, transactionDate: $transactionDate)';
}
}