diff --git a/sigl/domain/service.py b/sigl/domain/service.py index a1854df..17a0feb 100644 --- a/sigl/domain/service.py +++ b/sigl/domain/service.py @@ -8,8 +8,56 @@ from typing import List, Optional, Union from sqlalchemy.orm import Session -from sigl.exc import NotFoundError -from .models import ListEntry, ShoppingList +from sigl.exc import DomainError, NotFoundError +from .models import ListEntry, Product, ShoppingList + + +def list_addItem( + session: Session, + id: int, + *, + productId: Optional[int], + productName: Optional[str], + productCategory: Optional[str], + quantity: Optional[str], + notes: Optional[str], +) -> ListEntry: + """Add a Product to a Shopping List. + + If the `productId` parameter is provided, the method will look up the + product by ID and add it to the list. If the `product` parameter is not + provided, a new `Product` will be created with the provided `productName` + and `productCategory` values. + """ + sList = list_by_id(session, id) + if not sList: + raise NotFoundError(f'List {id} does not exist') + + product = None + if not productId: + if not productName: + raise DomainError('Product Name cannot be empty') + + product = Product(name=productName, category=productCategory) + + session.add(product) + + else: + product = product_by_id(session, productId) + if not product: + raise NotFoundError(f'Product {productId} does not exist') + + entry = ListEntry( + shoppingList=sList, + product=product, + quantity=quantity, + notes=notes, + ) + + session.add(entry) + session.commit() + + return entry def lists_all(session: Session) -> List[ShoppingList]: @@ -43,7 +91,7 @@ def list_delete(session: Session, id: int): def list_stores(session: Session, id: 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. """ @@ -67,8 +115,8 @@ def list_stores(session: Session, id: int) -> List[str]: def list_update( session: Session, id: int, - name: Union[str,None], - notes: Union[str,None], + name: Union[str, None], + notes: Union[str, None], ) -> ShoppingList: """Update the Name and/or Notes of a Shopping List.""" sList = list_by_id(session, id) @@ -82,3 +130,13 @@ def list_update( session.commit() return sList + + +def products_all(session: Session) -> List[Product]: + """Return all Products.""" + return session.query(Product).all() + + +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() diff --git a/sigl/templates/lists/detail.html.j2 b/sigl/templates/lists/detail.html.j2 index 59be874..86f26ad 100644 --- a/sigl/templates/lists/detail.html.j2 +++ b/sigl/templates/lists/detail.html.j2 @@ -4,7 +4,7 @@
{{ list.name }}
- + diff --git a/sigl/views/lists.py b/sigl/views/lists.py index a2f3844..d1201af 100644 --- a/sigl/views/lists.py +++ b/sigl/views/lists.py @@ -6,14 +6,15 @@ Copyright (c) 2022 Asymworks, LLC. All Rights Reserved. from flask import ( Blueprint, - abort, flash, redirect, render_template, request, url_for + flash, redirect, render_template, request, url_for ) from sigl.exc import Error from sigl.database import db from sigl.domain.service import ( lists_all, list_by_id, list_create, list_delete, - list_stores, + list_addItem, list_stores, + products_all, ) __all__ = ('bp', ) @@ -73,10 +74,10 @@ def detail(id): aisle = 'Unknown' bin = None locs = e.product.locations - for l in locs: - if l.store.lower() == sortStore.lower(): - aisle = l.aisle - bin = l.bin + for loc in locs: + if loc.store.lower() == sortStore.lower(): + aisle = loc.aisle + bin = loc.bin if aisle not in groups: groups[aisle] = [{'entry': e, 'bin': bin}] @@ -90,7 +91,6 @@ def detail(id): else: groups[category].append({'entry': e}) - flash('An error occurred during the processing of this request', 'error') return render_template( 'lists/detail.html.j2', list=list_by_id(db.session, id), @@ -113,4 +113,53 @@ def delete(id): except Error as e: flash(str(e), 'error') - return redirect(url_for('lists.home')) + return redirect(url_for('lists.home')) + + +@bp.route('/lists//addItem', methods=('GET', 'POST')) +def addItem(id): + """Add an Item to a Shopping List.""" + try: + sList = list_by_id(db.session, id) + products = products_all(db.session) + if request.method == 'POST': + if 'product' not in request.form: + flash( + 'An internal error occurred. Please reload the page and try again', + 'error' + ) + return render_template( + '/lists/addItem.html.j2', + list=sList, + products=products, + ) + + productId = request.form['product'] + productName = request.form.get('productName', None) + productCategory = request.form.get('productCategory', None) + quantity = request.form.get('quantity', None) + notes = request.form.get('notes', None) + + if productId == 'new' or productId == '': + productId = None + + list_addItem( + db.session, + id, + productId=productId, + productName=productName, + productCategory=productCategory, + quantity=quantity, + notes=notes, + ) + + return redirect(url_for('lists.detail', id=id)) + + except Error as e: + flash(str(e), 'error') + + return render_template( + '/lists/addItem.html.j2', + list=sList, + products=products, + )