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

@@ -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');
}
}
}

View File

@@ -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();
}
}

View File

@@ -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"
}
]
''';
}