fill
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import '../../../../core/errors/exceptions.dart';
|
||||
import '../../../../core/network/api_client.dart';
|
||||
import '../../../../core/network/api_response.dart';
|
||||
import '../models/warehouse_model.dart';
|
||||
|
||||
/// Abstract interface for warehouse remote data source
|
||||
abstract class WarehouseRemoteDataSource {
|
||||
/// Get all warehouses from the API
|
||||
///
|
||||
/// Returns [List<WarehouseModel>] on success
|
||||
/// Throws [ServerException] on API errors
|
||||
/// Throws [NetworkException] on network errors
|
||||
Future<List<WarehouseModel>> getWarehouses();
|
||||
}
|
||||
|
||||
/// Implementation of warehouse remote data source
|
||||
/// Uses ApiClient to make HTTP requests to the backend
|
||||
class WarehouseRemoteDataSourceImpl implements WarehouseRemoteDataSource {
|
||||
final ApiClient apiClient;
|
||||
|
||||
WarehouseRemoteDataSourceImpl(this.apiClient);
|
||||
|
||||
@override
|
||||
Future<List<WarehouseModel>> getWarehouses() async {
|
||||
try {
|
||||
// Make POST request to /portalWareHouse/search endpoint
|
||||
final response = await apiClient.post(
|
||||
'/portalWareHouse/search',
|
||||
data: {
|
||||
'pageIndex': 0,
|
||||
'pageSize': 100,
|
||||
'Name': null,
|
||||
'Code': null,
|
||||
'sortExpression': null,
|
||||
'sortDirection': null,
|
||||
},
|
||||
);
|
||||
|
||||
// Parse the API response wrapper
|
||||
final apiResponse = ApiResponse.fromJson(
|
||||
response.data,
|
||||
(json) {
|
||||
// Handle the list of warehouses
|
||||
if (json is List) {
|
||||
return json.map((e) => WarehouseModel.fromJson(e)).toList();
|
||||
}
|
||||
throw const ServerException('Invalid response format: expected List');
|
||||
},
|
||||
);
|
||||
|
||||
// Check if API call was successful
|
||||
if (apiResponse.isSuccess && apiResponse.value != null) {
|
||||
return apiResponse.value!;
|
||||
} else {
|
||||
// Extract error message from API response
|
||||
final errorMessage = apiResponse.errors.isNotEmpty
|
||||
? apiResponse.errors.first
|
||||
: 'Failed to get warehouses';
|
||||
|
||||
throw ServerException(
|
||||
errorMessage,
|
||||
code: apiResponse.firstErrorCode,
|
||||
);
|
||||
}
|
||||
} on ServerException {
|
||||
rethrow;
|
||||
} on NetworkException {
|
||||
rethrow;
|
||||
} catch (e) {
|
||||
// Wrap any unexpected errors
|
||||
throw ServerException(
|
||||
'Unexpected error while fetching warehouses: ${e.toString()}',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
100
lib/features/warehouse/data/models/warehouse_model.dart
Normal file
100
lib/features/warehouse/data/models/warehouse_model.dart
Normal file
@@ -0,0 +1,100 @@
|
||||
import '../../domain/entities/warehouse_entity.dart';
|
||||
|
||||
/// Warehouse data model
|
||||
/// Extends domain entity and adds JSON serialization
|
||||
/// Matches the API response format from backend
|
||||
class WarehouseModel extends WarehouseEntity {
|
||||
const WarehouseModel({
|
||||
required super.id,
|
||||
required super.name,
|
||||
required super.code,
|
||||
super.description,
|
||||
required super.isNGWareHouse,
|
||||
required super.totalCount,
|
||||
});
|
||||
|
||||
/// Create a WarehouseModel from JSON
|
||||
///
|
||||
/// JSON format from API:
|
||||
/// ```json
|
||||
/// {
|
||||
/// "Id": 1,
|
||||
/// "Name": "Kho nguyên vật liệu",
|
||||
/// "Code": "001",
|
||||
/// "Description": "Kho chứa nguyên vật liệu",
|
||||
/// "IsNGWareHouse": false,
|
||||
/// "TotalCount": 8
|
||||
/// }
|
||||
/// ```
|
||||
factory WarehouseModel.fromJson(Map<String, dynamic> json) {
|
||||
return WarehouseModel(
|
||||
id: json['Id'] ?? 0,
|
||||
name: json['Name'] ?? '',
|
||||
code: json['Code'] ?? '',
|
||||
description: json['Description'],
|
||||
isNGWareHouse: json['IsNGWareHouse'] ?? false,
|
||||
totalCount: json['TotalCount'] ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert model to JSON
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'Id': id,
|
||||
'Name': name,
|
||||
'Code': code,
|
||||
'Description': description,
|
||||
'IsNGWareHouse': isNGWareHouse,
|
||||
'TotalCount': totalCount,
|
||||
};
|
||||
}
|
||||
|
||||
/// Create from domain entity
|
||||
factory WarehouseModel.fromEntity(WarehouseEntity entity) {
|
||||
return WarehouseModel(
|
||||
id: entity.id,
|
||||
name: entity.name,
|
||||
code: entity.code,
|
||||
description: entity.description,
|
||||
isNGWareHouse: entity.isNGWareHouse,
|
||||
totalCount: entity.totalCount,
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert to domain entity
|
||||
WarehouseEntity toEntity() {
|
||||
return WarehouseEntity(
|
||||
id: id,
|
||||
name: name,
|
||||
code: code,
|
||||
description: description,
|
||||
isNGWareHouse: isNGWareHouse,
|
||||
totalCount: totalCount,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a copy with modified fields
|
||||
@override
|
||||
WarehouseModel copyWith({
|
||||
int? id,
|
||||
String? name,
|
||||
String? code,
|
||||
String? description,
|
||||
bool? isNGWareHouse,
|
||||
int? totalCount,
|
||||
}) {
|
||||
return WarehouseModel(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
code: code ?? this.code,
|
||||
description: description ?? this.description,
|
||||
isNGWareHouse: isNGWareHouse ?? this.isNGWareHouse,
|
||||
totalCount: totalCount ?? this.totalCount,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'WarehouseModel(id: $id, name: $name, code: $code, totalCount: $totalCount)';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import '../../../../core/errors/exceptions.dart';
|
||||
import '../../../../core/errors/failures.dart';
|
||||
import '../../domain/entities/warehouse_entity.dart';
|
||||
import '../../domain/repositories/warehouse_repository.dart';
|
||||
import '../datasources/warehouse_remote_datasource.dart';
|
||||
|
||||
/// Implementation of WarehouseRepository
|
||||
/// Coordinates between data sources and domain layer
|
||||
/// Converts exceptions to failures for proper error handling
|
||||
class WarehouseRepositoryImpl implements WarehouseRepository {
|
||||
final WarehouseRemoteDataSource remoteDataSource;
|
||||
|
||||
WarehouseRepositoryImpl(this.remoteDataSource);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<WarehouseEntity>>> getWarehouses() async {
|
||||
try {
|
||||
// Fetch warehouses from remote data source
|
||||
final warehouses = await remoteDataSource.getWarehouses();
|
||||
|
||||
// Convert models to entities
|
||||
final entities = warehouses
|
||||
.map((model) => model.toEntity())
|
||||
.toList();
|
||||
|
||||
return Right(entities);
|
||||
} on ServerException catch (e) {
|
||||
// Convert server exceptions to server failures
|
||||
return Left(ServerFailure(e.message));
|
||||
} on NetworkException catch (e) {
|
||||
// Convert network exceptions to network failures
|
||||
return Left(NetworkFailure(e.message));
|
||||
} catch (e) {
|
||||
// Handle any unexpected errors
|
||||
return Left(ServerFailure('Unexpected error: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user