Migrating Shoppinglist Module to new schema
This commit is contained in:
parent
1018414200
commit
ce8e63b596
@ -3,14 +3,6 @@ import config
|
||||
from application import postsqldb
|
||||
|
||||
def request_receipt_id(conn, site_name):
|
||||
"""gets the next id for receipts_id, currently returns a 8 digit number
|
||||
|
||||
Args:
|
||||
site (str): site to get the next id for
|
||||
|
||||
Returns:
|
||||
json: receipt_id, message, error keys
|
||||
"""
|
||||
next_receipt_id = None
|
||||
sql = f"SELECT receipt_id FROM {site_name}_receipts ORDER BY id DESC LIMIT 1;"
|
||||
try:
|
||||
@ -34,17 +26,6 @@ def request_receipt_id(conn, site_name):
|
||||
return next_receipt_id
|
||||
|
||||
def selectItemLocationsTuple(site_name, payload, convert=True):
|
||||
"""select a single tuple from ItemLocations table for site_name
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect):
|
||||
site_name (str):
|
||||
payload (tuple): [item_id, location_id]
|
||||
convert (bool): defaults to False, used to determine return of tuple/dict
|
||||
|
||||
Returns:
|
||||
tuple: the row that was returned from the table
|
||||
"""
|
||||
item_locations = ()
|
||||
database_config = config.config()
|
||||
select_item_location_sql = f"SELECT * FROM {site_name}_item_locations WHERE part_id = %s AND location_id = %s;"
|
||||
@ -62,17 +43,6 @@ def selectItemLocationsTuple(site_name, payload, convert=True):
|
||||
return error
|
||||
|
||||
def selectCostLayersTuple(site_name, payload, convert=True):
|
||||
"""select a single or series of cost layers from the database for site_name
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect):
|
||||
site_name (str):
|
||||
payload (tuple): (item_locations_id, )
|
||||
convert (bool): defaults to False, used for determining return as tuple/dict
|
||||
|
||||
Returns:
|
||||
list: list of tuples/dict from the cost_layers table for site_name
|
||||
"""
|
||||
cost_layers = ()
|
||||
database_config = config.config()
|
||||
select_cost_layers_sql = f"SELECT cl.* FROM {site_name}_item_locations il JOIN {site_name}_cost_layers cl ON cl.id = ANY(il.cost_layers) where il.id=%s;"
|
||||
@ -118,17 +88,6 @@ def selectLocationsTuple(site, payload, convert=True, conn=None):
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def selectItemLocationsTuple(site_name, payload, convert=True, conn=None):
|
||||
"""select a single tuple from ItemLocations table for site_name
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect):
|
||||
site_name (str):
|
||||
payload (tuple): [item_id, location_id]
|
||||
convert (bool): defaults to False, used to determine return of tuple/dict
|
||||
|
||||
Returns:
|
||||
tuple: the row that was returned from the table
|
||||
"""
|
||||
item_locations = ()
|
||||
self_conn = False
|
||||
select_item_location_sql = f"SELECT * FROM {site_name}_item_locations WHERE part_id = %s AND location_id = %s;"
|
||||
@ -276,21 +235,7 @@ def insertCostLayersTuple(site, payload, convert=True, conn=None):
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def insertTransactionsTuple(site, payload, convert=True, conn=None):
|
||||
"""insert payload into transactions table for site
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
site (str):
|
||||
payload (tuple): (timestamp[timestamp], logistics_info_id[int], barcode[str], name[str],
|
||||
transaction_type[str], quantity[float], description[str], user_id[int], data[jsonb])
|
||||
convert (bool, optional): Determines if to return tuple as dictionary. Defaults to False.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: inserted tuple
|
||||
"""
|
||||
# payload (tuple): (timestamp[timestamp], logistics_info_id[int], barcode[str], name[str],
|
||||
transaction = ()
|
||||
self_conn = False
|
||||
with open(f"application/poe/sql/insertTransactionsTuple.sql", "r+") as file:
|
||||
@ -319,20 +264,6 @@ def insertTransactionsTuple(site, payload, convert=True, conn=None):
|
||||
return transaction
|
||||
|
||||
def insertReceiptsTuple(site, payload, convert=True, conn=None):
|
||||
"""insert payload into receipt table of site
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
site (str):
|
||||
payload (tuple):
|
||||
convert (bool, optional): Determines if to return tuple as dictionary. Defaults to False.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: inserted tuple
|
||||
"""
|
||||
receipt = ()
|
||||
self_conn = False
|
||||
with open(f"application/poe/sql/insertReceiptsTuple.sql", "r+") as file:
|
||||
@ -362,21 +293,6 @@ def insertReceiptsTuple(site, payload, convert=True, conn=None):
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def insertReceiptItemsTuple(site, payload, convert=True, conn=None):
|
||||
"""insert payload into receipt_items table of site
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
site (str):
|
||||
payload (tuple): (type[str], receipt_id[int], barcode[str], name[str],
|
||||
qty[float], data[jsonb], status[str])
|
||||
convert (bool, optional): Determines if to return tuple as dictionary. Defaults to False.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: inserted tuple
|
||||
"""
|
||||
receipt_item = ()
|
||||
self_conn = False
|
||||
|
||||
@ -407,16 +323,6 @@ def insertReceiptItemsTuple(site, payload, convert=True, conn=None):
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def updateCostLayersTuple(site, payload, convert=True, conn=None):
|
||||
"""_summary_
|
||||
|
||||
Args:
|
||||
conn (_type_): _description_
|
||||
site (_type_): _description_
|
||||
payload (_type_): {'id': cost_layer_id, 'update': {column: data...}}
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
cost_layer = ()
|
||||
self_conn = False
|
||||
|
||||
@ -478,21 +384,6 @@ def updateItemLocation(site, payload, convert=True, conn=None):
|
||||
|
||||
|
||||
def deleteCostLayersTuple(site, payload, convert=True, conn=None):
|
||||
"""This is a basic funtion to delete a tuple from a table in site with an id. All
|
||||
tables in this database has id's associated with them.
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
site_name (str):
|
||||
payload (tuple): (tuple_id,)
|
||||
convert (bool, optional): Determines if to return tuple as dictionary. Defaults to True.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: deleted tuple
|
||||
"""
|
||||
deleted = ()
|
||||
self_conn = False
|
||||
sql = f"WITH deleted_rows AS (DELETE FROM {site}_cost_layers WHERE id IN ({','.join(['%s'] * len(payload))}) RETURNING *) SELECT * FROM deleted_rows;"
|
||||
|
||||
0
application/shoppinglists/__init__.py
Normal file
0
application/shoppinglists/__init__.py
Normal file
@ -4,26 +4,32 @@ from config import config, sites_config
|
||||
from main import unfoldCostLayers
|
||||
from user_api import login_required
|
||||
import postsqldb
|
||||
from application.shoppinglists import shoplist_database
|
||||
from application import database_payloads
|
||||
|
||||
shopping_list_api = Blueprint('shopping_list_API', __name__)
|
||||
shopping_list_api = Blueprint('shopping_list_API', __name__, template_folder="templates", static_folder="static")
|
||||
|
||||
@shopping_list_api.route("/shopping-lists")
|
||||
|
||||
# ROOT TEMPLATE CALLS
|
||||
@shopping_list_api.route("/")
|
||||
@login_required
|
||||
def shopping_lists():
|
||||
sites = [site[1] for site in main.get_sites(session['user']['sites'])]
|
||||
return render_template("shopping-lists/index.html", current_site=session['selected_site'], sites=sites)
|
||||
return render_template("lists.html", current_site=session['selected_site'], sites=sites)
|
||||
|
||||
@shopping_list_api.route("/shopping-list/<mode>/<id>")
|
||||
@shopping_list_api.route("/<mode>/<id>")
|
||||
@login_required
|
||||
def shopping_list(mode, id):
|
||||
sites = [site[1] for site in main.get_sites(session['user']['sites'])]
|
||||
if mode == "view":
|
||||
return render_template("shopping-lists/view.html", id=id, current_site=session['selected_site'], sites=sites)
|
||||
return render_template("view.html", id=id, current_site=session['selected_site'], sites=sites)
|
||||
if mode == "edit":
|
||||
return render_template("shopping-lists/edit.html", id=id, current_site=session['selected_site'], sites=sites)
|
||||
return render_template("edit.html", id=id, current_site=session['selected_site'], sites=sites)
|
||||
return redirect("/")
|
||||
|
||||
@shopping_list_api.route('/shopping-lists/addList', methods=["POST"])
|
||||
|
||||
# API CALLS
|
||||
@shopping_list_api.route('/api/addList', methods=["POST"])
|
||||
def addList():
|
||||
if request.method == "POST":
|
||||
list_name = request.get_json()['list_name']
|
||||
@ -43,7 +49,7 @@ def addList():
|
||||
return jsonify({'error': False, 'message': 'List added!!'})
|
||||
return jsonify({'error': True, 'message': 'These was an error with adding the list!'})
|
||||
|
||||
@shopping_list_api.route('/shopping-lists/getLists', methods=["GET"])
|
||||
@shopping_list_api.route('/api/getLists', methods=["GET"])
|
||||
def getShoppingLists():
|
||||
lists = []
|
||||
if request.method == "GET":
|
||||
@ -77,7 +83,7 @@ def getShoppingLists():
|
||||
|
||||
return jsonify({'shopping_lists': lists, 'end':math.ceil(count/limit), 'error': False, 'message': 'Lists queried successfully!'})
|
||||
|
||||
@shopping_list_api.route('/shopping-lists/getList', methods=["GET"])
|
||||
@shopping_list_api.route('/api/getList', methods=["GET"])
|
||||
def getShoppingList():
|
||||
if request.method == "GET":
|
||||
sl_id = int(request.args.get('id', 1))
|
||||
@ -87,19 +93,19 @@ def getShoppingList():
|
||||
lists = database.getShoppingList(conn, site_name, (sl_id, ), convert=True)
|
||||
return jsonify({'shopping_list': lists, 'error': False, 'message': 'Lists queried successfully!'})
|
||||
|
||||
@shopping_list_api.route('/shopping-lists/getListItem', methods=["GET"])
|
||||
# Added to Database
|
||||
@shopping_list_api.route('/api/getListItem', methods=["GET"])
|
||||
def getShoppingListItem():
|
||||
list_item = {}
|
||||
if request.method == "GET":
|
||||
sli_id = int(request.args.get('sli_id', 1))
|
||||
database_config = config()
|
||||
site_name = session['selected_site']
|
||||
with psycopg2.connect(**database_config) as conn:
|
||||
list_item = postsqldb.ShoppingListsTable.getItem(conn, site_name, (sli_id, ))
|
||||
list_item = shoplist_database.getShoppingListItem(site_name, (sli_id, ))
|
||||
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!'})
|
||||
|
||||
@shopping_list_api.route('/shopping-lists/getItems', methods=["GET"])
|
||||
# Added to database
|
||||
@shopping_list_api.route('/api/getItems', methods=["GET"])
|
||||
def getItems():
|
||||
recordset = []
|
||||
count = {'count': 0}
|
||||
@ -109,21 +115,19 @@ def getItems():
|
||||
search_string = request.args.get('search_string', 10)
|
||||
site_name = session['selected_site']
|
||||
offset = (page - 1) * limit
|
||||
database_config = config()
|
||||
with psycopg2.connect(**database_config) as conn:
|
||||
payload = (search_string, limit, offset)
|
||||
recordset, count = database.getItemsWithQOH(conn, site_name, payload, convert=True)
|
||||
sort_order = "ID ASC"
|
||||
payload = (search_string, limit, offset, sort_order)
|
||||
recordset, count = shoplist_database.getItemsWithQOH(site_name, payload, convert=True)
|
||||
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"})
|
||||
|
||||
@shopping_list_api.route('/shopping-lists/postListItem', methods=["POST"])
|
||||
# Added to database
|
||||
@shopping_list_api.route('/api/postListItem', methods=["POST"])
|
||||
def postListItem():
|
||||
if request.method == "POST":
|
||||
data = request.get_json()['data']
|
||||
site_name = session['selected_site']
|
||||
database_config = config()
|
||||
with psycopg2.connect(**database_config) as conn:
|
||||
sl_item = MyDataclasses.ShoppingListItemPayload(
|
||||
sl_item = database_payloads.ShoppingListItemPayload(
|
||||
uuid = data['uuid'],
|
||||
sl_id = data['sl_id'],
|
||||
item_type=data['item_type'],
|
||||
@ -133,22 +137,21 @@ def postListItem():
|
||||
item_id=data['item_id'],
|
||||
links=data['links']
|
||||
)
|
||||
database.insertShoppingListItemsTuple(conn, site_name, sl_item.payload())
|
||||
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('/shopping-lists/deleteListItem', methods=["POST"])
|
||||
# Added to Database
|
||||
@shopping_list_api.route('/api/deleteListItem', methods=["POST"])
|
||||
def deleteListItem():
|
||||
if request.method == "POST":
|
||||
sli_id = request.get_json()['sli_id']
|
||||
site_name = session['selected_site']
|
||||
database_config = config()
|
||||
with psycopg2.connect(**database_config) as conn:
|
||||
database.deleteShoppingListItemsTuple(conn, site_name, (sli_id, ))
|
||||
shoplist_database.deleteShoppingListItemsTuple(site_name, (sli_id, ))
|
||||
return jsonify({"error":False, "message":"item deleted succesfully!"})
|
||||
return jsonify({"error":True, "message":"There was an error with this POST statement"})
|
||||
|
||||
@shopping_list_api.route('/shopping-lists/saveListItem', methods=["POST"])
|
||||
@shopping_list_api.route('/api/saveListItem', methods=["POST"])
|
||||
def saveListItem():
|
||||
if request.method == "POST":
|
||||
sli_id = request.get_json()['sli_id']
|
||||
@ -160,7 +163,7 @@ def saveListItem():
|
||||
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('/shopping-lists/getSKUItemsFull', methods=["GET"])
|
||||
@shopping_list_api.route('/api/getSKUItemsFull', methods=["GET"])
|
||||
def getSKUItemsFull():
|
||||
items = []
|
||||
count = {'count': 0}
|
||||
146
application/shoppinglists/shoplist_database.py
Normal file
146
application/shoppinglists/shoplist_database.py
Normal file
@ -0,0 +1,146 @@
|
||||
|
||||
import psycopg2
|
||||
|
||||
import config
|
||||
from application import postsqldb
|
||||
|
||||
def getShoppingListItem(site, payload, convert=True, conn=None):
|
||||
"""_summary_
|
||||
|
||||
Args:
|
||||
conn (_type_): _description_
|
||||
site (_type_): _description_
|
||||
payload (_type_): (id, )
|
||||
convert (bool, optional): _description_. Defaults to True.
|
||||
|
||||
Raises:
|
||||
DatabaseError: _description_
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
record = ()
|
||||
self_conn = False
|
||||
with open('application/shoppinglists/sql/selectShoppingListItem.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 getItemsWithQOH(site, payload, convert=True, conn=None):
|
||||
recordset = []
|
||||
count = 0
|
||||
self_conn = False
|
||||
|
||||
with open(f"application/shoppinglists/sql/getItemsWithQOH.sql", "r+") as file:
|
||||
sql = file.read().replace("%%site_name%%", site).replace("%%sort_order%%", payload[3])
|
||||
|
||||
payload = list(payload)
|
||||
payload.pop(3)
|
||||
try:
|
||||
|
||||
if not conn:
|
||||
database_config = config.config()
|
||||
conn = psycopg2.connect(**database_config)
|
||||
conn.autocommit = True
|
||||
self_conn = True
|
||||
|
||||
if convert:
|
||||
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
|
||||
cur.execute(sql, payload)
|
||||
recordset = cur.fetchall()
|
||||
recordset = [dict(record) for record in recordset]
|
||||
cur.execute(f"SELECT COUNT(*) FROM {site}_items WHERE search_string LIKE '%%' || %s || '%%';", (payload[0], ))
|
||||
count = cur.fetchone()
|
||||
else:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, payload)
|
||||
recordset = cur.fetchall()
|
||||
cur.execute(f"SELECT COUNT(*) FROM {site}_items WHERE search_string LIKE '%%' || %s || '%%';", (payload[0], ))
|
||||
count = cur.fetchone()
|
||||
|
||||
if self_conn:
|
||||
conn.close()
|
||||
|
||||
return recordset, count
|
||||
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def deleteShoppingListItemsTuple(site_name, payload, convert=True, conn=None):
|
||||
deleted = ()
|
||||
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;"
|
||||
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 insertShoppingListItemsTuple(site, payload, convert=True, conn=None):
|
||||
shopping_list_item = ()
|
||||
self_conn = False
|
||||
with open(f"application/shoppinglists/sql/insertShoppingListItemsTuple.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:
|
||||
shopping_list_item = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||
elif rows and not convert:
|
||||
shopping_list_item = rows
|
||||
|
||||
if self_conn:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return shopping_list_item
|
||||
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
0
application/shoppinglists/shoplist_processess.py
Normal file
0
application/shoppinglists/shoplist_processess.py
Normal file
18
application/shoppinglists/sql/getItemsWithQOH.sql
Normal file
18
application/shoppinglists/sql/getItemsWithQOH.sql
Normal file
@ -0,0 +1,18 @@
|
||||
WITH sum_cte AS (
|
||||
SELECT mi.id, SUM(mil.quantity_on_hand)::FLOAT8 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 %%site_name%%_items.*,
|
||||
row_to_json(%%site_name%%_item_info.*) as item_info,
|
||||
sum_cte.total_sum as total_qoh,
|
||||
(SELECT COALESCE(row_to_json(u), '{}') FROM units as u WHERE u.id=%%site_name%%_item_info.uom) as uom
|
||||
FROM %%site_name%%_items
|
||||
LEFT JOIN sum_cte ON %%site_name%%_items.id = sum_cte.id
|
||||
LEFT JOIN %%site_name%%_item_info ON %%site_name%%_items.item_info_id = %%site_name%%_item_info.id
|
||||
WHERE %%site_name%%_items.search_string LIKE '%%' || %s || '%%'
|
||||
ORDER BY %%sort_order%%
|
||||
LIMIT %s OFFSET %s;
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
INSERT INTO %%site_name%%_shopping_list_items
|
||||
(uuid, sl_id, item_type, item_name, uom, qty, item_id, links)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
RETURNING *;
|
||||
4
application/shoppinglists/sql/selectShoppingListItem.sql
Normal file
4
application/shoppinglists/sql/selectShoppingListItem.sql
Normal file
@ -0,0 +1,4 @@
|
||||
SELECT items.*,
|
||||
(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
|
||||
WHERE items.id = %s;
|
||||
@ -88,7 +88,7 @@ async function replenishLineTable(sl_items){
|
||||
}
|
||||
|
||||
async function fetchShoppingList() {
|
||||
const url = new URL('/shopping-lists/getList', window.location.origin);
|
||||
const url = new URL('/shopping-lists/api/getList', window.location.origin);
|
||||
url.searchParams.append('id', sl_id);
|
||||
const response = await fetch(url);
|
||||
data = await response.json();
|
||||
@ -277,7 +277,7 @@ async function updateItemsPaginationElement() {
|
||||
|
||||
let items_limit = 25;
|
||||
async function fetchItems() {
|
||||
const url = new URL('/shopping-lists/getItems', window.location.origin);
|
||||
const url = new URL('/shopping-lists/api/getItems', window.location.origin);
|
||||
url.searchParams.append('page', pagination_current);
|
||||
url.searchParams.append('limit', items_limit);
|
||||
url.searchParams.append('search_string', search_string);
|
||||
@ -288,7 +288,7 @@ async function fetchItems() {
|
||||
}
|
||||
|
||||
async function fetchSLItem(sli_id) {
|
||||
const url = new URL('/shopping-lists/getListItem', window.location.origin);
|
||||
const url = new URL('/shopping-lists/api/getListItem', window.location.origin);
|
||||
url.searchParams.append('sli_id', sli_id);
|
||||
const response = await fetch(url);
|
||||
data = await response.json();
|
||||
@ -320,7 +320,7 @@ async function addCustomItem() {
|
||||
}
|
||||
|
||||
async function submitItemToList(newItem) {
|
||||
const response = await fetch(`/shopping-lists/postListItem`, {
|
||||
const response = await fetch(`/shopping-lists/api/postListItem`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -345,7 +345,7 @@ async function submitItemToList(newItem) {
|
||||
}
|
||||
|
||||
async function deleteLineItem(sli_id) {
|
||||
const response = await fetch(`/shopping-lists/deleteListItem`, {
|
||||
const response = await fetch(`/shopping-lists/api/deleteListItem`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -374,7 +374,7 @@ async function deleteLineItem(sli_id) {
|
||||
}
|
||||
|
||||
async function saveLineItem(sli_id, update) {
|
||||
const response = await fetch(`/shopping-lists/saveListItem`, {
|
||||
const response = await fetch(`/shopping-lists/api/saveListItem`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -58,12 +58,12 @@ async function replenishShoppingListCards(lists) {
|
||||
editOp.setAttribute('class', 'uk-button uk-button-small uk-button-default')
|
||||
editOp.innerHTML = '<span uk-icon="icon: pencil"></span> Edit'
|
||||
editOp.style = "margin-right: 10px;"
|
||||
editOp.href = `/shopping-list/edit/${lists[i].id}`
|
||||
editOp.href = `/shopping-lists/edit/${lists[i].id}`
|
||||
|
||||
let viewOp = document.createElement('a')
|
||||
viewOp.setAttribute('class', 'uk-button uk-button-small uk-button-default')
|
||||
viewOp.innerHTML = '<span uk-icon="icon: eye"></span> View'
|
||||
viewOp.href = `/shopping-list/view/${lists[i].id}`
|
||||
viewOp.href = `/shopping-lists/view/${lists[i].id}`
|
||||
//viewOp.style = "margin-right: 20px;"
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ async function openAddListModal() {
|
||||
var listLimit = 5;
|
||||
async function getShoppingLists(){
|
||||
console.log(pagination_current)
|
||||
const url = new URL('/shopping-lists/getLists', window.location.origin);
|
||||
const url = new URL('/shopping-lists/api/getLists', window.location.origin);
|
||||
url.searchParams.append('page', pagination_current);
|
||||
url.searchParams.append('limit', listLimit);
|
||||
response = await fetch(url)
|
||||
@ -98,7 +98,7 @@ async function addList() {
|
||||
let list_description = document.getElementById('addListDescription').value
|
||||
let list_type = document.getElementById('list_type').value
|
||||
|
||||
const response = await fetch(`/shopping-lists/addList`, {
|
||||
const response = await fetch(`/shopping-lists/api/addList`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -304,6 +304,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="{{ url_for('static', filename='handlers/shoppingListEditHandler.js') }}"></script>
|
||||
<script src="{{ url_for('shopping_list_API.static', filename='js/shoppingListEditHandler.js') }}"></script>
|
||||
<script>const sl_id = {{id|tojson}}</script>
|
||||
</html>
|
||||
@ -156,5 +156,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="{{ url_for('static', filename='handlers/shoppingListsHandler.js') }}"></script>
|
||||
<script src="{{ url_for('shopping_list_API.static', filename='js/shoppingListsHandler.js') }}"></script>
|
||||
</html>
|
||||
@ -116,6 +116,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="{{ url_for('static', filename='handlers/shoppingListViewHandler.js') }}"></script>
|
||||
<script src="{{ url_for('shopping_list_API.static', filename='js/shoppingListViewHandler.js') }}"></script>
|
||||
<script>const sl_id = {{id|tojson}}</script>
|
||||
</html>
|
||||
12
database.log
12
database.log
@ -1944,3 +1944,15 @@
|
||||
2025-07-04 08:19:34.889657 --- ERROR --- DatabaseError(message='invalid input syntax for type integer: "{"cost": 1.99, "expires": false}"LINE 3: ...41789001314%', 'Chicken Ramen Noodle Soup', 1, 5, '{"cost": ... ^',
|
||||
payload=('sku', 23, '%041789001314%', 'Chicken Ramen Noodle Soup', 1, 5, '{"cost": 1.99, "expires": false}', 'Unresolved'),
|
||||
sql='INSERT INTO test_recipe_items(uuid, rp_id, item_type, item_name, uom, qty, item_id, links) VALUES (%s, %s, %s, %s, %s, %s, %s, %s) RETURNING *;')
|
||||
2025-07-12 07:48:13.460875 --- ERROR --- DatabaseError(message='invalid input syntax for type integer: "each"LINE 3: VALUES ('5g89bj2', '5', 'custom', 'test', 'each', 1, NULL, '... ^',
|
||||
payload=('5g89bj2', '5', 'custom', 'test', 'each', 1, None, '{"main": ""}'),
|
||||
sql='INSERT INTO test_shopping_list_items(uuid, sl_id, item_type, item_name, uom, qty, item_id, links) VALUES (%s, %s, %s, %s, %s, %s, %s, %s) RETURNING *;')
|
||||
2025-07-12 07:57:23.925776 --- ERROR --- DatabaseError(message='syntax error at or near "ASC"LINE 16: ORDER BY ASC ^',
|
||||
payload=['', 25, 0],
|
||||
sql='WITH 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 )SELECT test_items.*, row_to_json(test_item_info.*) as item_info, sum_cte.total_sum as total_qoh, (SELECT COALESCE(row_to_json(u), '{}') FROM units as u WHERE u.id=test_item_info.uom) as uomFROM test_itemsLEFT JOIN sum_cte ON test_items.id = sum_cte.idLEFT JOIN test_item_info ON test_items.item_info_id = test_item_info.idWHERE test_items.search_string LIKE '%%' || %s || '%%'ORDER BY ASCLIMIT %s OFFSET %s;')
|
||||
2025-07-12 07:58:21.551161 --- ERROR --- DatabaseError(message='syntax error at or near "ASC"LINE 16: ORDER BY ASC ^',
|
||||
payload=['', 25, 0],
|
||||
sql='WITH 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 )SELECT test_items.*, row_to_json(test_item_info.*) as item_info, sum_cte.total_sum as total_qoh, (SELECT COALESCE(row_to_json(u), '{}') FROM units as u WHERE u.id=test_item_info.uom) as uomFROM test_itemsLEFT JOIN sum_cte ON test_items.id = sum_cte.idLEFT JOIN test_item_info ON test_items.item_info_id = test_item_info.idWHERE test_items.search_string LIKE '%%' || %s || '%%' ORDER BY ASC LIMIT %s OFFSET %s;')
|
||||
2025-07-12 08:43:43.017720 --- ERROR --- DatabaseError(message='invalid input syntax for type integer: " Pinch"LINE 1: ... = 'Acai-Blueberry-Pomegranate', qty = '1', uom = ' Pinch', ... ^',
|
||||
payload={'id': 12, 'update': {'item_name': 'Acai-Blueberry-Pomegranate', 'qty': '1', 'uom': ' Pinch', 'links': {'main': 'test'}}},
|
||||
sql='UPDATE test_shopping_list_items SET item_name = %s, qty = %s, uom = %s, links = %s WHERE id=%s RETURNING *;')
|
||||
@ -1,7 +1,7 @@
|
||||
import celery.schedules
|
||||
from flask import Flask, render_template, session, request, redirect, jsonify
|
||||
from flask_assets import Environment, Bundle
|
||||
import api, config, user_api, psycopg2, main, api_admin, receipts_API, shopping_list_API, group_api
|
||||
import api, config, user_api, psycopg2, main, api_admin, receipts_API, group_api
|
||||
from user_api import login_required, update_session_user
|
||||
from workshop_api import workshop_api
|
||||
import database
|
||||
@ -10,6 +10,7 @@ from webpush import trigger_push_notifications_for_subscriptions
|
||||
from application.recipes import recipes_api
|
||||
from application.items import items_API
|
||||
from application.poe import poe_api
|
||||
from application.shoppinglists import shoplist_api
|
||||
from flasgger import Swagger
|
||||
|
||||
|
||||
@ -31,7 +32,7 @@ app.register_blueprint(items_API.items_api, url_prefix='/items')
|
||||
app.register_blueprint(poe_api.point_of_ease, url_prefix='/poe')
|
||||
app.register_blueprint(workshop_api)
|
||||
app.register_blueprint(receipts_API.receipt_api)
|
||||
app.register_blueprint(shopping_list_API.shopping_list_api)
|
||||
app.register_blueprint(shoplist_api.shopping_list_api, url_prefix="/shopping-lists")
|
||||
app.register_blueprint(group_api.groups_api)
|
||||
app.register_blueprint(recipes_api.recipes_api, url_prefix='/recipes')
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user