178 lines
4.6 KiB
Dart
178 lines
4.6 KiB
Dart
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<List<Product>> getProducts();
|
|
|
|
Future<Product?> getProductById(String id);
|
|
|
|
Future<void> createProduct({
|
|
required String name,
|
|
required String category,
|
|
required int stockQuantity,
|
|
required int lowStockThreshold,
|
|
required int priceInCents,
|
|
required String? imagePath,
|
|
});
|
|
|
|
Future<void> updateProduct(Product product);
|
|
|
|
Future<void> deleteProduct(String id);
|
|
|
|
Future<void> decreaseStock(String productId, int amount);
|
|
|
|
Future<void> 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<List<Product>> 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<Product?> 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<void> 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<void> 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<void> deleteProduct(String id) async {
|
|
final query = database.delete(database.products)
|
|
..where((product) => product.id.equals(id));
|
|
|
|
await query.go();
|
|
}
|
|
|
|
@override
|
|
Future<void> decreaseStock(String productId, int amount) async {
|
|
_validateStockAmount(amount);
|
|
|
|
final updatedRows = await database.customUpdate(
|
|
'UPDATE products '
|
|
'SET stock_quantity = stock_quantity - ? '
|
|
'WHERE id = ? AND stock_quantity >= ?',
|
|
variables: [
|
|
Variable.withInt(amount),
|
|
Variable.withString(productId),
|
|
Variable.withInt(amount),
|
|
],
|
|
updates: {database.products},
|
|
);
|
|
|
|
if (updatedRows == 1) return;
|
|
|
|
final product = await getProductById(productId);
|
|
if (product == null) throw Exception('Product not found');
|
|
|
|
throw const InsufficientStockException();
|
|
}
|
|
|
|
@override
|
|
Future<void> increaseStock(String productId, int amount) async {
|
|
_validateStockAmount(amount);
|
|
|
|
final updatedRows = await database.customUpdate(
|
|
'UPDATE products '
|
|
'SET stock_quantity = stock_quantity + ? '
|
|
'WHERE id = ?',
|
|
variables: [Variable.withInt(amount), Variable.withString(productId)],
|
|
updates: {database.products},
|
|
);
|
|
|
|
if (updatedRows == 1) return;
|
|
|
|
throw Exception('Product not found');
|
|
}
|
|
|
|
void _validateStockAmount(int amount) {
|
|
if (amount <= 0) {
|
|
throw ArgumentError.value(amount, 'amount', 'Must be greater than zero');
|
|
}
|
|
}
|
|
}
|