Fixed a conversion uom bug in the planner

This commit is contained in:
Jadowyne Ulve 2025-08-23 07:14:25 -05:00
parent 1156ab5aca
commit bca3ccc864
19 changed files with 118 additions and 37 deletions

View File

@ -51,7 +51,6 @@ def getItemAllByID(site:str, payload: tuple, convert:bool=True):
with open('application/items/sql/getItemAllByID.sql', 'r+') as file: with open('application/items/sql/getItemAllByID.sql', 'r+') as file:
sql = file.read().replace("%%site_name%%", site) sql = file.read().replace("%%site_name%%", site)
record = () record = ()
print(sql)
try: try:
with psycopg2.connect(**database_config) as conn: with psycopg2.connect(**database_config) as conn:
with conn.cursor() as cur: with conn.cursor() as cur:
@ -138,7 +137,6 @@ def getModalSKUs(site:str, payload:tuple, convert:bool=True):
try: try:
with psycopg2.connect(**database_config) as conn: with psycopg2.connect(**database_config) as conn:
with conn.cursor() as cur: with conn.cursor() as cur:
print(payload)
cur.execute(sql, payload) cur.execute(sql, payload)
rows = cur.fetchall() rows = cur.fetchall()
if rows and convert: if rows and convert:
@ -906,7 +904,6 @@ def postUpdateItem(site:str, payload:dict):
transaction_data = {} transaction_data = {}
database_config = config.config() database_config = config.config()
data = payload['update'] data = payload['update']
print(data)
for key in data.keys(): for key in data.keys():
for key_2 in data[key].keys(): for key_2 in data[key].keys():
transaction_data[f"{key_2}_new"] = data[key][key_2] transaction_data[f"{key_2}_new"] = data[key][key_2]

View File

@ -135,7 +135,6 @@ def getModalItems():
site_name = session['selected_site'] site_name = session['selected_site']
offset = (page - 1) * limit offset = (page - 1) * limit
recordset, count = database_items.getModalSKUs(site_name, (search_string, limit, offset)) recordset, count = database_items.getModalSKUs(site_name, (search_string, limit, offset))
print(recordset, count)
return jsonify({"items":recordset, "end":math.ceil(count/limit), "error":False, "message":"items fetched succesfully!"}) return jsonify({"items":recordset, "end":math.ceil(count/limit), "error":False, "message":"items fetched succesfully!"})
return jsonify({"items":recordset, "end":math.ceil(count/limit), "error":True, "message": f"method {request.method} is not allowed."}) return jsonify({"items":recordset, "end":math.ceil(count/limit), "error":True, "message": f"method {request.method} is not allowed."})
@ -459,7 +458,6 @@ def saveBarcode():
""" """
if request.method == "POST": if request.method == "POST":
payload = {'barcode': request.get_json()['barcode'], 'update': request.get_json()['update']} payload = {'barcode': request.get_json()['barcode'], 'update': request.get_json()['update']}
print(payload)
site_name = session['selected_site'] site_name = session['selected_site']
try: try:
database_items.updateBarcodesTuple(site_name, payload) database_items.updateBarcodesTuple(site_name, payload)

View File

@ -141,16 +141,12 @@ def postLinkedItem(site, payload):
'location_id': location['location_id'] 'location_id': location['location_id']
} }
print(conn)
conn = postAdjustment(site, payload['user_id'], adjustment_payload, conn=conn) conn = postAdjustment(site, payload['user_id'], adjustment_payload, conn=conn)
print(conn)
#process.postTransaction(conn, site_name, user_id, payload) #process.postTransaction(conn, site_name, user_id, payload)
print(sum_child_qoh)
primary_location = database_items.selectItemLocationsTuple(site, (parent_item['id'], parent_item['logistics_info']['primary_location']['id']), convert=True) primary_location = database_items.selectItemLocationsTuple(site, (parent_item['id'], parent_item['logistics_info']['primary_location']['id']), convert=True)
print(primary_location)
adjustment_payload = { adjustment_payload = {
'item_id': parent_item['id'], 'item_id': parent_item['id'],
@ -165,9 +161,9 @@ def postLinkedItem(site, payload):
'expires': None, 'expires': None,
'location_id': primary_location['location_id'] 'location_id': primary_location['location_id']
} }
print(conn)
conn=postAdjustment(site, payload['user_id'], adjustment_payload, conn=conn) conn=postAdjustment(site, payload['user_id'], adjustment_payload, conn=conn)
print(conn)
itemLink = db.ItemLinkPayload( itemLink = db.ItemLinkPayload(
barcode=child_item['barcode'], barcode=child_item['barcode'],
link=parent_item['id'], link=parent_item['id'],
@ -176,11 +172,10 @@ def postLinkedItem(site, payload):
) )
_, conn = database_items.postInsertItemLink(site, itemLink.payload(), conn=conn) _, conn = database_items.postInsertItemLink(site, itemLink.payload(), conn=conn)
print(conn)
print(_['id'])
_, conn = database_items.postUpdateItemByID(site, {'id': child_item['id'], 'update': {'row_type': 'link'}}, conn=conn) _, conn = database_items.postUpdateItemByID(site, {'id': child_item['id'], 'update': {'row_type': 'link'}}, conn=conn)
print(conn)
print(_['id'])
conn.commit() conn.commit()
conn.close() conn.close()

