This commit is contained in:
2025-10-28 00:43:32 +07:00
parent de49f564b1
commit df99d0c9e3
19 changed files with 1000 additions and 1453 deletions

View File

@@ -1,7 +1,10 @@
import '../../../../core/constants/api_endpoints.dart';
import '../../../../core/errors/exceptions.dart';
import '../../../../core/network/api_client.dart';
import '../../../../core/network/api_response.dart';
import '../models/product_detail_request_model.dart';
import '../models/product_model.dart';
import '../models/product_stage_model.dart';
/// Abstract interface for products remote data source
abstract class ProductsRemoteDataSource {
@@ -13,6 +16,14 @@ abstract class ProductsRemoteDataSource {
/// Returns List<ProductModel>
/// Throws [ServerException] if the API call fails
Future<List<ProductModel>> getProducts(int warehouseId, String type);
/// Get product stages for a product in a warehouse
///
/// [request] - Request containing warehouseId and productId
///
/// Returns List<ProductStageModel> with all stages for the product
/// Throws [ServerException] if the API call fails
Future<List<ProductStageModel>> getProductDetail(ProductDetailRequestModel request);
}
/// Implementation of ProductsRemoteDataSource using ApiClient
@@ -59,4 +70,55 @@ class ProductsRemoteDataSourceImpl implements ProductsRemoteDataSource {
throw ServerException('Failed to get products: ${e.toString()}');
}
}
@override
Future<List<ProductStageModel>> getProductDetail(
ProductDetailRequestModel request) async {
try {
// Make API call to get product stages
final response = await apiClient.post(
ApiEndpoints.productDetail,
data: request.toJson(),
);
// Parse the API response - the Value field contains a list of stage objects
final apiResponse = ApiResponse.fromJson(
response.data as Map<String, dynamic>,
(json) {
// The API returns a list of stages for the product
final list = json as List;
if (list.isEmpty) {
throw const ServerException('Product stages not found');
}
// Parse all stages from the list
return list
.map((e) => ProductStageModel.fromJson(e as Map<String, dynamic>))
.toList();
},
);
// Check if the API call was successful
if (apiResponse.isSuccess && apiResponse.value != null) {
return apiResponse.value!;
} else {
// Throw exception with error message from API
throw ServerException(
apiResponse.errors.isNotEmpty
? apiResponse.errors.first
: 'Failed to get product stages',
);
}
} catch (e) {
// Re-throw ServerException as-is
if (e is ServerException) {
rethrow;
}
// Re-throw NetworkException as-is
if (e is NetworkException) {
rethrow;
}
// Wrap other exceptions in ServerException
throw ServerException('Failed to get product stages: ${e.toString()}');
}
}
}

View File

@@ -0,0 +1,25 @@
/// Request model for getting product details in a warehouse
///
/// Used to fetch product stage information for a specific warehouse and product
class ProductDetailRequestModel {
final int warehouseId;
final int productId;
const ProductDetailRequestModel({
required this.warehouseId,
required this.productId,
});
/// Convert to JSON for API request
Map<String, dynamic> toJson() {
return {
'WareHouseId': warehouseId,
'ProductId': productId,
};
}
@override
String toString() {
return 'ProductDetailRequestModel(warehouseId: $warehouseId, productId: $productId)';
}
}

View File

@@ -0,0 +1,67 @@
import '../../domain/entities/product_stage_entity.dart';
/// Product stage model for data layer
/// Represents a product at a specific production stage
class ProductStageModel extends ProductStageEntity {
const ProductStageModel({
required super.productId,
required super.productStageId,
required super.actionTypeId,
required super.passedQuantity,
required super.issuedQuantity,
required super.issuedQuantityWeight,
required super.passedQuantityWeight,
required super.stageName,
required super.createdDate,
});
/// Create ProductStageModel from JSON
factory ProductStageModel.fromJson(Map<String, dynamic> json) {
return ProductStageModel(
productId: json['ProductId'] as int,
productStageId: json['ProductStageId'] as int?,
actionTypeId: json['ActionTypeId'] as int?,
passedQuantity: json['PassedQuantity'] as int,
issuedQuantity: json['IssuedQuantity'] as int,
issuedQuantityWeight: (json['IssuedQuantityWeight'] as num).toDouble(),
passedQuantityWeight: (json['PassedQuantityWeight'] as num).toDouble(),
stageName: json['StageName'] as String?,
createdDate: json['CreatedDate'] as String,
);
}
/// Convert to JSON
Map<String, dynamic> toJson() {
return {
'ProductId': productId,
'ProductStageId': productStageId,
'ActionTypeId': actionTypeId,
'PassedQuantity': passedQuantity,
'IssuedQuantity': issuedQuantity,
'IssuedQuantityWeight': issuedQuantityWeight,
'PassedQuantityWeight': passedQuantityWeight,
'StageName': stageName,
'CreatedDate': createdDate,
};
}
/// Convert to entity
ProductStageEntity toEntity() {
return ProductStageEntity(
productId: productId,
productStageId: productStageId,
actionTypeId: actionTypeId,
passedQuantity: passedQuantity,
issuedQuantity: issuedQuantity,
issuedQuantityWeight: issuedQuantityWeight,
passedQuantityWeight: passedQuantityWeight,
stageName: stageName,
createdDate: createdDate,
);
}
@override
String toString() {
return 'ProductStageModel(productId: $productId, stageName: $stageName, passedQuantity: $passedQuantity)';
}
}

View File

@@ -2,8 +2,10 @@ import 'package:dartz/dartz.dart';
import '../../../../core/errors/exceptions.dart';
import '../../../../core/errors/failures.dart';
import '../../domain/entities/product_entity.dart';
import '../../domain/entities/product_stage_entity.dart';
import '../../domain/repositories/products_repository.dart';
import '../datasources/products_remote_datasource.dart';
import '../models/product_detail_request_model.dart';
/// Implementation of ProductsRepository
/// Handles data operations and error conversion
@@ -34,4 +36,33 @@ class ProductsRepositoryImpl implements ProductsRepository {
return Left(ServerFailure('Unexpected error: ${e.toString()}'));
}
}
@override
Future<Either<Failure, List<ProductStageEntity>>> getProductDetail(
int warehouseId,
int productId,
) async {
try {
// Create request model
final request = ProductDetailRequestModel(
warehouseId: warehouseId,
productId: productId,
);
// Fetch product stages from remote data source
final stages = await remoteDataSource.getProductDetail(request);
// Convert models to entities and return success
return Right(stages.map((stage) => stage.toEntity()).toList());
} on ServerException catch (e) {
// Convert ServerException to ServerFailure
return Left(ServerFailure(e.message));
} on NetworkException catch (e) {
// Convert NetworkException to NetworkFailure
return Left(NetworkFailure(e.message));
} catch (e) {
// Handle any other exceptions
return Left(ServerFailure('Unexpected error: ${e.toString()}'));
}
}
}