Finished Basic Migration to new Schema

This commit is contained in:
Jadowyne Ulve 2025-07-12 09:43:02 -05:00
parent ce8e63b596
commit 0cca96bb13
9 changed files with 263 additions and 97 deletions

View File

@ -29,26 +29,26 @@ def shopping_list(mode, id):
# API CALLS
# Added to Database
@shopping_list_api.route('/api/addList', methods=["POST"])
def addList():
if request.method == "POST":
list_name = request.get_json()['list_name']
list_description = request.get_json()['list_description']
list_type = request.get_json()['list_type']
database_config = config()
site_name = session['selected_site']
user_id = session['user_id']
with psycopg2.connect(**database_config) as conn:
shopping_list = MyDataclasses.ShoppingListPayload(
name=list_name,
description=list_description,
author=user_id,
type=list_type
)
database.insertShoppingListsTuple(conn, site_name, shopping_list.payload())
shopping_list = database_payloads.ShoppingListPayload(
name=list_name,
description=list_description,
author=user_id,
type=list_type
)
shoplist_database.insertShoppingListsTuple(site_name, shopping_list.payload())
return jsonify({'error': False, 'message': 'List added!!'})
return jsonify({'error': True, 'message': 'These was an error with adding the list!'})
# Added to Database
@shopping_list_api.route('/api/getLists', methods=["GET"])
def getShoppingLists():
lists = []
@ -56,42 +56,40 @@ def getShoppingLists():
page = int(request.args.get('page', 1))
limit = int(request.args.get('limit', 1))
offset = (page-1)*limit
database_config = config()
site_name = session['selected_site']
with psycopg2.connect(**database_config) as conn:
lists, count = database.getShoppingLists(conn, site_name, (limit, offset), convert=True)
lists, count = shoplist_database.getShoppingLists(site_name, (limit, offset))
for list in lists:
for list in lists:
if list['type'] == 'calculated':
items = []
not_items = database.getItemsSafetyStock(conn, site_name, convert=True)
for item in not_items:
new_item = {
'id': item['id'],
'uuid': item['barcode'],
'sl_id': 0,
'item_type': 'sku',
'item_name': item['item_name'],
'uom': item['uom'],
'qty': float(float(item['safety_stock']) - float(item['total_sum'])),
'item_id': item['id'],
'links': item['links']
}
items.append(new_item)
list['sl_items'] = items
if list['type'] == 'calculated':
items = []
not_items = shoplist_database.getItemsSafetyStock(site_name)
for item in not_items:
new_item = {
'id': item['id'],
'uuid': item['barcode'],
'sl_id': 0,
'item_type': 'sku',
'item_name': item['item_name'],
'uom': item['uom'],
'qty': float(float(item['safety_stock']) - float(item['total_sum'])),
'item_id': item['id'],
'links': item['links']
}
items.append(new_item)
list['sl_items'] = items
return jsonify({'shopping_lists': lists, 'end':math.ceil(count/limit), 'error': False, 'message': 'Lists queried successfully!'})
# Added to Database
@shopping_list_api.route('/api/getList', methods=["GET"])
def getShoppingList():
if request.method == "GET":
sl_id = int(request.args.get('id', 1))
database_config = config()
site_name = session['selected_site']
with psycopg2.connect(**database_config) as conn:
lists = database.getShoppingList(conn, site_name, (sl_id, ), convert=True)
return jsonify({'shopping_list': lists, 'error': False, 'message': 'Lists queried successfully!'})
list = shoplist_database.getShoppingList(site_name, (sl_id, ))
return jsonify({'shopping_list': list, 'error': False, 'message': 'Lists queried successfully!'})
# Added to Database
@shopping_list_api.route('/api/getListItem', methods=["GET"])
@ -151,39 +149,38 @@ def deleteListItem():
return jsonify({"error":False, "message":"item deleted succesfully!"})
return jsonify({"error":True, "message":"There was an error with this POST statement"})
# Added to Database
@shopping_list_api.route('/api/saveListItem', methods=["POST"])
def saveListItem():
if request.method == "POST":
sli_id = request.get_json()['sli_id']
update = request.get_json()['update']
site_name = session['selected_site']
database_config = config()
with psycopg2.connect(**database_config) as conn:
database.__updateTuple(conn, site_name, f"{site_name}_shopping_list_items", {'id': sli_id, 'update': update})
shoplist_database.updateShoppingListItemsTuple(site_name, {'id': sli_id, 'update': update})
return jsonify({"error":False, "message":"items fetched succesfully!"})
return jsonify({"error":True, "message":"There was an error with this GET statement"})
# Added to Database
@shopping_list_api.route('/api/getSKUItemsFull', methods=["GET"])
def getSKUItemsFull():
items = []
count = {'count': 0}
if request.method == "GET":
site_name = session['selected_site']
database_config = config()
with psycopg2.connect(**database_config) as conn:
not_items = database.getItemsSafetyStock(conn, site_name, convert=True)
for item in not_items:
new_item = {
'id': item['id'],
'uuid': item['barcode'],
'sl_id': 0,
'item_type': 'sku',
'item_name': item['item_name'],
'uom': item['uom'],
'qty': float(float(item['safety_stock']) - float(item['total_sum'])),
'item_id': item['id'],
'links': item['links']
}
items.append(new_item)
not_items = shoplist_database.getItemsSafetyStock(site_name)
for item in not_items:
new_item = {
'id': item['id'],
'uuid': item['barcode'],
'sl_id': 0,
'item_type': 'sku',
'item_name': item['item_name'],
'uom': item['uom'],
'qty': float(float(item['safety_stock']) - float(item['total_sum'])),
'item_id': item['id'],
'links': item['links']
}
items.append(new_item)
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"})

