diff --git a/sigl/domain/service.py b/sigl/domain/service.py
index ef7c660..bb2799e 100644
--- a/sigl/domain/service.py
+++ b/sigl/domain/service.py
@@ -4,12 +4,13 @@ Simple Grocery List (Sigl) | sigl.app
Copyright (c) 2022 Asymworks, LLC. All Rights Reserved.
"""
+from nis import cat
from typing import List, Optional, Union
from sqlalchemy.orm import Session
from sigl.exc import DomainError, NotFoundError
-from .models import ListEntry, Product, ShoppingList
+from .models import ListEntry, Product, ProductLocation, ShoppingList
def list_addItem(
@@ -132,12 +133,16 @@ def list_editItem(
return entry
-def list_stores(session: Session, id: int) -> List[str]:
+def list_stores(session: Session, id: Optional[int]) -> List[str]:
"""Get a list of all Stores for the List.
This helper returns a list of all Stores for which the Products in the
- List have locations.
+ List have locations. If the List ID is `None`, all stores for which any
+ Product has locations are returned.
"""
+ if id is None:
+ return list(set([l.store for l in session.query(ProductLocation).all()]))
+
sList = list_by_id(session, id)
if not sList:
raise NotFoundError(f'List {id} does not exist')
@@ -216,3 +221,92 @@ def products_all(session: Session) -> List[Product]:
def product_by_id(session: Session, id: int) -> Optional[Product]:
"""Load a specific Product."""
return session.query(Product).filter(Product.id == id).one_or_none()
+
+
+def product_create(
+ session: Session,
+ name: str,
+ *,
+ category: Optional[str],
+ notes: Optional[str],
+) -> Product:
+ """Create a new Product."""
+ product = Product(name=name, category=category, notes=notes)
+ session.add(product)
+ session.commit()
+
+ return product
+
+
+def product_delete(session: Session, id: int):
+ """Delete a Product."""
+ product = product_by_id(session, id)
+ if not product:
+ raise NotFoundError(f'Product {id} does not exist')
+
+ session.delete(product)
+ session.commit()
+
+
+def product_update(
+ session: Session,
+ id: int,
+ name: str,
+ category: Optional[str],
+ notes: Optional[str],
+) -> Product:
+ """Update a Product."""
+ product = product_by_id(session, id)
+ if not product:
+ raise NotFoundError(f'Product {id} does not exist')
+
+ product.name = name
+ product.category = category
+ product.notes = notes
+ product.set_modified_at()
+
+ session.add(product)
+ session.commit()
+
+ return product
+
+
+def product_addLocation(
+ session: Session,
+ id: int,
+ store: str,
+ *,
+ aisle: Optional[str],
+ bin: Optional[str]
+) -> ProductLocation:
+ """Add a Store Location to a Product."""
+ product = product_by_id(session, id)
+ if not product:
+ raise NotFoundError(f'Product {id} does not exist')
+
+ for loc in product.locations:
+ if loc.store.lower() == store.lower():
+ raise DomainError(f'A location already exists for store {loc.store}')
+
+ loc = ProductLocation(product=product, store=store, aisle=aisle, bin=bin)
+ session.add(loc)
+ session.commit()
+
+ return loc
+
+
+def product_removeLocation(
+ session: Session,
+ id: int,
+ store: str
+):
+ """Remove a Store Location from a Product."""
+ product = product_by_id(session, id)
+ if not product:
+ raise NotFoundError(f'Product {id} does not exist')
+
+ for loc in product.locations:
+ if loc.store.lower() == store.lower():
+ session.delete(loc)
+
+ session.commit()
diff --git a/sigl/templates/base.html.j2 b/sigl/templates/base.html.j2
index 0db372f..dc615be 100644
--- a/sigl/templates/base.html.j2
+++ b/sigl/templates/base.html.j2
@@ -25,8 +25,8 @@
diff --git a/sigl/templates/lists/editItem.html.j2 b/sigl/templates/lists/editItem.html.j2
index c88f76a..f42a96b 100644
--- a/sigl/templates/lists/editItem.html.j2
+++ b/sigl/templates/lists/editItem.html.j2
@@ -24,7 +24,7 @@
Cancel
-