price policy

This commit is contained in:
Phuoc Nguyen
2025-11-26 14:44:17 +07:00
parent a07f165f0c
commit 88ac2f2f07
14 changed files with 588 additions and 654 deletions

View File

@@ -1,59 +1,44 @@
/// Repository Implementation: Price Policy Repository
///
/// Concrete implementation of the PricePolicyRepository interface.
/// Coordinates between local and remote data sources to provide price policy data.
///
/// Currently uses mock data from local datasource.
/// Will implement offline-first strategy when backend API is available.
/// Fetches price policy documents from remote API.
library;
import 'package:worker/features/price_policy/data/datasources/price_policy_local_datasource.dart';
import 'package:worker/features/price_policy/data/datasources/price_policy_remote_datasource.dart';
import 'package:worker/features/price_policy/domain/entities/price_document.dart';
import 'package:worker/features/price_policy/domain/repositories/price_policy_repository.dart';
/// Price Policy Repository Implementation
///
/// Responsibilities:
/// - Coordinate between local cache and remote API (when available)
/// - Convert data models to domain entities
/// - Handle errors gracefully
/// - Manage cache invalidation
class PricePolicyRepositoryImpl implements PricePolicyRepository {
/// Local data source
final PricePolicyLocalDataSource localDataSource;
/// Remote data source (API) - TODO: Add when API is ready
// final PricePolicyRemoteDataSource remoteDataSource;
/// Remote data source
final PricePolicyRemoteDataSource remoteDataSource;
/// Constructor
PricePolicyRepositoryImpl({
required this.localDataSource,
// required this.remoteDataSource, // TODO: Add when API ready
const PricePolicyRepositoryImpl({
required this.remoteDataSource,
});
@override
Future<List<PriceDocument>> getAllDocuments() async {
try {
// TODO: Implement offline-first strategy
// 1. Check if cache is valid
// 2. Return cached data if valid
// 3. If cache invalid, fetch from remote
// Fetch documents separately to maintain category info
final pricingRuleModels =
await remoteDataSource.getDocumentsByType('PRICING_RULE');
final priceListModels =
await remoteDataSource.getDocumentsByType('PRICE_LIST');
// For now, get from local datasource (mock data)
final models = await localDataSource.getAllDocuments();
final entities = <PriceDocument>[
...pricingRuleModels.map((model) => model.toEntity(DocumentCategory.policy)),
...priceListModels.map((model) => model.toEntity(DocumentCategory.priceList)),
];
// Convert models to entities
final entities = models.map((model) => model.toEntity()).toList();
// Sort by published date (newest first)
entities.sort((a, b) => b.publishedDate.compareTo(a.publishedDate));
// Sort by update date (newest first)
entities.sort((a, b) => b.updatedAt.compareTo(a.updatedAt));
return entities;
} catch (e) {
// Log error and return empty list
// In production, this should throw proper domain failures
print('[PricePolicyRepository] Error getting documents: $e');
return [];
rethrow;
}
}
@@ -62,37 +47,35 @@ class PricePolicyRepositoryImpl implements PricePolicyRepository {
DocumentCategory category,
) async {
try {
// Convert category to string for datasource
final categoryString = _categoryToString(category);
// Convert category to API parameter
final pricingType = category.apiValue;
// Get documents from local datasource
final models = await localDataSource.getDocumentsByCategory(
categoryString,
);
// Fetch documents by type from API
final models = await remoteDataSource.getDocumentsByType(pricingType);
// Convert models to entities
final entities = models.map((model) => model.toEntity()).toList();
// Convert models to entities with the correct category
final entities = models.map((model) => model.toEntity(category)).toList();
// Sort by published date (newest first)
entities.sort((a, b) => b.publishedDate.compareTo(a.publishedDate));
// Sort by update date (newest first)
entities.sort((a, b) => b.updatedAt.compareTo(a.updatedAt));
return entities;
} catch (e) {
print('[PricePolicyRepository] Error getting documents by category: $e');
return [];
rethrow;
}
}
@override
Future<PriceDocument?> getDocumentById(String documentId) async {
try {
// Get document from local datasource
final model = await localDataSource.getDocumentById(documentId);
// Convert model to entity
return model?.toEntity();
// Since API doesn't have a get-by-id endpoint,
// we fetch all and find the matching one
final allDocuments = await getAllDocuments();
return allDocuments.firstWhere(
(doc) => doc.title == documentId,
orElse: () => throw Exception('Document not found'),
);
} catch (e) {
print('[PricePolicyRepository] Error getting document by id: $e');
return null;
}
}
@@ -100,35 +83,10 @@ class PricePolicyRepositoryImpl implements PricePolicyRepository {
@override
Future<List<PriceDocument>> refreshDocuments() async {
try {
// TODO: Implement remote fetch when API is available
// 1. Fetch from remote API
// 2. Cache the results locally
// 3. Return fresh data
// For now, just clear and refetch from local
await localDataSource.clearCache();
final models = await localDataSource.getAllDocuments();
// Convert models to entities
final entities = models.map((model) => model.toEntity()).toList();
// Sort by published date (newest first)
entities.sort((a, b) => b.publishedDate.compareTo(a.publishedDate));
return entities;
// Refresh is same as getAllDocuments since we're fetching from API
return await getAllDocuments();
} catch (e) {
print('[PricePolicyRepository] Error refreshing documents: $e');
return [];
}
}
/// Helper method to convert category enum to string
String _categoryToString(DocumentCategory category) {
switch (category) {
case DocumentCategory.policy:
return 'policy';
case DocumentCategory.priceList:
return 'priceList';
rethrow;
}
}
}