Added the ability to generate shopping lists
dynamically
This commit is contained in:
parent
a22faeb7a8
commit
faafa75422
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -238,6 +238,18 @@ def deleteListItem():
|
|||||||
return jsonify({"error":False, "message":"item deleted succesfully!"})
|
return jsonify({"error":False, "message":"item deleted succesfully!"})
|
||||||
return jsonify({"error":True, "message":"There was an error with this POST statement"})
|
return jsonify({"error":True, "message":"There was an error with this POST statement"})
|
||||||
|
|
||||||
|
@shopping_list_api.route('/api/deleteList', methods=["POST"])
|
||||||
|
@access_api.login_required
|
||||||
|
def deleteList():
|
||||||
|
if request.method == "POST":
|
||||||
|
shopping_list_uuid = request.get_json()['shopping_list_uuid']
|
||||||
|
site_name = session['selected_site']
|
||||||
|
user_id = session['user_id']
|
||||||
|
shoplist_processess.deleteShoppingList(site_name, {'shopping_list_uuid': shopping_list_uuid}, user_id)
|
||||||
|
return jsonify({"error":False, "message":"List Deleted succesfully!"})
|
||||||
|
return jsonify({"error":True, "message":"There was an error with this POST statement"})
|
||||||
|
|
||||||
|
|
||||||
# Added to Database
|
# Added to Database
|
||||||
@shopping_list_api.route('/api/saveListItem', methods=["POST"])
|
@shopping_list_api.route('/api/saveListItem', methods=["POST"])
|
||||||
@access_api.login_required
|
@access_api.login_required
|
||||||
@ -293,3 +305,15 @@ def setListItemState():
|
|||||||
|
|
||||||
return jsonify({"list_items":items, "error":False, "message":"items fetched succesfully!"})
|
return jsonify({"list_items":items, "error":False, "message":"items fetched succesfully!"})
|
||||||
return jsonify({"list_items":items, "error":True, "message":"There was an error with this GET statement"})
|
return jsonify({"list_items":items, "error":True, "message":"There was an error with this GET statement"})
|
||||||
|
|
||||||
|
|
||||||
|
@shopping_list_api.route('/api/postGeneratedList', methods=["POST"])
|
||||||
|
@access_api.login_required
|
||||||
|
def postGeneratedList():
|
||||||
|
if request.method == "POST":
|
||||||
|
payload: dict = request.get_json()
|
||||||
|
site_name: str = session['selected_site']
|
||||||
|
user_id: int = session['user_id']
|
||||||
|
shoplist_processess.postNewGeneratedList(site_name, payload, user_id)
|
||||||
|
return jsonify(status=201, message=f"List Generated successfully!")
|
||||||
|
return jsonify(status=405, message=f"{request.method} is not an accepted method on this endpoint!")
|
||||||
@ -1,7 +1,6 @@
|
|||||||
# 3rd Party imports
|
# 3rd Party imports
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
||||||
|
|
||||||
# applications imports
|
# applications imports
|
||||||
import config
|
import config
|
||||||
from application import postsqldb
|
from application import postsqldb
|
||||||
@ -150,7 +149,6 @@ def getRecipeItemsByUUID(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 getItemsWithQOH(site, payload, convert=True, conn=None):
|
def getItemsWithQOH(site, payload, convert=True, conn=None):
|
||||||
recordset = []
|
recordset = []
|
||||||
count = 0
|
count = 0
|
||||||
@ -263,7 +261,6 @@ def getListsModal(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 getItemsModal(site, payload, convert=True, conn=None):
|
def getItemsModal(site, payload, convert=True, conn=None):
|
||||||
recordsets = []
|
recordsets = []
|
||||||
count = 0
|
count = 0
|
||||||
@ -298,6 +295,63 @@ def getItemsModal(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 getItemByUUID(site, payload:dict, convert=True, conn=None):
|
||||||
|
""" payload: dict = {'item_uuid'}"""
|
||||||
|
record = ()
|
||||||
|
self_conn = False
|
||||||
|
with open('application/shoppinglists/sql/getItemByUUID.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.fetchone()
|
||||||
|
if rows and convert:
|
||||||
|
record = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||||
|
elif rows and not convert:
|
||||||
|
record = rows
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return record
|
||||||
|
except Exception as error:
|
||||||
|
raise postsqldb.DatabaseError(error, payload, sql)
|
||||||
|
|
||||||
|
def deleteShoppingListsTuple(site_name, payload, convert=True, conn=None):
|
||||||
|
deleted = ()
|
||||||
|
self_conn = False
|
||||||
|
sql = f"WITH deleted_rows AS (DELETE FROM {site_name}_shopping_lists WHERE {site_name}_shopping_lists.list_uuid IN ({','.join(['%s'] * len(payload))}) RETURNING *) SELECT * FROM deleted_rows;"
|
||||||
|
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:
|
||||||
|
deleted = [postsqldb.tupleDictionaryFactory(cur.description, r) for r in rows]
|
||||||
|
elif rows and not convert:
|
||||||
|
deleted = rows
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return deleted
|
||||||
|
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
|
||||||
|
|||||||
@ -37,3 +37,151 @@ def addRecipeItemsToList(site:str, data:dict, user_id: int, conn=None):
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
def postNewGeneratedList(site: str, data: dict, user_id: int, conn=None):
|
||||||
|
"""data={'list_type', 'list_name', 'list_description', 'custom_items', 'uncalculated_items', 'calculated_items', 'recipes', 'full_system_calculated', 'shopping_lists'}"""
|
||||||
|
list_type: str = data['list_type']
|
||||||
|
list_name: str = data['list_name']
|
||||||
|
list_description: str = data['list_description']
|
||||||
|
custom_items: list = data['custom_items']
|
||||||
|
uncalculated_items: list = data['uncalculated_items']
|
||||||
|
calculated_items: list = data['calculated_items']
|
||||||
|
recipes: list = data['recipes']
|
||||||
|
full_system_calculated: list = data['full_system_calculated']
|
||||||
|
shopping_lists: list = data['shopping_lists']
|
||||||
|
|
||||||
|
|
||||||
|
self_conn=False
|
||||||
|
|
||||||
|
if not conn:
|
||||||
|
database_config = config.config()
|
||||||
|
conn = psycopg2.connect(**database_config)
|
||||||
|
conn.autocommit = False
|
||||||
|
self_conn = True
|
||||||
|
|
||||||
|
shopping_list = database_payloads.ShoppingListPayload(
|
||||||
|
name=list_name,
|
||||||
|
description=list_description,
|
||||||
|
author=int(user_id),
|
||||||
|
sub_type="plain",
|
||||||
|
list_type=list_type
|
||||||
|
)
|
||||||
|
shopping_list = shoplist_database.insertShoppingListsTuple(site, shopping_list.payload(), conn=conn)
|
||||||
|
|
||||||
|
items_to_add_to_system = []
|
||||||
|
# start by checcking if i should iterate full sku calc
|
||||||
|
if full_system_calculated:
|
||||||
|
safety_stock_items = shoplist_database.getItemsSafetyStock(site, conn=conn)
|
||||||
|
for item in safety_stock_items:
|
||||||
|
qty = float(item['item_info']['safety_stock']-float(item['total_sum']))
|
||||||
|
temp_item = database_payloads.ShoppingListItemPayload(
|
||||||
|
list_uuid=shopping_list['list_uuid'],
|
||||||
|
item_type='calculated sku',
|
||||||
|
item_name=item['item_name'],
|
||||||
|
uom=item['item_info']['uom'],
|
||||||
|
qty=qty,
|
||||||
|
item_uuid=item['item_uuid'],
|
||||||
|
links=item['links']
|
||||||
|
)
|
||||||
|
items_to_add_to_system.append(temp_item)
|
||||||
|
|
||||||
|
if calculated_items and not full_system_calculated:
|
||||||
|
for item_uuid in calculated_items:
|
||||||
|
item = shoplist_database.getItemByUUID(site, {'item_uuid': item_uuid}, conn=conn)
|
||||||
|
qty = float(item['item_info']['safety_stock']-float(item['total_sum']))
|
||||||
|
temp_item = database_payloads.ShoppingListItemPayload(
|
||||||
|
list_uuid=shopping_list['list_uuid'],
|
||||||
|
item_type='calculated sku',
|
||||||
|
item_name=item['item_name'],
|
||||||
|
uom=item['item_info']['uom'],
|
||||||
|
qty=qty,
|
||||||
|
item_uuid=item['item_uuid'],
|
||||||
|
links=item['links']
|
||||||
|
)
|
||||||
|
items_to_add_to_system.append(temp_item)
|
||||||
|
|
||||||
|
|
||||||
|
if custom_items:
|
||||||
|
for item in custom_items:
|
||||||
|
temp_item = database_payloads.ShoppingListItemPayload(
|
||||||
|
list_uuid=shopping_list['list_uuid'],
|
||||||
|
item_type='custom',
|
||||||
|
item_name=item['item_name'],
|
||||||
|
uom=item['uom'],
|
||||||
|
qty=float(item['qty']),
|
||||||
|
item_uuid=None,
|
||||||
|
links={'main': item['link']}
|
||||||
|
)
|
||||||
|
items_to_add_to_system.append(temp_item)
|
||||||
|
|
||||||
|
if uncalculated_items:
|
||||||
|
for item in uncalculated_items:
|
||||||
|
temp_item = database_payloads.ShoppingListItemPayload(
|
||||||
|
list_uuid=shopping_list['list_uuid'],
|
||||||
|
item_type='uncalculated sku',
|
||||||
|
item_name=item['item_name'],
|
||||||
|
uom=item['uom'],
|
||||||
|
qty=float(item['qty']),
|
||||||
|
item_uuid=None,
|
||||||
|
links={'main': item['link']}
|
||||||
|
)
|
||||||
|
items_to_add_to_system.append(temp_item)
|
||||||
|
|
||||||
|
|
||||||
|
if recipes:
|
||||||
|
for recipe_uuid in recipes:
|
||||||
|
recipe_items = shoplist_database.getRecipeItemsByUUID(site, (recipe_uuid,), conn=conn)
|
||||||
|
for item in recipe_items:
|
||||||
|
temp_item = database_payloads.ShoppingListItemPayload(
|
||||||
|
list_uuid=shopping_list['list_uuid'],
|
||||||
|
item_type='recipe',
|
||||||
|
item_name=item['item_name'],
|
||||||
|
uom=item['uom'],
|
||||||
|
qty=float(item['qty']),
|
||||||
|
item_uuid=item['item_uuid'],
|
||||||
|
links=item['links']
|
||||||
|
)
|
||||||
|
items_to_add_to_system.append(temp_item)
|
||||||
|
|
||||||
|
if shopping_lists:
|
||||||
|
for shopping_list_uuid in shopping_lists:
|
||||||
|
shopping_list_items = shoplist_database.getShoppingList(site, (shopping_list_uuid,), conn=conn)['sl_items']
|
||||||
|
for item in shopping_list_items:
|
||||||
|
temp_item = database_payloads.ShoppingListItemPayload(
|
||||||
|
list_uuid=shopping_list['list_uuid'],
|
||||||
|
item_type=item['item_type'],
|
||||||
|
item_name=item['item_name'],
|
||||||
|
uom=item['uom']['id'],
|
||||||
|
qty=float(item['qty']),
|
||||||
|
item_uuid=item['item_uuid'],
|
||||||
|
links=item['links']
|
||||||
|
)
|
||||||
|
items_to_add_to_system.append(temp_item)
|
||||||
|
|
||||||
|
|
||||||
|
if items_to_add_to_system:
|
||||||
|
for item in items_to_add_to_system:
|
||||||
|
shoplist_database.insertShoppingListItemsTuple(site, item.payload(), conn=conn)
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def deleteShoppingList(site: str, data: dict, user_id: int, conn=None):
|
||||||
|
shopping_list_uuid = data['shopping_list_uuid']
|
||||||
|
self_conn=False
|
||||||
|
|
||||||
|
if not conn:
|
||||||
|
database_config = config.config()
|
||||||
|
conn = psycopg2.connect(**database_config)
|
||||||
|
conn.autocommit = False
|
||||||
|
self_conn = True
|
||||||
|
|
||||||
|
shopping_list_items = shoplist_database.getShoppingList(site, (shopping_list_uuid, ), conn=conn)['sl_items']
|
||||||
|
shopping_list_items = [item['list_item_uuid'] for item in shopping_list_items]
|
||||||
|
|
||||||
|
shoplist_database.deleteShoppingListsTuple(site, (shopping_list_uuid,), conn=conn)
|
||||||
|
shoplist_database.deleteShoppingListItemsTuple(site, shopping_list_items, conn=conn)
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
15
application/shoppinglists/sql/getItemByUUID.sql
Normal file
15
application/shoppinglists/sql/getItemByUUID.sql
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
WITH sum_cte AS (
|
||||||
|
SELECT mi.id, SUM(mil.quantity_on_hand) AS total_sum
|
||||||
|
FROM %%site_name%%_item_locations mil
|
||||||
|
JOIN %%site_name%%_items mi ON mil.part_id = mi.id
|
||||||
|
GROUP BY mi.id
|
||||||
|
)
|
||||||
|
|
||||||
|
SELECT items.*,
|
||||||
|
COALESCE(row_to_json(item_info.*), '{}') AS item_info,
|
||||||
|
COALESCE(sum_cte.total_sum, 0) AS total_sum
|
||||||
|
FROM %%site_name%%_items items
|
||||||
|
LEFT JOIN %%site_name%%_item_info item_info ON items.item_info_id = item_info.id
|
||||||
|
LEFT JOIN units ON units.id = item_info.uom
|
||||||
|
LEFT JOIN sum_cte ON items.id = sum_cte.id
|
||||||
|
WHERE items.item_uuid = %(item_uuid)s
|
||||||
@ -1075,3 +1075,27 @@ async function generateListsTable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Generate Functions
|
||||||
|
async function postGenerateList() {
|
||||||
|
let data = {
|
||||||
|
list_type: String(document.getElementById('generated_list_type').value),
|
||||||
|
list_name: String(document.getElementById('generated_list_name').value),
|
||||||
|
list_description: String(document.getElementById('generated_list_description').value),
|
||||||
|
custom_items: Object.values(custom_items),
|
||||||
|
uncalculated_items: Object.values(uncalculated_items),
|
||||||
|
calculated_items: Object.keys(calculated_items),
|
||||||
|
recipes: Object.keys(recipes),
|
||||||
|
full_system_calculated: full_sku_enabled,
|
||||||
|
shopping_lists: Object.keys(shopping_lists)
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`/shopping-lists/api/postGeneratedList`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -54,11 +54,11 @@ async function replenishShoppingListCards(lists) {
|
|||||||
footer_div.setAttribute('class', 'uk-card-footer')
|
footer_div.setAttribute('class', 'uk-card-footer')
|
||||||
footer_div.style = 'height: 40px; border: none;'
|
footer_div.style = 'height: 40px; border: none;'
|
||||||
|
|
||||||
let editOp = document.createElement('a')
|
//let editOp = document.createElement('a')
|
||||||
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].list_uuid}`
|
//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')
|
||||||
@ -66,8 +66,14 @@ async function replenishShoppingListCards(lists) {
|
|||||||
viewOp.href = `/shopping-lists/view/${lists[i].list_uuid}`
|
viewOp.href = `/shopping-lists/view/${lists[i].list_uuid}`
|
||||||
//viewOp.style = "margin-right: 20px;"
|
//viewOp.style = "margin-right: 20px;"
|
||||||
|
|
||||||
|
let deleteOp = document.createElement('a')
|
||||||
|
deleteOp.setAttribute('class', 'uk-button uk-button-small uk-button-default')
|
||||||
|
deleteOp.innerHTML = '<span uk-icon="icon: eye"></span> Delete'
|
||||||
|
deleteOp.onclick = async function(params) { await deleteList(lists[i].list_uuid)}
|
||||||
|
//viewOp.style = "margin-right: 20px;"
|
||||||
|
|
||||||
footer_div.append(editOp, viewOp)
|
|
||||||
|
footer_div.append(viewOp, deleteOp)
|
||||||
|
|
||||||
main_div.append(card_header_div, body_div, footer_div)
|
main_div.append(card_header_div, body_div, footer_div)
|
||||||
|
|
||||||
@ -123,6 +129,35 @@ async function addList() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function deleteList(shopping_list_uuid) {
|
||||||
|
const response = await fetch(`/shopping-lists/api/deleteList`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
shopping_list_uuid: shopping_list_uuid
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
data = await response.json();
|
||||||
|
transaction_status = "success"
|
||||||
|
if (data.error){
|
||||||
|
transaction_status = "danger"
|
||||||
|
}
|
||||||
|
|
||||||
|
UIkit.notification({
|
||||||
|
message: data.message,
|
||||||
|
status: transaction_status,
|
||||||
|
pos: 'top-right',
|
||||||
|
timeout: 5000
|
||||||
|
});
|
||||||
|
|
||||||
|
let lists = await getShoppingLists()
|
||||||
|
await replenishShoppingListCards(lists)
|
||||||
|
await updatePaginationElement()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
async function changeSite(site){
|
async function changeSite(site){
|
||||||
const response = await fetch(`/changeSite`, {
|
const response = await fetch(`/changeSite`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|||||||
@ -138,7 +138,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- basic info section -->
|
<!-- basic info section -->
|
||||||
<div class="uk-width-1-1">
|
<div class="uk-width-1-1">
|
||||||
<h1 class="uk-heading-xsmall uk-heading-divider">Shopping List Type</h1>
|
<h1 class="uk-heading-xsmall uk-heading-divider">Shopping List Info</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-width-1-1">
|
<div class="uk-width-1-1">
|
||||||
<p class="uk-text-small">Fill out the basic info asked for here, the description could be helpful to remind yourself and others what the list was generated for.
|
<p class="uk-text-small">Fill out the basic info asked for here, the description could be helpful to remind yourself and others what the list was generated for.
|
||||||
@ -152,11 +152,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-width-1-1">
|
<div class="uk-width-1-1">
|
||||||
<label class="uk-form-label" for="generated_list_name">Shopping List Description</label>
|
<label class="uk-form-label" for="generated_list_description">Shopping List Description</label>
|
||||||
<div class="uk-form-controls">
|
<div class="uk-form-controls">
|
||||||
<textarea id="generated_list_name" class="uk-textarea" rows="5" placeholder="Enter list description here..." aria-label="Textarea"></textarea>
|
<textarea id="generated_list_description" class="uk-textarea" rows="5" placeholder="Enter list description here..." aria-label="Textarea"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="uk-width-1-1">
|
||||||
|
<button onclick="postGenerateList()" class="uk-button uk-button-primary uk-align-right">Generate List</button>
|
||||||
|
</div>
|
||||||
<!-- Part section -->
|
<!-- Part section -->
|
||||||
<div class="uk-width-1-1">
|
<div class="uk-width-1-1">
|
||||||
<h1 class="uk-heading-xsmall uk-heading-divider">Shopping List Operators</h1>
|
<h1 class="uk-heading-xsmall uk-heading-divider">Shopping List Operators</h1>
|
||||||
|
|||||||
@ -112,7 +112,7 @@
|
|||||||
<div uk-grid>
|
<div uk-grid>
|
||||||
<div class="uk-width-1-2@m">
|
<div class="uk-width-1-2@m">
|
||||||
<ul class="uk-iconnav uk-flex-center uk-flex-left@m">
|
<ul class="uk-iconnav uk-flex-center uk-flex-left@m">
|
||||||
<li><a onclick="openAddListModal()" uk-icon="icon: plus">Add List</a></li>
|
<!--li><a onclick="openAddListModal()" uk-icon="icon: plus">Add List</a></li-->
|
||||||
<li><a href="/shopping-lists/generate" uk-icon="icon: plus">Generate List</a></li>
|
<li><a href="/shopping-lists/generate" uk-icon="icon: plus">Generate List</a></li>
|
||||||
<li><a href="#" uk-icon="icon: cloud-download">download</a></li>
|
<li><a href="#" uk-icon="icon: cloud-download">download</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@ -563,3 +563,18 @@
|
|||||||
2025-08-17 19:22:32.824380 --- ERROR --- DatabaseError(message='duplicate key value violates unique constraint "main_item_info_barcode_key"DETAIL: Key (barcode)=(%%) already exists.',
|
2025-08-17 19:22:32.824380 --- ERROR --- DatabaseError(message='duplicate key value violates unique constraint "main_item_info_barcode_key"DETAIL: Key (barcode)=(%%) already exists.',
|
||||||
payload=('%%', '', 1.0, 1, 0.0, 0.0, 0.0, False, '{}'),
|
payload=('%%', '', 1.0, 1, 0.0, 0.0, 0.0, False, '{}'),
|
||||||
sql='INSERT INTO main_item_info(barcode, packaging, uom_quantity, uom, cost, safety_stock, lead_time_days, ai_pick, prefixes) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING *;')
|
sql='INSERT INTO main_item_info(barcode, packaging, uom_quantity, uom, cost, safety_stock, lead_time_days, ai_pick, prefixes) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING *;')
|
||||||
|
2025-08-19 14:46:59.332054 --- ERROR --- DatabaseError(message='duplicate key value violates unique constraint "main_barcodes_pkey"DETAIL: Key (barcode)=(%181945000062%) already exists.',
|
||||||
|
payload=('%181945000062%', 'faecba1e-8817-4e19-9ade-d43cb4602aae', '1', '1', ''),
|
||||||
|
sql='INSERT INTO main_barcodes (barcode, item_uuid, in_exchange, out_exchange, descriptor) VALUES (%s, %s, %s, %s, %s) RETURNING *;')
|
||||||
|
2025-08-19 15:39:25.102811 --- ERROR --- DatabaseError(message='dict is not a sequence',
|
||||||
|
payload={'item_uuid': '392f05b5-4ccd-41da-875d-0e593f51b610'},
|
||||||
|
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 * FROM main_items 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 items.item_uuid = %{item_uuid}s')
|
||||||
|
2025-08-19 15:43:08.370309 --- ERROR --- DatabaseError(message='invalid reference to FROM-clause entry for table "main_items"LINE 10: LEFT JOIN main_item_info ON main_items.item_info_id = main_i... ^HINT: Perhaps you meant to reference the table alias "items".',
|
||||||
|
payload={'item_uuid': '392f05b5-4ccd-41da-875d-0e593f51b610'},
|
||||||
|
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 * FROM main_items 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 items.item_uuid = %(item_uuid)s')
|
||||||
|
2025-08-19 15:45:09.890974 --- ERROR --- DatabaseError(message='syntax error at or near "FROM"LINE 11: FROM main_items items ^',
|
||||||
|
payload={'item_uuid': '392f05b5-4ccd-41da-875d-0e593f51b610'},
|
||||||
|
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(main_item_info.*), '{}') AS item_info, COALESCE(sum_cte.total_sum, 0) AS total_sum,FROM main_items itemsLEFT JOIN main_item_info item_info ON items.item_info_id = item_info.idLEFT JOIN units ON units.id = item_info.uomLEFT JOIN sum_cte ON items.id = sum_cte.idWHERE items.item_uuid = %(item_uuid)s')
|
||||||
|
2025-08-19 15:45:32.184317 --- ERROR --- DatabaseError(message='syntax error at or near "FROM"LINE 11: FROM main_items items ^',
|
||||||
|
payload={'item_uuid': '392f05b5-4ccd-41da-875d-0e593f51b610'},
|
||||||
|
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 items.*, COALESCE(row_to_json(item_info.*), '{}') AS item_info, COALESCE(sum_cte.total_sum, 0) AS total_sum,FROM main_items itemsLEFT JOIN main_item_info item_info ON items.item_info_id = item_info.idLEFT JOIN units ON units.id = item_info.uomLEFT JOIN sum_cte ON items.id = sum_cte.idWHERE items.item_uuid = %(item_uuid)s')
|
||||||
BIN
static/pictures/favicon.ico
Normal file
BIN
static/pictures/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
Loading…
x
Reference in New Issue
Block a user