import 'package:drift/drift.dart'; import 'package:uuid/uuid.dart'; import '../database/app_database.dart'; import '../models/product.dart'; class InsufficientStockException implements Exception { const InsufficientStockException(); @override String toString() => 'Not enough stock'; } abstract class ProductService { Future> getProducts(); Future getProductById(String id); Future createProduct({ required String name, required String category, required int stockQuantity, required int lowStockThreshold, required int priceInCents, required String? imagePath, }); Future updateProduct(Product product); Future deleteProduct(String id); Future decreaseStock(String productId, int amount); Future increaseStock(String productId, int amount); } class DriftProductService implements ProductService { final AppDatabase database; final _uuid = const Uuid(); DriftProductService({required this.database}); Product _mapRowToProduct(ProductRow row) { return Product( id: row.id, name: row.name, category: row.category, stockQuantity: row.stockQuantity, lowStockThreshold: row.lowStockThreshold, priceInCents: row.priceInCents, imagePath: row.imagePath, active: row.active, ); } @override Future> getProducts() async { final query = database.select(database.products) ..where((product) => product.active.equals(true)) ..orderBy([(product) => OrderingTerm.asc(product.name)]); final rows = await query.get(); return rows.map(_mapRowToProduct).toList(); } @override Future getProductById(String id) async { final query = database.select(database.products) ..where((product) => product.id.equals(id)); final row = await query.getSingleOrNull(); if (row == null) { return null; } return _mapRowToProduct(row); } @override Future createProduct({ required String name, required String category, required int stockQuantity, required int lowStockThreshold, required int priceInCents, required String? imagePath, }) async { await database .into(database.products) .insert( ProductsCompanion.insert( id: _uuid.v4(), name: name, category: category, stockQuantity: stockQuantity, lowStockThreshold: lowStockThreshold, priceInCents: priceInCents, imagePath: Value(imagePath), ), ); } @override Future updateProduct(Product product) async { final query = database.update(database.products) ..where((row) => row.id.equals(product.id)); await query.write( ProductsCompanion( name: Value(product.name), category: Value(product.category), stockQuantity: Value(product.stockQuantity), lowStockThreshold: Value(product.lowStockThreshold), priceInCents: Value(product.priceInCents), imagePath: Value(product.imagePath), active: Value(product.active), ), ); } @override Future deleteProduct(String id) async { final query = database.delete(database.products) ..where((product) => product.id.equals(id)); await query.go(); } @override Future decreaseStock(String productId, int amount) async { final product = await getProductById(productId); if (product == null) { throw Exception('Product not found'); } if (product.stockQuantity < amount) { throw const InsufficientStockException(); } await updateProduct( product.copyWith(stockQuantity: product.stockQuantity - amount), ); } @override Future increaseStock(String productId, int amount) async { final product = await getProductById(productId); if (product == null) { throw Exception('Product not found'); } await updateProduct( product.copyWith(stockQuantity: product.stockQuantity + amount), ); } }