list orders
This commit is contained in:
@@ -247,4 +247,76 @@ class OrderRemoteDataSource {
|
||||
throw Exception('Failed to upload bill: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Get list of orders
|
||||
///
|
||||
/// Calls: POST /api/method/building_material.building_material.api.sales_order.get_list
|
||||
/// Body: { "limit_start": 0, "limit_page_length": 0 }
|
||||
/// Returns: List of orders
|
||||
Future<List<Map<String, dynamic>>> getOrdersList({
|
||||
int limitStart = 0,
|
||||
int limitPageLength = 0,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _dioClient.post<Map<String, dynamic>>(
|
||||
'${ApiConstants.frappeApiMethod}${ApiConstants.getOrdersList}',
|
||||
data: {
|
||||
'limit_start': limitStart,
|
||||
'limit_page_length': limitPageLength,
|
||||
},
|
||||
);
|
||||
|
||||
final data = response.data;
|
||||
if (data == null) {
|
||||
throw Exception('No data received from getOrdersList API');
|
||||
}
|
||||
|
||||
// Extract orders list from Frappe response
|
||||
final message = data['message'];
|
||||
if (message == null) {
|
||||
throw Exception('No message field in getOrdersList response');
|
||||
}
|
||||
|
||||
if (message is! List) {
|
||||
throw Exception('Expected list but got ${message.runtimeType}');
|
||||
}
|
||||
|
||||
return message.cast<Map<String, dynamic>>();
|
||||
} catch (e) {
|
||||
throw Exception('Failed to get orders list: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Get order detail
|
||||
///
|
||||
/// Calls: POST /api/method/building_material.building_material.api.sales_order.get_detail
|
||||
/// Body: { "name": "SAL-ORD-2025-00058-1" }
|
||||
/// Returns: Order details
|
||||
Future<Map<String, dynamic>> getOrderDetail(String orderName) async {
|
||||
try {
|
||||
final response = await _dioClient.post<Map<String, dynamic>>(
|
||||
'${ApiConstants.frappeApiMethod}${ApiConstants.getOrderDetail}',
|
||||
data: {'name': orderName},
|
||||
);
|
||||
|
||||
final data = response.data;
|
||||
if (data == null) {
|
||||
throw Exception('No data received from getOrderDetail API');
|
||||
}
|
||||
|
||||
// Extract order detail from Frappe response
|
||||
final message = data['message'];
|
||||
if (message == null) {
|
||||
throw Exception('No message field in getOrderDetail response');
|
||||
}
|
||||
|
||||
if (message is! Map<String, dynamic>) {
|
||||
throw Exception('Expected map but got ${message.runtimeType}');
|
||||
}
|
||||
|
||||
return message;
|
||||
} catch (e) {
|
||||
throw Exception('Failed to get order detail: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/// Order Status Local Data Source
|
||||
///
|
||||
/// Handles local caching of order status list using Hive.
|
||||
library;
|
||||
|
||||
import 'package:hive_ce/hive.dart';
|
||||
import 'package:worker/core/constants/storage_constants.dart';
|
||||
import 'package:worker/features/orders/data/models/order_status_model.dart';
|
||||
|
||||
/// Order Status Local Data Source
|
||||
class OrderStatusLocalDataSource {
|
||||
/// Get Hive box for order statuses
|
||||
Box<dynamic> get _box => Hive.box(HiveBoxNames.orderStatusBox);
|
||||
|
||||
/// Save order status list to cache
|
||||
Future<void> cacheStatusList(List<OrderStatusModel> statuses) async {
|
||||
// Clear existing cache
|
||||
await _box.clear();
|
||||
|
||||
// Save each status with its index as key
|
||||
for (final status in statuses) {
|
||||
await _box.put(status.index, status);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get cached order status list
|
||||
List<OrderStatusModel> getCachedStatusList() {
|
||||
try {
|
||||
final values = _box.values.whereType<OrderStatusModel>().toList();
|
||||
// Sort by index
|
||||
values.sort((a, b) => a.index.compareTo(b.index));
|
||||
return values;
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if cache exists and is not empty
|
||||
bool hasCachedData() {
|
||||
return _box.isNotEmpty;
|
||||
}
|
||||
|
||||
/// Clear all cached statuses
|
||||
Future<void> clearCache() async {
|
||||
await _box.clear();
|
||||
}
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
/// Local Data Source: Orders
|
||||
///
|
||||
/// Provides mock order data for development and testing.
|
||||
library;
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:worker/core/database/models/enums.dart';
|
||||
import 'package:worker/features/orders/data/models/order_model.dart';
|
||||
|
||||
/// Orders Local Data Source
|
||||
///
|
||||
/// Manages local mock order data.
|
||||
class OrdersLocalDataSource {
|
||||
/// Get all mock orders
|
||||
Future<List<OrderModel>> getAllOrders() async {
|
||||
try {
|
||||
debugPrint('[OrdersLocalDataSource] Loading mock orders...');
|
||||
|
||||
// Parse mock JSON data
|
||||
final decoded = jsonDecode(_mockOrdersJson);
|
||||
if (decoded is! List) {
|
||||
throw Exception('Invalid JSON format: expected List');
|
||||
}
|
||||
|
||||
final orders = decoded
|
||||
.map((json) => OrderModel.fromJson(json as Map<String, dynamic>))
|
||||
.toList();
|
||||
|
||||
debugPrint('[OrdersLocalDataSource] Loaded ${orders.length} orders');
|
||||
return orders;
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[OrdersLocalDataSource] Error loading orders: $e');
|
||||
debugPrint('Stack trace: $stackTrace');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get orders by status
|
||||
Future<List<OrderModel>> getOrdersByStatus(OrderStatus status) async {
|
||||
try {
|
||||
final allOrders = await getAllOrders();
|
||||
final filtered = allOrders
|
||||
.where((order) => order.status == status)
|
||||
.toList();
|
||||
|
||||
debugPrint(
|
||||
'[OrdersLocalDataSource] Filtered ${filtered.length} orders with status: $status',
|
||||
);
|
||||
return filtered;
|
||||
} catch (e) {
|
||||
debugPrint('[OrdersLocalDataSource] Error filtering orders: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Search orders by order number
|
||||
Future<List<OrderModel>> searchOrders(String query) async {
|
||||
try {
|
||||
if (query.isEmpty) {
|
||||
return getAllOrders();
|
||||
}
|
||||
|
||||
final allOrders = await getAllOrders();
|
||||
final filtered = allOrders
|
||||
.where(
|
||||
(order) =>
|
||||
order.orderNumber.toLowerCase().contains(query.toLowerCase()),
|
||||
)
|
||||
.toList();
|
||||
|
||||
debugPrint(
|
||||
'[OrdersLocalDataSource] Found ${filtered.length} orders matching "$query"',
|
||||
);
|
||||
return filtered;
|
||||
} catch (e) {
|
||||
debugPrint('[OrdersLocalDataSource] Error searching orders: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get order by ID
|
||||
Future<OrderModel?> getOrderById(String orderId) async {
|
||||
try {
|
||||
final allOrders = await getAllOrders();
|
||||
final order = allOrders.firstWhere(
|
||||
(order) => order.orderId == orderId,
|
||||
orElse: () => throw Exception('Order not found: $orderId'),
|
||||
);
|
||||
|
||||
debugPrint('[OrdersLocalDataSource] Found order: ${order.orderNumber}');
|
||||
return order;
|
||||
} catch (e) {
|
||||
debugPrint('[OrdersLocalDataSource] Error getting order: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Mock orders JSON data
|
||||
/// Matches the HTML design with 5 sample orders
|
||||
static const String _mockOrdersJson = '''
|
||||
[
|
||||
{
|
||||
"order_id": "ord_001",
|
||||
"order_number": "DH001234",
|
||||
"user_id": "user_001",
|
||||
"status": "processing",
|
||||
"total_amount": 12900000,
|
||||
"discount_amount": 0,
|
||||
"tax_amount": 0,
|
||||
"shipping_fee": 0,
|
||||
"final_amount": 12900000,
|
||||
"shipping_address": {
|
||||
"name": "Nguyễn Văn A",
|
||||
"phone": "0901234567",
|
||||
"street": "123 Đường Nguyễn Văn Linh",
|
||||
"district": "Quận 7",
|
||||
"city": "HCM",
|
||||
"postal_code": "70000"
|
||||
},
|
||||
"expected_delivery_date": "2025-08-06T00:00:00.000Z",
|
||||
"created_at": "2025-08-03T00:00:00.000Z",
|
||||
"updated_at": "2025-08-03T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"order_id": "ord_002",
|
||||
"order_number": "DH001233",
|
||||
"user_id": "user_001",
|
||||
"status": "completed",
|
||||
"total_amount": 8500000,
|
||||
"discount_amount": 0,
|
||||
"tax_amount": 0,
|
||||
"shipping_fee": 0,
|
||||
"final_amount": 8500000,
|
||||
"shipping_address": {
|
||||
"name": "Trần Thị B",
|
||||
"phone": "0912345678",
|
||||
"street": "456 Đại lộ Bình Dương",
|
||||
"city": "Thủ Dầu Một, Bình Dương",
|
||||
"postal_code": "75000"
|
||||
},
|
||||
"expected_delivery_date": "2025-06-27T00:00:00.000Z",
|
||||
"actual_delivery_date": "2025-06-27T00:00:00.000Z",
|
||||
"created_at": "2025-06-24T00:00:00.000Z",
|
||||
"updated_at": "2025-06-27T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"order_id": "ord_003",
|
||||
"order_number": "DH001232",
|
||||
"user_id": "user_001",
|
||||
"status": "shipped",
|
||||
"total_amount": 15200000,
|
||||
"discount_amount": 0,
|
||||
"tax_amount": 0,
|
||||
"shipping_fee": 0,
|
||||
"final_amount": 15200000,
|
||||
"shipping_address": {
|
||||
"name": "Lê Văn C",
|
||||
"phone": "0923456789",
|
||||
"street": "789 Phố Duy Tân",
|
||||
"district": "Cầu Giấy",
|
||||
"city": "Hà Nội",
|
||||
"postal_code": "10000"
|
||||
},
|
||||
"expected_delivery_date": "2025-03-05T00:00:00.000Z",
|
||||
"created_at": "2025-03-01T00:00:00.000Z",
|
||||
"updated_at": "2025-03-02T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"order_id": "ord_004",
|
||||
"order_number": "DH001231",
|
||||
"user_id": "user_001",
|
||||
"status": "pending",
|
||||
"total_amount": 6750000,
|
||||
"discount_amount": 0,
|
||||
"tax_amount": 0,
|
||||
"shipping_fee": 0,
|
||||
"final_amount": 6750000,
|
||||
"shipping_address": {
|
||||
"name": "Phạm Thị D",
|
||||
"phone": "0934567890",
|
||||
"street": "321 Đường Võ Văn Ngân",
|
||||
"city": "Thủ Đức, HCM",
|
||||
"postal_code": "71000"
|
||||
},
|
||||
"expected_delivery_date": "2024-11-12T00:00:00.000Z",
|
||||
"created_at": "2024-11-08T00:00:00.000Z",
|
||||
"updated_at": "2024-11-08T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"order_id": "ord_005",
|
||||
"order_number": "DH001230",
|
||||
"user_id": "user_001",
|
||||
"status": "cancelled",
|
||||
"total_amount": 3200000,
|
||||
"discount_amount": 0,
|
||||
"tax_amount": 0,
|
||||
"shipping_fee": 0,
|
||||
"final_amount": 3200000,
|
||||
"shipping_address": {
|
||||
"name": "Hoàng Văn E",
|
||||
"phone": "0945678901",
|
||||
"street": "654 Đường 3 Tháng 2",
|
||||
"city": "Rạch Giá, Kiên Giang",
|
||||
"postal_code": "92000"
|
||||
},
|
||||
"expected_delivery_date": "2024-08-04T00:00:00.000Z",
|
||||
"cancellation_reason": "Khách hàng yêu cầu hủy",
|
||||
"created_at": "2024-07-30T00:00:00.000Z",
|
||||
"updated_at": "2024-07-31T00:00:00.000Z"
|
||||
}
|
||||
]
|
||||
''';
|
||||
}
|
||||
@@ -1,161 +1,117 @@
|
||||
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';
|
||||
import 'package:worker/features/orders/domain/entities/order.dart';
|
||||
|
||||
part 'order_model.g.dart';
|
||||
|
||||
/// Order Model - Type ID: 6
|
||||
///
|
||||
/// Simplified model matching API response structure
|
||||
@HiveType(typeId: HiveTypeIds.orderModel)
|
||||
class OrderModel extends HiveObject {
|
||||
/// Order ID/Number (from API 'name' field)
|
||||
@HiveField(0)
|
||||
final String name;
|
||||
|
||||
/// Transaction date
|
||||
@HiveField(1)
|
||||
final String transactionDate;
|
||||
|
||||
/// Expected delivery date
|
||||
@HiveField(2)
|
||||
final String deliveryDate;
|
||||
|
||||
/// Delivery address
|
||||
@HiveField(3)
|
||||
final String address;
|
||||
|
||||
/// Grand total amount
|
||||
@HiveField(4)
|
||||
final double grandTotal;
|
||||
|
||||
/// Status label (Vietnamese)
|
||||
@HiveField(5)
|
||||
final String status;
|
||||
|
||||
/// Status color (Warning, Success, Danger, Info, Secondary)
|
||||
@HiveField(6)
|
||||
final String statusColor;
|
||||
|
||||
OrderModel({
|
||||
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,
|
||||
this.updatedAt,
|
||||
required this.statusColor,
|
||||
});
|
||||
|
||||
@HiveField(0)
|
||||
final String orderId;
|
||||
|
||||
@HiveField(1)
|
||||
final String orderNumber;
|
||||
|
||||
@HiveField(2)
|
||||
final String userId;
|
||||
|
||||
@HiveField(3)
|
||||
final OrderStatus status;
|
||||
|
||||
@HiveField(4)
|
||||
final double totalAmount;
|
||||
|
||||
@HiveField(5)
|
||||
final double discountAmount;
|
||||
|
||||
@HiveField(6)
|
||||
final double taxAmount;
|
||||
|
||||
@HiveField(7)
|
||||
final double shippingFee;
|
||||
|
||||
@HiveField(8)
|
||||
final double finalAmount;
|
||||
|
||||
@HiveField(9)
|
||||
final String? shippingAddress;
|
||||
|
||||
@HiveField(10)
|
||||
final String? billingAddress;
|
||||
|
||||
@HiveField(11)
|
||||
final DateTime? expectedDeliveryDate;
|
||||
|
||||
@HiveField(12)
|
||||
final DateTime? actualDeliveryDate;
|
||||
|
||||
@HiveField(13)
|
||||
final String? notes;
|
||||
|
||||
@HiveField(14)
|
||||
final String? cancellationReason;
|
||||
|
||||
@HiveField(15)
|
||||
final String? erpnextSalesOrder;
|
||||
|
||||
@HiveField(16)
|
||||
final DateTime createdAt;
|
||||
|
||||
@HiveField(17)
|
||||
final DateTime? updatedAt;
|
||||
|
||||
/// Create from JSON (API response)
|
||||
factory OrderModel.fromJson(Map<String, dynamic> json) {
|
||||
return OrderModel(
|
||||
orderId: json['order_id'] as String,
|
||||
orderNumber: json['order_number'] as String,
|
||||
userId: json['user_id'] as String,
|
||||
status: OrderStatus.values.firstWhere((e) => e.name == json['status']),
|
||||
totalAmount: (json['total_amount'] as num).toDouble(),
|
||||
discountAmount: (json['discount_amount'] as num).toDouble(),
|
||||
taxAmount: (json['tax_amount'] as num).toDouble(),
|
||||
shippingFee: (json['shipping_fee'] as num).toDouble(),
|
||||
finalAmount: (json['final_amount'] as num).toDouble(),
|
||||
shippingAddress: json['shipping_address'] != null
|
||||
? jsonEncode(json['shipping_address'])
|
||||
: null,
|
||||
billingAddress: json['billing_address'] != null
|
||||
? jsonEncode(json['billing_address'])
|
||||
: null,
|
||||
expectedDeliveryDate: json['expected_delivery_date'] != null
|
||||
? DateTime.parse(json['expected_delivery_date']?.toString() ?? '')
|
||||
: null,
|
||||
actualDeliveryDate: json['actual_delivery_date'] != null
|
||||
? DateTime.parse(json['actual_delivery_date']?.toString() ?? '')
|
||||
: null,
|
||||
notes: json['notes'] as String?,
|
||||
cancellationReason: json['cancellation_reason'] as String?,
|
||||
erpnextSalesOrder: json['erpnext_sales_order'] as String?,
|
||||
createdAt: DateTime.parse(json['created_at']?.toString() ?? ''),
|
||||
updatedAt: json['updated_at'] != null
|
||||
? DateTime.parse(json['updated_at']?.toString() ?? '')
|
||||
: null,
|
||||
name: json['name'] as String? ?? '',
|
||||
transactionDate: json['transaction_date'] as String? ?? '',
|
||||
deliveryDate: json['delivery_date'] as String? ?? '',
|
||||
address: json['address'] as String? ?? '',
|
||||
grandTotal: (json['grand_total'] as num?)?.toDouble() ?? 0.0,
|
||||
status: json['status'] as String? ?? '',
|
||||
statusColor: json['status_color'] as String? ?? 'Secondary',
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert to JSON
|
||||
Map<String, dynamic> toJson() => {
|
||||
'order_id': orderId,
|
||||
'order_number': orderNumber,
|
||||
'user_id': userId,
|
||||
'status': status.name,
|
||||
'total_amount': totalAmount,
|
||||
'discount_amount': discountAmount,
|
||||
'tax_amount': taxAmount,
|
||||
'shipping_fee': shippingFee,
|
||||
'final_amount': finalAmount,
|
||||
'shipping_address': shippingAddress != null
|
||||
? jsonDecode(shippingAddress!)
|
||||
: null,
|
||||
'billing_address': billingAddress != null
|
||||
? jsonDecode(billingAddress!)
|
||||
: null,
|
||||
'expected_delivery_date': expectedDeliveryDate?.toIso8601String(),
|
||||
'actual_delivery_date': actualDeliveryDate?.toIso8601String(),
|
||||
'notes': notes,
|
||||
'cancellation_reason': cancellationReason,
|
||||
'erpnext_sales_order': erpnextSalesOrder,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt?.toIso8601String(),
|
||||
};
|
||||
'name': name,
|
||||
'transaction_date': transactionDate,
|
||||
'delivery_date': deliveryDate,
|
||||
'address': address,
|
||||
'grand_total': grandTotal,
|
||||
'status': status,
|
||||
'status_color': statusColor,
|
||||
};
|
||||
|
||||
Map<String, dynamic>? get shippingAddressMap {
|
||||
if (shippingAddress == null) return null;
|
||||
/// Get parsed transaction date
|
||||
DateTime? get transactionDateTime {
|
||||
try {
|
||||
return jsonDecode(shippingAddress!) as Map<String, dynamic>;
|
||||
return DateTime.parse(transactionDate);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic>? get billingAddressMap {
|
||||
if (billingAddress == null) return null;
|
||||
/// Get parsed delivery date
|
||||
DateTime? get deliveryDateTime {
|
||||
try {
|
||||
return jsonDecode(billingAddress!) as Map<String, dynamic>;
|
||||
return DateTime.parse(deliveryDate);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert to domain entity
|
||||
Order toEntity() {
|
||||
return Order(
|
||||
name: name,
|
||||
transactionDate: transactionDate,
|
||||
deliveryDate: deliveryDate,
|
||||
address: address,
|
||||
grandTotal: grandTotal,
|
||||
status: status,
|
||||
statusColor: statusColor,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create from domain entity
|
||||
factory OrderModel.fromEntity(Order entity) {
|
||||
return OrderModel(
|
||||
name: entity.name,
|
||||
transactionDate: entity.transactionDate,
|
||||
deliveryDate: entity.deliveryDate,
|
||||
address: entity.address,
|
||||
grandTotal: entity.grandTotal,
|
||||
status: entity.status,
|
||||
statusColor: entity.statusColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,67 +17,34 @@ class OrderModelAdapter extends TypeAdapter<OrderModel> {
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return OrderModel(
|
||||
orderId: fields[0] as String,
|
||||
orderNumber: fields[1] as String,
|
||||
userId: fields[2] as String,
|
||||
status: fields[3] as OrderStatus,
|
||||
totalAmount: (fields[4] as num).toDouble(),
|
||||
discountAmount: (fields[5] as num).toDouble(),
|
||||
taxAmount: (fields[6] as num).toDouble(),
|
||||
shippingFee: (fields[7] as num).toDouble(),
|
||||
finalAmount: (fields[8] as num).toDouble(),
|
||||
shippingAddress: fields[9] as String?,
|
||||
billingAddress: fields[10] as String?,
|
||||
expectedDeliveryDate: fields[11] as DateTime?,
|
||||
actualDeliveryDate: fields[12] as DateTime?,
|
||||
notes: fields[13] as String?,
|
||||
cancellationReason: fields[14] as String?,
|
||||
erpnextSalesOrder: fields[15] as String?,
|
||||
createdAt: fields[16] as DateTime,
|
||||
updatedAt: fields[17] as DateTime?,
|
||||
name: fields[0] as String,
|
||||
transactionDate: fields[1] as String,
|
||||
deliveryDate: fields[2] as String,
|
||||
address: fields[3] as String,
|
||||
grandTotal: (fields[4] as num).toDouble(),
|
||||
status: fields[5] as String,
|
||||
statusColor: fields[6] as String,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, OrderModel obj) {
|
||||
writer
|
||||
..writeByte(18)
|
||||
..writeByte(0)
|
||||
..write(obj.orderId)
|
||||
..writeByte(1)
|
||||
..write(obj.orderNumber)
|
||||
..writeByte(2)
|
||||
..write(obj.userId)
|
||||
..writeByte(3)
|
||||
..write(obj.status)
|
||||
..writeByte(4)
|
||||
..write(obj.totalAmount)
|
||||
..writeByte(5)
|
||||
..write(obj.discountAmount)
|
||||
..writeByte(6)
|
||||
..write(obj.taxAmount)
|
||||
..writeByte(7)
|
||||
..write(obj.shippingFee)
|
||||
..writeByte(8)
|
||||
..write(obj.finalAmount)
|
||||
..writeByte(9)
|
||||
..write(obj.shippingAddress)
|
||||
..writeByte(10)
|
||||
..write(obj.billingAddress)
|
||||
..writeByte(11)
|
||||
..write(obj.expectedDeliveryDate)
|
||||
..writeByte(12)
|
||||
..write(obj.actualDeliveryDate)
|
||||
..writeByte(13)
|
||||
..write(obj.notes)
|
||||
..writeByte(14)
|
||||
..write(obj.cancellationReason)
|
||||
..writeByte(15)
|
||||
..write(obj.erpnextSalesOrder)
|
||||
..writeByte(16)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(17)
|
||||
..write(obj.updatedAt);
|
||||
..writeByte(0)
|
||||
..write(obj.name)
|
||||
..writeByte(1)
|
||||
..write(obj.transactionDate)
|
||||
..writeByte(2)
|
||||
..write(obj.deliveryDate)
|
||||
..writeByte(3)
|
||||
..write(obj.address)
|
||||
..writeByte(4)
|
||||
..write(obj.grandTotal)
|
||||
..writeByte(5)
|
||||
..write(obj.status)
|
||||
..writeByte(6)
|
||||
..write(obj.statusColor);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,19 +1,30 @@
|
||||
/// Order Status Model
|
||||
///
|
||||
/// Data model for order status from API responses.
|
||||
/// Data model for order status from API responses with Hive caching.
|
||||
library;
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:hive_ce/hive.dart';
|
||||
import 'package:worker/core/constants/storage_constants.dart';
|
||||
import 'package:worker/features/orders/domain/entities/order_status.dart';
|
||||
|
||||
/// Order Status Model
|
||||
class OrderStatusModel extends Equatable {
|
||||
part 'order_status_model.g.dart';
|
||||
|
||||
/// Order Status Model - Type ID: 62
|
||||
@HiveType(typeId: HiveTypeIds.orderStatusModel)
|
||||
class OrderStatusModel extends HiveObject {
|
||||
@HiveField(0)
|
||||
final String status;
|
||||
|
||||
@HiveField(1)
|
||||
final String label;
|
||||
|
||||
@HiveField(2)
|
||||
final String color;
|
||||
|
||||
@HiveField(3)
|
||||
final int index;
|
||||
|
||||
const OrderStatusModel({
|
||||
OrderStatusModel({
|
||||
required this.status,
|
||||
required this.label,
|
||||
required this.color,
|
||||
@@ -59,7 +70,4 @@ class OrderStatusModel extends Equatable {
|
||||
index: entity.index,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [status, label, color, index];
|
||||
}
|
||||
|
||||
50
lib/features/orders/data/models/order_status_model.g.dart
Normal file
50
lib/features/orders/data/models/order_status_model.g.dart
Normal file
@@ -0,0 +1,50 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'order_status_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// TypeAdapterGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class OrderStatusModelAdapter extends TypeAdapter<OrderStatusModel> {
|
||||
@override
|
||||
final typeId = 62;
|
||||
|
||||
@override
|
||||
OrderStatusModel read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return OrderStatusModel(
|
||||
status: fields[0] as String,
|
||||
label: fields[1] as String,
|
||||
color: fields[2] as String,
|
||||
index: (fields[3] as num).toInt(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, OrderStatusModel obj) {
|
||||
writer
|
||||
..writeByte(4)
|
||||
..writeByte(0)
|
||||
..write(obj.status)
|
||||
..writeByte(1)
|
||||
..write(obj.label)
|
||||
..writeByte(2)
|
||||
..write(obj.color)
|
||||
..writeByte(3)
|
||||
..write(obj.index);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is OrderStatusModelAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
@@ -4,22 +4,67 @@
|
||||
library;
|
||||
|
||||
import 'package:worker/features/orders/data/datasources/order_remote_datasource.dart';
|
||||
import 'package:worker/features/orders/data/datasources/order_status_local_datasource.dart';
|
||||
import 'package:worker/features/orders/data/models/order_model.dart';
|
||||
import 'package:worker/features/orders/domain/entities/order.dart';
|
||||
import 'package:worker/features/orders/domain/entities/order_status.dart';
|
||||
import 'package:worker/features/orders/domain/entities/payment_term.dart';
|
||||
import 'package:worker/features/orders/domain/repositories/order_repository.dart';
|
||||
|
||||
/// Order Repository Implementation
|
||||
class OrderRepositoryImpl implements OrderRepository {
|
||||
const OrderRepositoryImpl(this._remoteDataSource);
|
||||
const OrderRepositoryImpl(
|
||||
this._remoteDataSource,
|
||||
this._statusLocalDataSource,
|
||||
);
|
||||
|
||||
final OrderRemoteDataSource _remoteDataSource;
|
||||
final OrderStatusLocalDataSource _statusLocalDataSource;
|
||||
|
||||
@override
|
||||
Future<List<Order>> getOrdersList({
|
||||
int limitStart = 0,
|
||||
int limitPageLength = 0,
|
||||
}) async {
|
||||
try {
|
||||
final ordersData = await _remoteDataSource.getOrdersList(
|
||||
limitStart: limitStart,
|
||||
limitPageLength: limitPageLength,
|
||||
);
|
||||
// Convert JSON → Model → Entity
|
||||
return ordersData
|
||||
.map((json) => OrderModel.fromJson(json).toEntity())
|
||||
.toList();
|
||||
} catch (e) {
|
||||
throw Exception('Failed to get orders list: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<OrderStatus>> getOrderStatusList() async {
|
||||
try {
|
||||
// Try to get from cache first
|
||||
if (_statusLocalDataSource.hasCachedData()) {
|
||||
final cachedModels = _statusLocalDataSource.getCachedStatusList();
|
||||
if (cachedModels.isNotEmpty) {
|
||||
return cachedModels.map((model) => model.toEntity()).toList();
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch from API
|
||||
final models = await _remoteDataSource.getOrderStatusList();
|
||||
|
||||
// Cache the results
|
||||
await _statusLocalDataSource.cacheStatusList(models);
|
||||
|
||||
// Return entities
|
||||
return models.map((model) => model.toEntity()).toList();
|
||||
} catch (e) {
|
||||
// If API fails, try to return cached data
|
||||
final cachedModels = _statusLocalDataSource.getCachedStatusList();
|
||||
if (cachedModels.isNotEmpty) {
|
||||
return cachedModels.map((model) => model.toEntity()).toList();
|
||||
}
|
||||
throw Exception('Failed to get order status list: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user