View File

@ -4,48 +4,121 @@ import psycopg2
import config
from application import postsqldb
def getShoppingList(site, payload, convert=True, conn=None):
recordset = []
self_conn = False
with open(f"application/shoppinglists/sql/getShoppingListByID.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:
recordset = postsqldb.tupleDictionaryFactory(cur.description, rows)
if rows and not convert:
recordset = rows
if self_conn:
conn.close()
return recordset
except (Exception, psycopg2.DatabaseError) as error:
raise postsqldb.DatabaseError(error, payload, sql)
def getShoppingLists(site, payload, convert=True, conn=None):
recordset = []
count = 0
self_conn = False
with open(f"application/shoppinglists/sql/getShoppingLists.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]
if rows and not convert:
recordset = rows
cur.execute(f"SELECT COUNT(*) FROM {site}_shopping_lists;")
count = cur.fetchone()[0]
if self_conn:
conn.close()
return recordset, count
except (Exception, psycopg2.DatabaseError) as error:
raise postsqldb.DatabaseError(error, payload, sql)
def getItemsSafetyStock(site, convert=True, conn=None):
recordsets = []
self_conn = False
with open(f"application/shoppinglists/sql/getItemsSafetyStock.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)
rows = cur.fetchall()
if rows and convert:
recordsets = [postsqldb.tupleDictionaryFactory(cur.description, row) for row in rows]
if rows and not convert:
recordsets = rows
if self_conn:
conn.close()
return recordsets
except (Exception, psycopg2.DatabaseError) as error:
raise postsqldb.DatabaseError(error, None, sql)
def getShoppingListItem(site, payload, convert=True, conn=None):
"""_summary_
record = ()
self_conn = False
with open('application/shoppinglists/sql/selectShoppingListItem.sql', 'r') as file:
sql = file.read().replace("%%site_name%%", site)
try:
Args:
conn (_type_): _description_
site (_type_): _description_
payload (_type_): (id, )
convert (bool, optional): _description_. Defaults to True.
if not conn:
database_config = config.config()
conn = psycopg2.connect(**database_config)
conn.autocommit = True
self_conn = True
Raises:
DatabaseError: _description_
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
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)
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 = []
@ -115,6 +188,34 @@ def deleteShoppingListItemsTuple(site_name, payload, convert=True, conn=None):
except Exception as error:
raise postsqldb.DatabaseError(error, payload, sql)
def insertShoppingListsTuple(site, payload, convert=True, conn=None):
shopping_list = ()
self_conn = False
with open(f"application/shoppinglists/sql/insertShoppingListsTuple.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 = postsqldb.tupleDictionaryFactory(cur.description, rows)
elif rows and not convert:
shopping_list = rows
if self_conn:
conn.commit()
conn.close()
return shopping_list
except Exception as error:
raise postsqldb.DatabaseError(error, payload, sql)
def insertShoppingListItemsTuple(site, payload, convert=True, conn=None):
shopping_list_item = ()
self_conn = False
@ -144,3 +245,32 @@ def insertShoppingListItemsTuple(site, payload, convert=True, conn=None):
except Exception as error:
raise postsqldb.DatabaseError(error, payload, sql)
def updateShoppingListItemsTuple(site, payload, convert=True, conn=None):
updated = ()
self_conn = False
set_clause, values = postsqldb.updateStringFactory(payload['update'])
values.append(payload['id'])
sql = f"UPDATE {site}_shopping_list_items SET {set_clause} WHERE id=%s RETURNING *;"
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, values)
rows = cur.fetchone()
if rows and convert:
updated = postsqldb.tupleDictionaryFactory(cur.description, rows)
elif rows and not convert:
updated = rows
if self_conn:
conn.commit()
conn.close()
return updated
except Exception as error:
raise postsqldb.DatabaseError(error, payload, sql)

View File

@ -0,0 +1,11 @@
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 *
FROM %%site_name%%_items
LEFT JOIN %%site_name%%_item_info ON %%site_name%%_items.item_info_id = %%site_name%%_item_info.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);

View File

@ -0,0 +1,15 @@
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 %%site_name%%_shopping_list_items items
WHERE items.sl_id = (SELECT passed_id FROM passed_id)
)
SELECT (SELECT passed_id FROM passed_id) AS passed_id,
%%site_name%%_shopping_lists.*,
logins.username as author,
(SELECT COALESCE(array_agg(row_to_json(slis)), '{}') FROM cte_sl_items slis) AS sl_items
FROM %%site_name%%_shopping_lists
JOIN logins ON %%site_name%%_shopping_lists.author = logins.id
WHERE %%site_name%%_shopping_lists.id=(SELECT passed_id FROM passed_id)

View File

@ -0,0 +1,3 @@
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
FROM %%site_name%%_shopping_lists LIMIT %s OFFSET %s;

View File

@ -0,0 +1,4 @@
INSERT INTO %%site_name%%_shopping_lists
(name, description, author, creation_date, type)
VALUES (%s, %s, %s, %s, %s)
RETURNING *;

View File

@ -158,7 +158,7 @@ async function openLineEditModal(sli_id) {
console.log(sl_item)
document.getElementById('lineName').value = sl_item.item_name
document.getElementById('lineQty').value = sl_item.qty
document.getElementById('lineUOM').value = sl_item.uom.fullname
document.getElementById('lineUOM').value = sl_item.uom.id
console.log(sl_item.links)
if(!sl_item.links.hasOwnProperty('main')){

View File

@ -60,7 +60,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();
@ -68,7 +68,7 @@ async function fetchShoppingList() {
}
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();
@ -76,7 +76,7 @@ async function fetchSLItem(sli_id) {
}
async function fetchItemsFullCalculated() {
const url = new URL('/shopping-lists/getSKUItemsFull', window.location.origin);
const url = new URL('/shopping-lists/api/getSKUItemsFull', window.location.origin);
const response = await fetch(url);
data = await response.json();
return data.list_items;

View File

@ -1956,3 +1956,9 @@
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 *;')
2025-07-12 09:06:37.431664 --- ERROR --- DatabaseError(message='invalid input syntax for type integer: "each"LINE 3: VALUES ('5vpg73z', '5', 'custom', 'test', 'each', 2, NULL, '... ^',
payload=('5vpg73z', '5', 'custom', 'test', 'each', 2, None, '{"main": "test"}'),
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 09:29:10.063362 --- ERROR --- DatabaseError(message='tuple index out of range',
payload=(5,),
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;')