View File

@ -28,8 +28,9 @@ def getEventsByMonth():
site_name = session['selected_site'] site_name = session['selected_site']
year = int(request.args.get('year', 2025)) year = int(request.args.get('year', 2025))
month = int(request.args.get('month', 1)) month = int(request.args.get('month', 1))
events = ()
events = meal_planner_database.selectPlanEventsByMonth(site_name, (year, month)) events = meal_planner_processes.selectPlanEventsByMonth(site_name, year, month)
return jsonify(status=201, message="Events fetched Successfully!", events=events) return jsonify(status=201, message="Events fetched Successfully!", events=events)
return jsonify(status=405, message=f"{request.method} is not an allowed method on this endpoint!", events=events) return jsonify(status=405, message=f"{request.method} is not an allowed method on this endpoint!", events=events)

View File

@ -167,6 +167,36 @@ def selectPlanEventByUUID(site: str, payload: tuple, 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 selectConversionsTuple(site: str, payload: tuple, convert=True, conn=None):
"""payload=(event_uuid,)"""
self_conn = False
conversions = ()
sql = f"SELECT * FROM {site}_conversions WHERE item_id = %s AND uom_id = %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.fetchone()
if rows and convert:
conversions = postsqldb.tupleDictionaryFactory(cur.description, rows)
if rows and not convert:
conversions = rows
if self_conn:
conn.close()
return conversions
except Exception as error:
raise postsqldb.DatabaseError(error, payload, sql)
def insertPlanEventTuple(site: str, payload: tuple, convert=True, conn=None): def insertPlanEventTuple(site: str, payload: tuple, convert=True, conn=None):
self_conn = False self_conn = False
event_tuple = () event_tuple = ()

View File

@ -5,6 +5,22 @@ from application.meal_planner import meal_planner_database
from application import postsqldb, database_payloads from application import postsqldb, database_payloads
import config import config
def selectPlanEventsByMonth(site_name, year, month):
events = ()
events = meal_planner_database.selectPlanEventsByMonth(site_name, (year, month))
for event in events:
event['has_missing_ingredients'] = False
for recipe_item in event['recipe_items']:
if recipe_item['item_uom'] != None and recipe_item['ingrediant_uom'] != recipe_item['item_uom']:
conversion = meal_planner_database.selectConversionsTuple(site_name, (recipe_item['item_id'], recipe_item['ingrediant_uom']))
conv_factor = conversion.get('conv_factor', 1)
qty = float(recipe_item['qty']) / float(conv_factor)
recipe_item['qty'] = qty
if float(qty) > float(recipe_item['quantity_on_hand']):
event['has_missing_ingredients'] = True
return events
def addTakeOutEvent(site, data, user_id, conn=None): def addTakeOutEvent(site, data, user_id, conn=None):
event_date_start = datetime.datetime.strptime(data['event_date_start'], "%Y-%m-%d") event_date_start = datetime.datetime.strptime(data['event_date_start'], "%Y-%m-%d")
event_date_end = datetime.datetime.strptime(data['event_date_end'], "%Y-%m-%d") event_date_end = datetime.datetime.strptime(data['event_date_end'], "%Y-%m-%d")
@ -31,6 +47,9 @@ def addTakeOutEvent(site, data, user_id, conn=None):
print(receipt) print(receipt)
attendees = data['attendees']
cost = float(data['cost'])/int(attendees)
receipt_item = database_payloads.ReceiptItemPayload( receipt_item = database_payloads.ReceiptItemPayload(
type = 'custom', type = 'custom',
receipt_id=receipt['id'], receipt_id=receipt['id'],
@ -39,7 +58,7 @@ def addTakeOutEvent(site, data, user_id, conn=None):
name=data['event_shortname'], name=data['event_shortname'],
qty=data['attendees'], qty=data['attendees'],
uom=1, uom=1,
data={'cost': data['cost'], 'expires': False} data={'cost': cost, 'expires': False}
) )
receipt_item = meal_planner_database.insertReceiptItemsTuple(site, receipt_item.payload(), conn=conn) receipt_item = meal_planner_database.insertReceiptItemsTuple(site, receipt_item.payload(), conn=conn)
@ -57,7 +76,6 @@ def addTakeOutEvent(site, data, user_id, conn=None):
) )
event = meal_planner_database.insertPlanEventTuple(site, event_payload.payload(), conn=conn) event = meal_planner_database.insertPlanEventTuple(site, event_payload.payload(), conn=conn)
print(event)
if self_conn: if self_conn:
conn.commit() conn.commit()
conn.close() conn.close()

