Implemented recipes being added to shopping lists
This commit is contained in:
parent
c9674b93b9
commit
86e40f70f1
Binary file not shown.
@ -1,20 +1,11 @@
|
|||||||
CREATE TABLE IF NOT EXISTS %%site_name%%_shopping_list_items (
|
CREATE TABLE IF NOT EXISTS %%site_name%%_shopping_list_items (
|
||||||
id SERIAL PRIMARY KEY,
|
list_item_uuid UUID DEFAULT uuid_generate_v4() NOT NULL PRIMARY KEY,
|
||||||
uuid VARCHAR(32) NOT NULL,
|
list_uuid UUID NOT NULL,
|
||||||
sl_id INTEGER NOT NULL,
|
|
||||||
item_type VARCHAR(32) NOT NULL,
|
item_type VARCHAR(32) NOT NULL,
|
||||||
item_name TEXT NOT NULL,
|
item_name TEXT NOT NULL,
|
||||||
uom INTEGER NOT NULL,
|
uom INTEGER NOT NULL,
|
||||||
qty FLOAT8 NOT NULL,
|
qty FLOAT8 NOT NULL,
|
||||||
item_id INTEGER DEFAULT NULL,
|
item_uuid UUID DEFAULT NULL,
|
||||||
links JSONB DEFAULT '{"main": ""}',
|
links JSONB DEFAULT '{"main": ""}',
|
||||||
UNIQUE(uuid, sl_id),
|
UNIQUE(list_uuid, item_uuid)
|
||||||
CONSTRAINT fk_sl_id
|
|
||||||
FOREIGN KEY(sl_id)
|
|
||||||
REFERENCES %%site_name%%_shopping_lists(id)
|
|
||||||
ON DELETE CASCADE,
|
|
||||||
CONSTRAINT fk_item_id
|
|
||||||
FOREIGN KEY(item_id)
|
|
||||||
REFERENCES %%site_name%%_items(id)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);
|
);
|
||||||
@ -1,9 +1,11 @@
|
|||||||
CREATE TABLE IF NOT EXISTS %%site_name%%_shopping_lists (
|
CREATE TABLE IF NOT EXISTS %%site_name%%_shopping_lists (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
|
list_uuid UUID DEFAULT uuid_generate_v4() NOT NULL,
|
||||||
|
list_type VARCHAR(32),
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
author INTEGER,
|
author INTEGER,
|
||||||
creation_date TIMESTAMP,
|
creation_date TIMESTAMP,
|
||||||
type VARCHAR(64),
|
sub_type VARCHAR(64),
|
||||||
UNIQUE(name)
|
UNIQUE(list_uuid, name)
|
||||||
);
|
);
|
||||||
@ -305,24 +305,22 @@ class ReceiptPayload:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ShoppingListItemPayload:
|
class ShoppingListItemPayload:
|
||||||
uuid: str
|
list_uuid: str
|
||||||
sl_id: int
|
|
||||||
item_type: str
|
item_type: str
|
||||||
item_name: str
|
item_name: str
|
||||||
uom: str
|
uom: int
|
||||||
qty: float
|
qty: float
|
||||||
item_id: int = None
|
item_uuid: str = None
|
||||||
links: dict = field(default_factory=dict)
|
links: dict = field(default_factory=dict)
|
||||||
|
|
||||||
def payload(self):
|
def payload(self):
|
||||||
return (
|
return (
|
||||||
self.uuid,
|
self.list_uuid,
|
||||||
self.sl_id,
|
|
||||||
self.item_type,
|
self.item_type,
|
||||||
self.item_name,
|
self.item_name,
|
||||||
self.uom,
|
self.uom,
|
||||||
self.qty,
|
self.qty,
|
||||||
self.item_id,
|
self.item_uuid,
|
||||||
json.dumps(self.links)
|
json.dumps(self.links)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -7,7 +7,7 @@ import math
|
|||||||
# APPLICATION IMPORTS
|
# APPLICATION IMPORTS
|
||||||
from application import postsqldb, database_payloads
|
from application import postsqldb, database_payloads
|
||||||
from application.access_module import access_api
|
from application.access_module import access_api
|
||||||
from application.shoppinglists import shoplist_database
|
from application.shoppinglists import shoplist_database, shoplist_processess
|
||||||
|
|
||||||
shopping_list_api = Blueprint('shopping_list_API', __name__, template_folder="templates", static_folder="static")
|
shopping_list_api = Blueprint('shopping_list_API', __name__, template_folder="templates", static_folder="static")
|
||||||
|
|
||||||
@ -19,14 +19,14 @@ def shopping_lists():
|
|||||||
sites = [site[1] for site in postsqldb.get_sites(session['user']['sites'])]
|
sites = [site[1] for site in postsqldb.get_sites(session['user']['sites'])]
|
||||||
return render_template("lists.html", current_site=session['selected_site'], sites=sites)
|
return render_template("lists.html", current_site=session['selected_site'], sites=sites)
|
||||||
|
|
||||||
@shopping_list_api.route("/<mode>/<id>")
|
@shopping_list_api.route("/<mode>/<list_uuid>")
|
||||||
@access_api.login_required
|
@access_api.login_required
|
||||||
def shopping_list(mode, id):
|
def shopping_list(mode, list_uuid):
|
||||||
sites = [site[1] for site in postsqldb.get_sites(session['user']['sites'])]
|
sites = [site[1] for site in postsqldb.get_sites(session['user']['sites'])]
|
||||||
if mode == "view":
|
if mode == "view":
|
||||||
return render_template("view.html", id=id, current_site=session['selected_site'], sites=sites)
|
return render_template("view.html", list_uuid=list_uuid, current_site=session['selected_site'], sites=sites)
|
||||||
if mode == "edit":
|
if mode == "edit":
|
||||||
return render_template("edit.html", id=id, current_site=session['selected_site'], sites=sites)
|
return render_template("edit.html", list_uuid=list_uuid, current_site=session['selected_site'], sites=sites)
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
# API CALLS
|
# API CALLS
|
||||||
@ -65,20 +65,19 @@ def getShoppingLists():
|
|||||||
|
|
||||||
for list in lists:
|
for list in lists:
|
||||||
|
|
||||||
if list['type'] == 'calculated':
|
if list['sub_type'] == 'calculated':
|
||||||
items = []
|
items = []
|
||||||
not_items = shoplist_database.getItemsSafetyStock(site_name)
|
not_items = shoplist_database.getItemsSafetyStock(site_name)
|
||||||
for item in not_items:
|
for item in not_items:
|
||||||
new_item = {
|
new_item = {
|
||||||
'id': item['id'],
|
'list_item_uuid': 0,
|
||||||
'uuid': item['barcode'],
|
'list_uuid': list['list_uuid'],
|
||||||
'sl_id': 0,
|
|
||||||
'item_type': 'sku',
|
'item_type': 'sku',
|
||||||
'item_name': item['item_name'],
|
'item_name': item['item_name'],
|
||||||
'uom': item['uom'],
|
'uom': item['item_info']['uom'],
|
||||||
'qty': float(float(item['safety_stock']) - float(item['total_sum'])),
|
'qty': float(float(item['item_info']['safety_stock']) - float(item['total_sum'])),
|
||||||
'item_id': item['id'],
|
'links': item['links'],
|
||||||
'links': item['links']
|
'uom_fullname': ['uom_fullname']
|
||||||
}
|
}
|
||||||
items.append(new_item)
|
items.append(new_item)
|
||||||
list['sl_items'] = items
|
list['sl_items'] = items
|
||||||
@ -90,9 +89,9 @@ def getShoppingLists():
|
|||||||
@access_api.login_required
|
@access_api.login_required
|
||||||
def getShoppingList():
|
def getShoppingList():
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
sl_id = int(request.args.get('id', 1))
|
list_uuid = request.args.get('list_uuid', 1)
|
||||||
site_name = session['selected_site']
|
site_name = session['selected_site']
|
||||||
list = shoplist_database.getShoppingList(site_name, (sl_id, ))
|
list = shoplist_database.getShoppingList(site_name, (list_uuid, ))
|
||||||
return jsonify({'shopping_list': list, 'error': False, 'message': 'Lists queried successfully!'})
|
return jsonify({'shopping_list': list, 'error': False, 'message': 'Lists queried successfully!'})
|
||||||
|
|
||||||
# Added to Database
|
# Added to Database
|
||||||
@ -101,9 +100,9 @@ def getShoppingList():
|
|||||||
def getShoppingListItem():
|
def getShoppingListItem():
|
||||||
list_item = {}
|
list_item = {}
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
sli_id = int(request.args.get('sli_id', 1))
|
list_item_uuid = request.args.get('list_item_uuid', '')
|
||||||
site_name = session['selected_site']
|
site_name = session['selected_site']
|
||||||
list_item = shoplist_database.getShoppingListItem(site_name, (sli_id, ))
|
list_item = shoplist_database.getShoppingListItem(site_name, (list_item_uuid, ))
|
||||||
return jsonify({'list_item': list_item, 'error': False, 'message': 'Lists Items queried successfully!'})
|
return jsonify({'list_item': list_item, 'error': False, 'message': 'Lists Items queried successfully!'})
|
||||||
return jsonify({'list_item': list_item, 'error': True, 'message': 'List Items queried unsuccessfully!'})
|
return jsonify({'list_item': list_item, 'error': True, 'message': 'List Items queried unsuccessfully!'})
|
||||||
|
|
||||||
@ -125,6 +124,24 @@ def getItems():
|
|||||||
return jsonify({"items":recordset, "end":math.ceil(count['count']/limit), "error":False, "message":"items fetched succesfully!"})
|
return jsonify({"items":recordset, "end":math.ceil(count['count']/limit), "error":False, "message":"items fetched succesfully!"})
|
||||||
return jsonify({"items":recordset, "end":math.ceil(count['count']/limit), "error":True, "message":"There was an error with this GET statement"})
|
return jsonify({"items":recordset, "end":math.ceil(count['count']/limit), "error":True, "message":"There was an error with this GET statement"})
|
||||||
|
|
||||||
|
@shopping_list_api.route('/api/getRecipesModal', methods=["GET"])
|
||||||
|
@access_api.login_required
|
||||||
|
def getRecipesModal():
|
||||||
|
recordsets = []
|
||||||
|
count = 0
|
||||||
|
if request.method == "GET":
|
||||||
|
page = int(request.args.get('page', 1))
|
||||||
|
limit = int(request.args.get('limit', 10))
|
||||||
|
search_string = request.args.get('search_string', 10)
|
||||||
|
site_name = session['selected_site']
|
||||||
|
offset = (page - 1) * limit
|
||||||
|
|
||||||
|
payload = (search_string, limit, offset)
|
||||||
|
recordsets, count = shoplist_database.getRecipesModal(site_name, payload)
|
||||||
|
return jsonify(status=201, recipes=recordsets, end=math.ceil(count/limit), message=f"Recipes fetched successfully!")
|
||||||
|
return jsonify(status=405, recipes=recordsets, end=math.ceil(count/limit), message=f"{request.method} is not an accepted method on this endpoint!")
|
||||||
|
|
||||||
|
|
||||||
# Added to database
|
# Added to database
|
||||||
@shopping_list_api.route('/api/postListItem', methods=["POST"])
|
@shopping_list_api.route('/api/postListItem', methods=["POST"])
|
||||||
@access_api.login_required
|
@access_api.login_required
|
||||||
@ -133,6 +150,27 @@ def postListItem():
|
|||||||
data = request.get_json()['data']
|
data = request.get_json()['data']
|
||||||
site_name = session['selected_site']
|
site_name = session['selected_site']
|
||||||
sl_item = database_payloads.ShoppingListItemPayload(
|
sl_item = database_payloads.ShoppingListItemPayload(
|
||||||
|
list_uuid = data['list_uuid'],
|
||||||
|
item_type=data['item_type'],
|
||||||
|
item_name=data['item_name'],
|
||||||
|
uom=data['uom'],
|
||||||
|
qty=data['qty'],
|
||||||
|
item_uuid=data['item_uuid'],
|
||||||
|
links=data['links']
|
||||||
|
)
|
||||||
|
shoplist_database.insertShoppingListItemsTuple(site_name, sl_item.payload())
|
||||||
|
return jsonify({"error":False, "message":"items fetched succesfully!"})
|
||||||
|
return jsonify({"error":True, "message":"There was an error with this GET statement"})
|
||||||
|
|
||||||
|
@shopping_list_api.route('/api/postRecipeLine', methods=["POST"])
|
||||||
|
@access_api.login_required
|
||||||
|
def postRecipeLine():
|
||||||
|
if request.method == "POST":
|
||||||
|
data = request.get_json()
|
||||||
|
|
||||||
|
site_name = session['selected_site']
|
||||||
|
user_id = session['user_id']
|
||||||
|
"""sl_item = database_payloads.ShoppingListItemPayload(
|
||||||
uuid = data['uuid'],
|
uuid = data['uuid'],
|
||||||
sl_id = data['sl_id'],
|
sl_id = data['sl_id'],
|
||||||
item_type=data['item_type'],
|
item_type=data['item_type'],
|
||||||
@ -142,7 +180,9 @@ def postListItem():
|
|||||||
item_id=data['item_id'],
|
item_id=data['item_id'],
|
||||||
links=data['links']
|
links=data['links']
|
||||||
)
|
)
|
||||||
shoplist_database.insertShoppingListItemsTuple(site_name, sl_item.payload())
|
shoplist_database.insertShoppingListItemsTuple(site_name, sl_item.payload())"""
|
||||||
|
shoplist_processess.addRecipeItemsToList(site_name, data, user_id)
|
||||||
|
|
||||||
return jsonify({"error":False, "message":"items fetched succesfully!"})
|
return jsonify({"error":False, "message":"items fetched succesfully!"})
|
||||||
return jsonify({"error":True, "message":"There was an error with this GET statement"})
|
return jsonify({"error":True, "message":"There was an error with this GET statement"})
|
||||||
|
|
||||||
@ -162,10 +202,10 @@ def deleteListItem():
|
|||||||
@access_api.login_required
|
@access_api.login_required
|
||||||
def saveListItem():
|
def saveListItem():
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
sli_id = request.get_json()['sli_id']
|
list_item_uuid = request.get_json()['list_item_uuid']
|
||||||
update = request.get_json()['update']
|
update = request.get_json()['update']
|
||||||
site_name = session['selected_site']
|
site_name = session['selected_site']
|
||||||
shoplist_database.updateShoppingListItemsTuple(site_name, {'id': sli_id, 'update': update})
|
shoplist_database.updateShoppingListItemsTuple(site_name, {'uuid': list_item_uuid, 'update': update})
|
||||||
return jsonify({"error":False, "message":"items fetched succesfully!"})
|
return jsonify({"error":False, "message":"items fetched succesfully!"})
|
||||||
return jsonify({"error":True, "message":"There was an error with this GET statement"})
|
return jsonify({"error":True, "message":"There was an error with this GET statement"})
|
||||||
|
|
||||||
@ -179,6 +219,7 @@ def getSKUItemsFull():
|
|||||||
site_name = session['selected_site']
|
site_name = session['selected_site']
|
||||||
|
|
||||||
not_items = shoplist_database.getItemsSafetyStock(site_name)
|
not_items = shoplist_database.getItemsSafetyStock(site_name)
|
||||||
|
print(not_items)
|
||||||
for item in not_items:
|
for item in not_items:
|
||||||
new_item = {
|
new_item = {
|
||||||
'id': item['id'],
|
'id': item['id'],
|
||||||
@ -186,10 +227,11 @@ def getSKUItemsFull():
|
|||||||
'sl_id': 0,
|
'sl_id': 0,
|
||||||
'item_type': 'sku',
|
'item_type': 'sku',
|
||||||
'item_name': item['item_name'],
|
'item_name': item['item_name'],
|
||||||
'uom': item['uom'],
|
'uom': item['item_info']['uom'],
|
||||||
'qty': float(float(item['safety_stock']) - float(item['total_sum'])),
|
'qty': float(float(item['item_info']['safety_stock']) - float(item['total_sum'])),
|
||||||
'item_id': item['id'],
|
'item_id': item['id'],
|
||||||
'links': item['links']
|
'links': item['links'],
|
||||||
|
'uom_fullname': item['uom_fullname']
|
||||||
}
|
}
|
||||||
items.append(new_item)
|
items.append(new_item)
|
||||||
return jsonify({"list_items":items, "error":False, "message":"items fetched succesfully!"})
|
return jsonify({"list_items":items, "error":False, "message":"items fetched succesfully!"})
|
||||||
|
|||||||
@ -122,6 +122,35 @@ def getShoppingListItem(site, payload, convert=True, conn=None):
|
|||||||
except Exception as error:
|
except Exception as error:
|
||||||
raise postsqldb.DatabaseError(error, payload, sql)
|
raise postsqldb.DatabaseError(error, payload, sql)
|
||||||
|
|
||||||
|
def getRecipeItemsByUUID(site, payload, convert=True, conn=None):
|
||||||
|
recordset = ()
|
||||||
|
self_conn = False
|
||||||
|
with open('application/shoppinglists/sql/getRecipeItemsByUUID.sql', 'r') as file:
|
||||||
|
sql = file.read().replace("%%site_name%%", site)
|
||||||
|
try:
|
||||||
|
|
||||||
|
if not conn:
|
||||||
|
database_config = config.config()
|
||||||
|
conn = psycopg2.connect(**database_config)
|
||||||
|
conn.autocommit = True
|
||||||
|
self_conn = True
|
||||||
|
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(sql, payload)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
if rows and convert:
|
||||||
|
recordset = [postsqldb.tupleDictionaryFactory(cur.description, row) for row in rows]
|
||||||
|
elif rows and not convert:
|
||||||
|
recordset = rows
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return recordset
|
||||||
|
except Exception as error:
|
||||||
|
raise postsqldb.DatabaseError(error, payload, sql)
|
||||||
|
|
||||||
|
|
||||||
def getItemsWithQOH(site, payload, convert=True, conn=None):
|
def getItemsWithQOH(site, payload, convert=True, conn=None):
|
||||||
recordset = []
|
recordset = []
|
||||||
count = 0
|
count = 0
|
||||||
@ -161,11 +190,47 @@ def getItemsWithQOH(site, payload, convert=True, conn=None):
|
|||||||
|
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
raise postsqldb.DatabaseError(error, payload, sql)
|
raise postsqldb.DatabaseError(error, payload, sql)
|
||||||
|
|
||||||
|
def getRecipesModal(site, payload, convert=True, conn=None):
|
||||||
|
recordsets = []
|
||||||
|
count = 0
|
||||||
|
self_conn = False
|
||||||
|
|
||||||
|
|
||||||
|
sql = f"SELECT recipes.recipe_uuid, recipes.name FROM {site}_recipes recipes WHERE recipes.name LIKE '%%' || %s || '%%' LIMIT %s OFFSET %s;"
|
||||||
|
sql_count = f"SELECT COUNT(*) FROM {site}_recipes recipes WHERE recipes.name LIKE '%%' || %s || '%%';"
|
||||||
|
try:
|
||||||
|
if not conn:
|
||||||
|
database_config = config.config()
|
||||||
|
conn = psycopg2.connect(**database_config)
|
||||||
|
conn.autocommit = True
|
||||||
|
self_conn = True
|
||||||
|
|
||||||
|
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(sql, payload)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
if rows and convert:
|
||||||
|
recordsets = [postsqldb.tupleDictionaryFactory(cur.description, row) for row in rows]
|
||||||
|
if rows and not convert:
|
||||||
|
recordsets = rows
|
||||||
|
|
||||||
|
|
||||||
|
cur.execute(sql_count, (payload[0], ))
|
||||||
|
count = cur.fetchone()[0]
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return recordsets, count
|
||||||
|
|
||||||
|
except Exception as error:
|
||||||
|
raise postsqldb.DatabaseError(error, payload, sql)
|
||||||
|
|
||||||
def deleteShoppingListItemsTuple(site_name, payload, convert=True, conn=None):
|
def deleteShoppingListItemsTuple(site_name, payload, convert=True, conn=None):
|
||||||
deleted = ()
|
deleted = ()
|
||||||
self_conn = False
|
self_conn = False
|
||||||
sql = f"WITH deleted_rows AS (DELETE FROM {site_name}_shopping_list_items WHERE id IN ({','.join(['%s'] * len(payload))}) RETURNING *) SELECT * FROM deleted_rows;"
|
sql = f"WITH deleted_rows AS (DELETE FROM {site_name}_shopping_list_items WHERE {site_name}_shopping_list_items.list_item_uuid IN ({','.join(['%s'] * len(payload))}) RETURNING *) SELECT * FROM deleted_rows;"
|
||||||
try:
|
try:
|
||||||
|
|
||||||
if not conn:
|
if not conn:
|
||||||
@ -252,8 +317,8 @@ def updateShoppingListItemsTuple(site, payload, convert=True, conn=None):
|
|||||||
updated = ()
|
updated = ()
|
||||||
self_conn = False
|
self_conn = False
|
||||||
set_clause, values = postsqldb.updateStringFactory(payload['update'])
|
set_clause, values = postsqldb.updateStringFactory(payload['update'])
|
||||||
values.append(payload['id'])
|
values.append(payload['uuid'])
|
||||||
sql = f"UPDATE {site}_shopping_list_items SET {set_clause} WHERE id=%s RETURNING *;"
|
sql = f"UPDATE {site}_shopping_list_items SET {set_clause} WHERE list_item_uuid=%s::uuid RETURNING *;"
|
||||||
try:
|
try:
|
||||||
if not conn:
|
if not conn:
|
||||||
database_config = config.config()
|
database_config = config.config()
|
||||||
|
|||||||
@ -0,0 +1,39 @@
|
|||||||
|
import psycopg2
|
||||||
|
|
||||||
|
from application.shoppinglists import shoplist_database
|
||||||
|
from application import postsqldb, database_payloads
|
||||||
|
import config
|
||||||
|
|
||||||
|
def addRecipeItemsToList(site:str, data:dict, user_id: int, conn=None):
|
||||||
|
"""data = {'recipe_uuid', 'sl_id'}"""
|
||||||
|
|
||||||
|
self_conn=False
|
||||||
|
|
||||||
|
if not conn:
|
||||||
|
database_config = config.config()
|
||||||
|
conn = psycopg2.connect(**database_config)
|
||||||
|
conn.autocommit = False
|
||||||
|
self_conn = True
|
||||||
|
|
||||||
|
recipe_items = shoplist_database.getRecipeItemsByUUID(site, (data['recipe_uuid'],), conn=conn)
|
||||||
|
|
||||||
|
|
||||||
|
# for each item build a new item payload
|
||||||
|
for recipe_item in recipe_items:
|
||||||
|
# add item to the table pointing to the list_uuid
|
||||||
|
new_sl_item = database_payloads.ShoppingListItemPayload(
|
||||||
|
list_uuid = data['list_uuid'],
|
||||||
|
item_type='recipe',
|
||||||
|
item_name=recipe_item['item_name'],
|
||||||
|
uom=recipe_item['uom'],
|
||||||
|
qty=recipe_item['qty'],
|
||||||
|
item_uuid=recipe_item['item_uuid'],
|
||||||
|
links=recipe_item['links']
|
||||||
|
)
|
||||||
|
shoplist_database.insertShoppingListItemsTuple(site, new_sl_item.payload(), conn=conn)
|
||||||
|
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
@ -4,8 +4,12 @@ WITH sum_cte AS (
|
|||||||
JOIN %%site_name%%_items mi ON mil.part_id = mi.id
|
JOIN %%site_name%%_items mi ON mil.part_id = mi.id
|
||||||
GROUP BY mi.id
|
GROUP BY mi.id
|
||||||
)
|
)
|
||||||
SELECT *
|
SELECT %%site_name%%_items.*,
|
||||||
|
COALESCE(row_to_json(%%site_name%%_item_info.*), '{}') AS item_info,
|
||||||
|
COALESCE(sum_cte.total_sum, 0) AS total_sum,
|
||||||
|
units.fullname AS uom_fullname
|
||||||
FROM %%site_name%%_items
|
FROM %%site_name%%_items
|
||||||
LEFT JOIN %%site_name%%_item_info ON %%site_name%%_items.item_info_id = %%site_name%%_item_info.id
|
LEFT JOIN %%site_name%%_item_info ON %%site_name%%_items.item_info_id = %%site_name%%_item_info.id
|
||||||
|
LEFT JOIN units ON units.id = %%site_name%%_item_info.uom
|
||||||
LEFT JOIN sum_cte ON %%site_name%%_items.id = sum_cte.id
|
LEFT JOIN sum_cte ON %%site_name%%_items.id = sum_cte.id
|
||||||
WHERE %%site_name%%_item_info.safety_stock > COALESCE(sum_cte.total_sum, 0);
|
WHERE %%site_name%%_item_info.safety_stock > COALESCE(sum_cte.total_sum, 0);
|
||||||
|
|||||||
11
application/shoppinglists/sql/getRecipeItemsByUUID.sql
Normal file
11
application/shoppinglists/sql/getRecipeItemsByUUID.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
WITH passed_id AS (SELECT recipes.id AS passed_id FROM %%site_name%%_recipes recipes WHERE recipes.recipe_uuid = %s::uuid)
|
||||||
|
SELECT
|
||||||
|
COALESCE(item_info.uom, recipe_items.uom) as uom,
|
||||||
|
COALESCE(items.links, recipe_items.links) as links,
|
||||||
|
COALESCE(items.item_uuid, recipe_items.item_uuid) as item_uuid,
|
||||||
|
COALESCE(items.item_name, recipe_items.item_name) as item_name,
|
||||||
|
recipe_items.qty as qty
|
||||||
|
FROM %%site_name%%_recipe_items recipe_items
|
||||||
|
LEFT JOIN %%site_name%%_items items ON items.item_uuid = recipe_items.item_uuid
|
||||||
|
LEFT JOIN %%site_name%%_item_info item_info ON item_info.id = items.item_info_id
|
||||||
|
WHERE recipe_items.rp_id=(SELECT passed_id FROM passed_id);
|
||||||
@ -1,15 +1,15 @@
|
|||||||
WITH passed_id AS (SELECT %s AS passed_id),
|
WITH passed_uuid AS (SELECT %s AS passed_uuid),
|
||||||
cte_sl_items AS (
|
cte_sl_items AS (
|
||||||
SELECT items.*,
|
SELECT items.*,
|
||||||
(SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom
|
(SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom
|
||||||
FROM %%site_name%%_shopping_list_items items
|
FROM %%site_name%%_shopping_list_items items
|
||||||
WHERE items.sl_id = (SELECT passed_id FROM passed_id)
|
WHERE items.list_uuid = (SELECT passed_uuid::uuid FROM passed_uuid)
|
||||||
)
|
)
|
||||||
|
|
||||||
SELECT (SELECT passed_id FROM passed_id) AS passed_id,
|
SELECT (SELECT passed_uuid FROM passed_uuid) AS passed_uuid,
|
||||||
%%site_name%%_shopping_lists.*,
|
%%site_name%%_shopping_lists.*,
|
||||||
logins.username as author,
|
logins.username as author,
|
||||||
(SELECT COALESCE(array_agg(row_to_json(slis)), '{}') FROM cte_sl_items slis) AS sl_items
|
(SELECT COALESCE(array_agg(row_to_json(slis)), '{}') FROM cte_sl_items slis) AS sl_items
|
||||||
FROM %%site_name%%_shopping_lists
|
FROM %%site_name%%_shopping_lists
|
||||||
JOIN logins ON %%site_name%%_shopping_lists.author = logins.id
|
JOIN logins ON %%site_name%%_shopping_lists.author = logins.id
|
||||||
WHERE %%site_name%%_shopping_lists.id=(SELECT passed_id FROM passed_id)
|
WHERE %%site_name%%_shopping_lists.list_uuid=(SELECT passed_uuid::uuid FROM passed_uuid)
|
||||||
@ -1,3 +1,3 @@
|
|||||||
SELECT *,
|
SELECT *,
|
||||||
(SELECT COALESCE(array_agg(row_to_json(g)), '{}') FROM %%site_name%%_shopping_list_items g WHERE sl_id = %%site_name%%_shopping_lists.id) AS sl_items
|
(SELECT COALESCE(array_agg(row_to_json(g)), '{}') FROM %%site_name%%_shopping_list_items g WHERE list_uuid = %%site_name%%_shopping_lists.list_uuid) AS sl_items
|
||||||
FROM %%site_name%%_shopping_lists LIMIT %s OFFSET %s;
|
FROM %%site_name%%_shopping_lists LIMIT %s OFFSET %s;
|
||||||
@ -1,4 +1,6 @@
|
|||||||
INSERT INTO %%site_name%%_shopping_list_items
|
INSERT INTO %%site_name%%_shopping_list_items
|
||||||
(uuid, sl_id, item_type, item_name, uom, qty, item_id, links)
|
(list_uuid, item_type, item_name, uom, qty, item_uuid, links)
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s, %s, %s, %s)
|
||||||
|
ON CONFLICT (list_uuid, item_uuid) DO UPDATE
|
||||||
|
SET qty = %%site_name%%_shopping_list_items.qty + EXCLUDED.qty
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
SELECT items.*,
|
SELECT items.*,
|
||||||
(SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom
|
(SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom
|
||||||
FROM %%site_name%%_shopping_list_items items
|
FROM %%site_name%%_shopping_list_items items
|
||||||
WHERE items.id = %s;
|
WHERE items.list_item_uuid = %s::uuid;
|
||||||
@ -10,7 +10,7 @@ async function replenishForm(shopping_list){
|
|||||||
document.getElementById('list_creation_date').value = shopping_list.creation_date
|
document.getElementById('list_creation_date').value = shopping_list.creation_date
|
||||||
document.getElementById('list_description').value = shopping_list.description
|
document.getElementById('list_description').value = shopping_list.description
|
||||||
document.getElementById('list_author').value = shopping_list.author
|
document.getElementById('list_author').value = shopping_list.author
|
||||||
document.getElementById('list_type').value = shopping_list.type
|
document.getElementById('list_type').value = shopping_list.sub_type
|
||||||
|
|
||||||
if(shopping_list.type == "calculated"){
|
if(shopping_list.type == "calculated"){
|
||||||
document.getElementById('addLineButton').classList.add("uk-disabled")
|
document.getElementById('addLineButton').classList.add("uk-disabled")
|
||||||
@ -43,7 +43,7 @@ async function replenishLineTable(sl_items){
|
|||||||
typeCell.innerHTML = sl_items[i].item_type
|
typeCell.innerHTML = sl_items[i].item_type
|
||||||
|
|
||||||
let uuidCell = document.createElement('td')
|
let uuidCell = document.createElement('td')
|
||||||
uuidCell.innerHTML = sl_items[i].uuid
|
uuidCell.innerHTML = sl_items[i].list_item_uuid
|
||||||
|
|
||||||
let nameCell = document.createElement('td')
|
let nameCell = document.createElement('td')
|
||||||
nameCell.innerHTML = sl_items[i].item_name
|
nameCell.innerHTML = sl_items[i].item_name
|
||||||
@ -55,14 +55,14 @@ async function replenishLineTable(sl_items){
|
|||||||
editOp.innerHTML = `<span uk-icon="icon: pencil"></span>`
|
editOp.innerHTML = `<span uk-icon="icon: pencil"></span>`
|
||||||
editOp.style = 'margin-right: 5px;'
|
editOp.style = 'margin-right: 5px;'
|
||||||
editOp.onclick = async function () {
|
editOp.onclick = async function () {
|
||||||
await openLineEditModal(sl_items[i].id)
|
await openLineEditModal(sl_items[i].list_item_uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
let deleteOp = document.createElement('a')
|
let deleteOp = document.createElement('a')
|
||||||
deleteOp.setAttribute('class', 'uk-button uk-button-default uk-button-small')
|
deleteOp.setAttribute('class', 'uk-button uk-button-default uk-button-small')
|
||||||
deleteOp.innerHTML = `<span uk-icon="icon: trash"></span>`
|
deleteOp.innerHTML = `<span uk-icon="icon: trash"></span>`
|
||||||
deleteOp.onclick = async function () {
|
deleteOp.onclick = async function () {
|
||||||
await deleteLineItem(sl_items[i].id)
|
await deleteLineItem(sl_items[i].list_item_uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
opCell.append(editOp, deleteOp)
|
opCell.append(editOp, deleteOp)
|
||||||
@ -74,7 +74,7 @@ async function replenishLineTable(sl_items){
|
|||||||
|
|
||||||
async function fetchShoppingList() {
|
async function fetchShoppingList() {
|
||||||
const url = new URL('/shopping-lists/api/getList', window.location.origin);
|
const url = new URL('/shopping-lists/api/getList', window.location.origin);
|
||||||
url.searchParams.append('id', sl_id);
|
url.searchParams.append('list_uuid', list_uuid);
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
data = await response.json();
|
data = await response.json();
|
||||||
return data.shopping_list;
|
return data.shopping_list;
|
||||||
@ -91,26 +91,25 @@ async function updateItemsModalTable(items) {
|
|||||||
for(let i=0; i < items.length; i++){
|
for(let i=0; i < items.length; i++){
|
||||||
let tableRow = document.createElement('tr')
|
let tableRow = document.createElement('tr')
|
||||||
|
|
||||||
let idCell = document.createElement('td')
|
|
||||||
idCell.innerHTML = `${items[i].id}`
|
|
||||||
|
|
||||||
let barcodeCell = document.createElement('td')
|
|
||||||
barcodeCell.innerHTML = `${items[i].barcode}`
|
|
||||||
|
|
||||||
let nameCell = document.createElement('td')
|
let nameCell = document.createElement('td')
|
||||||
nameCell.innerHTML = `${items[i].item_name}`
|
nameCell.innerHTML = `${items[i].item_name}`
|
||||||
|
|
||||||
tableRow.id = items[i].id
|
let opCell = document.createElement('td')
|
||||||
tableRow.onclick = async function(){
|
|
||||||
|
let selectButton = document.createElement('button')
|
||||||
|
selectButton.innerHTML = "Select"
|
||||||
|
selectButton.setAttribute('class', 'uk-button uk-button-primary uk-button-small')
|
||||||
|
|
||||||
|
selectButton.onclick = async function(){
|
||||||
|
|
||||||
let newItem = {
|
let newItem = {
|
||||||
uuid: items[i].barcode,
|
list_uuid: list_uuid,
|
||||||
sl_id: sl_id,
|
|
||||||
item_type: 'sku',
|
item_type: 'sku',
|
||||||
item_name: items[i].item_name,
|
item_name: items[i].item_name,
|
||||||
uom: items[i].item_info.uom,
|
uom: items[i].item_info.uom,
|
||||||
qty: items[i].item_info.uom_quantity,
|
qty: items[i].item_info.uom_quantity,
|
||||||
item_id: items[i].id,
|
item_uuid: items[i].item_uuid,
|
||||||
links: {'main': items[i].links['main']}
|
links: {'main': items[i].links['main']}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +121,9 @@ async function updateItemsModalTable(items) {
|
|||||||
UIkit.modal(itemsModal).hide();
|
UIkit.modal(itemsModal).hide();
|
||||||
|
|
||||||
}
|
}
|
||||||
tableRow.append(idCell, barcodeCell, nameCell)
|
|
||||||
|
opCell.append(selectButton)
|
||||||
|
tableRow.append(nameCell, opCell)
|
||||||
itemsTableBody.append(tableRow)
|
itemsTableBody.append(tableRow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,13 +139,11 @@ async function openSKUModal() {
|
|||||||
UIkit.modal(itemsModal).show();
|
UIkit.modal(itemsModal).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openLineEditModal(sli_id) {
|
async function openLineEditModal(list_item_uuid) {
|
||||||
let sl_item = await fetchSLItem(sli_id)
|
let sl_item = await fetchSLItem(list_item_uuid)
|
||||||
console.log(sl_item)
|
|
||||||
document.getElementById('lineName').value = sl_item.item_name
|
document.getElementById('lineName').value = sl_item.item_name
|
||||||
document.getElementById('lineQty').value = sl_item.qty
|
document.getElementById('lineQty').value = sl_item.qty
|
||||||
document.getElementById('lineUOM').value = sl_item.uom.id
|
document.getElementById('lineUOM').value = sl_item.uom.id
|
||||||
console.log(sl_item.links)
|
|
||||||
|
|
||||||
if(!sl_item.links.hasOwnProperty('main')){
|
if(!sl_item.links.hasOwnProperty('main')){
|
||||||
sl_item.links.main = ''
|
sl_item.links.main = ''
|
||||||
@ -161,7 +160,7 @@ async function openLineEditModal(sli_id) {
|
|||||||
uom: document.getElementById('lineUOM').value,
|
uom: document.getElementById('lineUOM').value,
|
||||||
links: links
|
links: links
|
||||||
}
|
}
|
||||||
await saveLineItem(sl_item.id, update)
|
await saveLineItem(sl_item.list_item_uuid, update)
|
||||||
UIkit.modal(document.getElementById('lineEditModal')).hide();
|
UIkit.modal(document.getElementById('lineEditModal')).hide();
|
||||||
}
|
}
|
||||||
UIkit.modal(document.getElementById('lineEditModal')).show();
|
UIkit.modal(document.getElementById('lineEditModal')).show();
|
||||||
@ -272,9 +271,10 @@ async function fetchItems() {
|
|||||||
return data.items;
|
return data.items;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchSLItem(sli_id) {
|
async function fetchSLItem(list_item_uuid) {
|
||||||
|
console.log(list_item_uuid)
|
||||||
const url = new URL('/shopping-lists/api/getListItem', window.location.origin);
|
const url = new URL('/shopping-lists/api/getListItem', window.location.origin);
|
||||||
url.searchParams.append('sli_id', sli_id);
|
url.searchParams.append('list_item_uuid', list_item_uuid);
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
data = await response.json();
|
data = await response.json();
|
||||||
return data.list_item;
|
return data.list_item;
|
||||||
@ -284,16 +284,14 @@ async function addCustomItem() {
|
|||||||
let customModal = document.getElementById('customModal')
|
let customModal = document.getElementById('customModal')
|
||||||
UIkit.modal(customModal).hide();
|
UIkit.modal(customModal).hide();
|
||||||
|
|
||||||
uuid = `${sl_id}${Math.random().toString(36).substring(2, 8)}`
|
|
||||||
|
|
||||||
let newItem = {
|
let newItem = {
|
||||||
uuid: uuid,
|
list_uuid: list_uuid,
|
||||||
sl_id: sl_id,
|
|
||||||
item_type: 'custom',
|
item_type: 'custom',
|
||||||
item_name: document.getElementById('customName').value,
|
item_name: document.getElementById('customName').value,
|
||||||
uom: document.getElementById('customUOM').value,
|
uom: document.getElementById('customUOM').value,
|
||||||
qty: parseFloat(document.getElementById('customQty').value),
|
qty: parseFloat(document.getElementById('customQty').value),
|
||||||
item_id: null,
|
item_uuid: null,
|
||||||
links: {'main': document.getElementById('customLink').value}
|
links: {'main': document.getElementById('customLink').value}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,14 +356,14 @@ async function deleteLineItem(sli_id) {
|
|||||||
await replenishLineTable(shopping_list.sl_items)
|
await replenishLineTable(shopping_list.sl_items)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveLineItem(sli_id, update) {
|
async function saveLineItem(list_item_uuid, update) {
|
||||||
const response = await fetch(`/shopping-lists/api/saveListItem`, {
|
const response = await fetch(`/shopping-lists/api/saveListItem`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
sli_id: sli_id,
|
list_item_uuid: list_item_uuid,
|
||||||
update: update
|
update: update
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@ -386,4 +384,178 @@ async function saveLineItem(sli_id, update) {
|
|||||||
let shopping_list = await fetchShoppingList()
|
let shopping_list = await fetchShoppingList()
|
||||||
await replenishForm(shopping_list)
|
await replenishForm(shopping_list)
|
||||||
await replenishLineTable(shopping_list.sl_items)
|
await replenishLineTable(shopping_list.sl_items)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Recipes Modal and Functions
|
||||||
|
var recipes_pagination_current = 1;
|
||||||
|
var recipes_pagination_end = 1;
|
||||||
|
var recipes_search_string = ""
|
||||||
|
let recipes_limit = 25;
|
||||||
|
|
||||||
|
|
||||||
|
async function updateRecipesModalTable(recipes) {
|
||||||
|
let receipesTableBody = document.getElementById('receipesTableBody');
|
||||||
|
receipesTableBody.innerHTML = "";
|
||||||
|
|
||||||
|
for(let i=0; i < recipes.length; i++){
|
||||||
|
let tableRow = document.createElement('tr')
|
||||||
|
|
||||||
|
let nameCell = document.createElement('td')
|
||||||
|
nameCell.innerHTML = `${recipes[i].name}`
|
||||||
|
|
||||||
|
let opCell = document.createElement('td')
|
||||||
|
|
||||||
|
let selectButton = document.createElement('button')
|
||||||
|
selectButton.innerHTML = "Select"
|
||||||
|
selectButton.setAttribute('class', 'uk-button uk-button-primary uk-button-small')
|
||||||
|
|
||||||
|
selectButton.onclick = async function(){
|
||||||
|
await addRecipeLine(recipes[i].recipe_uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
opCell.append(selectButton)
|
||||||
|
tableRow.append(nameCell, opCell)
|
||||||
|
receipesTableBody.append(tableRow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openRecipesModal() {
|
||||||
|
let recipesModal = document.getElementById('recipesModal')
|
||||||
|
let recipes = await fetchRecipes()
|
||||||
|
recipes_pagination_current = 1;
|
||||||
|
recipes_search_string = '';
|
||||||
|
document.getElementById('searchRecipesInput').value = '';
|
||||||
|
await updateRecipesModalTable(recipes)
|
||||||
|
await updateRecipesPaginationElement()
|
||||||
|
UIkit.modal(recipesModal).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function searchRecipesTable(event) {
|
||||||
|
if(event.key==='Enter'){
|
||||||
|
recipes_search_string = event.srcElement.value
|
||||||
|
let recipes = await fetchRecipes()
|
||||||
|
await updateRecipesModalTable(recipes)
|
||||||
|
await updateRecipesPaginationElement()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setRecipesPage(pageNumber){
|
||||||
|
recipes_pagination_current = pageNumber;
|
||||||
|
let recipes = await fetchRecipes()
|
||||||
|
await updateRecipesModalTable(recipes)
|
||||||
|
await updateRecipesPaginationElement()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateRecipesPaginationElement() {
|
||||||
|
let paginationElement = document.getElementById('recipesPage');
|
||||||
|
paginationElement.innerHTML = "";
|
||||||
|
// previous
|
||||||
|
let previousElement = document.createElement('li')
|
||||||
|
if(recipes_pagination_current<=1){
|
||||||
|
previousElement.innerHTML = `<a><span uk-pagination-previous></span></a>`;
|
||||||
|
previousElement.classList.add('uk-disabled');
|
||||||
|
}else {
|
||||||
|
previousElement.innerHTML = `<a onclick="setRecipesPage(${recipes_pagination_current-1})"><span uk-pagination-previous></span></a>`;
|
||||||
|
}
|
||||||
|
paginationElement.append(previousElement)
|
||||||
|
|
||||||
|
//first
|
||||||
|
let firstElement = document.createElement('li')
|
||||||
|
if(recipes_pagination_current<=1){
|
||||||
|
firstElement.innerHTML = `<a><strong>1</strong></a>`;
|
||||||
|
firstElement.classList.add('uk-disabled');
|
||||||
|
}else {
|
||||||
|
firstElement.innerHTML = `<a onclick="setRecipesPage(1)">1</a>`;
|
||||||
|
}
|
||||||
|
paginationElement.append(firstElement)
|
||||||
|
|
||||||
|
// ...
|
||||||
|
if(recipes_pagination_current-2>1){
|
||||||
|
let firstDotElement = document.createElement('li')
|
||||||
|
firstDotElement.classList.add('uk-disabled')
|
||||||
|
firstDotElement.innerHTML = `<span>…</span>`;
|
||||||
|
paginationElement.append(firstDotElement)
|
||||||
|
}
|
||||||
|
// last
|
||||||
|
if(recipes_pagination_current-2>0){
|
||||||
|
let lastElement = document.createElement('li')
|
||||||
|
lastElement.innerHTML = `<a onclick="setRecipesPage(${recipes_pagination_current-1})">${recipes_pagination_current-1}</a>`
|
||||||
|
paginationElement.append(lastElement)
|
||||||
|
}
|
||||||
|
// current
|
||||||
|
if(recipes_pagination_current!=1 && recipes_pagination_current != recipes_pagination_end){
|
||||||
|
let currentElement = document.createElement('li')
|
||||||
|
currentElement.innerHTML = `<li class="uk-active"><span aria-current="page"><strong>${recipes_pagination_current}</strong></span></li>`
|
||||||
|
paginationElement.append(currentElement)
|
||||||
|
}
|
||||||
|
// next
|
||||||
|
if(recipes_pagination_current+2<recipes_pagination_end+1){
|
||||||
|
let nextElement = document.createElement('li')
|
||||||
|
nextElement.innerHTML = `<a onclick="setRecipesPage(${recipes_pagination_current+1})">${recipes_pagination_current+1}</a>`
|
||||||
|
paginationElement.append(nextElement)
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
if(recipes_pagination_current+2<=recipes_pagination_end){
|
||||||
|
let secondDotElement = document.createElement('li')
|
||||||
|
secondDotElement.classList.add('uk-disabled')
|
||||||
|
secondDotElement.innerHTML = `<span>…</span>`;
|
||||||
|
paginationElement.append(secondDotElement)
|
||||||
|
}
|
||||||
|
//end
|
||||||
|
let endElement = document.createElement('li')
|
||||||
|
if(recipes_pagination_current>=recipes_pagination_end){
|
||||||
|
endElement.innerHTML = `<a><strong>${recipes_pagination_end}</strong></a>`;
|
||||||
|
endElement.classList.add('uk-disabled');
|
||||||
|
}else {
|
||||||
|
endElement.innerHTML = `<a onclick="setRecipesPage(${recipes_pagination_end})">${recipes_pagination_end}</a>`;
|
||||||
|
}
|
||||||
|
paginationElement.append(endElement)
|
||||||
|
//next button
|
||||||
|
let nextElement = document.createElement('li')
|
||||||
|
if(recipes_pagination_current>=recipes_pagination_end){
|
||||||
|
nextElement.innerHTML = `<a><span uk-pagination-next></span></a>`;
|
||||||
|
nextElement.classList.add('uk-disabled');
|
||||||
|
}else {
|
||||||
|
nextElement.innerHTML = `<a onclick="setRecipesPage(${recipes_pagination_current+1})"><span uk-pagination-next></span></a>`;
|
||||||
|
}
|
||||||
|
paginationElement.append(nextElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchRecipes() {
|
||||||
|
const url = new URL('/shopping-lists/api/getRecipesModal', window.location.origin);
|
||||||
|
url.searchParams.append('page', recipes_pagination_current);
|
||||||
|
url.searchParams.append('limit', recipes_limit);
|
||||||
|
url.searchParams.append('search_string', recipes_search_string);
|
||||||
|
const response = await fetch(url);
|
||||||
|
data = await response.json();
|
||||||
|
recipes_pagination_end = data.end
|
||||||
|
return data.recipes;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addRecipeLine(recipe_uuid){
|
||||||
|
const response = await fetch(`/shopping-lists/api/postRecipeLine`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
recipe_uuid: recipe_uuid,
|
||||||
|
list_uuid: list_uuid
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
data = await response.json();
|
||||||
|
response_status = 'success'
|
||||||
|
if (data.error){
|
||||||
|
response_status = 'danger'
|
||||||
|
}
|
||||||
|
|
||||||
|
UIkit.notification({
|
||||||
|
message: data.message,
|
||||||
|
status: response_status,
|
||||||
|
pos: 'top-right',
|
||||||
|
timeout: 5000
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -3,7 +3,7 @@ document.addEventListener('DOMContentLoaded', async function() {
|
|||||||
await replenishForm(shopping_list)
|
await replenishForm(shopping_list)
|
||||||
|
|
||||||
list_items = shopping_list.sl_items
|
list_items = shopping_list.sl_items
|
||||||
if(shopping_list.type == "calculated"){
|
if(shopping_list.sub_type == "calculated"){
|
||||||
list_items = await fetchItemsFullCalculated()
|
list_items = await fetchItemsFullCalculated()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ async function replenishLineTable(sl_items){
|
|||||||
nameCell.innerHTML = namefield
|
nameCell.innerHTML = namefield
|
||||||
|
|
||||||
let qtyuomCell = document.createElement('td')
|
let qtyuomCell = document.createElement('td')
|
||||||
qtyuomCell.innerHTML = `${sl_items[i].qty} ${sl_items[i].uom.fullname}`
|
qtyuomCell.innerHTML = `${sl_items[i].qty} ${sl_items[i].uom_fullname}`
|
||||||
|
|
||||||
tableRow.append(checkboxCell, nameCell, qtyuomCell)
|
tableRow.append(checkboxCell, nameCell, qtyuomCell)
|
||||||
listItemsTableBody.append(tableRow)
|
listItemsTableBody.append(tableRow)
|
||||||
@ -46,7 +46,7 @@ async function replenishLineTable(sl_items){
|
|||||||
|
|
||||||
async function fetchShoppingList() {
|
async function fetchShoppingList() {
|
||||||
const url = new URL('/shopping-lists/api/getList', window.location.origin);
|
const url = new URL('/shopping-lists/api/getList', window.location.origin);
|
||||||
url.searchParams.append('id', sl_id);
|
url.searchParams.append('list_uuid', list_uuid);
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
data = await response.json();
|
data = await response.json();
|
||||||
return data.shopping_list;
|
return data.shopping_list;
|
||||||
|
|||||||
@ -13,7 +13,7 @@ document.addEventListener('DOMContentLoaded', async function() {
|
|||||||
async function replenishShoppingListCards(lists) {
|
async function replenishShoppingListCards(lists) {
|
||||||
let shopping_list_lists = document.getElementById('shopping_list_lists')
|
let shopping_list_lists = document.getElementById('shopping_list_lists')
|
||||||
shopping_list_lists.innerHTML = ""
|
shopping_list_lists.innerHTML = ""
|
||||||
|
console.log(lists)
|
||||||
for(let i=0; i < lists.length; i++){
|
for(let i=0; i < lists.length; i++){
|
||||||
console.log(lists[i])
|
console.log(lists[i])
|
||||||
let main_div = document.createElement('div')
|
let main_div = document.createElement('div')
|
||||||
@ -25,7 +25,7 @@ async function replenishShoppingListCards(lists) {
|
|||||||
|
|
||||||
let badge_div_dos = document.createElement('div')
|
let badge_div_dos = document.createElement('div')
|
||||||
badge_div_dos.setAttribute('class', 'uk-card-badge uk-label')
|
badge_div_dos.setAttribute('class', 'uk-card-badge uk-label')
|
||||||
badge_div_dos.innerHTML = lists[i].type
|
badge_div_dos.innerHTML = lists[i].sub_type
|
||||||
badge_div_dos.style = "margin-top: 30px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width:150px; text-align: right;"
|
badge_div_dos.style = "margin-top: 30px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width:150px; text-align: right;"
|
||||||
|
|
||||||
let card_header_div = document.createElement('div')
|
let card_header_div = document.createElement('div')
|
||||||
@ -58,12 +58,12 @@ async function replenishShoppingListCards(lists) {
|
|||||||
editOp.setAttribute('class', 'uk-button uk-button-small uk-button-default')
|
editOp.setAttribute('class', 'uk-button uk-button-small uk-button-default')
|
||||||
editOp.innerHTML = '<span uk-icon="icon: pencil"></span> Edit'
|
editOp.innerHTML = '<span uk-icon="icon: pencil"></span> Edit'
|
||||||
editOp.style = "margin-right: 10px;"
|
editOp.style = "margin-right: 10px;"
|
||||||
editOp.href = `/shopping-lists/edit/${lists[i].id}`
|
editOp.href = `/shopping-lists/edit/${lists[i].list_uuid}`
|
||||||
|
|
||||||
let viewOp = document.createElement('a')
|
let viewOp = document.createElement('a')
|
||||||
viewOp.setAttribute('class', 'uk-button uk-button-small uk-button-default')
|
viewOp.setAttribute('class', 'uk-button uk-button-small uk-button-default')
|
||||||
viewOp.innerHTML = '<span uk-icon="icon: eye"></span> View'
|
viewOp.innerHTML = '<span uk-icon="icon: eye"></span> View'
|
||||||
viewOp.href = `/shopping-lists/view/${lists[i].id}`
|
viewOp.href = `/shopping-lists/view/${lists[i].list_uuid}`
|
||||||
//viewOp.style = "margin-right: 20px;"
|
//viewOp.style = "margin-right: 20px;"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -160,6 +160,7 @@
|
|||||||
<li class="uk-nav-header">Line Type</li>
|
<li class="uk-nav-header">Line Type</li>
|
||||||
<li><a href="#customModal" uk-toggle>Custom</a></li>
|
<li><a href="#customModal" uk-toggle>Custom</a></li>
|
||||||
<li><a onclick="openSKUModal()">SKU</a></li>
|
<li><a onclick="openSKUModal()">SKU</a></li>
|
||||||
|
<li><a onclick="openRecipesModal()">Recipes</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -209,6 +210,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- This is the modal -->
|
<!-- This is the modal -->
|
||||||
|
<!-- Recipes modal lookup -->
|
||||||
|
<div id="recipesModal" uk-modal>
|
||||||
|
<div id="recipesModalInner" class="uk-modal-dialog uk-modal-body " uk-overflow-auto>
|
||||||
|
<h2 class="uk-modal-title">Select Item</h2>
|
||||||
|
<p>Select a Recipe from the system...</p>
|
||||||
|
<div id="searchRecipesForm" onkeydown="searchRecipesTable(event)" class="uk-search uk-search-default uk-align-center">
|
||||||
|
<input id="searchRecipesInput" class="uk-border-pill uk-search-input" type="search" placeholder="" aria-label="">
|
||||||
|
<span class="uk-search-icon-flip" uk-search-icon></span>
|
||||||
|
</div>
|
||||||
|
<nav aria-label="Pagination">
|
||||||
|
<ul id="recipesPage" class="uk-pagination uk-flex-center" uk-margin>
|
||||||
|
<li><a href="#"><span uk-pagination-previous></span></a></li>
|
||||||
|
<li><a href="#">1</a></li>
|
||||||
|
<li class="uk-disabled"><span>…</span></li>
|
||||||
|
<li><a href="#">5</a></li>
|
||||||
|
<li><a href="#">6</a></li>
|
||||||
|
<li class="uk-active"><span aria-current="page">7</span></li>
|
||||||
|
<li><a href="#">8</a></li>
|
||||||
|
<li><a href="#"><span uk-pagination-next></span></a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<table class="uk-table uk-table-striped uk-table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Operations</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="receipesTableBody">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Items modal lookup -->
|
<!-- Items modal lookup -->
|
||||||
<div id="itemsModal" uk-modal>
|
<div id="itemsModal" uk-modal>
|
||||||
<div id="itemsModalInner" class="uk-modal-dialog uk-modal-body " uk-overflow-auto>
|
<div id="itemsModalInner" class="uk-modal-dialog uk-modal-body " uk-overflow-auto>
|
||||||
@ -230,12 +264,11 @@
|
|||||||
<li><a href="#"><span uk-pagination-next></span></a></li>
|
<li><a href="#"><span uk-pagination-next></span></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<table class="uk-table uk-table-striped uk-table-hover">
|
<table class="uk-table uk-table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
|
||||||
<th>Barcode</th>
|
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
|
<th>Operations</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="itemsTableBody">
|
<tbody id="itemsTableBody">
|
||||||
@ -324,5 +357,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script src="{{ url_for('shopping_list_API.static', filename='js/shoppingListEditHandler.js') }}"></script>
|
<script src="{{ url_for('shopping_list_API.static', filename='js/shoppingListEditHandler.js') }}"></script>
|
||||||
<script>const sl_id = {{id|tojson}}</script>
|
<script>const list_uuid = {{list_uuid|tojson}}</script>
|
||||||
</html>
|
</html>
|
||||||
@ -136,5 +136,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script src="{{ url_for('shopping_list_API.static', filename='js/shoppingListViewHandler.js') }}"></script>
|
<script src="{{ url_for('shopping_list_API.static', filename='js/shoppingListViewHandler.js') }}"></script>
|
||||||
<script>const sl_id = {{id|tojson}}</script>
|
<script>const list_uuid = {{list_uuid|tojson}}</script>
|
||||||
</html>
|
</html>
|
||||||
@ -305,4 +305,97 @@
|
|||||||
sql='INSERT INTO main_logistics_info(barcode, primary_location, primary_zone, auto_issue_location, auto_issue_zone) VALUES (%s, %s, %s, %s, %s) RETURNING *;')
|
sql='INSERT INTO main_logistics_info(barcode, primary_location, primary_zone, auto_issue_location, auto_issue_zone) VALUES (%s, %s, %s, %s, %s) RETURNING *;')
|
||||||
2025-08-13 14:48:16.893199 --- ERROR --- DatabaseError(message='null value in column "barcode" of relation "main_logistics_info" violates not-null constraintDETAIL: Failing row contains (511, null, 1, 1, 1, 1).',
|
2025-08-13 14:48:16.893199 --- ERROR --- DatabaseError(message='null value in column "barcode" of relation "main_logistics_info" violates not-null constraintDETAIL: Failing row contains (511, null, 1, 1, 1, 1).',
|
||||||
payload=(None, 1, 1, 1, 1),
|
payload=(None, 1, 1, 1, 1),
|
||||||
sql='INSERT INTO main_logistics_info(barcode, primary_location, primary_zone, auto_issue_location, auto_issue_zone) VALUES (%s, %s, %s, %s, %s) RETURNING *;')
|
sql='INSERT INTO main_logistics_info(barcode, primary_location, primary_zone, auto_issue_location, auto_issue_zone) VALUES (%s, %s, %s, %s, %s) RETURNING *;')
|
||||||
|
2025-08-13 18:11:37.556015 --- ERROR --- DatabaseError(message='missing FROM-clause entry for table "recipes"LINE 1: SELECT COUNT(*) FROM main_recipes WHERE recipes.name LIKE '%... ^',
|
||||||
|
payload=('', 25, 0),
|
||||||
|
sql='SELECT recipes.recipe_uuid, recipes.name FROM main_recipes recipes WHERE recipes.name LIKE '%%' || %s || '%%' LIMIT %s OFFSET %s;')
|
||||||
|
2025-08-13 18:13:39.194633 --- ERROR --- DatabaseError(message='missing FROM-clause entry for table "recipes"LINE 1: SELECT COUNT(*) FROM main_recipes WHERE recipes.name LIKE '%... ^',
|
||||||
|
payload=('', 25, 0),
|
||||||
|
sql='SELECT * FROM main_recipes recipes WHERE recipes.name LIKE '%%' || %s || '%%' LIMIT %s OFFSET %s;')
|
||||||
|
2025-08-14 15:19:00.050654 --- ERROR --- DatabaseError(message='column "sl_id" does not existLINE 2: ...(g)), '{}') FROM test_shopping_list_items g WHERE sl_id = te... ^',
|
||||||
|
payload=(5, 0),
|
||||||
|
sql='SELECT *, (SELECT COALESCE(array_agg(row_to_json(g)), '{}') FROM test_shopping_list_items g WHERE sl_id = test_shopping_lists.id) AS sl_items FROM test_shopping_lists LIMIT %s OFFSET %s;')
|
||||||
|
2025-08-14 15:25:02.157300 --- ERROR --- DatabaseError(message='column items.sl_id does not existLINE 6: WHERE items.sl_id = (SELECT passed_id FROM passe... ^',
|
||||||
|
payload=(12,),
|
||||||
|
sql='WITH passed_id AS (SELECT %s AS passed_id), cte_sl_items AS ( SELECT items.*, (SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom FROM test_shopping_list_items items WHERE items.sl_id = (SELECT passed_id FROM passed_id) )SELECT (SELECT passed_id FROM passed_id) AS passed_id, test_shopping_lists.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(slis)), '{}') FROM cte_sl_items slis) AS sl_items FROM test_shopping_listsJOIN logins ON test_shopping_lists.author = logins.idWHERE test_shopping_lists.id=(SELECT passed_id FROM passed_id)')
|
||||||
|
2025-08-14 15:28:59.416536 --- ERROR --- DatabaseError(message='operator does not exist: uuid = integerLINE 6: WHERE items.list_uuid = (SELECT passed_uuid FROM... ^HINT: No operator matches the given name and argument types. You might need to add explicit type casts.',
|
||||||
|
payload=(12,),
|
||||||
|
sql='WITH passed_uuid AS (SELECT %s AS passed_uuid), cte_sl_items AS ( SELECT items.*, (SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom FROM test_shopping_list_items items WHERE items.list_uuid = (SELECT passed_uuid FROM passed_uuid) )SELECT (SELECT passed_uuid FROM passed_uuid) AS passed_uuid, test_shopping_lists.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(slis)), '{}') FROM cte_sl_items slis) AS sl_items FROM test_shopping_listsJOIN logins ON test_shopping_lists.author = logins.idWHERE test_shopping_lists.list_uuid=(SELECT passed_uuid FROM passed_uuid)')
|
||||||
|
2025-08-14 15:29:26.536839 --- ERROR --- DatabaseError(message='operator does not exist: uuid = integerLINE 6: WHERE items.list_uuid = (SELECT passed_uuid FROM... ^HINT: No operator matches the given name and argument types. You might need to add explicit type casts.',
|
||||||
|
payload=(2,),
|
||||||
|
sql='WITH passed_uuid AS (SELECT %s AS passed_uuid), cte_sl_items AS ( SELECT items.*, (SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom FROM test_shopping_list_items items WHERE items.list_uuid = (SELECT passed_uuid FROM passed_uuid) )SELECT (SELECT passed_uuid FROM passed_uuid) AS passed_uuid, test_shopping_lists.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(slis)), '{}') FROM cte_sl_items slis) AS sl_items FROM test_shopping_listsJOIN logins ON test_shopping_lists.author = logins.idWHERE test_shopping_lists.list_uuid=(SELECT passed_uuid FROM passed_uuid)')
|
||||||
|
2025-08-14 15:32:23.856954 --- ERROR --- DatabaseError(message='operator does not exist: uuid = textLINE 6: WHERE items.list_uuid = (SELECT passed_uuid FROM... ^HINT: No operator matches the given name and argument types. You might need to add explicit type casts.',
|
||||||
|
payload=('14d8ce2f-2920-47ae-a671-2953d567383d',),
|
||||||
|
sql='WITH passed_uuid AS (SELECT %s AS passed_uuid), cte_sl_items AS ( SELECT items.*, (SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom FROM test_shopping_list_items items WHERE items.list_uuid = (SELECT passed_uuid FROM passed_uuid) )SELECT (SELECT passed_uuid FROM passed_uuid) AS passed_uuid, test_shopping_lists.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(slis)), '{}') FROM cte_sl_items slis) AS sl_items FROM test_shopping_listsJOIN logins ON test_shopping_lists.author = logins.idWHERE test_shopping_lists.list_uuid=(SELECT passed_uuid FROM passed_uuid)')
|
||||||
|
2025-08-14 15:34:21.586465 --- ERROR --- DatabaseError(message='operator does not exist: uuid = textLINE 6: WHERE items.list_uuid = (SELECT passed_uuid FROM... ^HINT: No operator matches the given name and argument types. You might need to add explicit type casts.',
|
||||||
|
payload=('14d8ce2f-2920-47ae-a671-2953d567383d',),
|
||||||
|
sql='WITH passed_uuid AS (SELECT %s AS passed_uuid), cte_sl_items AS ( SELECT items.*, (SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom FROM test_shopping_list_items items WHERE items.list_uuid = (SELECT passed_uuid FROM passed_uuid) )SELECT (SELECT passed_uuid FROM passed_uuid) AS passed_uuid, test_shopping_lists.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(slis)), '{}') FROM cte_sl_items slis) AS sl_items FROM test_shopping_listsJOIN logins ON test_shopping_lists.author = logins.idWHERE test_shopping_lists.list_uuid=(SELECT passed_uuid FROM passed_uuid)')
|
||||||
|
2025-08-14 16:30:42.515423 --- ERROR --- DatabaseError(message='column "id" does not existLINE 1: ...ws AS (DELETE FROM test_shopping_list_items WHERE id IN ('e9... ^',
|
||||||
|
payload=('e9c4ff4f-0dad-444d-a8ba-525360b14f2b',),
|
||||||
|
sql='WITH deleted_rows AS (DELETE FROM test_shopping_list_items WHERE id IN (%s) RETURNING *) SELECT * FROM deleted_rows;')
|
||||||
|
2025-08-14 16:31:21.076149 --- ERROR --- DatabaseError(message='column "list_item_uud" does not existLINE 1: ...ws AS (DELETE FROM test_shopping_list_items WHERE list_item_... ^HINT: Perhaps you meant to reference the column "test_shopping_list_items.list_item_uuid".',
|
||||||
|
payload=('e9c4ff4f-0dad-444d-a8ba-525360b14f2b',),
|
||||||
|
sql='WITH deleted_rows AS (DELETE FROM test_shopping_list_items WHERE list_item_uud IN (%s) RETURNING *) SELECT * FROM deleted_rows;')
|
||||||
|
2025-08-14 16:32:02.625093 --- ERROR --- DatabaseError(message='column test_shopping_list_items.list_item_uud does not existLINE 1: ...ws AS (DELETE FROM test_shopping_list_items WHERE test_shopp... ^HINT: Perhaps you meant to reference the column "test_shopping_list_items.list_item_uuid".',
|
||||||
|
payload=('e9c4ff4f-0dad-444d-a8ba-525360b14f2b',),
|
||||||
|
sql='WITH deleted_rows AS (DELETE FROM test_shopping_list_items WHERE test_shopping_list_items.list_item_uud IN (%s) RETURNING *) SELECT * FROM deleted_rows;')
|
||||||
|
2025-08-14 16:33:56.856394 --- ERROR --- DatabaseError(message='cannot cast type integer to uuidLINE 4: WHERE items.list_item_uuid = 1::uuid; ^',
|
||||||
|
payload=(1,),
|
||||||
|
sql='SELECT items.*, (SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uomFROM test_shopping_list_items itemsWHERE items.list_item_uuid = %s::uuid; ')
|
||||||
|
2025-08-14 16:36:03.309409 --- ERROR --- DatabaseError(message='invalid input syntax for type uuid: ""LINE 4: WHERE items.list_item_uuid = ''::uuid; ^',
|
||||||
|
payload=('',),
|
||||||
|
sql='SELECT items.*, (SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uomFROM test_shopping_list_items itemsWHERE items.list_item_uuid = %s::uuid; ')
|
||||||
|
2025-08-14 16:44:56.545542 --- ERROR --- DatabaseError(message='duplicate key value violates unique constraint "unique combo"DETAIL: Key (item_name, list_uuid)=(Whole grain oats, 14d8ce2f-2920-47ae-a671-2953d567383d) already exists.',
|
||||||
|
payload=('14d8ce2f-2920-47ae-a671-2953d567383d', 'sku', 'Whole grain oats', 1, 1, '9b93104e-4df3-47c4-9d56-f75548ed2c6c', '{}'),
|
||||||
|
sql='INSERT INTO test_shopping_list_items(list_uuid, item_type, item_name, uom, qty, item_uuid, links) VALUES (%s, %s, %s, %s, %s, %s, %s) RETURNING *;')
|
||||||
|
2025-08-14 16:55:30.428449 --- ERROR --- DatabaseError(message='column recipes.recipe_uuid does not existLINE 3: WHERE recipes.recipe_uuid = 'ab60ddfa-90ab-4ce0-9c98-a505873... ^',
|
||||||
|
payload=('ab60ddfa-90ab-4ce0-9c98-a505873788bd',),
|
||||||
|
sql='SELECT * FROM test_recipe_items recipesWHERE recipes.recipe_uuid = %s::uuid;')
|
||||||
|
2025-08-14 17:00:16.133750 --- ERROR --- DatabaseError(message='syntax error at or near ":"LINE 1: ....recipe_uuid = 'ab60ddfa-90ab-4ce0-9c98-a505873788bd':uuid), ^',
|
||||||
|
payload=('ab60ddfa-90ab-4ce0-9c98-a505873788bd',),
|
||||||
|
sql='WITH passed_id AS (SELECT recipe.id AS passed_id FROM test_recipes recipes WHERE recipes.recipe_uuid = %s:uuid), sum_cte AS ( SELECT mi.id, SUM(mil.quantity_on_hand)::FLOAT8 AS total_sum FROM test_item_locations mil JOIN test_items mi ON mil.part_id = mi.id GROUP BY mi.id ), cte_recipe_items AS ( SELECT items.*, /*COALESCE(test_items.barcode, items.uuid) AS uuid,*/ (SELECT COALESCE(row_to_json(units.*), '{}') FROM units WHERE units.id=test_item_info.uom) AS item_uom, COALESCE(test_items.item_name, items.item_name) AS item_name, COALESCE(test_items.links, items.links) AS links, row_to_json(units.*) as uom, (SELECT COALESCE(array_agg(jsonb_build_object('conversion', conv, 'unit', units)), '{}') FROM test_conversions conv LEFT JOIN units ON conv.uom_id = units.id WHERE conv.item_id = test_items.id) AS conversions, COALESCE(sum_cte.total_sum, 0.0) AS quantity_on_hand FROM test_recipe_items items LEFT JOIN test_items ON items.item_id = test_items.id LEFT JOIN test_item_info ON test_items.item_info_id = test_item_info.id LEFT JOIN units ON units.id = items.uom LEFT JOIN sum_cte ON test_items.id = sum_cte.id WHERE items.rp_id = (SELECT passed_id FROM passed_id) ORDER BY items.item_name ASC ) SELECT (SELECT passed_id FROM passed_id) AS passed_id, test_recipes.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(ris)), '{}') FROM cte_recipe_items ris) AS recipe_itemsFROM test_recipesJOIN logins ON test_recipes.author = logins.idWHERE test_recipes.id=(SELECT passed_id FROM passed_id)')
|
||||||
|
2025-08-14 17:00:42.565091 --- ERROR --- DatabaseError(message='missing FROM-clause entry for table "recipe"LINE 1: WITH passed_id AS (SELECT recipe.id AS passed_id FROM test_r... ^',
|
||||||
|
payload=('ab60ddfa-90ab-4ce0-9c98-a505873788bd',),
|
||||||
|
sql='WITH passed_id AS (SELECT recipe.id AS passed_id FROM test_recipes recipes WHERE recipes.recipe_uuid = %s::uuid), sum_cte AS ( SELECT mi.id, SUM(mil.quantity_on_hand)::FLOAT8 AS total_sum FROM test_item_locations mil JOIN test_items mi ON mil.part_id = mi.id GROUP BY mi.id ), cte_recipe_items AS ( SELECT items.*, /*COALESCE(test_items.barcode, items.uuid) AS uuid,*/ (SELECT COALESCE(row_to_json(units.*), '{}') FROM units WHERE units.id=test_item_info.uom) AS item_uom, COALESCE(test_items.item_name, items.item_name) AS item_name, COALESCE(test_items.links, items.links) AS links, row_to_json(units.*) as uom, (SELECT COALESCE(array_agg(jsonb_build_object('conversion', conv, 'unit', units)), '{}') FROM test_conversions conv LEFT JOIN units ON conv.uom_id = units.id WHERE conv.item_id = test_items.id) AS conversions, COALESCE(sum_cte.total_sum, 0.0) AS quantity_on_hand FROM test_recipe_items items LEFT JOIN test_items ON items.item_id = test_items.id LEFT JOIN test_item_info ON test_items.item_info_id = test_item_info.id LEFT JOIN units ON units.id = items.uom LEFT JOIN sum_cte ON test_items.id = sum_cte.id WHERE items.rp_id = (SELECT passed_id FROM passed_id) ORDER BY items.item_name ASC ) SELECT (SELECT passed_id FROM passed_id) AS passed_id, test_recipes.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(ris)), '{}') FROM cte_recipe_items ris) AS recipe_itemsFROM test_recipesJOIN logins ON test_recipes.author = logins.idWHERE test_recipes.id=(SELECT passed_id FROM passed_id)')
|
||||||
|
2025-08-14 17:03:48.785824 --- ERROR --- DatabaseError(message='syntax error at or near "SELECT"LINE 2: SELECT (SELECT passed_id FROM passed_id) AS passed_id, ^',
|
||||||
|
payload=('ab60ddfa-90ab-4ce0-9c98-a505873788bd',),
|
||||||
|
sql='WITH passed_id AS (SELECT recipes.id AS passed_id FROM test_recipes recipes WHERE recipes.recipe_uuid = %s::uuid),SELECT (SELECT passed_id FROM passed_id) AS passed_id, recipe_items.*,FROM test_recipe_items recipe_itemsWHERE test_recipes.id=(SELECT passed_id FROM passed_id);')
|
||||||
|
2025-08-14 17:04:26.545601 --- ERROR --- DatabaseError(message='syntax error at or near "SELECT"LINE 2: SELECT (SELECT passed_id FROM passed_id) AS passed_id, ^',
|
||||||
|
payload=('ab60ddfa-90ab-4ce0-9c98-a505873788bd',),
|
||||||
|
sql='WITH passed_id AS (SELECT recipes.id AS passed_id FROM test_recipes recipes WHERE recipes.recipe_uuid = %s::uuid),SELECT (SELECT passed_id FROM passed_id) AS passed_id, recipe_items.*FROM test_recipe_items recipe_itemsWHERE test_recipes.id=(SELECT passed_id FROM passed_id);')
|
||||||
|
2025-08-14 17:04:43.018584 --- ERROR --- DatabaseError(message='missing FROM-clause entry for table "test_recipes"LINE 5: WHERE test_recipes.id=(SELECT passed_id FROM passed_id); ^',
|
||||||
|
payload=('ab60ddfa-90ab-4ce0-9c98-a505873788bd',),
|
||||||
|
sql='WITH passed_id AS (SELECT recipes.id AS passed_id FROM test_recipes recipes WHERE recipes.recipe_uuid = %s::uuid)SELECT (SELECT passed_id FROM passed_id) AS passed_id, recipe_items.*FROM test_recipe_items recipe_itemsWHERE test_recipes.id=(SELECT passed_id FROM passed_id);')
|
||||||
|
2025-08-14 17:13:12.481521 --- ERROR --- DatabaseError(message='syntax error at or near "FROM"LINE 7: FROM test_recipe_items recipe_items ^',
|
||||||
|
payload=('ab60ddfa-90ab-4ce0-9c98-a505873788bd',),
|
||||||
|
sql='WITH passed_id AS (SELECT recipes.id AS passed_id FROM test_recipes recipes WHERE recipes.recipe_uuid = %s::uuid)SELECT COALESCE(item_info.uom, recipe_items.uom) as uom, COALESCE(items.links, recipe_items.links) as links, items.item_uuid, items.item_name,FROM test_recipe_items recipe_itemsLEFT JOIN test_items items ON items.item_uuid = recipe_items.item_uuidLEFT JOIN test_item_info item_info ON item_info.id = items.item_info_idWHERE recipe_items.rp_id=(SELECT passed_id FROM passed_id);')
|
||||||
|
2025-08-14 17:15:03.135511 --- ERROR --- DatabaseError(message='COALESCE types character varying and integer cannot be matchedLINE 3: COALESCE(units.fullname, recipe_items.uom) as uom, ^',
|
||||||
|
payload=('ab60ddfa-90ab-4ce0-9c98-a505873788bd',),
|
||||||
|
sql='WITH passed_id AS (SELECT recipes.id AS passed_id FROM test_recipes recipes WHERE recipes.recipe_uuid = %s::uuid)SELECT COALESCE(units.fullname, recipe_items.uom) as uom, COALESCE(items.links, recipe_items.links) as links, items.item_uuid, items.item_nameFROM test_recipe_items recipe_itemsLEFT JOIN test_items items ON items.item_uuid = recipe_items.item_uuidLEFT JOIN test_item_info item_info ON item_info.id = items.item_info_idLEFT JOIN units ON units.id = item_info.uomWHERE recipe_items.rp_id=(SELECT passed_id FROM passed_id);')
|
||||||
|
2025-08-14 17:16:24.328017 --- ERROR --- DatabaseError(message='COALESCE types character varying and integer cannot be matchedLINE 3: ...ullname FROM units WHERE units.id=item_info.uom), recipe_ite... ^',
|
||||||
|
payload=('ab60ddfa-90ab-4ce0-9c98-a505873788bd',),
|
||||||
|
sql='WITH passed_id AS (SELECT recipes.id AS passed_id FROM test_recipes recipes WHERE recipes.recipe_uuid = %s::uuid)SELECT COALESCE((SELECT units.fullname FROM units WHERE units.id=item_info.uom), recipe_items.uom) as uom, COALESCE(items.links, recipe_items.links) as links, items.item_uuid, items.item_nameFROM test_recipe_items recipe_itemsLEFT JOIN test_items items ON items.item_uuid = recipe_items.item_uuidLEFT JOIN test_item_info item_info ON item_info.id = items.item_info_idWHERE recipe_items.rp_id=(SELECT passed_id FROM passed_id);')
|
||||||
|
2025-08-14 17:23:17.559471 --- ERROR --- DatabaseError(message='null value in column "item_name" of relation "test_shopping_list_items" violates not-null constraintDETAIL: Failing row contains (recipe, null, 1, 55, {"main": "1"}, f3571bbb-25d3-4b9d-aafd-6be67a289068, null, 14d8ce2f-2920-47ae-a671-2953d567383d).',
|
||||||
|
payload=('14d8ce2f-2920-47ae-a671-2953d567383d', 'recipe', None, 1, 55.0, None, '{"main": "1"}'),
|
||||||
|
sql='INSERT INTO test_shopping_list_items(list_uuid, item_type, item_name, uom, qty, item_uuid, links) VALUES (%s, %s, %s, %s, %s, %s, %s) RETURNING *;')
|
||||||
|
2025-08-14 17:30:27.390620 --- ERROR --- DatabaseError(message='duplicate key value violates unique constraint "unique combo"DETAIL: Key (item_name, list_uuid)=(Torani Peppermint syrup, ad3bfe0d-3442-42fa-af16-08a6fc0a1c33) already exists.',
|
||||||
|
payload=('ad3bfe0d-3442-42fa-af16-08a6fc0a1c33', 'recipe', 'Torani Peppermint syrup', 1, 1.0, '53d52046-8e70-4451-89fb-200de48ae6d0', '{}'),
|
||||||
|
sql='INSERT INTO test_shopping_list_items(list_uuid, item_type, item_name, uom, qty, item_uuid, links) VALUES (%s, %s, %s, %s, %s, %s, %s) RETURNING *;')
|
||||||
|
2025-08-14 17:48:08.287394 --- ERROR --- DatabaseError(message='column excluded.col2 does not existLINE 5: SET qty = test_shopping_list_items.qty + EXCLUDED.col2 ^',
|
||||||
|
payload=('ad3bfe0d-3442-42fa-af16-08a6fc0a1c33', 'recipe', 'Torani Peppermint syrup', 1, 1.0, '53d52046-8e70-4451-89fb-200de48ae6d0', '{}'),
|
||||||
|
sql='INSERT INTO test_shopping_list_items(list_uuid, item_type, item_name, uom, qty, item_uuid, links) VALUES (%s, %s, %s, %s, %s, %s, %s)ON CONFLICT (list_uuid, item_name) DO UPDATESET qty = test_shopping_list_items.qty + EXCLUDED.col2RETURNING *;')
|
||||||
|
2025-08-14 17:58:26.999337 --- ERROR --- DatabaseError(message='invalid input syntax for type uuid: "target='_blank'"',
|
||||||
|
payload=("target='_blank'",),
|
||||||
|
sql='WITH passed_uuid AS (SELECT %s AS passed_uuid), cte_sl_items AS ( SELECT items.*, (SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom FROM test_shopping_list_items items WHERE items.list_uuid = (SELECT passed_uuid::uuid FROM passed_uuid) )SELECT (SELECT passed_uuid FROM passed_uuid) AS passed_uuid, test_shopping_lists.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(slis)), '{}') FROM cte_sl_items slis) AS sl_items FROM test_shopping_listsJOIN logins ON test_shopping_lists.author = logins.idWHERE test_shopping_lists.list_uuid=(SELECT passed_uuid::uuid FROM passed_uuid)')
|
||||||
|
2025-08-14 17:58:32.904639 --- ERROR --- DatabaseError(message='invalid input syntax for type uuid: "target='_blank'"',
|
||||||
|
payload=("target='_blank'",),
|
||||||
|
sql='WITH passed_uuid AS (SELECT %s AS passed_uuid), cte_sl_items AS ( SELECT items.*, (SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom FROM test_shopping_list_items items WHERE items.list_uuid = (SELECT passed_uuid::uuid FROM passed_uuid) )SELECT (SELECT passed_uuid FROM passed_uuid) AS passed_uuid, test_shopping_lists.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(slis)), '{}') FROM cte_sl_items slis) AS sl_items FROM test_shopping_listsJOIN logins ON test_shopping_lists.author = logins.idWHERE test_shopping_lists.list_uuid=(SELECT passed_uuid::uuid FROM passed_uuid)')
|
||||||
|
2025-08-14 17:58:36.459552 --- ERROR --- DatabaseError(message='invalid input syntax for type uuid: "1"',
|
||||||
|
payload=('1',),
|
||||||
|
sql='WITH passed_uuid AS (SELECT %s AS passed_uuid), cte_sl_items AS ( SELECT items.*, (SELECT COALESCE(row_to_json(un), '{}') FROM units un WHERE un.id = items.uom LIMIT 1) AS uom FROM test_shopping_list_items items WHERE items.list_uuid = (SELECT passed_uuid::uuid FROM passed_uuid) )SELECT (SELECT passed_uuid FROM passed_uuid) AS passed_uuid, test_shopping_lists.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(slis)), '{}') FROM cte_sl_items slis) AS sl_items FROM test_shopping_listsJOIN logins ON test_shopping_lists.author = logins.idWHERE test_shopping_lists.list_uuid=(SELECT passed_uuid::uuid FROM passed_uuid)')
|
||||||
|
2025-08-14 18:14:47.690481 --- ERROR --- DatabaseError(message='relation "cte_item_info" does not existLINE 8: (SELECT COALESCE(row_to_json(ii), '{}') FROM cte_item_in... ^',
|
||||||
|
payload=None,
|
||||||
|
sql='WITH sum_cte AS ( SELECT mi.id, SUM(mil.quantity_on_hand) AS total_sum FROM main_item_locations mil JOIN main_items mi ON mil.part_id = mi.id GROUP BY mi.id)SELECT main_items.*, (SELECT COALESCE(row_to_json(ii), '{}') FROM cte_item_info ii) AS item_infoFROM main_itemsLEFT JOIN main_item_info ON main_items.item_info_id = main_item_info.idLEFT JOIN units ON units.id = main_item_info.uomLEFT JOIN sum_cte ON main_items.id = sum_cte.idWHERE main_item_info.safety_stock > COALESCE(sum_cte.total_sum, 0);')
|
||||||
|
2025-08-14 18:15:24.034419 --- ERROR --- DatabaseError(message='missing FROM-clause entry for table "item_info"LINE 8: COALESCE(row_to_json(item_info.*), '{}') AS item_info ^',
|
||||||
|
payload=None,
|
||||||
|
sql='WITH sum_cte AS ( SELECT mi.id, SUM(mil.quantity_on_hand) AS total_sum FROM main_item_locations mil JOIN main_items mi ON mil.part_id = mi.id GROUP BY mi.id)SELECT main_items.*, COALESCE(row_to_json(item_info.*), '{}') AS item_infoFROM main_itemsLEFT JOIN main_item_info ON main_items.item_info_id = main_item_info.idLEFT JOIN units ON units.id = main_item_info.uomLEFT JOIN sum_cte ON main_items.id = sum_cte.idWHERE main_item_info.safety_stock > COALESCE(sum_cte.total_sum, 0);')
|
||||||
7
run-server.sh
Normal file
7
run-server.sh
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Start Flask app
|
||||||
|
gnome-terminal -- bash -c "python webserver.py; exec bash" &
|
||||||
|
# Start Celery worker
|
||||||
|
gnome-terminal -- bash -c "celery -A celery_worker.celery worker --loglevel=info; exec bash" &
|
||||||
|
# Start Celery beat
|
||||||
|
gnome-terminal -- bash -c "celery -A celery_worker.celery beat --loglevel=info; exec bash" &
|
||||||
Loading…
x
Reference in New Issue
Block a user