138 lines
4.1 KiB
Python
138 lines
4.1 KiB
Python
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.models.inventory import Inventory
|
|
from app.models.product import Product
|
|
from app.models.warehouse import Warehouse
|
|
from app.schemas.inventory import InventoryCreate, InventoryUpdate
|
|
|
|
|
|
def get(db: Session, inventory_id: int) -> Optional[Inventory]:
|
|
return db.query(Inventory).filter(Inventory.id == inventory_id).first()
|
|
|
|
|
|
def get_by_product_and_warehouse(
|
|
db: Session, *, product_id: int, warehouse_id: int
|
|
) -> Optional[Inventory]:
|
|
return (
|
|
db.query(Inventory)
|
|
.filter(Inventory.product_id == product_id, Inventory.warehouse_id == warehouse_id)
|
|
.first()
|
|
)
|
|
|
|
|
|
def get_multi(
|
|
db: Session, *, skip: int = 0, limit: int = 100, warehouse_id: Optional[int] = None
|
|
) -> List[Inventory]:
|
|
query = db.query(Inventory)
|
|
if warehouse_id:
|
|
query = query.filter(Inventory.warehouse_id == warehouse_id)
|
|
return query.offset(skip).limit(limit).all()
|
|
|
|
|
|
def create(db: Session, *, obj_in: InventoryCreate) -> Inventory:
|
|
# Check if inventory already exists for this product/warehouse combination
|
|
existing = get_by_product_and_warehouse(
|
|
db, product_id=obj_in.product_id, warehouse_id=obj_in.warehouse_id
|
|
)
|
|
if existing:
|
|
# Update quantity instead of creating new
|
|
existing.quantity += obj_in.quantity
|
|
db.add(existing)
|
|
db.commit()
|
|
db.refresh(existing)
|
|
return existing
|
|
|
|
# Create new inventory record
|
|
db_obj = Inventory(
|
|
product_id=obj_in.product_id,
|
|
warehouse_id=obj_in.warehouse_id,
|
|
quantity=obj_in.quantity,
|
|
location=obj_in.location,
|
|
min_stock_level=obj_in.min_stock_level,
|
|
max_stock_level=obj_in.max_stock_level,
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
def update(
|
|
db: Session, *, db_obj: Inventory, obj_in: Union[InventoryUpdate, Dict[str, Any]]
|
|
) -> Inventory:
|
|
if isinstance(obj_in, dict):
|
|
update_data = obj_in
|
|
else:
|
|
update_data = obj_in.dict(exclude_unset=True)
|
|
for field in update_data:
|
|
setattr(db_obj, field, update_data[field])
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
def remove(db: Session, *, inventory_id: int) -> Inventory:
|
|
obj = db.query(Inventory).get(inventory_id)
|
|
db.delete(obj)
|
|
db.commit()
|
|
return obj
|
|
|
|
|
|
def get_with_details(db: Session, inventory_id: int) -> Optional[Tuple[Inventory, str, str]]:
|
|
"""Get inventory with product and warehouse names"""
|
|
result = (
|
|
db.query(Inventory, Product.name, Warehouse.name)
|
|
.join(Product)
|
|
.join(Warehouse)
|
|
.filter(Inventory.id == inventory_id)
|
|
.first()
|
|
)
|
|
if result:
|
|
inventory, product_name, warehouse_name = result
|
|
return inventory, product_name, warehouse_name
|
|
return None
|
|
|
|
|
|
def get_multi_with_details(
|
|
db: Session, *, skip: int = 0, limit: int = 100, warehouse_id: Optional[int] = None
|
|
) -> List[Tuple[Inventory, str, str]]:
|
|
"""Get multiple inventory items with product and warehouse names"""
|
|
query = (
|
|
db.query(Inventory, Product.name, Warehouse.name)
|
|
.join(Product)
|
|
.join(Warehouse)
|
|
)
|
|
if warehouse_id:
|
|
query = query.filter(Inventory.warehouse_id == warehouse_id)
|
|
return query.offset(skip).limit(limit).all()
|
|
|
|
|
|
def update_quantity(
|
|
db: Session, *, inventory_id: int, quantity_change: int
|
|
) -> Optional[Inventory]:
|
|
"""Update inventory quantity by adding the quantity_change (can be negative)"""
|
|
inventory = get(db, inventory_id)
|
|
if not inventory:
|
|
return None
|
|
|
|
inventory.quantity += quantity_change
|
|
if inventory.quantity < 0:
|
|
inventory.quantity = 0
|
|
|
|
db.add(inventory)
|
|
db.commit()
|
|
db.refresh(inventory)
|
|
return inventory
|
|
|
|
|
|
def get_low_stock_items(db: Session, *, limit: int = 100) -> List[Inventory]:
|
|
"""Get inventory items where quantity is below min_stock_level"""
|
|
return (
|
|
db.query(Inventory)
|
|
.filter(Inventory.quantity < Inventory.min_stock_level)
|
|
.limit(limit)
|
|
.all()
|
|
) |