View File

@ -8,22 +8,22 @@ sum_cte AS (
GROUP BY mi.id GROUP BY mi.id
), ),
cte_recipe_items AS ( cte_recipe_items AS (
SELECT rp_item.rp_id, rp_item.qty, COALESCE(sum_cte.total_sum, 0) as quantity_on_hand FROM %%site_name%%_recipe_items rp_item SELECT items.id AS item_id, rp_item.rp_id, rp_item.qty, rp_item.uom AS ingrediant_uom, item_info.uom AS item_uom, COALESCE(sum_cte.total_sum, 0) as quantity_on_hand FROM %%site_name%%_recipe_items rp_item
LEFT JOIN sum_cte ON sum_cte.item_uuid = rp_item.item_uuid LEFT JOIN sum_cte ON sum_cte.item_uuid = rp_item.item_uuid
), LEFT JOIN %%site_name%%_items items ON rp_item.item_uuid = items.item_uuid
recipe_missing_items AS ( LEFT JOIN %%site_name%%_item_info item_info ON items.item_info_id = item_info.id
SELECT )
rp_id, bool_or(qty > quantity_on_hand) AS has_missing_ingredients
FROM cte_recipe_items
GROUP BY rp_id
)
SELECT events.*, SELECT events.*,
COALESCE(row_to_json(recipes.*), '{}') as recipe, COALESCE(row_to_json(recipes.*), '{}') as recipe,
COALESCE(recipe_missing_items.has_missing_ingredients, FALSE) AS has_missing_ingredients COALESCE(ritems.recipe_items, '{}') as recipe_items
FROM %%site_name%%_plan_events events FROM %%site_name%%_plan_events events
LEFT JOIN %%site_name%%_recipes recipes ON recipes.recipe_uuid = events.recipe_uuid LEFT JOIN %%site_name%%_recipes recipes ON recipes.recipe_uuid = events.recipe_uuid
LEFT JOIN recipe_missing_items ON recipe_missing_items.rp_id = recipes.id LEFT JOIN LATERAL (
SELECT array_agg(row_to_json(ri.*)) AS recipe_items
FROM cte_recipe_items ri
WHERE ri.rp_id = recipes.id
) ritems ON TRUE
WHERE WHERE
event_date_end >= make_date((SELECT year FROM arguments), (SELECT month FROM arguments), 1) event_date_end >= make_date((SELECT year FROM arguments), (SELECT month FROM arguments), 1)
AND AND

View File

@ -252,6 +252,18 @@ def resolveLine():
return jsonify({'error': False, "message": "Line Saved Succesfully"}) return jsonify({'error': False, "message": "Line Saved Succesfully"})
return jsonify({'error': True, "message": "Something went wrong while saving line!"}) return jsonify({'error': True, "message": "Something went wrong while saving line!"})
@receipt_api.route('/api/resolveServiceLine', methods=["POST"])
@access_api.login_required
def resolveServiceLine():
if request.method == "POST":
line_id = int(request.get_json()['line_id'])
site_name = session['selected_site']
user_id = session['user_id']
payload = {'line_id': line_id}
receipts_processes.postService(site_name, user_id, payload)
return jsonify({'error': False, "message": "Line Saved Succesfully"})
return jsonify({'error': True, "message": "Something went wrong while saving line!"})
@receipt_api.route('/api/postVendorUpdate', methods=["POST"]) @receipt_api.route('/api/postVendorUpdate', methods=["POST"])
@access_api.login_required @access_api.login_required
def postVendorUpdate(): def postVendorUpdate():

View File

@ -146,6 +146,26 @@ def linkItem(site, user_id, data, conn=None):
return conn return conn
def postService(site, user_id, data, conn=None):
self_conn = False
if not conn:
database_config = config.config()
conn = psycopg2.connect(**database_config)
conn.autocommit = False
self_conn = True
receipt_item = receipts_database.selectReceiptItemsTuple(site, (data['line_id'],), conn=conn)
receipts_database.updateReceiptItemsTuple(site, {'id': receipt_item['id'], 'update': {'status': "Resolved"}}, conn=conn)
if self_conn:
conn.commit()
conn.close()
return False
return conn
def postLine(site, user_id, data, conn=None): def postLine(site, user_id, data, conn=None):
self_conn = False self_conn = False
if not conn: if not conn:

View File

@ -67,7 +67,11 @@ async function replenishLinesTable(receipt_items) {
label_color = 'purple' label_color = 'purple'
} }
if(receipt_items[i].type == 'PLU SKU'){ if(receipt_items[i].type == 'PLU SKU'){
label_color = 'blue' label_color = 'light blue'
}
if(receipt_items[i].type == 'take out'){
console.log(receipt_items[i])
label_color = 'brown'
} }
typeCell.innerHTML = `<span style="background-color: ${label_color};" class="uk-label">${receipt_items[i].type}</span>` typeCell.innerHTML = `<span style="background-color: ${label_color};" class="uk-label">${receipt_items[i].type}</span>`
@ -76,7 +80,6 @@ async function replenishLinesTable(receipt_items) {
let operationsCell = document.createElement('td') let operationsCell = document.createElement('td')
let linkOp = document.createElement('a') let linkOp = document.createElement('a')
linkOp.style = "margin-right: 5px;" linkOp.style = "margin-right: 5px;"
linkOp.setAttribute('class', 'uk-button uk-button-small uk-button-default') linkOp.setAttribute('class', 'uk-button uk-button-small uk-button-default')
@ -98,7 +101,7 @@ async function replenishLinesTable(receipt_items) {
resolveOp.setAttribute('class', 'uk-button uk-button-small uk-button-default') resolveOp.setAttribute('class', 'uk-button uk-button-small uk-button-default')
resolveOp.setAttribute('uk-icon', 'icon: check') resolveOp.setAttribute('uk-icon', 'icon: check')
resolveOp.onclick = async function(){ resolveOp.onclick = async function(){
await resolveLine(receipt_items[i].id) await resolveLine(receipt_items[i].id, receipt_items[i].type)
} }
let denyOp = document.createElement('a') let denyOp = document.createElement('a')
@ -244,8 +247,12 @@ async function addSKULine(item_id) {
} }
async function resolveLine(line_id) { async function resolveLine(line_id, type) {
const response = await fetch(`/receipts/api/resolveLine`, { let url = '/receipts/api/resolveLine'
if(type==="take out"){
url = '/receipts/api/resolveServiceLine'
}
const response = await fetch(url, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View File

@ -656,3 +656,6 @@
2025-08-21 18:44:41.870684 --- ERROR --- DatabaseError(message='column "name" does not existLINE 1: SELECT * FROM test_vendors ORDER BY name ASC LIMIT 10 OFFSET... ^', 2025-08-21 18:44:41.870684 --- ERROR --- DatabaseError(message='column "name" does not existLINE 1: SELECT * FROM test_vendors ORDER BY name ASC LIMIT 10 OFFSET... ^',
payload=(10, 0), payload=(10, 0),
sql='SELECT * FROM test_vendors ORDER BY name ASC LIMIT %s OFFSET %s;') sql='SELECT * FROM test_vendors ORDER BY name ASC LIMIT %s OFFSET %s;')
2025-08-23 07:01:48.754381 --- ERROR --- DatabaseError(message='column rp_item.type does not existLINE 11: ... SELECT items.id AS item_id, rp_item.rp_id, rp_item.ty... ^',
payload=(2025, 8),
sql='WITH arguments AS ( SELECT %s AS year, %s AS month),sum_cte AS ( SELECT mi.item_uuid, SUM(mil.quantity_on_hand)::FLOAT8 AS total_sum FROM main_item_locations mil JOIN main_items mi ON mil.part_id = mi.id GROUP BY mi.id ),cte_recipe_items AS ( SELECT items.id AS item_id, rp_item.rp_id, rp_item.type, rp_item.qty, rp_item.uom AS ingrediant_uom, item_info.uom AS item_uom, COALESCE(sum_cte.total_sum, 0) as quantity_on_hand FROM main_recipe_items rp_item LEFT JOIN sum_cte ON sum_cte.item_uuid = rp_item.item_uuid LEFT JOIN main_items items ON rp_item.item_uuid = items.item_uuid LEFT JOIN main_item_info item_info ON items.item_info_id = item_info.id ) SELECT events.*, COALESCE(row_to_json(recipes.*), '{}') as recipe, COALESCE(ritems.recipe_items, '{}') as recipe_itemsFROM main_plan_events eventsLEFT JOIN main_recipes recipes ON recipes.recipe_uuid = events.recipe_uuidLEFT JOIN LATERAL ( SELECT array_agg(row_to_json(ri.*)) AS recipe_items FROM cte_recipe_items ri WHERE ri.rp_id = recipes.id) ritems ON TRUEWHERE event_date_end >= make_date((SELECT year FROM arguments), (SELECT month FROM arguments), 1) AND event_date_start < (make_date((SELECT year FROM arguments), (SELECT month FROM arguments), 1) + INTERVAL '1 month');')